The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
tmpl_eval.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: c34ce3a43289c510402048a04e4453367cf5b014 $
19  *
20  * @brief #fr_pair_t template functions
21  * @file src/lib/server/tmpl_eval.c
22  *
23  * @ingroup AVP
24  *
25  * @copyright 2014-2020 The FreeRADIUS server project
26  */
27 RCSID("$Id: c34ce3a43289c510402048a04e4453367cf5b014 $")
28 
29 #define _TMPL_PRIVATE 1
30 
31 #include <freeradius-devel/server/exec.h>
32 #include <freeradius-devel/server/exec_legacy.h>
33 #include <freeradius-devel/server/tmpl.h>
34 #include <freeradius-devel/server/tmpl_dcursor.h>
35 #include <freeradius-devel/server/client.h>
36 #include <freeradius-devel/unlang/call.h>
37 #include <freeradius-devel/util/dlist.h>
38 #include <freeradius-devel/util/proto.h>
39 #include <freeradius-devel/util/value.h>
40 #include <freeradius-devel/util/edit.h>
41 #include <freeradius-devel/util/token.h>
42 #include <freeradius-devel/util/types.h>
43 
44 #include <talloc.h>
45 
46 static fr_dict_t const *dict_freeradius;
47 static fr_dict_t const *dict_radius;
48 
51  { .out = &dict_freeradius, .proto = "freeradius" },
52  { .out = &dict_radius, .proto = "radius" }, /* @todo - remove RADIUS from the server core... */
53  { NULL }
54 };
55 
56 /** Placeholder attribute for uses of unspecified attribute references
57  */
58 extern fr_dict_attr_t const *tmpl_attr_unspec;
60 
61 
62 /** Resolve attribute #fr_pair_list_t value to an attribute list.
63  *
64  * The value returned is a pointer to the pointer of the HEAD of a #fr_pair_t list in the
65  * #request_t. If the head of the list changes, the pointer will still be valid.
66  *
67  * @param[in] request containing the target lists.
68  * @param[in] list #fr_pair_list_t value to resolve to #fr_pair_t list. Will be NULL if list
69  * name couldn't be resolved.
70  * @return a pointer to the HEAD of a list in the #request_t.
71  *
72  * @see tmpl_dcursor_init
73  */
75 {
76  if (!request) return NULL;
77 
78  if (list == request_attr_request) {
79  if (!request->packet) return NULL;
80  return &request->request_pairs;
81  }
82 
83  if (list == request_attr_reply) {
84  if (!request->reply) return NULL;
85  return &request->reply_pairs;
86  }
87 
88  if (list == request_attr_control) return &request->control_pairs;
89 
90  if (list == request_attr_state) return &request->session_state_pairs;
91 
92  if (list == request_attr_local) return &request->local_pairs;
93 
94  RWDEBUG2("List \"%s\" is not available", tmpl_list_name(list, "<INVALID>"));
95 
96  return NULL;
97 }
98 
99 /** Return the correct TALLOC_CTX to alloc #fr_pair_t in, for a list
100  *
101  * Allocating new #fr_pair_t in the context of a #request_t is usually wrong.
102  * #fr_pair_t should be allocated in the context of a #fr_packet_t, so that if the
103  * #fr_packet_t is freed before the #request_t, the associated #fr_pair_t lists are
104  * freed too.
105  *
106  * @param[in] request containing the target lists.
107  * @param[in] list #fr_pair_list_t value to resolve to TALLOC_CTX.
108  * @return
109  * - TALLOC_CTX on success.
110  * - NULL on failure.
111  *
112  * @see tmpl_pair_list
113  */
114 TALLOC_CTX *tmpl_list_ctx(request_t *request, fr_dict_attr_t const *list)
115 {
116  if (!request) return NULL;
117 
118  if (list == request_attr_request) return request->request_ctx;
119 
120  if (list == request_attr_reply) return request->reply_ctx;
121 
122  if (list == request_attr_control) return request->control_ctx;
123 
124  if (list == request_attr_state) return request->session_state_ctx;
125 
126  if (list == request_attr_local) return request->local_ctx;
127 
128  return NULL;
129 }
130 
131 /** Resolve a list to the #fr_packet_t holding the HEAD pointer for a #fr_pair_t list
132  *
133  * Returns a pointer to the #fr_packet_t that holds the HEAD pointer of a given list,
134  * for the current #request_t.
135  *
136  * @param[in] request To resolve list in.
137  * @param[in] list #fr_pair_list_t value to resolve to #fr_packet_t.
138  * @return
139  * - #fr_packet_t on success.
140  * - NULL on failure.
141  *
142  * @see tmpl_pair_list
143  */
145 {
146  if (list == request_attr_request) return request->packet;
147 
148  if (list == request_attr_reply) return request->reply;
149 
150  return NULL;
151 }
152 
153 /** Resolve a #tmpl_request_ref_t to a #request_t.
154  *
155  * Sometimes #request_t structs may be chained to each other, as is the case
156  * when internally proxying EAP. This function resolves a #tmpl_request_ref_t
157  * to a #request_t higher in the chain than the current #request_t.
158  *
159  * @see tmpl_pair_list
160  * @param[in,out] context #request_t to start resolving from, and where to write
161  * a pointer to the resolved #request_t back to.
162  * @param[in] rql list of request qualifiers to follow.
163  * @return
164  * - 0 if request is valid in this context.
165  * - -1 if request is not valid in this context.
166  */
167 int tmpl_request_ptr(request_t **context, FR_DLIST_HEAD(tmpl_request_list) const *rql)
168 {
169  tmpl_request_t *rr = NULL;
170  request_t *request = *context;
171 
172  while ((rr = tmpl_request_list_next(rql, rr))) {
173  switch (rr->request) {
174  case REQUEST_CURRENT:
175  continue; /* noop */
176 
177  case REQUEST_PARENT: /* Navigate up one level */
178  if (!request->parent) return -1;
179  request = request->parent;
180  break;
181 
182  case REQUEST_OUTER: /* Navigate to the outermost request */
183  if (!request->parent) return -1;
184  while (request->parent) request = request->parent;
185  break;
186 
187  case REQUEST_UNKNOWN:
188  default:
189  fr_assert(0);
190  return -1;
191  }
192  }
193 
194  *context = request;
195 
196  return 0;
197 }
198 
199 /** Return the native data type of the expression
200  *
201  * @param[in] vpt to determine the type of.
202  * @return
203  * - FR_TYPE_NULL if the type of the #tmpl_t can't be determined.
204  * - The data type we'd expect the #tmpl_t to produce at runtime
205  * when expanded.
206  */
208 {
209  /*
210  * Regexes can't be expanded
211  */
212  if (tmpl_contains_regex(vpt)) return FR_TYPE_NULL;
213 
214  /*
215  * Casts take precedence over everything.
216  */
218 
219  /*
220  * Anything that's not a bare word will
221  * be a string unless there's a casting
222  * operator.
223  */
224  if (vpt->quote != T_BARE_WORD) return FR_TYPE_STRING;
225 
226  switch (vpt->type) {
227  case TMPL_TYPE_ATTR:
228  return tmpl_attr_tail_da(vpt)->type;
229 
230  case TMPL_TYPE_DATA:
231  return tmpl_value_type(vpt);
232 
233  case TMPL_TYPE_XLAT:
234  case TMPL_TYPE_EXEC:
235  return FR_TYPE_STRING;
236 
237  default:
238  break;
239  }
240 
241  return FR_TYPE_NULL;
242 }
243 
244 /** Expand a #tmpl_t to a string writing the result to a buffer
245  *
246  * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #tmpl_t
247  * provided by the conf parser, into a usable value.
248  * The value returned should be raw and undoctored for #FR_TYPE_STRING and #FR_TYPE_OCTETS types,
249  * and the printable (string) version of the data for all others.
250  *
251  * Depending what arguments are passed, either copies the value to buff, or writes a pointer
252  * to a string buffer to out. This allows the most efficient access to the value resolved by
253  * the #tmpl_t, avoiding unnecessary string copies.
254  *
255  * @note This function is used where raw string values are needed, which may mean the string
256  * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint
257  * should be used before using these values in debug statements. #is_printable can be used to
258  * check if the string only contains printable chars.
259  *
260  * @param[out] out Where to write a pointer to the string buffer. On return may
261  * point to buff if buff was used to store the value. Otherwise will
262  * point to a #fr_value_box_t buffer, or the name of the template.
263  * Must not be NULL.
264  * @param[out] buff Expansion buffer, may be NULL except for the following types:
265  * - #TMPL_TYPE_EXEC
266  * - #TMPL_TYPE_XLAT
267  * @param[in] bufflen Length of expansion buffer. Must be >= 2.
268  * @param[in] request Current request.
269  * @param[in] vpt to expand. Must be one of the following types:
270  * - #TMPL_TYPE_DATA_UNRESOLVED
271  * - #TMPL_TYPE_EXEC
272  * - #TMPL_TYPE_XLAT
273  * - #TMPL_TYPE_ATTR
274  * - #TMPL_TYPE_DATA
275  * @param[in] escape xlat escape function (only used for xlat types).
276  * @param[in] escape_ctx xlat escape function data.
277  * @param dst_type FR_TYPE_* matching out pointer. @see tmpl_expand.
278  * @return
279  * - -1 on failure.
280  * - The length of data written out.
281  */
283  uint8_t *buff, size_t bufflen,
284  request_t *request,
285  tmpl_t const *vpt,
286  xlat_escape_legacy_t escape, void const *escape_ctx,
287  fr_type_t dst_type)
288 {
289  fr_value_box_t value_to_cast = FR_VALUE_BOX_INITIALISER_NULL(value_to_cast);
290  fr_value_box_t value_from_cast = FR_VALUE_BOX_INITIALISER_NULL(value_from_cast);
291  fr_value_box_t const *to_cast = &value_to_cast;
292  fr_value_box_t const *from_cast = &value_from_cast;
293 
294  fr_pair_t *vp = NULL;
295 
296  fr_type_t src_type = FR_TYPE_NULL;
297 
298  ssize_t slen = -1; /* quiet compiler */
299 
300  TMPL_VERIFY(vpt);
301 
302  fr_assert(!buff || (bufflen >= 2));
303 
304  switch (vpt->type) {
306  RDEBUG4("EXPAND TMPL UNRESOLVED");
307  fr_value_box_bstrndup_shallow(&value_to_cast, NULL, vpt->name, vpt->len, false);
308  src_type = FR_TYPE_STRING;
309  break;
310 
311  case TMPL_TYPE_EXEC:
312  {
313  RDEBUG4("EXPAND TMPL EXEC");
314  if (!buff) {
315  fr_strerror_const("Missing expansion buffer for EXEC");
316  return -1;
317  }
318 
319  if (radius_exec_program_legacy((char *)buff, bufflen, request, vpt->name, NULL,
320  true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) return -1;
321  fr_value_box_strdup_shallow(&value_to_cast, NULL, (char *)buff, true);
322  src_type = FR_TYPE_STRING;
323  }
324  break;
325 
326  case TMPL_TYPE_XLAT:
327  {
328  size_t len;
329 
330  RDEBUG4("EXPAND TMPL XLAT PARSED");
331 
332  /* No EXPAND <xlat> here as the xlat code does it */
333 
334  if (!buff) {
335  fr_strerror_const("Missing expansion buffer for XLAT_STRUCT");
336  return -1;
337  }
338  /* Error in expansion, this is distinct from zero length expansion */
339  slen = xlat_eval_compiled((char *)buff, bufflen, request, tmpl_xlat(vpt), escape, escape_ctx);
340  if (slen < 0) return slen;
341 
342  RDEBUG2(" --> %s", (char *)buff); /* Print pre-unescaping (so it's escaped) */
343 
344  /*
345  * Undo any of the escaping that was done by the
346  * xlat expansion function.
347  *
348  * @fixme We need a way of signalling xlat not to escape things.
349  */
350  len = fr_value_str_unescape(&FR_SBUFF_IN((char *)buff, slen),
351  &FR_SBUFF_IN((char *)buff, slen), SIZE_MAX, '"');
352  fr_assert(buff);
353  fr_value_box_bstrndup_shallow(&value_to_cast, NULL, (char *)buff, len, true);
354  src_type = FR_TYPE_STRING;
355  }
356  break;
357 
358  case TMPL_TYPE_ATTR:
359  {
360  int ret;
361 
362  RDEBUG4("EXPAND TMPL ATTR");
363  ret = tmpl_find_vp(&vp, request, vpt);
364  if (ret < 0) return -2;
365 
366  to_cast = &vp->data;
367  src_type = vp->vp_type;
368  }
369  break;
370 
371  case TMPL_TYPE_DATA:
372  RDEBUG4("EXPAND TMPL DATA");
373  to_cast = tmpl_value(vpt);
374  src_type = tmpl_value_type(vpt);
375  break;
376 
377  /*
378  * We should never be expanding these.
379  */
381  case TMPL_TYPE_NULL:
385  case TMPL_TYPE_REGEX:
389  case TMPL_TYPE_MAX:
390  fr_assert(0);
391  return -1;
392  }
393 
394  /*
395  * Deal with casts.
396  */
397  switch (src_type) {
398  case FR_TYPE_STRING:
399  switch (dst_type) {
400  case FR_TYPE_STRING:
401  case FR_TYPE_OCTETS:
402  from_cast = to_cast;
403  break;
404 
405  default:
406  break;
407  }
408  break;
409 
410  case FR_TYPE_OCTETS:
411  switch (dst_type) {
412  /*
413  * Need to use the expansion buffer for this conversion as
414  * we need to add a \0 terminator.
415  */
416  case FR_TYPE_STRING:
417  if (!buff) {
418  fr_strerror_const("Missing expansion buffer for octet->string cast");
419  return -1;
420  }
421  if (bufflen <= to_cast->vb_length) {
422  fr_strerror_printf("Expansion buffer too small. "
423  "Have %zu bytes, need %zu bytes", bufflen,
424  to_cast->vb_length + 1);
425  return -1;
426  }
427  memcpy(buff, to_cast->vb_octets, to_cast->vb_length);
428  buff[to_cast->vb_length] = '\0';
429 
430  fr_value_box_bstrndup_shallow(&value_from_cast, NULL,
431  (char *)buff, to_cast->vb_length, true);
432  break;
433 
434  /*
435  * Just copy the pointer. Length does not include \0.
436  */
437  case FR_TYPE_OCTETS:
438  from_cast = to_cast;
439  break;
440 
441  default:
442  break;
443  }
444  break;
445 
446  default:
447  {
448  int ret;
449  TALLOC_CTX *ctx;
450 
451  /*
452  * Same type, just set from_cast to to_cast and copy the value.
453  */
454  if (src_type == dst_type) {
455  from_cast = to_cast;
456  break;
457  }
458 
459  MEM(ctx = talloc_new(request));
460 
461  from_cast = &value_from_cast;
462 
463  /*
464  * Data type conversion...
465  */
466  ret = fr_value_box_cast(ctx, &value_from_cast, dst_type, NULL, to_cast);
467  if (ret < 0) goto error;
468 
469 
470  /*
471  * For the dynamic types we need to copy the output
472  * to the buffer. Really we need a version of fr_value_box_cast
473  * that works with buffers, but it's not a high priority...
474  */
475  switch (dst_type) {
476  case FR_TYPE_STRING:
477  if (!buff) {
478  fr_strerror_const("Missing expansion buffer to store cast output");
479  error:
480  talloc_free(ctx);
481  return -1;
482  }
483  if (from_cast->vb_length >= bufflen) {
484  fr_strerror_printf("Expansion buffer too small. "
485  "Have %zu bytes, need %zu bytes", bufflen,
486  from_cast->vb_length + 1);
487  goto error;
488  }
489  memcpy(buff, from_cast->vb_strvalue, from_cast->vb_length);
490  buff[from_cast->vb_length] = '\0';
491 
492  fr_value_box_bstrndup_shallow(&value_from_cast, NULL,
493  (char *)buff, from_cast->vb_length, from_cast->tainted);
494  break;
495 
496  case FR_TYPE_OCTETS:
497  if (!buff) {
498  fr_strerror_const("Missing expansion buffer to store cast output");
499  goto error;
500  }
501  if (from_cast->vb_length > bufflen) {
502  fr_strerror_printf("Expansion buffer too small. "
503  "Have %zu bytes, need %zu bytes", bufflen, from_cast->vb_length);
504  goto error;
505  }
506  memcpy(buff, from_cast->vb_octets, from_cast->vb_length);
507  fr_value_box_memdup_shallow(&value_from_cast, NULL,
508  buff, from_cast->vb_length, from_cast->tainted);
509  break;
510 
511  default:
512  break;
513  }
514 
515  talloc_free(ctx); /* Free any dynamically allocated memory from the cast */
516  }
517  }
518 
519  RDEBUG4("Copying %zu bytes to %p from offset %zu",
520  fr_value_box_field_sizes[dst_type], *((void **)out), fr_value_box_offsets[dst_type]);
521 
522  fr_value_box_memcpy_out(out, from_cast);
523 
524  return from_cast->vb_length;
525 }
526 
527 /** Expand a template to a string, allocing a new buffer to hold the string
528  *
529  * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #tmpl_t
530  * provided by the conf parser, into a usable value.
531  * The value returned should be raw and undoctored for #FR_TYPE_STRING and #FR_TYPE_OCTETS types,
532  * and the printable (string) version of the data for all others.
533  *
534  * This function will always duplicate values, whereas #tmpl_expand may return a pointer to an
535  * existing buffer.
536  *
537  * @note This function is used where raw string values are needed, which may mean the string
538  * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint should
539  * be used before using these values in debug statements. #is_printable can be used to check
540  * if the string only contains printable chars.
541  *
542  * @note The type (char or uint8_t) can be obtained with talloc_get_type, and may be used as a
543  * hint as to how to process or print the data.
544  *
545  * @param ctx to allocate new buffer in.
546  * @param out Where to write pointer to the new buffer.
547  * @param request Current request.
548  * @param vpt to expand. Must be one of the following types:
549  * - #TMPL_TYPE_DATA_UNRESOLVED
550  * - #TMPL_TYPE_EXEC
551  * - #TMPL_TYPE_XLAT
552  * - #TMPL_TYPE_ATTR
553  * - #TMPL_TYPE_DATA
554  * @param escape xlat escape function (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
555  * @param escape_ctx xlat escape function data (only used for TMPL_TYPE_XLAT_UNRESOLVED_* types).
556  * @param dst_type FR_TYPE_* matching out pointer. @see tmpl_aexpand.
557  * @return
558  * - -1 on failure.
559  * - The length of data written to buff, or pointed to by out.
560  */
561 ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out,
562  request_t *request,
563  tmpl_t const *vpt,
564  xlat_escape_legacy_t escape, void const *escape_ctx,
565  fr_type_t dst_type)
566 {
567  fr_value_box_t *to_cast = NULL;
568  fr_value_box_t from_cast;
569 
570  fr_pair_t *vp = NULL;
572  bool needs_dup = false;
573 
574  ssize_t slen = -1;
575  int ret;
576 
577  TALLOC_CTX *tmp_ctx = talloc_new(ctx);
578 
579  TMPL_VERIFY(vpt);
580 
581  switch (vpt->type) {
583  RDEBUG4("EXPAND TMPL DATA UNRESOLVED");
584 
585  fr_value_box_bstrndup_shallow(&value, NULL, vpt->name, vpt->len, false);
586  to_cast = &value;
587  needs_dup = true;
588  break;
589 
590  case TMPL_TYPE_EXEC:
591  {
592  char *buff;
593 
594  RDEBUG4("EXPAND TMPL EXEC");
595 
596  MEM(fr_value_box_bstr_alloc(tmp_ctx, &buff, &value, NULL, 1024, true));
597  if (radius_exec_program_legacy(buff, 1024, request, vpt->name, NULL,
598  true, false, fr_time_delta_from_sec(EXEC_TIMEOUT)) != 0) {
599  error:
600  talloc_free(tmp_ctx);
601  return slen;
602  }
603  fr_value_box_strtrim(tmp_ctx, &value);
604  to_cast = &value;
605  }
606  break;
607 
609  {
610  fr_value_box_t tmp;
611  fr_type_t src_type = FR_TYPE_STRING;
612  char *result;
613 
614  RDEBUG4("EXPAND TMPL XLAT");
615 
616  /* Error in expansion, this is distinct from zero length expansion */
617  slen = xlat_aeval(tmp_ctx, &result, request, vpt->name, escape, escape_ctx);
618  if (slen < 0) goto error;
619 
620  /*
621  * Undo any of the escaping that was done by the
622  * xlat expansion function.
623  *
624  * @fixme We need a way of signalling xlat not to escape things.
625  */
626  ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL,
627  result, (size_t)slen,
628  NULL, false);
629  if (ret < 0) goto error;
630 
631  fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted);
632  to_cast = &value;
633  }
634  break;
635 
636  case TMPL_TYPE_XLAT:
638  {
639  fr_value_box_t tmp;
640  fr_type_t src_type = FR_TYPE_STRING;
641  char *result;
642 
643  RDEBUG4("EXPAND TMPL XLAT STRUCT");
644  /* No EXPAND xlat here as the xlat code does it */
645 
646  /* Error in expansion, this is distinct from zero length expansion */
647  slen = xlat_aeval_compiled(tmp_ctx, &result, request, tmpl_xlat(vpt), escape, escape_ctx);
648  if (slen < 0) goto error;
649 
650  /*
651  * Undo any of the escaping that was done by the
652  * xlat expansion function.
653  *
654  * @fixme We need a way of signalling xlat not to escape things.
655  */
656  ret = fr_value_box_from_str(tmp_ctx, &tmp, src_type, NULL,
657  result, (size_t)slen,
658  NULL, false);
659  if (ret < 0) goto error;
660 
661  fr_value_box_bstrndup_shallow(&value, NULL, tmp.vb_strvalue, tmp.vb_length, tmp.tainted);
662  to_cast = &value;
663  }
664  break;
665 
666  case TMPL_TYPE_ATTR:
667  RDEBUG4("EXPAND TMPL ATTR");
668 
669  ret = tmpl_find_vp(&vp, request, vpt);
670  if (ret < 0) {
671  talloc_free(tmp_ctx);
672  return -2;
673  }
674 
675  fr_assert(vp);
676 
677  to_cast = &vp->data;
678  switch (to_cast->type) {
679  case FR_TYPE_STRING:
680  case FR_TYPE_OCTETS:
681  fr_assert(to_cast->datum.ptr);
682  needs_dup = true;
683  break;
684 
685  default:
686  break;
687  }
688  break;
689 
690  case TMPL_TYPE_DATA:
691  {
692  RDEBUG4("EXPAND TMPL DATA");
693 
694  to_cast = UNCONST(fr_value_box_t *, tmpl_value(vpt));
695  switch (to_cast->type) {
696  case FR_TYPE_STRING:
697  case FR_TYPE_OCTETS:
698  fr_assert(to_cast->datum.ptr);
699  needs_dup = true;
700  break;
701 
702  default:
703  break;
704  }
705  }
706  break;
707 
708  /*
709  * We should never be expanding these.
710  */
712  case TMPL_TYPE_NULL:
714  case TMPL_TYPE_REGEX:
718  case TMPL_TYPE_MAX:
719  fr_assert(0);
720  goto error;
721  }
722 
723  /*
724  * Special case where we just copy the boxed value
725  * directly instead of casting it.
726  */
727  if (dst_type == FR_TYPE_VALUE_BOX) {
728  fr_value_box_t **vb_out = (fr_value_box_t **)out;
729 
730  MEM(*vb_out = fr_value_box_alloc_null(ctx));
731 
732  ret = needs_dup ? fr_value_box_copy(*vb_out, *vb_out, to_cast) : fr_value_box_steal(*vb_out, *vb_out, to_cast);
733  talloc_free(tmp_ctx);
734  if (ret < 0) {
735  RPEDEBUG("Failed copying data to output box");
736  TALLOC_FREE(*vb_out);
737  return -1;
738  }
739  VALUE_BOX_VERIFY(*vb_out);
740  return 0;
741  }
742 
743  /*
744  * Don't dup the buffers unless we need to.
745  */
746  if ((to_cast->type != dst_type) || needs_dup) {
747  ret = fr_value_box_cast(ctx, &from_cast, dst_type, NULL, to_cast);
748  if (ret < 0) goto error;
749  } else {
750  switch (to_cast->type) {
751  case FR_TYPE_OCTETS:
752  case FR_TYPE_STRING:
753  /*
754  * Ensure we don't free the output buffer when the
755  * tmp_ctx is freed.
756  */
757  if (value.datum.ptr && (talloc_parent(value.datum.ptr) == tmp_ctx)) {
758  (void)talloc_reparent(tmp_ctx, ctx, value.datum.ptr);
759  }
760  break;
761 
762  default:
763  break;
764  }
765  fr_value_box_copy_shallow(NULL, &from_cast, to_cast);
766  }
767 
768  RDEBUG4("Copying %zu bytes to %p from offset %zu",
769  fr_value_box_field_sizes[dst_type], *((void **)out), fr_value_box_offsets[dst_type]);
770 
771  fr_value_box_memcpy_out(out, &from_cast);
772 
773  /*
774  * Frees any memory allocated for temporary buffers
775  * in this function.
776  */
777  talloc_free(tmp_ctx);
778 
779  return from_cast.vb_length;
780 }
781 
782 /** Copy pairs matching a #tmpl_t in the current #request_t
783  *
784  * @param ctx to allocate new #fr_pair_t in.
785  * @param out Where to write the copied #fr_pair_t (s).
786  * @param request The current #request_t.
787  * @param vpt specifying the #fr_pair_t type or list to copy.
788  * Must be one of the following types:
789  * - #TMPL_TYPE_ATTR
790  * @return
791  * - -1 if no matching #fr_pair_t could be found.
792  * - -2 if list could not be found (doesn't exist in current #request_t).
793  * - -3 if context could not be found (no parent #request_t available).
794  * - -4 on memory allocation error.
795  */
796 int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
797 {
798  fr_pair_t *vp;
799  fr_dcursor_t from;
801  int err;
802 
803  TMPL_VERIFY(vpt);
804 
806 
807  for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
808  vp;
809  vp = fr_dcursor_next(&from)) {
810  vp = fr_pair_copy(ctx, vp);
811  if (!vp) {
813  fr_strerror_const("Out of memory");
814  err = -4;
815  break;
816  }
818  }
819  tmpl_dcursor_clear(&cc);
820 
821  return err;
822 }
823 
824 
825 /** Copy children of pairs matching a #tmpl_t in the current #request_t
826  *
827  * @param ctx to allocate new #fr_pair_t in.
828  * @param out Where to write the copied #fr_pair_t (s).
829  * @param request The current #request_t.
830  * @param vpt specifying the #fr_pair_t type or list to copy.
831  * Must be one of the following types:
832  * - #TMPL_TYPE_ATTR
833  * @return
834  * - -1 if no matching #fr_pair_t could be found.
835  * - -2 if list could not be found (doesn't exist in current #request_t).
836  * - -3 if context could not be found (no parent #request_t available).
837  * - -4 on memory allocation error.
838  */
839 int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
840 {
841  fr_pair_t *vp;
842  fr_dcursor_t from;
844  int err;
845 
846  TMPL_VERIFY(vpt);
847 
849 
851 
852  for (vp = tmpl_dcursor_init(&err, NULL, &cc, &from, request, vpt);
853  vp;
854  vp = fr_dcursor_next(&from)) {
855  switch (vp->vp_type) {
856  case FR_TYPE_STRUCTURAL:
857  if (fr_pair_list_copy(ctx, out, &vp->vp_group) < 0) {
858  err = -4;
859  goto done;
860  }
861  break;
862 
863  default:
864  continue;
865  }
866  }
867 done:
868  tmpl_dcursor_clear(&cc);
869 
870  return err;
871 }
872 
873 
874 /** Returns the first VP matching a #tmpl_t
875  *
876  * @param[out] out where to write the retrieved vp.
877  * @param[in] request The current #request_t.
878  * @param[in] vpt specifying the #fr_pair_t type to find.
879  * Must be one of the following types:
880  * - #TMPL_TYPE_ATTR
881  * @return
882  * - 0 on success (found matching #fr_pair_t).
883  * - -1 if no matching #fr_pair_t could be found.
884  * - -2 if list could not be found (doesn't exist in current #request_t).
885  * - -3 if context could not be found (no parent #request_t available).
886  */
887 int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
888 {
889  fr_dcursor_t cursor;
891  fr_pair_t *vp;
892  int err;
893 
894  TMPL_VERIFY(vpt);
895 
896  vp = tmpl_dcursor_init(&err, request, &cc, &cursor, request, vpt);
897  tmpl_dcursor_clear(&cc);
898 
899  if (out) *out = vp;
900 
901  return err;
902 }
903 
904 /** Returns the first VP matching a #tmpl_t, or if no VPs match, creates a new one.
905  *
906  * @param[out] out where to write the retrieved or created vp.
907  * @param[in] request The current #request_t.
908  * @param[in] vpt specifying the #fr_pair_t type to retrieve or create. Must be #TMPL_TYPE_ATTR.
909  * @return
910  * - 1 on success a pair was created.
911  * - 0 on success a pair was found.
912  * - -1 if a new #fr_pair_t couldn't be found or created.
913  * - -2 if list could not be found (doesn't exist in current #request_t).
914  * - -3 if context could not be found (no parent #request_t available).
915  */
917 {
918  fr_dcursor_t cursor;
920  fr_pair_t *vp;
921  int err;
922 
923  TMPL_VERIFY(vpt);
925 
926  *out = NULL;
927 
928  vp = tmpl_dcursor_init(&err, NULL, &cc, &cursor, request, vpt);
929  tmpl_dcursor_clear(&cc);
930 
931  switch (err) {
932  case 0:
933  *out = vp;
934  return 0;
935 
936  case -1:
937  {
938  TALLOC_CTX *ctx;
940 
941  tmpl_pair_list_and_ctx(ctx, head, request, tmpl_request(vpt), tmpl_list(vpt));
942  if (!head) return -1;
943 
944  if (pair_append_by_tmpl_parent(ctx, &vp, head, vpt, true) < 0) return -1;
945 
946  *out = vp;
947  }
948  return 1;
949 
950  default:
951  return err;
952  }
953 }
954 
955 /** Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
956  *
957  * This is the simple case - just add a vp at the first place where
958  * the parents exist, or create the parents, with no attempt to handle filters.
959  *
960  * It is functionally equivalent to fr_pair_append_by_da_parent() but
961  * uses a tmpl_t to build the nested structure rather than a fr_dict_attr_t.
962  *
963  * @param[in] ctx to allocate new pair(s) in
964  * @param[out] out Leaf pair we allocated.
965  * @param[in] list to insert into.
966  * @param[in] vpt tmpl representing the attribute to add.
967  * @param[in] skip_list skip list attr ref at the head of the tmpl.
968  * @return
969  * - 0 on success.
970  * - -1 on failure.
971  */
972 int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list)
973 {
974  fr_pair_t *vp = NULL;
975  TALLOC_CTX *pair_ctx = ctx;
976  tmpl_attr_t *ar, *leaf;
977  tmpl_attr_list_head_t const *ar_list = &vpt->data.attribute.ar;
978 
979  if (!tmpl_is_attr(vpt)) {
980  error:
981  *out = NULL;
982  return -1;
983  }
984 
985  leaf = tmpl_attr_list_tail(ar_list);
986  ar = tmpl_attr_list_head(ar_list);
987  if (!ar) goto error;
988  if (skip_list && tmpl_attr_is_list_attr(ar)) ar = tmpl_attr_list_next(ar_list, ar);
989 
990  /*
991  * Walk down the tmpl ar stack looking for candidate parent
992  * attributes and then allocating the leaf.
993  */
994  while (true) {
995  if (unlikely(!ar)) goto error;
996  /*
997  * We're not at the leaf, look for a potential parent
998  */
999  if (ar != leaf) {
1000  vp = fr_pair_find_by_da(list, NULL, ar->da);
1001  /*
1002  * HACK - Pretend we didn't see this stupid key field
1003  *
1004  * If we don't have this, the code creates a key pair
1005  * and then horribly mangles its data by adding children
1006  * to it.
1007  *
1008  * We just skip one level down an don't create or update
1009  * the key pair.
1010  */
1011  if (vp && fr_dict_attr_is_key_field(ar->da) && fr_type_is_leaf(vp->data.type)) {
1012  ar = tmpl_attr_list_next(ar_list, ar);
1013  continue;
1014  }
1015  }
1016  /*
1017  * Nothing found, create the pair
1018  */
1019  if (!vp) {
1020  if (fr_pair_append_by_da(pair_ctx, &vp, list, ar->da) < 0) goto error;
1021  }
1022 
1023  /*
1024  * We're at the leaf, return
1025  */
1026  if (ar == leaf) {
1027  *out = vp;
1028  return 0;
1029  }
1030 
1031  /*
1032  * Prepare for next level
1033  */
1034  list = &vp->vp_group;
1035  pair_ctx = vp;
1036  vp = NULL;
1037  ar = tmpl_attr_list_next(ar_list, ar);
1038  }
1039 }
1040 
1041 /** Insert a value-box to a list, with casting.
1042  *
1043  * @param list to append to
1044  * @param box box to cast / append
1045  * @param vpt tmpl with cast.
1046  * @return
1047  * - <0 for "cast failed"
1048  * - 0 for success
1049  */
1050 int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *box, tmpl_t const *vpt)
1051 {
1053  (box->type == tmpl_rules_cast(vpt))) {
1054  fr_value_box_list_insert_tail(list, box);
1055  return 0;
1056  }
1057 
1058  if (fr_value_box_cast_in_place(box, box, tmpl_rules_cast(vpt), tmpl_rules_enumv(vpt)) < 0) return -1;
1059 
1060  fr_value_box_list_insert_tail(list, box);
1061  VALUE_BOX_LIST_VERIFY(list);
1062  return 0;
1063 }
1064 
1065 /** Gets the value of a real or virtual attribute
1066  *
1067  * @param[in] ctx to allocate boxed value, and buffers in.
1068  * @param[out] out Where to write the boxed value.
1069  * @param[in] request The current request.
1070  * @param[in] vpt Representing the attribute.
1071  * @return
1072  * - <0 we failed getting a value for the attribute.
1073  * - 0 we successfully evaluated the tmpl
1074  */
1075 int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
1076 {
1077  fr_pair_t *vp = NULL;
1079 
1080  fr_dcursor_t cursor;
1081  tmpl_dcursor_ctx_t cc;
1082 
1083  int ret = 0;
1084  fr_value_box_list_t list;
1085 
1087 
1088  fr_value_box_list_init(&list);
1089 
1090  /*
1091  * See if we're dealing with an attribute in the request
1092  *
1093  * This allows users to manipulate virtual attributes as if
1094  * they were real ones.
1095  */
1096  vp = tmpl_dcursor_init(NULL, NULL, &cc, &cursor, request, vpt);
1097 
1098  /*
1099  * We didn't find the VP in a list, check to see if it's
1100  * virtual. This allows the caller to "realize" the
1101  * attribute, and we then prefer the realized version to
1102  * the virtual one.
1103  */
1104  if (!vp) {
1105  /*
1106  * Zero count.
1107  */
1108  if (tmpl_attr_tail_num(vpt) == NUM_COUNT) {
1109  value = fr_value_box_alloc(ctx, FR_TYPE_UINT32, NULL);
1110  if (!value) {
1111  oom:
1112  fr_strerror_const("Out of memory");
1113  ret = -1;
1114  goto fail;
1115  }
1116  value->datum.int32 = 0;
1117  fr_value_box_list_insert_tail(&list, value);
1118  } /* Fall through to being done */
1119 
1120  goto done;
1121  }
1122 
1123  switch (tmpl_attr_tail_num(vpt)) {
1124  /*
1125  * Return a count of the VPs.
1126  */
1127  case NUM_COUNT:
1128  {
1129  uint32_t count = 0;
1130 
1131  while (vp != NULL) {
1132  count++;
1133  vp = fr_dcursor_next(&cursor);
1134  }
1135 
1136  value = fr_value_box_alloc(ctx, FR_TYPE_UINT32, NULL);
1137  if (!value) goto oom;
1138  value->datum.uint32 = count;
1139  fr_value_box_list_insert_tail(&list, value);
1140  break;
1141  }
1142 
1143  /*
1144  * Output multiple #value_box_t, one per attribute.
1145  */
1146  case NUM_ALL:
1147  /*
1148  * Loop over all matching #fr_value_pair
1149  * shallow copying buffers.
1150  */
1151  while (vp != NULL) {
1152  if (fr_type_is_structural(vp->vp_type)) {
1153  value = fr_value_box_alloc(ctx, FR_TYPE_GROUP, NULL);
1154  if (!value) goto oom;
1155 
1156  if (fr_pair_list_copy_to_box(value, &vp->vp_group) < 0) {
1157  talloc_free(value);
1158  goto oom;
1159  }
1160 
1161  } else {
1162  value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1163  if (!value) goto oom;
1164  fr_value_box_copy(value, value, &vp->data);
1165  }
1166 
1167  fr_value_box_list_insert_tail(&list, value);
1168  vp = fr_dcursor_next(&cursor);
1169  }
1170  break;
1171 
1172  default:
1173  fr_assert(fr_type_is_leaf(vp->vp_type));
1174 
1175  value = fr_value_box_alloc(ctx, vp->data.type, vp->da);
1176  if (!value) goto oom;
1177 
1178  fr_value_box_copy(value, value, &vp->data); /* Also dups taint */
1179  fr_value_box_list_insert_tail(&list, value);
1180  break;
1181  }
1182 
1183 done:
1184  /*
1185  * Evaluate casts if necessary.
1186  */
1187  if (ret == 0) {
1188  if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1189  fr_value_box_list_talloc_free(&list);
1190  ret = -1;
1191  goto fail;
1192  }
1193 
1194  fr_value_box_list_move(out, &list);
1195  }
1196 
1197 fail:
1198  tmpl_dcursor_clear(&cc);
1200  return ret;
1201 }
1202 
1203 
1204 /** Gets the value of a tmpl
1205  *
1206  * The result is returned "raw". The caller must do any escaping it desires.
1207  *
1208  * @param[in] ctx to allocate boxed value, and buffers in.
1209  * @param[out] out Where to write the boxed value.
1210  * @param[in] request The current request.
1211  * @param[in] vpt Representing the tmpl
1212  * @return
1213  * - <0 we failed getting a value for the tmpl
1214  * - 0 we successfully evaluated the tmpl
1215  */
1216 int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
1217 {
1218  char *p;
1220  fr_value_box_list_t list;
1221 
1222  if (tmpl_needs_resolving(vpt)) {
1223  fr_strerror_const("Cannot evaluate unresolved tmpl");
1224  return -1;
1225  }
1226 
1227  if (tmpl_async_required(vpt)) {
1228  fr_strerror_const("Cannot statically evaluate asynchronous expansions");
1229  return -1;
1230  }
1231 
1232  if (tmpl_contains_regex(vpt)) {
1233  fr_strerror_const("Cannot statically evaluate regular expression");
1234  return -1;
1235  }
1236 
1237  if (tmpl_is_attr(vpt)) {
1238  return tmpl_eval_pair(ctx, out, request, vpt);
1239  }
1240 
1241  if (tmpl_is_data(vpt)) {
1243 
1244  fr_value_box_copy(value, value, tmpl_value(vpt)); /* Also dups taint */
1245  goto done;
1246  }
1247 
1249 
1250  /*
1251  * @todo - respect escaping functions. But the sync
1252  * escaping uses a different method than the async ones.
1253  * And we then also need to escape the output of
1254  * tmpl_eval_pair(), too.
1255  */
1257  if (tmpl_aexpand(value, &p, request, vpt, NULL, NULL) < 0) {
1258  talloc_free(value);
1259  return -1;
1260  }
1261  fr_value_box_bstrndup_shallow(value, NULL, p, talloc_array_length(p) - 1, true);
1262 
1263  /*
1264  * Cast the results if necessary.
1265  */
1266 done:
1267  fr_value_box_list_init(&list);
1268  fr_value_box_list_insert_tail(&list, value);
1269 
1270  if (tmpl_eval_cast_in_place(&list, request, vpt) < 0) {
1271  fr_value_box_list_talloc_free(&list);
1272  return -1;
1273  }
1274 
1275  fr_value_box_list_move(out, &list);
1277 
1278  return 0;
1279 }
1280 
1281 /** Allocate a uctx for an escaping function
1282  *
1283  * @param[in] request The current request.
1284  * @param[in] escape Describing how to escape tmpl data.
1285  *
1286  * @return the uctx to pass to the escape function.
1287  */
1288 static inline void *tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
1289 {
1290  switch (escape->uctx.type) {
1292  return UNCONST(void *, escape->uctx.ptr);
1293 
1295  {
1296  void *uctx;
1297 
1298  fr_assert_msg(escape->uctx.size > 0, "TMPL_ESCAPE_UCTX_ALLOC must specify uctx.size > 0");
1299  MEM(uctx = talloc_zero_array(NULL, uint8_t, escape->uctx.size));
1300  if (escape->uctx.talloc_type) talloc_set_type(uctx, escape->uctx.talloc_type);
1301  return uctx;
1302  }
1303 
1305  fr_assert_msg(escape->uctx.func.alloc, "TMPL_ESCAPE_UCTX_ALLOC_FUNC must specify a non-null alloc.func");
1306  return escape->uctx.func.alloc(request, escape->uctx.func.uctx);
1307 
1308  default:
1309  fr_assert_msg(0, "Unknown escape uctx type %u", escape->uctx.type);
1310  return NULL;
1311  }
1312 }
1313 
1314 /** Free a uctx for an escaping function
1315  *
1316  * @param[in] escape Describing how to escape tmpl data.
1317  * @param[in] uctx The uctx to free.
1318  */
1319 static inline void tmpl_eval_escape_uctx_free(tmpl_escape_t const *escape, void *uctx)
1320 {
1321  switch (escape->uctx.type) {
1323  return;
1324 
1326  talloc_free(uctx);
1327  return;
1328 
1330  if (escape->uctx.func.free) escape->uctx.func.free(uctx);
1331  return;
1332  }
1333 }
1334 
1335 /** Casts a value or list of values according to the tmpl
1336  *
1337  * @param[in,out] list Where to write the boxed value.
1338  * @param[in] request The current request.
1339  * @param[in] vpt Representing the attribute.
1340  * @return
1341  * - <0 the cast failed
1342  * - 0 we successfully evaluated the tmpl
1343  */
1344 int tmpl_eval_cast_in_place(fr_value_box_list_t *list, request_t *request, tmpl_t const *vpt)
1345 {
1346  fr_type_t cast = tmpl_rules_cast(vpt);
1347  bool did_concat = false;
1348  void *uctx = NULL;
1349 
1350  if (fr_type_is_structural(cast)) {
1351  fr_strerror_printf("Cannot cast to structural type '%s'", fr_type_to_str(cast));
1352  return -1;
1353  }
1354 
1355  /*
1356  * Quoting around the tmpl means everything
1357  * needs to be concatenated, either as a string
1358  * or octets string.
1359  */
1360  switch (vpt->quote) {
1364  case T_BACK_QUOTED_STRING:
1365  {
1366  ssize_t slen;
1367  fr_value_box_t *vb;
1368 
1369  vb = fr_value_box_list_head(list);
1370  if (!vb) return 0;
1371 
1372  if (tmpl_escape_pre_concat(vpt)) {
1373  uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1374  /*
1375  * Sets escaped values, so boxes don't get re-escaped
1376  */
1377  if (unlikely(fr_value_box_list_escape_in_place(list, vpt->rules.escape.func,
1378  vpt->rules.escape.safe_for, uctx) < 0)) {
1379  error:
1380  tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1381  return -1;
1382  }
1383  }
1384 
1386  FR_VALUE_BOX_LIST_FREE_BOX, true, SIZE_MAX);
1387  if (slen < 0) goto error;
1388  VALUE_BOX_LIST_VERIFY(list);
1389 
1390  /*
1391  * If there's no cast, or it's a cast to
1392  * a string, we're done!
1393  *
1394  * Otherwise we now need to re-cast the
1395  * result.
1396  */
1397  if (fr_type_is_null(cast) || fr_type_is_string(cast)) {
1398  success:
1399  tmpl_eval_escape_uctx_free(&vpt->rules.escape, uctx);
1400  return 0;
1401  }
1402 
1403  did_concat = true;
1404  }
1405  break;
1406 
1407  default:
1408  break;
1409  }
1410 
1411  if (fr_type_is_null(cast)) goto success;
1412 
1413  /*
1414  * Quoting above handled all concatenation,
1415  * we now need to handle potentially
1416  * multivalued lists.
1417  */
1418  fr_value_box_list_foreach_safe(list, vb) {
1419  if (fr_value_box_cast_in_place(vb, vb, cast, NULL) < 0) goto error;
1420  }}
1421 
1422  /*
1423  * ...and finally, apply the escape function
1424  * if necessary. This is done last so that
1425  * the escape function gets boxes of the type
1426  * it expects.
1427  */
1429  uctx = tmpl_eval_escape_uctx_alloc(request, &vpt->rules.escape);
1430  if (unlikely(fr_value_box_list_escape_in_place(list, vpt->rules.escape.func,
1431  vpt->rules.escape.safe_for, uctx) < 0)) goto error;
1432  }
1433 
1434  /*
1435  * If there's no escape function, but there is
1436  * an escaped value, mark all the boxes up with
1437  * this value.
1438  *
1439  * This is mostly useful for call_env usage in
1440  * modules where certain values are implicitly safe
1441  * for consumption, like SQL statements in the SQL
1442  * module.
1443  */
1444  if (!vpt->rules.escape.func && vpt->rules.escape.safe_for) {
1445  fr_value_box_list_mark_safe_for(list, vpt->rules.escape.safe_for);
1446  }
1447 
1449 
1450  goto success;
1451 }
1452 
1454 {
1455  fr_dict_attr_t *da;
1456 
1457  if (fr_dict_autoload(tmpl_dict) < 0) {
1458  PERROR("%s", __FUNCTION__);
1459  return -1;
1460  }
1461 
1463  fr_assert(da != NULL);
1464 
1465  da->type = FR_TYPE_NULL;
1466  tmpl_attr_unspec = da;
1467 
1468  return 0;
1469 }
1470 
1472 {
1474 
1476 }
static int context
Definition: radmin.c:71
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition: build.h:165
#define RCSID(id)
Definition: build.h:444
#define unlikely(_x)
Definition: build.h:378
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition: dcursor.h:287
#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
void fr_dict_unknown_free(fr_dict_attr_t const **da)
Free dynamically allocated (unknown attributes)
Definition: dict_unknown.c:148
#define fr_dict_autofree(_to_free)
Definition: dict.h:674
static fr_slen_t err
Definition: dict.h:645
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition: dict.h:263
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict_util.c:1997
#define fr_dict_autoload(_to_load)
Definition: dict.h:671
#define fr_dict_attr_is_key_field(_da)
Definition: dict.h:149
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
Definition: dict_unknown.c:345
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition: dict.h:262
Test enumeration values.
Definition: dict_test.h:92
#define EXEC_TIMEOUT
Default wait time for exec calls (in seconds).
Definition: exec.h:32
int radius_exec_program_legacy(char *out, size_t outlen, request_t *request, char const *cmd, fr_pair_list_t *input_pairs, bool exec_wait, bool shell_escape, fr_time_delta_t timeout)
Execute a program.
Definition: exec_legacy.c:474
#define PERROR(_fmt,...)
Definition: log.h:228
#define RWDEBUG2(fmt,...)
Definition: log.h:362
#define RPEDEBUG(fmt,...)
Definition: log.h:376
#define RDEBUG4(fmt,...)
Definition: log.h:344
talloc_free(reap)
typedef FR_DLIST_HEAD(map_list) map_list_t
Given these are used in so many places, it's more friendly to have a proper type.
size_t(* xlat_escape_legacy_t)(request_t *request, char *out, size_t outlen, char const *in, void *arg)
Definition: merged_model.c:213
fr_type_t
Definition: merged_model.c:80
@ FR_TYPE_STRING
String of printable characters.
Definition: merged_model.c:83
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
Definition: merged_model.c:81
@ FR_TYPE_VALUE_BOX
A boxed value.
Definition: merged_model.c:125
@ FR_TYPE_UINT32
32 Bit unsigned integer.
Definition: merged_model.c:99
@ FR_TYPE_OCTETS
Raw octets.
Definition: merged_model.c:84
@ FR_TYPE_GROUP
A grouping of other attributes.
Definition: merged_model.c:124
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
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:688
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
Definition: pair.c:1461
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition: pair.c:2316
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
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition: pair.c:484
int fr_pair_list_copy_to_box(fr_value_box_t *dst, fr_pair_list_t *from)
Copy the contents of a pair list to a set of value-boxes.
Definition: pair.c:2351
static bool done
Definition: radclient.c:80
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
fr_dict_attr_t const * request_attr_request
Definition: request.c:41
fr_dict_attr_t const * request_attr_control
Definition: request.c:43
fr_dict_attr_t const * request_attr_local
Definition: request.c:45
fr_dict_attr_t const * request_attr_state
Definition: request.c:44
fr_dict_attr_t const * request_attr_reply
Definition: request.c:42
#define FR_SBUFF_IN(_start, _len_or_end)
static int16_t tmpl_attr_tail_num(tmpl_t const *vpt)
Return the last attribute reference's attribute number.
Definition: tmpl.h:880
#define TMPL_VERIFY(_vpt)
Definition: tmpl.h:953
#define tmpl_is_xlat(vpt)
Definition: tmpl.h:215
#define tmpl_rules_enumv(_tmpl)
Definition: tmpl.h:938
static fr_slen_t vpt
Definition: tmpl.h:1260
#define tmpl_value(_tmpl)
Definition: tmpl.h:932
static char const * tmpl_list_name(fr_dict_attr_t const *list, char const *def)
Return the name of a tmpl list or def if list not provided.
Definition: tmpl.h:910
#define tmpl_contains_regex(vpt)
Definition: tmpl.h:230
static fr_dict_attr_t const * tmpl_attr_tail_da(tmpl_t const *vpt)
Return the last attribute reference da.
Definition: tmpl.h:796
#define tmpl_is_attr(vpt)
Definition: tmpl.h:213
#define NUM_ALL
Definition: tmpl.h:400
bool tmpl_async_required(tmpl_t const *vpt)
Return whether or not async is required for this tmpl.
#define tmpl_xlat(_tmpl)
Definition: tmpl.h:925
static bool tmpl_attr_is_list_attr(tmpl_attr_t const *ar)
Return true if the tmpl_attr is one of the list types.
Definition: tmpl.h:674
#define tmpl_rules_cast(_tmpl)
Definition: tmpl.h:937
@ TMPL_TYPE_REGEX_UNCOMPILED
Regex where compilation is possible but hasn't been performed yet.
Definition: tmpl.h:162
@ TMPL_TYPE_MAX
Marker for the last tmpl type.
Definition: tmpl.h:203
@ TMPL_TYPE_ATTR_UNRESOLVED
An attribute reference that we couldn't resolve but looked valid.
Definition: tmpl.h:189
@ TMPL_TYPE_ATTR
Reference to one or more attributes.
Definition: tmpl.h:146
@ TMPL_TYPE_XLAT
Pre-parsed xlat expansion.
Definition: tmpl.h:150
@ TMPL_TYPE_NULL
Has no value.
Definition: tmpl.h:138
@ TMPL_TYPE_EXEC
Callout to an external script or program.
Definition: tmpl.h:154
@ TMPL_TYPE_REGEX_XLAT_UNRESOLVED
A regular expression with unresolved xlat functions or attribute references.
Definition: tmpl.h:201
@ TMPL_TYPE_DATA
Value in native boxed format.
Definition: tmpl.h:142
@ TMPL_TYPE_REGEX
Compiled (and possibly JIT'd) regular expression.
Definition: tmpl.h:158
@ TMPL_TYPE_DATA_UNRESOLVED
Unparsed literal string.
Definition: tmpl.h:183
@ TMPL_TYPE_XLAT_UNRESOLVED
A xlat expansion with unresolved xlat functions or attribute references.
Definition: tmpl.h:197
@ TMPL_TYPE_REGEX_XLAT
A regex containing xlat expansions.
Definition: tmpl.h:166
@ TMPL_TYPE_EXEC_UNRESOLVED
An exec with unresolved xlat function or attribute references.
Definition: tmpl.h:193
@ TMPL_TYPE_UNINITIALISED
Uninitialised.
Definition: tmpl.h:134
#define NUM_COUNT
Definition: tmpl.h:401
#define tmpl_pair_list_and_ctx(_ctx, _head, _request, _ref, _list)
Determine the correct context and list head.
Definition: tmpl.h:985
#define tmpl_is_data(vpt)
Definition: tmpl.h:211
#define tmpl_value_type(_tmpl)
Definition: tmpl.h:934
@ REQUEST_OUTER
request_t containing the outer layer of the EAP conversation.
Definition: tmpl.h:92
@ REQUEST_PARENT
Parent (whatever it is).
Definition: tmpl.h:96
@ REQUEST_UNKNOWN
Unknown request.
Definition: tmpl.h:97
@ REQUEST_CURRENT
The current request (default).
Definition: tmpl.h:91
static fr_dict_attr_t const * tmpl_list(tmpl_t const *vpt)
Definition: tmpl.h:899
#define tmpl_aexpand(_ctx, _out, _request, _vpt, _escape, _escape_ctx)
Expand a tmpl to a C type, allocing a new buffer to hold the string.
Definition: tmpl.h:1054
#define tmpl_needs_resolving(vpt)
Definition: tmpl.h:228
static char buff[sizeof("18446744073709551615")+3]
Definition: size_tests.c:41
return count
Definition: module.c:175
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
fr_dict_attr_t const *_CONST da
Resolved dictionary attribute.
Definition: tmpl.h:431
Define manipulation functions for the attribute reference list.
Definition: tmpl.h:468
tmpl_request_ref_t _CONST request
Definition: tmpl.h:472
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
Functions which we wish were included in the standard talloc distribution.
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition: time.h:588
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
Definition: tmpl_dcursor.c:419
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Definition: tmpl_dcursor.h:99
Maintains state between cursor calls.
Definition: tmpl_dcursor.h:61
fr_value_box_escape_t func
How to escape when returned from evaluation.
Definition: tmpl_escape.h:81
#define tmpl_escape_post_concat(_tmpl)
See if we should perform output escaping after concatenation.
Definition: tmpl_escape.h:123
struct tmpl_escape_t::@72 uctx
#define tmpl_escape_pre_concat(_tmpl)
See if we should perform output escaping before concatenation.
Definition: tmpl_escape.h:118
@ TMPL_ESCAPE_UCTX_ALLOC
A new uctx of the specified size and type is allocated and freed when escaping is complete.
Definition: tmpl_escape.h:33
@ TMPL_ESCAPE_UCTX_STATIC
A static (to us) is provided by whatever is initialising the tmpl_escape_t.
Definition: tmpl_escape.h:31
@ TMPL_ESCAPE_UCTX_ALLOC_FUNC
A new uctx of the specified size and type is allocated and pre-populated by memcpying uctx....
Definition: tmpl_escape.h:35
Escaping rules for tmpls.
Definition: tmpl_escape.h:80
int tmpl_find_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
Returns the first VP matching a tmpl_t.
Definition: tmpl_eval.c:887
fr_packet_t * tmpl_packet_ptr(request_t *request, fr_dict_attr_t const *list)
Resolve a list to the fr_packet_t holding the HEAD pointer for a fr_pair_t list.
Definition: tmpl_eval.c:144
TALLOC_CTX * tmpl_list_ctx(request_t *request, fr_dict_attr_t const *list)
Return the correct TALLOC_CTX to alloc fr_pair_t in, for a list.
Definition: tmpl_eval.c:114
int tmpl_value_list_insert_tail(fr_value_box_list_t *list, fr_value_box_t *box, tmpl_t const *vpt)
Insert a value-box to a list, with casting.
Definition: tmpl_eval.c:1050
fr_dict_attr_t const * tmpl_attr_unspec
Placeholder attribute for uses of unspecified attribute references.
Definition: tmpl_eval.c:59
static fr_dict_t const * dict_freeradius
Definition: tmpl_eval.c:46
static fr_dict_t const * dict_radius
Definition: tmpl_eval.c:47
int tmpl_request_ptr(request_t **context, FR_DLIST_HEAD(tmpl_request_list) const *rql)
Resolve a tmpl_request_ref_t to a request_t.
Definition: tmpl_eval.c:167
int tmpl_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
Gets the value of a tmpl.
Definition: tmpl_eval.c:1216
int tmpl_eval_cast_in_place(fr_value_box_list_t *list, request_t *request, tmpl_t const *vpt)
Casts a value or list of values according to the tmpl.
Definition: tmpl_eval.c:1344
void tmpl_global_free(void)
Definition: tmpl_eval.c:1471
fr_pair_list_t * tmpl_list_head(request_t *request, fr_dict_attr_t const *list)
Resolve attribute fr_pair_list_t value to an attribute list.
Definition: tmpl_eval.c:74
ssize_t _tmpl_to_atype(TALLOC_CTX *ctx, void *out, request_t *request, tmpl_t const *vpt, xlat_escape_legacy_t escape, void const *escape_ctx, fr_type_t dst_type)
Expand a template to a string, allocing a new buffer to hold the string.
Definition: tmpl_eval.c:561
int tmpl_global_init(void)
Definition: tmpl_eval.c:1453
int tmpl_eval_pair(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, tmpl_t const *vpt)
Gets the value of a real or virtual attribute.
Definition: tmpl_eval.c:1075
ssize_t _tmpl_to_type(void *out, uint8_t *buff, size_t bufflen, request_t *request, tmpl_t const *vpt, xlat_escape_legacy_t escape, void const *escape_ctx, fr_type_t dst_type)
Expand a tmpl_t to a string writing the result to a buffer.
Definition: tmpl_eval.c:282
goto success
Definition: tmpl_eval.c:1450
int tmpl_copy_pair_children(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
Copy children of pairs matching a tmpl_t in the current request_t.
Definition: tmpl_eval.c:839
static void * tmpl_eval_escape_uctx_alloc(request_t *request, tmpl_escape_t const *escape)
Allocate a uctx for an escaping function.
Definition: tmpl_eval.c:1288
int tmpl_copy_pairs(TALLOC_CTX *ctx, fr_pair_list_t *out, request_t *request, tmpl_t const *vpt)
Copy pairs matching a tmpl_t in the current request_t.
Definition: tmpl_eval.c:796
static void tmpl_eval_escape_uctx_free(tmpl_escape_t const *escape, void *uctx)
Free a uctx for an escaping function.
Definition: tmpl_eval.c:1319
VALUE_BOX_LIST_VERIFY(list)
int tmpl_find_or_add_vp(fr_pair_t **out, request_t *request, tmpl_t const *vpt)
Returns the first VP matching a tmpl_t, or if no VPs match, creates a new one.
Definition: tmpl_eval.c:916
fr_dict_autoload_t tmpl_dict[]
Definition: tmpl_eval.c:50
fr_type_t tmpl_expanded_type(tmpl_t const *vpt)
Return the native data type of the expression.
Definition: tmpl_eval.c:207
int pair_append_by_tmpl_parent(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, tmpl_t const *vpt, bool skip_list)
Allocate and insert a leaf vp from a tmpl_t, building the parent vps if needed.
Definition: tmpl_eval.c:972
@ T_SINGLE_QUOTED_STRING
Definition: token.h:122
@ T_BARE_WORD
Definition: token.h:120
@ T_BACK_QUOTED_STRING
Definition: token.h:123
@ T_DOUBLE_QUOTED_STRING
Definition: token.h:121
@ T_SOLIDUS_QUOTED_STRING
Definition: token.h:124
ssize_t xlat_eval_compiled(char *out, size_t outlen, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition: xlat_eval.c:1462
static fr_slen_t head
Definition: xlat.h:408
ssize_t xlat_aeval_compiled(TALLOC_CTX *ctx, char **out, request_t *request, xlat_exp_head_t const *head, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition: xlat_eval.c:1479
ssize_t xlat_aeval(TALLOC_CTX *ctx, char **out, request_t *request, char const *fmt, xlat_escape_legacy_t escape, void const *escape_ctx))
Definition: xlat_eval.c:1470
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
Definition: pair_inline.c:113
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
#define fr_strerror_const(_msg)
Definition: strerror.h:223
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
Definition: types.h:433
#define fr_type_is_structural(_x)
Definition: types.h:371
#define fr_type_is_string(_x)
Definition: types.h:327
#define FR_TYPE_STRUCTURAL
Definition: types.h:296
#define fr_type_is_null(_x)
Definition: types.h:326
#define fr_type_is_leaf(_x)
Definition: types.h:372
size_t const fr_value_box_field_sizes[]
How many bytes wide each of the value data fields are.
Definition: value.c:149
ssize_t fr_value_box_from_str(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, char const *in, size_t inlen, fr_sbuff_unescape_rules_t const *erules, bool tainted)
Definition: value.c:5264
int fr_value_box_strtrim(TALLOC_CTX *ctx, fr_value_box_t *vb)
Trim the length of the string buffer to match the length of the C string.
Definition: value.c:3902
int fr_value_box_list_escape_in_place(fr_value_box_list_t *list, fr_value_box_escape_t escape, fr_value_box_safe_for_t safe_for, void *uctx)
Escape a list of value boxes in place.
Definition: value.c:5930
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition: value.c:3301
size_t const fr_value_box_offsets[]
Where the value starts in the fr_value_box_t.
Definition: value.c:189
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:3689
int fr_value_box_cast_in_place(TALLOC_CTX *ctx, fr_value_box_t *vb, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv)
Convert one type of fr_value_box_t to another in place.
Definition: value.c:3521
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
Definition: value.c:4497
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
Definition: value.c:3783
size_t fr_value_str_unescape(fr_sbuff_t *out, fr_sbuff_t *in, size_t inlen, char quote)
Convert a string value with escape sequences into its binary form.
Definition: value.c:1083
void fr_value_box_list_mark_safe_for(fr_value_box_list_t *list, fr_value_box_safe_for_t safe_for)
Set the escaped flag for all value boxes in a list.
Definition: value.c:6261
void fr_value_box_strdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Assign a buffer containing a nul terminated string to a box, but don't copy it.
Definition: value.c:3985
int fr_value_box_bstr_alloc(TALLOC_CTX *ctx, char **out, fr_value_box_t *dst, fr_dict_attr_t const *enumv, size_t len, bool tainted)
Alloc and assign an empty \0 terminated string to a fr_value_box_t.
Definition: value.c:4020
int fr_value_box_steal(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t *src)
Copy value data verbatim moving any buffers to the specified context.
Definition: value.c:3807
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
Definition: value.c:4181
int fr_value_box_list_concat_in_place(TALLOC_CTX *ctx, fr_value_box_t *out, fr_value_box_list_t *list, fr_type_t type, fr_value_box_list_action_t proc_action, bool flatten, size_t max_size)
Concatenate a list of value boxes.
Definition: value.c:5725
@ FR_VALUE_BOX_LIST_FREE_BOX
Free each processed box.
Definition: value.h:211
#define fr_value_box_list_foreach_safe(_list_head, _iter)
Definition: value.h:200
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition: value.h:608
static int fr_value_box_memcpy_out(void *out, fr_value_box_t const *vb)
Copy the value of a value box to a field in a C struct.
Definition: value.h:751
#define vb_length
Definition: value.h:265
#define FR_VALUE_BOX_INITIALISER_NULL(_vb)
A static initialiser for stack/globally allocated boxes.
Definition: value.h:475
#define VALUE_BOX_VERIFY(_x)
Definition: value.h:1291
#define fr_value_box_alloc_null(_ctx)
Allocate a value box for later use with a value assignment function.
Definition: value.h:619
static size_t char ** out
Definition: value.h:984