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;
115 for(vp = check; vp; vp = vp->next) {
116 DEBUG2(" auth_type_fixup: %s [%d]", vp->name, vp->attribute);
122 #define FIND_MODE_NAME 0
123 #define FIND_MODE_REPLY 1
126 * Read the users, huntgroups or hints file.
127 * Return a PAIR_LIST.
129 int pairlist_read(const char *file, PAIR_LIST **list, int complain)
132 int mode = FIND_MODE_NAME;
136 VALUE_PAIR *check_tmp;
137 VALUE_PAIR *reply_tmp;
138 PAIR_LIST *pl = NULL, *last = NULL, *t;
141 LRAD_TOKEN parsecode;
145 * Open the file. The error message should be a little
148 if ((fp = fopen(file, "r")) == NULL) {
151 radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
152 file, strerror(errno));
158 * Read the entire file into memory for speed.
160 while(fgets(buffer, sizeof(buffer), fp) != NULL) {
162 if (strchr(buffer, '\n') == NULL) {
163 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
167 if (buffer[0] == '#' || buffer[0] == '\n') continue;
169 if(mode == FIND_MODE_NAME) {
171 * Find the entry starting with the users name
173 if (isspace(buffer[0])) {
174 if (parsecode != T_EOL) {
176 "%s[%d]: Unexpected trailing comma for entry %s",
177 file, lineno, entry);
185 getword(&ptr, entry, sizeof(entry));
188 * Include another file if we see
191 if (strcasecmp(entry, "$include") == 0) {
195 while (!isspace(*ptr))
200 * If it's an absolute pathname,
201 * then use it verbatim.
203 * If not, then make the $include
204 * files *relative* to the current
208 strNcpy(newfile, file,
210 ptr = strrchr(newfile, '/');
216 if (pairlist_read(s, &t, 0) != 0) {
219 "%s[%d]: Could not open included file %s: %s",
220 file, lineno, s, strerror(errno));
229 while (last && last->next)
235 * Parse the check values
240 parsecode = userparse(ptr, &check_tmp);
241 if (parsecode == T_INVALID) {
244 "%s[%d]: Parse error (check) for entry %s: %s",
245 file, lineno, entry, librad_errstr);
248 } else if (parsecode == T_COMMA) {
250 "%s[%d]: Unexpected trailing comma in check item list for entry %s",
251 file, lineno, entry);
255 mode = FIND_MODE_REPLY;
259 if(*buffer == ' ' || *buffer == '\t') {
260 if (parsecode != T_COMMA) {
262 "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
263 file, lineno, entry);
269 * Parse the reply values
271 parsecode = userparse(buffer, &reply_tmp);
275 "%s[%d]: Parse error (reply) for entry %s: %s",
276 file, lineno, entry, librad_errstr);
283 * Done with this entry...
285 t = rad_malloc(sizeof(PAIR_LIST));
287 auth_type_fixup(check_tmp);
288 memset(t, 0, sizeof(*t));
289 t->name = strdup(entry);
290 t->check = check_tmp;
291 t->reply = reply_tmp;
292 t->lineno = old_lineno;
301 mode = FIND_MODE_NAME;
308 * Make sure that we also read the last line of the file!
310 if (mode == FIND_MODE_REPLY) {
325 static void debug_pair_list(PAIR_LIST *pl)
330 printf("Pair list: %s\n", pl->name);
331 printf("** Check:\n");
332 for(vp = pl->check; vp; vp = vp->next) {
334 fprint_attr_val(stdout, vp);
337 printf("** Reply:\n");
338 for(vp = pl->reply; vp; vp = vp->next) {
340 fprint_attr_val(stdout, vp);
348 #ifndef BUILDDBM /* HACK HACK */
353 static void realm_free(REALM *cl)
365 * Read the realms file.
367 int read_realms_file(const char *file)
382 if ((fp = fopen(file, "r")) == NULL) {
383 /* The realms file is not mandatory. If it exists it will
384 be used, however, since the new style config files are
385 more robust and flexible they are more likely to get used.
386 So this is a non-fatal error. */
389 while(fgets(buffer, 256, fp) != NULL) {
391 if (strchr(buffer, '\n') == NULL) {
392 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
395 if (buffer[0] == '#' || buffer[0] == '\n')
398 if (!getword(&p, realm, sizeof(realm)) ||
399 !getword(&p, hostnm, sizeof(hostnm))) {
400 radlog(L_ERR, "%s[%d]: syntax error", file, lineno);
404 c = rad_malloc(sizeof(REALM));
405 memset(c, 0, sizeof(REALM));
407 if ((s = strchr(hostnm, ':')) != NULL) {
409 c->auth_port = atoi(s);
410 c->acct_port = c->auth_port + 1;
412 c->auth_port = auth_port;
413 c->acct_port = acct_port;
416 if (strcmp(hostnm, "LOCAL") == 0) {
418 * Local realms don't have an IP address,
421 c->acct_ipaddr = c->ipaddr = htonl(INADDR_NONE);
423 c->auth_port = auth_port;
424 c->acct_port = acct_port;
428 c->ipaddr = ip_getaddr(hostnm);
429 c->acct_ipaddr = c->ipaddr;
431 if (c->ipaddr == htonl(INADDR_NONE)) {
432 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
433 file, lineno, hostnm);
438 * Find the remote server in the "clients" list.
439 * If we can't find it, there's a big problem...
441 client = client_find(c->ipaddr);
442 if (client == NULL) {
443 radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
444 file, lineno, hostnm, realm);
447 memcpy(c->secret, client->secret, sizeof(c->secret));
451 * Double-check lengths to be sure they're sane
453 if (strlen(hostnm) >= sizeof(c->server)) {
454 radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
456 strlen(hostnm), sizeof(c->server) - 1);
459 if (strlen(realm) > sizeof(c->realm)) {
460 radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
462 strlen(realm), sizeof(c->realm) - 1);
467 * OK, they're sane, copy them over.
469 strcpy(c->realm, realm);
470 strcpy(c->server, hostnm);
471 c->striprealm = TRUE;
474 while (getword(&p, opts, sizeof(opts))) {
475 if (strcmp(opts, "nostrip") == 0)
476 c->striprealm = FALSE;
477 if (strstr(opts, "noacct") != NULL)
479 if (strstr(opts, "trusted") != NULL)
481 if (strstr(opts, "notrealm") != NULL)
483 if (strstr(opts, "notsuffix") != NULL)
495 #endif /* BUILDDBM */
498 * Mark a host inactive
500 void realm_disable(uint32_t ipaddr)
506 for(cl = realms; cl; cl = cl->next)
507 if ((ipaddr == cl->ipaddr) ||
508 (ipaddr == cl->acct_ipaddr)) {
510 cl->wakeup = now + proxy_dead_time;
515 * Find a realm in the REALM list.
517 REALM *realm_find(const char *realm)
520 REALM *default_realm = NULL;
526 * If we're passed a NULL realm pointer,
527 * then look for a "NULL" realm string.
533 for (cl = realms; cl; cl = cl->next) {
535 * Wake up any sleeping realm.
537 if (cl->wakeup <= now) {
542 * It's not alive, skip it.
549 * If it matches exactly, return it.
551 if (strcmp(cl->realm, realm) == 0) {
556 * No default realm, try to set one.
558 if ((default_realm == NULL) &&
559 (strcmp(cl->realm, "DEFAULT") == 0)) {
562 } /* loop over all realms */
565 * Didn't find anything that matched exactly, return
568 return default_realm;
573 * Find a realm for a proxy reply by proxy's IP
575 REALM *realm_findbyaddr(uint32_t ipaddr)
580 * Note that we do NOT check for inactive realms!
582 * If we get a packet from an end server, then we mark it
583 * as active, and return the realm.
585 for(cl = realms; cl != NULL; cl = cl->next)
586 if ((ipaddr == cl->ipaddr) ||
587 (ipaddr == cl->acct_ipaddr)) {