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.
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.
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
20 * @brief #VALUE_PAIR template functions
25 * @copyright 2014-2015 The FreeRADIUS server project
29 #include <freeradius-devel/radiusd.h>
30 #include <freeradius-devel/rad_assert.h>
34 /** Map #tmpl_type_t values to descriptive strings
36 FR_NAME_NUMBER const tmpl_names[] = {
37 { "literal", TMPL_TYPE_LITERAL },
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 },
51 /** Map keywords to #pair_lists_t values
53 const FR_NAME_NUMBER pair_lists[] = {
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 },
60 { "proxy-request", PAIR_LIST_PROXY_REQUEST },
61 { "proxy-reply", PAIR_LIST_PROXY_REPLY },
64 { "coa", PAIR_LIST_COA },
65 { "coa-reply", PAIR_LIST_COA_REPLY },
66 { "disconnect", PAIR_LIST_DM },
67 { "disconnect-reply", PAIR_LIST_DM_REPLY },
72 /** Map keywords to #request_refs_t values
74 const FR_NAME_NUMBER request_refs[] = {
75 { "outer", REQUEST_OUTER },
76 { "current", REQUEST_CURRENT },
77 { "parent", REQUEST_PARENT },
81 /** @name Parse list and request qualifiers to #pair_lists_t and #request_refs_t values
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.
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.
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.
94 /** Resolve attribute name to a #pair_lists_t value.
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.
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
104 * If we can't find a string that looks like a request qualifier, set out to def, and
107 * @note #radius_list_name should be called before passing a name string that may
108 * contain qualifiers to #dict_attrbyname.
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).
120 size_t radius_list_name(pair_lists_t *out, char const *name, pair_lists_t def)
122 char const *p = name;
125 /* This should never be a NULL pointer */
129 * Try and determine the end of the token
131 for (q = p; dict_attr_allowed_chars[(uint8_t) *q]; q++);
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
141 *out = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
142 if (*out != PAIR_LIST_UNKNOWN) return q - p;
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.
154 char const *d = q + 1;
156 if (isdigit((int) *d)) {
157 while (isdigit((int) *d)) d++;
160 * Char after the number string
161 * was a token delimiter, so this is a
162 * tag, not a list qualifier.
164 if (!dict_attr_allowed_chars[(uint8_t) *d]) {
170 *out = fr_substr2int(pair_lists, p, PAIR_LIST_UNKNOWN, (q - p));
171 if (*out == PAIR_LIST_UNKNOWN) return 0;
173 return (q + 1) - name; /* Consume the list and delimiter */
182 /** Resolve attribute #pair_lists_t value to an attribute list.
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.
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.
192 * @see tmpl_cursor_init
193 * @see fr_cursor_init
195 VALUE_PAIR **radius_list(REQUEST *request, pair_lists_t list)
197 if (!request) return NULL;
200 /* Don't add default */
201 case PAIR_LIST_UNKNOWN:
204 case PAIR_LIST_REQUEST:
205 if (!request->packet) return NULL;
206 return &request->packet->vps;
208 case PAIR_LIST_REPLY:
209 if (!request->reply) return NULL;
210 return &request->reply->vps;
212 case PAIR_LIST_CONTROL:
213 return &request->config;
215 case PAIR_LIST_STATE:
216 return &request->state;
219 case PAIR_LIST_PROXY_REQUEST:
220 if (!request->proxy) break;
221 return &request->proxy->vps;
223 case PAIR_LIST_PROXY_REPLY:
224 if (!request->proxy_reply) break;
225 return &request->proxy_reply->vps;
230 (request->coa->proxy->code == PW_CODE_COA_REQUEST)) {
231 return &request->coa->proxy->vps;
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;
245 (request->coa->proxy->code == PW_CODE_DISCONNECT_REQUEST)) {
246 return &request->coa->proxy->vps;
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;
260 RWDEBUG2("List \"%s\" is not available",
261 fr_int2str(pair_lists, list, "<INVALID>"));
266 /** Resolve a list to the #RADIUS_PACKET holding the HEAD pointer for a #VALUE_PAIR list
268 * Returns a pointer to the #RADIUS_PACKET that holds the HEAD pointer of a given list,
269 * for the current #REQUEST.
271 * @param[in] request To resolve list in.
272 * @param[in] list #pair_lists_t value to resolve to #RADIUS_PACKET.
273 * @return a #RADIUS_PACKET on success, else NULL.
277 RADIUS_PACKET *radius_packet(REQUEST *request, pair_lists_t list)
280 /* Don't add default */
281 case PAIR_LIST_STATE:
282 case PAIR_LIST_CONTROL:
283 case PAIR_LIST_UNKNOWN:
286 case PAIR_LIST_REQUEST:
287 return request->packet;
289 case PAIR_LIST_REPLY:
290 return request->reply;
293 case PAIR_LIST_PROXY_REQUEST:
294 return request->proxy;
296 case PAIR_LIST_PROXY_REPLY:
297 return request->proxy_reply;
303 return request->coa->packet;
305 case PAIR_LIST_COA_REPLY:
306 case PAIR_LIST_DM_REPLY:
307 return request->coa->reply;
314 /** Return the correct TALLOC_CTX to alloc #VALUE_PAIR in, for a list
316 * Allocating new #VALUE_PAIR in the context of a #REQUEST is usually wrong.
317 * #VALUE_PAIR should be allocated in the context of a #RADIUS_PACKET, so that if the
318 * #RADIUS_PACKET is freed before the #REQUEST, the associated #VALUE_PAIR lists are
321 * @param[in] request containing the target lists.
322 * @param[in] list #pair_lists_t value to resolve to TALLOC_CTX.
323 * @return a TALLOC_CTX on success, else NULL.
327 TALLOC_CTX *radius_list_ctx(REQUEST *request, pair_lists_t list)
329 if (!request) return NULL;
332 case PAIR_LIST_REQUEST:
333 return request->packet;
335 case PAIR_LIST_REPLY:
336 return request->reply;
338 case PAIR_LIST_CONTROL:
341 case PAIR_LIST_STATE:
345 case PAIR_LIST_PROXY_REQUEST:
346 return request->proxy;
348 case PAIR_LIST_PROXY_REPLY:
349 return request->proxy_reply;
354 if (!request->coa) return NULL;
355 rad_assert(request->coa->proxy != NULL);
356 if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
357 return request->coa->proxy;
359 case PAIR_LIST_COA_REPLY:
360 if (!request->coa) return NULL;
361 rad_assert(request->coa->proxy != NULL);
362 if (request->coa->proxy->code != PW_CODE_COA_REQUEST) return NULL;
363 return request->coa->proxy_reply;
366 if (!request->coa) return NULL;
367 rad_assert(request->coa->proxy != NULL);
368 if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
369 return request->coa->proxy;
371 case PAIR_LIST_DM_REPLY:
372 if (!request->coa) return NULL;
373 rad_assert(request->coa->proxy != NULL);
374 if (request->coa->proxy->code != PW_CODE_DISCONNECT_REQUEST) return NULL;
375 return request->coa->proxy_reply;
377 /* Don't add default */
378 case PAIR_LIST_UNKNOWN:
385 /** Resolve attribute name to a #request_refs_t value.
387 * Check the name string for qualifiers that reference a parent #REQUEST.
389 * If we find a string that matches a #request_refs qualifier, return the number of chars
392 * If we're sure we've definitely found a list qualifier token delimiter (``*``) but the
393 * qualifier doesn't match one of the #request_refs qualifiers, return 0 and set out to
396 * If we can't find a string that looks like a request qualifier, set out to def, and
399 * @param[out] out The #request_refs_t value the name resolved to (or #REQUEST_UNKNOWN).
400 * @param[in] name of attribute.
401 * @param[in] def default request ref to return if no request qualifier is present.
402 * @return 0 if no valid request qualifier could be found, else the number of bytes consumed.
403 * The caller may then advanced the name pointer by the value returned, to get the
404 * start of the attribute list or attribute name(if any).
406 * @see radius_list_name
409 size_t radius_request_name(request_refs_t *out, char const *name, request_refs_t def)
415 * Try and determine the end of the token
417 for (q = p; dict_attr_allowed_chars[(uint8_t) *q] && (*q != '.') && (*q != '-'); q++);
420 * First token delimiter wasn't a '.'
427 *out = fr_substr2int(request_refs, name, REQUEST_UNKNOWN, q - p);
428 if (*out == REQUEST_UNKNOWN) return 0;
433 /** Resolve a #request_refs_t to a #REQUEST.
435 * Sometimes #REQUEST structs may be chained to each other, as is the case
436 * when internally proxying EAP. This function resolves a #request_refs_t
437 * to a #REQUEST higher in the chain than the current #REQUEST.
440 * @param[in,out] context #REQUEST to start resolving from, and where to write
441 * a pointer to the resolved #REQUEST back to.
442 * @param[in] name (request) to resolve.
443 * @return 0 if request is valid in this context, else -1.
445 int radius_request(REQUEST **context, request_refs_t name)
447 REQUEST *request = *context;
450 case REQUEST_CURRENT:
453 case REQUEST_PARENT: /* for future use in request chaining */
455 if (!request->parent) {
458 *context = request->parent;
461 case REQUEST_UNKNOWN:
471 /** @name Alloc or initialise #vp_tmpl_t
473 * @note Should not usually be called outside of tmpl_* functions, use one of
474 * the tmpl_*from_* functions instead.
478 /** Initialise stack allocated #vp_tmpl_t
480 * @note Name is not strdupe'd or memcpy'd so must be available, and must not change
481 * for the lifetime of the #vp_tmpl_t.
483 * @param[out] vpt to initialise.
484 * @param[in] type to set in the #vp_tmpl_t.
485 * @param[in] name of the #vp_tmpl_t.
486 * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
487 * If < 0 strlen will be used to determine the length.
488 * @return a pointer to the initialised #vp_tmpl_t. The same value as
491 vp_tmpl_t *tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type, char const *name, ssize_t len)
494 rad_assert(type != TMPL_TYPE_UNKNOWN);
495 rad_assert(type <= TMPL_TYPE_NULL);
497 memset(vpt, 0, sizeof(vp_tmpl_t));
502 vpt->len = len < 0 ? strlen(name) :
508 /** Create a new heap allocated #vp_tmpl_t
510 * @param[in,out] ctx to allocate in.
511 * @param[in] type to set in the #vp_tmpl_t.
512 * @param[in] name of the #vp_tmpl_t (will be copied to a new talloc buffer parented
513 * by the #vp_tmpl_t).
514 * @param[in] len The length of the buffer (or a substring of the buffer) pointed to by name.
515 * If < 0 strlen will be used to determine the length.
516 * @return the newly allocated #vp_tmpl_t.
518 vp_tmpl_t *tmpl_alloc(TALLOC_CTX *ctx, tmpl_type_t type, char const *name, ssize_t len)
522 rad_assert(type != TMPL_TYPE_UNKNOWN);
523 rad_assert(type <= TMPL_TYPE_NULL);
525 vpt = talloc_zero(ctx, vp_tmpl_t);
526 if (!vpt) return NULL;
529 vpt->name = talloc_bstrndup(vpt, name, len < 0 ? strlen(name) : (size_t)len);
530 vpt->len = talloc_array_length(vpt->name) - 1;
537 /** @name Create new #vp_tmpl_t from a string
541 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
543 * @note The name field is just a copy of the input pointer, if you know that string might be
544 * freed before you're done with the #vp_tmpl_t use #tmpl_afrom_attr_str
547 * @param[out] vpt to modify.
548 * @param[in] name of attribute including #request_refs and #pair_lists qualifiers.
549 * If only #request_refs and #pair_lists qualifiers are found, a #TMPL_TYPE_LIST
550 * #vp_tmpl_t will be produced.
551 * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
553 * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
555 * @param[in] allow_unknown If true attributes in the format accepted by
556 * #dict_unknown_from_substr will be allowed, even if they're not in the main
558 * If an unknown attribute is found a #TMPL_TYPE_ATTR #vp_tmpl_t will be
559 * produced with the unknown #DICT_ATTR stored in the ``unknown.da`` buffer.
560 * This #DICT_ATTR will have its ``flags.is_unknown`` field set to true.
561 * If #tmpl_from_attr_substr is being called on startup, the #vp_tmpl_t may be
562 * passed to #tmpl_define_unknown_attr to add the unknown attribute to the main
564 * If the unknown attribute is not added to the main dictionary the #vp_tmpl_t
565 * cannot be used to search for a #VALUE_PAIR in a #REQUEST.
566 * @param[in] allow_undefined If true, we don't generate a parse error on unknown attributes.
567 * If an unknown attribute is found a #TMPL_TYPE_ATTR_UNDEFINED #vp_tmpl_t
569 * @return <= 0 on error (offset as negative integer), > 0 on success
570 * (number of bytes parsed).
572 * @see REMARKER to produce pretty error markers from the return value.
574 ssize_t tmpl_from_attr_substr(vp_tmpl_t *vpt, char const *name,
575 request_refs_t request_def, pair_lists_t list_def,
576 bool allow_unknown, bool allow_undefined)
581 tmpl_type_t type = TMPL_TYPE_ATTR;
583 value_pair_tmpl_attr_t attr; /* So we don't fill the tmpl with junk and then error out */
585 memset(vpt, 0, sizeof(*vpt));
586 memset(&attr, 0, sizeof(attr));
592 p += radius_request_name(&attr.request, p, request_def);
593 if (attr.request == REQUEST_UNKNOWN) {
594 fr_strerror_printf("Invalid request qualifier");
599 * Finding a list qualifier is optional
601 p += radius_list_name(&attr.list, p, list_def);
602 if (attr.list == PAIR_LIST_UNKNOWN) {
603 fr_strerror_printf("Invalid list qualifier");
611 * This may be just a bare list, but it can still
612 * have instance selectors and tag selectors.
616 type = TMPL_TYPE_LIST;
617 attr.num = NUM_ALL; /* Hack - Should be removed once tests are updated */
621 type = TMPL_TYPE_LIST;
622 attr.num = NUM_ALL; /* Hack - Should be removed once tests are updated */
629 attr.da = dict_attrbyname_substr(&p);
634 * Record start of attribute in case we need to error out.
638 fr_strerror(); /* Clear out any existing errors */
641 * Attr-1.2.3.4 is OK.
643 if (dict_unknown_from_substr((DICT_ATTR *)&attr.unknown.da, &p) == 0) {
645 * Check what we just parsed really hasn't been defined
646 * in the main dictionaries.
648 * If it has, parsing is the same as if the attribute
649 * name had been used instead of its OID.
651 attr.da = dict_attrbyvalue(((DICT_ATTR *)&attr.unknown.da)->attr,
652 ((DICT_ATTR *)&attr.unknown.da)->vendor);
654 vpt->auto_converted = true;
658 if (!allow_unknown) {
659 fr_strerror_printf("Unknown attribute");
664 * Unknown attributes can't be encoded, as we don't
665 * know how to encode them!
667 attr.da = (DICT_ATTR *)&attr.unknown.da;
669 goto do_num; /* unknown attributes can't have tags */
673 * Can't parse it as an attribute, might be a literal string
674 * let the caller decide.
676 * Don't alter the fr_strerror buffer, should contain the parse
677 * error from dict_unknown_from_substr.
679 if (!allow_undefined) return -(a - name);
682 * Copy the name to a field for later resolution
684 type = TMPL_TYPE_ATTR_UNDEFINED;
685 for (q = attr.unknown.name; dict_attr_allowed_chars[(int) *p]; *q++ = *p++) {
686 if (q >= (attr.unknown.name + sizeof(attr.unknown.name) - 1)) {
687 fr_strerror_printf("Attribute name is too long");
697 * The string MIGHT have a tag.
700 if (attr.da && !attr.da->flags.has_tag) { /* Lists don't have a da */
701 fr_strerror_printf("Attribute '%s' cannot have a tag", attr.da->name);
705 num = strtol(p + 1, &q, 10);
706 if ((num > 0x1f) || (num < 0)) {
707 fr_strerror_printf("Invalid tag value '%li' (should be between 0-31)", num);
708 return -((p + 1)- name);
716 if (*p == '\0') goto finish;
723 attr.num = NUM_COUNT;
738 num = strtol(p, &q, 10);
740 fr_strerror_printf("Array index is not an integer");
744 if ((num > 1000) || (num < 0)) {
745 fr_strerror_printf("Invalid array reference '%li' (should be between 0-1000)", num);
754 fr_strerror_printf("No closing ']' for array index");
766 * Copy over the attribute definition, now we're
767 * sure what we were passed is valid.
769 memcpy(&vpt->data.attribute, &attr, sizeof(vpt->data.attribute));
770 if ((vpt->type == TMPL_TYPE_ATTR) && attr.da->flags.is_unknown) {
771 vpt->tmpl_da = (DICT_ATTR *)&vpt->data.attribute.unknown.da;
779 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
781 * @note Unlike #tmpl_from_attr_substr this function will error out if the entire
782 * name string isn't parsed.
784 * @copydetails tmpl_from_attr_substr
786 ssize_t tmpl_from_attr_str(vp_tmpl_t *vpt, char const *name,
787 request_refs_t request_def, pair_lists_t list_def,
788 bool allow_unknown, bool allow_undefined)
792 slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
793 if (slen <= 0) return slen;
794 if (name[slen] != '\0') {
795 /* This looks wrong, but it produces meaningful errors for unknown attrs with tags */
796 fr_strerror_printf("Unexpected text after %s", fr_int2str(tmpl_names, vpt->type, "<INVALID>"));
805 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
807 * @param[in,out] ctx to allocate #vp_tmpl_t in.
808 * @param[out] out Where to write pointer to new #vp_tmpl_t.
809 * @param[in] name of attribute including #request_refs and #pair_lists qualifiers.
810 * If only #request_refs #pair_lists qualifiers are found, a #TMPL_TYPE_LIST
811 * #vp_tmpl_t will be produced.
812 * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
814 * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
816 * @param[in] allow_unknown If true attributes in the format accepted by
817 * #dict_unknown_from_substr will be allowed, even if they're not in the main
819 * If an unknown attribute is found a #TMPL_TYPE_ATTR #vp_tmpl_t will be
820 * produced with the unknown #DICT_ATTR stored in the ``unknown.da`` buffer.
821 * This #DICT_ATTR will have its ``flags.is_unknown`` field set to true.
822 * If #tmpl_from_attr_substr is being called on startup, the #vp_tmpl_t may be
823 * passed to #tmpl_define_unknown_attr to add the unknown attribute to the main
825 * If the unknown attribute is not added to the main dictionary the #vp_tmpl_t
826 * cannot be used to search for a #VALUE_PAIR in a #REQUEST.
827 * @param[in] allow_undefined If true, we don't generate a parse error on unknown attributes.
828 * If an unknown attribute is found a #TMPL_TYPE_ATTR_UNDEFINED #vp_tmpl_t
830 * @return <= 0 on error (offset as negative integer), > 0 on success
831 * (number of bytes parsed).
833 * @see REMARKER to produce pretty error markers from the return value.
835 ssize_t tmpl_afrom_attr_substr(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
836 request_refs_t request_def, pair_lists_t list_def,
837 bool allow_unknown, bool allow_undefined)
842 MEM(vpt = talloc(ctx, vp_tmpl_t)); /* tmpl_from_attr_substr zeros it */
844 slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
849 vpt->name = talloc_strndup(vpt, vpt->name, slen);
858 /** Parse a string into a TMPL_TYPE_ATTR_* or #TMPL_TYPE_LIST type #vp_tmpl_t
860 * @note Unlike #tmpl_afrom_attr_substr this function will error out if the entire
861 * name string isn't parsed.
863 * @copydetails tmpl_afrom_attr_substr
865 ssize_t tmpl_afrom_attr_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *name,
866 request_refs_t request_def, pair_lists_t list_def,
867 bool allow_unknown, bool allow_undefined)
872 MEM(vpt = talloc(ctx, vp_tmpl_t)); /* tmpl_from_attr_substr zeros it */
874 slen = tmpl_from_attr_substr(vpt, name, request_def, list_def, allow_unknown, allow_undefined);
879 if (name[slen] != '\0') {
880 /* This looks wrong, but it produces meaningful errors for unknown attrs with tags */
881 fr_strerror_printf("Unexpected text after %s", fr_int2str(tmpl_names, vpt->type, "<INVALID>"));
885 vpt->name = talloc_strndup(vpt, vpt->name, vpt->len);
894 /** Convert an arbitrary string into a #vp_tmpl_t
896 * @note Unlike #tmpl_afrom_attr_str return code 0 doesn't necessarily indicate failure,
897 * may just mean a 0 length string was parsed.
899 * @note xlats and regexes are left uncompiled. This is to support the two pass parsing
900 * done by the modcall code. Compilation on pass1 of that code could fail, as
901 * attributes or xlat functions registered by modules may not be available (yet).
903 * @note For details of attribute parsing see #tmpl_from_attr_substr.
905 * @param[in,out] ctx To allocate #vp_tmpl_t in.
906 * @param[out] out Where to write the pointer to the new #vp_tmpl_t.
907 * @param[in] in String to convert to a #vp_tmpl_t.
908 * @param[in] inlen length of string to convert.
909 * @param[in] type of quoting around value. May be one of:
910 * - #T_BARE_WORD - If string begins with ``&`` produces #TMPL_TYPE_ATTR,
911 * #TMPL_TYPE_ATTR_UNDEFINED, #TMPL_TYPE_LIST or error.
912 * If string does not begin with ``&`` produces #TMPL_TYPE_LITERAL,
913 * #TMPL_TYPE_ATTR or #TMPL_TYPE_LIST.
914 * - #T_SINGLE_QUOTED_STRING - Produces #TMPL_TYPE_LITERAL
915 * - #T_DOUBLE_QUOTED_STRING - Produces #TMPL_TYPE_XLAT or #TMPL_TYPE_LITERAL (if
916 * string doesn't contain ``%``).
917 * - #T_BACK_QUOTED_STRING - Produces #TMPL_TYPE_EXEC
918 * - #T_OP_REG_EQ - Produces #TMPL_TYPE_REGEX
919 * @param[in] request_def The default #REQUEST to set if no #request_refs qualifiers are
921 * @param[in] list_def The default list to set if no #pair_lists qualifiers are found in
923 * @param[in] do_unescape whether or not we should do unescaping. Should be false if the
924 * caller already did it.
925 * @return <= 0 on error (offset as negative integer), > 0 on success
926 * (number of bytes parsed).
927 * @see REMARKER to produce pretty error markers from the return value.
929 * @see tmpl_from_attr_substr
931 ssize_t tmpl_afrom_str(TALLOC_CTX *ctx, vp_tmpl_t **out, char const *in, size_t inlen, FR_TOKEN type,
932 request_refs_t request_def, pair_lists_t list_def, bool do_unescape)
938 PW_TYPE data_type = PW_TYPE_STRING;
939 vp_tmpl_t *vpt = NULL;
945 * If we can parse it as an attribute, it's an attribute.
946 * Otherwise, treat it as a literal.
950 slen = tmpl_afrom_attr_str(ctx, &vpt, in, request_def, list_def, true, (in[0] == '&'));
951 if ((in[0] == '&') && (slen <= 0)) return slen;
955 case T_SINGLE_QUOTED_STRING:
959 if (cf_new_escape && do_unescape) {
960 slen = value_data_from_str(ctx, &data, &data_type, NULL, in, inlen, quote);
961 if (slen < 0) return 0;
963 vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, data.strvalue, talloc_array_length(data.strvalue) - 1);
964 talloc_free(data.ptr);
966 vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, in, inlen);
972 case T_DOUBLE_QUOTED_STRING:
977 if (do_unescape) { /* otherwise \ is just another character */
994 * If the double quoted string needs to be
995 * expanded at run time, make it an xlat
996 * expansion. Otherwise, convert it to be a
999 if (cf_new_escape && do_unescape) {
1000 slen = value_data_from_str(ctx, &data, &data_type, NULL, in, inlen, '"');
1001 if (slen < 0) return slen;
1004 vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, data.strvalue,
1005 talloc_array_length(data.strvalue) - 1);
1007 vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, data.strvalue,
1008 talloc_array_length(data.strvalue) - 1);
1011 talloc_free(data.ptr);
1014 vpt = tmpl_alloc(ctx, TMPL_TYPE_XLAT, in, inlen);
1016 vpt = tmpl_alloc(ctx, TMPL_TYPE_LITERAL, in, inlen);
1023 case T_BACK_QUOTED_STRING:
1024 if (cf_new_escape && do_unescape) {
1025 slen = value_data_from_str(ctx, &data, &data_type, NULL, in, inlen, '`');
1026 if (slen < 0) return slen;
1028 vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, data.strvalue, talloc_array_length(data.strvalue) - 1);
1029 talloc_free(data.ptr);
1031 vpt = tmpl_alloc(ctx, TMPL_TYPE_EXEC, in, inlen);
1036 case T_OP_REG_EQ: /* hack */
1037 vpt = tmpl_alloc(ctx, TMPL_TYPE_REGEX, in, inlen);
1043 return 0; /* 0 is an error here too */
1046 rad_assert((slen >= 0) && (vpt != NULL));
1056 /** @name Cast or convert #vp_tmpl_t
1058 * #tmpl_cast_in_place can be used to convert #TMPL_TYPE_LITERAL to a #TMPL_TYPE_DATA of a
1059 * specified #PW_TYPE.
1061 * #tmpl_cast_in_place_str does the same as #tmpl_cast_in_place, but will always convert to
1062 * #PW_TYPE #PW_TYPE_STRING.
1064 * #tmpl_cast_to_vp does the same as #tmpl_cast_in_place, but outputs a #VALUE_PAIR.
1066 * #tmpl_define_unknown_attr converts a #TMPL_TYPE_ATTR with an unknown #DICT_ATTR to a
1067 * #TMPL_TYPE_ATTR with a known #DICT_ATTR, by adding the unknown #DICT_ATTR to the main
1068 * dictionary, and updating the ``tmpl_da`` pointer.
1072 /** Convert #vp_tmpl_t of type #TMPL_TYPE_LITERAL or #TMPL_TYPE_DATA to #TMPL_TYPE_DATA of type specified
1074 * @note Conversion is done in place.
1075 * @note Irrespective of whether the #vp_tmpl_t was #TMPL_TYPE_LITERAL or #TMPL_TYPE_DATA,
1076 * on successful cast it will be #TMPL_TYPE_DATA.
1078 * @param[in,out] vpt The template to modify. Must be of type #TMPL_TYPE_LITERAL
1079 * or #TMPL_TYPE_DATA.
1080 * @param[in] type to cast to.
1081 * @param[in] enumv Enumerated dictionary values associated with a #DICT_ATTR.
1082 * @return 0 on success, -1 on failure.
1084 int tmpl_cast_in_place(vp_tmpl_t *vpt, PW_TYPE type, DICT_ATTR const *enumv)
1090 rad_assert(vpt != NULL);
1091 rad_assert((vpt->type == TMPL_TYPE_LITERAL) || (vpt->type == TMPL_TYPE_DATA));
1093 switch (vpt->type) {
1094 case TMPL_TYPE_LITERAL:
1095 vpt->tmpl_data_type = type;
1098 * Why do we pass a pointer to the tmpl type? Goddamn WiMAX.
1100 ret = value_data_from_str(vpt, &vpt->tmpl_data_value, &vpt->tmpl_data_type,
1101 enumv, vpt->name, vpt->len, '\0');
1102 if (ret < 0) return -1;
1104 vpt->type = TMPL_TYPE_DATA;
1105 vpt->tmpl_data_length = (size_t) ret;
1108 case TMPL_TYPE_DATA:
1112 if (type == vpt->tmpl_data_type) return 0; /* noop */
1114 ret = value_data_cast(vpt, &new, type, enumv, vpt->tmpl_data_type,
1115 NULL, &vpt->tmpl_data_value, vpt->tmpl_data_length);
1116 if (ret < 0) return -1;
1119 * Free old value buffers
1121 switch (vpt->tmpl_data_type) {
1122 case PW_TYPE_STRING:
1123 case PW_TYPE_OCTETS:
1124 talloc_free(vpt->tmpl_data_value.ptr);
1131 memcpy(&vpt->tmpl_data_value, &new, sizeof(vpt->tmpl_data_value));
1132 vpt->tmpl_data_type = type;
1133 vpt->tmpl_data_length = (size_t) ret;
1146 /** Convert #vp_tmpl_t of type #TMPL_TYPE_LITERAL to #TMPL_TYPE_DATA of type #PW_TYPE_STRING
1148 * @note Conversion is done in place.
1150 * @param[in,out] vpt The template to modify. Must be of type #TMPL_TYPE_LITERAL.
1152 void tmpl_cast_in_place_str(vp_tmpl_t *vpt)
1154 rad_assert(vpt != NULL);
1155 rad_assert(vpt->type == TMPL_TYPE_LITERAL);
1157 vpt->tmpl_data.vp_strvalue = talloc_typed_strdup(vpt, vpt->name);
1158 rad_assert(vpt->tmpl_data.vp_strvalue != NULL);
1160 vpt->type = TMPL_TYPE_DATA;
1161 vpt->tmpl_data_type = PW_TYPE_STRING;
1162 vpt->tmpl_data_length = talloc_array_length(vpt->tmpl_data.vp_strvalue) - 1;
1165 /** Expand a #vp_tmpl_t to a string, parse it as an attribute of type cast, create a #VALUE_PAIR from the result
1167 * @note Like #tmpl_expand, but produces a #VALUE_PAIR.
1169 * @param out Where to write pointer to the new #VALUE_PAIR.
1170 * @param request The current #REQUEST.
1171 * @param vpt to cast. Must be one of the following types:
1172 * - #TMPL_TYPE_LITERAL
1175 * - #TMPL_TYPE_XLAT_STRUCT
1178 * @param cast type of #VALUE_PAIR to create.
1179 * @return 0 on success, -1 on failure.
1181 int tmpl_cast_to_vp(VALUE_PAIR **out, REQUEST *request,
1182 vp_tmpl_t const *vpt, DICT_ATTR const *cast)
1193 vp = fr_pair_afrom_da(request, cast);
1196 if (vpt->type == TMPL_TYPE_DATA) {
1198 rad_assert(vp->da->type == vpt->tmpl_data_type);
1200 value_data_copy(vp, &vp->data, vpt->tmpl_data_type, &vpt->tmpl_data_value, vpt->tmpl_data_length);
1205 rcode = tmpl_aexpand(vp, &p, request, vpt, NULL, NULL);
1207 fr_pair_list_free(&vp);
1213 * New escapes: strings are in binary form.
1215 if (cf_new_escape && (vp->da->type == PW_TYPE_STRING)) {
1216 vp->data.ptr = talloc_steal(vp, data.ptr);
1217 vp->vp_length = rcode;
1219 } else if (fr_pair_value_from_str(vp, data.strvalue, rcode) < 0) {
1220 talloc_free(data.ptr);
1221 fr_pair_list_free(&vp);
1229 /** Add an unknown #DICT_ATTR specified by a #vp_tmpl_t to the main dictionary
1231 * @param vpt to add. ``tmpl_da`` pointer will be updated to point to the
1232 * #DICT_ATTR inserted into the dictionary.
1233 * @return 0 on success, -1 on failure.
1235 int tmpl_define_unknown_attr(vp_tmpl_t *vpt)
1237 DICT_ATTR const *da;
1239 if (!vpt) return -1;
1243 if (vpt->type != TMPL_TYPE_ATTR) return 0;
1245 if (!vpt->tmpl_da->flags.is_unknown) return 0;
1247 da = dict_unknown_add(vpt->tmpl_da);
1254 /** @name Resolve a #vp_tmpl_t outputting the result in various formats
1259 /** Expand a #vp_tmpl_t to a string writing the result to a buffer
1261 * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #vp_tmpl_t
1262 * provided by the conf parser, into a usable value.
1263 * The value returned should be raw and undoctored for #PW_TYPE_STRING and #PW_TYPE_OCTETS types,
1264 * and the printable (string) version of the data for all others.
1266 * Depending what arguments are passed, either copies the value to buff, or writes a pointer
1267 * to a string buffer to out. This allows the most efficient access to the value resolved by
1268 * the #vp_tmpl_t, avoiding unecessary string copies.
1270 * @note This function is used where raw string values are needed, which may mean the string
1271 * returned may be binary data or contain unprintable chars. #fr_prints or #fr_aprints should
1272 * be used before using these values in debug statements. #is_printable can be used to check
1273 * if the string only contains printable chars.
1275 * @param out Where to write a pointer to the string buffer. On return may point to buff if
1276 * buff was used to store the value. Otherwise will point to a #value_data_t buffer,
1277 * or the name of the template. To force copying to buff, out should be NULL.
1278 * @param buff Expansion buffer, may be NULL if out is not NULL, and processing #TMPL_TYPE_LITERAL
1280 * @param bufflen Length of expansion buffer.
1281 * @param request Current request.
1282 * @param vpt to expand. Must be one of the following types:
1283 * - #TMPL_TYPE_LITERAL
1286 * - #TMPL_TYPE_XLAT_STRUCT
1289 * @param escape xlat escape function (only used for xlat types).
1290 * @param escape_ctx xlat escape function data.
1291 * @return -1 on error, else the length of data written to buff, or pointed to by out.
1293 ssize_t tmpl_expand(char const **out, char *buff, size_t bufflen, REQUEST *request,
1294 vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
1297 ssize_t slen = -1; /* quiet compiler */
1301 rad_assert(vpt->type != TMPL_TYPE_LIST);
1303 if (out) *out = NULL;
1305 switch (vpt->type) {
1306 case TMPL_TYPE_LITERAL:
1307 RDEBUG4("EXPAND TMPL LITERAL");
1311 memcpy(buff, vpt->name, vpt->len >= bufflen ? bufflen : vpt->len + 1);
1317 case TMPL_TYPE_EXEC:
1319 RDEBUG4("EXPAND TMPL EXEC");
1321 if (radius_exec_program(request, buff, bufflen, NULL, request, vpt->name, NULL,
1322 true, false, EXEC_TIMEOUT) != 0) {
1325 slen = strlen(buff);
1326 if (out) *out = buff;
1330 case TMPL_TYPE_XLAT:
1331 RDEBUG4("EXPAND TMPL XLAT");
1333 /* Error in expansion, this is distinct from zero length expansion */
1334 slen = radius_xlat(buff, bufflen, request, vpt->name, escape, escape_ctx);
1335 if (slen < 0) return slen;
1336 if (out) *out = buff;
1339 case TMPL_TYPE_XLAT_STRUCT:
1340 RDEBUG4("EXPAND TMPL XLAT STRUCT");
1342 /* Error in expansion, this is distinct from zero length expansion */
1343 slen = radius_xlat_struct(buff, bufflen, request, vpt->tmpl_xlat, escape, escape_ctx);
1347 slen = strlen(buff);
1348 if (out) *out = buff;
1351 case TMPL_TYPE_ATTR:
1355 RDEBUG4("EXPAND TMPL ATTR");
1357 ret = tmpl_find_vp(&vp, request, vpt);
1358 if (ret < 0) return -2;
1360 if (out && ((vp->da->type == PW_TYPE_STRING) || (vp->da->type == PW_TYPE_OCTETS))) {
1361 *out = vp->data.ptr;
1362 slen = vp->vp_length;
1364 if (out) *out = buff;
1365 slen = vp_prints_value(buff, bufflen, vp, '\0');
1370 case TMPL_TYPE_DATA:
1372 RDEBUG4("EXPAND TMPL DATA");
1374 if (out && ((vpt->tmpl_data_type == PW_TYPE_STRING) || (vpt->tmpl_data_type == PW_TYPE_OCTETS))) {
1375 *out = vpt->tmpl_data_value.ptr;
1376 slen = vpt->tmpl_data_length;
1378 if (out) *out = buff;
1380 * @todo tmpl_expand should accept an enumv da from the lhs of the map.
1382 slen = value_data_prints(buff, bufflen, vpt->tmpl_data_type, NULL, &vpt->tmpl_data_value, vpt->tmpl_data_length, '\0');
1388 * We should never be expanding these.
1390 case TMPL_TYPE_UNKNOWN:
1391 case TMPL_TYPE_NULL:
1392 case TMPL_TYPE_LIST:
1393 case TMPL_TYPE_REGEX:
1394 case TMPL_TYPE_ATTR_UNDEFINED:
1395 case TMPL_TYPE_REGEX_STRUCT:
1401 if (slen < 0) return slen;
1406 * If we're doing correct escapes, we may have to re-parse the string.
1407 * If the string is from another expansion, it needs re-parsing.
1408 * Or, if it's from a "string" attribute, it needs re-parsing.
1409 * Integers, IP addresses, etc. don't need re-parsing.
1411 if (cf_new_escape && (vpt->type != TMPL_TYPE_ATTR)) {
1415 PW_TYPE type = PW_TYPE_STRING;
1417 slen = value_data_from_str(ctx, &vd, &type, NULL, *out, slen, '"');
1418 talloc_free(*out); /* free the old value */
1423 if (vpt->type == TMPL_TYPE_XLAT_STRUCT) {
1424 RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
1425 RDEBUG2(" --> %s", buff);
1431 /** Expand a template to a string, allocing a new buffer to hold the string
1433 * The intended use of #tmpl_expand and #tmpl_aexpand is for modules to easily convert a #vp_tmpl_t
1434 * provided by the conf parser, into a usable value.
1435 * The value returned should be raw and undoctored for #PW_TYPE_STRING and #PW_TYPE_OCTETS types,
1436 * and the printable (string) version of the data for all others.
1438 * This function will always duplicate values, whereas #tmpl_expand may return a pointer to an
1441 * @note This function is used where raw string values are needed, which may mean the string
1442 * returned may be binary data or contain unprintable chars. #fr_prints or #fr_aprints should
1443 * be used before using these values in debug statements. #is_printable can be used to check
1444 * if the string only contains printable chars.
1446 * @note The type (char or uint8_t) can be obtained with talloc_get_type, and may be used as a
1447 * hint as to how to process or print the data.
1449 * @param ctx to allocate new buffer in.
1450 * @param out Where to write pointer to the new buffer.
1451 * @param request Current request.
1452 * @param vpt to expand. Must be one of the following types:
1453 * - #TMPL_TYPE_LITERAL
1456 * - #TMPL_TYPE_XLAT_STRUCT
1459 * @param escape xlat escape function (only used for xlat types).
1460 * @param escape_ctx xlat escape function data (only used for xlat types).
1463 * - The length of data written to buff, or pointed to by out.
1465 ssize_t tmpl_aexpand(TALLOC_CTX *ctx, char **out, REQUEST *request, vp_tmpl_t const *vpt,
1466 xlat_escape_t escape, void *escape_ctx)
1469 ssize_t slen = -1; /* quiet compiler */
1471 rad_assert(vpt->type != TMPL_TYPE_LIST);
1477 switch (vpt->type) {
1478 case TMPL_TYPE_LITERAL:
1479 RDEBUG4("EXPAND TMPL LITERAL");
1480 *out = talloc_bstrndup(ctx, vpt->name, vpt->len);
1483 case TMPL_TYPE_EXEC:
1487 RDEBUG4("EXPAND TMPL EXEC");
1488 buff = talloc_array(ctx, char, 1024);
1489 if (radius_exec_program(request, buff, 1024, NULL, request, vpt->name, NULL,
1490 true, false, EXEC_TIMEOUT) != 0) {
1494 slen = strlen(buff);
1499 case TMPL_TYPE_XLAT:
1500 RDEBUG4("EXPAND TMPL XLAT");
1501 /* Error in expansion, this is distinct from zero length expansion */
1502 slen = radius_axlat(out, request, vpt->name, escape, escape_ctx);
1508 slen = strlen(*out);
1511 case TMPL_TYPE_XLAT_STRUCT:
1512 RDEBUG4("EXPAND TMPL XLAT STRUCT");
1513 /* Error in expansion, this is distinct from zero length expansion */
1514 slen = radius_axlat_struct(out, request, vpt->tmpl_xlat, escape, escape_ctx);
1519 slen = strlen(*out);
1522 case TMPL_TYPE_ATTR:
1526 RDEBUG4("EXPAND TMPL ATTR");
1527 ret = tmpl_find_vp(&vp, request, vpt);
1528 if (ret < 0) return -2;
1530 switch (vpt->tmpl_da->type) {
1531 case PW_TYPE_STRING:
1532 *out = talloc_bstrndup(ctx, vp->vp_strvalue, vp->vp_length);
1533 if (!*out) return -1;
1534 slen = vp->vp_length;
1537 case PW_TYPE_OCTETS:
1538 *out = talloc_memdup(ctx, vp->vp_octets, vp->vp_length);
1539 if (!*out) return -1;
1540 slen = vp->vp_length;
1544 *out = vp_aprints_value(ctx, vp, '\0');
1545 if (!*out) return -1;
1546 slen = talloc_array_length(*out) - 1;
1552 case TMPL_TYPE_DATA:
1554 RDEBUG4("EXPAND TMPL DATA");
1556 switch (vpt->tmpl_data_type) {
1557 case PW_TYPE_STRING:
1558 *out = talloc_bstrndup(ctx, vpt->tmpl_data_value.strvalue, vpt->tmpl_data_length);
1559 if (!*out) return -1;
1560 slen = vpt->tmpl_data_length;
1563 case PW_TYPE_OCTETS:
1564 *out = talloc_memdup(ctx, vpt->tmpl_data_value.octets, vpt->tmpl_data_length);
1565 if (!*out) return -1;
1566 slen = vpt->tmpl_data_length;
1570 *out = value_data_aprints(ctx, vpt->tmpl_data_type, NULL, &vpt->tmpl_data_value, vpt->tmpl_data_length, '\0');
1571 if (!*out) return -1;
1572 slen = talloc_array_length(*out) - 1;
1579 * We should never be expanding these.
1581 case TMPL_TYPE_UNKNOWN:
1582 case TMPL_TYPE_NULL:
1583 case TMPL_TYPE_LIST:
1584 case TMPL_TYPE_REGEX:
1585 case TMPL_TYPE_ATTR_UNDEFINED:
1586 case TMPL_TYPE_REGEX_STRUCT:
1592 if (slen < 0) return slen;
1595 * If we're doing correct escapes, we may have to re-parse the string.
1596 * If the string is from another expansion, it needs re-parsing.
1597 * Or, if it's from a "string" attribute, it needs re-parsing.
1598 * Integers, IP addresses, etc. don't need re-parsing.
1600 if (cf_new_escape && (vpt->type != TMPL_TYPE_ATTR)) {
1603 PW_TYPE type = PW_TYPE_STRING;
1605 slen = value_data_from_str(ctx, &vd, &type, NULL, *out, slen, '"');
1606 talloc_free(*out); /* free the old value */
1610 if (vpt->type == TMPL_TYPE_XLAT_STRUCT) {
1611 RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */
1612 RDEBUG2(" --> %s", *out);
1618 /** Print a #vp_tmpl_t to a string
1620 * @param[out] out Where to write the presentation format #vp_tmpl_t string.
1621 * @param[in] outlen Size of output buffer.
1622 * @param[in] vpt to print
1623 * @param[in] values Used for integer attributes only. #DICT_ATTR to use when mapping integer
1624 * values to strings.
1625 * @return the size of the string written to the output buffer.
1627 size_t tmpl_prints(char *out, size_t outlen, vp_tmpl_t const *vpt, DICT_ATTR const *values)
1641 switch (vpt->type) {
1645 case TMPL_TYPE_REGEX:
1646 case TMPL_TYPE_REGEX_STRUCT:
1650 case TMPL_TYPE_XLAT:
1651 case TMPL_TYPE_XLAT_STRUCT:
1654 case TMPL_TYPE_LITERAL: /* single-quoted or bare word */
1658 for (p = vpt->name; *p != '\0'; p++) {
1659 if (*p == ' ') break;
1660 if (*p == '\'') break;
1661 if (!dict_attr_allowed_chars[(int) *p]) break;
1665 strlcpy(out, vpt->name, outlen);
1672 case TMPL_TYPE_EXEC:
1676 case TMPL_TYPE_LIST:
1678 if (vpt->tmpl_request == REQUEST_CURRENT) {
1679 snprintf(out + 1, outlen - 1, "%s",
1680 fr_int2str(pair_lists, vpt->tmpl_list, ""));
1682 snprintf(out + 1, outlen - 1, "%s.%s",
1683 fr_int2str(request_refs, vpt->tmpl_request, ""),
1684 fr_int2str(pair_lists, vpt->tmpl_list, ""));
1689 case TMPL_TYPE_ATTR:
1691 if (vpt->tmpl_request == REQUEST_CURRENT) {
1692 if (vpt->tmpl_list == PAIR_LIST_REQUEST) {
1693 strlcpy(out + 1, vpt->tmpl_da->name, outlen - 1);
1695 snprintf(out + 1, outlen - 1, "%s:%s",
1696 fr_int2str(pair_lists, vpt->tmpl_list, ""),
1697 vpt->tmpl_da->name);
1701 snprintf(out + 1, outlen - 1, "%s.%s:%s",
1702 fr_int2str(request_refs, vpt->tmpl_request, ""),
1703 fr_int2str(pair_lists, vpt->tmpl_list, ""),
1704 vpt->tmpl_da->name);
1710 if ((vpt->tmpl_tag == TAG_ANY) && (vpt->tmpl_num == NUM_ANY)) return len;
1715 if (vpt->tmpl_tag != TAG_ANY) {
1716 snprintf(q, outlen, ":%d", vpt->tmpl_tag);
1722 switch (vpt->tmpl_num) {
1727 snprintf(q, outlen, "[*]");
1733 snprintf(q, outlen, "[#]");
1739 snprintf(q, outlen, "[n]");
1745 snprintf(q, outlen, "[%i]", vpt->tmpl_num);
1753 case TMPL_TYPE_ATTR_UNDEFINED:
1755 if (vpt->tmpl_request == REQUEST_CURRENT) {
1756 if (vpt->tmpl_list == PAIR_LIST_REQUEST) {
1757 strlcpy(out + 1, vpt->tmpl_unknown_name, outlen - 1);
1759 snprintf(out + 1, outlen - 1, "%s:%s",
1760 fr_int2str(pair_lists, vpt->tmpl_list, ""),
1761 vpt->tmpl_unknown_name);
1765 snprintf(out + 1, outlen - 1, "%s.%s:%s",
1766 fr_int2str(request_refs, vpt->tmpl_request, ""),
1767 fr_int2str(pair_lists, vpt->tmpl_list, ""),
1768 vpt->tmpl_unknown_name);
1773 if (vpt->tmpl_num == NUM_ANY) {
1780 if (vpt->tmpl_num != NUM_ANY) {
1781 snprintf(q, outlen, "[%i]", vpt->tmpl_num);
1788 case TMPL_TYPE_DATA:
1789 return value_data_prints(out, outlen, vpt->tmpl_data_type, values, &vpt->tmpl_data_value,
1790 vpt->tmpl_data_length, vpt->quote);
1801 * Print it with appropriate escaping
1803 if (cf_new_escape && (c == '/')) {
1804 len = fr_prints(q, outlen - 3, vpt->name, vpt->len, '\0');
1806 len = fr_prints(q, outlen - 3, vpt->name, vpt->len, c);
1816 /** Initialise a #vp_cursor_t to the #VALUE_PAIR specified by a #vp_tmpl_t
1818 * This makes iterating over the one or more #VALUE_PAIR specified by a #vp_tmpl_t
1819 * significantly easier.
1821 * @param err May be NULL if no error code is required. Will be set to:
1823 * - -1 if no matching #VALUE_PAIR could be found.
1824 * - -2 if list could not be found (doesn't exist in current #REQUEST).
1825 * - -3 if context could not be found (no parent #REQUEST available).
1826 * @param cursor to store iterator state.
1827 * @param request The current #REQUEST.
1828 * @param vpt specifying the #VALUE_PAIR type/tag or list to iterate over.
1829 * @return the first #VALUE_PAIR specified by the #vp_tmpl_t, or NULL if no matching
1830 * #VALUE_PAIR found, and NULL on error.
1832 * @see tmpl_cursor_next
1834 VALUE_PAIR *tmpl_cursor_init(int *err, vp_cursor_t *cursor, REQUEST *request, vp_tmpl_t const *vpt)
1836 VALUE_PAIR **vps, *vp = NULL;
1841 rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
1845 if (radius_request(&request, vpt->tmpl_request) < 0) {
1849 vps = radius_list(request, vpt->tmpl_list);
1854 (void) fr_cursor_init(cursor, vps);
1856 switch (vpt->type) {
1858 * May not may not be found, but it *is* a known name.
1860 case TMPL_TYPE_ATTR:
1861 switch (vpt->tmpl_num) {
1863 vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
1872 * Get the last instance of a VALUE_PAIR.
1876 VALUE_PAIR *last = NULL;
1878 while ((vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag))) {
1888 * Callers expect NUM_COUNT to setup the cursor to point
1889 * to the first attribute in the list we're meant to be
1892 * It does not produce a virtual attribute containing the
1893 * total number of attributes.
1896 return fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
1899 num = vpt->tmpl_num;
1900 while ((vp = fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag))) {
1902 if (num-- <= 0) return vp;
1910 case TMPL_TYPE_LIST:
1911 switch (vpt->tmpl_num) {
1915 vp = fr_cursor_init(cursor, vps);
1924 * Get the last instance of a VALUE_PAIR.
1928 VALUE_PAIR *last = NULL;
1930 for (vp = fr_cursor_init(cursor, vps);
1932 vp = fr_cursor_next(cursor)) {
1942 num = vpt->tmpl_num;
1943 for (vp = fr_cursor_init(cursor, vps);
1945 vp = fr_cursor_next(cursor)) {
1947 if (num-- <= 0) return vp;
1961 /** Returns the next #VALUE_PAIR specified by vpt
1963 * @param cursor initialised with #tmpl_cursor_init.
1964 * @param vpt specifying the #VALUE_PAIR type/tag to iterate over.
1965 * Must be one of the following types:
1968 * @return NULL if no more matching #VALUE_PAIR of the specified type/tag are found.
1970 VALUE_PAIR *tmpl_cursor_next(vp_cursor_t *cursor, vp_tmpl_t const *vpt)
1972 rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
1976 switch (vpt->type) {
1978 * May not may not be found, but it *is* a known name.
1980 case TMPL_TYPE_ATTR:
1981 switch (vpt->tmpl_num) {
1986 case NUM_COUNT: /* This cursor is being used to count matching attrs */
1989 return fr_cursor_next_by_da(cursor, vpt->tmpl_da, vpt->tmpl_tag);
1991 case TMPL_TYPE_LIST:
1992 switch (vpt->tmpl_num) {
1997 case NUM_COUNT: /* This cursor is being used to count matching attrs */
2000 return fr_cursor_next(cursor);
2004 return NULL; /* Older versions of GCC flag the lack of return as an error */
2008 /** Copy pairs matching a #vp_tmpl_t in the current #REQUEST
2010 * @param ctx to allocate new #VALUE_PAIR in.
2011 * @param out Where to write the copied #VALUE_PAIR (s).
2012 * @param request The current #REQUEST.
2013 * @param vpt specifying the #VALUE_PAIR type/tag or list to copy.
2014 * Must be one of the following types:
2018 * - -1 if no matching #VALUE_PAIR could be found.
2019 * - -2 if list could not be found (doesn't exist in current #REQUEST).
2020 * - -3 if context could not be found (no parent #REQUEST available).
2021 * - -4 on memory allocation error.
2023 int tmpl_copy_vps(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
2026 vp_cursor_t from, to;
2032 rad_assert((vpt->type == TMPL_TYPE_ATTR) || (vpt->type == TMPL_TYPE_LIST));
2036 fr_cursor_init(&to, out);
2038 for (vp = tmpl_cursor_init(&err, &from, request, vpt);
2040 vp = tmpl_cursor_next(&from, vpt)) {
2041 vp = fr_pair_copy(ctx, vp);
2043 fr_pair_list_free(out);
2046 fr_cursor_insert(&to, vp);
2052 /** Returns the first VP matching a #vp_tmpl_t
2054 * @param out where to write the retrieved vp.
2055 * @param request The current #REQUEST.
2056 * @param vpt specifying the #VALUE_PAIR type/tag to find.
2057 * Must be one of the following types:
2061 * - -1 if no matching #VALUE_PAIR could be found.
2062 * - -2 if list could not be found (doesn't exist in current #REQUEST).
2063 * - -3 if context could not be found (no parent #REQUEST available).
2065 int tmpl_find_vp(VALUE_PAIR **out, REQUEST *request, vp_tmpl_t const *vpt)
2074 vp = tmpl_cursor_init(&err, &cursor, request, vpt);
2081 #ifdef WITH_VERIFY_PTR
2082 /** Used to check whether areas of a vp_tmpl_t are zeroed out
2084 * @param ptr Offset to begin checking at.
2085 * @param len How many bytes to check.
2086 * @return pointer to the first non-zero byte, or NULL if all bytes were zero.
2088 static uint8_t const *not_zeroed(uint8_t const *ptr, size_t len)
2092 for (i = 0; i < len; i++) {
2093 if (ptr[i] != 0x00) return ptr + i;
2098 #define CHECK_ZEROED(_x) not_zeroed((uint8_t const *)&_x + sizeof(_x), sizeof(vpt->data) - sizeof(_x))
2100 /** Verify fields of a vp_tmpl_t make sense
2102 * @note If the #vp_tmpl_t is invalid, causes the server to exit.
2104 * @param file obtained with __FILE__.
2105 * @param line obtained with __LINE__.
2106 * @param vpt to check.
2108 void tmpl_verify(char const *file, int line, vp_tmpl_t const *vpt)
2112 if (vpt->type == TMPL_TYPE_UNKNOWN) {
2113 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: vp_tmpl_t type was "
2114 "TMPL_TYPE_UNKNOWN (uninitialised)", file, line);
2119 if (vpt->type > TMPL_TYPE_NULL) {
2120 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: vp_tmpl_t type was %i "
2121 "(outside range of tmpl_names)", file, line, vpt->type);
2127 * Do a memcmp of the bytes after where the space allocated for
2128 * the union member should have ended and the end of the union.
2129 * These should always be zero if the union has been initialised
2132 * If they're still all zero, do TMPL_TYPE specific checks.
2134 switch (vpt->type) {
2135 case TMPL_TYPE_NULL:
2136 if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2137 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_NULL "
2138 "has non-zero bytes in its data union", file, line);
2144 case TMPL_TYPE_LITERAL:
2145 if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2146 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LITERAL "
2147 "has non-zero bytes in its data union", file, line);
2153 case TMPL_TYPE_XLAT:
2154 case TMPL_TYPE_XLAT_STRUCT:
2157 /* @todo When regexes get converted to xlat the flags field of the regex union is used
2158 case TMPL_TYPE_XLAT:
2159 if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2160 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT "
2161 "has non-zero bytes in its data union", file, line);
2167 case TMPL_TYPE_XLAT_STRUCT:
2168 if (CHECK_ZEROED(vpt->data.xlat)) {
2169 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_XLAT_STRUCT "
2170 "has non-zero bytes after the data.xlat pointer in the union", file, line);
2177 case TMPL_TYPE_EXEC:
2178 if (not_zeroed((uint8_t const *)&vpt->data, sizeof(vpt->data))) {
2179 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_EXEC "
2180 "has non-zero bytes in its data union", file, line);
2186 case TMPL_TYPE_ATTR_UNDEFINED:
2187 rad_assert(vpt->tmpl_da == NULL);
2190 case TMPL_TYPE_ATTR:
2191 if (CHECK_ZEROED(vpt->data.attribute)) {
2192 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2193 "has non-zero bytes after the data.attribute struct in the union",
2199 if (vpt->tmpl_da->flags.is_unknown) {
2200 if (vpt->tmpl_da != (DICT_ATTR *)&vpt->data.attribute.unknown.da) {
2201 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2202 "da is marked as unknown, but does not point to the template's "
2203 "unknown da buffer", file, line);
2209 DICT_ATTR const *da;
2212 * Attribute may be present with multiple names
2214 da = dict_attrbyname(vpt->tmpl_da->name);
2216 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2217 "attribute \"%s\" (%s) not found in global dictionary",
2218 file, line, vpt->tmpl_da->name,
2219 fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"));
2224 if ((da->type == PW_TYPE_COMBO_IP_ADDR) && (da->type != vpt->tmpl_da->type)) {
2225 da = dict_attrbytype(vpt->tmpl_da->attr, vpt->tmpl_da->vendor, vpt->tmpl_da->type);
2227 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2228 "attribute \"%s\" variant (%s) not found in global dictionary",
2229 file, line, vpt->tmpl_da->name,
2230 fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"));
2236 if (da != vpt->tmpl_da) {
2237 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_ATTR "
2238 "dictionary pointer %p \"%s\" (%s) "
2239 "and global dictionary pointer %p \"%s\" (%s) differ",
2241 vpt->tmpl_da, vpt->tmpl_da->name,
2242 fr_int2str(dict_attr_types, vpt->tmpl_da->type, "<INVALID>"),
2244 fr_int2str(dict_attr_types, da->type, "<INVALID>"));
2251 case TMPL_TYPE_LIST:
2252 if (CHECK_ZEROED(vpt->data.attribute)) {
2253 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST"
2254 "has non-zero bytes after the data.attribute struct in the union", file, line);
2259 if (vpt->tmpl_da != NULL) {
2260 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_LIST da pointer was NULL", file, line);
2266 case TMPL_TYPE_DATA:
2267 if (CHECK_ZEROED(vpt->data.literal)) {
2268 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA "
2269 "has non-zero bytes after the data.literal struct in the union",
2275 if (vpt->tmpl_data_type == PW_TYPE_INVALID) {
2276 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
2277 "PW_TYPE_INVALID (uninitialised)", file, line);
2282 if (vpt->tmpl_data_type >= PW_TYPE_MAX) {
2283 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA type was "
2284 "%i (outside the range of PW_TYPEs)", file, line, vpt->tmpl_data_type);
2289 * Unlike VALUE_PAIRs we can't guarantee that VALUE_PAIR_TMPL buffers will
2290 * be talloced. They may be allocated on the stack or in global variables.
2292 switch (vpt->tmpl_data_type) {
2293 case PW_TYPE_STRING:
2294 if (vpt->tmpl_data.vp_strvalue[vpt->tmpl_data_length] != '\0') {
2295 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA char buffer not \\0 "
2296 "terminated", file, line);
2303 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA is of type TLV",
2308 case PW_TYPE_OCTETS:
2312 if (vpt->tmpl_data_length == 0) {
2313 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_DATA data pointer not NULL "
2314 "but len field is zero", file, line);
2322 case TMPL_TYPE_REGEX:
2324 * iflag field is used for non compiled regexes too.
2326 if (CHECK_ZEROED(vpt->data.preg)) {
2327 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2328 "has non-zero bytes after the data.preg struct in the union", file, line);
2333 if (vpt->tmpl_preg != NULL) {
2334 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2335 "preg field was not nULL", file, line);
2340 if ((vpt->tmpl_iflag != true) && (vpt->tmpl_iflag != false)) {
2341 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2342 "iflag field was neither true or false", file, line);
2347 if ((vpt->tmpl_mflag != true) && (vpt->tmpl_mflag != false)) {
2348 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2349 "mflag field was neither true or false", file, line);
2356 case TMPL_TYPE_REGEX_STRUCT:
2357 if (CHECK_ZEROED(vpt->data.preg)) {
2358 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
2359 "has non-zero bytes after the data.preg struct in the union", file, line);
2364 if (vpt->tmpl_preg == NULL) {
2365 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
2366 "comp field was NULL", file, line);
2371 if ((vpt->tmpl_iflag != true) && (vpt->tmpl_iflag != false)) {
2372 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX_STRUCT "
2373 "iflag field was neither true or false", file, line);
2378 if ((vpt->tmpl_mflag != true) && (vpt->tmpl_mflag != false)) {
2379 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: TMPL_TYPE_REGEX "
2380 "mflag field was neither true or false", file, line);
2386 case TMPL_TYPE_UNKNOWN: