2 * files.c Read config files into memory.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000 The FreeRADIUS server project
21 * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
22 * Copyright 2000 Alan DeKok <aland@ox.org>
25 static const char rcsid[] = "$Id$";
31 #ifdef HAVE_NETINET_IN_H
32 # include <netinet/in.h>
42 #include "rad_assert.h"
47 void pairlist_free(PAIR_LIST **pl)
51 for (p = *pl; p; p = next) {
52 if (p->name) free(p->name);
53 if (p->check) pairfree(&p->check);
54 if (p->reply) pairfree(&p->reply);
62 #define FIND_MODE_NAME 0
63 #define FIND_MODE_REPLY 1
66 * Read the users, huntgroups or hints file.
69 int pairlist_read(const char *file, PAIR_LIST **list, int complain)
72 int mode = FIND_MODE_NAME;
76 VALUE_PAIR *check_tmp;
77 VALUE_PAIR *reply_tmp;
78 PAIR_LIST *pl = NULL, *t;
79 PAIR_LIST **last = &pl;
86 * Open the file. The error message should be a little
89 if ((fp = fopen(file, "r")) == NULL) {
92 radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
93 file, strerror(errno));
99 * Read the entire file into memory for speed.
101 while(fgets(buffer, sizeof(buffer), fp) != NULL) {
103 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
104 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
108 if (buffer[0] == '#' || buffer[0] == '\n') continue;
111 * If the line contains nothing but whitespace,
115 while ((ptr[0] == ' ') ||
121 if (ptr[0] == '\0') continue;
124 if(mode == FIND_MODE_NAME) {
126 * Find the entry starting with the users name
128 if (isspace((int) buffer[0])) {
129 if (parsecode != T_EOL) {
131 "%s[%d]: Unexpected trailing comma for entry %s",
132 file, lineno, entry);
140 getword(&ptr, entry, sizeof(entry));
143 * Include another file if we see
146 if (strcasecmp(entry, "$include") == 0) {
147 while(isspace((int) *ptr))
150 while (!isspace((int) *ptr))
155 * If it's an absolute pathname,
156 * then use it verbatim.
158 * If not, then make the $include
159 * files *relative* to the current
163 strNcpy(newfile, file,
165 ptr = strrchr(newfile, '/');
171 if (pairlist_read(s, &t, 0) != 0) {
174 "%s[%d]: Could not open included file %s: %s",
175 file, lineno, s, strerror(errno));
182 * t may be NULL, it may have one
183 * entry, or it may be a linked list
184 * of entries. Go to the end of the
188 last = &((*last)->next);
193 * Parse the check values
198 parsecode = userparse(ptr, &check_tmp);
199 if (parsecode == T_OP_INVALID) {
202 "%s[%d]: Parse error (check) for entry %s: %s",
203 file, lineno, entry, librad_errstr);
206 } else if (parsecode == T_COMMA) {
208 "%s[%d]: Unexpected trailing comma in check item list for entry %s",
209 file, lineno, entry);
213 mode = FIND_MODE_REPLY;
217 if(*buffer == ' ' || *buffer == '\t') {
218 if (parsecode != T_COMMA) {
220 "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
221 file, lineno, entry);
227 * Parse the reply values
229 parsecode = userparse(buffer, &reply_tmp);
230 /* valid tokens are 1 or greater */
234 "%s[%d]: Parse error (reply) for entry %s: %s",
235 file, lineno, entry, librad_errstr);
242 * Done with this entry...
244 t = rad_malloc(sizeof(PAIR_LIST));
246 memset(t, 0, sizeof(*t));
247 t->name = strdup(entry);
248 t->check = check_tmp;
249 t->reply = reply_tmp;
250 t->lineno = old_lineno;
257 mode = FIND_MODE_NAME;
264 * Make sure that we also read the last line of the file!
266 if (mode == FIND_MODE_REPLY) {
281 static void debug_pair_list(PAIR_LIST *pl)
286 printf("Pair list: %s\n", pl->name);
287 printf("** Check:\n");
288 for(vp = pl->check; vp; vp = vp->next) {
290 fprint_attr_val(stdout, vp);
293 printf("** Reply:\n");
294 for(vp = pl->reply; vp; vp = vp->next) {
296 fprint_attr_val(stdout, vp);
304 #ifndef BUILDDBM /* HACK HACK */
309 void realm_free(REALM *cl)
321 * Read the realms file.
323 int read_realms_file(const char *file)
333 int got_realm = FALSE;
335 realm_free(mainconfig.realms);
336 mainconfig.realms = NULL;
337 tail = &mainconfig.realms;
339 if ((fp = fopen(file, "r")) == NULL) {
340 /* The realms file is not mandatory. If it exists it will
341 be used, however, since the new style config files are
342 more robust and flexible they are more likely to get used.
343 So this is a non-fatal error. */
347 while(fgets(buffer, 256, fp) != NULL) {
349 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
350 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
353 if (buffer[0] == '#' || buffer[0] == '\n')
356 if (!getword(&p, realm, sizeof(realm)) ||
357 !getword(&p, hostnm, sizeof(hostnm))) {
358 radlog(L_ERR, "%s[%d]: syntax error", file, lineno);
363 c = rad_malloc(sizeof(REALM));
364 memset(c, 0, sizeof(REALM));
366 if ((s = strchr(hostnm, ':')) != NULL) {
368 c->auth_port = atoi(s);
369 c->acct_port = c->auth_port + 1;
371 c->auth_port = PW_AUTH_UDP_PORT;
372 c->acct_port = PW_ACCT_UDP_PORT;
375 if (strcmp(hostnm, "LOCAL") == 0) {
377 * Local realms don't have an IP address,
380 c->ipaddr.af = c->acct_ipaddr.af = AF_INET;
381 c->ipaddr.ipaddr.ip4addr.s_addr = c->acct_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
389 if (ip_hton(hostnm, AF_INET, &c->ipaddr) < 0) {
390 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
391 file, lineno, hostnm);
394 c->acct_ipaddr = c->ipaddr;
397 * Find the remote server in the "clients" list.
398 * If we can't find it, there's a big problem...
400 client = client_find_old(&c->ipaddr);
401 if (client == NULL) {
402 radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
403 file, lineno, hostnm, realm);
406 memcpy(c->secret, client->secret, sizeof(c->secret));
410 * Double-check lengths to be sure they're sane
412 if (strlen(hostnm) >= sizeof(c->server)) {
413 radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
415 (int) strlen(hostnm),
416 (int) sizeof(c->server) - 1);
419 if (strlen(realm) > sizeof(c->realm)) {
420 radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
423 (int) sizeof(c->realm) - 1);
428 * OK, they're sane, copy them over.
430 strcpy(c->realm, realm);
431 strcpy(c->server, hostnm);
432 c->striprealm = TRUE;
434 c->acct_active = TRUE;
436 while (getword(&p, opts, sizeof(opts))) {
437 if (strcmp(opts, "nostrip") == 0)
438 c->striprealm = FALSE;
439 if (strstr(opts, "noacct") != NULL)
441 if (strstr(opts, "trusted") != NULL)
443 if (strstr(opts, "notrealm") != NULL)
445 if (strstr(opts, "notsuffix") != NULL)
456 * Complain only if the realms file has content.
459 radlog(L_INFO, "Using deprecated realms file. Support for this will go away soon.");
464 #endif /* BUILDDBM */
467 * Mark a host inactive
469 void realm_disable(uint32_t ipaddr, int port)
475 for(cl = mainconfig.realms; cl; cl = cl->next) {
476 if (cl->ipaddr.af != AF_INET) rad_assert(0 == 1);
478 if ((ipaddr == cl->ipaddr.ipaddr.ip4addr.s_addr) &&
479 (port == cl->auth_port)) {
481 * If we've received a reply (any reply)
482 * from the home server in the time spent
483 * re-sending this request, then don't mark
486 if (cl->last_reply > (( now - mainconfig.proxy_retry_delay * mainconfig.proxy_retry_count ))) {
491 cl->wakeup = now + mainconfig.proxy_dead_time;
492 radlog(L_PROXY, "marking authentication server %s:%d for realm %s dead",
493 cl->server, port, cl->realm);
494 } else if ((ipaddr == cl->acct_ipaddr.ipaddr.ip4addr.s_addr) &&
495 (port == cl->acct_port)) {
496 if (cl->last_reply > (( now - mainconfig.proxy_retry_delay * mainconfig.proxy_retry_count ))) {
500 cl->acct_active = FALSE;
501 cl->acct_wakeup = now + mainconfig.proxy_dead_time;
502 radlog(L_PROXY, "marking accounting server %s:%d for realm %s dead",
503 cl->acct_server, port, cl->realm);
509 * Find a realm in the REALM list.
511 REALM *realm_find(const char *realm, int accounting)
514 REALM *default_realm = NULL;
521 * If we're passed a NULL realm pointer,
522 * then look for a "NULL" realm string.
528 for (cl = mainconfig.realms; cl; cl = cl->next) {
530 * Wake up any sleeping realm.
532 if (cl->wakeup <= now) {
535 if (cl->acct_wakeup <= now) {
536 cl->acct_active = TRUE;
540 * Asked for auth/acct, and the auth/acct server
541 * is not active. Skip it.
543 if ((!accounting && !cl->active) ||
544 (accounting && !cl->acct_active)) {
547 * We've been asked to NOT fall through
548 * to the DEFAULT realm if there are
549 * exact matches for this realm which are
552 if ((!mainconfig.proxy_fallback) &&
553 (strcasecmp(cl->realm, realm) == 0)) {
560 * If it matches exactly, return it.
562 * Note that we just want ONE live realm
563 * here. We don't care about round-robin, or
564 * scatter techniques, as that's more properly
565 * the responsibility of the proxying code.
567 if (strcasecmp(cl->realm, realm) == 0) {
572 * No default realm, try to set one.
574 if ((default_realm == NULL) &&
575 (strcmp(cl->realm, "DEFAULT") == 0)) {
578 } /* loop over all realms */
581 * There WAS one or more matches which were marked dead,
582 * AND there were NO live matches, AND we've been asked
583 * to NOT fall through to the DEFAULT realm. Therefore,
584 * we return NULL, which means "no match found".
586 if (!mainconfig.proxy_fallback && dead_match) {
587 if (mainconfig.wake_all_if_all_dead) {
589 for (cl = mainconfig.realms; cl; cl = cl->next) {
590 if(strcasecmp(cl->realm,realm) == 0) {
591 if (!accounting && !cl->active) {
595 else if (accounting &&
597 cl->acct_active = TRUE;
609 /* If we didn't find the realm 'NULL' don't return the
612 if ((strcmp(realm, "NULL")) == 0) {
617 * Didn't find anything that matched exactly, return the
618 * DEFAULT realm. We also return the DEFAULT realm if
619 * all matching realms were marked dead, and we were
620 * asked to fall through to the DEFAULT realm in this
623 return default_realm;
627 * Find a realm for a proxy reply by proxy's IP
629 * Note that we don't do anything else.
631 REALM *realm_findbyaddr(uint32_t ipaddr, int port)
636 * Note that we do NOT check for inactive realms!
638 * The purpose of this code is simply to find a matching
639 * source IP/Port pair, for a home server which is allowed
640 * to send us proxy replies. If we get a reply, then it
641 * doesn't matter if we think the realm is inactive.
643 for (cl = mainconfig.realms; cl != NULL; cl = cl->next) {
644 if (cl->ipaddr.af != AF_INET) rad_assert(0 == 1);
646 if ((ipaddr == cl->ipaddr.ipaddr.ip4addr.s_addr) &&
647 (port == cl->auth_port)) {
650 } else if ((ipaddr == cl->acct_ipaddr.ipaddr.ip4addr.s_addr) &&
651 (port == cl->acct_port)) {