The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
tmpl_dcursor.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: 5ddd1f4992dbee561d8ff327dcb300a12e484a69 $
19  *
20  * @brief #fr_pair_t template functions
21  * @file src/lib/server/tmpl_dcursor.c
22  *
23  * @ingroup AVP
24  *
25  * @copyright 2020-2021 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
26  */
27 RCSID("$Id: 5ddd1f4992dbee561d8ff327dcb300a12e484a69 $")
28 
29 #include <freeradius-devel/server/exec.h>
30 #include <freeradius-devel/server/exec_legacy.h>
31 #include <freeradius-devel/server/tmpl.h>
32 #include <freeradius-devel/server/tmpl_dcursor.h>
33 #include <freeradius-devel/util/dlist.h>
34 #include <freeradius-devel/util/proto.h>
35 #include <freeradius-devel/util/value.h>
36 #include <freeradius-devel/util/edit.h>
37 
38 static inline CC_HINT(always_inline)
40 {
41  if (!cc->pool) MEM(cc->pool = talloc_pool(cc->ctx, sizeof(tmpl_dcursor_nested_t) * 5));
42 }
43 
44 /** Traverse a list of attributes
45  *
46  * A dcursor iterator function for matching attributes
47  *
48  * @param[in] list being traversed.
49  * @param[in] curr item in the list to start tests from.
50  * @param[in] uctx Context for evaluation - in this instance a #tmpl_dcursor_nested_t
51  * @return
52  * - the next matching attribute
53  * - NULL if none found
54  */
55 static void *_tmpl_cursor_child_next(fr_dlist_head_t *list, void *curr, void *uctx)
56 {
57  tmpl_dcursor_nested_t *ns = uctx;
58  fr_pair_t *vp = curr;
59 
60  while ((vp = fr_dlist_next(list, vp))) {
61  if (fr_dict_attr_cmp(ns->ar->ar_da, vp->da) == 0) break;
62  }
63 
64  return vp;
65 }
66 
67 static inline CC_HINT(always_inline) void tmpl_cursor_nested_push(tmpl_dcursor_ctx_t *cc, tmpl_dcursor_nested_t *ns)
68 {
69  fr_dlist_insert_tail(&cc->nested, ns);
70 }
71 
72 static inline CC_HINT(always_inline) void tmpl_cursor_nested_pop(tmpl_dcursor_ctx_t *cc)
73 {
75 
76  if (ns != &cc->leaf) talloc_free(ns);
77 }
78 
79 /** Initialise the evaluation context for traversing a group attribute
80  *
81  */
82 static inline CC_HINT(always_inline)
83 void _tmpl_cursor_pair_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_dcursor_ctx_t *cc)
84 {
86 
87  if (tmpl_attr_list_next(&cc->vpt->data.attribute.ar, ar)) {
89  MEM(ns = talloc(cc->pool, tmpl_dcursor_nested_t));
90  } else {
91  ns = &cc->leaf;
92  }
93 
94  *ns = (tmpl_dcursor_nested_t){
95  .ar = ar,
96  .list_ctx = list_ctx
97  };
98 
99  /*
100  * Iterates over attributes of a specific type
101  */
102  if (ar_is_normal(ar)) {
104  /*
105  * Iterates over all attributes at this level
106  */
107  } else if (ar_is_unspecified(ar)) {
109  } else {
110  fr_assert_msg(0, "Invalid attr reference type");
111  }
112  tmpl_cursor_nested_push(cc, ns);
113 }
114 
115 /** Evaluates, then, sometimes, pops evaluation contexts from the tmpl stack
116  *
117  * To pop or not to pop is determined by whether evaluating the context again
118  * would/should/could produce another fr_pair_t.
119  *
120  * @param[in] curr The pair to evaluate.
121  * @param[in] cc Tracks state between cursor calls.
122  * @return the vp evaluated.
123  */
124 static inline CC_HINT(always_inline)
126 {
127  tmpl_attr_t const *ar;
129  fr_pair_t *iter = curr, *vp;
130  bool pop = false;
131 
132  ns = fr_dlist_tail(&cc->nested);
133  ar = ns->ar;
134  vp = fr_dcursor_current(&ns->cursor);
135 
136  fr_assert(!ar || ar_filter_is_none(ar) || ar_filter_is_num(ar)); /* @todo - add evaluation of conditions */
137 
138  if (ar) switch (ar->ar_num) {
139  /*
140  * Get the first instance
141  */
142  case NUM_UNSPEC:
143  pop = true;
144  break;
145 
146  /*
147  * Get all instances
148  */
149  case NUM_ALL:
150  case NUM_COUNT:
151  all_inst:
152  if (!vp) pop = true; /* pop only when we're done */
153  fr_dcursor_next(&ns->cursor);
154  break;
155 
156  /*
157  * Get the last instance
158  */
159  case NUM_LAST:
160  while ((iter = fr_dcursor_next(&ns->cursor))) {
161  vp = iter;
162  }
163  pop = true;
164  break;
165 
166  /*
167  * Get the n'th instance
168  */
169  default:
170  {
171  int16_t i = 0;
172 
173  while ((i++ < ar->ar_num) && vp) vp = fr_dcursor_next(&ns->cursor);
174  pop = true;
175  }
176  break;
177  } else goto all_inst;
178 
179  /*
180  * If no pair was found and there is a fill
181  * callback, call that, depending on the suffix
182  */
183  if (!vp && cc->build && ar) switch (ar->ar_num) {
184  case NUM_UNSPEC:
185  case NUM_LAST:
186  case 0:
187  vp = cc->build(ns->list_ctx, &ns->cursor, ar->da, cc->uctx);
188  break;
189 
190  default:
191  break;
192  }
193 
194  if (pop) tmpl_cursor_nested_pop(cc);
195 
196  return vp;
197 }
198 
199 static void *_tmpl_cursor_next(UNUSED fr_dlist_head_t *list, void *curr, void *uctx)
200 {
201  tmpl_dcursor_ctx_t *cc = uctx;
202  tmpl_t const *vpt = cc->vpt;
203 
204  fr_pair_t *vp;
205 
206  switch (vpt->type) {
207  case TMPL_TYPE_ATTR:
208  {
209  tmpl_attr_t const *ar = NULL;
210  tmpl_dcursor_nested_t *ns = NULL;
211 
212  /*
213  * - Continue until there are no evaluation contexts
214  * - Push a evaluation context if evaluating the head of the
215  * stack yields a VP and we're not at the deepest attribute
216  * reference.
217  * - Return if we have a VP and there are no more attribute
218  * references to push, i.e. we're at the deepest attribute
219  * reference.
220  */
221  while ((ns = fr_dlist_tail(&cc->nested))) {
222  ar = ns->ar;
223  vp = _tmpl_cursor_eval(curr, cc);
224  if (!vp) continue;
225 
226  ar = tmpl_attr_list_next(&vpt->data.attribute.ar, ar);
227  if (ar) {
228  fr_pair_list_t *list_head;
229 
230  list_head = &vp->vp_group;
231  _tmpl_cursor_pair_init(vp, list_head, ar, cc);
232  curr = fr_pair_list_head(list_head);
233  continue;
234  }
235 
236  return vp;
237  }
238 
239  return NULL;
240  }
241 
242  default:
243  fr_assert(0);
244  }
245 
246  return NULL;
247 }
248 
249 #ifdef TMPL_DCURSOR_MOD
250 static int tmpl_dcursor_insert(UNUSED fr_dlist_head_t *list, void *to_insert, void *uctx)
251 {
252  tmpl_dcursor_ctx_t *cc = uctx;
254 
255  if (!ns) return 0;
256 
257  fr_dcursor_insert(&ns->cursor, to_insert);
258  return 0;
259 }
260 
261 static int tmpl_dcursor_remove(UNUSED fr_dlist_head_t *list, void *to_remove, void *uctx)
262 {
263  tmpl_dcursor_ctx_t *cc = uctx;
265  void *current;
266 
267  if (!ns) return 0;
268 
270  if (current == to_remove) {
272  } else {
273  fr_dcursor_set_current(&ns->cursor, to_remove);
276  }
277  return 0;
278 }
279 #endif
280 
281 /** Initialise a #fr_dcursor_t at the specified point in a pair tree
282  *
283  * This makes iterating over the one or more #fr_pair_t specified by a #tmpl_t
284  * significantly easier.
285  *
286  * @param[out] err May be NULL if no error code is required.
287  * Will be set to:
288  * - 0 on success.
289  * - -1 if no matching #fr_pair_t could be found.
290  * - -2 if list could not be found (doesn't exist in current #request_t).
291  * - -3 if context could not be found (no parent #request_t available).
292  * @param[in] ctx to make temporary allocations under.
293  * @param[in] cc to initialise. Tracks evaluation state.
294  * Must be explicitly cleared with tmpl_cursor_state_clear
295  * otherwise we will leak memory.
296  * @param[in] cursor to store iterator position.
297  * @param[in] request the current request.
298  * @param[in] list a nested list to start evaluating from.
299  * May be the child list of a pair in the request's pair tree.
300  * @param[in] vpt specifying the #fr_pair_t type or list to iterate over.
301  * @param[in] build Callback to build missing pairs.
302  * @param[in] uctx to pass to build.
303  * @return
304  * - First #fr_pair_t specified by the #tmpl_t.
305  * - NULL if no matching #fr_pair_t found, and NULL on error.
306  *
307  * @see tmpl_cursor_next
308  */
310  fr_dcursor_t *cursor,
311  request_t *request, fr_pair_t *list, tmpl_t const *vpt,
312  tmpl_dcursor_build_t build, void *uctx)
313 {
314  fr_pair_t *vp = NULL;
315 
316  TMPL_VERIFY(vpt);
317 
318  /*
319  * Initialise the temporary cursor context
320  */
321  *cc = (tmpl_dcursor_ctx_t){
322  .vpt = vpt,
323  .ctx = ctx,
324  .request = request,
325  .list = &list->vp_group,
326  .build = build,
327  .uctx = uctx
328  };
330 
331  /*
332  * Prime the stack!
333  */
334  switch (vpt->type) {
335  case TMPL_TYPE_ATTR:
336  _tmpl_cursor_pair_init(list, cc->list, tmpl_attr_list_head(&vpt->data.attribute.ar), cc);
337  break;
338 
339  default:
340  fr_assert(0);
341  break;
342  }
343 
344  /*
345  * Get the first entry from the tmpl
346  */
347 #ifndef TMPL_DCURSOR_MOD
349 #else
350  vp = fr_dcursor_iter_mod_init(cursor, fr_pair_list_to_dlist(cc->list), _tmpl_cursor_next, NULL, cc, tmpl_dcursor_insert, tmpl_dcursor_remove, cc);
351 #endif
352  if (!vp) {
353  if (err) {
354  *err = -1;
355  if (tmpl_is_list(vpt)) {
356  fr_strerror_printf("List \"%s\" is empty", vpt->name);
357  } else {
358  fr_strerror_printf("No matching \"%s\" pairs found", tmpl_attr_tail_da(vpt)->name);
359  }
360  }
361  return NULL;
362  }
363 
364  return vp;
365 }
366 
367 /** Initialise a #fr_dcursor_t to the #fr_pair_t specified by a #tmpl_t
368  *
369  * This makes iterating over the one or more #fr_pair_t specified by a #tmpl_t
370  * significantly easier.
371  *
372  * @param[out] err May be NULL if no error code is required.
373  * Will be set to:
374  * - 0 on success.
375  * - -1 if no matching #fr_pair_t could be found.
376  * - -2 if list could not be found (doesn't exist in current #request_t).
377  * - -3 if context could not be found (no parent #request_t available).
378  * @param[in] ctx to make temporary allocations under.
379  * @param[in] cc to initialise. Tracks evaluation state.
380  * Must be explicitly cleared with tmpl_cursor_state_clear
381  * otherwise we will leak memory.
382  * @param[in] cursor to store iterator position.
383  * @param[in] request The current #request_t.
384  * @param[in] vpt specifying the #fr_pair_t type or list to iterate over.
385  * @param[in] build Callback to build missing pairs.
386  * @param[in] uctx for building new pairs.
387  * @return
388  * - First #fr_pair_t specified by the #tmpl_t.
389  * - NULL if no matching #fr_pair_t found, and NULL on error.
390  *
391  * @see tmpl_cursor_next
392  */
394  fr_dcursor_t *cursor, request_t *request, tmpl_t const *vpt,
395  tmpl_dcursor_build_t build, void *uctx)
396 {
397  fr_pair_t *list;
398 
400 
401  if (err) *err = 0;
402 
403  /*
404  * Navigate to the correct request context (parent, outer, current, etc...)
405  */
406  if (tmpl_request_ptr(&request, tmpl_request(vpt)) < 0) {
407  if (err) *err = -3;
408  memset(cc, 0, sizeof(*cc)); /* so tmpl_dcursor_clear doesn't explode */
409  return NULL;
410  }
411  list = request->pair_root; /* Start navigating from the root of that request */
412 
413  return tmpl_dcursor_init_relative(err, ctx, cc, cursor, request, list, vpt, build, uctx);
414 }
415 
416 /** Clear any temporary state allocations
417  *
418  */
420 {
421  /*
422  * If the pool wasn't created, nothing was talloc'd which
423  * needs freeing.
424  */
425  if (!cc->pool) return;
426 
427  fr_dlist_remove(&cc->nested, &cc->leaf); /* Noop if leaf isn't inserted */
429 
430  TALLOC_FREE(cc->pool);
431 }
432 
433 /** Simple pair building callback for use with tmpl_dcursors
434  *
435  * Which always appends the new pair to the tail of the list
436  * since it is only called when no matching pairs were found when
437  * walking the list.
438  *
439  * @param[in] parent to allocate new pair within.
440  * @param[in,out] cursor to append new pair to.
441  * @param[in] da of new pair.
442  * @param[in] uctx unused.
443  * @return
444  * - newly allocated #fr_pair_t.
445  * - NULL on error.
446  */
448 {
449  fr_pair_t *vp;
450  vp = fr_pair_afrom_da(parent, da);
451  if (vp) fr_dcursor_append(cursor, vp);
452  return vp;
453 }
454 
455 #define EXTENT_ADD(_out, _ar, _list_ctx, _list) \
456  do { \
457  tmpl_attr_extent_t *_extent; \
458  MEM(_extent = talloc(ctx, tmpl_attr_extent_t)); \
459  *_extent = (tmpl_attr_extent_t){ \
460  .ar = _ar, \
461  .list_ctx = _list_ctx, \
462  .list = _list \
463  }; \
464  fr_dlist_insert_tail(_out, _extent); \
465  } while (0)
466 
467 /** Determines points where the reference list extends beyond the current pair tree
468  *
469  * If a particular branch in the VP hierarchy is incomplete, i.e. the chain of attribute
470  * refers to nodes deeper than the nodes currently in the tree, then we return the
471  * deepest point node in the tree which matched, and the ar that we failed to evaluate.
472  *
473  * If the reference list resolves to one or more structural pairs, return those as well.
474  *
475  * This function can be used for a number of different operations, but it's most useful
476  * for determining insertion points for new attributes, or determining which attributes
477  * need to be updated.
478  *
479  * @param[in] ctx to allocate. It's recommended to pass a pool with space
480  * for at least five extent structures.
481  * @param[out] existing List of extents we discovered by evaluating all
482  * attribute references. May be NULL.
483  * @param[out] to_build List of extents that need building out, i.e. references
484  * extend beyond pairs. May be NULL.
485  * @param[in] request The current #request_t.
486  * @param[in] vpt specifying the #fr_pair_t type to retrieve or create.
487  * Must be #TMPL_TYPE_ATTR.
488  * @return
489  * - 0 on success a pair was found.
490  * - -2 if list could not be found (doesn't exist in current #request_t).
491  * - -3 if context could not be found (no parent #request_t available).
492  */
493 int tmpl_extents_find(TALLOC_CTX *ctx,
494  fr_dlist_head_t *existing, fr_dlist_head_t *to_build,
495  request_t *request, tmpl_t const *vpt)
496 {
497  fr_pair_t *curr = NULL;
498  fr_pair_list_t *list_head;
499 
500  TALLOC_CTX *list_ctx = NULL;
501 
503  tmpl_dcursor_nested_t *ns = NULL;
504 
505  tmpl_attr_t const *ar = NULL;
506 
507  TMPL_VERIFY(vpt);
508 
510 
511  /*
512  * Navigate to the correct request context
513  */
514  if (tmpl_request_ptr(&request, tmpl_request(vpt)) < 0) return -3;
515 
516  list_head = &request->pair_root->vp_group;
517  list_ctx = request->pair_root;
518 
519  /*
520  * If it's a leaf skip all the expensive
521  * initialisation and just return the list
522  * it's part of.
523  *
524  * This is only needed because lists are
525  * treated specially. Once lists are groups
526  * this can be removed.
527  */
528  ar = tmpl_attr_list_head(&vpt->data.attribute.ar);
529  switch (ar->ar_da->type) {
530  case FR_TYPE_STRUCTURAL:
531  break;
532 
533  default:
534  if (existing) EXTENT_ADD(existing, NULL, list_ctx, list_head);
535  return 0;
536  }
537 
538  /*
539  * Initialise the temporary cursor context
540  */
541  cc = (tmpl_dcursor_ctx_t){
542  .vpt = vpt,
543  .ctx = ctx,
544  .request = request,
545  .list = list_head
546  };
548 
549  /*
550  * Prime the stack!
551  */
552  _tmpl_cursor_pair_init(list_ctx, cc.list, tmpl_attr_list_head(&vpt->data.attribute.ar), &cc);
553 
554  /*
555  * - Continue until there are no evaluation contexts
556  * - Push a evaluation context if evaluating the head of the
557  * stack yields a VP and we're not at the deepest attribute
558  * reference.
559  * - Return if we have a VP and there are no more attribute
560  * references to push, i.e. we're at the deepest attribute
561  * reference.
562  */
563  curr = fr_pair_list_head(list_head);
564  while ((ns = fr_dlist_tail(&cc.nested))) {
565  tmpl_attr_t const *n_ar;
566 
567  list_ctx = ns->list_ctx;
568  ar = ns->ar;
569  curr = _tmpl_cursor_eval(curr, &cc);
570  if (!curr) {
571  /*
572  * References extend beyond current
573  * pair tree.
574  */
575  if (!ar->resolve_only && to_build) EXTENT_ADD(to_build, ar, list_ctx, list_head);
576  continue; /* Rely on _tmpl_cursor_eval popping the stack */
577  }
578 
579  /*
580  * Evaluate the next reference
581  */
582  n_ar = tmpl_attr_list_next(&vpt->data.attribute.ar, ar);
583  if (n_ar) {
584  ar = n_ar;
585  list_head = &curr->vp_group;
586  list_ctx = curr; /* Allocations are under the group */
587  _tmpl_cursor_pair_init(list_ctx, list_head, ar, &cc);
588  curr = fr_pair_list_head(list_head);
589  continue;
590  }
591 
592  /*
593  * Only reached when we can't find an exiting
594  * part of the pair_root to keep walking.
595  *
596  * VP tree may extend beyond the reference.
597  * If the reference was structural, record this
598  * as an extent.
599  */
600  if (existing) EXTENT_ADD(existing, NULL, list_ctx, list_head);
601 
602  break;
603  }
604 
605  return 0;
606 }
607 
608 /** Allocate interior pairs
609  *
610  * Builds out the pair tree to the point where leaf attributes can be added
611  *
612  * @param[out] existing List to add built out attributes to.
613  * @param[in] to_build List to remove attributes from.
614  * @param[in] vpt We are evaluating.
615  * @return
616  * - 0 on success.
617  * - -1 on failure.
618  */
620 {
621  tmpl_attr_extent_t *extent = NULL;
622 
623  while ((extent = fr_dlist_head(to_build))) {
624  fr_pair_list_t *list;
625  TALLOC_CTX *list_ctx;
626  fr_pair_t *vp;
627  tmpl_attr_t const *ar;
628 
629  fr_assert(extent->ar); /* Interior extents MUST contain an ar */
630 
631  /*
632  * Try and allocate VPs for the
633  * rest of the attribute references.
634  */
635  for (ar = extent->ar, list = extent->list, list_ctx = extent->list_ctx;
636  ar;
637  ar = tmpl_attr_list_next(&vpt->data.attribute.ar, ar)) {
638  switch (ar->type) {
641  /*
642  * Don't build leaf attributes
643  */
644  if (!fr_type_is_structural(ar->ar_da->type)) continue;
645 
646  MEM(vp = fr_pair_afrom_da(list_ctx, ar->ar_da)); /* Copies unknowns */
647  fr_pair_append(list, vp);
648  list = &vp->vp_group;
649  list_ctx = vp; /* New allocations occur under the VP */
650  break;
651 
652  default:
653  fr_assert_fail("references of this type should have been resolved");
654  return -1;
655  }
656  }
657 
658  fr_dlist_remove(to_build, extent); /* Do this *before* zeroing the dlist headers */
659  *extent = (tmpl_attr_extent_t){
660  .list = list,
661  .list_ctx = list_ctx
662  };
663  fr_dlist_insert_tail(existing, extent); /* move between in and out */
664  }
665 
666  return 0;
667 }
668 
670 {
671  tmpl_attr_extent_t const *extent = NULL;
672  fr_pair_t *vp = NULL;
673 
674  for (extent = fr_dlist_head(head);
675  extent;
676  extent = fr_dlist_next(head, extent)) {
677  tmpl_attr_t const *ar = extent->ar;
678  char const *ctx_name;
679 
680  if (ar) {
681  FR_FAULT_LOG("extent-interior-attr");
682  tmpl_attr_ref_debug(extent->ar, 0);
683  } else {
684  FR_FAULT_LOG("extent-leaf");
685  }
686 
687  ctx_name = talloc_get_name(extent->list_ctx);
688  if (strcmp(ctx_name, "fr_pair_t") == 0) {
689  FR_FAULT_LOG("list_ctx : %p (%s, %s)", extent->list_ctx, ctx_name,
690  ((fr_pair_t *)extent->list_ctx)->da->name);
691  } else {
692  FR_FAULT_LOG("list_ctx : %p (%s)", extent->list_ctx, ctx_name);
693  }
694  FR_FAULT_LOG("list : %p", extent->list);
695  if (fr_pair_list_empty(extent->list)) {
696  FR_FAULT_LOG("list (first) : none (%p)", extent->list);
697  } else {
698  vp = fr_pair_list_head(extent->list);
699  FR_FAULT_LOG("list (first) : %s (%p)", vp->da->name, extent->list);
700  }
701  }
702 
703 }
#define RCSID(id)
Definition: build.h:444
#define UNUSED
Definition: build.h:313
static void * fr_dcursor_remove(fr_dcursor_t *cursor)
Remove the current item.
Definition: dcursor.h:479
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition: dcursor.h:405
static int fr_dcursor_insert(fr_dcursor_t *cursor, void *v)
Insert directly after the current item.
Definition: dcursor.h:434
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition: dcursor.h:728
static void * fr_dcursor_set_current(fr_dcursor_t *cursor, void *item)
Set the cursor to a specified item.
Definition: dcursor.h:352
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
#define fr_dcursor_iter_mod_init(_cursor, _list, _iter, _peek, _iter_uctx, _insert, _remove, _mod_uctx)
Initialise a cursor with a custom iterator.
Definition: dcursor.h:686
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition: dcursor.h:336
#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:208
#define fr_assert_fail(_msg,...)
Calls panic_action ifndef NDEBUG, else logs error.
Definition: debug.h:214
#define FR_FAULT_LOG(_fmt,...)
Definition: debug.h:49
static fr_slen_t err
Definition: dict.h:645
static int8_t fr_dict_attr_cmp(fr_dict_attr_t const *a, fr_dict_attr_t const *b)
Definition: dict.h:466
#define fr_dlist_init(_head, _type, _field)
Initialise the head structure of a doubly linked list.
Definition: dlist.h:260
static void * fr_dlist_next(fr_dlist_head_t const *list_head, void const *ptr)
Get the next item in a list.
Definition: dlist.h:555
static void fr_dlist_talloc_free(fr_dlist_head_t *head)
Free all items in a doubly linked list (with talloc)
Definition: dlist.h:908
static void * fr_dlist_pop_tail(fr_dlist_head_t *list_head)
Remove the tail item in a list.
Definition: dlist.h:688
static void * fr_dlist_tail(fr_dlist_head_t const *list_head)
Return the TAIL item of a list or NULL if the list is empty.
Definition: dlist.h:531
static void * fr_dlist_head(fr_dlist_head_t const *list_head)
Return the HEAD item of a list or NULL if the list is empty.
Definition: dlist.h:486
static int fr_dlist_insert_tail(fr_dlist_head_t *list_head, void *ptr)
Insert an item into the tail of a list.
Definition: dlist.h:378
static void * fr_dlist_remove(fr_dlist_head_t *list_head, void *ptr)
Remove an item from the list.
Definition: dlist.h:638
Head of a doubly linked list.
Definition: dlist.h:51
talloc_free(reap)
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:278
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:1340
static rc_request_t * current
Definition: radclient-ng.c:97
static char const * name
#define TMPL_VERIFY(_vpt)
Definition: tmpl.h:953
#define ar_is_unspecified(_ar)
Definition: tmpl.h:503
#define NUM_LAST
Definition: tmpl.h:402
static fr_slen_t vpt
Definition: tmpl.h:1260
TALLOC_CTX * list_ctx
Where to allocate new attributes if building out from the current extents of the tree.
Definition: tmpl.h:605
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition: tmpl.h:796
void tmpl_attr_ref_debug(const tmpl_attr_t *ar, int idx)
#define tmpl_is_attr(vpt)
Definition: tmpl.h:213
#define NUM_ALL
Definition: tmpl.h:400
#define ar_filter_is_num(_ar)
Definition: tmpl.h:513
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition: tmpl.h:146
#define NUM_COUNT
Definition: tmpl.h:401
static bool tmpl_is_list(tmpl_t const *vpt)
Definition: tmpl.h:915
#define NUM_UNSPEC
Definition: tmpl.h:399
int tmpl_request_ptr(request_t **request, FR_DLIST_HEAD(tmpl_request_list) const *rql)
Resolve a tmpl_request_ref_t to a request_t.
Definition: tmpl_eval.c:167
fr_pair_list_t * list
List that we tried to evaluate ar in and failed.
Definition: tmpl.h:607
#define ar_is_normal(_ar)
Definition: tmpl.h:502
@ TMPL_ATTR_TYPE_NORMAL
Normal, resolved, attribute ref.
Definition: tmpl.h:386
@ TMPL_ATTR_TYPE_UNKNOWN
We have an attribute number but it doesn't match anything in the dictionary, or isn't a child of the ...
Definition: tmpl.h:389
tmpl_attr_t const * ar
Attribute representing the ar after the deepest node that was found in the existing pair tree when ev...
Definition: tmpl.h:599
#define ar_filter_is_none(_ar)
Definition: tmpl.h:512
Describes the current extents of a pair tree in relation to the tree described by a tmpl_t.
Definition: tmpl.h:596
fr_assert(0)
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
fr_pair_t * vp
An element in a list of nested attribute references.
Definition: tmpl.h:427
unsigned int _CONST resolve_only
This reference and those before it.
Definition: tmpl.h:450
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Definition: tmpl.h:431
tmpl_attr_type_t _CONST type
is a raw reference
Definition: tmpl.h:455
Stores an attribute, a value and various bits of other data.
Definition: pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition: pair.h:69
fr_pair_t * tmpl_dcursor_init_relative(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ctx_t *cc, fr_dcursor_t *cursor, request_t *request, fr_pair_t *list, tmpl_t const *vpt, tmpl_dcursor_build_t build, void *uctx)
Initialise a fr_dcursor_t at the specified point in a pair tree.
Definition: tmpl_dcursor.c:309
static void * _tmpl_cursor_next(UNUSED fr_dlist_head_t *list, void *curr, void *uctx)
Definition: tmpl_dcursor.c:199
static void _tmpl_cursor_pair_init(TALLOC_CTX *list_ctx, fr_pair_list_t *list, tmpl_attr_t const *ar, tmpl_dcursor_ctx_t *cc)
Initialise the evaluation context for traversing a group attribute.
Definition: tmpl_dcursor.c:83
fr_pair_t * _tmpl_dcursor_init(int *err, TALLOC_CTX *ctx, tmpl_dcursor_ctx_t *cc, fr_dcursor_t *cursor, request_t *request, tmpl_t const *vpt, tmpl_dcursor_build_t build, void *uctx)
Initialise a fr_dcursor_t to the fr_pair_t specified by a tmpl_t.
Definition: tmpl_dcursor.c:393
static fr_pair_t * _tmpl_cursor_eval(fr_pair_t *curr, tmpl_dcursor_ctx_t *cc)
Evaluates, then, sometimes, pops evaluation contexts from the tmpl stack.
Definition: tmpl_dcursor.c:125
int tmpl_extents_build_to_leaf_parent(fr_dlist_head_t *existing, fr_dlist_head_t *to_build, tmpl_t const *vpt)
Allocate interior pairs.
Definition: tmpl_dcursor.c:619
int tmpl_extents_find(TALLOC_CTX *ctx, fr_dlist_head_t *existing, fr_dlist_head_t *to_build, request_t *request, tmpl_t const *vpt)
Determines points where the reference list extends beyond the current pair tree.
Definition: tmpl_dcursor.c:493
fr_pair_t * tmpl_dcursor_pair_build(fr_pair_t *parent, fr_dcursor_t *cursor, fr_dict_attr_t const *da, UNUSED void *uctx)
Simple pair building callback for use with tmpl_dcursors.
Definition: tmpl_dcursor.c:447
static void tmpl_cursor_nested_push(tmpl_dcursor_ctx_t *cc, tmpl_dcursor_nested_t *ns)
Definition: tmpl_dcursor.c:67
static void tmpl_cursor_nested_pop(tmpl_dcursor_ctx_t *cc)
Definition: tmpl_dcursor.c:72
static void _tmpl_cursor_pool_init(tmpl_dcursor_ctx_t *cc)
Definition: tmpl_dcursor.c:39
static void * _tmpl_cursor_child_next(fr_dlist_head_t *list, void *curr, void *uctx)
Traverse a list of attributes.
Definition: tmpl_dcursor.c:55
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
Definition: tmpl_dcursor.c:419
void tmpl_extents_debug(fr_dlist_head_t *head)
Definition: tmpl_dcursor.c:669
#define EXTENT_ADD(_out, _ar, _list_ctx, _list)
Definition: tmpl_dcursor.c:455
tmpl_dcursor_nested_t leaf
Pre-allocated leaf state.
Definition: tmpl_dcursor.h:78
fr_pair_list_t * list
List within the request.
Definition: tmpl_dcursor.h:68
fr_dcursor_t cursor
Cursor to track where we are in the list in case we're doing counts.
Definition: tmpl_dcursor.h:54
fr_pair_t *(* tmpl_dcursor_build_t)(fr_pair_t *parent, fr_dcursor_t *cursor, fr_dict_attr_t const *da, void *uctx)
Callback function for populating missing pair.
Definition: tmpl_dcursor.h:39
struct tmpl_dcursor_ctx_s tmpl_dcursor_ctx_t
Definition: tmpl_dcursor.h:28
fr_dlist_head_t nested
Nested state.
Definition: tmpl_dcursor.h:70
tmpl_t const * vpt
tmpl we're evaluating.
Definition: tmpl_dcursor.h:64
struct tmpl_dcursor_nested_s tmpl_dcursor_nested_t
Definition: tmpl_dcursor.h:29
TALLOC_CTX * pool
Temporary pool.
Definition: tmpl_dcursor.h:63
TALLOC_CTX * list_ctx
Track where we should be allocating attributes.
Definition: tmpl_dcursor.h:48
tmpl_attr_t const * ar
Attribute reference this state entry is associated with.
Definition: tmpl_dcursor.h:46
Maintains state between cursor calls.
Definition: tmpl_dcursor.h:61
State for traversing an attribute reference.
Definition: tmpl_dcursor.h:44
static fr_slen_t head
Definition: xlat.h:408
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition: pair_inline.c:43
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition: pair.h:568
fr_dlist_head_t * fr_pair_list_to_dlist(fr_pair_list_t const *list)
Get the dlist head from a pair list.
Definition: pair_inline.c:162
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
Definition: pair_inline.c:125
static fr_slen_t parent
Definition: pair.h:844
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_type_is_structural(_x)
Definition: types.h:371
#define FR_TYPE_STRUCTURAL
Definition: types.h:296