📄 dict.c
字号:
(block_vendor != vendor)) { librad_log("dict_init: %s[%d]: mismatched vendor %s within BEGIN-VENDOR/END-VENDOR block", fn, line, argv[3]); return -1; } } s = strtok(NULL, ","); } } if (block_vendor) vendor = block_vendor; /* * Special checks for tags, they make our life much more * difficult. */ if (flags.has_tag) { /* * Only string, octets, and integer can be tagged. */ switch (type) { case PW_TYPE_STRING: case PW_TYPE_INTEGER: break; default: librad_log("dict_init: %s[%d]: Attributes of type %s cannot be tagged.", fn, line, lrad_int2str(type_table, type, "?Unknown?")); return -1; } } /* * Add it in. */ if (dict_addattr(argv[0], vendor, type, value, flags) < 0) { librad_log("dict_init: %s[%d]: %s", fn, line, librad_errstr); return -1; } return 0;}/* * Process the VALUE command */static int process_value(const char* fn, const int line, char **argv, int argc){ int value; if (argc != 3) { librad_log("dict_init: %s[%d]: invalid VALUE line", fn, line); return -1; } /* * For Compatibility, skip "Server-Config" */ if (strcasecmp(argv[0], "Server-Config") == 0) return 0; /* * Validate all entries */ if (!isdigit((int) argv[2][0])) { librad_log("dict_init: %s[%d]: invalid value", fn, line); return -1; } sscanf(argv[2], "%i", &value); if (dict_addvalue(argv[1], argv[0], value) < 0) { librad_log("dict_init: %s[%d]: %s", fn, line, librad_errstr); return -1; } return 0;}/* * Process the VENDOR command */static int process_vendor(const char* fn, const int line, char **argv, int argc){ int value; const char *format = NULL; if ((argc < 2) || (argc > 3)) { librad_log( "dict_init: %s[%d] invalid VENDOR entry", fn, line); return -1; } /* * Validate all entries */ if (!isdigit((int) argv[1][0])) { librad_log("dict_init: %s[%d]: invalid value", fn, line); return -1; } value = atoi(argv[1]); /* Create a new VENDOR entry for the list */ if (dict_addvendor(argv[0], value) < 0) { librad_log("dict_init: %s[%d]: %s", fn, line, librad_errstr); return -1; } /* * Look for a format statement */ if (argc == 3) { format = argv[2]; } else if (value == VENDORPEC_USR) { /* catch dictionary screw-ups */ format = "format=4,0"; } else if (value == VENDORPEC_LUCENT) { format = "format=2,1"; } else if (value == VENDORPEC_STARENT) { format = "format=2,2"; } /* else no fixups to do */ if (format) { int type, length; const char *p; DICT_VENDOR *dv; if (strncasecmp(format, "format=", 7) != 0) { librad_log("dict_init: %s[%d]: Invalid format for VENDOR. Expected \"format=\", got \"%s\"", fn, line, format); return -1; } p = format + 7; if ((strlen(p) != 3) || !isdigit((int) p[0]) || (p[1] != ',') || !isdigit((int) p[2])) { librad_log("dict_init: %s[%d]: Invalid format for VENDOR. Expected text like \"1,1\", got \"%s\"", fn, line, p); return -1; } type = (int) (p[0] - '0'); length = (int) (p[2] - '0'); dv = dict_vendorbyvalue(value); if (!dv) { librad_log("dict_init: %s[%d]: Failed adding format for VENDOR", fn, line); return -1; } if ((type != 1) && (type != 2) && (type != 4)) { librad_log("dict_init: %s[%d]: invalid type value %d for VENDOR", fn, line, type); return -1; } if ((length != 0) && (length != 1) && (length != 2)) { librad_log("dict_init: %s[%d]: invalid length value %d for VENDOR", fn, line, length); return -1; } dv->type = type; dv->length = length; } return 0;}/* * String split routine. Splits an input string IN PLACE * into pieces, based on spaces. */static int str2argv(char *str, char **argv, int max_argc){ int argc = 0; while (*str) { if (argc >= max_argc) return argc; /* * Chop out comments early. */ if (*str == '#') { *str = '\0'; break; } while ((*str == ' ') || (*str == '\t') || (*str == '\r') || (*str == '\n')) *(str++) = '\0'; if (!*str) return argc; argv[argc] = str; argc++; while (*str && (*str != ' ') && (*str != '\t') && (*str != '\r') && (*str != '\n')) str++; } return argc;}#define MAX_ARGV (16)/* * Initialize the dictionary. */static int my_dict_init(const char *dir, const char *fn, const char *src_file, int src_line){ FILE *fp; char dirtmp[256]; char buf[256]; char *p; int line = 0; int vendor; int block_vendor; struct stat statbuf; char *argv[MAX_ARGV]; int argc; if (!dir) { librad_log("dict_init: No directory specified"); return -1; } if ((strlen(fn) >= sizeof(dirtmp) / 2) || (strlen(dir) >= sizeof(dirtmp) / 2)) { librad_log("dict_init: filename name too long"); return -1; } /* * First see if fn is relative to dir. If so, create * new filename. If not, remember the absolute dir. */ if ((p = strrchr(fn, '/')) != NULL) { strcpy(dirtmp, fn); dirtmp[p - fn] = 0; dir = dirtmp; } else if (dir[0] && strcmp(dir, ".") != 0) { snprintf(dirtmp, sizeof(dirtmp), "%s/%s", dir, fn); fn = dirtmp; } if ((fp = fopen(fn, "r")) == NULL) { if (!src_file) { librad_log("dict_init: Couldn't open dictionary \"%s\": %s", fn, strerror(errno)); } else { librad_log("dict_init: %s[%d]: Couldn't open dictionary \"%s\": %s", src_file, src_line, fn, strerror(errno)); } return -1; } stat(fn, &statbuf); /* fopen() guarantees this will succeed */ if (!S_ISREG(statbuf.st_mode)) { fclose(fp); librad_log("dict_init: Dictionary \"%s\" is not a regular file", fn); return -1; } /* * Globally writable dictionaries means that users can control * the server configuration with little difficulty. */ if ((statbuf.st_mode & S_IWOTH) != 0) { fclose(fp); librad_log("dict_init: Dictionary \"%s\" is globally writable. Refusing to start due to insecure configuration.", fn); return -1; } dict_stat_add(fn, &statbuf); /* * Seed the random pool with data. */ lrad_rand_seed(&statbuf, sizeof(statbuf)); block_vendor = 0; while (fgets(buf, sizeof(buf), fp) != NULL) { line++; if (buf[0] == '#' || buf[0] == 0 || buf[0] == '\n' || buf[0] == '\r') continue; /* * Comment characters should NOT be appearing anywhere but * as start of a comment; */ p = strchr(buf, '#'); if (p) *p = '\0'; argc = str2argv(buf, argv, MAX_ARGV); if (argc == 0) continue; if (argc == 1) { librad_log( "dict_init: %s[%d] invalid entry", fn, line); fclose(fp); return -1; } if (0) { int i; fprintf(stderr, "ARGC = %d\n",argc); for (i = 0; i < argc; i++) { fprintf(stderr, "\t%s\n", argv[i]); } } /* * See if we need to import another dictionary. */ if (strcasecmp(argv[0], "$INCLUDE") == 0) { if (my_dict_init(dir, argv[1], fn, line) < 0) { fclose(fp); return -1; } continue; } /* $INCLUDE */ /* * Perhaps this is an attribute. */ if (strcasecmp(argv[0], "ATTRIBUTE") == 0) { if (process_attribute(fn, line, block_vendor, argv + 1, argc - 1) == -1) { fclose(fp); return -1; } continue; } /* * Process VALUE lines. */ if (strcasecmp(argv[0], "VALUE") == 0) { if (process_value(fn, line, argv + 1, argc - 1) == -1) { fclose(fp); return -1; } continue; } /* * Process VENDOR lines. */ if (strcasecmp(argv[0], "VENDOR") == 0) { if (process_vendor(fn, line, argv + 1, argc - 1) == -1) { fclose(fp); return -1; } continue; } if (strcasecmp(argv[0], "BEGIN-VENDOR") == 0) { if (argc != 2) { librad_log( "dict_init: %s[%d] invalid BEGIN-VENDOR entry", fn, line); fclose(fp); return -1; } vendor = dict_vendorbyname(argv[1]); if (!vendor) { librad_log( "dict_init: %s[%d]: unknown vendor %s", fn, line, argv[1]); fclose(fp); return -1; } block_vendor = vendor; continue; } /* BEGIN-VENDOR */ if (strcasecmp(argv[0], "END-VENDOR") == 0) { if (argc != 2) { librad_log( "dict_init: %s[%d] invalid END-VENDOR entry", fn, line); fclose(fp); return -1; } vendor = dict_vendorbyname(argv[1]); if (!vendor) { librad_log( "dict_init: %s[%d]: unknown vendor %s", fn, line, argv[1]); fclose(fp); return -1; } if (vendor != block_vendor) { librad_log( "dict_init: %s[%d]: END-VENDOR %s does not match any previous BEGIN-VENDOR", fn, line, argv[1]); fclose(fp); return -1; } block_vendor = 0; continue; } /* END-VENDOR */ /* * Any other string: We don't recognize it. */ librad_log( "dict_init: %s[%d] invalid keyword \"%s\"", fn, line, argv[0]); fclose(fp); return -1; } fclose(fp); return 0;}/* * Empty callback for hash table initialization. */static int null_callback(void *ctx, void *data){ ctx = ctx; /* -Wunused */ data = data; /* -Wunused */ return 0;}/* * Initialize the directory, then fix the attr member of * all attributes. */int dict_init(const char *dir, const char *fn){ if (!dir) return -1; /* * Check if we need to change anything. If not, don't do * anything. */ if (dict_stat_check(dir, fn)) { return 0; } /* * Free the dictionaries, and the stat cache. */ dict_free(); stat_root_dir = strdup(dir); stat_root_file = strdup(fn); /* * Create the table of vendor by name. There MAY NOT * be multiple vendors of the same name. * * Each vendor is malloc'd, so the free function is free. */ vendors_byname = lrad_hash_table_create(dict_vendor_name_hash, dict_vendor_name_cmp, free); if (!vendors_byname) { return -1; } /* * Create the table of vendors by value. There MAY * be vendors of the same value. If there are, we * pick the latest one. */ vendors_byvalue = lrad_hash_table_create(dict_vendor_value_hash, dict_vendor_value_cmp, NULL); if (!vendors_byvalue) { return -1; } /* * Create the table of attributes by name. There MAY NOT * be multiple attributes of the same name. * * Each attribute is malloc'd, so the free function is free. */ attributes_byname = lrad_hash_table_create(dict_attr_name_hash, dict_attr_name_cmp, free); if (!attributes_byname) { return -1; } /* * Create the table of attributes by value. There MAY * be attributes of the same value. If there are, we * pick the latest one. */ attributes_byvalue = lrad_hash_table_create(dict_attr_value_hash, dict_attr_value_cmp, NULL); if (!attributes_byvalue) { return -1; } values_byname = lrad_hash_table_create(dict_value_name_hash, dict_value_name_cmp, free); if (!values_byname) { return -1; } values_byvalue = lrad_hash_table_create(dict_value_value_hash, dict_value_value_cmp, NULL); if (!values_byvalue) { return -1; } value_fixup = NULL; /* just to be safe. */ if (my_dict_init(dir, fn, NULL, 0) < 0) return -1; if (value_fixup) { DICT_ATTR *a; value_fixup_t *this, *next; for (this = value_fixup; this != NULL; this = next) { next = this->next; a = dict_attrbyname(this->attrstr); if (!a) { librad_log( "dict_init: No ATTRIBUTE \"%s\" defined for VALUE \"%s\"", this->attrstr, this->dval->name); return -1; /* leak, but they should die... */ } this->dval->attr = a->attr; /* * Add the value into the dictionary. */ if (!lrad_hash_table_replace(values_byname, this->dval)) { librad_log("dict_addvalue: Duplicate value name %s for attribute %s", this->dval->name, a->name); return -1; } /* * Allow them to use the old name, but * prefer the new name when printing * values. */ if (!lrad_hash_table_finddata(values_byvalue, this->dval)) { lrad_hash_table_replace(values_byvalue, this->dval); } free(this); /* * Just so we don't lose track of things. */ value_fixup = next; } } /* * Walk over all of the hash tables to ensure they're * initialized. We do this because the threads may perform * lookups, and we don't want multi-threaded re-ordering * of the table entries. That would be bad. */ lrad_hash_table_walk(vendors_byname, null_callback, NULL); lrad_hash_table_walk(vendors_byvalue, null_callback, NULL); lrad_hash_table_walk(attributes_byname, null_callback, NULL); lrad_hash_table_walk(attributes_byvalue, null_callback, NULL); lrad_hash_table_walk(values_byvalue, null_callback, NULL); lrad_hash_table_walk(values_byname, null_callback, NULL); return 0;}/* * Get an attribute by its numerical value. */DICT_ATTR *dict_attrbyvalue(int attr){ DICT_ATTR dattr; dattr.attr = attr; return lrad_hash_table_finddata(attributes_byvalue, &dattr);}/* * Get an attribute by its name. */DICT_ATTR *dict_attrbyname(const char *name){ DICT_ATTR dattr; if (!name) return NULL; strNcpy(dattr.name, name, sizeof(dattr.name)); return lrad_hash_table_finddata(attributes_byname, &dattr);}/* * Associate a value with an attribute and return it. */DICT_VALUE *dict_valbyattr(int attr, int value){ DICT_VALUE dval; dval.attr = attr; dval.value = value; return lrad_hash_table_finddata(values_byvalue, &dval);}/* * Get a value by its name, keyed off of an attribute. */DICT_VALUE *dict_valbyname(int attr, const char *name){ DICT_VALUE *dv; uint32_t buffer[(sizeof(*dv) + DICT_VALUE_MAX_NAME_LEN + 3)/4]; if (!name) return NULL; dv = (DICT_VALUE *) buffer; dv->attr = attr; strNcpy(dv->name, name, DICT_VALUE_MAX_NAME_LEN); return lrad_hash_table_finddata(values_byname, dv);}/* * Get the vendor PEC based on the vendor name * * This is efficient only for small numbers of vendors. */int dict_vendorbyname(const char *name){ DICT_VENDOR *dv; uint32_t buffer[(sizeof(*dv) + DICT_VENDOR_MAX_NAME_LEN + 3)/4]; if (!name) return 0; dv = (DICT_VENDOR *) buffer; strNcpy(dv->name, name, DICT_VENDOR_MAX_NAME_LEN); dv = lrad_hash_table_finddata(vendors_byname, dv); if (!dv) return 0; return dv->vendorpec;}/* * Return the vendor struct based on the PEC. */DICT_VENDOR *dict_vendorbyvalue(int vendorpec){ DICT_VENDOR dv; dv.vendorpec = vendorpec; return lrad_hash_table_finddata(vendors_byvalue, &dv);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -