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 :)
25 static const char rcsid[] =
29 #define xstrdup strdup
31 CONF_SECTION *config = NULL;
33 extern RADCLIENT *clients;
36 static int generate_realms(const char *filename);
37 static int generate_clients(const char *filename);
40 #define RADIUS_CONFIG "radiusd.conf"
44 * Create a new CONF_PAIR
46 CONF_PAIR *cf_pair_alloc(const char *attr, const char *value, int operator)
50 cp = (CONF_PAIR *)xalloc(sizeof(CONF_PAIR));
51 memset(cp, 0, sizeof(CONF_PAIR));
52 cp->attr = xstrdup(attr);
53 cp->value = xstrdup(value);
54 cp->operator = operator;
60 * Add a pair to a configuration section.
62 void cf_pair_add(CONF_SECTION *cs, CONF_PAIR *cp_new)
66 for (cp = cs->cps; cp && cp->next; cp = cp->next)
78 void cf_pair_free(CONF_PAIR *cp)
80 if (cp == NULL) return;
82 if (cp->attr) free(cp->attr);
83 if (cp->value) free(cp->value);
88 * Allocate a CONF_SECTION
90 CONF_SECTION *cf_section_alloc(const char *name1, const char *name2)
94 if (name1 == NULL || !name1[0]) name1 = "main";
96 cs = (CONF_SECTION *)xalloc(sizeof(CONF_SECTION));
97 memset(cs, 0, sizeof(CONF_SECTION));
98 cs->name1 = xstrdup(name1);
99 cs->name2 = (name2 && *name2) ? xstrdup(name2) : NULL;
105 * Free a CONF_SECTION
107 void cf_section_free(CONF_SECTION *cs)
109 CONF_PAIR *cp, *next;
110 CONF_SECTION *sub, *next_sub;
112 if (cs == NULL) return;
114 for (cp = cs->cps; cp; cp = next) {
120 * Clear out any possible subsections as well
122 for (sub = cs->sub; sub; sub = next_sub) {
123 next_sub = sub->next;
124 cf_section_free(sub);
127 if (cs->name1) free(cs->name1);
128 if (cs->name2) free(cs->name2);
131 * And free the section
137 * Parse a configuration section into user-supplied variables.
139 int cf_section_parse(CONF_SECTION *cs, const CONF_PARSER *variables)
149 * Handle the user-supplied variables.
151 for (i = 0; variables[i].name != NULL; i++) {
152 value = variables[i].dflt;
154 cp = cf_pair_find(cs, variables[i].name);
159 switch (variables[i].type)
161 case PW_TYPE_BOOLEAN:
163 * Allow yes/no and on/off
165 if ((strcasecmp(value, "yes") == 0) ||
166 (strcasecmp(value, "on") == 0)) {
167 *(int *)variables[i].data = 1;
168 } else if ((strcasecmp(value, "no") == 0) ||
169 (strcasecmp(value, "off") == 0)) {
170 *(int *)variables[i].data = 0;
172 *(int *)variables[i].data = 0;
173 log(L_ERR, "Bad value \"%s\" for boolean variable %s", value, variables[i].name);
176 DEBUG2("Config: %s.%s = %s",
182 case PW_TYPE_INTEGER:
183 *(int *)variables[i].data = strtol(value, 0, 0);
184 DEBUG2("Config: %s.%s = %d",
187 *(int *)variables[i].data);
190 case PW_TYPE_STRING_PTR:
191 q = (char **) variables[i].data;
195 DEBUG2("Config: %s.%s = \"%s\"",
198 value ? value : "(null)");
199 *q = value ? strdup(value) : NULL;
204 * Allow '*' as any address
206 if (strcmp(value, "*") == 0) {
207 *(uint32_t *) variables[i].data = 0;
210 ipaddr = ip_getaddr(value);
212 log(L_ERR, "Can't find IP address for host %s", value);
215 DEBUG2("Config: %s.%s = %s IP address [%s]",
218 value, ip_ntoa(buffer, ipaddr));
219 *(uint32_t *) variables[i].data = ipaddr;
223 log(L_ERR, "type %d not supported yet", variables[i].type);
226 } /* switch over variable type */
227 } /* for all variables in the configuration section */
234 * Read a part of the config file.
236 static CONF_SECTION *cf_section_read(const char *cf, int *lineno, FILE *fp,
237 const char *name1, const char *name2)
239 CONF_SECTION *cs, *csp, *css;
249 * Ensure that the user can't add CONF_SECTIONs
250 * with 'internal' names;
252 if ((name1 != NULL) && (name1[0] == '_')) {
253 log(L_ERR, "%s[%d]: Illegal configuration section name",
259 * Allow for $INCLUDE files???
261 * This sure looks wrong. But it looked wrong before I touched
262 * the file, so don't blame me. Please, just pass the config
263 * file through cpp or m4 and cut out the bloat. --Pac.
265 if (name1 && strcasecmp(name1, "$INCLUDE") == 0) {
266 return conf_read(name2);
270 * Allocate new section.
272 cs = cf_section_alloc(name1, name2);
273 cs->lineno = *lineno;
278 while (fgets(buf, sizeof(buf), fp) != NULL) {
286 * No '=': must be a section or sub-section.
288 if (strchr(ptr, '=') == NULL) {
289 t1 = gettoken(&ptr, buf1, sizeof(buf1));
290 t2 = gettoken(&ptr, buf2, sizeof(buf2));
291 t3 = gettoken(&ptr, buf3, sizeof(buf3));
293 t1 = gettoken(&ptr, buf1, sizeof(buf1));
294 t2 = gettoken(&ptr, buf2, sizeof(buf2));
295 t3 = getword(&ptr, buf3, sizeof(buf3));
298 if (buf1[0] == 0 || buf1[0] == '#')
302 * See if it's the end of a section.
304 if (t1 == T_RCBRACE) {
305 if (name1 == NULL || buf2[0]) {
306 log(L_ERR, "%s[%d]: Unexpected end of section",
315 * Perhaps a subsection.
318 if (t2 == T_LCBRACE || t3 == T_LCBRACE) {
319 css = cf_section_read(cf, lineno, fp, buf1,
320 t2==T_LCBRACE ? NULL : buf2);
325 for (csp = cs->sub; csp && csp->next; csp = csp->next)
336 * Must be a normal attr = value line.
338 if (buf1[0] != 0 && buf2[0] == 0 && buf3[0] == 0) {
340 } else if (buf1[0] == 0 || buf2[0] == 0 || buf3[0] == 0 ||
341 (t2 < T_EQSTART || t2 > T_EQEND)) {
342 log(L_ERR, "%s[%d]: Line is not in 'attribute = value' format",
349 * Ensure that the user can't add CONF_PAIRs
350 * with 'internal' names;
352 if (buf1[0] == '_') {
353 log(L_ERR, "%s[%d]: Illegal configuration pair name \"%s\"",
360 * Handle variable substitution via ${foo}
364 while (*ptr >= ' ') {
366 * Ignore anything other than "${"
375 * Look for trailing '}', and silently
376 * ignore anything that doesn't match.
378 q = strchr(ptr, '}');
384 memcpy(buf2, ptr + 2, q - ptr - 2);
385 buf2[q - ptr - 2] = '\0';
386 cpn = cf_pair_find(cs, buf2);
388 log(L_ERR, "%s[%d]: Unknown variable \"%s\"",
393 strcpy(p, cpn->value);
400 * Add this CONF_PAIR to our CONF_SECTION
402 cpn = cf_pair_alloc(buf1, buf, t2);
403 cpn->lineno = *lineno;
404 cf_pair_add(cs, cpn);
408 * See if EOF was unexpected ..
411 log(L_ERR, "%s[%d]: unexpected end of file", cf, *lineno);
420 * Read the config file.
422 CONF_SECTION *conf_read(const char *conffile)
428 if ((fp = fopen(conffile, "r")) == NULL) {
429 log(L_ERR, "cannot open %s: %s",
430 conffile, strerror(errno));
434 cs = cf_section_read(conffile, &lineno, fp, NULL, NULL);
441 * Read the configuration and library
442 * This uses the new kind of configuration file as defined by
443 * Miquel at http://www.miquels.cistron.nl/radius/
446 int read_radius_conf_file(void)
451 /* Lets go for the new configuration files */
453 sprintf(buffer, "%.200s/%.50s", radius_dir, RADIUS_CONFIG);
454 if ((cs = conf_read(buffer)) == NULL) {
459 * Free the old configuration data, and replace it
462 cf_section_free(config);
468 * Fail if we can't generate list of clients
471 if (generate_clients(buffer) < 0) {
476 * If there isn't any realms it isn't fatal..
478 if (generate_realms(buffer) < 0) {
486 * Create the linked list of realms from the new configuration type
487 * This way we don't have to change to much in the other source-files
490 static int generate_realms(const char *filename)
494 char *s, *authhost, *accthost;
496 for (cs = config->sub; cs; cs = cs->next) {
497 if (strcmp(cs->name1, "realm") == 0) {
499 log(L_CONS|L_ERR, "%s[%d]: Missing realm name", filename, cs->lineno);
503 * We've found a realm, allocate space for it
505 if ((c = malloc(sizeof(REALM))) == NULL) {
506 log(L_CONS|L_ERR, "Out of memory");
509 memset(c, 0, sizeof(REALM));
511 * An authhost must exist in the configuration
513 if ((authhost = cf_section_value_find(cs, "authhost")) == NULL) {
515 "%s[%d]: No authhost entry in realm",
516 filename, cs->lineno);
519 if ((s = strchr(authhost, ':')) != NULL) {
521 c->auth_port = atoi(s);
523 c->auth_port = auth_port;
525 accthost = cf_section_value_find(cs, "accthost");
526 if ((s =strchr(accthost, ':')) != NULL) {
528 c->acct_port = atoi(s);
530 c->acct_port = acct_port;
532 if (strcmp(authhost, "LOCAL") != 0)
533 c->ipaddr = ip_getaddr(authhost);
536 * Double check length, just to be sure!
538 if (strlen(authhost) >= sizeof(c->server)) {
539 log(L_ERR, "%s[%d]: Server name of length %d is greater that allowed: %d",
540 filename, cs->lineno,
541 strlen(authhost), sizeof(c->server) - 1);
544 if (strlen(cs->name2) >= sizeof(c->realm)) {
545 log(L_ERR, "%s[%d]: Realm name of length %d is greater than allowed %d",
546 filename, cs->lineno,
547 strlen(cs->name2), sizeof(c->server) - 1);
551 strcpy(c->realm, cs->name2);
552 strcpy(c->server, authhost);
554 s = cf_section_value_find(cs, "secret");
556 log(L_ERR, "%s[%d]: No shared secret supplied for realm",
557 filename, cs->lineno);
561 if (strlen(s) >= sizeof(c->secret)) {
562 log(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
563 filename, cs->lineno,
564 strlen(s), sizeof(c->secret) - 1);
567 strNcpy(c->secret, s, sizeof(c->secret));
571 if ((cf_section_value_find(cs, "nostrip")) != NULL)
573 if ((cf_section_value_find(cs, "noacct")) != NULL)
575 if ((cf_section_value_find(cs, "trusted")) != NULL)
588 * Create the linked list of realms from the new configuration type
589 * This way we don't have to change to much in the other source-files
592 static int generate_clients(const char *filename)
596 char *hostnm, *secret, *shortnm;
598 for (cs = config->sub; cs; cs = cs->next) {
599 if (strcmp(cs->name1, "client") == 0) {
601 log(L_CONS|L_ERR, "%s[%d]: Missing client name", filename, cs->lineno);
605 * Check the lengths, we don't want any core dumps
608 secret = cf_section_value_find(cs, "secret");
609 shortnm = cf_section_value_find(cs, "shortname");
611 if (strlen(secret) >= sizeof(c->secret)) {
612 log(L_ERR, "%s[%d]: Secret of length %d is greater than the allowed maximum of %d.",
613 filename, cs->lineno,
614 strlen(secret), sizeof(c->secret) - 1);
617 if (strlen(shortnm) > sizeof(c->shortname)) {
618 log(L_ERR, "%s[%d]: NAS short name of length %d is greater than the allowed maximum of %d.",
619 filename, cs->lineno,
620 strlen(shortnm), sizeof(c->shortname) - 1);
624 * The size is fine.. Let's create the buffer
626 if ((c = malloc(sizeof(RADCLIENT))) == NULL) {
627 log(L_CONS|L_ERR, "Out of memory");
631 c->ipaddr = ip_getaddr(hostnm);
632 strcpy(c->secret, secret);
633 strcpy(c->shortname, shortnm);
634 ip_hostname(c->longname, sizeof(c->longname),
646 * Return a CONF_PAIR within a CONF_SECTION.
649 CONF_PAIR *cf_pair_find(CONF_SECTION *section, const char *name)
653 if (section == NULL) {
657 for (cp = section->cps; cp; cp = cp->next)
658 if (strcmp(cp->attr, name) == 0)
665 * Return the value of a CONF_PAIR
668 char *cf_pair_value(CONF_PAIR *pair)
670 return (pair ? pair->value : NULL);
675 * Find a value in a CONF_SECTION
677 char *cf_section_value_find(CONF_SECTION *section, const char *attr)
681 cp = cf_pair_find(section, attr);
683 return (cp ? cp->value : NULL);
687 * Return the next pair after a CONF_PAIR
688 * with a certain name (char *attr)
691 CONF_PAIR *cf_pair_find_next(CONF_SECTION *section, CONF_PAIR *pair, const char *attr)
696 * If pair is NULL this must be a first time run
697 * Find the pair with correct name
701 cp = cf_pair_find(section, attr);
706 for (; cp; cp = cp->next)
707 if (strcmp(cp->attr, attr) == 0)
714 * Find a CONF_SECTION, or return the root if name is NULL
717 CONF_SECTION *cf_section_find(const char *name)
720 return cf_section_sub_find(config, name);
726 * Find a sub-section in a section
729 CONF_SECTION *cf_section_sub_find(CONF_SECTION *section, const char *name)
733 for (cs = section->sub; cs; cs = cs->next)
734 if (strcmp(cs->name1, name) == 0)
742 * Return the next subsection after a CONF_SECTION
743 * with a certain name1 (char *name1)
746 CONF_SECTION *cf_subsection_find_next(CONF_SECTION *section,
747 CONF_SECTION *subsection,
753 * If subsection is NULL this must be a first time run
754 * Find the subsection with correct name
757 if (subsection == NULL){
760 cp = subsection->next;
763 for (; cp; cp = cp->next)
764 if (strcmp(cp->name1, name1) == 0)
771 * Find the configuration section for a module
774 CONF_SECTION *cf_module_config_find(const char *modulename)
778 for (cs = config->sub; cs; cs = cs->next)
779 if ((strcmp(cs->name1, "module") == 0)
780 && (strcmp(cs->name2, modulename) == 0))
787 * JMG dump_config tries to dump the config structure in a readable format
791 static int dump_config_section(CONF_SECTION *cs, int indent)
797 /* The DEBUG macro doesn't let me
798 * for(i=0;i<indent;++i) debugputchar('\t');
799 * so I had to get creative. --Pac. */
801 for (cp = cs->cps; cp; cp = cp->next)
803 indent, "\t\t\t\t\t\t\t\t\t\t\t", cp->attr, cp->value);
805 for (scs = cs->sub; scs; scs = scs->next) {
806 DEBUG("%.*s%s %s%s{",
807 indent, "\t\t\t\t\t\t\t\t\t\t\t",
809 scs->name2 ? scs->name2 : "",
810 scs->name2 ? " " : "");
811 dump_config_section(scs, indent+1);
813 indent, "\t\t\t\t\t\t\t\t\t\t\t");
819 int dump_config(void)
821 return dump_config_section(config, 0);