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>
49 void pairlist_free(PAIR_LIST **pl)
53 for (p = *pl; p; p = next) {
54 if (p->name) free(p->name);
55 if (p->check) pairfree(&p->check);
56 if (p->reply) pairfree(&p->reply);
66 * If Password or Crypt-Password is set, but there is no
67 * Auth-Type, add one (kludge!).
69 static void auth_type_fixup(VALUE_PAIR *check)
76 * See if a password is present. Return right away
77 * if we see Auth-Type.
79 for (vp = check; vp; vp = vp->next) {
80 if (vp->attribute == PW_AUTHTYPE)
82 if (vp->attribute == PW_PASSWORD) {
84 n = PW_AUTHTYPE_LOCAL;
86 if (vp->attribute == PW_CRYPT_PASSWORD) {
88 n = PW_AUTHTYPE_CRYPT;
96 * Add an Auth-Type attribute.
99 if ((vp = paircreate(PW_AUTHTYPE, PW_TYPE_INTEGER)) == NULL) {
100 radlog(L_CONS|L_ERR, "no memory");
104 vp->operator = T_OP_ADD;
113 for(vp = check; vp; vp = vp->next) {
114 DEBUG2(" auth_type_fixup: %s [%d]", vp->name, vp->attribute);
120 #define FIND_MODE_NAME 0
121 #define FIND_MODE_REPLY 1
124 * Read the users, huntgroups or hints file.
125 * Return a PAIR_LIST.
127 int pairlist_read(const char *file, PAIR_LIST **list, int complain)
130 int mode = FIND_MODE_NAME;
134 VALUE_PAIR *check_tmp;
135 VALUE_PAIR *reply_tmp;
136 PAIR_LIST *pl = NULL, *last = NULL, *t;
139 LRAD_TOKEN parsecode;
143 * Open the file. The error message should be a little
146 if ((fp = fopen(file, "r")) == NULL) {
149 radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
150 file, strerror(errno));
156 * Read the entire file into memory for speed.
158 while(fgets(buffer, sizeof(buffer), fp) != NULL) {
160 if (strchr(buffer, '\n') == NULL) {
161 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
165 if (buffer[0] == '#' || buffer[0] == '\n') continue;
167 if(mode == FIND_MODE_NAME) {
169 * Find the entry starting with the users name
171 if (isspace(buffer[0])) {
172 if (parsecode != T_EOL) {
174 "%s[%d]: Unexpected trailing comma for entry %s",
175 file, lineno, entry);
183 getword(&ptr, entry, sizeof(entry));
186 * Include another file if we see
189 if (strcasecmp(entry, "$include") == 0) {
193 while (!isspace(*ptr))
198 * If it's an absolute pathname,
199 * then use it verbatim.
201 * If not, then make the $include
202 * files *relative* to the current
206 strNcpy(newfile, file,
208 ptr = strrchr(newfile, '/');
214 if (pairlist_read(s, &t, 0) != 0) {
217 "%s[%d]: Could not open included file %s: %s",
218 file, lineno, s, strerror(errno));
227 while (last && last->next)
233 * Parse the check values
238 parsecode = userparse(ptr, &check_tmp);
239 if (parsecode == T_INVALID) {
242 "%s[%d]: Parse error (check) for entry %s: %s",
243 file, lineno, entry, librad_errstr);
246 } else if (parsecode == T_COMMA) {
248 "%s[%d]: Unexpected trailing comma in check item list for entry %s",
249 file, lineno, entry);
253 mode = FIND_MODE_REPLY;
257 if(*buffer == ' ' || *buffer == '\t') {
258 if (parsecode != T_COMMA) {
260 "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
261 file, lineno, entry);
267 * Parse the reply values
269 parsecode = userparse(buffer, &reply_tmp);
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 (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 = auth_port;
411 c->acct_port = acct_port;
414 if (strcmp(hostnm, "LOCAL") == 0) {
415 c->ipaddr = htonl(INADDR_LOOPBACK);
417 c->ipaddr = ip_getaddr(hostnm);
420 if (c->ipaddr == 0) {
421 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
422 file, lineno, hostnm);
427 * Find the remote server in the "clients" list.
428 * If we can't find it, there's a big problem...
430 client = client_find(c->ipaddr);
431 if (client == NULL) {
432 radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
433 file, lineno, hostnm, realm);
436 memcpy(c->secret, client->secret, sizeof(c->secret));
439 * Double-check lengths to be sure they're sane
441 if (strlen(hostnm) >= sizeof(c->server)) {
442 radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
444 strlen(hostnm), sizeof(c->server) - 1);
447 if (strlen(realm) > sizeof(c->realm)) {
448 radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
450 strlen(realm), sizeof(c->realm) - 1);
455 * OK, they're sane, copy them over.
457 strcpy(c->realm, realm);
458 strcpy(c->server, hostnm);
459 c->striprealm = TRUE;
461 while (getword(&p, opts, sizeof(opts))) {
462 if (strcmp(opts, "nostrip") == 0)
463 c->striprealm = FALSE;
464 if (strstr(opts, "noacct") != NULL)
466 if (strstr(opts, "trusted") != NULL)
468 if (strstr(opts, "notrealm") != NULL)
470 if (strstr(opts, "notsuffix") != NULL)
481 #endif /* BUILDDBM */
484 * Find a realm in the REALM list.
486 REALM *realm_find(const char *realm)
491 * If we're passed a NULL realm pointer,
492 * then look for a "NULL" realm string.
498 for(cl = realms; cl; cl = cl->next)
499 if (strcmp(cl->realm, realm) == 0)
503 for(cl = realms; cl; cl = cl->next)
504 if (strcmp(cl->realm, "DEFAULT") == 0)
511 * Find a realm for a proxy reply by proxy's IP
513 REALM *realm_findbyaddr(uint32_t ipaddr)
517 for(cl = realms; cl != NULL; cl = cl->next)
518 if (ipaddr == cl->ipaddr)