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.
97 * FIXME: put Auth-Type _first_ (doesn't matter now,
98 * might matter some day).
101 if ((vp = paircreate(PW_AUTHTYPE, PW_TYPE_INTEGER)) == NULL) {
102 radlog(L_CONS|L_ERR, "no memory");
106 vp->operator = T_OP_ADD;
114 #define FIND_MODE_NAME 0
115 #define FIND_MODE_REPLY 1
118 * Read the users, huntgroups or hints file.
119 * Return a PAIR_LIST.
121 int pairlist_read(const char *file, PAIR_LIST **list, int complain)
124 int mode = FIND_MODE_NAME;
128 VALUE_PAIR *check_tmp;
129 VALUE_PAIR *reply_tmp;
130 PAIR_LIST *pl = NULL, *last = NULL, *t;
137 * Open the file. The error message should be a little
140 if ((fp = fopen(file, "r")) == NULL) {
141 if (!complain) return -1;
142 radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
143 file, strerror(errno));
149 * Read the entire file into memory for speed.
151 while(fgets(buffer, sizeof(buffer), fp) != NULL) {
153 if (strchr(buffer, '\n') == NULL) {
154 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
158 if (buffer[0] == '#' || buffer[0] == '\n') continue;
160 if(mode == FIND_MODE_NAME) {
162 * Find the entry starting with the users name
164 if (isspace(buffer[0])) {
165 if (parsecode != T_EOL) {
167 "%s[%d]: Unexpected trailing comma for entry %s",
168 file, lineno, entry);
176 getword(&ptr, entry, sizeof(entry));
179 * Include another file if we see
182 if (strcasecmp(entry, "$include") == 0) {
186 while (!isspace(*ptr))
191 * If it's an absolute pathname,
192 * then use it verbatim.
194 * If not, then make the $include
195 * files *relative* to the current
199 strNcpy(newfile, file,
201 ptr = strrchr(newfile, '/');
207 if (pairlist_read(s, &t, 0) != 0) {
210 "%s[%d]: Could not open included file %s: %s",
211 file, lineno, s, strerror(errno));
220 while (last && last->next)
226 * Parse the check values
231 parsecode = userparse(ptr, &check_tmp);
235 "%s[%d]: Parse error (check) for entry %s: %s",
236 file, lineno, entry, librad_errstr);
239 } else if (parsecode == T_COMMA) {
241 "%s[%d]: Unexpected trailing comma in check item list for entry %s",
242 file, lineno, entry);
246 mode = FIND_MODE_REPLY;
250 if(*buffer == ' ' || *buffer == '\t') {
251 if (parsecode != T_COMMA) {
253 "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
254 file, lineno, entry);
260 * Parse the reply values
262 parsecode = userparse(buffer, &reply_tmp);
266 "%s[%d]: Parse error (reply) for entry %s: %s",
267 file, lineno, entry, librad_errstr);
274 * Done with this entry...
276 t = rad_malloc(sizeof(PAIR_LIST));
278 auth_type_fixup(check_tmp);
279 memset(t, 0, sizeof(*t));
280 t->name = strdup(entry);
281 t->check = check_tmp;
282 t->reply = reply_tmp;
283 t->lineno = old_lineno;
292 mode = FIND_MODE_NAME;
299 * Make sure that we also read the last line of the file!
301 if (mode == FIND_MODE_REPLY) {
316 static void debug_pair_list(PAIR_LIST *pl)
321 printf("Pair list: %s\n", pl->name);
322 printf("** Check:\n");
323 for(vp = pl->check; vp; vp = vp->next) {
325 fprint_attr_val(stdout, vp);
328 printf("** Reply:\n");
329 for(vp = pl->reply; vp; vp = vp->next) {
331 fprint_attr_val(stdout, vp);
339 #ifndef BUILDDBM /* HACK HACK */
344 static void realm_free(REALM *cl)
356 * Read the realms file.
358 int read_realms_file(const char *file)
373 if ((fp = fopen(file, "r")) == NULL) {
374 #if 1 /* For now - realms file is not obligatory */
377 radlog(L_CONS|L_ERR, "cannot open %s", file);
381 while(fgets(buffer, 256, fp) != NULL) {
383 if (strchr(buffer, '\n') == NULL) {
384 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
387 if (buffer[0] == '#' || buffer[0] == '\n')
390 if (!getword(&p, realm, sizeof(realm)) ||
391 !getword(&p, hostnm, sizeof(hostnm))) {
392 radlog(L_ERR, "%s[%d]: syntax error", file, lineno);
396 c = rad_malloc(sizeof(REALM));
397 memset(c, 0, sizeof(REALM));
399 if ((s = strchr(hostnm, ':')) != NULL) {
401 c->auth_port = atoi(s);
402 c->acct_port = c->auth_port + 1;
404 c->auth_port = auth_port;
405 c->acct_port = acct_port;
408 if (strcmp(hostnm, "LOCAL") == 0) {
409 c->ipaddr = htonl(INADDR_LOOPBACK);
411 c->ipaddr = ip_getaddr(hostnm);
414 if (c->ipaddr == 0) {
415 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
416 file, lineno, hostnm);
421 * Find the remote server in the "clients" list.
422 * If we can't find it, there's a big problem...
424 client = client_find(c->ipaddr);
425 if (client == NULL) {
426 radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
427 file, lineno, hostnm, realm);
430 memcpy(c->secret, client->secret, sizeof(c->secret));
433 * Double-check lengths to be sure they're sane
435 if (strlen(hostnm) >= sizeof(c->server)) {
436 radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
438 strlen(hostnm), sizeof(c->server) - 1);
441 if (strlen(realm) > sizeof(c->realm)) {
442 radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
444 strlen(realm), sizeof(c->realm) - 1);
449 * OK, they're sane, copy them over.
451 strcpy(c->realm, realm);
452 strcpy(c->server, hostnm);
453 c->striprealm = TRUE;
455 while (getword(&p, opts, sizeof(opts))) {
456 if (strcmp(opts, "nostrip") == 0)
457 c->striprealm = FALSE;
458 if (strstr(opts, "noacct") != NULL)
460 if (strstr(opts, "trusted") != NULL)
462 if (strstr(opts, "notrealm") != NULL)
464 if (strstr(opts, "notsuffix") != NULL)
475 #endif /* BUILDDBM */
478 * Find a realm in the REALM list.
480 REALM *realm_find(const char *realm)
485 * If we're passed a NULL realm pointer,
486 * then look for a "NULL" realm string.
492 for(cl = realms; cl; cl = cl->next)
493 if (strcmp(cl->realm, realm) == 0)
496 for(cl = realms; cl; cl = cl->next)
497 if (strcmp(cl->realm, "DEFAULT") == 0)
504 * Find a realm for a proxy reply by proxy's IP
506 REALM *realm_findbyaddr(uint32_t ipaddr)
510 for(cl = realms; cl; cl = cl->next)
511 if (ipaddr == cl->ipaddr)