All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
radattr.c
Go to the documentation of this file.
1 /*
2  * radattr.c RADIUS Attribute debugging tool.
3  *
4  * Version: $Id: bb0f560ed6b8ca9011bb654f7732a3569302e653 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2010 Alan DeKok <aland@freeradius.org>
21  */
22 
23 RCSID("$Id: bb0f560ed6b8ca9011bb654f7732a3569302e653 $")
24 
25 #include <freeradius-devel/libradius.h>
26 
27 typedef struct REQUEST REQUEST;
28 
29 #include <freeradius-devel/tmpl.h>
30 #include <freeradius-devel/map.h>
31 
32 #include <freeradius-devel/parser.h>
33 #include <freeradius-devel/xlat.h>
34 #include <freeradius-devel/conf.h>
35 #include <freeradius-devel/radpaths.h>
36 #include <freeradius-devel/dhcp.h>
37 
38 #include <ctype.h>
39 
40 #ifdef HAVE_GETOPT_H
41 # include <getopt.h>
42 #endif
43 
44 #include <assert.h>
45 
46 #include <freeradius-devel/log.h>
48 
49 #include <sys/wait.h>
50 pid_t rad_fork(void);
51 pid_t rad_waitpid(pid_t pid, int *status);
52 
53 pid_t rad_fork(void)
54 {
55  return fork();
56 }
57 
58 pid_t rad_waitpid(pid_t pid, int *status)
59 {
60  return waitpid(pid, status, 0);
61 }
62 
63 static ssize_t xlat_test(UNUSED char **out, UNUSED size_t outlen,
64  UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
65  UNUSED REQUEST *request, UNUSED char const *fmt)
66 {
67  return 0;
68 }
69 
71  .sockfd = -1,
72  .id = 0,
73  .code = PW_CODE_ACCESS_REQUEST,
74  .vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
75 };
76 
77 
79  .sockfd = -1,
80  .id = 0,
81  .code = PW_CODE_ACCESS_ACCEPT,
82  .vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
83 };
84 
85 
86 static char const *my_secret = "testing123";
87 
88 /*
89  * End of hacks for xlat
90  *
91  **********************************************************************/
92 
93 static int encode_tlv(char *buffer, uint8_t *output, size_t outlen);
94 
95 static char const hextab[] = "0123456789abcdef";
96 
97 static int encode_data_string(char *buffer,
98  uint8_t *output, size_t outlen)
99 {
100  int length = 0;
101  char *p;
102 
103  p = buffer + 1;
104 
105  while (*p && (outlen > 0)) {
106  if (*p == '"') {
107  return length;
108  }
109 
110  if (*p != '\\') {
111  *(output++) = *(p++);
112  outlen--;
113  length++;
114  continue;
115  }
116 
117  switch (p[1]) {
118  default:
119  *(output++) = p[1];
120  break;
121 
122  case 'n':
123  *(output++) = '\n';
124  break;
125 
126  case 'r':
127  *(output++) = '\r';
128  break;
129 
130  case 't':
131  *(output++) = '\t';
132  break;
133  }
134 
135  outlen--;
136  length++;
137  }
138 
139  fprintf(stderr, "String is not terminated\n");
140  return 0;
141 }
142 
143 static int encode_data_tlv(char *buffer, char **endptr,
144  uint8_t *output, size_t outlen)
145 {
146  int depth = 0;
147  int length;
148  char *p;
149 
150  for (p = buffer; *p != '\0'; p++) {
151  if (*p == '{') depth++;
152  if (*p == '}') {
153  depth--;
154  if (depth == 0) break;
155  }
156  }
157 
158  if (*p != '}') {
159  fprintf(stderr, "No trailing '}' in string starting "
160  "with \"%s\"\n",
161  buffer);
162  return 0;
163  }
164 
165  *endptr = p + 1;
166  *p = '\0';
167 
168  p = buffer + 1;
169  while (isspace((int) *p)) p++;
170 
171  length = encode_tlv(p, output, outlen);
172  if (length == 0) return 0;
173 
174  return length;
175 }
176 
177 static int encode_hex(char *p, uint8_t *output, size_t outlen)
178 {
179  int length = 0;
180  while (*p) {
181  char *c1, *c2;
182 
183  while (isspace((int) *p)) p++;
184 
185  if (!*p) break;
186 
187  if(!(c1 = memchr(hextab, tolower((int) p[0]), 16)) ||
188  !(c2 = memchr(hextab, tolower((int) p[1]), 16))) {
189  fprintf(stderr, "Invalid data starting at "
190  "\"%s\"\n", p);
191  return 0;
192  }
193 
194  *output = ((c1 - hextab) << 4) + (c2 - hextab);
195  output++;
196  length++;
197  p += 2;
198 
199  outlen--;
200  if (outlen == 0) {
201  fprintf(stderr, "Too much data\n");
202  return 0;
203  }
204  }
205 
206  return length;
207 }
208 
209 
210 static int encode_data(char *p, uint8_t *output, size_t outlen)
211 {
212  int length;
213 
214  if (!isspace((int) *p)) {
215  fprintf(stderr, "Invalid character following attribute "
216  "definition\n");
217  return 0;
218  }
219 
220  while (isspace((int) *p)) p++;
221 
222  if (*p == '{') {
223  int sublen;
224  char *q;
225 
226  length = 0;
227 
228  do {
229  while (isspace((int) *p)) p++;
230  if (!*p) {
231  if (length == 0) {
232  fprintf(stderr, "No data\n");
233  return 0;
234  }
235 
236  break;
237  }
238 
239  sublen = encode_data_tlv(p, &q, output, outlen);
240  if (sublen == 0) return 0;
241 
242  length += sublen;
243  output += sublen;
244  outlen -= sublen;
245  p = q;
246  } while (*q);
247 
248  return length;
249  }
250 
251  if (*p == '"') {
252  length = encode_data_string(p, output, outlen);
253  return length;
254  }
255 
256  length = encode_hex(p, output, outlen);
257 
258  if (length == 0) {
259  fprintf(stderr, "Empty string\n");
260  return 0;
261  }
262 
263  return length;
264 }
265 
266 static int decode_attr(char *buffer, char **endptr)
267 {
268  long attr;
269 
270  attr = strtol(buffer, endptr, 10);
271  if (*endptr == buffer) {
272  fprintf(stderr, "No valid number found in string "
273  "starting with \"%s\"\n", buffer);
274  return 0;
275  }
276 
277  if (!**endptr) {
278  fprintf(stderr, "Nothing follows attribute number\n");
279  return 0;
280  }
281 
282  if ((attr <= 0) || (attr > 256)) {
283  fprintf(stderr, "Attribute number is out of valid "
284  "range\n");
285  return 0;
286  }
287 
288  return (int) attr;
289 }
290 
291 static int decode_vendor(char *buffer, char **endptr)
292 {
293  long vendor;
294 
295  if (*buffer != '.') {
296  fprintf(stderr, "Invalid separator before vendor id\n");
297  return 0;
298  }
299 
300  vendor = strtol(buffer + 1, endptr, 10);
301  if (*endptr == (buffer + 1)) {
302  fprintf(stderr, "No valid vendor number found\n");
303  return 0;
304  }
305 
306  if (!**endptr) {
307  fprintf(stderr, "Nothing follows vendor number\n");
308  return 0;
309  }
310 
311  if ((vendor <= 0) || (vendor > (1 << 24))) {
312  fprintf(stderr, "Vendor number is out of valid range\n");
313  return 0;
314  }
315 
316  if (**endptr != '.') {
317  fprintf(stderr, "Invalid data following vendor number\n");
318  return 0;
319  }
320  (*endptr)++;
321 
322  return (int) vendor;
323 }
324 
325 static int encode_tlv(char *buffer, uint8_t *output, size_t outlen)
326 {
327  int attr;
328  int length;
329  char *p;
330 
331  attr = decode_attr(buffer, &p);
332  if (attr == 0) return 0;
333 
334  output[0] = attr;
335  output[1] = 2;
336 
337  if (*p == '.') {
338  p++;
339  length = encode_tlv(p, output + 2, outlen - 2);
340 
341  } else {
342  length = encode_data(p, output + 2, outlen - 2);
343  }
344 
345  if (length == 0) return 0;
346  if (length > (255 - 2)) {
347  fprintf(stderr, "TLV data is too long\n");
348  return 0;
349  }
350 
351  output[1] += length;
352 
353  return length + 2;
354 }
355 
356 static int encode_vsa(char *buffer, uint8_t *output, size_t outlen)
357 {
358  int vendor;
359  int length;
360  char *p;
361 
362  vendor = decode_vendor(buffer, &p);
363  if (vendor == 0) return 0;
364 
365  output[0] = 0;
366  output[1] = (vendor >> 16) & 0xff;
367  output[2] = (vendor >> 8) & 0xff;
368  output[3] = vendor & 0xff;
369 
370  length = encode_tlv(p, output + 4, outlen - 4);
371  if (length == 0) return 0;
372  if (length > (255 - 6)) {
373  fprintf(stderr, "VSA data is too long\n");
374  return 0;
375  }
376 
377 
378  return length + 4;
379 }
380 
381 static int encode_evs(char *buffer, uint8_t *output, size_t outlen)
382 {
383  int vendor;
384  int attr;
385  int length;
386  char *p;
387 
388  vendor = decode_vendor(buffer, &p);
389  if (vendor == 0) return 0;
390 
391  attr = decode_attr(p, &p);
392  if (attr == 0) return 0;
393 
394  output[0] = 0;
395  output[1] = (vendor >> 16) & 0xff;
396  output[2] = (vendor >> 8) & 0xff;
397  output[3] = vendor & 0xff;
398  output[4] = attr;
399 
400  length = encode_data(p, output + 5, outlen - 5);
401  if (length == 0) return 0;
402 
403  return length + 5;
404 }
405 
406 static int encode_extended(char *buffer,
407  uint8_t *output, size_t outlen)
408 {
409  int attr;
410  int length;
411  char *p;
412 
413  attr = decode_attr(buffer, &p);
414  if (attr == 0) return 0;
415 
416  output[0] = attr;
417 
418  if (attr == 26) {
419  length = encode_evs(p, output + 1, outlen - 1);
420  } else {
421  length = encode_data(p, output + 1, outlen - 1);
422  }
423  if (length == 0) return 0;
424  if (length > (255 - 3)) {
425  fprintf(stderr, "Extended Attr data is too long\n");
426  return 0;
427  }
428 
429  return length + 1;
430 }
431 
432 static int encode_long_extended(char *buffer,
433  uint8_t *output, size_t outlen)
434 {
435  int attr;
436  int length, total;
437  char *p;
438 
439  attr = decode_attr(buffer, &p);
440  if (attr == 0) return 0;
441 
442  /* output[0] is the extended attribute */
443  output[1] = 4;
444  output[2] = attr;
445  output[3] = 0;
446 
447  if (attr == 26) {
448  length = encode_evs(p, output + 4, outlen - 4);
449  if (length == 0) return 0;
450 
451  output[1] += 5;
452  length -= 5;
453  } else {
454  length = encode_data(p, output + 4, outlen - 4);
455  }
456  if (length == 0) return 0;
457 
458  total = 0;
459  while (1) {
460  int sublen = 255 - output[1];
461 
462  if (length <= sublen) {
463  output[1] += length;
464  total += output[1];
465  break;
466  }
467 
468  length -= sublen;
469 
470  memmove(output + 255 + 4, output + 255, length);
471  memcpy(output + 255, output, 4);
472 
473  output[1] = 255;
474  output[3] |= 0x80;
475 
476  output += 255;
477  output[1] = 4;
478  total += 255;
479  }
480 
481  return total;
482 }
483 
484 static int encode_rfc(char *buffer, uint8_t *output, size_t outlen)
485 {
486  int attr;
487  int length, sublen;
488  char *p;
489 
490  attr = decode_attr(buffer, &p);
491  if (attr == 0) return 0;
492 
493  length = 2;
494  output[0] = attr;
495  output[1] = 2;
496 
497  if (attr == 26) {
498  sublen = encode_vsa(p, output + 2, outlen - 2);
499 
500  } else if ((attr < 241) || (attr > 246)) {
501  sublen = encode_data(p, output + 2, outlen - 2);
502 
503  } else {
504  if (*p != '.') {
505  fprintf(stderr, "Invalid data following "
506  "attribute number\n");
507  return 0;
508  }
509 
510  if (attr < 245) {
511  sublen = encode_extended(p + 1,
512  output + 2, outlen - 2);
513  } else {
514 
515  /*
516  * Not like the others!
517  */
518  return encode_long_extended(p + 1, output, outlen);
519  }
520  }
521  if (sublen == 0) return 0;
522  if (sublen > (255 -2)) {
523  fprintf(stderr, "RFC Data is too long\n");
524  return 0;
525  }
526 
527  output[1] += sublen;
528  return length + sublen;
529 }
530 
531 static void parse_condition(char const *input, char *output, size_t outlen)
532 {
533  ssize_t slen;
534  char const *error = NULL;
535  fr_cond_t *cond;
536 
537  slen = fr_condition_tokenize(NULL, NULL, input, &cond, &error, FR_COND_ONE_PASS);
538  if (slen <= 0) {
539  snprintf(output, outlen, "ERROR offset %d %s", (int) -slen, error);
540  return;
541  }
542 
543  input += slen;
544  if (*input != '\0') {
545  talloc_free(cond);
546  snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) slen);
547  return;
548  }
549 
550  fr_cond_snprint(output, outlen, cond);
551 
552  talloc_free(cond);
553 }
554 
555 static void parse_xlat(char const *input, char *output, size_t outlen)
556 {
557  ssize_t slen;
558  char const *error = NULL;
559  char *fmt = talloc_typed_strdup(NULL, input);
560  xlat_exp_t *head;
561 
562  slen = xlat_tokenize(fmt, fmt, &head, &error);
563  if (slen <= 0) {
564  snprintf(output, outlen, "ERROR offset %d '%s'", (int) -slen, error);
565  return;
566  }
567 
568  if (input[slen] != '\0') {
569  snprintf(output, outlen, "ERROR offset %d 'Too much text'", (int) slen);
570  return;
571  }
572 
573  xlat_snprint(output, outlen, head);
574  talloc_free(fmt);
575 }
576 
577 static void process_file(fr_dict_t *dict, const char *root_dir, char const *filename)
578 {
579  int lineno;
580  size_t i, outlen;
581  ssize_t len, data_len;
582  FILE *fp;
583  char input[8192], buffer[8192];
584  char output[8192];
585  char directory[8192];
586  uint8_t *attr, data[2048];
587 
588  if (strcmp(filename, "-") == 0) {
589  fp = stdin;
590  filename = "<stdin>";
591  directory[0] = '\0';
592 
593  } else {
594  if (root_dir && *root_dir) {
595  snprintf(directory, sizeof(directory), "%s/%s", root_dir, filename);
596  } else {
597  strlcpy(directory, filename, sizeof(directory));
598  }
599 
600  fp = fopen(directory, "r");
601  if (!fp) {
602  fprintf(stderr, "Error opening %s: %s\n",
603  directory, fr_syserror(errno));
604  exit(1);
605  }
606 
607  filename = directory;
608  }
609 
610  lineno = 0;
611  *output = '\0';
612  data_len = 0;
613 
614  while (fgets(buffer, sizeof(buffer), fp) != NULL) {
615  char *p = strchr(buffer, '\n');
616  VALUE_PAIR *vp, *head = NULL;
617 
618  lineno++;
619 
620  if (!p) {
621  if (!feof(fp)) {
622  fprintf(stderr, "Line %d too long in %s\n",
623  lineno, directory);
624  exit(1);
625  }
626  } else {
627  *p = '\0';
628  }
629 
630  /*
631  * Comments, with hacks for User-Name[#]
632  */
633  p = strchr(buffer, '#');
634  if (p && ((p == buffer) ||
635  ((p > buffer) && (p[-1] != '[')))) *p = '\0';
636 
637  p = buffer;
638  while (isspace((int) *p)) p++;
639  if (!*p) continue;
640 
641  DEBUG2("%s[%d]: %s\n", filename, lineno, buffer);
642 
643  strlcpy(input, p, sizeof(input));
644 
645  if (strncmp(p, "raw ", 4) == 0) {
646  outlen = encode_rfc(p + 4, data, sizeof(data));
647  if (outlen == 0) {
648  fprintf(stderr, "Parse error in line %d of %s\n",
649  lineno, directory);
650  exit(1);
651  }
652 
653  print_hex:
654  if (outlen == 0) {
655  output[0] = 0;
656  continue;
657  }
658 
659  if (outlen >= (sizeof(output) / 2)) {
660  outlen = (sizeof(output) / 2) - 1;
661  }
662 
663  data_len = outlen;
664  for (i = 0; i < outlen; i++) {
665  if (sizeof(output) < (3*i)) break;
666 
667  snprintf(output + 3*i, sizeof(output) - (3*i) - 1,
668  "%02x ", data[i]);
669  }
670  outlen = strlen(output);
671  output[outlen - 1] = '\0';
672  continue;
673  }
674 
675  if (strncmp(p, "data ", 5) == 0) {
676  if (strcmp(p + 5, output) != 0) {
677  fprintf(stderr, "Mismatch at line %d of %s\n\tgot : %s\n\texpected : %s\n",
678  lineno, directory, output, p + 5);
679  exit(1);
680  }
681  continue;
682  }
683 
684  if (strncmp(p, "encode ", 7) == 0) {
685  vp_cursor_t cursor;
686  fr_radius_ctx_t encoder_ctx = { .packet = &my_packet,
687  .original = &my_original,
688  .secret = my_secret };
689 
690  if (strcmp(p + 7, "-") == 0) {
691  p = output;
692  } else {
693  p += 7;
694  }
695 
696  if (fr_pair_list_afrom_str(NULL, p, &head) != T_EOL) {
697  strlcpy(output, fr_strerror(), sizeof(output));
698  continue;
699  }
700 
701  attr = data;
702  fr_cursor_init(&cursor, &head);
703  while ((vp = fr_cursor_current(&cursor))) {
704  len = fr_radius_encode_pair(attr, data + sizeof(data) - attr, &cursor, &encoder_ctx);
705  if (len < 0) {
706  fprintf(stderr, "Failed encoding %s: %s\n",
707  vp->da->name, fr_strerror());
708  exit(1);
709  }
710 
711  attr += len;
712  if (len == 0) break;
713  }
714 
715  fr_pair_list_free(&head);
716  outlen = attr - data;
717  goto print_hex;
718  }
719 
720  if (strncmp(p, "decode ", 7) == 0) {
721  ssize_t my_len;
722  vp_cursor_t cursor;
723  fr_radius_ctx_t decoder_ctx = { .packet = &my_packet,
724  .original = &my_original,
725  .secret = my_secret };
726  if (strcmp(p + 7, "-") == 0) {
727  attr = data;
728  len = data_len;
729  } else {
730  attr = data;
731  len = encode_hex(p + 7, data, sizeof(data));
732  if (len == 0) {
733  fprintf(stderr, "Failed decoding hex string at line %d of %s\n", lineno, directory);
734  exit(1);
735  }
736  }
737 
738  fr_cursor_init(&cursor, &head);
739  my_len = 0;
740  while (len > 0) {
741  my_len = fr_radius_decode_pair(NULL, &cursor, fr_dict_root(fr_dict_internal), attr, len,
742  &decoder_ctx);
743  if (my_len < 0) {
744  fr_pair_list_free(&head);
745  break;
746  }
747 
748  if (my_len > len) {
749  fprintf(stderr, "Internal sanity check failed at %d\n", __LINE__);
750  exit(1);
751  }
752 
753  attr += my_len;
754  len -= my_len;
755  }
756 
757  /*
758  * Output may be an error, and we ignore
759  * it if so.
760  */
761  if (head) {
762  p = output;
763  for (vp = fr_cursor_first(&cursor);
764  vp;
765  vp = fr_cursor_next(&cursor)) {
766  fr_pair_snprint(p, sizeof(output) - (p - output), vp);
767  p += strlen(p);
768 
769  if (vp->next) {strcpy(p, ", ");
770  p += 2;
771  }
772  }
773 
774  fr_pair_list_free(&head);
775  } else if (my_len < 0) {
776  strlcpy(output, fr_strerror(), sizeof(output));
777 
778  } else { /* zero-length attribute */
779  *output = '\0';
780  }
781  continue;
782  }
783 
784  /*
785  * And some DHCP tests
786  */
787  if (strncmp(p, "encode-dhcp ", 12) == 0) {
788  vp_cursor_t cursor;
789 
790  if (strcmp(p + 12, "-") == 0) {
791  p = output;
792  } else {
793  p += 12;
794  }
795 
796  if (fr_pair_list_afrom_str(NULL, p, &head) != T_EOL) {
797  strlcpy(output, fr_strerror(), sizeof(output));
798  continue;
799  }
800 
801  fr_cursor_init(&cursor, &head);
802 
803 
804  attr = data;
805  while ((vp = fr_cursor_current(&cursor))) {
806  len = fr_dhcp_encode_option(attr, sizeof(data) - (data -attr), &cursor, NULL);
807  if (len < 0) {
808  fprintf(stderr, "Failed encoding %s: %s\n",
809  vp->da->name, fr_strerror());
810  exit(1);
811  }
812  attr += len;
813  };
814 
815  fr_pair_list_free(&head);
816  outlen = attr - data;
817  goto print_hex;
818  }
819 
820  if (strncmp(p, "decode-dhcp ", 12) == 0) {
821  vp_cursor_t cursor;
822  ssize_t my_len = 0;
823 
824  if (strcmp(p + 12, "-") == 0) {
825  attr = data;
826  len = data_len;
827  } else {
828  attr = data;
829  len = encode_hex(p + 12, data, sizeof(data));
830  if (len == 0) {
831  fprintf(stderr, "Failed decoding hex string at line %d of %s\n", lineno, directory);
832  exit(1);
833  }
834  }
835 
836  {
837  uint8_t const *end, *option_p;
838 
839  option_p = attr;
840  end = option_p + len;
841 
842  fr_cursor_init(&cursor, &head);
843 
844  /*
845  * Loop over all the options data
846  */
847  while (option_p < end) {
848  vp = NULL;
849  my_len = fr_dhcp_decode_option(NULL, &cursor,
850  fr_dict_root(fr_dict_internal), option_p,
851  end - option_p, NULL);
852  if (my_len <= 0) {
853  fr_pair_list_free(&head);
854  break;
855  }
856  option_p += my_len;
857  }
858  }
859 
860  /*
861  * Output may be an error, and we ignore
862  * it if so.
863  */
864  if (head) {
865  p = output;
866  for (vp = fr_cursor_first(&cursor);
867  vp;
868  vp = fr_cursor_next(&cursor)) {
869  fr_pair_snprint(p, sizeof(output) - (p - output), vp);
870  p += strlen(p);
871 
872  if (vp->next) {strcpy(p, ", ");
873  p += 2;
874  }
875  }
876 
877  fr_pair_list_free(&head);
878  } else if (my_len < 0) {
879  strlcpy(output, fr_strerror(), sizeof(output));
880 
881  } else { /* zero-length attribute */
882  *output = '\0';
883  }
884  continue;
885  }
886 
887  if (strncmp(p, "attribute ", 10) == 0) {
888  p += 10;
889 
890  if (fr_pair_list_afrom_str(NULL, p, &head) != T_EOL) {
891  strlcpy(output, fr_strerror(), sizeof(output));
892  continue;
893  }
894 
895  fr_pair_snprint(output, sizeof(output), head);
896  continue;
897  }
898 
899  if (strncmp(p, "dictionary ", 11) == 0) {
900  p += 11;
901 
902  if (fr_dict_parse_str(dict, p, fr_dict_root(dict), 0) < 0) {
903  strlcpy(output, fr_strerror(), sizeof(output));
904  continue;
905  }
906 
907  strlcpy(output, "ok", sizeof(output));
908  continue;
909  }
910 
911  if (strncmp(p, "$INCLUDE ", 9) == 0) {
912  char *q;
913 
914  p += 9;
915  while (isspace((int) *p)) p++;
916 
917  q = strrchr(directory, '/');
918  if (q) {
919  *q = '\0';
920  process_file(dict, directory, p);
921  *q = '/';
922  } else {
923  process_file(dict, NULL, p);
924  }
925  continue;
926  }
927 
928  if (strncmp(p, "condition ", 10) == 0) {
929  p += 10;
930  parse_condition(p, output, sizeof(output));
931  continue;
932  }
933 
934  if (strncmp(p, "xlat ", 5) == 0) {
935  p += 5;
936  parse_xlat(p, output, sizeof(output));
937  continue;
938  }
939 
940  fprintf(stderr, "Unknown input at line %d of %s\n",
941  lineno, directory);
942  exit(1);
943  }
944 
945  if (fp != stdin) fclose(fp);
946 }
947 
948 static void NEVER_RETURNS usage(void)
949 {
950  fprintf(stderr, "usage: radattr [OPTS] filename\n");
951  fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
952  fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
953  fprintf(stderr, " -x Debugging mode.\n");
954  fprintf(stderr, " -M Show talloc memory report.\n");
955 
956  exit(1);
957 }
958 
959 int main(int argc, char *argv[])
960 {
961  int c;
962  bool report = false;
963  char const *radius_dir = RADDBDIR;
964  char const *dict_dir = DICTDIR;
965  int *inst = &c;
966  fr_dict_t *dict = NULL;
967 
968 #ifndef NDEBUG
969  if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
970  fr_perror("radattr");
971  exit(EXIT_FAILURE);
972  }
973 #endif
974 
975 
976  while ((c = getopt(argc, argv, "d:D:xMh")) != EOF) switch (c) {
977  case 'd':
978  radius_dir = optarg;
979  break;
980  case 'D':
981  dict_dir = optarg;
982  break;
983  case 'x':
984  fr_debug_lvl++;
985  rad_debug_lvl = fr_debug_lvl;
986  fr_log_fp = stdout;
988  default_log.fd = STDOUT_FILENO;
989  break;
990  case 'M':
991  report = true;
992  break;
993  case 'h':
994  default:
995  usage();
996  }
997  argc -= (optind - 1);
998  argv += (optind - 1);
999 
1000  /*
1001  * Mismatch between the binary and the libraries it depends on
1002  */
1004  fr_perror("radattr");
1005  return 1;
1006  }
1007 
1008  if (fr_dict_init(NULL, &dict, dict_dir, RADIUS_DICTIONARY, "radius") < 0) {
1009  fr_perror("radattr");
1010  return 1;
1011  }
1012 
1013  if (fr_dict_read(dict, radius_dir, RADIUS_DICTIONARY) == -1) {
1014  fr_perror("radattr");
1015  return 1;
1016  }
1017 
1018  if (xlat_register(inst, "test", xlat_test, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN) < 0) {
1019  fprintf(stderr, "Failed registering xlat");
1020  return 1;
1021  }
1022 
1023  if (argc < 2) {
1024  process_file(dict, NULL, "-");
1025 
1026  } else {
1027  process_file(dict, NULL, argv[1]);
1028  }
1029 
1030  if (report) {
1031  talloc_free(dict);
1032  fr_log_talloc_report(NULL);
1033  }
1034 
1035  return 0;
1036 }
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
Definition: pair.c:544
static int encode_vsa(char *buffer, uint8_t *output, size_t outlen)
Definition: radattr.c:356
static char const * dict_dir
Definition: radwho.c:53
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
#define FR_COND_ONE_PASS
Definition: parser.h:96
static void NEVER_RETURNS usage(void)
Definition: radattr.c:948
FILE * fr_log_fp
Definition: radius.c:81
VALUE_PAIR * fr_cursor_first(vp_cursor_t *cursor)
Rewind cursor to the start of the list.
Definition: cursor.c:105
static char const * radius_dir
Path to raddb directory.
Definition: mainconfig.c:88
int xlat_register(void *mod_inst, char const *name, xlat_func_t func, xlat_escape_t escape, xlat_instantiate_t instantiate, size_t inst_size, size_t buf_len)
Register an xlat function.
Definition: xlat.c:717
int fr_radius_encode_pair(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx)
Encode a data structure into a RADIUS attribute.
static void process_file(fr_dict_t *dict, const char *root_dir, char const *filename)
Definition: radattr.c:577
Definition: token.h:34
int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
Definition: dict.c:2291
static RADIUS_PACKET my_original
Definition: radattr.c:70
#define UNUSED
Definition: libradius.h:134
ssize_t fr_dhcp_encode_option(uint8_t *out, size_t outlen, vp_cursor_t *cursor, void *encoder_ctx)
ssize_t fr_dhcp_decode_option(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t len, void *decoder_ctx)
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
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition: snprintf.c:686
uint8_t length
Definition: proto_bfd.c:203
#define inst
fr_log_t default_log
Definition: log.c:216
int fr_log_talloc_report(TALLOC_CTX *ctx)
Generate a talloc memory report for a context and print to stderr/stdout.
Definition: debug.c:810
#define XLAT_DEFAULT_BUF_LEN
Definition: xlat.h:89
static int encode_data_string(char *buffer, uint8_t *output, size_t outlen)
Definition: radattr.c:97
int fr_debug_lvl
Definition: misc.c:40
static int encode_long_extended(char *buffer, uint8_t *output, size_t outlen)
Definition: radattr.c:432
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
struct value_pair * next
Definition: pair.h:116
int fr_fault_setup(char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition: debug.c:890
Vendors and attribute names.
Definition: dict.c:61
RFC2865 - Access-Request.
Definition: radius.h:92
Definition: xlat.c:60
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition: version.c:38
static int decode_attr(char *buffer, char **endptr)
Definition: radattr.c:266
static int encode_data_tlv(char *buffer, char **endptr, uint8_t *output, size_t outlen)
Definition: radattr.c:143
static void parse_condition(char const *input, char *output, size_t outlen)
Definition: radattr.c:531
static char const hextab[]
Definition: radattr.c:95
static int encode_evs(char *buffer, uint8_t *output, size_t outlen)
Definition: radattr.c:381
#define DEBUG2(fmt,...)
Definition: log.h:176
void void fr_perror(char const *,...) CC_HINT(format(printf
static int encode_hex(char *p, uint8_t *output, size_t outlen)
Definition: radattr.c:177
static RADIUS_PACKET my_packet
Definition: radattr.c:78
RFC2865 - Access-Accept.
Definition: radius.h:93
#define RADIUS_DICTIONARY
Definition: conf.h:7
static int encode_data(char *p, uint8_t *output, size_t outlen)
Definition: radattr.c:210
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
VALUE_PAIR * fr_cursor_current(vp_cursor_t *cursor)
Return the VALUE_PAIR the cursor current points to.
Definition: cursor.c:304
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
static char const * my_secret
Definition: radattr.c:86
static ssize_t xlat_test(UNUSED char **out, UNUSED size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, UNUSED REQUEST *request, UNUSED char const *fmt)
Definition: radattr.c:63
char name[1]
Attribute name.
Definition: dict.h:89
static int encode_tlv(char *buffer, uint8_t *output, size_t outlen)
Definition: radattr.c:325
uint8_t data[]
Definition: eap_pwd.h:625
enum log_lvl log_lvl_t
ssize_t fr_radius_decode_pair(TALLOC_CTX *ctx, vp_cursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decoder_ctx)
Create a "normal" VALUE_PAIR from the given data.
size_t fr_cond_snprint(char *buffer, size_t bufsize, fr_cond_t const *c)
Definition: parser.c:50
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
static int encode_extended(char *buffer, uint8_t *output, size_t outlen)
Definition: radattr.c:406
static void parse_xlat(char const *input, char *output, size_t outlen)
Definition: radattr.c:555
static void print_hex(RADIUS_PACKET *packet)
Definition: dhcpclient.c:235
ssize_t ssize_t ssize_t ssize_t ssize_t xlat_tokenize(TALLOC_CTX *ctx, char *fmt, xlat_exp_t **head, char const **error)
Definition: xlat.c:1784
ssize_t fr_condition_tokenize(TALLOC_CTX *ctx, CONF_ITEM *ci, char const *start, fr_cond_t **head, char const **error, int flag)
Tokenize a conditional check.
Definition: parser.c:1711
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
pid_t rad_waitpid(pid_t pid, int *status)
Definition: radattr.c:58
int main(int argc, char *argv[])
Definition: radattr.c:959
static int encode_rfc(char *buffer, uint8_t *output, size_t outlen)
Definition: radattr.c:484
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
int fr_dict_parse_str(fr_dict_t *dict, char *buf, fr_dict_attr_t const *parent, unsigned int vendor)
Definition: dict.c:2306
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
RADIUS_PACKET const * packet
Definition: libradius.h:267
log_dst_t dst
Log destination.
Definition: log.h:72
#define NEVER_RETURNS
Definition: libradius.h:133
Log to stdout.
Definition: log.h:58
FR_TOKEN fr_pair_list_afrom_str(TALLOC_CTX *ctx, char const *buffer, VALUE_PAIR **head)
Read one line of attribute/value pairs into a list.
Definition: pair.c:1261
#define RCSID(id)
Definition: build.h:135
pid_t rad_fork(void)
Definition: radattr.c:53
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
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
int fd
File descriptor to write messages to.
Definition: log.h:71
static int decode_vendor(char *buffer, char **endptr)
Definition: radattr.c:291
int fr_dict_init(TALLOC_CTX *ctx, fr_dict_t **out, char const *dir, char const *fn, char const *name)
(re)initialize a protocol dictionary
Definition: dict.c:2148
#define RADIUSD_MAGIC_NUMBER
Definition: libradius.h:51
size_t xlat_snprint(char *buffer, size_t bufsize, xlat_exp_t const *node)
Definition: xlat.c:1659