X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fconffile.c;h=ee47afb7928a501d8c9cf77272775c56cf91e5b2;hb=671bde96d7e9e68b8dbf871db4d9ded33964a4d4;hp=016d80be03f2be7c76234845d84b2cf42e104a90;hpb=4d5f3e99704ed9296882944fe90eda6ed20732aa;p=freeradius.git diff --git a/src/main/conffile.c b/src/main/conffile.c index 016d80b..ee47afb 100644 --- a/src/main/conffile.c +++ b/src/main/conffile.c @@ -447,6 +447,42 @@ static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2, return cs; } +/* + * Replace pair in a given section with a new pair, + * of the given value. + */ +int cf_pair_replace(CONF_SECTION *cs, CONF_PAIR *cp, const char *value) +{ + CONF_PAIR *newp; + CONF_ITEM *ci, *cn, **last; + + newp = cf_pair_alloc(cp->attr, value, cp->operator, cp->value_type, + cs); + if (!newp) return -1; + + ci = cf_pairtoitem(cp); + cn = cf_pairtoitem(newp); + + /* + * Find the old one from the linked list, and replace it + * with the new one. + */ + for (last = &cs->children; (*last) != NULL; last = &(*last)->next) { + if (*last == ci) { + cn->next = (*last)->next; + *last = cn; + ci->next = NULL; + break; + } + } + + rbtree_deletebydata(cs->pair_tree, ci); + + rbtree_insert(cs->pair_tree, cn); + + return 0; +} + /* * Add an item to a configuration section. @@ -481,11 +517,13 @@ static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci) if (!cs->section_tree) { cs->section_tree = rbtree_create(section_cmp, NULL, 0); - /* ignore any errors */ + if (!cs->section_tree) { + radlog(L_ERR, "Out of memory"); + _exit(1); + } } - if (cs->section_tree) { - rbtree_insert(cs->section_tree, cs_new); } + rbtree_insert(cs->section_tree, cs_new); /* * Two names: find the named instance. @@ -564,6 +602,8 @@ CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs, * "foo.bar.baz" means "from the root" */ } else if (strchr(p, '.') != NULL) { + if (!parentcs) goto no_such_item; + cs = parentcs; } @@ -634,7 +674,7 @@ CONF_ITEM *cf_reference_item(const CONF_SECTION *parentcs, /* * "foo" is "in the current section, OR in main". */ - if ((p == name) && (cs != parentcs)) { + if ((p == name) && (parentcs != NULL) && (cs != parentcs)) { cs = parentcs; goto retry; } @@ -728,6 +768,11 @@ static const char *cf_expand_variables(const char *cf, int *lineno, * Substitute the value of the variable. */ cp = cf_itemtopair(ci); + if (!cp->value) { + radlog(L_ERR, "%s[%d]: Reference \"%s\" has no value", + cf, *lineno, input); + return NULL; + } strcpy(p, cp->value); p += strlen(p); ptr = end + 1; @@ -806,10 +851,10 @@ int cf_item_parse(CONF_SECTION *cs, const char *name, char **q; const char *value; fr_ipaddr_t ipaddr; - const CONF_PAIR *cp; + const CONF_PAIR *cp = NULL; char ipbuf[128]; - cp = cf_pair_find(cs, name); + if (cs) cp = cf_pair_find(cs, name); if (cp) { value = cp->value; @@ -863,7 +908,9 @@ int cf_item_parse(CONF_SECTION *cs, const char *name, if (value == dflt) { char buffer[8192]; - int lineno = cs->item.lineno; + int lineno = 0; + + if (cs) lineno = cs->item.lineno; /* * FIXME: sizeof(buffer)? @@ -897,7 +944,9 @@ int cf_item_parse(CONF_SECTION *cs, const char *name, if (value == dflt) { char buffer[8192]; - int lineno = cs->item.lineno; + int lineno = 0; + + if (cs) lineno = cs->item.lineno; /* * FIXME: sizeof(buffer)? @@ -1119,6 +1168,7 @@ static int condition_looks_ok(const char **ptr) * Parse error. */ if (*q != '{') { + DEBUG2("Expected open brace '{' after condition at %s", p); return 0; } @@ -1142,6 +1192,7 @@ static int condition_looks_ok(const char **ptr) } } + DEBUG3("Unexpected error"); return 0; } @@ -1194,12 +1245,12 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, * Read, checking for line continuations ('\\' at EOL) */ for (;;) { - int eof; + int at_eof; /* * Get data, and remember if we are at EOF. */ - eof = (fgets(cbuf, sizeof(buf) - (cbuf - buf), fp) == NULL); + at_eof = (fgets(cbuf, sizeof(buf) - (cbuf - buf), fp) == NULL); (*lineno)++; /* @@ -1221,14 +1272,14 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, * conditions. */ if (cbuf == buf) { - if (eof) break; + if (at_eof) break; ptr = buf; while (*ptr && isspace((int) *ptr)) ptr++; if (!*ptr || (*ptr == '#')) continue; - } else if (eof || (len == 0)) { + } else if (at_eof || (len == 0)) { radlog(L_ERR, "%s[%d]: Continuation at EOF is illegal", filename, *lineno); return -1; @@ -1250,7 +1301,44 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, } ptr = cbuf = buf; - t1 = gettoken(&ptr, buf1, sizeof(buf1)); + + /* + * The parser is getting to be evil. + */ + while ((*ptr == ' ') || (*ptr == '\t')) ptr++; + + if (((ptr[0] == '%') && (ptr[1] == '{')) || + (ptr[0] == '`')) { + int hack; + + if (ptr[0] == '%') { + hack = rad_copy_variable(buf1, ptr); + } else { + hack = rad_copy_string(buf1, ptr); + } + if (hack < 0) { + radlog(L_ERR, "%s[%d]: Invalid expansion: %s", + filename, *lineno, ptr); + return -1; + } + + t1 = T_BARE_WORD; + ptr += hack; + + t2 = gettoken(&ptr, buf2, sizeof(buf2)); + switch (t2) { + case T_EOL: + case T_HASH: + goto do_bare_word; + + default: + radlog(L_ERR, "%s[%d]: Invalid expansion: %s", + filename, *lineno, ptr); + return -1; + } + } else { + t1 = gettoken(&ptr, buf1, sizeof(buf1)); + } /* * The caller eats "name1 name2 {", and calls us @@ -1376,12 +1464,19 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, if (strcasecmp(buf1, "$template") == 0) { CONF_ITEM *ci; - CONF_SECTION *parentcs; + CONF_SECTION *parentcs, *templatecs; t2 = getword(&ptr, buf2, sizeof(buf2)); parentcs = cf_top_section(current); - ci = cf_reference_item(parentcs, this, buf2); + templatecs = cf_section_sub_find(parentcs, "templates"); + if (!templatecs) { + radlog(L_ERR, "%s[%d]: No \"templates\" section for reference \"%s\"", + filename, *lineno, buf2); + return -1; + } + + ci = cf_reference_item(parentcs, templatecs, buf2); if (!ci || (ci->type != CONF_ITEM_SECTION)) { radlog(L_ERR, "%s[%d]: Reference \"%s\" not found", filename, *lineno, buf2); @@ -1415,6 +1510,8 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, switch (t2) { case T_EOL: case T_HASH: + do_bare_word: + t3 = t2; t2 = T_OP_EQ; value = NULL; goto do_set; @@ -1424,6 +1521,7 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, case T_OP_SUB: case T_OP_LE: case T_OP_GE: + case T_OP_CMP_FALSE: if (!this || (strcmp(this->name1, "update") != 0)) { radlog(L_ERR, "%s[%d]: Invalid operator in assignment", filename, *lineno); @@ -1432,8 +1530,13 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, case T_OP_EQ: case T_OP_SET: - do_set: t3 = getstring(&ptr, buf3, sizeof(buf3)); + if (t3 == T_OP_INVALID) { + radlog(L_ERR, "%s[%d]: Parse error: %s", + filename, *lineno, + fr_strerror()); + return -1; + } /* * Handle variable substitution via ${foo} @@ -1453,6 +1556,7 @@ static int cf_section_read(const char *filename, int *lineno, FILE *fp, /* * Add this CONF_PAIR to our CONF_SECTION */ + do_set: cpn = cf_pair_alloc(buf1, value, t2, t3, this); cpn->item.filename = filename; cpn->item.lineno = *lineno; @@ -1605,6 +1709,12 @@ int cf_file_include(const char *filename, CONF_SECTION *cs) return -1; } + if (cf_data_find_internal(cs, filename, PW_TYPE_FILENAME)) { + radlog(L_ERR, "Cannot include the same file twice: \"%s\"", + filename); + return -1; + } + /* * Add the filename to the section */ @@ -1614,7 +1724,7 @@ int cf_file_include(const char *filename, CONF_SECTION *cs) 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\"", + radlog(L_ERR|L_CONS, "Internal error opening file \"%s\"", filename); return -1; } @@ -1622,7 +1732,7 @@ int cf_file_include(const char *filename, CONF_SECTION *cs) cd = cf_data_find_internal(cs, filename, PW_TYPE_FILENAME); if (!cd) { fclose(fp); - radlog(L_ERR|L_CONS, "Internal error open file \"%s\"", + radlog(L_ERR|L_CONS, "Internal error opening file \"%s\"", filename); return -1; } @@ -1727,7 +1837,7 @@ const char *cf_pair_value(CONF_PAIR *pair) /* * Copied here for error reporting. */ -extern void librad_log(const char *, ...); +extern void fr_strerror_printf(const char *, ...); /* * Turn a CONF_PAIR into a VALUE_PAIR @@ -1735,33 +1845,26 @@ extern void librad_log(const char *, ...); */ VALUE_PAIR *cf_pairtovp(CONF_PAIR *pair) { - DICT_ATTR *da; VALUE_PAIR *vp; if (!pair) { - librad_log("Internal error"); - return NULL; - } - - da = dict_attrbyname(pair->attr); - if (!da) { - librad_log("Unknown attribute %s", pair->attr); + fr_strerror_printf("Internal error"); return NULL; } if (!pair->value) { - librad_log("No value given for attribute %s", pair->attr); + fr_strerror_printf("No value given for attribute %s", pair->attr); return NULL; } - vp = pairalloc(da); + /* + * pairmake handles tags. pairalloc() doesn't. + */ + vp = pairmake(pair->attr, NULL, pair->operator); if (!vp) { - librad_log("Out of memory"); return NULL; } - vp->operator = pair->operator; - if (pair->value_type == T_BARE_WORD) { if ((vp->type == PW_TYPE_STRING) && (pair->value[0] == '0') && (pair->value[1] == 'x')) { @@ -1868,10 +1971,12 @@ CONF_SECTION *cf_section_sub_find(const CONF_SECTION *cs, const char *name) { CONF_ITEM *ci; + if (!name) return NULL; /* can't find an un-named section */ + /* * Do the fast lookup if possible. */ - if (name && cs->section_tree) { + if (cs->section_tree) { CONF_SECTION mycs; mycs.name1 = name; @@ -2360,25 +2465,25 @@ void cf_log_err(CONF_ITEM *ci, const char *fmt, ...) } -void cf_log_info(UNUSED CONF_SECTION *cs, const char *fmt, ...) +void cf_log_info(CONF_SECTION *cs, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - if (debug_flag > 1 && cf_log_config) vradlog(L_DBG, fmt, ap); + if (debug_flag > 1 && cf_log_config && cs) vradlog(L_DBG, fmt, ap); va_end(ap); } /* * Wrapper to simplify the code. */ -void cf_log_module(UNUSED CONF_SECTION *cs, const char *fmt, ...) +void cf_log_module(CONF_SECTION *cs, const char *fmt, ...) { va_list ap; char buffer[256]; va_start(ap, fmt); - if (debug_flag > 1 && cf_log_modules) { + if (debug_flag > 1 && cf_log_modules && cs) { vsnprintf(buffer, sizeof(buffer), fmt, ap); radlog(L_DBG, " Module: %s", buffer); @@ -2386,6 +2491,12 @@ void cf_log_module(UNUSED CONF_SECTION *cs, const char *fmt, ...) va_end(ap); } +const CONF_PARSER *cf_section_parse_table(CONF_SECTION *cs) +{ + if (!cs) return NULL; + + return cs->variables; +} #if 0 /* @@ -2437,3 +2548,159 @@ int dump_config(CONF_SECTION *cs) return dump_config_section(cs, 0); } #endif + +static const char *cf_pair_print_value(const CONF_PAIR *cp, + char *buffer, size_t buflen) +{ + char *p; + + if (!cp->value) return ""; + + switch (cp->value_type) { + default: + case T_BARE_WORD: + snprintf(buffer, buflen, "%s", cp->value); + break; + + case T_SINGLE_QUOTED_STRING: + snprintf(buffer, buflen, "'%s'", cp->value); + break; + + case T_DOUBLE_QUOTED_STRING: + buffer[0] = '"'; + fr_print_string(cp->value, strlen(cp->value), + buffer + 1, buflen - 3); + p = buffer + strlen(buffer); /* yuck... */ + p[0] = '"'; + p[1] = '\0'; + break; + } + + return buffer; +} + + +int cf_pair2xml(FILE *fp, const CONF_PAIR *cp) +{ + fprintf(fp, "<%s>", cp->attr); + if (cp->value) { + char buffer[2048]; + + char *p = buffer; + const char *q = cp->value; + + while (*q && (p < (buffer + sizeof(buffer) - 1))) { + if (q[0] == '&') { + memcpy(p, "&", 4); + p += 5; + + } else if (q[0] == '<') { + memcpy(p, "<", 4); + p += 4; + + } else if (q[0] == '>') { + memcpy(p, ">", 4); + p += 4; + + } else { + *(p++) = *q; + } + q++; + } + + *p = '\0'; + fprintf(fp, "%s", buffer); + } + + fprintf(fp, "\n", cp->attr); + + return 1; +} + +int cf_section2xml(FILE *fp, const CONF_SECTION *cs) +{ + CONF_ITEM *ci, *next; + + /* + * Section header + */ + fprintf(fp, "<%s>\n", cs->name1); + if (cs->name2) { + fprintf(fp, "<_name2>%s\n", cs->name2); + } + + /* + * Loop over contents. + */ + for (ci = cs->children; ci; ci = next) { + next = ci->next; + + switch (ci->type) { + case CONF_ITEM_PAIR: + if (!cf_pair2xml(fp, (CONF_PAIR *) ci)) return 0; + break; + + case CONF_ITEM_SECTION: + if (!cf_section2xml(fp, (CONF_SECTION *) ci)) return 0; + break; + + default: /* should really be an error. */ + break; + + } + } + + fprintf(fp, "\n", cs->name1); + + return 1; /* success */ +} + +int cf_pair2file(FILE *fp, const CONF_PAIR *cp) +{ + char buffer[2048]; + + fprintf(fp, "\t%s = %s\n", cp->attr, + cf_pair_print_value(cp, buffer, sizeof(buffer))); + + return 1; +} + +int cf_section2file(FILE *fp, const CONF_SECTION *cs) +{ + const CONF_ITEM *ci, *next; + + /* + * Section header + */ + if (!cs->name2) { + fprintf(fp, "%s {\n", cs->name1); + } else { + fprintf(fp, "%s %s {\n", + cs->name1, cs->name2); + } + + /* + * Loop over contents. + */ + for (ci = cs->children; ci; ci = next) { + next = ci->next; + + switch (ci->type) { + case CONF_ITEM_PAIR: + if (!cf_pair2file(fp, (const CONF_PAIR *) ci)) return 0; + break; + + case CONF_ITEM_SECTION: + if (!cf_section2file(fp, (const CONF_SECTION *) ci)) return 0; + break; + + default: /* should really be an error. */ + break; + + } + } + + fprintf(fp, "}\n"); + + return 1; /* success */ +}