The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
verify.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: d14b1103fe9eda9a3fea20448c416204bb2ea887 $
19 *
20 * @file tls/verify.c
21 * @brief Expose certificate OIDs as attributes, and call validation virtual
22 * server to check cert is valid.
23 *
24 * @copyright 2001 hereUare Communications, Inc. (raghud@hereuare.com)
25 * @copyright 2003 Alan DeKok (aland@freeradius.org)
26 * @copyright 2006-2016 The FreeRADIUS server project
27 */
28#ifdef WITH_TLS
29#define LOG_PREFIX "tls"
30
31#include <freeradius-devel/server/exec.h>
32#include <freeradius-devel/server/pair.h>
33#include <freeradius-devel/tls/log.h>
34#include <freeradius-devel/unlang/function.h>
35#include <freeradius-devel/unlang/subrequest.h>
36#include <freeradius-devel/util/debug.h>
37#include <freeradius-devel/util/strerror.h>
38#include <freeradius-devel/util/syserror.h>
39
40#include "attrs.h"
41#include "base.h"
42
43/** Check to see if a verification operation should apply to a certificate
44 *
45 * @param[in] depth starting at 0.
46 * Certificate 0 is the leaf cert (i.e. the client or server cert);
47 * @param[in] untrusted The number of untrusted certificates.
48 * @param[in] mode to check
49 * @return
50 * - true if a given validation check should apply.
51 ** - false if a validation check should not apply.
52 */
53static inline CC_HINT(always_inline)
54bool verify_applies(fr_tls_verify_mode_t mode, int depth, int untrusted)
55{
56 if (mode == FR_TLS_VERIFY_MODE_ALL) return true;
57 if (mode == FR_TLS_VERIFY_MODE_DISABLED) return false;
58
59 if ((mode & FR_TLS_VERIFY_MODE_LEAF) && (depth == 0)) return true;
60 if ((mode & FR_TLS_VERIFY_MODE_ISSUER) && (depth == 1)) return true;
61 if ((mode & FR_TLS_VERIFY_MODE_UNTRUSTED) && (depth < untrusted)) return true;
62
63 return false;
64}
65
67DIAG_OFF(used-but-marked-unused) /* fix spurious warnings for sk macros */
68
69/** Print verbose humanly readable messages about why certificate validation failed
70 *
71 */
72static void tls_verify_error_detail(request_t *request, SSL_CTX *ctx, int err)
73{
74 X509_STORE *store = SSL_CTX_get_ex_data(ctx, FR_TLS_EX_CTX_INDEX_VERIFY_STORE);
75
76 switch (err) {
77 /*
78 * We linked the provided cert to at least one
79 * other in a chain, but the chain doesn't terminate
80 * in a root CA.
81 */
82 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
84
85 /*
86 * We failed to link the provided cert to any
87 * other local certificates in the chain.
88 */
89 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
90 RDEBUG2("Static certificates in verification store are");
91 if (RDEBUG_ENABLED2) {
92 RINDENT();
93 fr_tls_x509_objects_log(request, L_DBG, X509_STORE_get0_objects(store));
94 REXDENT();
95 }
96 break;
97
98 default:
99 break;
100 }
101}
102
103/** Validates a certificate using custom logic
104 *
105 * Before trusting a certificate, we make sure that the certificate is
106 * 'valid'. There are several checks we perform to verify its validity.
107 *
108 * 1. Verify the certificate's signature, and verifying that the certificate has
109 * been issued by a trusted Certificate Authority (this is done for us by OpenSSL).
110 *
111 * 2. Verify that the certificate is valid for the present date (i.e. it is being
112 * presented within its validity dates).
113 *
114 * 3. Verify that the certificate has not been revoked by its issuing Certificate
115 * Authority, by checking with respect to a Certificate Revocation List (CRL).
116 *
117 * @note This callback will be called multiple times based on the depth of the root
118 * certificate chain.
119 *
120 * @note As a byproduct of validation, various OIDs will be extracted from the
121 * certificates, and inserted into the session-state list as fr_pair_t.
122 *
123 * @param ok preverify ok. 1 if true, 0 if false.
124 * @param x509_ctx containing certs to verify.
125 * @return
126 * - 0 if not valid.
127 * - 1 if valid.
128 */
129int fr_tls_verify_cert_cb(int ok, X509_STORE_CTX *x509_ctx)
130{
131 X509 *cert;
132
133 SSL_CTX *ssl_ctx;
134 SSL *ssl;
135 fr_tls_session_t *tls_session;
136 int err, depth;
137 fr_tls_conf_t *conf;
138 int my_ok = ok;
139 int untrusted;
140
141 request_t *request;
142 fr_pair_t *container = NULL;
143 fr_pair_t *depth_pair;
144
145 cert = X509_STORE_CTX_get_current_cert(x509_ctx);
146 err = X509_STORE_CTX_get_error(x509_ctx);
147 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
148 untrusted = X509_STORE_CTX_get_num_untrusted(x509_ctx);
149
150 /*
151 * Retrieve the pointer to the SSL of the connection currently treated
152 * and the application specific data stored into the SSL object.
153 */
154 ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
155 ssl_ctx = SSL_get_SSL_CTX(ssl);
156 conf = fr_tls_session_conf(ssl);
157 tls_session = talloc_get_type_abort(SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TLS_SESSION), fr_tls_session_t);
158 request = fr_tls_session_request(tls_session->ssl);
159
160 /*
161 * If this error appears it suggests
162 * that OpenSSL is trying to perform post-handshake
163 * certificate validation which we don't support.
164 */
165 if (!tls_session->can_pause) {
166 fr_assert_msg("Unexpected call to %s. "
167 "tls_session_async_handshake_cont must be in call stack", __FUNCTION__);
168 return 0;
169 }
170
171 /*
172 * Bail out as quickly as possible, producing
173 * as few errors as possible.
174 */
175 if (unlang_request_is_cancelled(request)) {
176 X509_STORE_CTX_set_error(x509_ctx, 0);
177 return 1;
178 }
179
180 /*
181 * Find or add the chain depth attribute and record the greatest depth we see + 1,
182 * as depth is zero based.
183 */
184 if (unlikely(fr_pair_find_or_append_by_da(request->session_state_ctx, &depth_pair, &request->session_state_pairs,
186 RERROR("Failed to add certificate chain depth pair");
187 return 0;
188 }
189 if (depth_pair->vp_uint32 < ((uint32_t)depth) + 1) depth_pair->vp_uint32 = (uint32_t)depth + 1;
190
191 if (RDEBUG_ENABLED3) {
192 char subject[2048];
193 STACK_OF(X509) *our_chain;
194 int i;
195
196 our_chain = X509_STORE_CTX_get0_chain(x509_ctx);
197 RDEBUG3("Certificate chain - %i cert(s) untrusted", untrusted);
198 for (i = sk_X509_num(our_chain); i > 0 ; i--) {
199 X509 *this_cert = sk_X509_value(our_chain, i - 1);
200
201 X509_NAME_oneline(X509_get_subject_name(this_cert), subject, sizeof(subject));
202 subject[sizeof(subject) - 1] = '\0';
203
204 RDEBUG3("%s [%i] %s", this_cert == cert ? ">" : " ", i - 1, subject);
205 }
206 }
207
208 /*
209 * See if the user has disabled verification for
210 * this certificate. If they have, force verification
211 * to succeed.
212 */
213 if (!my_ok) {
214 char const *p = X509_verify_cert_error_string(err);
215 if (!verify_applies(conf->verify.mode, depth, untrusted)) {
216 RDEBUG2("Ignoring verification error - %s (%i)", p, err);
217 tls_verify_error_detail(request, ssl_ctx, err);
218
219 my_ok = 1;
220 X509_STORE_CTX_set_error(x509_ctx, 0);
221 } else {
222 RERROR("Verification error - %s (%i)", p, err);
223 tls_verify_error_detail(request, ssl_ctx, err);
224 goto done;
225 }
226 }
227
228 if (verify_applies(conf->verify.attribute_mode, depth, untrusted) &&
229 (!(container = fr_pair_find_by_da_idx(&request->session_state_pairs, attr_tls_certificate, depth)) ||
230 fr_pair_list_empty(&container->vp_group))) {
231 if (!container) {
232 unsigned int i;
233
234 /*
235 * Build a stack of container attributes.
236 *
237 * OpenSSL passes us the deepest certificate
238 * first, so we need to build out sufficient
239 * TLS-Certificate container TLVs so the TLS-Certificate
240 * indexes match the attribute depth.
241 */
242 for (i = fr_pair_count_by_da(&request->session_state_pairs, attr_tls_certificate);
243 i <= (unsigned int)depth;
244 i++) {
245 MEM(container = fr_pair_afrom_da(request->session_state_ctx, attr_tls_certificate));
246 fr_pair_append(&request->session_state_pairs, container);
247 }
248 }
249
250#ifdef STATIC_ANALYZER
251 /*
252 * Container can never be NULL, because if container
253 * was previously NULL, i will be <= depth.
254 */
255 if (!fr_cond_assert(container)) {
256 my_ok = 0;
257 goto done;
258 }
259#endif
260 /*
261 * If we fail to populate the cert attributes,
262 * trash all instances in the session-state list
263 * and cause validation to fail.
264 */
265 if (fr_tls_session_pairs_from_x509_cert(&container->vp_group, container,
266 request, cert, conf->verify.der_decode) < 0) {
267 fr_pair_delete_by_da(&request->session_state_pairs, attr_tls_certificate);
268 if (conf->verify.der_decode) {
269 fr_pair_delete_by_da(&request->session_state_pairs, attr_der_certificate);
270 }
271 my_ok = 0;
272 goto done;
273 }
274
275 log_request_pair(L_DBG_LVL_2, request, NULL, container, "session-state.");
276 }
277done:
278 /*
279 * If verification hasn't already failed
280 * and we're meant to verify this cert
281 * then call the virtual server.
282 *
283 * We only call the virtual server for
284 * the certificate at depth 0 as all
285 * other certificate attributes should
286 * have been added by this point.
287 */
288 if (my_ok && (depth == 0)) {
289 if (conf->verify_certificate && tls_session->verify_client_cert) {
290 RDEBUG2("Requesting certificate validation");
291
292 /*
293 * This sets the validation state of the tls_session
294 * so that when we call ASYNC_pause_job(), and execution
295 * jumps back to tls_session_async_handshake_cont
296 * (just under SSL_read())
297 * the code there knows what job it needs to push onto
298 * the unlang stack.
299 */
300 fr_tls_verify_cert_request(tls_session, SSL_session_reused(tls_session->ssl));
301
302 /*
303 * Jumps back to SSL_read() in session.c
304 *
305 * Be aware that if the request is cancelled
306 * whatever was meant to be done during the
307 * time we yielded may not have been completed.
308 */
309 ASYNC_pause_job();
310
311 /*
312 * Just try and bail out as quickly as possible.
313 */
314 if (unlang_request_is_cancelled(request)) {
315 X509_STORE_CTX_set_error(x509_ctx, 0);
316 fr_tls_verify_cert_reset(tls_session);
317 return 1;
318 }
319
320
321 /*
322 * If we couldn't validate the certificate
323 * then validation overall fails.
324 */
325 if (!fr_tls_verify_cert_result(tls_session)) {
326 REDEBUG("Certificate validation failed");
327 my_ok = 0;
328 X509_STORE_CTX_set_error(x509_ctx, X509_V_ERR_APPLICATION_VERIFICATION);
329 }
330 }
331 }
332
333 tls_session->client_cert_ok = (my_ok > 0);
334 RDEBUG2("[verify] = %s", my_ok ? "ok" : "invalid");
335
336 return my_ok;
337}
338DIAG_ON(used-but-marked-unused)
340
341/** Revalidates the client's certificate chain
342 *
343 * Wraps the fr_tls_verify_cert_cb callback, allowing us to use the same
344 * validation logic whenever we need to.
345 *
346 * @note Only use so far is forcing the chain to be re-validated on session
347 * resumption.
348 *
349 * @return
350 * - 1 if the chain could be validated.
351 * - 0 if the chain failed validation.
352 */
353int fr_tls_verify_cert_chain(request_t *request, SSL *ssl)
354{
355 int err;
356 int verify;
357 int ret = 1;
358
359 SSL_CTX *ssl_ctx;
360 STACK_OF(X509) *chain;
361 X509 *cert;
362 X509_STORE *store;
363 X509_STORE_CTX *store_ctx;
364
365 /*
366 * If there's no client certificate, we just return OK.
367 */
368 cert = SSL_get0_peer_certificate(ssl); /* Does not increase ref count */
369 if (!cert) return 1;
370
371 ssl_ctx = SSL_get_SSL_CTX(ssl);
372 store_ctx = X509_STORE_CTX_new();
373 if (unlikely(store_ctx == NULL)) {
374 REDEBUG("Failed allocating X509_STORE_CTX");
375 return 0;
376 }
377
378 chain = SSL_get_peer_cert_chain(ssl); /* Does not increase ref count */
379 store = SSL_CTX_get_ex_data(ssl_ctx, FR_TLS_EX_CTX_INDEX_VERIFY_STORE); /* Gets the verification store */
380
381 /*
382 * This sets up a store_ctx for doing peer certificate verification.
383 *
384 * store_ctx - Is the ctx to initialise
385 * store - Is an X509_STORE of implicitly
386 * trusted certificates. Here we're using
387 * the verify store that was created when we
388 * allocated the SSL_CTX.
389 * cert - Is the certificate to validate.
390 * chain - Is any other certificates the peer provided
391 * us in order to build a chain from a trusted
392 * root or intermediary to its leaf (cert).
393 *
394 * Note: SSL_CTX_get_cert_store() returns the ctx->cert_store, which
395 * is not the same as the verification cert store.
396 */
397 if (unlikely(X509_STORE_CTX_init(store_ctx, store, cert, chain) != 1)) {
398 REDEBUG("Failed initialising X509_STORE_CTX");
399 X509_STORE_CTX_free(store_ctx);
400 return 0;
401 }
402
403 X509_STORE_CTX_set_ex_data(store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), ssl);
404 X509_STORE_CTX_set_verify_cb(store_ctx, fr_tls_verify_cert_cb);
405
406 verify = X509_verify_cert(store_ctx);
407 if (verify != 1) {
408 err = X509_STORE_CTX_get_error(store_ctx);
409
410 if (err != X509_V_OK) {
411 REDEBUG("Failed re-validating resumed session: %s", X509_verify_cert_error_string(err));
412 ret = 0;
413 }
414 }
415
416 X509_STORE_CTX_free(store_ctx);
417
418 return ret;
419}
420
421/** Process the result of `verify certificate { ... }`
422 *
423 */
424static unlang_action_t tls_verify_client_cert_result(request_t *request, void *uctx)
425{
426 fr_tls_session_t *tls_session = talloc_get_type_abort(uctx, fr_tls_session_t);
427 fr_pair_t *vp, *next;
428
429 fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_REQUESTED);
430
431 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_tls_packet_type);
432 if (!vp || (vp->vp_uint32 != enum_tls_packet_type_success->vb_uint32)) {
433 REDEBUG("Failed (re-)validating certificates");
434
435 /*
436 * Hoist any instances of Module-Failure-Message from the subrequest
437 * so they can be used for logging failures.
438 */
439 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_module_failure_message);
440 while (vp && request->parent) {
441 next = fr_pair_find_by_da(&request->request_pairs, vp, attr_module_failure_message);
442 fr_pair_remove(&request->request_pairs, vp);
443 fr_pair_steal_append(request->parent->request_ctx, &request->parent->request_pairs, vp);
444 vp = next;
445 }
446
447 tls_session->validate.state = FR_TLS_VALIDATION_FAILED;
449 }
450
451 tls_session->validate.state = FR_TLS_VALIDATION_SUCCESS;
452
453 RDEBUG2("Certificates (re-)validated");
454
456}
457
458/** Push a `verify certificate { ... }` call into the current request, using a subrequest
459 *
460 * @param[in] request The current request.
461 * @param[in] tls_session The current TLS session.
462 * @return
463 * - UNLANG_ACTION_CALCULATE_RESULT on noop.
464 * - UNLANG_ACTION_PUSHED_CHILD on success.
465 * - UNLANG_ACTION_FAIL on failure.
466 */
467static unlang_action_t tls_verify_client_cert_push(request_t *request, fr_tls_session_t *tls_session)
468{
469 fr_tls_conf_t *conf = fr_tls_session_conf(tls_session->ssl);
470 request_t *child;
471 fr_pair_t *vp;
473
474 MEM(child = unlang_subrequest_alloc(request, dict_tls));
475 request = child;
476
477 /*
478 * Add extra pairs to the subrequest
479 */
480 fr_tls_session_extra_pairs_copy_to_child(child, tls_session);
481
482 /*
483 * Setup the child request for loading
484 * session resumption data.
485 */
487 vp->vp_uint32 = enum_tls_packet_type_verify_certificate->vb_uint32;
488
489 /*
490 * Copy certificate pairs to the child session state
491 */
492 vp = NULL;
493 while ((vp = fr_pair_find_by_da(&request->parent->session_state_pairs, vp, attr_tls_certificate))) {
494 fr_pair_append(&request->session_state_pairs, fr_pair_copy(request->session_state_ctx, vp));
495 }
496 if (conf->verify.der_decode) {
497 while ((vp = fr_pair_find_by_da(&request->parent->session_state_pairs, vp, attr_der_certificate))) {
498 fr_pair_append(&request->session_state_pairs, fr_pair_copy(request->session_state_ctx, vp));
499 }
500 }
501
503 vp->vp_bool = tls_session->validate.resumed;
504
505 /*
506 * Allocate a child, and set it up to call
507 * the TLS virtual server.
508 */
509 ua = fr_tls_call_push(child, tls_verify_client_cert_result, conf, tls_session, false);
510 if (ua < 0) {
511 PERROR("Failed calling TLS virtual server");
512 talloc_free(child);
513 return UNLANG_ACTION_FAIL;
514 }
515
516 return ua;
517}
518
519/** Clear any previous validation result
520 *
521 * Should be called by the validation requestor to get the result and reset
522 * the validation state.
523 *
524 * @return
525 * - true if the certificate chain was validated.
526 * - false if the certificate chain failed validation.
527 */
528bool fr_tls_verify_cert_result(fr_tls_session_t *tls_session)
529{
530 bool result;
531
532 fr_assert(tls_session->validate.state != FR_TLS_VALIDATION_INIT);
533
534 result = tls_session->validate.state == FR_TLS_VALIDATION_SUCCESS;
535
536 tls_session->validate.state = FR_TLS_VALIDATION_INIT;
537 tls_session->validate.resumed = false;
538
539 return result;
540}
541
542/** Reset the verification state
543 *
544 */
545void fr_tls_verify_cert_reset(fr_tls_session_t *tls_session)
546{
547 tls_session->validate.state = FR_TLS_VALIDATION_INIT;
548 tls_session->validate.resumed = false;
549}
550
551/** Setup a verification request
552 *
553 */
554void fr_tls_verify_cert_request(fr_tls_session_t *tls_session, bool session_resumed)
555{
556 fr_assert(tls_session->validate.state == FR_TLS_VALIDATION_INIT);
557
558 tls_session->validate.state = FR_TLS_VALIDATION_REQUESTED;
559 tls_session->validate.resumed = session_resumed;
560}
561
562/** Push a `verify certificate { ... }` section
563 *
564 * @param[in] request The current request.
565 * @param[in] tls_session The current TLS session.
566 * @return
567 * - UNLANG_ACTION_CALCULATE_RESULT - No pending actions
568 * - UNLANG_ACTION_PUSHED_CHILD - Pending operations to evaluate.
569 */
570unlang_action_t fr_tls_verify_cert_pending_push(request_t *request, fr_tls_session_t *tls_session)
571{
572 if (tls_session->validate.state == FR_TLS_VALIDATION_REQUESTED) {
573 return tls_verify_client_cert_push(request, tls_session);
574 }
575
577}
578#endif /* WITH_TLS */
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
#define store(_store, _var)
#define DIAG_UNKNOWN_PRAGMAS
Definition build.h:533
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
Definition build.h:391
#define DIAG_ON(_x)
Definition build.h:535
#define unlikely(_x)
Definition build.h:455
#define DIAG_OFF(_x)
Definition build.h:534
#define fr_cond_assert(_x)
Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x.
Definition debug.h:131
#define fr_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
Definition debug.h:202
#define MEM(x)
Definition debug.h:36
static fr_slen_t err
Definition dict.h:882
talloc_free(hp)
bool unlang_request_is_cancelled(request_t const *request)
Return whether a request has been cancelled.
Definition interpret.c:1970
HIDDEN fr_dict_attr_t const * attr_tls_certificate
Attribute definitions for lib curl.
Definition base.c:36
static fr_dict_t const * dict_tls
Definition base.c:77
static fr_dict_attr_t const * attr_module_failure_message
Definition log.c:206
void log_request_pair(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_t const *vp, char const *prefix)
Print a fr_pair_t.
Definition log.c:787
#define PERROR(_fmt,...)
Definition log.h:233
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:460
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:352
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RERROR(fmt,...)
Definition log.h:315
#define RINDENT()
Indent R* messages by one level.
Definition log.h:447
HIDDEN fr_dict_attr_t const * attr_tls_packet_type
HIDDEN fr_dict_attr_t const * attr_tls_session_resumed
fr_value_box_t const * enum_tls_packet_type_success
HIDDEN fr_dict_attr_t const * attr_der_certificate
fr_value_box_t const * enum_tls_packet_type_verify_certificate
HIDDEN fr_dict_attr_t const * attr_tls_certificate_chain_depth
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
Definition log.h:68
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:56
unsigned int uint32_t
static size_t used
static uint8_t depth(fr_minmax_heap_index_t i)
Definition minmax_heap.c:83
unsigned int fr_pair_count_by_da(fr_pair_list_t const *list, fr_dict_attr_t const *da)
Return the number of instances of a given da in the specified list.
Definition pair.c:684
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:707
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1352
int fr_pair_delete_by_da(fr_pair_list_t *list, fr_dict_attr_t const *da)
Delete matching pairs from the specified list.
Definition pair.c:1696
fr_pair_t * fr_pair_find_by_da_idx(fr_pair_list_t const *list, fr_dict_attr_t const *da, unsigned int idx)
Find a pair with a matching da at a given index.
Definition pair.c:755
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
Definition pair.c:290
int fr_pair_steal_append(TALLOC_CTX *list_ctx, fr_pair_list_t *list, fr_pair_t *vp)
Change a vp's talloc ctx and insert it into a new list.
Definition pair.c:562
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:503
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG_ENABLED2()
#define RDEBUG2(fmt,...)
static bool done
Definition radclient.c:80
static rs_t * conf
Definition radsniff.c:52
#define pair_append_request(_attr, _da)
Allocate and append a fr_pair_t to the request list.
Definition pair.h:37
#define pair_prepend_request(_attr, _da)
Allocate and prepend a fr_pair_t to the request list.
Definition pair.h:77
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
request_t * unlang_subrequest_alloc(request_t *parent, fr_dict_t const *namespace)
Allocate a subrequest to run through a virtual server at some point in the future.
Definition subrequest.c:302
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_remove(fr_pair_list_t *list, fr_pair_t *vp)
Remove fr_pair_t from a list without freeing.
Definition pair_inline.c:93
static int fr_pair_find_or_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Definition pair.h:540