Radcli library 1.5.3
A simple radius library
Loading...
Searching...
No Matches
dict.c
1/*
2 * Copyright (C) 1995,1996,1997 Lars Fenneberg
3 *
4 * Copyright 1992 Livingston Enterprises, Inc.
5 *
6 * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
7 * and Merit Network, Inc. All Rights Reserved
8 *
9 * See the file COPYRIGHT for the respective terms and conditions.
10 * If the file is missing contact me at lf@elemental.net
11 * and I'll send you a copy.
12 *
13 */
14
21
22#include <config.h>
23#include <includes.h>
24#include <radcli/radcli.h>
25#include "util.h"
26
38DICT_ATTR *rc_dict_addattr(rc_handle *rh, char const * namestr, uint32_t value, int type, uint32_t vendorspec)
39{
40 DICT_ATTR *attr;
41
42 if (strlen (namestr) > RC_NAME_LENGTH)
43 {
44 rc_log(LOG_ERR, "rc_dict_addattr: invalid attribute length");
45 return NULL;
46 }
47
48 if (type < 0 || type >= PW_TYPE_MAX)
49 {
50 rc_log(LOG_ERR, "rc_dict_addattr: invalid attribute type");
51 return NULL;
52 }
53
54 /* Create a new attribute for the list */
55 if ((attr = malloc(sizeof (DICT_ATTR))) == NULL)
56 {
57 rc_log(LOG_CRIT, "rc_dict_addattr: out of memory");
58 return NULL;
59 }
60
61 strlcpy(attr->name, namestr, sizeof(attr->name));
62 attr->value = RADCLI_VENDOR_ATTR_SET(value, vendorspec);
63 attr->type = type;
64
65 /* Insert it into the list */
66 attr->next = rh->dictionary_attributes;
67 rh->dictionary_attributes = attr;
68 return attr;
69}
70
81DICT_VALUE *rc_dict_addval(rc_handle *rh, char const * attrstr, char const * namestr, uint32_t value)
82{
83 DICT_VALUE *dval;
84
85 if (strlen(attrstr) > RC_NAME_LENGTH)
86 {
87 rc_log(LOG_ERR, "rc_dict_addval: invalid attribute length");
88 return NULL;
89 }
90
91 if (strlen(namestr) > RC_NAME_LENGTH)
92 {
93 rc_log(LOG_ERR, "rc_dict_addval: invalid name length");
94 return NULL;
95 }
96
97 /* Create a new VALUE entry for the list */
98 if ((dval = malloc(sizeof (DICT_VALUE))) == NULL)
99 {
100 rc_log(LOG_CRIT, "rc_dict_addval: out of memory");
101 return NULL;
102 }
103 strlcpy(dval->attrname, attrstr, sizeof(dval->attrname));
104 strlcpy(dval->name, namestr, sizeof(dval->name));
105 dval->value = value;
106
107 /* Insert it into the list */
108 dval->next = rh->dictionary_values;
109 rh->dictionary_values = dval;
110 return dval;
111}
112
122DICT_VENDOR *rc_dict_addvend(rc_handle *rh, char const * namestr, uint32_t vendorspec)
123{
124 DICT_VENDOR *dvend;
125
126 if (strlen(namestr) > RC_NAME_LENGTH)
127 {
128 rc_log(LOG_ERR, "rc_dict_addvend: invalid vendor name length");
129 return NULL;
130 }
131
132 /* Create a new VENDOR entry for the list */
133 dvend = malloc(sizeof(DICT_VENDOR));
134 if (dvend == NULL)
135 {
136 rc_log(LOG_CRIT, "rc_dict_init: out of memory");
137 return NULL;
138 }
139 strlcpy(dvend->vendorname, namestr, sizeof(dvend->vendorname));
140 dvend->vendorpec = vendorspec;
141
142 /* Insert it into the list */
143 dvend->next = rh->dictionary_vendors;
144 rh->dictionary_vendors = dvend;
145 return dvend;
146}
147
148/* Parse the input dictionary-config and initialize the dictionary.
149 *
150 * Read all ATTRIBUTES into the dictionary_attributes list.
151 * Read all VALUES into the dictionary_values list.
152 *
153 * @param rh a handle to parsed configuration.
154 * @param dictfd a handle to the dictionary config.
155 * @param filename the name of the dictionary file.
156 * @return 0 on success, -1 on failure.
157 */
159static int is_unsigned_decimal(char const *s)
160{
161 if (*s == '\0')
162 return 0;
163 for (; *s != '\0'; s++) {
164 if (!isdigit((unsigned char) *s))
165 return 0;
166 }
167 return 1;
168}
169
170static int rc_dict_init(rc_handle *rh, FILE *dictfd, char const *filename)
171{
172 char namestr[AUTH_ID_LEN];
173 char valstr[AUTH_ID_LEN];
174 char attrstr[AUTH_ID_LEN];
175 char typestr[AUTH_ID_LEN];
176 char optstr[AUTH_ID_LEN];
177 char ifilename[RC_MAX(1024, PATH_MAX)] = {0};
178 char *cp;
179 char *saveptr;
180 char *tok;
181 int line_no = 0;
182 DICT_ATTR *attr;
183 DICT_VALUE *dval;
184 DICT_VENDOR *dvend;
185 char *buffer = NULL;
186 size_t bufsize = 0;
187 uint32_t value;
188 int type;
189 unsigned attr_vendorspec = 0;
190 const char *pfilename = filename;
191
192 if (pfilename == NULL)
193 {
194 pfilename = "memory";
195 }
196
197 while (getline (&buffer, &bufsize, dictfd) != -1)
198 {
199 line_no++;
200
201 /* Skip empty space */
202 if (*buffer == '#' || *buffer == '\0' || *buffer == '\n' || \
203 *buffer == '\r')
204 {
205 continue;
206 }
207
208 /* Strip out comments */
209 cp = strchr(buffer, '#');
210 if (cp != NULL)
211 {
212 *cp = '\0';
213 }
214
215 tok = strtok_r(buffer, " \t\r\n", &saveptr);
216 if (tok == NULL)
217 {
218 continue;
219 }
220
221 if (strcmp (tok, "ATTRIBUTE") == 0)
222 {
223 char *name_t, *val_t, *type_t, *opt_t;
224
225 /* Read the ATTRIBUTE line */
226 name_t = strtok_r(NULL, " \t\r\n", &saveptr);
227 val_t = strtok_r(NULL, " \t\r\n", &saveptr);
228 type_t = strtok_r(NULL, " \t\r\n", &saveptr);
229 opt_t = strtok_r(NULL, " \t\r\n", &saveptr);
230 if (name_t == NULL || val_t == NULL || type_t == NULL)
231 {
232 rc_log(LOG_ERR,
233 "rc_dict_init: invalid attribute on line %d of "
234 "dictionary %s", line_no, pfilename);
235 goto error;
236 }
237 /*
238 * Validate all entries. Length checks must run against the
239 * original tokens, before strlcpy() truncates them into the
240 * fixed-size buffers below -- otherwise an over-long name can
241 * never trip the check, since the truncated copy is always
242 * within bounds.
243 */
244 if (strlen (name_t) > RC_NAME_LENGTH)
245 {
246 rc_log(LOG_ERR,
247 "rc_dict_init: invalid name length on line %d of "
248 "dictionary %s", line_no, pfilename);
249 goto error;
250 }
251
252 strlcpy(namestr, name_t, sizeof(namestr));
253 strlcpy(valstr, val_t, sizeof(valstr));
254 strlcpy(typestr, type_t, sizeof(typestr));
255 if (opt_t != NULL)
256 {
257 strlcpy(optstr, opt_t, sizeof(optstr));
258 }
259 else
260 {
261 optstr[0] = '\0';
262 }
263
264 if (!is_unsigned_decimal (valstr))
265 {
266 rc_log(LOG_ERR,
267 "rc_dict_init: invalid value on line %d of dictionary %s",
268 line_no, pfilename);
269 goto error;
270 }
271 value = atoi (valstr);
272
273 if (strcmp (typestr, "string") == 0)
274 {
275 type = PW_TYPE_STRING;
276 }
277 else if (strcmp (typestr, "integer") == 0)
278 {
279 type = PW_TYPE_INTEGER;
280 }
281 else if (strcmp (typestr, "ipaddr") == 0)
282 {
283 type = PW_TYPE_IPADDR;
284 }
285 else if (strcmp (typestr, "ipv4addr") == 0)
286 {
287 type = PW_TYPE_IPADDR;
288 }
289 else if (strcmp (typestr, "ipv6addr") == 0)
290 {
291 type = PW_TYPE_IPV6ADDR;
292 }
293 else if (strcmp (typestr, "ipv6prefix") == 0)
294 {
295 type = PW_TYPE_IPV6PREFIX;
296 }
297 else if (strcmp (typestr, "date") == 0)
298 {
299 type = PW_TYPE_DATE;
300 }
301 else
302 {
303 rc_log(LOG_ERR,
304 "rc_dict_init: invalid type on line %d of dictionary %s",
305 line_no, pfilename);
306 goto error;
307 }
308
309 dvend = NULL;
310 if (optstr[0] != '\0') {
311 char *cp1;
312 for (cp1 = optstr; cp1 != NULL; cp1 = cp) {
313 cp = strchr(cp1, ',');
314 if (cp != NULL) {
315 *cp = '\0';
316 cp++;
317 }
318 if (strncmp(cp1, "vendor=", 7) == 0)
319 cp1 += 7;
320 dvend = rc_dict_findvend(rh, cp1);
321 if (dvend == NULL) {
322 rc_log(LOG_ERR,
323 "rc_dict_init: unknown Vendor-Id %s on line %d of "
324 "dictionary %s", cp1, line_no, pfilename);
325 goto error;
326 }
327 }
328 }
329
330 /* Create a new attribute for the list */
331 if ((attr = malloc (sizeof (DICT_ATTR))) == NULL)
332 {
333 rc_log(LOG_CRIT, "rc_dict_init: out of memory");
334 goto error;
335 }
336 strlcpy (attr->name, namestr, sizeof(attr->name));
337 attr->type = type;
338
339 if (dvend != NULL) {
340 attr->value = RADCLI_VENDOR_ATTR_SET(value, dvend->vendorpec);
341 } else {
342 attr->value = RADCLI_VENDOR_ATTR_SET(value, attr_vendorspec);
343 }
344
345 /* Insert it into the list */
346 attr->next = rh->dictionary_attributes;
347 rh->dictionary_attributes = attr;
348 }
349 else if (strcmp (tok, "VALUE") == 0)
350 {
351 char *attr_t, *name_t, *val_t;
352
353 /* Read the VALUE line */
354 attr_t = strtok_r(NULL, " \t\r\n", &saveptr);
355 name_t = strtok_r(NULL, " \t\r\n", &saveptr);
356 val_t = strtok_r(NULL, " \t\r\n", &saveptr);
357 if (attr_t == NULL || name_t == NULL || val_t == NULL)
358 {
359 rc_log(LOG_ERR,
360 "rc_dict_init: invalid value entry on line %d of "
361 "dictionary %s", line_no, pfilename);
362 goto error;
363 }
364 /*
365 * Validate all entries. Length checks must run against the
366 * original tokens, before strlcpy() truncates them below.
367 */
368 if (strlen (attr_t) > RC_NAME_LENGTH)
369 {
370 rc_log(LOG_ERR,
371 "rc_dict_init: invalid attribute length on line %d of "
372 "dictionary %s", line_no, pfilename);
373 goto error;
374 }
375
376 if (strlen (name_t) > RC_NAME_LENGTH)
377 {
378 rc_log(LOG_ERR,
379 "rc_dict_init: invalid name length on line %d of "
380 "dictionary %s", line_no, pfilename);
381 goto error;
382 }
383
384 strlcpy(attrstr, attr_t, sizeof(attrstr));
385 strlcpy(namestr, name_t, sizeof(namestr));
386 strlcpy(valstr, val_t, sizeof(valstr));
387
388 if (!is_unsigned_decimal (valstr))
389 {
390 rc_log(LOG_ERR,
391 "rc_dict_init: invalid value on line %d of dictionary %s",
392 line_no, pfilename);
393 goto error;
394 }
395 value = atoi (valstr);
396
397 /* Create a new VALUE entry for the list */
398 if ((dval = malloc (sizeof (DICT_VALUE))) == NULL)
399 {
400 rc_log(LOG_CRIT, "rc_dict_init: out of memory");
401 goto error;
402 }
403 strlcpy (dval->attrname, attrstr, sizeof(dval->attrname));
404 strlcpy (dval->name, namestr, sizeof(dval->name));
405 dval->value = value;
406
407 /* Insert it into the list */
408 dval->next = rh->dictionary_values;
409 rh->dictionary_values = dval;
410 }
411 else if ((filename != NULL) &&
412 (strcmp (tok, "$INCLUDE") == 0))
413 {
414 char *path_t;
415
416 /* Read the $INCLUDE line. The path token is used directly
417 * (strtok_r null-terminates it in place in buffer, which is
418 * large enough for the longest path this parser can see),
419 * copied into ifilename (RC_MAX(1024, PATH_MAX)-sized) since
420 * $INCLUDE paths can legitimately be longer than 63 chars. */
421 path_t = strtok_r(NULL, " \t\r\n", &saveptr);
422 if (path_t == NULL)
423 {
424 rc_log(LOG_ERR,
425 "rc_dict_init: invalid include entry on line %d of "
426 "dictionary %s", line_no, pfilename);
427 goto error;
428 }
429 strlcpy(ifilename, path_t, sizeof(ifilename));
430 /* Append directory if necessary */
431 if (path_t[0] != '/') {
432 cp = strrchr(filename, '/');
433 if (cp != NULL) {
434 *cp = '\0';
435 strlcpy(ifilename, filename, sizeof(ifilename));
436 strlcat(ifilename, "/", sizeof(ifilename));
437 strlcat(ifilename, path_t, sizeof(ifilename));
438 *cp = '/';
439 }
440 }
441 if (rc_read_dictionary(rh, ifilename) < 0)
442 {
443 goto error;
444 }
445 }
446 else if (strcmp (tok, "END-VENDOR") == 0)
447 {
448 attr_vendorspec = 0;
449 }
450 else if (strcmp (tok, "BEGIN-VENDOR") == 0)
451 {
452 DICT_VENDOR *v;
453 char *name_t;
454
455 /* Read the vendor name */
456 name_t = strtok_r(NULL, " \t\r\n", &saveptr);
457 if (name_t == NULL)
458 {
459 rc_log(LOG_ERR,
460 "rc_dict_init: invalid Vendor-Id on line %d of "
461 "dictionary %s", line_no, pfilename);
462 goto error;
463 }
464
465 v = rc_dict_findvend(rh, name_t);
466 if (v == NULL) {
467 rc_log(LOG_ERR,
468 "rc_dict_init: unknown Vendor %s on line %d of "
469 "dictionary %s", name_t, line_no, pfilename);
470 goto error;
471 }
472
473 attr_vendorspec = v->vendorpec;
474 }
475 else if (strcmp (tok, "VENDOR") == 0)
476 {
477 char *name_t, *val_t;
478
479 /* Read the VENDOR line */
480 name_t = strtok_r(NULL, " \t\r\n", &saveptr);
481 val_t = strtok_r(NULL, " \t\r\n", &saveptr);
482 if (name_t == NULL || val_t == NULL)
483 {
484 rc_log(LOG_ERR,
485 "rc_dict_init: invalid Vendor-Id on line %d of "
486 "dictionary %s", line_no, pfilename);
487 goto error;
488 }
489 /* Validate all entries against the original tokens, before
490 * strlcpy() truncates them below. */
491 if (strlen (name_t) > RC_NAME_LENGTH)
492 {
493 rc_log(LOG_ERR,
494 "rc_dict_init: invalid attribute length on line %d of "
495 "dictionary %s", line_no, pfilename);
496 goto error;
497 }
498
499 strlcpy(attrstr, name_t, sizeof(attrstr));
500 strlcpy(valstr, val_t, sizeof(valstr));
501
502 if (!is_unsigned_decimal (valstr))
503 {
504 rc_log(LOG_ERR,
505 "rc_dict_init: invalid Vendor-Id on line %d of "
506 "dictionary %s", line_no, pfilename);
507 goto error;
508 }
509 value = atoi (valstr);
510
511 /* Create a new VENDOR entry for the list */
512 dvend = malloc(sizeof(DICT_VENDOR));
513 if (dvend == NULL)
514 {
515 rc_log(LOG_CRIT, "rc_dict_init: out of memory");
516 goto error;
517 }
518 strlcpy (dvend->vendorname, attrstr, sizeof(dvend->vendorname));
519 dvend->vendorpec = value;
520
521 /* Insert it into the list */
522 dvend->next = rh->dictionary_vendors;
523 rh->dictionary_vendors = dvend;
524 }
525 }
526 free(buffer);
527 return 0;
528
529error:
530 free(buffer);
531 return -1;
532}
534
544int rc_read_dictionary (rc_handle *rh, char const *filename)
545{
546 FILE *dictfd;
547 int ret_val = 0;
548
549 if (rh->first_dict_read != NULL && strcmp(filename, rh->first_dict_read) == 0)
550 return 0;
551
552 if ((dictfd = fopen (filename, "r")) == NULL)
553 {
554 rc_log(LOG_ERR, "rc_read_dictionary couldn't open dictionary %s: %s",
555 filename, strerror(errno));
556 return -1;
557 }
558
559 ret_val = rc_dict_init(rh, dictfd, filename);
560
561 fclose (dictfd);
562
563 if (rh->first_dict_read == NULL)
564 rh->first_dict_read = strdup(filename);
565
566 return ret_val;
567}
568
579int rc_read_dictionary_from_buffer (rc_handle *rh, char const *buf, size_t size)
580{
581 FILE *dictfd;
582 int ret_val = 0;
583
584 if ((dictfd = fmemopen ((void *)buf, size, "r")) == NULL)
585 {
586 rc_log(LOG_ERR, "rc_read_dictionary_from_buffer failed to read "
587 "input buffer %s", strerror(errno));
588 return -1;
589 }
590
591 ret_val = rc_dict_init(rh, dictfd, NULL);
592
593 fclose (dictfd);
594
595 return ret_val;
596}
597
604DICT_ATTR *rc_dict_getattr(rc_handle const *rh, uint64_t attribute)
605{
606 DICT_ATTR *attr;
607
608 attr = rh->dictionary_attributes;
609 while (attr != NULL)
610 {
611 if (attr->value == attribute)
612 {
613 return attr;
614 }
615 attr = attr->next;
616 }
617 return NULL;
618}
619
627DICT_ATTR *rc_dict_findattr(rc_handle const *rh, char const *attrname)
628{
629 DICT_ATTR *attr;
630
631 attr = rh->dictionary_attributes;
632 while (attr != NULL)
633 {
634 if (strcasecmp (attr->name, attrname) == 0)
635 {
636 return attr;
637 }
638 attr = attr->next;
639 }
640 return NULL;
641}
642
643
650DICT_VALUE *rc_dict_findval(rc_handle const *rh, char const *valname)
651{
652 DICT_VALUE *val;
653 val = rh->dictionary_values;
654 while (val != NULL)
655 {
656 if (strcasecmp (val->name, valname) == 0)
657 {
658 return val;
659 }
660 val = val->next;
661 }
662 return NULL;
663}
664
671DICT_VENDOR *rc_dict_findvend(rc_handle const *rh, char const *vendorname)
672{
673 DICT_VENDOR *vend;
674
675 for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next)
676 if (strcasecmp(vend->vendorname, vendorname) == 0)
677 return vend;
678 return NULL;
679}
680
687DICT_VENDOR *rc_dict_getvend (rc_handle const *rh, uint32_t vendorspec)
688{
689 DICT_VENDOR *vend;
690
691 for (vend = rh->dictionary_vendors; vend != NULL; vend = vend->next)
692 if (vend->vendorpec == vendorspec)
693 return vend;
694 return NULL;
695}
696
704DICT_VALUE *rc_dict_getval(rc_handle const *rh, uint32_t value, char const *attrname)
705{
706 DICT_VALUE *val;
707
708 val = rh->dictionary_values;
709 while (val != NULL)
710 {
711 if (strcasecmp (val->attrname, attrname) == 0 &&
712 val->value == value)
713 {
714 return val;
715 }
716 val = val->next;
717 }
718 return NULL;
719}
720
725void rc_dict_free(rc_handle *rh)
726{
727 DICT_ATTR *attr, *nattr;
728 DICT_VALUE *val, *nval;
729 DICT_VENDOR *vend, *nvend;
730
731 for (attr = rh->dictionary_attributes; attr != NULL; attr = nattr) {
732 nattr = attr->next;
733 free(attr);
734 }
735 for (val = rh->dictionary_values; val != NULL; val = nval) {
736 nval = val->next;
737 free(val);
738 }
739 for (vend = rh->dictionary_vendors; vend != NULL; vend = nvend) {
740 nvend = vend->next;
741 free(vend);
742 }
743 rh->dictionary_attributes = NULL;
744 rh->dictionary_values = NULL;
745 rh->dictionary_vendors = NULL;
746}
747
DICT_VALUE * rc_dict_getval(rc_handle const *rh, uint32_t value, char const *attrname)
Get DICT_VALUE based on attribute name and integer value number.
Definition dict.c:704
DICT_ATTR * rc_dict_addattr(rc_handle *rh, char const *namestr, uint32_t value, int type, uint32_t vendorspec)
Add attribute to dictionary.
Definition dict.c:38
DICT_VENDOR * rc_dict_findvend(rc_handle const *rh, char const *vendorname)
Lookup a DICT_VENDOR by its name.
Definition dict.c:671
int rc_read_dictionary_from_buffer(rc_handle *rh, char const *buf, size_t size)
Initialize the dictionary from Buffer.
Definition dict.c:579
DICT_VALUE * rc_dict_findval(rc_handle const *rh, char const *valname)
Lookup a DICT_VALUE by its name.
Definition dict.c:650
int rc_read_dictionary(rc_handle *rh, char const *filename)
Initialize the dictionary.
Definition dict.c:544
DICT_VENDOR * rc_dict_getvend(rc_handle const *rh, uint32_t vendorspec)
Lookup a DICT_VENDOR by its IANA number.
Definition dict.c:687
DICT_ATTR * rc_dict_getattr(rc_handle const *rh, uint64_t attribute)
Lookup a DICT_ATTR by attribute number.
Definition dict.c:604
void rc_dict_free(rc_handle *rh)
Frees the allocated dictionary.
Definition dict.c:725
DICT_VALUE * rc_dict_addval(rc_handle *rh, char const *attrstr, char const *namestr, uint32_t value)
Add value to dictionary.
Definition dict.c:81
DICT_VENDOR * rc_dict_addvend(rc_handle *rh, char const *namestr, uint32_t vendorspec)
Add vendor to dictionary.
Definition dict.c:122
DICT_ATTR * rc_dict_findattr(rc_handle const *rh, char const *attrname)
Lookup a DICT_ATTR by its name.
Definition dict.c:627
@ PW_TYPE_IPADDR
The attribute is an IPv4 address in host-byte order.
Definition radcli.h:123
@ PW_TYPE_IPV6ADDR
The attribute is an 128-bit IPv6 address.
Definition radcli.h:125
@ PW_TYPE_MAX
Maximum number of types (last+1)
Definition radcli.h:127
@ PW_TYPE_IPV6PREFIX
The attribute is an IPv6 prefix; the lvalue will indicate its size.
Definition radcli.h:126
@ PW_TYPE_INTEGER
The attribute is a 32-bit integer.
Definition radcli.h:122
@ PW_TYPE_DATE
The attribute contains a 32-bit number indicating the seconds since epoch.
Definition radcli.h:124
@ PW_TYPE_STRING
The attribute is a printable string.
Definition radcli.h:121
Public API of the radcli library.
rc_attr_type type
string, int, etc..
Definition radcli.h:445
uint64_t value
attribute index and vendor number; use VENDOR() and ATTRID() to separate.
Definition radcli.h:444
char name[RC_NAME_LENGTH+1]
attribute name.
Definition radcli.h:443