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 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)
383 if ((fp = fopen(file, "r")) == NULL) {
384 /* The realms file is not mandatory. If it exists it will
385 be used, however, since the new style config files are
386 more robust and flexible they are more likely to get used.
387 So this is a non-fatal error. */
390 while(fgets(buffer, 256, fp) != NULL) {
392 if (strchr(buffer, '\n') == NULL) {
393 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
396 if (buffer[0] == '#' || buffer[0] == '\n')
399 if (!getword(&p, realm, sizeof(realm)) ||
400 !getword(&p, hostnm, sizeof(hostnm))) {
401 radlog(L_ERR, "%s[%d]: syntax error", file, lineno);
405 c = rad_malloc(sizeof(REALM));
406 memset(c, 0, sizeof(REALM));
408 if ((s = strchr(hostnm, ':')) != NULL) {
410 c->auth_port = atoi(s);
411 c->acct_port = c->auth_port + 1;
413 c->auth_port = auth_port;
414 c->acct_port = acct_port;
417 if (strcmp(hostnm, "LOCAL") == 0) {
418 c->ipaddr = htonl(INADDR_LOOPBACK);
420 c->ipaddr = ip_getaddr(hostnm);
423 if (c->ipaddr == 0) {
424 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
425 file, lineno, hostnm);
430 * Find the remote server in the "clients" list.
431 * If we can't find it, there's a big problem...
433 client = client_find(c->ipaddr);
434 if (client == NULL) {
435 radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
436 file, lineno, hostnm, realm);
439 memcpy(c->secret, client->secret, sizeof(c->secret));
442 * Double-check lengths to be sure they're sane
444 if (strlen(hostnm) >= sizeof(c->server)) {
445 radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
447 strlen(hostnm), sizeof(c->server) - 1);
450 if (strlen(realm) > sizeof(c->realm)) {
451 radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
453 strlen(realm), sizeof(c->realm) - 1);
458 * OK, they're sane, copy them over.
460 strcpy(c->realm, realm);
461 strcpy(c->server, hostnm);
462 c->striprealm = TRUE;
465 while (getword(&p, opts, sizeof(opts))) {
466 if (strcmp(opts, "nostrip") == 0)
467 c->striprealm = FALSE;
468 if (strstr(opts, "noacct") != NULL)
470 if (strstr(opts, "trusted") != NULL)
472 if (strstr(opts, "notrealm") != NULL)
474 if (strstr(opts, "notsuffix") != NULL)
486 #endif /* BUILDDBM */
489 * Mark a host inactive
491 void realm_disable(uint32_t ipaddr)
497 for(cl = realms; cl; cl = cl->next)
498 if (ipaddr == cl->ipaddr) {
500 cl->wakeup = now + proxy_dead_time;
505 * Find a realm in the REALM list.
507 REALM *realm_find(const char *realm)
510 REALM *default_realm = NULL;
516 * If we're passed a NULL realm pointer,
517 * then look for a "NULL" realm string.
523 for (cl = realms; cl; cl = cl->next) {
525 * Wake up any sleeping realm.
527 if (cl->wakeup <= now) {
532 * It's not alive, skip it.
539 * If it matches exactly, return it.
541 if (strcmp(cl->realm, realm) == 0) {
546 * No default realm, try to set one.
548 if ((default_realm == NULL) &&
549 (strcmp(cl->realm, "DEFAULT") == 0)) {
552 } /* loop over all realms */
555 * Didn't find anything that matched exactly, return
558 return default_realm;
563 * Find a realm for a proxy reply by proxy's IP
565 REALM *realm_findbyaddr(uint32_t ipaddr)
570 * Note that we do NOT check for inactive realms!
572 * If we get a packet from an end server, then we mark it
573 * as active, and return the realm.
575 for(cl = realms; cl != NULL; cl = cl->next)
576 if (ipaddr == cl->ipaddr) {