24#include <radcli/radcli.h>
25#include <radcli/radcli2.h>
34static int is_unsigned_decimal(
char const *s)
38 for (; *s !=
'\0'; s++) {
39 if (!isdigit((
unsigned char) *s))
85static int dict2_check_attr(rc_handle *rh,
const struct radcli_dict_attr *cand,
86 char const *pfilename,
int line_no,
87 struct radcli_dict_attr **existing_out)
89 struct radcli_dict_attr *existing = radcli_dict_attr_by_name(rh, cand->name);
91 *existing_out = existing;
95 if (existing->value == cand->value && existing->type == cand->type)
100 "%s: line %d: attribute %s redefined with a conflicting "
101 "definition (id %u vendor %u type %d -> id %u vendor %u type %d)",
102 pfilename, line_no, cand->name,
103 (
unsigned)ATTRID(existing->value), (
unsigned)VENDOR(existing->value), existing->type,
104 (
unsigned)ATTRID(cand->value), (
unsigned)VENDOR(cand->value), cand->type);
107 "attribute %s redefined with a conflicting definition "
108 "(id %u vendor %u type %d -> id %u vendor %u type %d)",
110 (
unsigned)ATTRID(existing->value), (
unsigned)VENDOR(existing->value), existing->type,
111 (
unsigned)ATTRID(cand->value), (
unsigned)VENDOR(cand->value), cand->type);
130static int dict2_check_value(rc_handle *rh,
const struct radcli_dict_value *cand,
131 char const *pfilename,
int line_no,
132 struct radcli_dict_value **existing_out)
134 struct radcli_dict_value *existing =
135 radcli_dict_value_by_attr(rh, cand->attrname, cand->value);
137 *existing_out = existing;
138 if (existing == NULL)
141 if (strcasecmp(existing->name, cand->name) == 0)
146 "%s: line %d: VALUE %u for attribute %s redefined with a "
147 "conflicting name (%s -> %s)",
148 pfilename, line_no, cand->value, cand->attrname,
149 existing->name, cand->name);
152 "VALUE for attribute %s redefined with a conflicting name "
153 "(%s -> %s)", cand->attrname, existing->name, cand->name);
172static int dict2_check_vendor(rc_handle *rh,
const struct radcli_dict_vendor *cand,
173 char const *pfilename,
int line_no,
174 struct radcli_dict_vendor **existing_out)
176 struct radcli_dict_vendor *existing = radcli_dict_vendor_by_name(rh, cand->name);
178 *existing_out = existing;
179 if (existing == NULL)
182 if (existing->pec == cand->pec)
187 "%s: line %d: VENDOR %s redefined with a conflicting Vendor-Id "
188 "(%u -> %u)", pfilename, line_no, cand->name, existing->pec, cand->pec);
191 "VENDOR %s redefined with a conflicting Vendor-Id (%u -> %u)",
192 cand->name, existing->pec, cand->pec);
212static int dict2_parse(rc_handle *rh, FILE *dictfd,
char const *filename)
214 char namestr[AUTH_ID_LEN];
215 char valstr[AUTH_ID_LEN];
216 char attrstr[AUTH_ID_LEN];
217 char typestr[AUTH_ID_LEN];
218 char optstr[AUTH_ID_LEN];
219 char ifilename[RC_MAX(1024, PATH_MAX)] = {0};
224 struct radcli_dict_attr *attr;
225 struct radcli_dict_value *dval;
226 struct radcli_dict_vendor *dvend;
233 uint32_t gigawords_attrid;
234 unsigned attr_vendorspec = 0;
235 const char *pfilename = filename;
237 if (pfilename == NULL)
239 pfilename =
"memory";
242 while (getline (&buffer, &bufsize, dictfd) != -1)
247 if (*buffer ==
'#' || *buffer ==
'\0' || *buffer ==
'\n' || \
254 cp = strchr(buffer,
'#');
260 tok = strtok_r(buffer,
" \t\r\n", &saveptr);
266 if (strcmp (tok,
"ATTRIBUTE") == 0)
268 char *name_t, *val_t, *type_t, *opt_t;
271 name_t = strtok_r(NULL,
" \t\r\n", &saveptr);
272 val_t = strtok_r(NULL,
" \t\r\n", &saveptr);
273 type_t = strtok_r(NULL,
" \t\r\n", &saveptr);
274 opt_t = strtok_r(NULL,
" \t\r\n", &saveptr);
275 if (name_t == NULL || val_t == NULL || type_t == NULL)
278 "rc_dict_init: invalid attribute on line %d of "
279 "dictionary %s", line_no, pfilename);
289 if (strlen (name_t) > RC_NAME_LENGTH)
292 "rc_dict_init: invalid name length on line %d of "
293 "dictionary %s", line_no, pfilename);
297 strlcpy(namestr, name_t,
sizeof(namestr));
298 strlcpy(valstr, val_t,
sizeof(valstr));
299 strlcpy(typestr, type_t,
sizeof(typestr));
302 strlcpy(optstr, opt_t,
sizeof(optstr));
309 if (!is_unsigned_decimal (valstr))
312 "rc_dict_init: invalid value on line %d of dictionary %s",
316 value = atoi (valstr);
318 if (strcmp (typestr,
"string") == 0)
320 type = PW_TYPE_STRING;
322 else if (strcmp (typestr,
"integer") == 0)
324 type = PW_TYPE_INTEGER;
326 else if (strcmp (typestr,
"uint32") == 0)
331 type = PW_TYPE_INTEGER;
333 else if (strcmp (typestr,
"enum") == 0)
343 type = PW_TYPE_INTEGER;
345 else if (strcmp (typestr,
"ipaddr") == 0)
347 type = PW_TYPE_IPADDR;
349 else if (strcmp (typestr,
"ipv4addr") == 0)
351 type = PW_TYPE_IPADDR;
353 else if (strcmp (typestr,
"ipv6addr") == 0)
355 type = PW_TYPE_IPV6ADDR;
357 else if (strcmp (typestr,
"ipv6prefix") == 0)
359 type = PW_TYPE_IPV6PREFIX;
361 else if (strcmp (typestr,
"date") == 0)
365 else if (strcmp (typestr,
"time") == 0)
374 else if (strcmp (typestr,
"integer64") == 0)
387 else if (strcmp (typestr,
"ipv4prefix") == 0)
397 type = PW_TYPE_MAX + 1;
399 else if (strcmp (typestr,
"text") == 0)
408 type = PW_TYPE_MAX + 2;
410 else if (strcmp (typestr,
"ifid") == 0)
419 type = PW_TYPE_MAX + 3;
424 "rc_dict_init: invalid type on line %d of dictionary %s",
432 gigawords_attrid = 0;
433 if (optstr[0] !=
'\0') {
435 for (cp1 = optstr; cp1 != NULL; cp1 = cp) {
436 cp = strchr(cp1,
',');
442 if (strcmp(cp1,
"has_tag") == 0) {
448 if (strncmp(cp1,
"encrypt=", 8) == 0) {
460 if (strcmp(cp1 + 8,
"User-Password") == 0) {
464 if (strcmp(cp1 + 8,
"Tunnel-Password") == 0) {
469 "rc_dict_init: unsupported encrypt=%s on line %d "
470 "of dictionary %s (only encrypt=User-Password and "
471 "encrypt=Tunnel-Password are implemented)",
472 cp1 + 8, line_no, pfilename);
476 if (strncmp(cp1,
"gigawords=", 10) == 0) {
478 long v = strtol(cp1 + 10, &endp, 10);
492 if (*endp !=
'\0' || v <= 0 || v > 0xff) {
494 "rc_dict_init: invalid gigawords=%s on line %d "
495 "of dictionary %s", cp1 + 10, line_no, pfilename);
498 gigawords_attrid = (uint32_t)v;
502 if (strncmp(cp1,
"vendor=", 7) == 0)
504 dvend = radcli_dict_vendor_by_name(rh, cp1);
507 "rc_dict_init: unknown Vendor-Id %s on line %d of "
508 "dictionary %s", cp1, line_no, pfilename);
515 if ((attr = calloc (1,
sizeof (*attr))) == NULL)
517 rc_log(LOG_CRIT,
"rc_dict_init: out of memory");
520 strlcpy (attr->name, namestr,
sizeof(attr->name));
521 dict2_lc(attr->name_key,
sizeof(attr->name_key), attr->name);
525 attr->value = RADCLI_VENDOR_ATTR_SET(value, dvend->pec);
527 attr->value = RADCLI_VENDOR_ATTR_SET(value, attr_vendorspec);
531 struct radcli_dict_attr *existing;
532 int cmp = dict2_check_attr(rh, attr, pfilename, line_no, &existing);
537 }
else if (cmp > 0) {
544 HASH_ADD(hh_name, rh->dict->attrs_by_name, name_key, strlen(attr->name_key), attr);
545 HASH_ADD(hh_id, rh->dict->attrs_by_id, value,
sizeof(attr->value), attr);
549 if (encrypt_type != 0 || has_tag_flag != 0) {
550 struct radcli_dict_flags *fl = calloc(1,
sizeof(*fl));
553 rc_log(LOG_CRIT,
"rc_dict_init: out of memory");
556 fl->attr_id = attr->value;
557 fl->encrypt_type = encrypt_type;
558 fl->has_tag = has_tag_flag;
559 HASH_ADD(hh, rh->dict->flags_by_attr_id, attr_id,
sizeof(fl->attr_id), fl);
562 if (gigawords_attrid != 0) {
563 struct radcli_dict_gigawords *gw = calloc(1,
sizeof(*gw));
566 rc_log(LOG_CRIT,
"rc_dict_init: out of memory");
569 gw->attr_id = attr->value;
573 gw->gigawords_attrid = RADCLI_VENDOR_ATTR_SET(gigawords_attrid,
574 VENDOR(attr->value));
575 HASH_ADD(hh, rh->dict->gigawords_by_attr_id, attr_id,
sizeof(gw->attr_id), gw);
578 else if (strcmp (tok,
"VALUE") == 0)
580 char *attr_t, *name_t, *val_t;
583 attr_t = strtok_r(NULL,
" \t\r\n", &saveptr);
584 name_t = strtok_r(NULL,
" \t\r\n", &saveptr);
585 val_t = strtok_r(NULL,
" \t\r\n", &saveptr);
586 if (attr_t == NULL || name_t == NULL || val_t == NULL)
589 "rc_dict_init: invalid value entry on line %d of "
590 "dictionary %s", line_no, pfilename);
597 if (strlen (attr_t) > RC_NAME_LENGTH)
600 "rc_dict_init: invalid attribute length on line %d of "
601 "dictionary %s", line_no, pfilename);
605 if (strlen (name_t) > RC_NAME_LENGTH)
608 "rc_dict_init: invalid name length on line %d of "
609 "dictionary %s", line_no, pfilename);
613 strlcpy(attrstr, attr_t,
sizeof(attrstr));
614 strlcpy(namestr, name_t,
sizeof(namestr));
615 strlcpy(valstr, val_t,
sizeof(valstr));
617 if (!is_unsigned_decimal (valstr))
620 "rc_dict_init: invalid value on line %d of dictionary %s",
624 value = atoi (valstr);
627 if ((dval = calloc (1,
sizeof (*dval))) == NULL)
629 rc_log(LOG_CRIT,
"rc_dict_init: out of memory");
632 strlcpy (dval->attrname, attrstr,
sizeof(dval->attrname));
633 strlcpy (dval->name, namestr,
sizeof(dval->name));
634 dict2_lc(dval->name_key,
sizeof(dval->name_key), dval->name);
635 dict2_lc(dval->attr_key.attrname_key,
sizeof(dval->attr_key.attrname_key), dval->attrname);
636 dict2_lc(dval->attr_name_key.attrname_key,
sizeof(dval->attr_name_key.attrname_key), dval->attrname);
637 dict2_lc(dval->attr_name_key.name_key,
sizeof(dval->attr_name_key.name_key), dval->name);
639 dval->attr_key.value = value;
642 struct radcli_dict_value *existing;
643 int cmp = dict2_check_value(rh, dval, pfilename, line_no, &existing);
648 }
else if (cmp > 0) {
651 HASH_ADD(hh_name, rh->dict->values_by_name, name_key, strlen(dval->name_key), dval);
652 HASH_ADD(hh_attr, rh->dict->values_by_attr, attr_key,
sizeof(dval->attr_key), dval);
653 HASH_ADD(hh_attr_name, rh->dict->values_by_attr_name, attr_name_key,
sizeof(dval->attr_name_key), dval);
657 else if ((filename != NULL) &&
658 (strcmp (tok,
"$INCLUDE") == 0))
667 path_t = strtok_r(NULL,
" \t\r\n", &saveptr);
671 "rc_dict_init: invalid include entry on line %d of "
672 "dictionary %s", line_no, pfilename);
675 strlcpy(ifilename, path_t,
sizeof(ifilename));
677 if (path_t[0] !=
'/') {
678 cp = strrchr(filename,
'/');
681 strlcpy(ifilename, filename,
sizeof(ifilename));
682 strlcat(ifilename,
"/",
sizeof(ifilename));
683 strlcat(ifilename, path_t,
sizeof(ifilename));
687 if (radcli2_priv_read_dictionary(rh, ifilename) < 0)
692 else if (strcmp (tok,
"END-VENDOR") == 0)
696 else if (strcmp (tok,
"BEGIN-VENDOR") == 0)
698 struct radcli_dict_vendor *v;
702 name_t = strtok_r(NULL,
" \t\r\n", &saveptr);
706 "rc_dict_init: invalid Vendor-Id on line %d of "
707 "dictionary %s", line_no, pfilename);
711 v = radcli_dict_vendor_by_name(rh, name_t);
714 "rc_dict_init: unknown Vendor %s on line %d of "
715 "dictionary %s", name_t, line_no, pfilename);
719 attr_vendorspec = v->pec;
721 else if (strcmp (tok,
"VENDOR") == 0)
723 char *name_t, *val_t;
726 name_t = strtok_r(NULL,
" \t\r\n", &saveptr);
727 val_t = strtok_r(NULL,
" \t\r\n", &saveptr);
728 if (name_t == NULL || val_t == NULL)
731 "rc_dict_init: invalid Vendor-Id on line %d of "
732 "dictionary %s", line_no, pfilename);
737 if (strlen (name_t) > RC_NAME_LENGTH)
740 "rc_dict_init: invalid attribute length on line %d of "
741 "dictionary %s", line_no, pfilename);
745 strlcpy(attrstr, name_t,
sizeof(attrstr));
746 strlcpy(valstr, val_t,
sizeof(valstr));
748 if (!is_unsigned_decimal (valstr))
751 "rc_dict_init: invalid Vendor-Id on line %d of "
752 "dictionary %s", line_no, pfilename);
755 value = atoi (valstr);
758 dvend = calloc(1,
sizeof(*dvend));
761 rc_log(LOG_CRIT,
"rc_dict_init: out of memory");
764 strlcpy (dvend->name, attrstr,
sizeof(dvend->name));
765 dict2_lc(dvend->name_key,
sizeof(dvend->name_key), dvend->name);
769 struct radcli_dict_vendor *existing;
770 int cmp = dict2_check_vendor(rh, dvend, pfilename, line_no, &existing);
775 }
else if (cmp > 0) {
778 HASH_ADD(hh_name, rh->dict->vendors_by_name, name_key, strlen(dvend->name_key), dvend);
779 HASH_ADD(hh_pec, rh->dict->vendors_by_pec, pec,
sizeof(dvend->pec), dvend);
798int radcli2_priv_read_dictionary (rc_handle *rh,
char const *filename)
803 if (rh->first_dict_read != NULL && strcmp(filename, rh->first_dict_read) == 0)
806 if (dict2_ensure(rh) < 0)
809 if ((dictfd = fopen (filename,
"r")) == NULL)
811 rc_log(LOG_ERR,
"radcli2_priv_read_dictionary couldn't open dictionary %s: %s",
812 filename, strerror(errno));
816 ret_val = dict2_parse(rh, dictfd, filename);
820 if (rh->first_dict_read == NULL)
821 rh->first_dict_read = strdup(filename);
833int radcli2_priv_read_dictionary_from_buffer (rc_handle *rh,
char const *buf,
size_t size)
838 if (dict2_ensure(rh) < 0)
841 if ((dictfd = fmemopen ((
void *)buf, size,
"r")) == NULL)
843 rc_log(LOG_ERR,
"radcli2_priv_read_dictionary_from_buffer failed to read "
844 "input buffer %s", strerror(errno));
848 ret_val = dict2_parse(rh, dictfd, NULL);
869struct radcli_dict_attr *radcli_dict_attr_add(rc_handle *rh,
const char *name,
870 uint32_t value,
int type, uint32_t vendorspec)
872 struct radcli_dict_attr *attr;
874 if (strlen(name) > RC_NAME_LENGTH)
876 rc_log(LOG_ERR,
"rc_dict_addattr: invalid attribute length");
880 if (type < 0 || type >= PW_TYPE_MAX)
882 rc_log(LOG_ERR,
"rc_dict_addattr: invalid attribute type");
886 if (dict2_ensure(rh) < 0)
889 if ((attr = calloc(1,
sizeof(*attr))) == NULL)
891 rc_log(LOG_CRIT,
"rc_dict_addattr: out of memory");
895 strlcpy(attr->name, name,
sizeof(attr->name));
896 dict2_lc(attr->name_key,
sizeof(attr->name_key), attr->name);
897 attr->value = RADCLI_VENDOR_ATTR_SET(value, vendorspec);
901 struct radcli_dict_attr *existing;
902 int cmp = dict2_check_attr(rh, attr, NULL, 0, &existing);
907 }
else if (cmp > 0) {
913 HASH_ADD(hh_name, rh->dict->attrs_by_name, name_key, strlen(attr->name_key), attr);
914 HASH_ADD(hh_id, rh->dict->attrs_by_id, value,
sizeof(attr->value), attr);
931struct radcli_dict_value *radcli_dict_value_add(rc_handle *rh,
const char *attrname,
932 const char *name, uint32_t value)
934 struct radcli_dict_value *dval;
936 if (strlen(attrname) > RC_NAME_LENGTH)
938 rc_log(LOG_ERR,
"rc_dict_addval: invalid attribute length");
942 if (strlen(name) > RC_NAME_LENGTH)
944 rc_log(LOG_ERR,
"rc_dict_addval: invalid name length");
948 if (dict2_ensure(rh) < 0)
951 if ((dval = calloc(1,
sizeof(*dval))) == NULL)
953 rc_log(LOG_CRIT,
"rc_dict_addval: out of memory");
956 strlcpy(dval->attrname, attrname,
sizeof(dval->attrname));
957 strlcpy(dval->name, name,
sizeof(dval->name));
958 dict2_lc(dval->name_key,
sizeof(dval->name_key), dval->name);
959 dict2_lc(dval->attr_key.attrname_key,
sizeof(dval->attr_key.attrname_key), dval->attrname);
960 dict2_lc(dval->attr_name_key.attrname_key,
sizeof(dval->attr_name_key.attrname_key), dval->attrname);
961 dict2_lc(dval->attr_name_key.name_key,
sizeof(dval->attr_name_key.name_key), dval->name);
963 dval->attr_key.value = value;
966 struct radcli_dict_value *existing;
967 int cmp = dict2_check_value(rh, dval, NULL, 0, &existing);
972 }
else if (cmp > 0) {
978 HASH_ADD(hh_name, rh->dict->values_by_name, name_key, strlen(dval->name_key), dval);
979 HASH_ADD(hh_attr, rh->dict->values_by_attr, attr_key,
sizeof(dval->attr_key), dval);
980 HASH_ADD(hh_attr_name, rh->dict->values_by_attr_name, attr_name_key,
sizeof(dval->attr_name_key), dval);
995struct radcli_dict_vendor *radcli_dict_vendor_add(rc_handle *rh,
const char *name,
998 struct radcli_dict_vendor *dvend;
1000 if (strlen(name) > RC_NAME_LENGTH)
1002 rc_log(LOG_ERR,
"rc_dict_addvend: invalid vendor name length");
1006 if (dict2_ensure(rh) < 0)
1009 if ((dvend = calloc(1,
sizeof(*dvend))) == NULL)
1011 rc_log(LOG_CRIT,
"rc_dict_addvend: out of memory");
1014 strlcpy(dvend->name, name,
sizeof(dvend->name));
1015 dict2_lc(dvend->name_key,
sizeof(dvend->name_key), dvend->name);
1016 dvend->pec = vendorspec;
1019 struct radcli_dict_vendor *existing;
1020 int cmp = dict2_check_vendor(rh, dvend, NULL, 0, &existing);
1025 }
else if (cmp > 0) {
1031 HASH_ADD(hh_name, rh->dict->vendors_by_name, name_key, strlen(dvend->name_key), dvend);
1032 HASH_ADD(hh_pec, rh->dict->vendors_by_pec, pec,
sizeof(dvend->pec), dvend);