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$";
28 #include "libradius.h"
33 # include <netinet/in.h>
44 extern int proxy_dead_time;
51 void pairlist_free(PAIR_LIST **pl)
55 for (p = *pl; p; p = next) {
56 if (p->name) free(p->name);
57 if (p->check) pairfree(&p->check);
58 if (p->reply) pairfree(&p->reply);
68 * If User-Password or Crypt-Password is set, but there is no
69 * Auth-Type, add one (kludge!).
71 static void auth_type_fixup(VALUE_PAIR **check)
78 * See if a password is present. Return right away
79 * if we see Auth-Type.
81 for (vp = *check; vp; vp = vp->next) {
82 if (vp->attribute == PW_AUTHTYPE)
84 if (vp->attribute == PW_PASSWORD) {
86 n = PW_AUTHTYPE_LOCAL;
88 if (vp->attribute == PW_CRYPT_PASSWORD) {
90 n = PW_AUTHTYPE_CRYPT;
98 * Add an Auth-Type attribute.
101 if ((vp = paircreate(PW_AUTHTYPE, PW_TYPE_INTEGER)) == NULL) {
102 radlog(L_CONS|L_ERR, "no memory");
106 vp->operator = T_OP_ADD;
107 strcpy(vp->strvalue, "Local");
112 for(vp = *check; vp; vp = vp->next) {
113 DEBUG2(" auth_type_fixup: %s [%d]", vp->name, vp->attribute);
119 #define FIND_MODE_NAME 0
120 #define FIND_MODE_REPLY 1
123 * Read the users, huntgroups or hints file.
124 * Return a PAIR_LIST.
126 int pairlist_read(const char *file, PAIR_LIST **list, int complain)
129 int mode = FIND_MODE_NAME;
133 VALUE_PAIR *check_tmp;
134 VALUE_PAIR *reply_tmp;
135 PAIR_LIST *pl = NULL, *last = NULL, *t;
138 LRAD_TOKEN parsecode;
142 * Open the file. The error message should be a little
145 if ((fp = fopen(file, "r")) == NULL) {
148 radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
149 file, strerror(errno));
155 * Read the entire file into memory for speed.
157 while(fgets(buffer, sizeof(buffer), fp) != NULL) {
159 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
160 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
164 if (buffer[0] == '#' || buffer[0] == '\n') continue;
166 if(mode == FIND_MODE_NAME) {
168 * Find the entry starting with the users name
170 if (isspace((int) buffer[0])) {
171 if (parsecode != T_EOL) {
173 "%s[%d]: Unexpected trailing comma for entry %s",
174 file, lineno, entry);
182 getword(&ptr, entry, sizeof(entry));
185 * Include another file if we see
188 if (strcasecmp(entry, "$include") == 0) {
189 while(isspace((int) *ptr))
192 while (!isspace((int) *ptr))
197 * If it's an absolute pathname,
198 * then use it verbatim.
200 * If not, then make the $include
201 * files *relative* to the current
205 strNcpy(newfile, file,
207 ptr = strrchr(newfile, '/');
213 if (pairlist_read(s, &t, 0) != 0) {
216 "%s[%d]: Could not open included file %s: %s",
217 file, lineno, s, strerror(errno));
226 while (last && last->next)
232 * Parse the check values
237 parsecode = userparse(ptr, &check_tmp);
238 if (parsecode == T_INVALID) {
241 "%s[%d]: Parse error (check) for entry %s: %s",
242 file, lineno, entry, librad_errstr);
245 } else if (parsecode == T_COMMA) {
247 "%s[%d]: Unexpected trailing comma in check item list for entry %s",
248 file, lineno, entry);
252 mode = FIND_MODE_REPLY;
256 if(*buffer == ' ' || *buffer == '\t') {
257 if (parsecode != T_COMMA) {
259 "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
260 file, lineno, entry);
266 * Parse the reply values
268 parsecode = userparse(buffer, &reply_tmp);
269 /* valid tokens are 1 or greater */
273 "%s[%d]: Parse error (reply) for entry %s: %s",
274 file, lineno, entry, librad_errstr);
281 * Done with this entry...
283 t = rad_malloc(sizeof(PAIR_LIST));
285 auth_type_fixup(&check_tmp);
286 memset(t, 0, sizeof(*t));
287 t->name = strdup(entry);
288 t->check = check_tmp;
289 t->reply = reply_tmp;
290 t->lineno = old_lineno;
299 mode = FIND_MODE_NAME;
306 * Make sure that we also read the last line of the file!
308 if (mode == FIND_MODE_REPLY) {
323 static void debug_pair_list(PAIR_LIST *pl)
328 printf("Pair list: %s\n", pl->name);
329 printf("** Check:\n");
330 for(vp = pl->check; vp; vp = vp->next) {
332 fprint_attr_val(stdout, vp);
335 printf("** Reply:\n");
336 for(vp = pl->reply; vp; vp = vp->next) {
338 fprint_attr_val(stdout, vp);
346 #ifndef BUILDDBM /* HACK HACK */
351 static void realm_free(REALM *cl)
363 * Read the realms file.
365 int read_realms_file(const char *file)
380 if ((fp = fopen(file, "r")) == NULL) {
381 /* The realms file is not mandatory. If it exists it will
382 be used, however, since the new style config files are
383 more robust and flexible they are more likely to get used.
384 So this is a non-fatal error. */
387 while(fgets(buffer, 256, fp) != NULL) {
389 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
390 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
393 if (buffer[0] == '#' || buffer[0] == '\n')
396 if (!getword(&p, realm, sizeof(realm)) ||
397 !getword(&p, hostnm, sizeof(hostnm))) {
398 radlog(L_ERR, "%s[%d]: syntax error", file, lineno);
402 c = rad_malloc(sizeof(REALM));
403 memset(c, 0, sizeof(REALM));
405 if ((s = strchr(hostnm, ':')) != NULL) {
407 c->auth_port = atoi(s);
408 c->acct_port = c->auth_port + 1;
410 c->auth_port = PW_AUTH_UDP_PORT;
411 c->acct_port = PW_ACCT_UDP_PORT;
414 if (strcmp(hostnm, "LOCAL") == 0) {
416 * Local realms don't have an IP address,
419 c->acct_ipaddr = c->ipaddr = htonl(INADDR_NONE);
421 c->auth_port = auth_port;
422 c->acct_port = acct_port;
426 c->ipaddr = ip_getaddr(hostnm);
427 c->acct_ipaddr = c->ipaddr;
429 if (c->ipaddr == htonl(INADDR_NONE)) {
430 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
431 file, lineno, hostnm);
436 * Find the remote server in the "clients" list.
437 * If we can't find it, there's a big problem...
439 client = client_find(c->ipaddr);
440 if (client == NULL) {
441 radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
442 file, lineno, hostnm, realm);
445 memcpy(c->secret, client->secret, sizeof(c->secret));
449 * Double-check lengths to be sure they're sane
451 if (strlen(hostnm) >= sizeof(c->server)) {
452 radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
454 strlen(hostnm), sizeof(c->server) - 1);
457 if (strlen(realm) > sizeof(c->realm)) {
458 radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
460 strlen(realm), sizeof(c->realm) - 1);
465 * OK, they're sane, copy them over.
467 strcpy(c->realm, realm);
468 strcpy(c->server, hostnm);
469 c->striprealm = TRUE;
471 c->acct_active = TRUE;
473 while (getword(&p, opts, sizeof(opts))) {
474 if (strcmp(opts, "nostrip") == 0)
475 c->striprealm = FALSE;
476 if (strstr(opts, "noacct") != NULL)
478 if (strstr(opts, "trusted") != NULL)
480 if (strstr(opts, "notrealm") != NULL)
482 if (strstr(opts, "notsuffix") != NULL)
494 #endif /* BUILDDBM */
497 * Mark a host inactive
499 void realm_disable(uint32_t ipaddr, int port)
505 for(cl = realms; cl; cl = cl->next)
506 if ((ipaddr == cl->ipaddr) && (port == cl->auth_port)) {
508 cl->wakeup = now + proxy_dead_time;
509 radlog(L_PROXY, "marking authentication server %s:%d for realm %s dead",
510 cl->server, port, cl->realm);
511 } else if ((ipaddr == cl->acct_ipaddr) && (port == cl->acct_port)) {
512 cl->acct_active = FALSE;
513 cl->acct_wakeup = now + proxy_dead_time;
514 radlog(L_PROXY, "marking accounting server %s:%d for realm %s dead",
515 cl->server, port, cl->realm);
520 * Find a realm in the REALM list.
522 REALM *realm_find(const char *realm, int acct)
525 REALM *default_realm = NULL;
532 * If we're passed a NULL realm pointer,
533 * then look for a "NULL" realm string.
539 for (cl = realms; cl; cl = cl->next) {
541 * Wake up any sleeping realm.
543 if (cl->wakeup <= now) {
546 if (cl->acct_wakeup <= now) {
547 cl->acct_active = TRUE;
551 * Asked for auth/acct, and the auth/acct server
552 * is not active. Skip it.
554 if ((!acct && !cl->active) ||
555 (acct && !cl->acct_active)) {
558 * We've been asked to NOT fall through
559 * to the DEFAULT realm if there are
560 * exact matches for this realm which are
563 if ((!proxy_fallback) &&
564 (strcasecmp(cl->realm, realm) == 0)) {
571 * If it matches exactly, return it.
573 if (strcasecmp(cl->realm, realm) == 0) {
578 * No default realm, try to set one.
580 if ((default_realm == NULL) &&
581 (strcmp(cl->realm, "DEFAULT") == 0)) {
584 } /* loop over all realms */
587 * There WAS one or more matches which were marked dead,
588 * AND there were NO live matches, AND we've been asked
589 * to NOT fall through to the DEFAULT realm. Therefore,
590 * we return NULL, which means "no match found".
592 if (!proxy_fallback && dead_match) {
597 * Didn't find anything that matched exactly, return the
598 * DEFAULT realm. We also return the DEFAULT realm if
599 * all matching realms were marked dead, and we were
600 * asked to fall through to the DEFAULT realm in this
603 return default_realm;
607 * Find a realm for a proxy reply by proxy's IP
609 REALM *realm_findbyaddr(uint32_t ipaddr, int port)
614 * Note that we do NOT check for inactive realms!
616 * If we get a packet from an end server, then we mark it
617 * as active, and return the realm.
619 for(cl = realms; cl != NULL; cl = cl->next)
620 if ((ipaddr == cl->ipaddr) && (port == cl->auth_port)) {
623 } else if ((ipaddr == cl->acct_ipaddr) && (port == cl->acct_port)) {
624 cl->acct_active = TRUE;