📄 conffile.c
字号:
/* * Not doing continuations: check for edge * conditions. */ if (cbuf == buf) { if (eof) break; ptr = buf; while (*ptr && isspace((int) *ptr)) ptr++; if (!*ptr || (*ptr == '#')) continue; } else if (eof || (len == 0)) { radlog(L_ERR, "%s[%d]: Continuation at EOF is illegal", filename, *lineno); return -1; } /* * See if there's a continuation. */ while ((len > 0) && ((cbuf[len - 1] == '\n') || (cbuf[len - 1] == '\r'))) { len--; cbuf[len] = '\0'; } if ((len > 0) && (cbuf[len - 1] == '\\')) { cbuf[len - 1] = '\0'; cbuf += len - 1; continue; } ptr = cbuf = buf; t1 = gettoken(&ptr, buf1, sizeof(buf1)); /* * The caller eats "name1 name2 {", and calls us * for the data inside of the section. So if we * receive a closing brace, then it must mean the * end of the section. */ if (t1 == T_RCBRACE) { if (this == current) { radlog(L_ERR, "%s[%d]: Too many closing braces", filename, *lineno); return -1; } this = this->item.parent; continue; } /* * Allow for $INCLUDE files * * This *SHOULD* work for any level include. * I really really really hate this file. -cparker */ if ((strcasecmp(buf1, "$INCLUDE") == 0) || (strcasecmp(buf1, "$-INCLUDE") == 0)) { int relative = 1; t2 = getword(&ptr, buf2, sizeof(buf2)); if (buf2[0] == '$') relative = 0; value = cf_expand_variables(filename, lineno, this, buf, buf2); if (!value) return -1; if (!FR_DIR_IS_RELATIVE(value)) relative = 0; if (relative) { value = cf_local_file(current, value, buf3, sizeof(buf3)); if (!value) { radlog(L_ERR, "%s[%d]: Directories too deep.", filename, *lineno); return -1; } }#ifdef HAVE_DIRENT_H /* * $INCLUDE foo/ * * Include ALL non-"dot" files in the directory. * careful! */ if (value[strlen(value) - 1] == '/') { DIR *dir; struct dirent *dp; struct stat stat_buf; DEBUG2("including files in directory %s", value ); dir = opendir(value); if (!dir) { radlog(L_ERR, "%s[%d]: Error reading directory %s: %s", filename, *lineno, value, strerror(errno)); return -1; } /* * Read the directory, ignoring "." files. */ while ((dp = readdir(dir)) != NULL) { const char *p; if (dp->d_name[0] == '.') continue; /* * Check for valid characters */ for (p = dp->d_name; *p != '\0'; p++) { if (isalpha((int)*p) || isdigit((int)*p) || (*p == '-') || (*p == '_') || (*p == '.')) continue; break; } if (*p != '\0') continue; snprintf(buf2, sizeof(buf2), "%s%s", value, dp->d_name); if ((stat(buf2, &stat_buf) != 0) || S_ISDIR(stat_buf.st_mode)) continue; /* * Read the file into the current * configuration sectoin. */ if (cf_file_include(buf2, this) < 0) { closedir(dir); return -1; } } closedir(dir); } else#endif { /* it was a normal file */ if (buf1[1] == '-') { struct stat statbuf; if (stat(value, &statbuf) < 0) { DEBUG("WARNING: Not including file %s: %s", value, strerror(errno)); continue; } } if (cf_file_include(value, this) < 0) { return -1; } } continue; } /* we were in an include */ if (strcasecmp(buf1, "$template") == 0) { CONF_ITEM *ci; CONF_SECTION *parentcs; t2 = getword(&ptr, buf2, sizeof(buf2)); parentcs = cf_top_section(current); ci = cf_reference_item(parentcs, this, buf2); if (!ci || (ci->type != CONF_ITEM_SECTION)) { radlog(L_ERR, "%s[%d]: Reference \"%s\" not found", filename, *lineno, buf2); return -1; } if (this->template) { radlog(L_ERR, "%s[%d]: Section already has a template", filename, *lineno); return -1; } this->template = cf_itemtosection(ci); continue; } /* * Ensure that the user can't add CONF_PAIRs * with 'internal' names; */ if (buf1[0] == '_') { radlog(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"", filename, *lineno, buf1); return -1; } /* * Grab the next token. */ t2 = gettoken(&ptr, buf2, sizeof(buf2)); switch (t2) { case T_EOL: case T_HASH: t2 = T_OP_EQ; value = NULL; goto do_set; case T_OP_ADD: case T_OP_CMP_EQ: case T_OP_SUB: case T_OP_LE: case T_OP_GE: if (!this || (strcmp(this->name1, "update") != 0)) { radlog(L_ERR, "%s[%d]: Invalid operator in assignment", filename, *lineno); return -1; } case T_OP_EQ: case T_OP_SET: do_set: t3 = getstring(&ptr, buf3, sizeof(buf3)); /* * Handle variable substitution via ${foo} */ if ((t3 == T_BARE_WORD) || (t3 == T_DOUBLE_QUOTED_STRING)) { value = cf_expand_variables(filename, lineno, this, buf, buf3); if (!value) return -1; } else if ((t3 == T_EOL) || (t3 == T_HASH)) { value = NULL; } else { value = buf3; } /* * Add this CONF_PAIR to our CONF_SECTION */ cpn = cf_pair_alloc(buf1, value, t2, t3, this); cpn->item.filename = filename; cpn->item.lineno = *lineno; cf_item_add(this, cf_pairtoitem(cpn)); continue; /* * This horrible code is here to support * if/then/else failover in the * authorize, etc. sections. It makes no * sense anywhere else. */ case T_LBRACE: if ((strcmp(buf1, "if") == 0) || (strcmp(buf1, "elsif") == 0)) { const char *end = ptr; CONF_SECTION *server; if (!condition_looks_ok(&end)) { radlog(L_ERR, "%s[%d]: Parse error in condition at: %s", filename, *lineno, ptr); return -1; } if ((size_t) (end - ptr) >= (sizeof(buf2) - 1)) { radlog(L_ERR, "%s[%d]: Statement too complicated after \"%s\"", filename, *lineno, buf1); return -1; } /* * More sanity checking. This is * getting to be a horrible hack. */ server = this; while (server) { if (strcmp(server->name1, "server") == 0) break; server = server->item.parent; } if (0 && !server) { radlog(L_ERR, "%s[%d]: Processing directives such as \"%s\" cannot be used here.", filename, *lineno, buf1); return -1; } buf2[0] = '('; memcpy(buf2 + 1, ptr, end - ptr); buf2[end - ptr + 1] = '\0'; ptr = end + 1; t2 = T_BARE_WORD; goto section_alloc; } else { radlog(L_ERR, "%s[%d]: Parse error after \"%s\"", filename, *lineno, buf1); return -1; } /* FALL-THROUGH */ /* * No '=', must be a section or sub-section. */ case T_BARE_WORD: case T_DOUBLE_QUOTED_STRING: case T_SINGLE_QUOTED_STRING: t3 = gettoken(&ptr, buf3, sizeof(buf3)); if (t3 != T_LCBRACE) { radlog(L_ERR, "%s[%d]: Expecting section start brace '{' after \"%s %s\"", filename, *lineno, buf1, buf2); return -1; } case T_LCBRACE: section_alloc: css = cf_section_alloc(buf1, t2 == T_LCBRACE ? NULL : buf2, this); if (!css) { radlog(L_ERR, "%s[%d]: Failed allocating memory for section", filename, *lineno); return -1; } cf_item_add(this, cf_sectiontoitem(css)); css->item.filename = filename; css->item.lineno = *lineno; /* * The current section is now the child section. */ this = css; continue; default: radlog(L_ERR, "%s[%d]: Parse error after \"%s\"", filename, *lineno, buf1); return -1; } } /* * See if EOF was unexpected .. */ if (feof(fp) && (this != current)) { radlog(L_ERR, "%s[%d]: EOF reached without closing brace for section %s starting at line %d", filename, *lineno, cf_section_name1(this), cf_section_lineno(this)); return -1; } return 0;}/* * Include one config file in another. */int cf_file_include(const char *filename, CONF_SECTION *cs){ FILE *fp; int lineno = 0; struct stat statbuf; time_t *mtime; CONF_DATA *cd; DEBUG2( "including configuration file %s", filename); if (stat(filename, &statbuf) == 0) {#ifdef S_IWOTH if ((statbuf.st_mode & S_IWOTH) != 0) { radlog(L_ERR|L_CONS, "Configuration file %s is globally writable. Refusing to start due to insecure configuration.", filename); return -1; }#endif#ifdef S_IROTH if (0 && (statbuf.st_mode & S_IROTH) != 0) { radlog(L_ERR|L_CONS, "Configuration file %s is globally readable. Refusing to start due to insecure configuration.", filename); return -1; }#endif } fp = fopen(filename, "r"); if (!fp) { radlog(L_ERR|L_CONS, "Unable to open file \"%s\": %s", filename, strerror(errno)); return -1; } /* * Add the filename to the section */ mtime = rad_malloc(sizeof(*mtime)); *mtime = statbuf.st_mtime; if (cf_data_add_internal(cs, filename, mtime, free, PW_TYPE_FILENAME) < 0) { fclose(fp); radlog(L_ERR|L_CONS, "Internal error open file \"%s\"", filename); return -1; } cd = cf_data_find_internal(cs, filename, PW_TYPE_FILENAME); if (!cd) { fclose(fp); radlog(L_ERR|L_CONS, "Internal error open file \"%s\"", filename); return -1; } if (!cs->item.filename) cs->item.filename = filename; /* * Read the section. It's OK to have EOF without a * matching close brace. */ if (cf_section_read(cd->name, &lineno, fp, cs) < 0) { fclose(fp); return -1; } fclose(fp); return 0;}/* * Bootstrap a config file. */CONF_SECTION *cf_file_read(const char *filename){ char *p; CONF_PAIR *cp; CONF_SECTION *cs; cs = cf_section_alloc("main", NULL, NULL); if (!cs) return NULL; cp = cf_pair_alloc("confdir", filename, T_OP_SET, T_BARE_WORD, cs); if (!cp) return NULL; p = strrchr(cp->value, FR_DIR_SEP); if (p) *p = '\0'; cp->item.filename = "internal"; cp->item.lineno = 0; cf_item_add(cs, cf_pairtoitem(cp)); if (cf_file_include(filename, cs) < 0) { cf_section_free(&cs); return NULL; } return cs;}/* * Return a CONF_PAIR within a CONF_SECTION. */CONF_PAIR *cf_pair_find(const CONF_SECTION *cs, const char *name){ CONF_ITEM *ci; CONF_PAIR *cp = NULL; if (!cs) return NULL; /* * Find the name in the tree, for speed. */ if (name) { CONF_PAIR mycp; mycp.attr = name; cp = rbtree_finddata(cs->pair_tree, &mycp); } else { /* * Else find the first one that matches */ for (ci = cs->children; ci; ci = ci->next) { if (ci->type == CONF_ITEM_PAIR) { return cf_itemtopair(ci); } } } if (cp || !cs->template) return cp; return cf_pair_find(cs->template, name);}/* * Return the attr of a CONF_PAIR */const char *cf_pair_attr(CONF_PAIR *pair){ return (pair ? pair->attr : NULL);}/* * Return the value of a CONF_PAIR */const char *cf_pair_value(CONF_PAIR *pair){ return (pair ? pair->value : NULL);}/* * Copied here for error reporting. */extern void librad_log(const char *, ...);/* * Turn a CONF_PAIR into a VALUE_PAIR * For now, ignore the "value_type" field... */VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair){ VALUE_PAIR *vp; if (!pair) { librad_log("Internal error"); return NULL; } if (!pair->value) { librad_log("No value given for attribute %s", pair->attr); return NULL; } /* * pairmake handles tags. pairalloc() doesn't. */ vp = pairmake(pair->attr, NULL, pair->operator); if (!vp) { return NULL; } if (pair->value_type == T_BARE_WORD) { if ((vp->type == PW_TYPE_STRING) && (pair->value[0] == '0') && (pair->value[1] == 'x')) { vp->type = PW_TYPE_OCTETS; } if (!pairparsevalue(vp, pair->value)) { pairfree(&vp); return NULL; } vp->flags.do_xlat = 0; } else if (pair->value_type == T_SINGLE_QUOTED_STRING) { if (!pairparsevalue(vp, pair->value)) { pairfree(&vp); return NULL; } vp->flags.do_xlat = 0; } else { vp->flags.do_xlat = 1; } return vp;}/* * Return the first label of a CONF_SECTION */const char *cf_section_name1(const CONF_SECTION *cs){ return (cs ? cs->name1 : NULL);}/* * Return the second label of a CONF_SECTION */const char *cf_section_name2(const CONF_SECTION *cs){ return (cs ? cs->name2 : NULL);}/* * Find a value in a CONF_SECTION */const char *cf_section_value_find(const CONF_SECTION *cs, const char *attr){ CONF_PAIR *cp; cp = cf_pair_find(cs, attr); return (cp ? cp->value : NULL);}/* * Return the next pair after a CONF_PAIR * with a certain name (char *attr) If the requested * attr is NULL, any attr matches. */CONF_PAIR *cf_pair_find_next(const CONF_SECTION *cs, CONF_PAIR *pair, const char *attr){ CONF_ITEM *ci; /* * If pair is NULL this must be a first time run * Find the pair with correct name */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -