All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pair.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: 8e5224bbcef33e06938684bb69e42626b0a43072 $
19  *
20  * @brief Valuepair functions that are radiusd-specific and as such do not
21  * belong in the library.
22  * @file main/pair.c
23  *
24  * @ingroup AVP
25  *
26  * @copyright 2000,2006 The FreeRADIUS server project
27  * @copyright 2000 Alan DeKok <aland@ox.org>
28  */
29 
30 RCSID("$Id: 8e5224bbcef33e06938684bb69e42626b0a43072 $")
31 
32 #include <ctype.h>
33 
34 #include <freeradius-devel/radiusd.h>
35 #include <freeradius-devel/rad_assert.h>
36 
37 struct cmp {
40  bool first_only;
41  void *instance; /* module instance */
43  struct cmp *next;
44 };
45 static struct cmp *cmp;
46 
47 /** Compares check and vp by value.
48  *
49  * Does not call any per-attribute comparison function, but does honour
50  * check.operator. Basically does "vp.value check.op check.value".
51  *
52  * @param request Current request.
53  * @param check rvalue, and operator.
54  * @param vp lvalue.
55  * @return
56  * - 0 if check and vp are equal
57  * - -1 if vp value is less than check value.
58  * - 1 is vp value is more than check value.
59  * - -2 on error.
60  */
61 #ifdef HAVE_REGEX
62 int radius_compare_vps(REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
63 #else
65 #endif
66 {
67  int ret = 0;
68 
69  /*
70  * Check for =* and !* and return appropriately
71  */
72  if (check->op == T_OP_CMP_TRUE) return 0;
73  if (check->op == T_OP_CMP_FALSE) return 1;
74 
75 #ifdef HAVE_REGEX
76  if ((check->op == T_OP_REG_EQ) || (check->op == T_OP_REG_NE)) {
77  ssize_t slen;
78  regex_t *preg = NULL;
79  regmatch_t rxmatch[REQUEST_MAX_REGEX + 1]; /* +1 for %{0} (whole match) capture group */
80  size_t nmatch = sizeof(rxmatch) / sizeof(regmatch_t);
81 
82  char *expr = NULL, *value = NULL;
83  char const *expr_p, *value_p;
84 
85  if (check->da->type == PW_TYPE_STRING) {
86  expr_p = check->vp_strvalue;
87  } else {
88  expr_p = expr = fr_pair_value_asprint(check, check, '\0');
89  }
90 
91  if (vp->da->type == PW_TYPE_STRING) {
92  value_p = vp->vp_strvalue;
93  } else {
94  value_p = value = fr_pair_value_asprint(vp, vp, '\0');
95  }
96 
97  if (!expr_p || !value_p) {
98  REDEBUG("Error stringifying operand for regular expression");
99 
100  regex_error:
101  talloc_free(preg);
102  talloc_free(expr);
103  talloc_free(value);
104  return -2;
105  }
106 
107  /*
108  * Include substring matches.
109  */
110  slen = regex_compile(request, &preg, expr_p, talloc_array_length(expr_p) - 1, false, false, true, true);
111  if (slen <= 0) {
112  REMARKER(expr_p, -slen, fr_strerror());
113 
114  goto regex_error;
115  }
116 
117  slen = regex_exec(preg, value_p, talloc_array_length(value_p) - 1, rxmatch, &nmatch);
118  if (slen < 0) {
119  RERROR("%s", fr_strerror());
120 
121  goto regex_error;
122  }
123 
124  if (check->op == T_OP_REG_EQ) {
125  /*
126  * Add in %{0}. %{1}, etc.
127  */
128  regex_sub_to_request(request, &preg, value_p, talloc_array_length(value_p) - 1,
129  rxmatch, nmatch);
130  ret = (slen == 1) ? 0 : -1;
131  } else {
132  ret = (slen != 1) ? 0 : -1;
133  }
134 
135  talloc_free(preg);
136  talloc_free(expr);
137  talloc_free(value);
138  goto finish;
139  }
140 #endif
141 
142  /*
143  * Attributes must be of the same type.
144  *
145  * FIXME: deal with type mismatch properly if one side contain
146  * ABINARY, OCTETS or STRING by converting the other side to
147  * a string
148  *
149  */
150  if (vp->da->type != check->da->type) return -1;
151 
152  /*
153  * Tagged attributes are equal if and only if both the
154  * tag AND value match.
155  */
156  if (check->da->flags.has_tag && !TAG_EQ(check->tag, vp->tag)) {
157  ret = ((int) vp->tag) - ((int) check->tag);
158  if (ret != 0) goto finish;
159  }
160 
161  /*
162  * Not a regular expression, compare the types.
163  */
164  switch (check->da->type) {
165 #ifdef WITH_ASCEND_BINARY
166  /*
167  * Ascend binary attributes can be treated
168  * as opaque objects, I guess...
169  */
170  case PW_TYPE_ABINARY:
171 #endif
172  case PW_TYPE_OCTETS:
173  if (vp->vp_length != check->vp_length) {
174  ret = 1; /* NOT equal */
175  break;
176  }
177  ret = memcmp(vp->vp_strvalue, check->vp_strvalue,
178  vp->vp_length);
179  break;
180 
181  case PW_TYPE_STRING:
182  ret = strcmp(vp->vp_strvalue,
183  check->vp_strvalue);
184  break;
185 
186  case PW_TYPE_BYTE:
187  ret = vp->vp_byte - check->vp_byte;
188  break;
189  case PW_TYPE_SHORT:
190  ret = vp->vp_short - check->vp_short;
191  break;
192  case PW_TYPE_INTEGER:
193  ret = vp->vp_integer - check->vp_integer;
194  break;
195 
196  case PW_TYPE_INTEGER64:
197  /*
198  * Don't want integer overflow!
199  */
200  if (vp->vp_integer64 < check->vp_integer64) {
201  ret = -1;
202  } else if (vp->vp_integer64 > check->vp_integer64) {
203  ret = +1;
204  } else {
205  ret = 0;
206  }
207  break;
208 
209  case PW_TYPE_SIGNED:
210  if (vp->vp_signed < check->vp_signed) {
211  ret = -1;
212  } else if (vp->vp_signed > check->vp_signed) {
213  ret = +1;
214  } else {
215  ret = 0;
216  }
217  break;
218 
219  case PW_TYPE_DATE:
220  ret = vp->vp_date - check->vp_date;
221  break;
222 
223  case PW_TYPE_IPV4_ADDR:
224  ret = ntohl(vp->vp_ipaddr) - ntohl(check->vp_ipaddr);
225  break;
226 
227  case PW_TYPE_IPV6_ADDR:
228  ret = memcmp(&vp->vp_ipv6addr, &check->vp_ipv6addr, sizeof(vp->vp_ipv6addr));
229  break;
230 
231  case PW_TYPE_IPV6_PREFIX:
232  ret = memcmp(vp->vp_ipv6prefix, check->vp_ipv6prefix, sizeof(vp->vp_ipv6prefix));
233  break;
234 
235  case PW_TYPE_IFID:
236  ret = memcmp(vp->vp_ifid, check->vp_ifid, sizeof(vp->vp_ifid));
237  break;
238 
239  default:
240  break;
241  }
242 
243 finish:
244  if (ret > 0) return 1;
245  if (ret < 0) return -1;
246  return 0;
247 }
248 
249 
250 /** Compare check and vp. May call the attribute comparison function.
251  *
252  * Unlike radius_compare_vps() this function will call any attribute-specific
253  * comparison functions registered.
254  *
255  * @param request Current request.
256  * @param req list pairs.
257  * @param check item to compare.
258  * @param check_pairs list.
259  * @param reply_pairs list.
260  * @return
261  * - 0 if check and vp are equal.
262  * - -1 if vp value is less than check value.
263  * - 1 is vp value is more than check value.
264  */
266  VALUE_PAIR *check, VALUE_PAIR *check_pairs,
267  VALUE_PAIR **reply_pairs)
268 {
269  struct cmp *c;
270 
271  /*
272  * Check for =* and !* and return appropriately
273  */
274  if (check->op == T_OP_CMP_TRUE) return 0;
275  if (check->op == T_OP_CMP_FALSE) return 1;
276 
277  /*
278  * See if there is a special compare function.
279  *
280  * FIXME: use new RB-Tree code.
281  */
282  for (c = cmp; c; c = c->next) {
283  if (c->attribute == check->da) {
284  return (c->compare)(c->instance, request, req, check,
285  check_pairs, reply_pairs);
286  }
287  }
288 
289  if (!req) return -1; /* doesn't exist, don't compare it */
290 
291  return radius_compare_vps(request, check, req);
292 }
293 
294 
295 /** Find a comparison function for two attributes.
296  *
297  * @todo this should probably take DA's.
298  * @param attribute to find comparison function for.
299  * @return
300  * - true if a comparison function was found
301  * - false.
302  */
304 {
305  struct cmp *c;
306 
307  for (c = cmp; c; c = c->next) {
308  if (c->attribute == attribute) {
309  return true;
310  }
311  }
312 
313  return false;
314 }
315 
316 
317 /** See what attribute we want to compare with.
318  *
319  * @param attribute to find comparison function for.
320  * @param from reference to compare with
321  * @return
322  * - true if the comparison callback require a matching attribute in the request.
323  * - false.
324  */
326 {
327  struct cmp *c;
328 
329  for (c = cmp; c; c = c->next) {
330  if (c->attribute == attribute) {
331  *from = c->from;
332  return c->first_only;
333  }
334  }
335 
336  *from = attribute;
337  return false;
338 }
339 
340 /** Register a function as compare function
341  *
342  * @param name the attribute comparison to register
343  * @param from the attribute we want to compare with. Normally this is the same as attribute.
344  * If null call the comparison function on every attributes in the request if first_only is
345  * false.
346  * @param first_only will decide if we loop over the request attributes or stop on the first one.
347  * @param func comparison function.
348  * @param instance argument to comparison function.
349  * @return 0
350  */
352  bool first_only, RAD_COMPARE_FUNC func, void *instance)
353 {
354  fr_dict_attr_flags_t flags;
355  fr_dict_attr_t const *da;
356 
357  memset(&flags, 0, sizeof(flags));
358  flags.compare = 1;
359 
360  da = fr_dict_attr_by_name(NULL, name);
361  if (da) {
362  if (!da->flags.compare) {
363  fr_strerror_printf("Attribute '%s' already exists", name);
364  return -1;
365  }
366  } else if (from) {
367  if (fr_dict_attr_add(NULL, fr_dict_root(fr_dict_internal), name, -1, from->type, flags) < 0) {
368  fr_strerror_printf("Failed creating attribute '%s': %s", name, fr_strerror());
369  return -1;
370  }
371 
372  da = fr_dict_attr_by_name(NULL, name);
373  if (!da) {
374  fr_strerror_printf("Failed finding attribute '%s'", name);
375  return -1;
376  }
377 
378  DEBUG("Creating attribute %s", name);
379  }
380 
381  return paircompare_register(da, from, first_only, func, instance);
382 }
383 
384 /** Register a function as compare function.
385  *
386  * @param attribute to register comparison function for.
387  * @param from the attribute we want to compare with. Normally this is the same as attribute.
388  * If null call the comparison function on every attributes in the request if first_only is
389  * false.
390  * @param first_only will decide if we loop over the request attributes or stop on the first one.
391  * @param func comparison function.
392  * @param instance argument to comparison function.
393  * @return 0
394  */
396  bool first_only, RAD_COMPARE_FUNC func, void *instance)
397 {
398  struct cmp *c;
399 
400  rad_assert(attribute != NULL);
401 
402  paircompare_unregister(attribute, func);
403 
404  c = rad_malloc(sizeof(struct cmp));
405 
406  c->compare = func;
407  c->attribute = attribute;
408  c->from = from;
409  c->first_only = first_only;
410  c->instance = instance;
411  c->next = cmp;
412  cmp = c;
413 
414  return 0;
415 }
416 
417 /** Unregister comparison function for an attribute
418  *
419  * @param attribute dict reference to unregister for.
420  * @param func comparison function to remove.
421  */
423 {
424  struct cmp *c, *last;
425 
426  last = NULL;
427  for (c = cmp; c; c = c->next) {
428  if (c->attribute == attribute && c->compare == func) {
429  break;
430  }
431  last = c;
432  }
433 
434  if (c == NULL) return;
435 
436  if (last != NULL) {
437  last->next = c->next;
438  } else {
439  cmp = c->next;
440  }
441 
442  free(c);
443 }
444 
445 /** Unregister comparison function for a module
446  *
447  * All paircompare() functions for this module will be unregistered.
448  *
449  * @param instance the module instance
450  */
452 {
453  struct cmp *c, **tail;
454 
455  tail = &cmp;
456  while ((c = *tail) != NULL) {
457  if (c->instance == instance) {
458  *tail = c->next;
459  free(c);
460  continue;
461  }
462 
463  tail = &(c->next);
464  }
465 }
466 
467 /** Compare two pair lists except for the password information.
468  *
469  * For every element in "check" at least one matching copy must be present
470  * in "reply".
471  *
472  * @param[in] request Current request.
473  * @param[in] req_list request valuepairs.
474  * @param[in] check Check/control valuepairs.
475  * @param[in,out] rep_list Reply value pairs.
476  *
477  * @return 0 on match.
478  */
479 int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check,
480  VALUE_PAIR **rep_list)
481 {
482  vp_cursor_t cursor;
483  VALUE_PAIR *check_item;
484  VALUE_PAIR *auth_item;
485  fr_dict_attr_t const *from;
486 
487  int result = 0;
488  int compare;
489  bool first_only;
490 
491  for (check_item = fr_cursor_init(&cursor, &check);
492  check_item;
493  check_item = fr_cursor_next(&cursor)) {
494  /*
495  * If the user is setting a configuration value,
496  * then don't bother comparing it to any attributes
497  * sent to us by the user. It ALWAYS matches.
498  */
499  if ((check_item->op == T_OP_SET) ||
500  (check_item->op == T_OP_ADD)) {
501  continue;
502  }
503 
504  if (!check_item->da->vendor) switch (check_item->da->attr) {
505  /*
506  * Attributes we skip during comparison.
507  * These are "server" check items.
508  */
509  case PW_CRYPT_PASSWORD:
510  case PW_AUTH_TYPE:
511  case PW_AUTZ_TYPE:
512  case PW_ACCT_TYPE:
513  case PW_SESSION_TYPE:
514  case PW_STRIP_USER_NAME:
515  continue;
516 
517  /*
518  * IF the password attribute exists, THEN
519  * we can do comparisons against it. If not,
520  * then the request did NOT contain a
521  * User-Password attribute, so we CANNOT do
522  * comparisons against it.
523  *
524  * This hack makes CHAP-Password work..
525  */
526  case PW_USER_PASSWORD:
527  if (check_item->op == T_OP_CMP_EQ) {
528  WARN("Found User-Password == \"...\"");
529  WARN("Are you sure you don't mean Cleartext-Password?");
530  WARN("See \"man rlm_pap\" for more information");
531  }
532  if (fr_pair_find_by_num(req_list, 0, PW_USER_PASSWORD, TAG_ANY) == NULL) {
533  continue;
534  }
535  break;
536  }
537 
538  /*
539  * See if this item is present in the request.
540  */
541  first_only = otherattr(check_item->da, &from);
542 
543  auth_item = req_list;
544  try_again:
545  if (!first_only) {
546  while (auth_item != NULL) {
547  if ((auth_item->da == from) || (!from)) {
548  break;
549  }
550  auth_item = auth_item->next;
551  }
552  }
553 
554  /*
555  * Not found, it's not a match.
556  */
557  if (auth_item == NULL) {
558  /*
559  * Didn't find it. If we were *trying*
560  * to not find it, then we succeeded.
561  */
562  if (check_item->op == T_OP_CMP_FALSE) {
563  continue;
564  } else {
565  return -1;
566  }
567  }
568 
569  /*
570  * Else we found it, but we were trying to not
571  * find it, so we failed.
572  */
573  if (check_item->op == T_OP_CMP_FALSE) {
574  return -1;
575  }
576 
577  /*
578  * We've got to xlat the string before doing
579  * the comparison.
580  */
581  radius_xlat_do(request, check_item);
582 
583  /*
584  * OK it is present now compare them.
585  */
586  compare = radius_callback_compare(request, auth_item,
587  check_item, check, rep_list);
588 
589  switch (check_item->op) {
590  case T_OP_EQ:
591  default:
592  RWDEBUG("Invalid operator '%s' for item %s: reverting to '=='",
593  fr_int2str(fr_tokens_table, check_item->op, "<INVALID>"), check_item->da->name);
594  /* FALL-THROUGH */
595  case T_OP_CMP_TRUE:
596  case T_OP_CMP_FALSE:
597  case T_OP_CMP_EQ:
598  if (compare != 0) result = -1;
599  break;
600 
601  case T_OP_NE:
602  if (compare == 0) result = -1;
603  break;
604 
605  case T_OP_LT:
606  if (compare >= 0) result = -1;
607  break;
608 
609  case T_OP_GT:
610  if (compare <= 0) result = -1;
611  break;
612 
613  case T_OP_LE:
614  if (compare > 0) result = -1;
615  break;
616 
617  case T_OP_GE:
618  if (compare < 0) result = -1;
619  break;
620 
621 #ifdef HAVE_REGEX
622  case T_OP_REG_EQ:
623  case T_OP_REG_NE:
624  if (compare != 0) result = -1;
625  break;
626 #endif
627  } /* switch over the operator of the check item */
628 
629  /*
630  * This attribute didn't match, but maybe there's
631  * another of the same attribute, which DOES match.
632  */
633  if ((result != 0) && (!first_only)) {
634  auth_item = auth_item->next;
635  result = 0;
636  goto try_again;
637  }
638 
639  } /* for every entry in the check item list */
640 
641  return result;
642 }
643 
644 /** Expands an attribute marked with fr_pair_mark_xlat
645  *
646  * Writes the new value to the vp.
647  *
648  * @param request Current request.
649  * @param vp to expand.
650  * @return On failure pair will still no longer be marked for xlat expansion.
651  * - 0 if successful.
652  * - -1 On xlat failure.
653  * - -2 On parse failure.
654  */
656 {
657  ssize_t slen;
658 
659  char *expanded = NULL;
660  if (vp->type != VT_XLAT) return 0;
661 
662  vp->type = VT_DATA;
663 
664  slen = radius_axlat(&expanded, request, vp->xlat, NULL, NULL);
665  rad_const_free(vp->xlat);
666  vp->xlat = NULL;
667  if (slen < 0) {
668  return -1;
669  }
670 
671  /*
672  * Parse the string into a new value.
673  *
674  * If the VALUE_PAIR is being used in a regular expression
675  * then we just want to copy the new value in unmolested.
676  */
677  if ((vp->op == T_OP_REG_EQ) || (vp->op == T_OP_REG_NE)) {
678  fr_pair_value_strsteal(vp, expanded);
679  return 0;
680  }
681 
682  if (fr_pair_value_from_str(vp, expanded, -1) < 0){
683  talloc_free(expanded);
684  return -2;
685  }
686 
687  talloc_free(expanded);
688 
689  return 0;
690 }
691 
692 /** Create a #VALUE_PAIR and add it to a list of #VALUE_PAIR s
693  *
694  * @note This function ALWAYS returns. If we're OOM, then it causes the
695  * @note server to exit, so you don't need to check the return value.
696  *
697  * @param[in] ctx for talloc
698  * @param[out] vps List to add new #VALUE_PAIR to, if NULL will just
699  * return #VALUE_PAIR.
700  * @param[in] attribute number.
701  * @param[in] vendor number.
702  * @return a new #VALUE_PAIR or causes server to exit on error.
703  */
704 VALUE_PAIR *radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps,
705  unsigned int attribute, unsigned int vendor)
706 {
707  VALUE_PAIR *vp;
708 
709  vp = fr_pair_afrom_num(ctx, vendor, attribute);
710  if (!vp) {
711  ERROR("No memory!");
712  rad_assert("No memory" == NULL);
713  fr_exit_now(1);
714  }
715 
716  if (vps) fr_pair_add(vps, vp);
717 
718  return vp;
719 }
720 
721 /** Print a single valuepair to stderr or error log.
722  *
723  * @param[in] vp list to print.
724  */
726 {
727  if (!vp || !rad_debug_lvl || !fr_log_fp) return;
728 
730 }
731 
732 /** Print a single valuepair to stderr or error log.
733  *
734  * @param[in] level Debug level (1-4).
735  * @param[in] request to read logging params from.
736  * @param[in] vp to print.
737  * @param[in] prefix (optional).
738  */
739 void rdebug_pair(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
740 {
741  char buffer[256];
742  if (!vp || !request || !request->log.func) return;
743 
744  if (!radlog_debug_enabled(L_DBG, level, request)) return;
745 
746  fr_pair_snprint(buffer, sizeof(buffer), vp);
747  RDEBUGX(level, "%s%s", prefix ? prefix : "&", buffer);
748 }
749 
750 /** Print a list of VALUE_PAIRs.
751  *
752  * @param[in] level Debug level (1-4).
753  * @param[in] request to read logging params from.
754  * @param[in] vp to print.
755  * @param[in] prefix (optional).
756  */
757 void rdebug_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
758 {
759  vp_cursor_t cursor;
760  char buffer[256];
761  if (!vp || !request || !request->log.func) return;
762 
763  if (!radlog_debug_enabled(L_DBG, level, request)) return;
764 
765  RINDENT();
766  for (vp = fr_cursor_init(&cursor, &vp);
767  vp;
768  vp = fr_cursor_next(&cursor)) {
769  VERIFY_VP(vp);
770 
771  fr_pair_snprint(buffer, sizeof(buffer), vp);
772  RDEBUGX(level, "%s%s", prefix ? prefix : "&", buffer);
773  }
774  REXDENT();
775 }
776 
777 /** Print a list of protocol VALUE_PAIRs.
778  *
779  * @param[in] level Debug level (1-4).
780  * @param[in] request to read logging params from.
781  * @param[in] vp to print.
782  * @param[in] prefix (optional).
783  */
784 void rdebug_proto_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
785 {
786  vp_cursor_t cursor;
787  char buffer[256];
788  if (!vp || !request || !request->log.func) return;
789 
790  if (!radlog_debug_enabled(L_DBG, level, request)) return;
791 
792  RINDENT();
793  for (vp = fr_cursor_init(&cursor, &vp);
794  vp;
795  vp = fr_cursor_next(&cursor)) {
796  VERIFY_VP(vp);
797  if ((vp->da->vendor == 0) &&
798  ((vp->da->attr & 0xFFFF) > 0xff)) continue;
799  fr_pair_snprint(buffer, sizeof(buffer), vp);
800  RDEBUGX(level, "%s%s", prefix ? prefix : "", buffer);
801  }
802  REXDENT();
803 }
804 
805 /** Return a VP from the specified request.
806  *
807  * @param out where to write the pointer to the resolved VP. Will be NULL if the attribute couldn't
808  * be resolved.
809  * @param request current request.
810  * @param name attribute name including qualifiers.
811  * @return
812  * - -4 if either the attribute or qualifier were invalid.
813  * - The same error codes as #tmpl_find_vp for other error conditions.
814  */
815 int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
816 {
817  int rcode;
818  vp_tmpl_t vpt;
819 
820  *out = NULL;
821 
822  if (tmpl_from_attr_str(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
823  return -4;
824  }
825 
826  rcode = tmpl_find_vp(out, request, &vpt);
827 
828  return rcode;
829 }
830 
831 /** Copy VP(s) from the specified request.
832  *
833  * @param ctx to alloc new VALUE_PAIRs in.
834  * @param out where to write the pointer to the copied VP. Will be NULL if the attribute couldn't be
835  * resolved.
836  * @param request current request.
837  * @param name attribute name including qualifiers.
838  * @return
839  * - -4 if either the attribute or qualifier were invalid.
840  * - The same error codes as #tmpl_find_vp for other error conditions.
841  */
842 int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name)
843 {
844  int rcode;
845  vp_tmpl_t vpt;
846 
847  *out = NULL;
848 
849  if (tmpl_from_attr_str(&vpt, name, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false) <= 0) {
850  return -4;
851  }
852 
853  rcode = tmpl_copy_vps(ctx, out, request, &vpt);
854 
855  return rcode;
856 }
857 
858 void module_failure_msg(REQUEST *request, char const *fmt, ...)
859 {
860  va_list ap;
861 
862  va_start(ap, fmt);
863  vmodule_failure_msg(request, fmt, ap);
864  va_end(ap);
865 }
866 
867 /** Add a module failure message VALUE_PAIR to the request
868  */
869 void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap)
870 {
871  char *p;
872  VALUE_PAIR *vp;
873  va_list aq;
874 
875  if (!fmt || !request || !request->packet) {
876  return;
877  }
878 
879  /*
880  * If we don't copy the original ap we get a segfault from vasprintf. This is apparently
881  * due to ap sometimes being implemented with a stack offset which is invalidated if
882  * ap is passed into another function. See here:
883  * http://julipedia.meroh.net/2011/09/using-vacopy-to-safely-pass-ap.html
884  *
885  * I don't buy that explanation, but doing a va_copy here does prevent SEGVs seen when
886  * running unit tests which generate errors under CI.
887  */
888  va_copy(aq, ap);
889  p = talloc_vasprintf(request, fmt, aq);
890  va_end(aq);
891 
892  MEM(vp = pair_make_request("Module-Failure-Message", NULL, T_OP_ADD));
893  if (request->module && (request->module[0] != '\0')) {
894  fr_pair_value_snprintf(vp, "%s: %s", request->module, p);
895  } else {
896  fr_pair_value_snprintf(vp, "%s", p);
897  }
898  talloc_free(p);
899 }
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
VALUE_PAIR has a single value.
Definition: pair.h:101
int radius_xlat_do(REQUEST *request, VALUE_PAIR *vp)
Expands an attribute marked with fr_pair_mark_xlat.
Definition: pair.c:655
int paircompare_register(fr_dict_attr_t const *attribute, fr_dict_attr_t const *from, bool first_only, RAD_COMPARE_FUNC func, void *instance)
Register a function as compare function.
Definition: pair.c:395
void vmodule_failure_msg(REQUEST *request, char const *fmt, va_list ap)
Add a module failure message VALUE_PAIR to the request.
Definition: pair.c:869
FILE * fr_log_fp
Definition: radius.c:81
void module_failure_msg(REQUEST *request, char const *fmt,...)
Definition: pair.c:858
128 Bit IPv6 Address.
Definition: radius.h:40
struct cmp * next
Definition: pair.c:43
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
#define RINDENT()
Indent R* messages by one level.
Definition: log.h:265
void debug_pair(VALUE_PAIR *vp)
Print a single valuepair to stderr or error log.
Definition: pair.c:725
#define RERROR(fmt,...)
Definition: log.h:207
Definition: token.h:47
Only displayed when debugging is enabled.
Definition: log.h:41
struct rad_request::@7 log
Dictionary attribute.
Definition: dict.h:77
void * rad_malloc(size_t size)
Definition: util.c:411
Ascend binary format a packed data structure.
Definition: radius.h:37
#define MEM(x)
Definition: radiusd.h:396
static struct cmp * cmp
Definition: pair.c:45
32 Bit signed integer.
Definition: radius.h:45
static char const * name
#define REMARKER(_m, _i, _e)
Output string with error marker, showing where format error occurred.
Definition: log.h:306
#define VERIFY_VP(_x)
Definition: pair.h:44
#define UNUSED
Definition: libradius.h:134
int8_t tag
Tag value used to group valuepairs.
Definition: pair.h:121
const FR_NAME_NUMBER fr_tokens_table[]
Definition: token.c:30
IPv6 Prefix.
Definition: radius.h:41
#define pair_make_request(_a, _b, _c)
Definition: radiusd.h:545
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
Values of the encryption flags.
Definition: dict.h:40
int radius_callback_compare(REQUEST *request, VALUE_PAIR *req, VALUE_PAIR *check, VALUE_PAIR *check_pairs, VALUE_PAIR **reply_pairs)
Compare check and vp.
Definition: pair.c:265
valuepair value must be xlat expanded when it's added to VALUE_PAIR tree.
Definition: pair.h:102
Definition: token.h:46
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
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
int fr_pair_value_from_str(VALUE_PAIR *vp, char const *value, size_t inlen)
Convert string value to native attribute value.
Definition: pair.c:1840
struct value_pair * next
Definition: pair.h:116
static bool otherattr(fr_dict_attr_t const *attribute, fr_dict_attr_t const **from)
See what attribute we want to compare with.
Definition: pair.c:325
void rdebug_pair(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
Print a single valuepair to stderr or error log.
Definition: pair.c:739
int paircompare(REQUEST *request, VALUE_PAIR *req_list, VALUE_PAIR *check, VALUE_PAIR **rep_list)
Compare two pair lists except for the password information.
Definition: pair.c:479
Definition: token.h:50
bool first_only
Definition: pair.c:40
#define rad_assert(expr)
Definition: rad_assert.h:38
void fr_pair_value_snprintf(VALUE_PAIR *vp, char const *fmt,...)
Print data into an "string" data type.
Definition: pair.c:2071
void paircompare_unregister(fr_dict_attr_t const *attribute, RAD_COMPARE_FUNC func)
Unregister comparison function for an attribute.
Definition: pair.c:422
8 Bit unsigned integer.
Definition: radius.h:42
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *add)
Add a VP to the end of the list.
Definition: pair.c:659
#define DEBUG(fmt,...)
Definition: log.h:175
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
Interface ID.
Definition: radius.h:39
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
int radius_get_vp(VALUE_PAIR **out, REQUEST *request, char const *name)
Return a VP from the specified request.
Definition: pair.c:815
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
int radius_compare_vps(UNUSED REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp)
Compares check and vp by value.
Definition: pair.c:64
unsigned int attr
Attribute number.
Definition: dict.h:79
Definition: token.h:43
size_t fr_pair_snprint(char *out, size_t outlen, VALUE_PAIR const *vp)
Print one attribute and value to a string.
Definition: pair.c:2189
Attributes in incoming or internally proxied request.
Definition: tmpl.h:82
#define TAG_EQ(_x, _y)
Check if tags are equal.
Definition: pair.h:198
void fr_pair_fprint(FILE *fp, VALUE_PAIR const *vp)
Print one attribute and value to FP.
Definition: pair.c:2232
void * instance
Definition: pair.c:41
Definition: token.h:49
fr_dict_attr_t const * from
Definition: pair.c:39
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
bool radlog_debug_enabled(log_type_t type, log_lvl_t lvl, REQUEST *request) CC_HINT(nonnull)
Whether a request specific debug message should be logged.
Definition: log.c:604
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
void rad_const_free(void const *ptr)
Definition: util.c:424
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition: log.h:272
The current request.
Definition: tmpl.h:113
Definition: token.h:45
FR_TOKEN op
Operator to use when moving or inserting valuepair into a list.
Definition: pair.h:118
32 Bit unsigned integer.
Definition: radius.h:34
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
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
int radius_copy_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, char const *name)
Copy VP(s) from the specified request.
Definition: pair.c:842
64 Bit unsigned integer.
Definition: radius.h:51
Definition: token.h:48
static char const * prefix
Definition: mainconfig.c:81
char name[1]
Attribute name.
Definition: dict.h:89
#define TAG_ANY
Definition: pair.h:191
value_type_t type
Type of pointer in value union.
Definition: pair.h:132
32 Bit Unix timestamp.
Definition: radius.h:36
enum log_lvl log_lvl_t
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
#define fr_exit_now(_x)
Definition: libradius.h:511
#define WARN(fmt,...)
Definition: log.h:144
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
void rdebug_proto_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
Print a list of protocol VALUE_PAIRs.
Definition: pair.c:784
void fr_pair_value_strsteal(VALUE_PAIR *vp, char const *src)
Reparent an allocated char buffer to a VALUE_PAIR.
Definition: pair.c:1955
#define REDEBUG(fmt,...)
Definition: log.h:254
int radius_find_compare(fr_dict_attr_t const *attribute)
Find a comparison function for two attributes.
Definition: pair.c:303
void rdebug_pair_list(log_lvl_t level, REQUEST *request, VALUE_PAIR *vp, char const *prefix)
Print a list of VALUE_PAIRs.
Definition: pair.c:757
unsigned int has_tag
Tagged attribute.
Definition: dict.h:46
int(* RAD_COMPARE_FUNC)(void *instance, REQUEST *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR *, VALUE_PAIR **)
Definition: radiusd.h:332
Definition: pair.c:37
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
int paircompare_register_byname(char const *name, fr_dict_attr_t const *from, bool first_only, RAD_COMPARE_FUNC func, void *instance)
Register a function as compare function.
Definition: pair.c:351
String of printable characters.
Definition: radius.h:33
#define RDEBUGX(_l, fmt,...)
Definition: log.h:242
#define RWDEBUG(fmt,...)
Definition: log.h:251
PW_TYPE type
Value type.
Definition: dict.h:80
#define RCSID(id)
Definition: build.h:135
Definition: token.h:51
32 Bit IPv4 Address.
Definition: radius.h:35
char const * module
Module the request is currently being processed by.
Definition: radiusd.h:253
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
A source or sink of value data.
Definition: tmpl.h:187
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
#define ERROR(fmt,...)
Definition: log.h:145
unsigned int compare
has a paircompare registered
Definition: dict.h:55
16 Bit unsigned integer.
Definition: radius.h:43
Raw octets.
Definition: radius.h:38
RAD_COMPARE_FUNC compare
Definition: pair.c:42
fr_dict_attr_t const * attribute
Definition: pair.c:38
void paircompare_unregister_instance(void *instance)
Unregister comparison function for a module.
Definition: pair.c:451
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