All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tmpl.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: 6769d5a08663f1efbddab110468dd57147bb33dd $
19  *
20  * @brief #VALUE_PAIR template functions
21  * @file main/tmpl.c
22  *
23  * @ingroup AVP
24  *
25  * @copyright 2014-2015 The FreeRADIUS server project
26  */
27 RCSID("$Id: 6769d5a08663f1efbddab110468dd57147bb33dd $")
28 
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/rad_assert.h>
31 
32 #include <ctype.h>
33 
34 /** Map #tmpl_type_t values to descriptive strings
35  */
37  { "literal", TMPL_TYPE_UNPARSED },
38  { "xlat", TMPL_TYPE_XLAT },
39  { "attr", TMPL_TYPE_ATTR },
40  { "unknown attr", TMPL_TYPE_ATTR_UNDEFINED },
41  { "list", TMPL_TYPE_LIST },
42  { "regex", TMPL_TYPE_REGEX },
43  { "exec", TMPL_TYPE_EXEC },
44  { "data", TMPL_TYPE_DATA },
45  { "parsed xlat", TMPL_TYPE_XLAT_STRUCT },
46  { "parsed regex", TMPL_TYPE_REGEX_STRUCT },
47  { "null", TMPL_TYPE_NULL },
48  { NULL, 0 }
49 };
50 
51 /** Map keywords to #pair_lists_t values
52  */
54  { "request", PAIR_LIST_REQUEST },
55  { "reply", PAIR_LIST_REPLY },
56  { "control", PAIR_LIST_CONTROL }, /* New name should have priority */
57  { "config", PAIR_LIST_CONTROL },
58  { "session-state", PAIR_LIST_STATE },
59 #ifdef WITH_PROXY
60  { "proxy-request", PAIR_LIST_PROXY_REQUEST },
61  { "proxy-reply", PAIR_LIST_PROXY_REPLY },
62 #endif
63 #ifdef WITH_COA
64  { "coa", PAIR_LIST_COA },
65  { "coa-reply", PAIR_LIST_COA_REPLY },
66  { "disconnect", PAIR_LIST_DM },
67  { "disconnect-reply", PAIR_LIST_DM_REPLY },
68 #endif
69  { NULL , -1 }
70 };
71 
72 /** Map keywords to #request_refs_t values
73  */
75  { "outer", REQUEST_OUTER },
76  { "current", REQUEST_CURRENT },
77  { "parent", REQUEST_PARENT },
78  { NULL , -1 }
79 };
80 
81 /** @name Parse list and request qualifiers to #pair_lists_t and #request_refs_t values
82  *
83  * These functions also resolve #pair_lists_t and #request_refs_t values to #REQUEST
84  * structs and the head of #VALUE_PAIR lists in those structs.
85  *
86  * For adding new #VALUE_PAIR to the lists, the #radius_list_ctx function can be used
87  * to obtain the appropriate TALLOC_CTX pointer.
88  *
89  * @note These don't really have much to do with #vp_tmpl_t. They're in the same
90  * file as they're used almost exclusively by the tmpl_* functions.
91  * @{
92  */
93 
94 /** Resolve attribute name to a #pair_lists_t value.
95  *
96  * Check the name string for #pair_lists qualifiers and write a #pair_lists_t value
97  * for that list to out. This value may be passed to #radius_list, along with the current
98  * #REQUEST, to get a pointer to the actual list in the #REQUEST.
99  *
100  * If we're sure we've definitely found a list qualifier token delimiter (``:``) but the
101  * string doesn't match a #radius_list qualifier, return 0 and write #PAIR_LIST_UNKNOWN
102  * to out.
103  *
104  * If we can't find a string that looks like a request qualifier, set out to def, and
105  * return 0.
106  *
107  * @note #radius_list_name should be called before passing a name string that may
108  * contain qualifiers to #fr_dict_attr_by_name.
109  *
110  * @param[out] out Where to write the list qualifier.
111  * @param[in] name String containing list qualifiers to parse.
112  * @param[in] def the list to return if no qualifiers were found.
113  * @return 0 if no valid list qualifier could be found, else the number of bytes consumed.
114  * The caller may then advanced the name pointer by the value returned, to get the
115  * start of the attribute name (if any).
116  *
117  * @see pair_list
118  * @see radius_list
119  */
120 size_t radius_list_name(pair_lists_t *out, char const *name, pair_lists_t def)
121 {
122  char const *p = name;
123  char const *q;
124 
125  /* This should never be a NULL pointer */
126  rad_assert(name);
127 
128  /*
129  * Try and determine the end of the token
130  */
131  for (q = p; fr_dict_attr_allowed_chars[(uint8_t) *q]; q++);
132 
133  switch (*q) {
134  /*
135  * It's a bareword made up entirely of dictionary chars
136  * check and see if it's a list qualifier, and if it's
137  * not, return the def and say we couldn't parse
138  * anything.
139  */
140  case '\0':
141  *out = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
142  if (*out != PAIR_LIST_UNKNOWN) return q - p;
143  *out = def;
144  return 0;
145 
146  /*
147  * It may be a list qualifier delimiter. Because of tags
148  * We need to check that it doesn't look like a tag suffix.
149  * We do this by looking at the chars between ':' and the
150  * next token delimiter, and seeing if they're all digits.
151  */
152  case ':':
153  {
154  char const *d = q + 1;
155 
156  if (isdigit((int) *d)) {
157  while (isdigit((int) *d)) d++;
158 
159  /*
160  * Char after the number string
161  * was a token delimiter, so this is a
162  * tag, not a list qualifier.
163  */
164  if (!fr_dict_attr_allowed_chars[(uint8_t) *d]) {
165  *out = def;
166  return 0;
167  }
168  }
169 
170  *out = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
171  if (*out == PAIR_LIST_UNKNOWN) return 0;
172 
173  return (q + 1) - name; /* Consume the list and delimiter */
174  }
175 
176  default:
177  *out = def;
178  return 0;
179  }
180 }
181 
182 /** Resolve attribute #pair_lists_t value to an attribute list.
183  *
184  * The value returned is a pointer to the pointer of the HEAD of a #VALUE_PAIR list in the
185  * #REQUEST. If the head of the list changes, the pointer will still be valid.
186  *
187  * @param[in] request containing the target lists.
188  * @param[in] list #pair_lists_t value to resolve to #VALUE_PAIR list. Will be NULL if list
189  * name couldn't be resolved.
190  * @return a pointer to the HEAD of a list in the #REQUEST.
191  *
192  * @see tmpl_cursor_init
193  * @see fr_cursor_init
194  */
196 {
197  if (!request) return NULL;
198 
199  switch (list) {
200  /* Don't add default */
201  case PAIR_LIST_UNKNOWN:
202  break;
203 
204  case PAIR_LIST_REQUEST:
205  if (!request->packet) return NULL;
206  return &request->packet->vps;
207 
208  case PAIR_LIST_REPLY:
209  if (!request->reply) return NULL;
210  return &request->reply->vps;
211 
212  case PAIR_LIST_CONTROL:
213  return &request->config;
214 
215  case PAIR_LIST_STATE:
216  return &request->state;
217 
218 #ifdef WITH_PROXY
220  if (!request->proxy) break;
221  return &request->proxy->vps;
222 
224  if (!request->proxy_reply) break;
225  return &request->proxy_reply->vps;
226 #endif
227 #ifdef WITH_COA
228  case PAIR_LIST_COA:
229  if (request->coa &&
230  (request->coa->proxy->code == PW_CODE_COA_REQUEST)) {
231  return &request->coa->proxy->vps;
232  }
233  break;
234 
235  case PAIR_LIST_COA_REPLY:
236  if (request->coa && /* match reply with request */
237  (request->coa->proxy->code == PW_CODE_COA_REQUEST) &&
238  request->coa->proxy_reply) {
239  return &request->coa->proxy_reply->vps;
240  }
241  break;
242 
243  case PAIR_LIST_DM:
244  if (request->coa &&
245  (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST)) {
246  return &request->coa->proxy->vps;
247  }
248  break;
249 
250  case PAIR_LIST_DM_REPLY:
251  if (request->coa && /* match reply with request */
252  (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST) &&
253  request->coa->proxy_reply) {
254  return &request->coa->proxy->vps;
255  }
256  break;
257 #endif
258  }
259 
260  RWDEBUG2("List \"%s\" is not available",
261  fr_int2str(pair_lists, list, "<INVALID>"));
262 
263  return NULL;
264 }
265 
266 /** Resolve a list to the #RADIUS_PACKET holding the HEAD pointer for a #VALUE_PAIR list
267  *
268  * Returns a pointer to the #RADIUS_PACKET that holds the HEAD pointer of a given list,
269  * for the current #REQUEST.
270  *
271  * @param[in] request To resolve list in.
272  * @param[in] list #pair_lists_t value to resolve to #RADIUS_PACKET.
273  * @return
274  * - #RADIUS_PACKET on success.
275  * - NULL on failure.
276  *
277  * @see radius_list
278  */
280 {
281  switch (list) {
282  /* Don't add default */
283  case PAIR_LIST_STATE:
284  case PAIR_LIST_CONTROL:
285  case PAIR_LIST_UNKNOWN:
286  return NULL;
287 
288  case PAIR_LIST_REQUEST:
289  return request->packet;
290 
291  case PAIR_LIST_REPLY:
292  return request->reply;
293 
294 #ifdef WITH_PROXY
296  return request->proxy;
297 
299  return request->proxy_reply;
300 #endif
301 
302 #ifdef WITH_COA
303  case PAIR_LIST_COA:
304  case PAIR_LIST_DM:
305  return request->coa->packet;
306 
307  case PAIR_LIST_COA_REPLY:
308  case PAIR_LIST_DM_REPLY:
309  return request->coa->reply;
310 #endif
311  }
312 
313  return NULL;
314 }
315 
316 /** Return the correct TALLOC_CTX to alloc #VALUE_PAIR in, for a list
317  *
318  * Allocating new #VALUE_PAIR in the context of a #REQUEST is usually wrong.
319  * #VALUE_PAIR should be allocated in the context of a #RADIUS_PACKET, so that if the
320  * #RADIUS_PACKET is freed before the #REQUEST, the associated #VALUE_PAIR lists are
321  * freed too.
322  *
323  * @param[in] request containing the target lists.
324  * @param[in] list #pair_lists_t value to resolve to TALLOC_CTX.
325  * @return
326  * - TALLOC_CTX on success.
327  * - NULL on failure.
328  *
329  * @see radius_list
330  */
331 TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list)
332 {
333  if (!request) return NULL;
334 
335  switch (list) {
336  case PAIR_LIST_REQUEST:
337  return request->packet;
338 
339  case PAIR_LIST_REPLY:
340  return request->reply;
341 
342  case PAIR_LIST_CONTROL:
343  return request;
344 
345  case PAIR_LIST_STATE:
346  return request->state_ctx;
347 
348 #ifdef WITH_PROXY
350  return request->proxy;
351 
353  return request->proxy_reply;
354 #endif
355 
356 #ifdef WITH_COA
357  case PAIR_LIST_COA:
358  if (!request->coa) return NULL;
359  rad_assert(request->coa->proxy != NULL);
360  if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
361  return request->coa->proxy;
362 
363  case PAIR_LIST_COA_REPLY:
364  if (!request->coa) return NULL;
365  rad_assert(request->coa->proxy != NULL);
366  if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
367  return request->coa->proxy_reply;
368 
369  case PAIR_LIST_DM:
370  if (!request->coa) return NULL;
371  rad_assert(request->coa->proxy != NULL);
372  if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
373  return request->coa->proxy;
374 
375  case PAIR_LIST_DM_REPLY:
376  if (!request->coa) return NULL;
377  rad_assert(request->coa->proxy != NULL);
378  if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
379  return request->coa->proxy_reply;
380 #endif
381  /* Don't add default */
382  case PAIR_LIST_UNKNOWN:
383  break;
384  }
385 
386  return NULL;
387 }
388 
389 /** Resolve attribute name to a #request_refs_t value.
390  *
391  * Check the name string for qualifiers that reference a parent #REQUEST.
392  *
393  * If we find a string that matches a #request_refs qualifier, return the number of chars
394  * we consumed.
395  *
396  * If we're sure we've definitely found a list qualifier token delimiter (``*``) but the
397  * qualifier doesn't match one of the #request_refs qualifiers, return 0 and set out to
398  * #REQUEST_UNKNOWN.
399  *
400  * If we can't find a string that looks like a request qualifier, set out to def, and
401  * return 0.
402  *
403  * @param[out] out The #request_refs_t value the name resolved to (or #REQUEST_UNKNOWN).
404  * @param[in] name of attribute.
405  * @param[in] def default request ref to return if no request qualifier is present.
406  * @return 0 if no valid request qualifier could be found, else the number of bytes consumed.
407  * The caller may then advanced the name pointer by the value returned, to get the
408  * start of the attribute list or attribute name(if any).
409  *
410  * @see radius_list_name
411  * @see request_refs
412  */
414 {
415  char const *p, *q;
416 
417  p = name;
418  /*
419  * Try and determine the end of the token
420  */
421  for (q = p; fr_dict_attr_allowed_chars[(uint8_t) *q] && (*q != '.') && (*q != '-'); q++);
422 
423  /*
424  * First token delimiter wasn't a '.'
425  */
426  if (*q != '.') {
427  *out = def;
428  return 0;
429  }
430 
431  *out = fr_substr2int(request_refs, name, REQUEST_UNKNOWN, q - p);
432  if (*out == REQUEST_UNKNOWN) return 0;
433 
434  return (q + 1) - p;
435 }
436 
437 /** Resolve a #request_refs_t to a #REQUEST.
438  *
439  * Sometimes #REQUEST structs may be chained to each other, as is the case
440  * when internally proxying EAP. This function resolves a #request_refs_t
441  * to a #REQUEST higher in the chain than the current #REQUEST.
442  *
443  * @see radius_list
444  * @param[in,out] context #REQUEST to start resolving from, and where to write
445  * a pointer to the resolved #REQUEST back to.
446  * @param[in] name (request) to resolve.
447  * @return
448  * - 0 if request is valid in this context.
449  * - -1 if request is not valid in this context.
450  */
452 {
453  REQUEST *request = *context;
454 
455  switch (name) {
456  case REQUEST_CURRENT:
457  return 0;
458 
459  case REQUEST_PARENT: /* for future use in request chaining */
460  case REQUEST_OUTER:
461  if (!request->parent) {
462  return -1;
463  }
464  *context = request->parent;
465  break;
466 
467  case REQUEST_UNKNOWN:
468  default:
469  rad_assert(0);
470  return -1;
471  }
472 
473  return 0;
474 }
475 /** @} */
476 
477 /** @name Alloc or initialise #vp_tmpl_t
478  *
479  * @note Should not usually be called outside of tmpl_* functions, use one of
480  * the tmpl_*from_* functions instead.
481  * @{
482  */
483 
484 /** Initialise stack allocated #vp_tmpl_t
485  *
486  * @note Name is not strdupe'd or memcpy'd so must be available, and must not change
487  * for the lifetime of the #vp_tmpl_t.
488  *
489  * @param[out] vpt to initialise.
490  * @param[in] type to set in the #vp_tmpl_t.
491  * @param[in] name of the #vp_tmpl_t.
492  * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
493  * If < 0 strlen will be used to determine the length.
494  * @param[in] quote The type of quoting around the template name.
495  * @return a pointer to the initialised #vp_tmpl_t. The same value as vpt.
496  */
497 vp_tmpl_t *tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
498 {
499  rad_assert(vpt);
500  rad_assert(type != TMPL_TYPE_UNKNOWN);
501  rad_assert(type <= TMPL_TYPE_NULL);
502 
503  memset(vpt, 0, sizeof(vp_tmpl_t));
504  vpt->type = type;
505 
506  if (name) {
507  vpt->name = name;
508  vpt->len = len < 0 ? strlen(name) :
509  (size_t) len;
510  vpt->quote = quote;
511  }
512  return vpt;
513 }
514 
515 /** Create a new heap allocated #vp_tmpl_t
516  *
517  * @param[in,out] ctx to allocate in.
518  * @param[in] type to set in the #vp_tmpl_t.
519  * @param[in] name of the #vp_tmpl_t (will be copied to a new talloc buffer parented
520  * by the #vp_tmpl_t).
521  * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
522  * If < 0 strlen will be used to determine the length.
523  * @param[in] quote The type of quoting around the template name.
524  * @return the newly allocated #vp_tmpl_t.
525  */
526 vp_tmpl_t *tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
527 {
528  vp_tmpl_t *vpt;
529 
530  rad_assert(type != TMPL_TYPE_UNKNOWN);
531  rad_assert(type <= TMPL_TYPE_NULL);
532 
533  vpt = talloc_zero(ctx, vp_tmpl_t);
534  if (!vpt) return NULL;
535  vpt->type = type;
536  if (name) {
537  vpt->name = talloc_bstrndup(vpt, name, len < 0 ? strlen(name) : (size_t)len);
538  vpt->len = talloc_array_length(vpt->name) - 1;
539  vpt->quote = quote;
540  }
541 
542  return vpt;
543 }
544 /* @} **/
545 
546 /** @name Create new #vp_tmpl_t from a string
547  *
548  * @{
549  */
550 
551 /** Initialise a #vp_tmpl_t to search for, or create attributes
552  *
553  * @param vpt to initialise.
554  * @param da of #VALUE_PAIR type to operate on.
555  * @param tag Must be one of:
556  * - A positive integer specifying a specific tag.
557  * - #TAG_ANY - Attribute with no specific tag value.
558  * - #TAG_NONE - No tag.
559  * @param num Specific instance, or all instances. Must be one of:
560  * - A positive integer specifying an instance.
561  * - #NUM_ALL - All instances.
562  * - #NUM_ANY - The first instance found.
563  * - #NUM_LAST - The last instance found.
564  * @param request to operate on.
565  * @param list to operate on.
566  */
567 void tmpl_from_da(vp_tmpl_t *vpt, fr_dict_attr_t const *da, int8_t tag, int num,
568  request_refs_t request, pair_lists_t list)
569 {
570  static char const name[] = "internal";
571 
572  rad_assert(da);
573 
574  tmpl_init(vpt, TMPL_TYPE_ATTR, name, sizeof(name), T_BARE_WORD);
575  vpt->tmpl_da = da;
576 
577  vpt->tmpl_request = request;
578  vpt->tmpl_list = list;
579  vpt->tmpl_tag = tag;
580  vpt->tmpl_num = num;
581 }
582 
583 /** Create a #vp_tmpl_t from a #value_data_t
584  *
585  * @param[in,out] ctx to allocate #vp_tmpl_t in.
586  * @param[out] out Where to write pointer to new #vp_tmpl_t.
587  * @param[in] data to convert.
588  * @param[in] type of data.
589  * @param[in] enumv Used to convert integers to string types for printing. May be NULL.
590  * @param[in] steal If true, any buffers are moved to the new ctx instead of being duplicated.
591  * @return
592  * - 0 on success.
593  * - -1 on failure.
594  */
595 int tmpl_afrom_value_data(TALLOC_CTX *ctx, vp_tmpl_t **out, value_data_t *data,
596  PW_TYPE type, fr_dict_attr_t const *enumv, bool steal)
597 {
598  char const *name;
599  vp_tmpl_t *vpt;
600 
601  vpt = talloc(ctx, vp_tmpl_t);
602  name = value_data_asprint(vpt, type, enumv, data, '\0');
603  tmpl_init(vpt, TMPL_TYPE_DATA, name, talloc_array_length(name),
605 
606  if (steal) {
607  if (value_data_steal(vpt, &vpt->tmpl_data_value, type, data) < 0) {
608  talloc_free(vpt);
609  return -1;
610  }
611  vpt->tmpl_data_type = type;
612  } else {
613  if (value_data_copy(vpt, &vpt->tmpl_data_value, type, data) < 0) {
614  talloc_free(vpt);
615  return -1;
616  }
617  vpt->tmpl_data_type = type;
618  }
619  *out = vpt;
620 
621  return 0;
622 }
623 
624 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
625  *
626  * @note The name field is just a copy of the input pointer, if you know that string might be
627  * freed before you're done with the #vp_tmpl_t use #tmpl_afrom_attr_str
628  * instead.
629  *
630  * @param[out] vpt to modify.
631  * @param[in] name of attribute including #request_refs and #pair_lists qualifiers.
632  * If only #request_refs and #pair_lists qualifiers are found, a #TMPL_TYPE_LIST
633  * #vp_tmpl_t will be produced.
634  * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
635  * found in name.
636  * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
637  * name.
638  * @param[in] allow_unknown If true attributes in the format accepted by
639  * #fr_dict_unknown_from_suboid will be allowed, even if they're not in the main
640  * dictionaries.
641  * If an unknown attribute is found a #TMPL_TYPE_ATTR #vp_tmpl_t will be
642  * produced with the unknown #fr_dict_attr_t stored in the ``unknown.da`` buffer.
643  * This #fr_dict_attr_t will have its ``flags.is_unknown`` field set to true.
644  * If #tmpl_from_attr_substr is being called on startup, the #vp_tmpl_t may be
645  * passed to #tmpl_define_unknown_attr to add the unknown attribute to the main
646  * dictionary.
647  * If the unknown attribute is not added to the main dictionary the #vp_tmpl_t
648  * cannot be used to search for a #VALUE_PAIR in a #REQUEST.
649  * @param[in] allow_undefined If true, we don't generate a parse error on unknown attributes.
650  * If an unknown attribute is found a #TMPL_TYPE_ATTR_UNDEFINED #vp_tmpl_t
651  * will be produced. A #vp_tmpl_t of this type can be passed to
652  * #tmpl_define_undefined_attr which will add the attribute to the global dictionary,
653  * and fixup the #vp_tmpl_t, changing it to a #TMPL_TYPE_ATTR with a pointer to the
654  * new #fr_dict_attr_t.
655  * @return
656  * - <= 0 on error (parse failure offset as negative integer).
657  * - > 0 on success (number of bytes parsed).
658  *
659  * @see REMARKER to produce pretty error markers from the return value.
660  */
661 ssize_t tmpl_from_attr_substr(vp_tmpl_t *vpt, char const *name,
662  request_refs_t request_def, pair_lists_t list_def,
663  bool allow_unknown, bool allow_undefined)
664 {
665  char const *p;
666  long num;
667  char *q;
669 
670  value_pair_tmpl_attr_t attr; /* So we don't fill the tmpl with junk and then error out */
671 
672  memset(vpt, 0, sizeof(*vpt));
673  memset(&attr, 0, sizeof(attr));
674 
675  p = name;
676 
677  if (*p == '&') p++;
678 
679  p += radius_request_name(&attr.request, p, request_def);
680  if (attr.request == REQUEST_UNKNOWN) {
681  fr_strerror_printf("Invalid request qualifier");
682  return -(p - name);
683  }
684 
685  /*
686  * Finding a list qualifier is optional
687  */
688  p += radius_list_name(&attr.list, p, list_def);
689  if (attr.list == PAIR_LIST_UNKNOWN) {
690  fr_strerror_printf("Invalid list qualifier");
691  return -(p - name);
692  }
693 
694  attr.tag = TAG_ANY;
695  attr.num = NUM_ANY;
696 
697  /*
698  * This may be just a bare list, but it can still
699  * have instance selectors and tag selectors.
700  */
701  switch (*p) {
702  case '\0':
703  type = TMPL_TYPE_LIST;
704  attr.num = NUM_ALL; /* Hack - Should be removed once tests are updated */
705  goto finish;
706 
707  case '[':
708  type = TMPL_TYPE_LIST;
709  attr.num = NUM_ALL; /* Hack - Should be removed once tests are updated */
710  goto do_num;
711 
712  default:
713  break;
714  }
715 
716  attr.da = fr_dict_attr_by_name_substr(NULL, &p);
717  if (!attr.da) {
718  char const *a;
719 
720  /*
721  * Record start of attribute in case we need to error out.
722  */
723  a = p;
724 
725  fr_strerror(); /* Clear out any existing errors */
726 
727  /*
728  * Attr-1.2.3.4 is OK.
729  */
730  if (fr_dict_unknown_from_suboid(NULL, (fr_dict_attr_t *)&attr.unknown.vendor,
732  &p) == 0) {
733  /*
734  * Check what we just parsed really hasn't been defined
735  * in the main dictionaries.
736  *
737  * If it has, parsing is the same as if the attribute
738  * name had been used instead of its OID.
739  */
740  attr.da = fr_dict_attr_child_by_num(((fr_dict_attr_t *)&attr.unknown.da)->parent,
741  ((fr_dict_attr_t *)&attr.unknown.da)->attr);
742  if (attr.da) {
743  vpt->auto_converted = true;
744  goto do_num;
745  }
746 
747  if (!allow_unknown) {
748  fr_strerror_printf("Unknown attribute");
749  return -(a - name);
750  }
751 
752  /*
753  * Unknown attributes can't be encoded, as we don't
754  * know how to encode them!
755  */
756  ((fr_dict_attr_t *)attr.unknown.da)->flags.internal = 1;
757  attr.da = (fr_dict_attr_t *)&attr.unknown.da;
758 
759  goto do_num; /* unknown attributes can't have tags */
760  }
761 
762  /*
763  * Can't parse it as an attribute, might be a literal string
764  * let the caller decide.
765  *
766  * Don't alter the fr_strerror buffer, should contain the parse
767  * error from fr_dict_unknown_from_suboid.
768  */
769  if (!allow_undefined) return -(a - name);
770 
771  /*
772  * Copy the name to a field for later resolution
773  */
775  for (q = attr.unknown.name; fr_dict_attr_allowed_chars[(int) *p]; *q++ = *p++) {
776  if (q >= (attr.unknown.name + sizeof(attr.unknown.name) - 1)) {
777  fr_strerror_printf("Attribute name is too long");
778  return -(p - name);
779  }
780  }
781  *q = '\0';
782 
783  goto do_num;
784  }
785 
786  /*
787  * The string MIGHT have a tag.
788  */
789  if (*p == ':') {
790  if (attr.da && !attr.da->flags.has_tag) { /* Lists don't have a da */
791  fr_strerror_printf("Attribute '%s' cannot have a tag", attr.da->name);
792  return -(p - name);
793  }
794 
795  num = strtol(p + 1, &q, 10);
796  if ((num > 0x1f) || (num < 0)) {
797  fr_strerror_printf("Invalid tag value '%li' (should be between 0-31)", num);
798  return -((p + 1)- name);
799  }
800 
801  attr.tag = num;
802  p = q;
803  }
804 
805 do_num:
806  if (*p == '\0') goto finish;
807 
808  if (*p == '[') {
809  p++;
810 
811  switch (*p) {
812  case '#':
813  attr.num = NUM_COUNT;
814  p++;
815  break;
816 
817  case '*':
818  attr.num = NUM_ALL;
819  p++;
820  break;
821 
822  case 'n':
823  attr.num = NUM_LAST;
824  p++;
825  break;
826 
827  default:
828  num = strtol(p, &q, 10);
829  if (p == q) {
830  fr_strerror_printf("Array index is not an integer");
831  return -(p - name);
832  }
833 
834  if ((num > 1000) || (num < 0)) {
835  fr_strerror_printf("Invalid array reference '%li' (should be between 0-1000)", num);
836  return -(p - name);
837  }
838  attr.num = num;
839  p = q;
840  break;
841  }
842 
843  if (*p != ']') {
844  fr_strerror_printf("No closing ']' for array index");
845  return -(p - name);
846  }
847  p++;
848  }
849 
850 finish:
851  vpt->type = type;
852  vpt->name = name;
853  vpt->len = p - name;
854  vpt->quote = T_BARE_WORD;
855 
856  /*
857  * Copy over the attribute definition, now we're
858  * sure what we were passed is valid.
859  */
860  memcpy(&vpt->data.attribute, &attr, sizeof(vpt->data.attribute));
861  if ((vpt->type == TMPL_TYPE_ATTR) && attr.da->flags.is_unknown) {
862  vpt->tmpl_da = (fr_dict_attr_t *)&vpt->data.attribute.unknown.da;
863  }
864 
865  VERIFY_TMPL(vpt); /* Because we want to ensure we produced something sane */
866 
867  return vpt->len;
868 }
869 
870 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
871  *
872  * @note Unlike #tmpl_from_attr_substr this function will error out if the entire
873  * name string isn't parsed.
874  *
875  * @copydetails tmpl_from_attr_substr
876  */
877 ssize_t tmpl_from_attr_str(vp_tmpl_t *vpt, char const *name,
878  request_refs_t request_def, pair_lists_t list_def,
879  bool allow_unknown, bool allow_undefined)
880 {
881  ssize_t slen;
882 
883  slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
884  if (slen <= 0) return slen;
885  if (name[slen] != '\0') {
886  /* This looks wrong, but it produces meaningful errors for unknown attrs with tags */
887  fr_strerror_printf("Unexpected text after %s", fr_int2str(tmpl_names, vpt->type, "<INVALID>"));
888  return -slen;
889  }
890 
891  VERIFY_TMPL(vpt);
892 
893  return slen;
894 }
895 
896 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
897  *
898  * @param[in,out] ctx to allocate #vp_tmpl_t in.
899  * @param[out] out Where to write pointer to new #vp_tmpl_t.
900  * @param[in] name of attribute including #request_refs and #pair_lists qualifiers.
901  * If only #request_refs #pair_lists qualifiers are found, a #TMPL_TYPE_LIST
902  * #vp_tmpl_t will be produced.
903  * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
904  * found in name.
905  * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
906  * name.
907  * @param[in] allow_unknown If true attributes in the format accepted by
908  * #fr_dict_unknown_from_suboid will be allowed, even if they're not in the main
909  * dictionaries.
910  * If an unknown attribute is found a #TMPL_TYPE_ATTR #vp_tmpl_t will be
911  * produced with the unknown #fr_dict_attr_t stored in the ``unknown.da`` buffer.
912  * This #fr_dict_attr_t will have its ``flags.is_unknown`` field set to true.
913  * If #tmpl_from_attr_substr is being called on startup, the #vp_tmpl_t may be
914  * passed to #tmpl_define_unknown_attr to add the unknown attribute to the main
915  * dictionary.
916  * If the unknown attribute is not added to the main dictionary the #vp_tmpl_t
917  * cannot be used to search for a #VALUE_PAIR in a #REQUEST.
918  * @param[in] allow_undefined If true, we don't generate a parse error on unknown attributes.
919  * If an unknown attribute is found a #TMPL_TYPE_ATTR_UNDEFINED #vp_tmpl_t
920  * will be produced.
921  * @return <= 0 on error (offset as negative integer), > 0 on success
922  * (number of bytes parsed).
923  *
924  * @see REMARKER to produce pretty error markers from the return value.
925  */
926 ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
927  request_refs_t request_def, pair_lists_t list_def,
928  bool allow_unknown, bool allow_undefined)
929 {
930  ssize_t slen;
931  vp_tmpl_t *vpt;
932 
933  MEM(vpt = talloc(ctx, vp_tmpl_t)); /* tmpl_from_attr_substr zeros it */
934 
935  slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
936  if (slen <= 0) {
937  TALLOC_FREE(vpt);
938  return slen;
939  }
940  vpt->name = talloc_strndup(vpt, vpt->name, slen);
941 
942  VERIFY_TMPL(vpt);
943 
944  *out = vpt;
945 
946  return slen;
947 }
948 
949 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
950  *
951  * @note Unlike #tmpl_afrom_attr_substr this function will error out if the entire
952  * name string isn't parsed.
953  *
954  * @copydetails tmpl_afrom_attr_substr
955  */
956 ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
957  request_refs_t request_def, pair_lists_t list_def,
958  bool allow_unknown, bool allow_undefined)
959 {
960  ssize_t slen;
961  vp_tmpl_t *vpt;
962 
963  MEM(vpt = talloc(ctx, vp_tmpl_t)); /* tmpl_from_attr_substr zeros it */
964 
965  slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
966  if (slen <= 0) {
967  TALLOC_FREE(vpt);
968  return slen;
969  }
970  if (name[slen] != '\0') {
971  /* This looks wrong, but it produces meaningful errors for unknown attrs with tags */
972  fr_strerror_printf("Unexpected text after %s", fr_int2str(tmpl_names, vpt->type, "<INVALID>"));
973  TALLOC_FREE(vpt);
974  return -slen;
975  }
976  vpt->name = talloc_strndup(vpt, vpt->name, vpt->len);
977 
978  VERIFY_TMPL(vpt);
979 
980  *out = vpt;
981 
982  return slen;
983 }
984 
985 /** Convert an arbitrary string into a #vp_tmpl_t
986  *
987  * @note Unlike #tmpl_afrom_attr_str return code 0 doesn't necessarily indicate failure,
988  * may just mean a 0 length string was parsed.
989  *
990  * @note xlats and regexes are left uncompiled. This is to support the two pass parsing
991  * done by the modcall code. Compilation on pass1 of that code could fail, as
992  * attributes or xlat functions registered by modules may not be available (yet).
993  *
994  * @note For details of attribute parsing see #tmpl_from_attr_substr.
995  *
996  * @param[in,out] ctx To allocate #vp_tmpl_t in.
997  * @param[out] out Where to write the pointer to the new #vp_tmpl_t.
998  * @param[in] in String to convert to a #vp_tmpl_t.
999  * @param[in] inlen length of string to convert.
1000  * @param[in] type of quoting around value. May be one of:
1001  * - #T_BARE_WORD - If string begins with ``&`` produces #TMPL_TYPE_ATTR,
1002  * #TMPL_TYPE_ATTR_UNDEFINED, #TMPL_TYPE_LIST or error.
1003  * If string does not begin with ``&`` produces #TMPL_TYPE_UNPARSED,
1004  * #TMPL_TYPE_ATTR or #TMPL_TYPE_LIST.
1005  * - #T_SINGLE_QUOTED_STRING - Produces #TMPL_TYPE_UNPARSED
1006  * - #T_DOUBLE_QUOTED_STRING - Produces #TMPL_TYPE_XLAT or #TMPL_TYPE_UNPARSED (if
1007  * string doesn't contain ``%``).
1008  * - #T_BACK_QUOTED_STRING - Produces #TMPL_TYPE_EXEC
1009  * - #T_OP_REG_EQ - Produces #TMPL_TYPE_REGEX
1010  * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
1011  * found in name.
1012  * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
1013  * name.
1014  * @param[in] do_unescape whether or not we should do unescaping. Should be false if the
1015  * caller already did it.
1016  * @return <= 0 on error (offset as negative integer), > 0 on success
1017  * (number of bytes parsed).
1018  * @see REMARKER to produce pretty error markers from the return value.
1019  *
1020  * @see tmpl_from_attr_substr
1021  */
1022 ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *in, size_t inlen, FR_TOKEN type,
1023  request_refs_t request_def, pair_lists_t list_def, bool do_unescape)
1024 {
1025  bool do_xlat;
1026  char quote;
1027  char const *p;
1028  ssize_t slen;
1029  PW_TYPE data_type = PW_TYPE_STRING;
1030  vp_tmpl_t *vpt = NULL;
1032 
1033  switch (type) {
1034  case T_BARE_WORD:
1035  /*
1036  * No attribute names start with 0x, and if they did, the user
1037  * can just use the explicit & prefix.
1038  */
1039  if ((in[0] == '0') && (tolower(in[1]) == 'x')) {
1040  size_t binlen, len;
1041 
1042  /*
1043  * Hex strings must contain even number of characters
1044  */
1045  if (inlen & 0x01) {
1046  fr_strerror_printf("Hex string not even length");
1047  return -inlen;
1048  }
1049 
1050  if (inlen <= 2) {
1051  fr_strerror_printf("Zero length hex string is invalid");
1052  return -inlen;
1053  }
1054 
1055  binlen = (inlen - 2) / 2;
1056 
1057  vpt = tmpl_alloc(ctx, TMPL_TYPE_DATA, in, inlen, type);
1058  vpt->tmpl_data_value.ptr = talloc_array(vpt, uint8_t, binlen);
1059  vpt->tmpl_data_length = binlen;
1060  vpt->tmpl_data_type = PW_TYPE_OCTETS;
1061 
1062  len = fr_hex2bin(vpt->tmpl_data_value.ptr, binlen, in + 2, inlen - 2);
1063  if (len != binlen) {
1064  fr_strerror_printf("Hex string contains none hex char");
1065  talloc_free(vpt);
1066  return -(len + 2);
1067  }
1068  slen = len;
1069  break;
1070  }
1071 
1072  /*
1073  * If we can parse it as an attribute, it's an attribute.
1074  * Otherwise, treat it as a literal.
1075  */
1076  quote = '\0';
1077 
1078  slen = tmpl_afrom_attr_str(ctx, &vpt, in, request_def, list_def, true, (in[0] == '&'));
1079  if ((in[0] == '&') && (slen <= 0)) return slen;
1080  if (slen > 0) break;
1081  goto parse;
1082 
1084  quote = '\'';
1085 
1086  parse:
1087  if (do_unescape) {
1088  if (value_data_from_str(ctx, &data, &data_type, NULL, in, inlen, quote) < 0) return 0;
1089 
1090  vpt = tmpl_alloc(ctx, TMPL_TYPE_UNPARSED, data.strvalue, talloc_array_length(data.strvalue) - 1, type);
1091  talloc_free(data.ptr);
1092  } else {
1093  vpt = tmpl_alloc(ctx, TMPL_TYPE_UNPARSED, in, inlen, type);
1094  }
1095  slen = vpt->len;
1096  break;
1097 
1099  do_xlat = false;
1100 
1101  p = in;
1102  while (*p) {
1103  if (do_unescape) { /* otherwise \ is just another character */
1104  if (*p == '\\') {
1105  if (!p[1]) break;
1106  p += 2;
1107  continue;
1108  }
1109  }
1110 
1111  if (*p == '%') {
1112  do_xlat = true;
1113  break;
1114  }
1115 
1116  p++;
1117  }
1118 
1119  /*
1120  * If the double quoted string needs to be
1121  * expanded at run time, make it an xlat
1122  * expansion. Otherwise, convert it to be a
1123  * literal.
1124  */
1125  if (do_unescape) {
1126  if (value_data_from_str(ctx, &data, &data_type, NULL, in,
1127  inlen, fr_token_quote[type]) < 0) return -1;
1128  if (do_xlat) {
1129  vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, data.strvalue,
1130  talloc_array_length(data.strvalue) - 1, type);
1131  } else {
1132  vpt = tmpl_alloc(ctx, TMPL_TYPE_UNPARSED, data.strvalue,
1133  talloc_array_length(data.strvalue) - 1, type);
1135  }
1136  talloc_free(data.ptr);
1137  } else {
1138  if (do_xlat) {
1139  vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, in, inlen, type);
1140  } else {
1141  vpt = tmpl_alloc(ctx, TMPL_TYPE_UNPARSED, in, inlen, type);
1143  }
1144  }
1145  slen = vpt->len;
1146  break;
1147 
1148  case T_BACK_QUOTED_STRING:
1149  if (do_unescape) {
1150  if (value_data_from_str(ctx, &data, &data_type, NULL, in,
1151  inlen, fr_token_quote[type]) < 0) return -1;
1152 
1153  vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, data.strvalue, talloc_array_length(data.strvalue) - 1, type);
1154  talloc_free(data.ptr);
1155  } else {
1156  vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, in, inlen, type);
1157  }
1158  slen = vpt->len;
1159  break;
1160 
1161  case T_OP_REG_EQ: /* hack */
1162  vpt = tmpl_alloc(ctx, TMPL_TYPE_REGEX, in, inlen, T_BARE_WORD);
1163  slen = vpt->len;
1164  break;
1165 
1166  default:
1167  rad_assert(0);
1168  return 0; /* 0 is an error here too */
1169  }
1170  rad_assert(vpt);
1171  vpt->quote = type;
1172 
1173  rad_assert(slen >= 0);
1174 
1175  VERIFY_TMPL(vpt);
1176  *out = vpt;
1177 
1178  return slen;
1179 }
1180 /* @} **/
1181 
1182 /** @name Cast or convert #vp_tmpl_t
1183  *
1184  * #tmpl_cast_in_place can be used to convert #TMPL_TYPE_UNPARSED to a #TMPL_TYPE_DATA of a
1185  * specified #PW_TYPE.
1186  *
1187  * #tmpl_cast_in_place_str does the same as #tmpl_cast_in_place, but will always convert to
1188  * #PW_TYPE #PW_TYPE_STRING.
1189  *
1190  * #tmpl_cast_to_vp does the same as #tmpl_cast_in_place, but outputs a #VALUE_PAIR.
1191  *
1192  * #tmpl_define_unknown_attr converts a #TMPL_TYPE_ATTR with an unknown #fr_dict_attr_t to a
1193  * #TMPL_TYPE_ATTR with a known #fr_dict_attr_t, by adding the unknown #fr_dict_attr_t to the main
1194  * dictionary, and updating the ``tmpl_da`` pointer.
1195  * @{
1196  */
1197 
1198 /** Convert #vp_tmpl_t of type #TMPL_TYPE_UNPARSED or #TMPL_TYPE_DATA to #TMPL_TYPE_DATA of type specified
1199  *
1200  * @note Conversion is done in place.
1201  * @note Irrespective of whether the #vp_tmpl_t was #TMPL_TYPE_UNPARSED or #TMPL_TYPE_DATA,
1202  * on successful cast it will be #TMPL_TYPE_DATA.
1203  *
1204  * @param[in,out] vpt The template to modify. Must be of type #TMPL_TYPE_UNPARSED
1205  * or #TMPL_TYPE_DATA.
1206  * @param[in] type to cast to.
1207  * @param[in] enumv Enumerated dictionary values associated with a #fr_dict_attr_t.
1208  * @return
1209  * - 0 on success.
1210  * - -1 on failure.
1211  */
1213 {
1214  VERIFY_TMPL(vpt);
1215 
1216  rad_assert(vpt != NULL);
1217  rad_assert((vpt->type == TMPL_TYPE_UNPARSED) || (vpt->type == TMPL_TYPE_DATA));
1218 
1219  switch (vpt->type) {
1220  case TMPL_TYPE_UNPARSED:
1221  vpt->tmpl_data_type = type;
1222 
1223  /*
1224  * Why do we pass a pointer to the tmpl type? Goddamn WiMAX.
1225  */
1226  if (value_data_from_str(vpt, &vpt->tmpl_data_value, &vpt->tmpl_data_type,
1227  enumv, vpt->name, vpt->len, '\0') < 0) return -1;
1228  vpt->type = TMPL_TYPE_DATA;
1229  break;
1230 
1231  case TMPL_TYPE_DATA:
1232  {
1233  value_data_t new;
1234 
1235  if (type == vpt->tmpl_data_type) return 0; /* noop */
1236 
1237  if (value_data_cast(vpt, &new, type, enumv, vpt->tmpl_data_type,
1238  NULL, &vpt->tmpl_data_value) < 0) return -1;
1239 
1240  /*
1241  * Free old value buffers
1242  */
1243  switch (vpt->tmpl_data_type) {
1244  case PW_TYPE_STRING:
1245  case PW_TYPE_OCTETS:
1246  talloc_free(vpt->tmpl_data_value.ptr);
1247  break;
1248 
1249  default:
1250  break;
1251  }
1252 
1253  memcpy(&vpt->tmpl_data_value, &new, sizeof(vpt->tmpl_data_value));
1254  vpt->tmpl_data_type = type;
1255  }
1256  break;
1257 
1258  default:
1259  rad_assert(0);
1260  }
1261 
1262  VERIFY_TMPL(vpt);
1263 
1264  return 0;
1265 }
1266 
1267 /** Convert #vp_tmpl_t of type #TMPL_TYPE_UNPARSED to #TMPL_TYPE_DATA of type #PW_TYPE_STRING
1268  *
1269  * @note Conversion is done in place.
1270  *
1271  * @param[in,out] vpt The template to modify. Must be of type #TMPL_TYPE_UNPARSED.
1272  */
1274 {
1275  rad_assert(vpt != NULL);
1277 
1278  vpt->tmpl_data.vp_strvalue = talloc_typed_strdup(vpt, vpt->name);
1279  rad_assert(vpt->tmpl_data.vp_strvalue != NULL);
1280 
1281  vpt->type = TMPL_TYPE_DATA;
1282  vpt->tmpl_data_type = PW_TYPE_STRING;
1283  vpt->tmpl_data_length = talloc_array_length(vpt->tmpl_data.vp_strvalue) - 1;
1284 }
1285 
1286 /** Expand a #vp_tmpl_t to a string, parse it as an attribute of type cast, create a #VALUE_PAIR from the result
1287  *
1288  * @note Like #tmpl_expand, but produces a #VALUE_PAIR.
1289  *
1290  * @param out Where to write pointer to the new #VALUE_PAIR.
1291  * @param request The current #REQUEST.
1292  * @param vpt to cast. Must be one of the following types:
1293  * - #TMPL_TYPE_UNPARSED
1294  * - #TMPL_TYPE_EXEC
1295  * - #TMPL_TYPE_XLAT
1296  * - #TMPL_TYPE_XLAT_STRUCT
1297  * - #TMPL_TYPE_ATTR
1298  * - #TMPL_TYPE_DATA
1299  * @param cast type of #VALUE_PAIR to create.
1300  * @return
1301  * - 0 on success.
1302  * - -1 on failure.
1303  */
1304 int tmpl_cast_to_vp(VALUE_PAIR **out, REQUEST *request,
1305  vp_tmpl_t const *vpt, fr_dict_attr_t const *cast)
1306 {
1307  int rcode;
1308  VALUE_PAIR *vp;
1310  char *p;
1311 
1312  VERIFY_TMPL(vpt);
1313 
1314  *out = NULL;
1315 
1316  vp = fr_pair_afrom_da(request, cast);
1317  if (!vp) return -1;
1318 
1319  if (vpt->type == TMPL_TYPE_DATA) {
1320  VERIFY_VP(vp);
1321  rad_assert(vp->da->type == vpt->tmpl_data_type);
1322 
1323  value_data_copy(vp, &vp->data, vpt->tmpl_data_type, &vpt->tmpl_data_value);
1324  *out = vp;
1325  return 0;
1326  }
1327 
1328  rcode = tmpl_aexpand(vp, &p, request, vpt, NULL, NULL);
1329  if (rcode < 0) {
1330  fr_pair_list_free(&vp);
1331  return rcode;
1332  }
1333  data.strvalue = p;
1334 
1335  /*
1336  * New escapes: strings are in binary form.
1337  */
1338  if (vp->da->type == PW_TYPE_STRING) {
1339  vp->data.ptr = talloc_steal(vp, data.ptr);
1340  vp->vp_length = rcode;
1341  } else if (fr_pair_value_from_str(vp, data.strvalue, rcode) < 0) {
1342  talloc_free(data.ptr);
1343  fr_pair_list_free(&vp);
1344  return -1;
1345  }
1346 
1347  *out = vp;
1348  return 0;
1349 }
1350 
1351 /** Add an unknown #fr_dict_attr_t specified by a #vp_tmpl_t to the main dictionary
1352  *
1353  * @param vpt to add. ``tmpl_da`` pointer will be updated to point to the
1354  * #fr_dict_attr_t inserted into the dictionary.
1355  * @return
1356  * - 1 noop (did nothing) - Not possible to convert tmpl.
1357  * - 0 on success.
1358  * - -1 on failure.
1359  */
1361 {
1362  fr_dict_attr_t const *da;
1363 
1364  if (!vpt) return 1;
1365 
1366  VERIFY_TMPL(vpt);
1367 
1368  if (vpt->type != TMPL_TYPE_ATTR) return 1;
1369 
1370  if (!vpt->tmpl_da->flags.is_unknown) return 1;
1371 
1372  da = fr_dict_unknown_add(NULL, vpt->tmpl_da);
1373  if (!da) return -1;
1374  vpt->tmpl_da = da;
1375 
1376  return 0;
1377 }
1378 
1379 /** Add an undefined #fr_dict_attr_t specified by a #vp_tmpl_t to the main dictionary
1380  *
1381  * @note fr_dict_attr_add will not return an error if the attribute already exists
1382  * meaning that multiple #vp_tmpl_t specifying the same attribute can be
1383  * passed to this function to be fixed up, so long as the type and flags
1384  * are identical.
1385  *
1386  * @param vpt specifying undefined attribute to add. ``tmpl_da`` pointer will be
1387  * updated to point to the #fr_dict_attr_t inserted into the dictionary.
1388  * Lists and requests will be preserved.
1389  * @param type to define undefined attribute as.
1390  * @param flags to define undefined attribute with.
1391  * @return
1392  * - 1 noop (did nothing) - Not possible to convert tmpl.
1393  * - 0 on success.
1394  * - -1 on failure.
1395  */
1397 {
1398  fr_dict_attr_t const *da;
1399 
1400  if (!vpt) return -1;
1401 
1402  VERIFY_TMPL(vpt);
1403 
1404  if (vpt->type != TMPL_TYPE_ATTR_UNDEFINED) return 1;
1405 
1406  if (fr_dict_attr_add(NULL, fr_dict_root(fr_dict_internal), vpt->tmpl_unknown_name, -1, type, *flags) < 0) {
1407  return -1;
1408  }
1409  da = fr_dict_attr_by_name(NULL, vpt->tmpl_unknown_name);
1410  if (!da) return -1;
1411 
1412  if (type != da->type) {
1413  fr_strerror_printf("Attribute %s of type %s already defined with type %s",
1414  da->name, fr_int2str(dict_attr_types, type, "<UNKNOWN>"),
1415  fr_int2str(dict_attr_types, da->type, "<UNKNOWN>"));
1416  return -1;
1417  }
1418 
1419  if (memcmp(flags, &da->flags, sizeof(*flags)) != 0) {
1420  fr_strerror_printf("Attribute %s already defined with different flags", da->name);
1421  return -1;
1422  }
1423 
1424 #ifndef NDEBUG
1425  /*
1426  * Clear existing data (so we don't trip TMPL_VERIFY);
1427  */
1428  memset(&vpt->data.attribute.unknown, 0, sizeof(vpt->data.attribute.unknown));
1429 #endif
1430 
1431  vpt->tmpl_da = da;
1432  vpt->type = TMPL_TYPE_ATTR;
1433 
1434  return 0;
1435 }
1436 /* @} **/
1437 
1438 /** @name Resolve a #vp_tmpl_t outputting the result in various formats
1439  *
1440  * @{
1441  */
1442 
1443 /** Expand a #vp_tmpl_t to a string writing the result to a buffer
1444  *
1445  * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #vp_tmpl_t
1446  * provided by the conf parser, into a usable value.
1447  * The value returned should be raw and undoctored for #PW_TYPE_STRING and #PW_TYPE_OCTETS types,
1448  * and the printable (string) version of the data for all others.
1449  *
1450  * Depending what arguments are passed, either copies the value to buff, or writes a pointer
1451  * to a string buffer to out. This allows the most efficient access to the value resolved by
1452  * the #vp_tmpl_t, avoiding unecessary string copies.
1453  *
1454  * @note This function is used where raw string values are needed, which may mean the string
1455  * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint should
1456  * be used before using these values in debug statements. #is_printable can be used to check
1457  * if the string only contains printable chars.
1458  *
1459  * @param out Where to write a pointer to the string buffer. On return may point to buff if
1460  * buff was used to store the value. Otherwise will point to a #value_data_t buffer,
1461  * or the name of the template. To force copying to buff, out should be NULL.
1462  * @param buff Expansion buffer, may be NULL if out is not NULL, and processing #TMPL_TYPE_UNPARSED
1463  * or string types.
1464  * @param bufflen Length of expansion buffer.
1465  * @param request Current request.
1466  * @param vpt to expand. Must be one of the following types:
1467  * - #TMPL_TYPE_UNPARSED
1468  * - #TMPL_TYPE_EXEC
1469  * - #TMPL_TYPE_XLAT
1470  * - #TMPL_TYPE_XLAT_STRUCT
1471  * - #TMPL_TYPE_ATTR
1472  * - #TMPL_TYPE_DATA
1473  * @param escape xlat escape function (only used for xlat types).
1474  * @param escape_ctx xlat escape function data.
1475  * @return
1476  * - -1 on failure.
1477  * - The length of data written to buff, or pointed to by out.
1478  */
1479 ssize_t tmpl_expand(char const **out, char *buff, size_t bufflen, REQUEST *request,
1480  vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
1481 {
1482  VALUE_PAIR *vp;
1483  ssize_t slen = -1; /* quiet compiler */
1484 
1485  VERIFY_TMPL(vpt);
1486 
1487  rad_assert(vpt->type != TMPL_TYPE_LIST);
1488 
1489  if (out) *out = NULL;
1490 
1491  switch (vpt->type) {
1492  case TMPL_TYPE_UNPARSED:
1493  RDEBUG4("EXPAND TMPL LITERAL");
1494 
1495  if (!out) {
1496  rad_assert(buff);
1497  memcpy(buff, vpt->name, vpt->len >= bufflen ? bufflen : vpt->len + 1);
1498  } else {
1499  *out = vpt->name;
1500  }
1501  return vpt->len;
1502 
1503  case TMPL_TYPE_EXEC:
1504  {
1505  RDEBUG4("EXPAND TMPL EXEC");
1506  rad_assert(buff);
1507  if (radius_exec_program(request, buff, bufflen, NULL, request, vpt->name, NULL,
1508  true, false, EXEC_TIMEOUT) != 0) {
1509  return -1;
1510  }
1511  slen = strlen(buff);
1512  if (out) *out = buff;
1513  }
1514  break;
1515 
1516  case TMPL_TYPE_XLAT:
1517  RDEBUG4("EXPAND TMPL XLAT");
1518  rad_assert(buff);
1519  /* Error in expansion, this is distinct from zero length expansion */
1520  slen = radius_xlat(buff, bufflen, request, vpt->name, escape, escape_ctx);
1521  if (slen < 0) return slen;
1522  if (out) *out = buff;
1523  break;
1524 
1525  case TMPL_TYPE_XLAT_STRUCT:
1526  RDEBUG4("EXPAND TMPL XLAT STRUCT");
1527  rad_assert(buff);
1528  /* Error in expansion, this is distinct from zero length expansion */
1529  slen = radius_xlat_struct(buff, bufflen, request, vpt->tmpl_xlat, escape, escape_ctx);
1530  if (slen < 0) {
1531  return slen;
1532  }
1533  slen = strlen(buff);
1534  if (out) *out = buff;
1535  break;
1536 
1537  case TMPL_TYPE_ATTR:
1538  {
1539  int ret;
1540 
1541  RDEBUG4("EXPAND TMPL ATTR");
1542  rad_assert(buff);
1543  ret = tmpl_find_vp(&vp, request, vpt);
1544  if (ret < 0) return -2;
1545 
1546  if (out && ((vp->da->type == PW_TYPE_STRING) || (vp->da->type == PW_TYPE_OCTETS))) {
1547  *out = vp->data.ptr;
1548  slen = vp->vp_length;
1549  } else {
1550  if (out) *out = buff;
1551  slen = fr_pair_value_snprint(buff, bufflen, vp, '\0');
1552  }
1553  }
1554  break;
1555 
1556  case TMPL_TYPE_DATA:
1557  {
1558  RDEBUG4("EXPAND TMPL DATA");
1559 
1560  if (out && ((vpt->tmpl_data_type == PW_TYPE_STRING) || (vpt->tmpl_data_type == PW_TYPE_OCTETS))) {
1561  *out = vpt->tmpl_data_value.ptr;
1562  slen = vpt->tmpl_data_length;
1563  } else {
1564  if (out) *out = buff;
1565  /**
1566  * @todo tmpl_expand should accept an enumv da from the lhs of the map.
1567  */
1568  slen = value_data_snprint(buff, bufflen, vpt->tmpl_data_type, NULL, &vpt->tmpl_data_value, '\0');
1569  }
1570  }
1571  break;
1572 
1573  /*
1574  * We should never be expanding these.
1575  */
1576  case TMPL_TYPE_UNKNOWN:
1577  case TMPL_TYPE_NULL:
1578  case TMPL_TYPE_LIST:
1579  case TMPL_TYPE_REGEX:
1582  rad_assert(0 == 1);
1583  slen = -1;
1584  break;
1585  }
1586 
1587  if (slen < 0) return slen;
1588 
1589 
1590 #if 0
1591  /*
1592  * If we're doing correct escapes, we may have to re-parse the string.
1593  * If the string is from another expansion, it needs re-parsing.
1594  * Or, if it's from a "string" attribute, it needs re-parsing.
1595  * Integers, IP addresses, etc. don't need re-parsing.
1596  */
1597  if (vpt->type != TMPL_TYPE_ATTR) {
1598  value_data_t vd;
1599  int ret;
1600 
1601  PW_TYPE type = PW_TYPE_STRING;
1602 
1603  ret = value_data_from_str(ctx, &vd, &type, NULL, *out, slen, '"');
1604  talloc_free(*out); /* free the old value */
1605  if (ret < 0) return -1;
1606  *out = vd.ptr;
1607  slen = vd.length;
1608  }
1609 #endif
1610 
1611  if (vpt->type == TMPL_TYPE_XLAT_STRUCT) {
1612  RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
1613  RDEBUG2(" --> %s", buff);
1614  }
1615 
1616  return slen;
1617 }
1618 
1619 /** Expand a template to a string, allocing a new buffer to hold the string
1620  *
1621  * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #vp_tmpl_t
1622  * provided by the conf parser, into a usable value.
1623  * The value returned should be raw and undoctored for #PW_TYPE_STRING and #PW_TYPE_OCTETS types,
1624  * and the printable (string) version of the data for all others.
1625  *
1626  * This function will always duplicate values, whereas #tmpl_expand may return a pointer to an
1627  * existing buffer.
1628  *
1629  * @note This function is used where raw string values are needed, which may mean the string
1630  * returned may be binary data or contain unprintable chars. #fr_snprint or #fr_asprint should
1631  * be used before using these values in debug statements. #is_printable can be used to check
1632  * if the string only contains printable chars.
1633  *
1634  * @note The type (char or uint8_t) can be obtained with talloc_get_type, and may be used as a
1635  * hint as to how to process or print the data.
1636  *
1637  * @param ctx to allocate new buffer in.
1638  * @param out Where to write pointer to the new buffer.
1639  * @param request Current request.
1640  * @param vpt to expand. Must be one of the following types:
1641  * - #TMPL_TYPE_UNPARSED
1642  * - #TMPL_TYPE_EXEC
1643  * - #TMPL_TYPE_XLAT
1644  * - #TMPL_TYPE_XLAT_STRUCT
1645  * - #TMPL_TYPE_ATTR
1646  * - #TMPL_TYPE_DATA
1647  * @param escape xlat escape function (only used for xlat types).
1648  * @param escape_ctx xlat escape function data (only used for xlat types).
1649  * @return
1650  * - -1 on failure.
1651  * - The length of data written to buff, or pointed to by out.
1652  */
1653 ssize_t tmpl_aexpand(TALLOC_CTX *ctx, char **out, REQUEST *request, vp_tmpl_t const *vpt,
1654  xlat_escape_t escape, void *escape_ctx)
1655 {
1656  VALUE_PAIR *vp;
1657  ssize_t slen = -1; /* quiet compiler */
1658 
1659  rad_assert(vpt->type != TMPL_TYPE_LIST);
1660 
1661  VERIFY_TMPL(vpt);
1662 
1663  *out = NULL;
1664 
1665  switch (vpt->type) {
1666  case TMPL_TYPE_UNPARSED:
1667  RDEBUG4("EXPAND TMPL LITERAL");
1668  *out = talloc_bstrndup(ctx, vpt->name, vpt->len);
1669  return vpt->len;
1670 
1671  case TMPL_TYPE_EXEC:
1672  {
1673  char *buff = NULL;
1674 
1675  RDEBUG4("EXPAND TMPL EXEC");
1676  buff = talloc_array(ctx, char, 1024);
1677  if (radius_exec_program(request, buff, 1024, NULL, request, vpt->name, NULL,
1678  true, false, EXEC_TIMEOUT) != 0) {
1679  TALLOC_FREE(buff);
1680  return -1;
1681  }
1682  slen = strlen(buff);
1683  *out = buff;
1684  }
1685  break;
1686 
1687  case TMPL_TYPE_XLAT:
1688  RDEBUG4("EXPAND TMPL XLAT");
1689  /* Error in expansion, this is distinct from zero length expansion */
1690  slen = radius_axlat(out, request, vpt->name, escape, escape_ctx);
1691  if (slen < 0) {
1692  rad_assert(!*out);
1693  return slen;
1694  }
1695  rad_assert(*out);
1696  slen = strlen(*out);
1697  break;
1698 
1699  case TMPL_TYPE_XLAT_STRUCT:
1700  RDEBUG4("EXPAND TMPL XLAT STRUCT");
1701  /* Error in expansion, this is distinct from zero length expansion */
1702  slen = radius_axlat_struct(out, request, vpt->tmpl_xlat, escape, escape_ctx);
1703  if (slen < 0) {
1704  rad_assert(!*out);
1705  return slen;
1706  }
1707  rad_assert(*out);
1708 
1709  slen = strlen(*out);
1710  break;
1711 
1712  case TMPL_TYPE_ATTR:
1713  {
1714  int ret;
1715 
1716  RDEBUG4("EXPAND TMPL ATTR");
1717  ret = tmpl_find_vp(&vp, request, vpt);
1718  if (ret < 0) return -2;
1719 
1720  switch (vpt->tmpl_da->type) {
1721  case PW_TYPE_STRING:
1722  *out = talloc_bstrndup(ctx, vp->vp_strvalue, vp->vp_length);
1723  if (!*out) return -1;
1724  slen = vp->vp_length;
1725  break;
1726 
1727  case PW_TYPE_OCTETS:
1728  *out = talloc_memdup(ctx, vp->vp_octets, vp->vp_length);
1729  if (!*out) return -1;
1730  slen = vp->vp_length;
1731  break;
1732 
1733  default:
1734  *out = fr_pair_value_asprint(ctx, vp, '\0');
1735  if (!*out) return -1;
1736  slen = talloc_array_length(*out) - 1;
1737  break;
1738  }
1739  }
1740  break;
1741 
1742  case TMPL_TYPE_DATA:
1743  {
1744  RDEBUG4("EXPAND TMPL DATA");
1745 
1746  switch (vpt->tmpl_data_type) {
1747  case PW_TYPE_STRING:
1748  *out = talloc_bstrndup(ctx, vpt->tmpl_data_value.strvalue, vpt->tmpl_data_length);
1749  if (!*out) return -1;
1750  slen = vpt->tmpl_data_length;
1751  break;
1752 
1753  case PW_TYPE_OCTETS:
1754  *out = talloc_memdup(ctx, vpt->tmpl_data_value.octets, vpt->tmpl_data_length);
1755  if (!*out) return -1;
1756  slen = vpt->tmpl_data_length;
1757  break;
1758 
1759  default:
1760  *out = value_data_asprint(ctx, vpt->tmpl_data_type, NULL, &vpt->tmpl_data_value, '\0');
1761  if (!*out) return -1;
1762  slen = talloc_array_length(*out) - 1;
1763  break;
1764  }
1765  }
1766  break;
1767 
1768  /*
1769  * We should never be expanding these.
1770  */
1771  case TMPL_TYPE_UNKNOWN:
1772  case TMPL_TYPE_NULL:
1773  case TMPL_TYPE_LIST:
1774  case TMPL_TYPE_REGEX:
1777  rad_assert(0 == 1);
1778  slen = -1;
1779  break;
1780  }
1781 
1782  if (slen < 0) return slen;
1783 
1784  /*
1785  * If we're doing correct escapes, we may have to re-parse the string.
1786  * If the string is from another expansion, it needs re-parsing.
1787  * Or, if it's from a "string" attribute, it needs re-parsing.
1788  * Integers, IP addresses, etc. don't need re-parsing.
1789  */
1790  if (vpt->type != TMPL_TYPE_ATTR) {
1791  value_data_t vd;
1792  int ret;
1793 
1794  PW_TYPE type = PW_TYPE_STRING;
1795 
1796  ret = value_data_from_str(ctx, &vd, &type, NULL, *out, slen, '"');
1797  talloc_free(*out); /* free the old value */
1798  if (ret < 0) return -1;
1799  *out = vd.ptr;
1800  slen = vd.length;
1801  }
1802 
1803  if (vpt->type == TMPL_TYPE_XLAT_STRUCT) {
1804  RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
1805  RDEBUG2(" --> %s", *out);
1806  }
1807 
1808  return slen;
1809 }
1810 
1811 /** Print a #vp_tmpl_t to a string
1812  *
1813  * @param[out] out Where to write the presentation format #vp_tmpl_t string.
1814  * @param[in] outlen Size of output buffer.
1815  * @param[in] vpt to print.
1816  * @param[in] values Used for #TMPL_TYPE_DATA only. #fr_dict_attr_t to use when mapping integer
1817  * values to strings.
1818  * @return
1819  * - The number of bytes written to the out buffer.
1820  * - A number >= outlen if truncation has occurred.
1821  */
1822 size_t tmpl_snprint(char *out, size_t outlen, vp_tmpl_t const *vpt, fr_dict_attr_t const *values)
1823 {
1824  size_t len;
1825  char const *p;
1826  char c;
1827  char *out_p = out, *end = out_p + outlen;
1828 
1829  if (!vpt || (outlen < 3)) {
1830  empty:
1831  *out = '\0';
1832  return 0;
1833  }
1834  VERIFY_TMPL(vpt);
1835 
1836  out[outlen - 1] = '\0'; /* Always terminate for safety */
1837 
1838  switch (vpt->type) {
1839  case TMPL_TYPE_LIST:
1840  *out_p++ = '&';
1841 
1842  /*
1843  * Don't add &current.
1844  */
1845  if (vpt->tmpl_request == REQUEST_CURRENT) {
1846  len = snprintf(out_p, end - out_p, "%s", fr_int2str(pair_lists, vpt->tmpl_list, ""));
1847  RETURN_IF_TRUNCATED(out_p, len, end - out_p);
1848  goto inst_and_tag;
1849  }
1850 
1851  len = snprintf(out_p, end - out_p, "%s.%s", fr_int2str(request_refs, vpt->tmpl_request, ""),
1852  fr_int2str(pair_lists, vpt->tmpl_list, ""));
1853  RETURN_IF_TRUNCATED(out_p, len, end - out_p);
1854  goto inst_and_tag;
1855 
1857  case TMPL_TYPE_ATTR:
1858  *out_p++ = '&';
1859 
1860  p = vpt->type == TMPL_TYPE_ATTR ? vpt->tmpl_da->name : vpt->tmpl_unknown_name;
1861 
1862  /*
1863  * Don't add &current.
1864  */
1865  if (vpt->tmpl_request == REQUEST_CURRENT) {
1866  if (vpt->tmpl_list == PAIR_LIST_REQUEST) {
1867  len = strlcpy(out_p, p, end - out_p);
1868  RETURN_IF_TRUNCATED(out_p, len, end - out_p);
1869  goto inst_and_tag;
1870  }
1871 
1872  /*
1873  * Don't add &request:
1874  */
1875  len = snprintf(out_p, end - out_p, "%s:%s",
1876  fr_int2str(pair_lists, vpt->tmpl_list, ""), p);
1877  RETURN_IF_TRUNCATED(out_p, len, end - out_p);
1878  goto inst_and_tag;
1879  }
1880 
1881  len = snprintf(out_p, end - out_p, "%s.%s:%s", fr_int2str(request_refs, vpt->tmpl_request, ""),
1882  fr_int2str(pair_lists, vpt->tmpl_list, ""), p);
1883  RETURN_IF_TRUNCATED(out_p, len, end - out_p);
1884 
1885  inst_and_tag:
1886  if (vpt->tmpl_tag != TAG_ANY) {
1887  len = snprintf(out_p, end - out_p, ":%d", vpt->tmpl_tag);
1888  RETURN_IF_TRUNCATED(out_p, len, end - out_p);
1889  }
1890 
1891  switch (vpt->tmpl_num) {
1892  case NUM_ANY:
1893  goto finish;
1894 
1895  case NUM_ALL:
1896  len = snprintf(out_p, end - out_p, "[*]");
1897  break;
1898 
1899  case NUM_COUNT:
1900  len = snprintf(out_p, end - out_p, "[#]");
1901  break;
1902 
1903  case NUM_LAST:
1904  len = snprintf(out_p, end - out_p, "[n]");
1905  break;
1906 
1907  default:
1908  len = snprintf(out_p, end - out_p, "[%i]", vpt->tmpl_num);
1909  break;
1910  }
1911  RETURN_IF_TRUNCATED(out_p, len, end - out_p);
1912  goto finish;
1913 
1914  /*
1915  * Regexes have their own set of escaping rules
1916  */
1917  case TMPL_TYPE_REGEX:
1919  if (outlen < 4) goto empty; /* / + <c> + / + \0 */
1920  *out_p++ = '/';
1921  len = fr_snprint(out_p, (end - out_p) - 1, vpt->name, vpt->len, '\0');
1922  RETURN_IF_TRUNCATED(out_p, len, (end - out_p) - 1);
1923  *out_p++ = '/';
1924  goto finish;
1925 
1926  case TMPL_TYPE_XLAT:
1927  case TMPL_TYPE_XLAT_STRUCT:
1928  c = '"';
1929  goto do_literal;
1930 
1931  case TMPL_TYPE_EXEC:
1932  c = '`';
1933  goto do_literal;
1934 
1935  case TMPL_TYPE_UNPARSED:
1936  /*
1937  * Nasty nasty hack that needs to be fixed.
1938  *
1939  * Determines what quoting to use around strings based on their content.
1940  * Should use vpt->quote, but that's not always set correctly
1941  * at the moment.
1942  */
1943  for (p = vpt->name; *p != '\0'; p++) {
1944  if (*p == ' ') break;
1945  if (*p == '\'') break;
1946  if (!fr_dict_attr_allowed_chars[(int) *p]) break;
1947  }
1948  c = *p ? '"' : '\0';
1949 
1950 do_literal:
1951  if (outlen < 4) goto empty; /* / + <c> + / + \0 */
1952  if (c != '\0') *out_p++ = c;
1953  len = fr_snprint(out_p, (end - out_p) - ((c == '\0') ? 0 : 1), vpt->name, vpt->len, c);
1954  RETURN_IF_TRUNCATED(out_p, len, (end - out_p) - ((c == '\0') ? 0 : 1));
1955  if (c != '\0') *out_p++ = c;
1956  break;
1957 
1958  case TMPL_TYPE_DATA:
1959  return value_data_snprint(out, outlen, vpt->tmpl_data_type, values, &vpt->tmpl_data_value,
1960  fr_token_quote[vpt->quote]);
1961 
1962  default:
1963  goto empty;
1964  }
1965 
1966 finish:
1967  *out_p = '\0';
1968  return (out_p - out);
1969 }
1970 
1971 /** Initialise a #vp_cursor_t to the #VALUE_PAIR specified by a #vp_tmpl_t
1972  *
1973  * This makes iterating over the one or more #VALUE_PAIR specified by a #vp_tmpl_t
1974  * significantly easier.
1975  *
1976  * @param err May be NULL if no error code is required. Will be set to:
1977  * - 0 on success.
1978  * - -1 if no matching #VALUE_PAIR could be found.
1979  * - -2 if list could not be found (doesn't exist in current #REQUEST).
1980  * - -3 if context could not be found (no parent #REQUEST available).
1981  * @param cursor to store iterator state.
1982  * @param request The current #REQUEST.
1983  * @param vpt specifying the #VALUE_PAIR type/tag or list to iterate over.
1984  * @return
1985  * - First #VALUE_PAIR specified by the #vp_tmpl_t.
1986  * - NULL if no matching #VALUE_PAIR found, and NULL on error.
1987  *
1988  * @see tmpl_cursor_next
1989  */
1990 VALUE_PAIR *tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
1991 {
1992  VALUE_PAIR **vps, *vp = NULL;
1993  int num;
1994 
1995  VERIFY_TMPL(vpt);
1996 
1997  rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
1998 
1999  if (err) *err = 0;
2000 
2001  if (radius_request(&request, vpt->tmpl_request) < 0) {
2002  if (err) *err = -3;
2003  return NULL;
2004  }
2005  vps = radius_list(request, vpt->tmpl_list);
2006  if (!vps) {
2007  if (err) *err = -2;
2008  return NULL;
2009  }
2010  (void) fr_cursor_init(cursor, vps);
2011 
2012  switch (vpt->type) {
2013  /*
2014  * May not may not be found, but it *is* a known name.
2015  */
2016  case TMPL_TYPE_ATTR:
2017  switch (vpt->tmpl_num) {
2018  case NUM_ANY:
2019  vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
2020  if (!vp) {
2021  if (err) *err = -1;
2022  return NULL;
2023  }
2024  VERIFY_VP(vp);
2025  return vp;
2026 
2027  /*
2028  * Get the last instance of a VALUE_PAIR.
2029  */
2030  case NUM_LAST:
2031  {
2032  VALUE_PAIR *last = NULL;
2033 
2034  while ((vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag))) {
2035  VERIFY_VP(vp);
2036  last = vp;
2037  }
2038  VERIFY_VP(last);
2039  if (!last) break;
2040  return last;
2041  }
2042 
2043  /*
2044  * Callers expect NUM_COUNT to setup the cursor to point
2045  * to the first attribute in the list we're meant to be
2046  * counting.
2047  *
2048  * It does not produce a virtual attribute containing the
2049  * total number of attributes.
2050  */
2051  case NUM_COUNT:
2052  return fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
2053 
2054  default:
2055  num = vpt->tmpl_num;
2056  while ((vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag))) {
2057  VERIFY_VP(vp);
2058  if (num-- <= 0) return vp;
2059  }
2060  break;
2061  }
2062 
2063  if (err) *err = -1;
2064  return NULL;
2065 
2066  case TMPL_TYPE_LIST:
2067  switch (vpt->tmpl_num) {
2068  case NUM_COUNT:
2069  case NUM_ANY:
2070  case NUM_ALL:
2071  vp = fr_cursor_init(cursor, vps);
2072  if (!vp) {
2073  if (err) *err = -1;
2074  return NULL;
2075  }
2076  VERIFY_VP(vp);
2077  return vp;
2078 
2079  /*
2080  * Get the last instance of a VALUE_PAIR.
2081  */
2082  case NUM_LAST:
2083  {
2084  VALUE_PAIR *last = NULL;
2085 
2086  for (vp = fr_cursor_init(cursor, vps);
2087  vp;
2088  vp = fr_cursor_next(cursor)) {
2089  VERIFY_VP(vp);
2090  last = vp;
2091  }
2092  if (!last) break;
2093  VERIFY_VP(last);
2094  return last;
2095  }
2096 
2097  default:
2098  num = vpt->tmpl_num;
2099  for (vp = fr_cursor_init(cursor, vps);
2100  vp;
2101  vp = fr_cursor_next(cursor)) {
2102  VERIFY_VP(vp);
2103  if (num-- <= 0) return vp;
2104  }
2105  break;
2106  }
2107 
2108  break;
2109 
2110  default:
2111  rad_assert(0);
2112  }
2113 
2114  return vp;
2115 }
2116 
2117 /** Returns the next #VALUE_PAIR specified by vpt
2118  *
2119  * @param cursor initialised with #tmpl_cursor_init.
2120  * @param vpt specifying the #VALUE_PAIR type/tag to iterate over.
2121  * Must be one of the following types:
2122  * - #TMPL_TYPE_LIST
2123  * - #TMPL_TYPE_ATTR
2124  * @return
2125  * - The next #VALUE_PAIR matching the #vp_tmpl_t.
2126  * - NULL if no more matching #VALUE_PAIR of the specified type/tag are found.
2127  */
2129 {
2130  rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
2131 
2132  VERIFY_TMPL(vpt);
2133 
2134  switch (vpt->type) {
2135  /*
2136  * May not may not be found, but it *is* a known name.
2137  */
2138  case TMPL_TYPE_ATTR:
2139  switch (vpt->tmpl_num) {
2140  default:
2141  return NULL;
2142 
2143  case NUM_ALL:
2144  case NUM_COUNT: /* This cursor is being used to count matching attrs */
2145  break;
2146  }
2147  return fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
2148 
2149  case TMPL_TYPE_LIST:
2150  switch (vpt->tmpl_num) {
2151  default:
2152  return NULL;
2153 
2154  case NUM_ALL:
2155  case NUM_COUNT: /* This cursor is being used to count matching attrs */
2156  break;
2157  }
2158  return fr_cursor_next(cursor);
2159 
2160  default:
2161  rad_assert(0);
2162  return NULL; /* Older versions of GCC flag the lack of return as an error */
2163  }
2164 }
2165 
2166 /** Copy pairs matching a #vp_tmpl_t in the current #REQUEST
2167  *
2168  * @param ctx to allocate new #VALUE_PAIR in.
2169  * @param out Where to write the copied #VALUE_PAIR (s).
2170  * @param request The current #REQUEST.
2171  * @param vpt specifying the #VALUE_PAIR type/tag or list to copy.
2172  * Must be one of the following types:
2173  * - #TMPL_TYPE_LIST
2174  * - #TMPL_TYPE_ATTR
2175  * @return
2176  * - -1 if no matching #VALUE_PAIR could be found.
2177  * - -2 if list could not be found (doesn't exist in current #REQUEST).
2178  * - -3 if context could not be found (no parent #REQUEST available).
2179  * - -4 on memory allocation error.
2180  */
2181 int tmpl_copy_vps(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
2182 {
2183  VALUE_PAIR *vp;
2184  vp_cursor_t from, to;
2185 
2186  VERIFY_TMPL(vpt);
2187 
2188  int err;
2189 
2190  rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
2191 
2192  *out = NULL;
2193 
2194  fr_cursor_init(&to, out);
2195 
2196  for (vp = tmpl_cursor_init(&err, &from, request, vpt);
2197  vp;
2198  vp = tmpl_cursor_next(&from, vpt)) {
2199  vp = fr_pair_copy(ctx, vp);
2200  if (!vp) {
2201  fr_pair_list_free(out);
2202  return -4;
2203  }
2204  fr_cursor_insert(&to, vp);
2205  }
2206 
2207  return err;
2208 }
2209 
2210 /** Returns the first VP matching a #vp_tmpl_t
2211  *
2212  * @param[out] out where to write the retrieved vp.
2213  * @param[in] request The current #REQUEST.
2214  * @param[in] vpt specifying the #VALUE_PAIR type/tag to find.
2215  * Must be one of the following types:
2216  * - #TMPL_TYPE_LIST
2217  * - #TMPL_TYPE_ATTR
2218  * @return
2219  * - 0 on success (found matching #VALUE_PAIR).
2220  * - -1 if no matching #VALUE_PAIR could be found.
2221  * - -2 if list could not be found (doesn't exist in current #REQUEST).
2222  * - -3 if context could not be found (no parent #REQUEST available).
2223  */
2224 int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
2225 {
2226  vp_cursor_t cursor;
2227  VALUE_PAIR *vp;
2228 
2229  VERIFY_TMPL(vpt);
2230 
2231  int err;
2232 
2233  vp = tmpl_cursor_init(&err, &cursor, request, vpt);
2234  if (out) *out = vp;
2235 
2236  return err;
2237 }
2238 
2239 /** Returns the first VP matching a #vp_tmpl_t, or if no VPs match, creates a new one.
2240  *
2241  * @param[out] out where to write the retrieved or created vp.
2242  * @param[in] request The current #REQUEST.
2243  * @param[in] vpt specifying the #VALUE_PAIR type/tag to retrieve or create. Must be #TMPL_TYPE_ATTR.
2244  * @return
2245  * - 1 on success a pair was created.
2246  * - 0 on success a pair was found.
2247  * - -1 if a new #VALUE_PAIR couldn't be found or created.
2248  * - -2 if list could not be found (doesn't exist in current #REQUEST).
2249  * - -3 if context could not be found (no parent #REQUEST available).
2250  */
2251 int tmpl_find_or_add_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
2252 {
2253  vp_cursor_t cursor;
2254  VALUE_PAIR *vp;
2255  int err;
2256 
2257  VERIFY_TMPL(vpt);
2258  rad_assert(vpt->type == TMPL_TYPE_ATTR);
2259 
2260  *out = NULL;
2261 
2262  vp = tmpl_cursor_init(&err, &cursor, request, vpt);
2263  switch (err) {
2264  case 0:
2265  *out = vp;
2266  return 0;
2267 
2268  case -1:
2269  {
2270  TALLOC_CTX *ctx;
2271  VALUE_PAIR **head;
2272 
2273  RADIUS_LIST_AND_CTX(ctx, head, request, vpt->tmpl_request, vpt->tmpl_list);
2274 
2275  vp = fr_pair_afrom_da(ctx, vpt->tmpl_da);
2276  if (!vp) {
2277  REDEBUG("Failed allocating attribute %s", vpt->tmpl_da->name);
2278  return -1;
2279  }
2280  *out = vp;
2281  }
2282  return 0;
2283 
2284  default:
2285  return err;
2286  }
2287 }
2288 /* @} **/
2289 
2290 #ifdef WITH_VERIFY_PTR
2291 /** Used to check whether areas of a vp_tmpl_t are zeroed out
2292  *
2293  * @param ptr Offset to begin checking at.
2294  * @param len How many bytes to check.
2295  * @return
2296  * - Pointer to the first non-zero byte.
2297  * - NULL if all bytes were zero.
2298  */
2299 static uint8_t const *not_zeroed(uint8_t const *ptr, size_t len)
2300 {
2301  size_t i;
2302 
2303  for (i = 0; i < len; i++) {
2304  if (ptr[i] != 0x00) return ptr + i;
2305  }
2306 
2307  return NULL;
2308 }
2309 #define CHECK_ZEROED(_x) not_zeroed((uint8_t const *)&_x + sizeof(_x), sizeof(vpt->data) - sizeof(_x))
2310 
2311 /** Verify fields of a vp_tmpl_t make sense
2312  *
2313  * @note If the #vp_tmpl_t is invalid, causes the server to exit.
2314  *
2315  * @param file obtained with __FILE__.
2316  * @param line obtained with __LINE__.
2317  * @param vpt to check.
2318  */
2319 void tmpl_verify(char const *file, int line, vp_tmpl_t const *vpt)
2320 {
2321  rad_assert(vpt);
2322 
2323  if (vpt->type == TMPL_TYPE_UNKNOWN) {
2324  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: vp_tmpl_t type was "
2325  "TMPL_TYPE_UNKNOWN (uninitialised)", file, line);
2326  fr_assert(0);
2327  fr_exit_now(1);
2328  }
2329 
2330  if (vpt->type > TMPL_TYPE_NULL) {
2331  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: vp_tmpl_t type was %i "
2332  "(outside range of tmpl_names)", file, line, vpt->type);
2333  fr_assert(0);
2334  fr_exit_now(1);
2335  }
2336 
2337  if (!vpt->name && (vpt->quote != T_INVALID)) {
2338  char quote = vpt->quote > T_TOKEN_LAST ? '?' : fr_token_quote[vpt->quote];
2339 
2340  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: Quote type '%c' (%i) was set for NULL name",
2341  file, line, quote, vpt->quote);
2342  fr_assert(0);
2343  fr_exit_now(1);
2344  }
2345 
2346  if (vpt->name && (vpt->quote == T_INVALID)) {
2347  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: No quoting type was set for name \"%.*s\"",
2348  file, line, (int)vpt->len, vpt->name);
2349  fr_assert(0);
2350  fr_exit_now(1);
2351  }
2352 
2353  /*
2354  * Do a memcmp of the bytes after where the space allocated for
2355  * the union member should have ended and the end of the union.
2356  * These should always be zero if the union has been initialised
2357  * properly.
2358  *
2359  * If they're still all zero, do TMPL_TYPE specific checks.
2360  */
2361  switch (vpt->type) {
2362  case TMPL_TYPE_NULL:
2363  if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2364  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_NULL "
2365  "has non-zero bytes in its data union", file, line);
2366  fr_assert(0);
2367  fr_exit_now(1);
2368  }
2369  break;
2370 
2371  case TMPL_TYPE_UNPARSED:
2372  if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2373  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_UNPARSED "
2374  "has non-zero bytes in its data union", file, line);
2375  fr_assert(0);
2376  fr_exit_now(1);
2377  }
2378  break;
2379 
2380  case TMPL_TYPE_XLAT:
2381  case TMPL_TYPE_XLAT_STRUCT:
2382  break;
2383 
2384 /* @todo When regexes get converted to xlat the flags field of the regex union is used
2385  case TMPL_TYPE_XLAT:
2386  if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2387  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT "
2388  "has non-zero bytes in its data union", file, line);
2389  fr_assert(0);
2390  fr_exit_now(1);
2391  }
2392  break;
2393 
2394  case TMPL_TYPE_XLAT_STRUCT:
2395  if (CHECK_ZEROED(vpt->data.xlat)) {
2396  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT_STRUCT "
2397  "has non-zero bytes after the data.xlat pointer in the union", file, line);
2398  fr_assert(0);
2399  fr_exit_now(1);
2400  }
2401  break;
2402 */
2403 
2404  case TMPL_TYPE_EXEC:
2405  if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2406  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_EXEC "
2407  "has non-zero bytes in its data union", file, line);
2408  fr_assert(0);
2409  fr_exit_now(1);
2410  }
2411  break;
2412 
2414  rad_assert(vpt->tmpl_da == NULL);
2415  break;
2416 
2417  case TMPL_TYPE_ATTR:
2418  if (CHECK_ZEROED(vpt->data.attribute)) {
2419  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2420  "has non-zero bytes after the data.attribute struct in the union",
2421  file, line);
2422  fr_assert(0);
2423  fr_exit_now(1);
2424  }
2425 
2426  if (vpt->tmpl_da->flags.is_unknown) {
2427  if (vpt->tmpl_da != (fr_dict_attr_t const *)&vpt->data.attribute.unknown.da) {
2428  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2429  "da is marked as unknown, but does not point to the template's "
2430  "unknown da buffer", file, line);
2431  fr_assert(0);
2432  fr_exit_now(1);
2433  }
2434 
2435  } else {
2436  fr_dict_attr_t const *da;
2437 
2438  /*
2439  * Attribute may be present with multiple names
2440  */
2441  da = fr_dict_attr_by_name(NULL, vpt->tmpl_da->name);
2442  if (!da) {
2443  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2444  "attribute \"%s\" (%s) not found in global dictionary",
2445  file, line, vpt->tmpl_da->name,
2446  fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"));
2447  fr_assert(0);
2448  fr_exit_now(1);
2449  }
2450 
2451  if ((da->type == PW_TYPE_COMBO_IP_ADDR) && (da->type != vpt->tmpl_da->type)) {
2452  da = fr_dict_attr_by_type(NULL, vpt->tmpl_da->vendor,
2453  vpt->tmpl_da->attr, vpt->tmpl_da->type);
2454  if (!da) {
2455  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2456  "attribute \"%s\" variant (%s) not found in global dictionary",
2457  file, line, vpt->tmpl_da->name,
2458  fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"));
2459  fr_assert(0);
2460  fr_exit_now(1);
2461  }
2462  }
2463 
2464  if (da != vpt->tmpl_da) {
2465  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2466  "dictionary pointer %p \"%s\" (%s) "
2467  "and global dictionary pointer %p \"%s\" (%s) differ",
2468  file, line,
2469  vpt->tmpl_da, vpt->tmpl_da->name,
2470  fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"),
2471  da, da->name,
2472  fr_int2str(dict_attr_types, da->type, "<INVALID>"));
2473  fr_assert(0);
2474  fr_exit_now(1);
2475  }
2476  }
2477  break;
2478 
2479  case TMPL_TYPE_LIST:
2480  if (CHECK_ZEROED(vpt->data.attribute)) {
2481  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST"
2482  "has non-zero bytes after the data.attribute struct in the union", file, line);
2483  fr_assert(0);
2484  fr_exit_now(1);
2485  }
2486 
2487  if (vpt->tmpl_da != NULL) {
2488  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST da pointer was NULL", file, line);
2489  fr_assert(0);
2490  fr_exit_now(1);
2491  }
2492  break;
2493 
2494  case TMPL_TYPE_DATA:
2495  if (CHECK_ZEROED(vpt->data.literal)) {
2496  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA "
2497  "has non-zero bytes after the data.literal struct in the union",
2498  file, line);
2499  fr_assert(0);
2500  fr_exit_now(1);
2501  }
2502 
2503  if (vpt->tmpl_data_type == PW_TYPE_INVALID) {
2504  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
2505  "PW_TYPE_INVALID (uninitialised)", file, line);
2506  fr_assert(0);
2507  fr_exit_now(1);
2508  }
2509 
2510  if (vpt->tmpl_data_type >= PW_TYPE_MAX) {
2511  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
2512  "%i (outside the range of PW_TYPEs)", file, line, vpt->tmpl_data_type);
2513  fr_assert(0);
2514  fr_exit_now(1);
2515  }
2516  /*
2517  * Unlike VALUE_PAIRs we can't guarantee that VALUE_PAIR_TMPL buffers will
2518  * be talloced. They may be allocated on the stack or in global variables.
2519  */
2520  switch (vpt->tmpl_data_type) {
2521  case PW_TYPE_STRING:
2522  if (vpt->tmpl_data.vp_strvalue[vpt->tmpl_data_length] != '\0') {
2523  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA char buffer not \\0 "
2524  "terminated", file, line);
2525  fr_assert(0);
2526  fr_exit_now(1);
2527  }
2528  break;
2529 
2530  case PW_TYPE_TLV:
2531  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA is of type TLV",
2532  file, line);
2533  fr_assert(0);
2534  fr_exit_now(1);
2535 
2536  case PW_TYPE_OCTETS:
2537  break;
2538 
2539  default:
2540  if (vpt->tmpl_data_length == 0) {
2541  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA data pointer not NULL "
2542  "but len field is zero", file, line);
2543  fr_assert(0);
2544  fr_exit_now(1);
2545  }
2546  }
2547 
2548  break;
2549 
2550  case TMPL_TYPE_REGEX:
2551  /*
2552  * iflag field is used for non compiled regexes too.
2553  */
2554  if (CHECK_ZEROED(vpt->data.preg)) {
2555  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2556  "has non-zero bytes after the data.preg struct in the union", file, line);
2557  fr_assert(0);
2558  fr_exit_now(1);
2559  }
2560 
2561  if (vpt->tmpl_preg != NULL) {
2562  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2563  "preg field was not NULL", file, line);
2564  fr_assert(0);
2565  fr_exit_now(1);
2566  }
2567 
2568  if ((vpt->tmpl_iflag != true) && (vpt->tmpl_iflag != false)) {
2569  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2570  "iflag field was neither true or false", file, line);
2571  fr_assert(0);
2572  fr_exit_now(1);
2573  }
2574 
2575  if ((vpt->tmpl_mflag != true) && (vpt->tmpl_mflag != false)) {
2576  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2577  "mflag field was neither true or false", file, line);
2578  fr_assert(0);
2579  fr_exit_now(1);
2580  }
2581 
2582  break;
2583 
2585  if (CHECK_ZEROED(vpt->data.preg)) {
2586  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
2587  "has non-zero bytes after the data.preg struct in the union", file, line);
2588  fr_assert(0);
2589  fr_exit_now(1);
2590  }
2591 
2592  if (vpt->tmpl_preg == NULL) {
2593  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
2594  "comp field was NULL", file, line);
2595  fr_assert(0);
2596  fr_exit_now(1);
2597  }
2598 
2599  if ((vpt->tmpl_iflag != true) && (vpt->tmpl_iflag != false)) {
2600  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
2601  "iflag field was neither true or false", file, line);
2602  fr_assert(0);
2603  fr_exit_now(1);
2604  }
2605 
2606  if ((vpt->tmpl_mflag != true) && (vpt->tmpl_mflag != false)) {
2607  FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2608  "mflag field was neither true or false", file, line);
2609  fr_assert(0);
2610  fr_exit_now(1);
2611  }
2612  break;
2613 
2614  case TMPL_TYPE_UNKNOWN:
2615  rad_assert(0);
2616  }
2617 }
2618 #endif
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
Definition: pair.c:544
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
Definition: dict.c:3611
ssize_t ssize_t ssize_t radius_axlat(char **out, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
int tmpl_cast_to_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt, fr_dict_attr_t const *cast)
Expand a vp_tmpl_t to a string, parse it as an attribute of type cast, create a VALUE_PAIR from the r...
Definition: tmpl.c:1304
int radius_exec_program(TALLOC_CTX *ctx, char *out, size_t outlen, VALUE_PAIR **output_pairs, REQUEST *request, char const *cmd, VALUE_PAIR *input_pairs, bool exec_wait, bool shell_escape, int timeout) CC_HINT(nonnull(5
vp_tmpl_t * tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
Initialise stack allocated vp_tmpl_t.
Definition: tmpl.c:497
const char fr_token_quote[]
Convert tokens back to a quoting character.
Definition: token.c:96
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
int radius_request(REQUEST **context, request_refs_t name)
Resolve a request_refs_t to a REQUEST.
Definition: tmpl.c:451
RADIUS_PACKET * radius_packet(REQUEST *request, pair_lists_t list)
Resolve a list to the RADIUS_PACKET holding the HEAD pointer for a VALUE_PAIR list.
Definition: tmpl.c:279
size_t tmpl_snprint(char *out, size_t outlen, vp_tmpl_t const *vpt, fr_dict_attr_t const *values)
Print a vp_tmpl_t to a string.
Definition: tmpl.c:1822
ssize_t ssize_t ssize_t ssize_t radius_axlat_struct(char **out, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx) CC_HINT(nonnull(1
FR_NAME_NUMBER const tmpl_names[]
Map tmpl_type_t values to descriptive strings.
Definition: tmpl.c:36
#define NUM_ANY
Definition: pair.h:201
RADIUS_PACKET * proxy_reply
Incoming response from proxy server.
Definition: radiusd.h:238
Dictionary attribute.
Definition: dict.h:77
REQUEST containing the outer layer of the EAP conversation.
Definition: tmpl.h:110
char const * name
Raw string used to create the template.
Definition: tmpl.h:190
#define MEM(x)
Definition: radiusd.h:396
bool auto_converted
Attr-26.9.1 –> Cisco-AVPair.
Definition: tmpl.h:194
int tmpl_cast_in_place(vp_tmpl_t *vpt, PW_TYPE type, fr_dict_attr_t const *enumv)
Convert vp_tmpl_t of type TMPL_TYPE_UNPARSED or TMPL_TYPE_DATA to TMPL_TYPE_DATA of type specified...
Definition: tmpl.c:1212
WiMAX IPv4 or IPv6 address depending on length.
Definition: radius.h:46
Dictionary attribute.
Definition: tmpl.h:133
static char const * name
TALLOC_CTX * radius_list_ctx(REQUEST *request, pair_lists_t list)
Return the correct TALLOC_CTX to alloc VALUE_PAIR in, for a list.
Definition: tmpl.c:331
Attributes sent in response to the forked Disconnect-Request.
Definition: tmpl.h:101
ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:926
int tmpl_define_unknown_attr(vp_tmpl_t *vpt)
Add an unknown fr_dict_attr_t specified by a vp_tmpl_t to the main dictionary.
Definition: tmpl.c:1360
Pre-parsed XLAT expansion.
Definition: tmpl.h:139
Attributes to send in a forked CoA-Request.
Definition: tmpl.h:97
#define VERIFY_VP(_x)
Definition: pair.h:44
Unparsed literal string.
Definition: tmpl.h:131
void size_t fr_pair_value_snprint(char *out, size_t outlen, VALUE_PAIR const *vp, char quote)
Print the value of an attribute to a string.
Definition: pair.c:2107
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
Unknown request.
Definition: tmpl.h:109
union value_pair_tmpl_attr_t::@10 unknown
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
int fr_dict_attr_add(fr_dict_t *dict, fr_dict_attr_t const *parent, char const *name, int attr, PW_TYPE type, fr_dict_attr_flags_t flags)
Add an attribute to the dictionary.
Definition: dict.c:582
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
Number of defined data types.
Definition: radius.h:59
Values of the encryption flags.
Definition: dict.h:40
A copy of attributes in the request list that may be modified in pre-proxy before proxying the reques...
Definition: tmpl.h:90
size_t(* xlat_escape_t)(REQUEST *request, char *out, size_t outlen, char const *in, void *arg)
Definition: xlat.h:36
pair_lists_t list
List to search or insert in.
Definition: tmpl.h:150
VALUE_PAIR * tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt)
Returns the next VALUE_PAIR specified by vpt.
Definition: tmpl.c:2128
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
fr_dict_attr_flags_t flags
Flags.
Definition: dict.h:88
const int fr_dict_attr_allowed_chars[256]
Definition: dict.c:145
size_t fr_snprint(char *out, size_t outlen, char const *in, ssize_t inlen, char quote)
Escape any non printable or non-UTF8 characters in the input string.
Definition: print.c:179
char * fr_pair_value_asprint(TALLOC_CTX *ctx, VALUE_PAIR const *vp, char quote)
Print one attribute value to a string.
Definition: pair.c:2123
RADIUS_PACKET * proxy
Outgoing request to proxy server.
Definition: radiusd.h:237
Attributes to send in a forked Disconnect-Request.
Definition: tmpl.h:100
pair_lists
Definition: tmpl.h:80
Attribute not found in the global dictionary.
Definition: tmpl.h:134
#define rad_assert(expr)
Definition: rad_assert.h:38
Pre-parsed regular expression.
Definition: tmpl.h:140
void tmpl_cast_in_place_str(vp_tmpl_t *vpt)
Convert vp_tmpl_t of type TMPL_TYPE_UNPARSED to TMPL_TYPE_DATA of type PW_TYPE_STRING.
Definition: tmpl.c:1273
unsigned int is_unknown
Attribute number or vendor is unknown.
Definition: dict.h:42
int value_data_cast(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE dst_type, fr_dict_attr_t const *dst_enumv, PW_TYPE src_type, fr_dict_attr_t const *src_enumv, value_data_t const *src)
Convert one type of value_data_t to another.
Definition: value.c:1073
Value in native format.
Definition: tmpl.h:138
ssize_t tmpl_from_attr_substr(vp_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:661
void tmpl_from_da(vp_tmpl_t *vpt, fr_dict_attr_t const *da, int8_t tag, int num, request_refs_t request, pair_lists_t list)
Initialise a vp_tmpl_t to search for, or create attributes.
Definition: tmpl.c:567
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
Definition: cursor.c:321
const FR_NAME_NUMBER dict_attr_types[]
Map data types to names representing those types.
Definition: dict.c:85
size_t fr_hex2bin(uint8_t *bin, size_t outlen, char const *hex, size_t inlen)
Convert hex strings to binary data.
Definition: misc.c:220
Regular expression.
Definition: tmpl.h:136
#define FR_FAULT_LOG(fmt,...)
Definition: libradius.h:462
REQUEST * coa
CoA request originated by this request.
Definition: radiusd.h:307
Attributes sent in response to the forked CoA-Request.
Definition: tmpl.h:98
TALLOC_CTX * state_ctx
for request->state
Definition: radiusd.h:230
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
unsigned int code
Packet code (type).
Definition: libradius.h:155
#define fr_assert(_x)
Definition: libradius.h:505
size_t radius_request_name(request_refs_t *out, char const *name, request_refs_t def)
Resolve attribute name to a request_refs_t value.
Definition: tmpl.c:413
Attribute list.
Definition: tmpl.h:135
int value_data_steal(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE type, value_data_t const *src)
Copy value data verbatim moving any buffers to the specified context.
Definition: value.c:1512
int fr_dict_unknown_from_suboid(fr_dict_t *dict, fr_dict_attr_t *vendor_da, fr_dict_attr_t *da, fr_dict_attr_t const *parent, char const **name)
Create a dictionary attribute by name embedded in another string.
Definition: dict.c:3034
REQUEST * parent
Definition: radiusd.h:290
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
ssize_t ssize_t radius_xlat_struct(char *out, size_t outlen, REQUEST *request, xlat_exp_t const *xlat, xlat_escape_t escape, void *ctx) CC_HINT(nonnull(1
int num
For array references.
Definition: tmpl.h:158
ssize_t tmpl_expand(char const **out, char *buff, size_t bufflen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
Definition: tmpl.c:1479
Invalid (uninitialised) attribute type.
Definition: radius.h:32
The current request.
Definition: tmpl.h:113
#define VERIFY_TMPL(_x)
Definition: tmpl.h:266
ssize_t radius_xlat(char *out, size_t outlen, REQUEST *request, char const *fmt, xlat_escape_t escape, void *escape_ctx) CC_HINT(nonnull(1
int fr_pair_value_from_str(VALUE_PAIR *vp, char const *value, size_t len)
Convert string value to native attribute value.
Definition: pair.c:1840
tmpl_type_t type
What type of value tmpl refers to.
Definition: tmpl.h:188
RFC3575/RFC5176 - CoA-Request.
Definition: radius.h:108
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
#define RWDEBUG2(fmt,...)
Definition: log.h:252
enum tmpl_type tmpl_type_t
Types of vp_tmpl_t.
size_t len
Length of the raw string used to create the template.
Definition: tmpl.h:191
#define RETURN_IF_TRUNCATED(_p, _ret, _max)
Boilerplate for checking truncation.
Definition: libradius.h:216
int value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE type, const value_data_t *src)
Copy value data verbatim duplicating any buffers.
Definition: value.c:1479
fr_dict_attr_t const * fr_dict_attr_by_type(fr_dict_t *dict, unsigned int vendor, unsigned int attr, PW_TYPE type)
Lookup a attribute by its its vendor and attribute numbers and data type.
Definition: dict.c:3549
Callout to an external script or program.
Definition: tmpl.h:137
#define RDEBUG2(fmt,...)
Definition: log.h:244
#define NUM_ALL
Definition: pair.h:202
int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
Returns the first VP matching a vp_tmpl_t.
Definition: tmpl.c:2224
char name[1]
Attribute name.
Definition: dict.h:89
uint8_t data[]
Definition: eap_pwd.h:625
size_t length
Length of value data.
Definition: pair.h:87
char * talloc_bstrndup(void const *t, char const *in, size_t inlen)
Binary safe strndup function.
Definition: missing.c:632
request_refs_t request
Request to search or insert in.
Definition: tmpl.h:149
#define TAG_ANY
Definition: pair.h:191
ssize_t tmpl_from_attr_str(vp_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:877
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
VALUE_PAIR * state
VALUE_PAIR (s) available over the lifetime of the authentication attempt.
Definition: radiusd.h:231
Describes a TMPL_TYPE_ATTR, TMPL_TYPE_ATTR_UNDEFINED or TMPL_TYPE_LIST.
Definition: tmpl.h:148
Unknown list.
Definition: tmpl.h:81
vp_tmpl_t * tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
Create a new heap allocated vp_tmpl_t.
Definition: tmpl.c:526
int value_data_from_str(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE *src_type, fr_dict_attr_t const *src_enumv, char const *src, ssize_t src_len, char quote)
Convert string value to a value_data_t type.
Definition: value.c:455
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
Attributes to send in the response.
Definition: tmpl.h:84
int tmpl_find_or_add_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
Returns the first VP matching a vp_tmpl_t, or if no VPs match, creates a new one. ...
Definition: tmpl.c:2251
#define fr_exit_now(_x)
Definition: libradius.h:511
ssize_t tmpl_aexpand(TALLOC_CTX *ctx, char **out, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a template to a string, allocing a new buffer to hold the string.
Definition: tmpl.c:1653
enum pair_lists pair_lists_t
fr_dict_attr_t const * fr_dict_attr_by_name_substr(fr_dict_t *dict, char const **name)
Look up a dictionary attribute by a name embedded in another string.
Definition: dict.c:3445
fr_dict_attr_t const * fr_dict_unknown_add(fr_dict_t *dict, fr_dict_attr_t const *old)
Converts an unknown to a known by adding it to the internal dictionaries.
Definition: dict.c:2384
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
#define REDEBUG(fmt,...)
Definition: log.h:254
ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
Definition: tmpl.c:956
unsigned int has_tag
Tagged attribute.
Definition: dict.h:46
VALUE_PAIR * fr_pair_copy(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
Copy a single valuepair.
Definition: pair.c:129
VALUE_PAIR * tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
Initialise a vp_cursor_t to the VALUE_PAIR specified by a vp_tmpl_t.
Definition: tmpl.c:1990
#define EXEC_TIMEOUT
Definition: radiusd.h:329
Not currently used.
Definition: tmpl.h:114
fr_dict_attr_t const * da
Resolved dictionary attribute.
Definition: tmpl.h:152
#define NUM_LAST
Definition: pair.h:204
enum fr_token FR_TOKEN
int tmpl_copy_vps(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
Copy pairs matching a vp_tmpl_t in the current REQUEST.
Definition: tmpl.c:2181
Uninitialised.
Definition: tmpl.h:130
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
VALUE_PAIR * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute.
Definition: pair.c:58
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
XLAT expansion.
Definition: tmpl.h:132
Attributes to store multiple rounds of challenges/responses.
Definition: tmpl.h:87
#define NUM_COUNT
Definition: pair.h:203
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
#define RDEBUG4(fmt,...)
Definition: log.h:246
#define RADIUS_LIST_AND_CTX(_ctx, _head, _request, _ref, _list)
Determine the correct context and list head.
Definition: tmpl.h:333
Attributes that change the behaviour of modules.
Definition: tmpl.h:85
String of printable characters.
Definition: radius.h:33
Contains nested attributes.
Definition: radius.h:47
FR_TOKEN quote
What type of quoting was around the raw string.
Definition: tmpl.h:192
PW_TYPE type
Value type.
Definition: dict.h:80
int tmpl_afrom_value_data(TALLOC_CTX *ctx, vp_tmpl_t **out, value_data_t *data, PW_TYPE type, fr_dict_attr_t const *enumv, bool steal)
Create a vp_tmpl_t from a value_data_t.
Definition: tmpl.c:595
#define RCSID(id)
Definition: build.h:135
VALUE_PAIR * fr_cursor_next_by_da(vp_cursor_t *cursor, fr_dict_attr_t const *da, int8_t tag) CC_HINT(nonnull)
Iterate over attributes of a given DA in the pairlist.
Definition: cursor.c:237
int fr_substr2int(FR_NAME_NUMBER const *table, char const *name, int def, int len)
Definition: token.c:471
Attributes sent in response to the proxied request.
Definition: tmpl.h:93
VALUE_PAIR ** radius_list(REQUEST *request, pair_lists_t list)
Resolve attribute pair_lists_t value to an attribute list.
Definition: tmpl.c:195
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
size_t radius_list_name(pair_lists_t *out, char const *name, pair_lists_t def)
Resolve attribute name to a pair_lists_t value.
Definition: tmpl.c:120
union vp_tmpl_t::@11 data
fr_dict_t * fr_dict_internal
Internal server dictionary.
Definition: dict.c:81
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
Definition: dict.c:2339
ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *in, size_t inlen, FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def, bool do_unescape)
Convert an arbitrary string into a vp_tmpl_t.
Definition: tmpl.c:1022
A source or sink of value data.
Definition: tmpl.h:187
enum requests request_refs_t
char * value_data_asprint(TALLOC_CTX *ctx, PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
Print one attribute value to a string.
Definition: value.c:1543
Raw octets.
Definition: radius.h:38
Has no value.
Definition: tmpl.h:141
int tmpl_define_undefined_attr(vp_tmpl_t *vpt, PW_TYPE type, fr_dict_attr_flags_t const *flags)
Add an undefined fr_dict_attr_t specified by a vp_tmpl_t to the main dictionary.
Definition: tmpl.c:1396
int8_t tag
For tag references.
Definition: tmpl.h:159
PW_TYPE
Internal data types used within libfreeradius.
Definition: radius.h:31
const FR_NAME_NUMBER request_refs[]
Map keywords to request_refs_t values.
Definition: tmpl.c:74
RFC3575/RFC5176 - Disconnect-Request.
Definition: radius.h:105
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_t *dict, char const *attr)
Locate a fr_dict_attr_t by its name.
Definition: dict.c:3493
value_data_t data
Definition: pair.h:133
size_t value_data_snprint(char *out, size_t outlen, PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
Print the value of an attribute to a string.
Definition: value.c:1727