2 * conffile.c Read the radiusd.conf file.
4 * Yep I should learn to use lex & yacc, or at least
5 * write a decent parser. I know how to do that, really :)
23 static const char rcsid[] =
27 #define xstrdup strdup
29 typedef enum conf_type {
35 struct conf_item *next;
36 struct conf_part *parent;
50 struct conf_item *children;
53 CONF_SECTION *config = NULL;
55 extern RADCLIENT *clients;
58 static int generate_realms(const char *filename);
59 static int generate_clients(const char *filename);
62 #define RADIUS_CONFIG "radiusd.conf"
66 * Isolate the scary casts in these tiny provably-safe functions
68 CONF_PAIR *cf_itemtopair(CONF_ITEM *ci)
72 assert(ci->type == CONF_ITEM_PAIR);
73 return (CONF_PAIR *)ci;
75 CONF_SECTION *cf_itemtosection(CONF_ITEM *ci)
79 assert(ci->type == CONF_ITEM_SECTION);
80 return (CONF_SECTION *)ci;
82 static CONF_ITEM *cf_pairtoitem(CONF_PAIR *cp)
86 return (CONF_ITEM *)cp;
88 static CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs)
92 return (CONF_ITEM *)cs;
96 * Create a new CONF_PAIR
98 static CONF_PAIR *cf_pair_alloc(const char *attr, const char *value,
99 int operator, CONF_SECTION *parent)
103 cp = (CONF_PAIR *)xalloc(sizeof(CONF_PAIR));
104 memset(cp, 0, sizeof(CONF_PAIR));
105 cp->item.type = CONF_ITEM_PAIR;
106 cp->item.parent = parent;
107 cp->attr = xstrdup(attr);
108 cp->value = xstrdup(value);
109 cp->operator = operator;
115 * Add an item to a configuration section.
117 static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci_new)
121 for (ci = cs->children; ci && ci->next; ci = ci->next)
125 cs->children = ci_new;
133 void cf_pair_free(CONF_PAIR *cp)
135 if (cp == NULL) return;
137 if (cp->attr) free(cp->attr);
138 if (cp->value) free(cp->value);
143 * Allocate a CONF_SECTION
145 static CONF_SECTION *cf_section_alloc(const char *name1, const char *name2,
146 CONF_SECTION *parent)
150 if (name1 == NULL || !name1[0]) name1 = "main";
152 cs = (CONF_SECTION *)xalloc(sizeof(CONF_SECTION));
153 memset(cs, 0, sizeof(CONF_SECTION));
154 cs->item.type = CONF_ITEM_SECTION;
155 cs->item.parent = parent;
156 cs->name1 = xstrdup(name1);
157 cs->name2 = (name2 && *name2) ? xstrdup(name2) : NULL;
163 * Free a CONF_SECTION
165 void cf_section_free(CONF_SECTION *cs)
167 CONF_ITEM *ci, *next;
169 if (cs == NULL) return;
171 for (ci = cs->children; ci; ci = next) {
173 if (ci->type==CONF_ITEM_PAIR)
174 cf_pair_free(cf_itemtopair(ci));
176 cf_section_free(cf_itemtosection(ci));
179 if (cs->name1) free(cs->name1);
180 if (cs->name2) free(cs->name2);
183 * And free the section
189 * Parse a configuration section into user-supplied variables.
191 int cf_section_parse(CONF_SECTION *cs, const CONF_PARSER *variables)
201 * Handle the user-supplied variables.
203 for (i = 0; variables[i].name != NULL; i++) {
204 value = variables[i].dflt;
206 cp = cf_pair_find(cs, variables[i].name);
211 switch (variables[i].type)
213 case PW_TYPE_BOOLEAN:
215 * Allow yes/no and on/off
217 if ((strcasecmp(value, "yes") == 0) ||
218 (strcasecmp(value, "on") == 0)) {
219 *(int *)variables[i].data = 1;
220 } else if ((strcasecmp(value, "no") == 0) ||
221 (strcasecmp(value, "off") == 0)) {
222 *(int *)variables[i].data = 0;
224 *(int *)variables[i].data = 0;
225 radlog(L_ERR, "Bad value \"%s\" for boolean variable %s", value, variables[i].name);
228 DEBUG2("Config: %s.%s = %s",
234 case PW_TYPE_INTEGER:
235 *(int *)variables[i].data = strtol(value, 0, 0);
236 DEBUG2("Config: %s.%s = %d",
239 *(int *)variables[i].data);
242 case PW_TYPE_STRING_PTR:
243 q = (char **) variables[i].data;
247 DEBUG2("Config: %s.%s = \"%s\"",
250 value ? value : "(null)");
251 *q = value ? strdup(value) : NULL;
256 * Allow '*' as any address
258 if (strcmp(value, "*") == 0) {
259 *(uint32_t *) variables[i].data = 0;
262 ipaddr = ip_getaddr(value);
264 radlog(L_ERR, "Can't find IP address for host %s", value);
267 DEBUG2("Config: %s.%s = %s IP address [%s]",
270 value, ip_ntoa(buffer, ipaddr));
271 *(uint32_t *) variables[i].data = ipaddr;
275 radlog(L_ERR, "type %d not supported yet", variables[i].type);
278 } /* switch over variable type */
279 } /* for all variables in the configuration section */
286 * Read a part of the config file.
288 static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
289 const char *name1, const char *name2,
290 CONF_SECTION *parent)
292 CONF_SECTION *cs, *css, *outercs;
302 * Ensure that the user can't add CONF_SECTIONs
303 * with 'internal' names;
305 if ((name1 != NULL) && (name1[0] == '_')) {
306 radlog(L_ERR, "%s[%d]: Illegal configuration section name",
312 * Allow for $INCLUDE files???
314 * This sure looks wrong. But it looked wrong before I touched
315 * the file, so don't blame me. Please, just pass the config
316 * file through cpp or m4 and cut out the bloat. --Pac.
318 if (name1 && strcasecmp(name1, "$INCLUDE") == 0) {
319 return conf_read(name2);
323 * Allocate new section.
325 cs = cf_section_alloc(name1, name2, parent);
326 cs->item.lineno = *lineno;
331 while (fgets(buf, sizeof(buf), fp) != NULL) {
339 * No '=': must be a section or sub-section.
341 if (strchr(ptr, '=') == NULL) {
342 t1 = gettoken(&ptr, buf1, sizeof(buf1));
343 t2 = gettoken(&ptr, buf2, sizeof(buf2));
344 t3 = gettoken(&ptr, buf3, sizeof(buf3));
346 t1 = gettoken(&ptr, buf1, sizeof(buf1));
347 t2 = gettoken(&ptr, buf2, sizeof(buf2));
348 t3 = getword(&ptr, buf3, sizeof(buf3));
351 if (buf1[0] == 0 || buf1[0] == '#')
355 * See if it's the end of a section.
357 if (t1 == T_RCBRACE) {
358 if (name1 == NULL || buf2[0]) {
359 radlog(L_ERR, "%s[%d]: Unexpected end of section",
368 * Perhaps a subsection.
370 if (t2 == T_LCBRACE || t3 == T_LCBRACE) {
371 css = cf_section_read(cf, lineno, fp, buf1,
372 t2==T_LCBRACE ? NULL : buf2, cs);
377 cf_item_add(cs, cf_sectiontoitem(css));
383 * Ignore semi-colons.
385 if (*buf2 == ';') *buf2 = '\0';
388 * Must be a normal attr = value line.
390 if (buf1[0] != 0 && buf2[0] == 0 && buf3[0] == 0) {
392 } else if (buf1[0] == 0 || buf2[0] == 0 || buf3[0] == 0 ||
393 (t2 < T_EQSTART || t2 > T_EQEND)) {
394 radlog(L_ERR, "%s[%d]: Line is not in 'attribute = value' format",
401 * Ensure that the user can't add CONF_PAIRs
402 * with 'internal' names;
404 if (buf1[0] == '_') {
405 radlog(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"",
412 * Handle variable substitution via ${foo}
416 while (*ptr >= ' ') {
418 * Ignore anything other than "${"
427 * Look for trailing '}', and silently
428 * ignore anything that doesn't match.
430 q = strchr(ptr, '}');
436 memcpy(buf2, ptr + 2, q - ptr - 2);
437 buf2[q - ptr - 2] = '\0';
438 cpn = cf_pair_find(cs, buf2);
439 /* Also look recursively up the section tree,
440 * so things like ${confdir} can be defined
441 * there and used inside the module config
443 for (outercs=cs->item.parent
445 outercs=outercs->item.parent) {
446 cpn = cf_pair_find(outercs, buf2);
449 radlog(L_ERR, "%s[%d]: Unknown variable \"%s\"",
454 strcpy(p, cpn->value);
461 * Add this CONF_PAIR to our CONF_SECTION
463 cpn = cf_pair_alloc(buf1, buf, t2, parent);
464 cpn->item.lineno = *lineno;
465 cf_item_add(cs, cf_pairtoitem(cpn));
469 * See if EOF was unexpected ..
472 radlog(L_ERR, "%s[%d]: unexpected end of file", cf, *lineno);
481 * Read the config file.
483 CONF_SECTION *conf_read(const char *conffile)
489 if ((fp = fopen(conffile, "r")) == NULL) {
490 radlog(L_ERR, "cannot open %s: %s",
491 conffile, strerror(errno));
495 cs = cf_section_read(conffile, &lineno, fp, NULL, NULL, NULL);
502 * Read the configuration and library
503 * This uses the new kind of configuration file as defined by
504 * Miquel at http://www.miquels.cistron.nl/radius/
507 int read_radius_conf_file(void)
512 /* Lets go for the new configuration files */
514 sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
515 if ((cs = conf_read(buffer)) == NULL) {
520 * Free the old configuration data, and replace it
523 cf_section_free(config);
529 * Fail if we can't generate list of clients
532 if (generate_clients(buffer) < 0) {
537 * If there isn't any realms it isn't fatal..
539 if (generate_realms(buffer) < 0) {
547 * Create the linked list of realms from the new configuration type
548 * This way we don't have to change to much in the other source-files
551 static int generate_realms(const char *filename)
555 char *s, *authhost, *accthost;
557 for (cs = cf_subsection_find_next(config, NULL, "realm")
559 cs = cf_subsection_find_next(config, cs, "realm")) {
561 radlog(L_CONS|L_ERR, "%s[%d]: Missing realm name", filename, cs->item.lineno);
565 * We've found a realm, allocate space for it
567 if ((c = malloc(sizeof(REALM))) == NULL) {
568 radlog(L_CONS|L_ERR, "Out of memory");
571 memset(c, 0, sizeof(REALM));
573 * An authhost must exist in the configuration
575 if ((authhost = cf_section_value_find(cs, "authhost")) == NULL) {
577 "%s[%d]: No authhost entry in realm",
578 filename, cs->item.lineno);
581 if ((s = strchr(authhost, ':')) != NULL) {
583 c->auth_port = atoi(s);
585 c->auth_port = auth_port;
587 accthost = cf_section_value_find(cs, "accthost");
588 if ((s =strchr(accthost, ':')) != NULL) {
590 c->acct_port = atoi(s);
592 c->acct_port = acct_port;
594 if (strcmp(authhost, "LOCAL") != 0)
595 c->ipaddr = ip_getaddr(authhost);
598 * Double check length, just to be sure!
600 if (strlen(authhost) >= sizeof(c->server)) {
601 radlog(L_ERR, "%s[%d]: Server name of length %d is greater that allowed: %d",
602 filename, cs->item.lineno,
603 strlen(authhost), sizeof(c->server) - 1);
606 if (strlen(cs->name2) >= sizeof(c->realm)) {
607 radlog(L_ERR, "%s[%d]: Realm name of length %d is greater than allowed %d",
608 filename, cs->item.lineno,
609 strlen(cs->name2), sizeof(c->server) - 1);
613 strcpy(c->realm, cs->name2);
614 strcpy(c->server, authhost);
616 s = cf_section_value_find(cs, "secret");
618 radlog(L_ERR, "%s[%d]: No shared secret supplied for realm",
619 filename, cs->item.lineno);
623 if (strlen(s) >= sizeof(c->secret)) {
624 radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
625 filename, cs->item.lineno,
626 strlen(s), sizeof(c->secret) - 1);
629 strNcpy(c->secret, s, sizeof(c->secret));
633 if ((cf_section_value_find(cs, "nostrip")) != NULL)
635 if ((cf_section_value_find(cs, "noacct")) != NULL)
637 if ((cf_section_value_find(cs, "trusted")) != NULL)
649 * Create the linked list of realms from the new configuration type
650 * This way we don't have to change to much in the other source-files
653 static int generate_clients(const char *filename)
657 char *hostnm, *secret, *shortnm;
659 for (cs = cf_subsection_find_next(config, NULL, "client")
661 cs = cf_subsection_find_next(config, cs, "client")) {
663 radlog(L_CONS|L_ERR, "%s[%d]: Missing client name", filename, cs->item.lineno);
667 * Check the lengths, we don't want any core dumps
670 secret = cf_section_value_find(cs, "secret");
671 shortnm = cf_section_value_find(cs, "shortname");
673 if (strlen(secret) >= sizeof(c->secret)) {
674 radlog(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
675 filename, cs->item.lineno,
676 strlen(secret), sizeof(c->secret) - 1);
679 if (strlen(shortnm) > sizeof(c->shortname)) {
680 radlog(L_ERR, "%s[%d]: NAS short name of length %d is greater than the allowed maximum of %d.",
681 filename, cs->item.lineno,
682 strlen(shortnm), sizeof(c->shortname) - 1);
686 * The size is fine.. Let's create the buffer
688 if ((c = malloc(sizeof(RADCLIENT))) == NULL) {
689 radlog(L_CONS|L_ERR, "Out of memory");
693 c->ipaddr = ip_getaddr(hostnm);
694 strcpy(c->secret, secret);
695 strcpy(c->shortname, shortnm);
696 ip_hostname(c->longname, sizeof(c->longname),
707 * Return a CONF_PAIR within a CONF_SECTION.
710 CONF_PAIR *cf_pair_find(CONF_SECTION *section, const char *name)
714 if (section == NULL) {
718 for (ci = section->children; ci; ci = ci->next) {
719 if (ci->type != CONF_ITEM_PAIR)
721 if (name == NULL || strcmp(cf_itemtopair(ci)->attr, name) == 0)
725 return cf_itemtopair(ci);
729 * Return the attr of a CONF_PAIR
732 char *cf_pair_attr(CONF_PAIR *pair)
734 return (pair ? pair->attr : NULL);
738 * Return the value of a CONF_PAIR
741 char *cf_pair_value(CONF_PAIR *pair)
743 return (pair ? pair->value : NULL);
747 * Return the first label of a CONF_SECTION
750 char *cf_section_name1(CONF_SECTION *section)
752 return (section ? section->name1 : NULL);
756 * Return the second label of a CONF_SECTION
759 char *cf_section_name2(CONF_SECTION *section)
761 return (section ? section->name2 : NULL);
765 * Find a value in a CONF_SECTION
767 char *cf_section_value_find(CONF_SECTION *section, const char *attr)
771 cp = cf_pair_find(section, attr);
773 return (cp ? cp->value : NULL);
777 * Return the next pair after a CONF_PAIR
778 * with a certain name (char *attr) If the requested
779 * attr is NULL, any attr matches.
782 CONF_PAIR *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char *attr)
787 * If pair is NULL this must be a first time run
788 * Find the pair with correct name
792 return cf_pair_find(section, attr);
795 ci = cf_pairtoitem(pair)->next;
797 for (; ci; ci = ci->next) {
798 if (ci->type != CONF_ITEM_PAIR)
800 if (attr == NULL || strcmp(cf_itemtopair(ci)->attr, attr) == 0)
804 return cf_itemtopair(ci);
808 * Find a CONF_SECTION, or return the root if name is NULL
811 CONF_SECTION *cf_section_find(const char *name)
814 return cf_section_sub_find(config, name);
820 * Find a sub-section in a section
823 CONF_SECTION *cf_section_sub_find(CONF_SECTION *section, const char *name)
827 for (ci = section->children; ci; ci = ci->next) {
828 if (ci->type != CONF_ITEM_SECTION)
830 if (strcmp(cf_itemtosection(ci)->name1, name) == 0)
834 return cf_itemtosection(ci);
839 * Return the next subsection after a CONF_SECTION
840 * with a certain name1 (char *name1). If the requested
841 * name1 is NULL, any name1 matches.
844 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
845 CONF_SECTION *subsection,
851 * If subsection is NULL this must be a first time run
852 * Find the subsection with correct name
855 if (subsection == NULL){
856 ci = section->children;
858 ci = cf_sectiontoitem(subsection)->next;
861 for (; ci; ci = ci->next) {
862 if (ci->type != CONF_ITEM_SECTION)
865 strcmp(cf_itemtosection(ci)->name1, name1) == 0)
869 return cf_itemtosection(ci);
873 * Return the next item after a CONF_ITEM.
876 CONF_ITEM *cf_item_find_next(CONF_SECTION *section, CONF_ITEM *item)
879 * If item is NULL this must be a first time run
880 * Return the first item
884 return section->children;
890 int cf_section_lineno(CONF_SECTION *section)
892 return cf_sectiontoitem(section)->lineno;
895 int cf_pair_lineno(CONF_PAIR *pair)
897 return cf_pairtoitem(pair)->lineno;
900 int cf_item_is_section(CONF_ITEM *item)
902 return item->type == CONF_ITEM_SECTION;
907 * JMG dump_config tries to dump the config structure in a readable format
911 static int dump_config_section(CONF_SECTION *cs, int indent)
917 /* The DEBUG macro doesn't let me
918 * for(i=0;i<indent;++i) debugputchar('\t');
919 * so I had to get creative. --Pac. */
921 for (ci = cs->children; ci; ci = ci->next) {
922 if (ci->type == CONF_ITEM_PAIR) {
923 cp=cf_itemtopair(ci);
925 indent, "\t\t\t\t\t\t\t\t\t\t\t",
926 cp->attr, cp->value);
928 scs=cf_itemtosection(ci);
929 DEBUG("%.*s%s %s%s{",
930 indent, "\t\t\t\t\t\t\t\t\t\t\t",
932 scs->name2 ? scs->name2 : "",
933 scs->name2 ? " " : "");
934 dump_config_section(scs, indent+1);
936 indent, "\t\t\t\t\t\t\t\t\t\t\t");
943 int dump_config(void)
945 return dump_config_section(config, 0);