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 User-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;
105 strcpy(vp->strvalue, "Local");
110 for(vp = *check; vp; vp = vp->next) {
111 DEBUG2(" auth_type_fixup: %s [%d]", vp->name, vp->attribute);
117 #define FIND_MODE_NAME 0
118 #define FIND_MODE_REPLY 1
121 * Read the users, huntgroups or hints file.
122 * Return a PAIR_LIST.
124 int pairlist_read(const char *file, PAIR_LIST **list, int complain)
127 int mode = FIND_MODE_NAME;
131 VALUE_PAIR *check_tmp;
132 VALUE_PAIR *reply_tmp;
133 PAIR_LIST *pl = NULL, *last = NULL, *t;
136 LRAD_TOKEN parsecode;
140 * Open the file. The error message should be a little
143 if ((fp = fopen(file, "r")) == NULL) {
146 radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
147 file, strerror(errno));
153 * Read the entire file into memory for speed.
155 while(fgets(buffer, sizeof(buffer), fp) != NULL) {
157 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
158 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
162 if (buffer[0] == '#' || buffer[0] == '\n') continue;
164 if(mode == FIND_MODE_NAME) {
166 * Find the entry starting with the users name
168 if (isspace((int) buffer[0])) {
169 if (parsecode != T_EOL) {
171 "%s[%d]: Unexpected trailing comma for entry %s",
172 file, lineno, entry);
180 getword(&ptr, entry, sizeof(entry));
183 * Include another file if we see
186 if (strcasecmp(entry, "$include") == 0) {
187 while(isspace((int) *ptr))
190 while (!isspace((int) *ptr))
195 * If it's an absolute pathname,
196 * then use it verbatim.
198 * If not, then make the $include
199 * files *relative* to the current
203 strNcpy(newfile, file,
205 ptr = strrchr(newfile, '/');
211 if (pairlist_read(s, &t, 0) != 0) {
214 "%s[%d]: Could not open included file %s: %s",
215 file, lineno, s, strerror(errno));
224 while (last && last->next)
230 * Parse the check values
235 parsecode = userparse(ptr, &check_tmp);
236 if (parsecode == T_INVALID) {
239 "%s[%d]: Parse error (check) for entry %s: %s",
240 file, lineno, entry, librad_errstr);
243 } else if (parsecode == T_COMMA) {
245 "%s[%d]: Unexpected trailing comma in check item list for entry %s",
246 file, lineno, entry);
250 mode = FIND_MODE_REPLY;
254 if(*buffer == ' ' || *buffer == '\t') {
255 if (parsecode != T_COMMA) {
257 "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
258 file, lineno, entry);
264 * Parse the reply values
266 parsecode = userparse(buffer, &reply_tmp);
267 /* valid tokens are 1 or greater */
271 "%s[%d]: Parse error (reply) for entry %s: %s",
272 file, lineno, entry, librad_errstr);
279 * Done with this entry...
281 t = rad_malloc(sizeof(PAIR_LIST));
283 auth_type_fixup(&check_tmp);
284 memset(t, 0, sizeof(*t));
285 t->name = strdup(entry);
286 t->check = check_tmp;
287 t->reply = reply_tmp;
288 t->lineno = old_lineno;
297 mode = FIND_MODE_NAME;
304 * Make sure that we also read the last line of the file!
306 if (mode == FIND_MODE_REPLY) {
321 static void debug_pair_list(PAIR_LIST *pl)
326 printf("Pair list: %s\n", pl->name);
327 printf("** Check:\n");
328 for(vp = pl->check; vp; vp = vp->next) {
330 fprint_attr_val(stdout, vp);
333 printf("** Reply:\n");
334 for(vp = pl->reply; vp; vp = vp->next) {
336 fprint_attr_val(stdout, vp);
344 #ifndef BUILDDBM /* HACK HACK */
349 void realm_free(REALM *cl)
361 * Read the realms file.
363 int read_realms_file(const char *file)
374 realm_free(mainconfig.realms);
375 mainconfig.realms = NULL;
376 tail = &mainconfig.realms;
378 if ((fp = fopen(file, "r")) == NULL) {
379 /* The realms file is not mandatory. If it exists it will
380 be used, however, since the new style config files are
381 more robust and flexible they are more likely to get used.
382 So this is a non-fatal error. */
385 while(fgets(buffer, 256, fp) != NULL) {
387 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
388 radlog(L_ERR, "%s[%d]: line too long", file, lineno);
391 if (buffer[0] == '#' || buffer[0] == '\n')
394 if (!getword(&p, realm, sizeof(realm)) ||
395 !getword(&p, hostnm, sizeof(hostnm))) {
396 radlog(L_ERR, "%s[%d]: syntax error", file, lineno);
400 c = rad_malloc(sizeof(REALM));
401 memset(c, 0, sizeof(REALM));
403 if ((s = strchr(hostnm, ':')) != NULL) {
405 c->auth_port = atoi(s);
406 c->acct_port = c->auth_port + 1;
408 c->auth_port = PW_AUTH_UDP_PORT;
409 c->acct_port = PW_ACCT_UDP_PORT;
412 if (strcmp(hostnm, "LOCAL") == 0) {
414 * Local realms don't have an IP address,
417 c->acct_ipaddr = c->ipaddr = htonl(INADDR_NONE);
419 c->auth_port = auth_port;
420 c->acct_port = acct_port;
424 c->ipaddr = ip_getaddr(hostnm);
425 c->acct_ipaddr = c->ipaddr;
427 if (c->ipaddr == htonl(INADDR_NONE)) {
428 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
429 file, lineno, hostnm);
434 * Find the remote server in the "clients" list.
435 * If we can't find it, there's a big problem...
437 client = client_find(c->ipaddr);
438 if (client == NULL) {
439 radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
440 file, lineno, hostnm, realm);
443 memcpy(c->secret, client->secret, sizeof(c->secret));
447 * Double-check lengths to be sure they're sane
449 if (strlen(hostnm) >= sizeof(c->server)) {
450 radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
452 strlen(hostnm), sizeof(c->server) - 1);
455 if (strlen(realm) > sizeof(c->realm)) {
456 radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
458 strlen(realm), sizeof(c->realm) - 1);
463 * OK, they're sane, copy them over.
465 strcpy(c->realm, realm);
466 strcpy(c->server, hostnm);
467 c->striprealm = TRUE;
469 c->acct_active = TRUE;
471 while (getword(&p, opts, sizeof(opts))) {
472 if (strcmp(opts, "nostrip") == 0)
473 c->striprealm = FALSE;
474 if (strstr(opts, "noacct") != NULL)
476 if (strstr(opts, "trusted") != NULL)
478 if (strstr(opts, "notrealm") != NULL)
480 if (strstr(opts, "notsuffix") != NULL)
492 #endif /* BUILDDBM */
495 * Mark a host inactive
497 void realm_disable(uint32_t ipaddr, int port)
503 for(cl = mainconfig.realms; cl; cl = cl->next)
504 if ((ipaddr == cl->ipaddr) && (port == cl->auth_port)) {
506 cl->wakeup = now + mainconfig.proxy_dead_time;
507 radlog(L_PROXY, "marking authentication server %s:%d for realm %s dead",
508 cl->server, port, cl->realm);
509 } else if ((ipaddr == cl->acct_ipaddr) && (port == cl->acct_port)) {
510 cl->acct_active = FALSE;
511 cl->acct_wakeup = now + mainconfig.proxy_dead_time;
512 radlog(L_PROXY, "marking accounting server %s:%d for realm %s dead",
513 cl->server, port, cl->realm);
518 * Find a realm in the REALM list.
520 REALM *realm_find(const char *realm, int acct)
522 REALM *cl, *realmptr;
523 REALM *default_realm = NULL;
524 REALM *rr_array[maximum_proxies];
526 int dead_match = 0, efform = 0, p = 0, i = 0;
527 static int proxy_return;
531 * If we're passed a NULL realm pointer,
532 * then look for a "NULL" realm string.
538 for (cl = mainconfig.realms; cl; cl = cl->next) {
540 * Wake up any sleeping realm.
542 if (cl->wakeup <= now) {
545 if (cl->acct_wakeup <= now) {
546 cl->acct_active = TRUE;
550 * Asked for auth/acct, and the auth/acct server
551 * is not active. Skip it.
553 if ((!acct && !cl->active) ||
554 (acct && !cl->acct_active)) {
557 * We've been asked to NOT fall through
558 * to the DEFAULT realm if there are
559 * exact matches for this realm which are
562 if ((!mainconfig.proxy_fallback) &&
563 (strcasecmp(cl->realm, realm) == 0)) {
570 * If it matches exactly, return it.
572 if (strcasecmp(cl->realm, realm) == 0) {
574 * Seperate parsing of list for round-robin
576 if(cl->total > 1 && cl->ldflag == 1) {
577 /*Get all of the realms from initial list*/
578 for(i = 1; i <= cl->total; i++) {
579 for(realmptr = mainconfig.realms; realmptr;
580 realmptr = realmptr->next) {
581 if((strcasecmp(realmptr->realm,
583 (realmptr->node == i)) {
584 rr_array[i] = realmptr;
585 if(realmptr->active == TRUE)
594 /*if only one realm active, return it*/
596 for (p = 1; p < i; p++) {
597 realmptr = rr_array[p];
598 if(realmptr->active == TRUE) {
603 for(p = 1; p < i; p++) {
604 realmptr = rr_array[p];
605 if(realmptr->chose == 1) {
613 * been returned as access-reply
616 if(efform == cl->total && proxy_return == 0) {
617 for(p = 1; p < i; p++) {
618 realmptr = rr_array[p];
624 * if this realm hasn't been chosen and
625 * this is not being returned for
627 * else if the realm has been chosen
628 * and this is for access-reply
629 * else this realm is dead (reset if
630 * this is the last realm in the list)
633 for(p = 1; p < i; p++) {
634 realmptr = rr_array[p];
635 if((realmptr->chose == 0) &&
636 (proxy_return < realmptr->node) &&
637 (realmptr->active == TRUE && realmptr->acct_active == TRUE)
639 proxy_return = realmptr->node;
643 else if ((realmptr->chose == 1) &&
644 (proxy_return == realmptr->node)
646 if(proxy_return + 1 > realmptr->total) {
654 if((realmptr->active == FALSE ||
655 realmptr->acct_active == FALSE ) &&
656 (realmptr->node == realmptr->total)
666 * else we have single
667 * realm or non-rr realm
676 * No default realm, try to set one.
678 if ((default_realm == NULL) &&
679 (strcmp(cl->realm, "DEFAULT") == 0)) {
682 } /* loop over all realms */
685 * There WAS one or more matches which were marked dead,
686 * AND there were NO live matches, AND we've been asked
687 * to NOT fall through to the DEFAULT realm. Therefore,
688 * we return NULL, which means "no match found".
690 if (!mainconfig.proxy_fallback && dead_match) {
695 * Didn't find anything that matched exactly, return the
696 * DEFAULT realm. We also return the DEFAULT realm if
697 * all matching realms were marked dead, and we were
698 * asked to fall through to the DEFAULT realm in this
701 return default_realm;
705 * Find a realm for a proxy reply by proxy's IP
707 REALM *realm_findbyaddr(uint32_t ipaddr, int port)
712 * Note that we do NOT check for inactive realms!
714 * If we get a packet from an end server, then we mark it
715 * as active, and return the realm.
717 for(cl = mainconfig.realms; cl != NULL; cl = cl->next)
718 if ((ipaddr == cl->ipaddr) && (port == cl->auth_port)) {
721 } else if ((ipaddr == cl->acct_ipaddr) && (port == cl->acct_port)) {
722 cl->acct_active = TRUE;
730 * Catch any errors in set-up of RR list or exceeding max_proxies
732 void check_proxies(int max_config) {
735 maximum_proxies = max_config;
736 for(rptr=mainconfig.realms; rptr; rptr = rptr->next) {
737 if(rptr->total > max_config || rptr->total >= 1) {
738 for(next = mainconfig.realms; next; next = next->next) {
739 if(next->ldflag != 0 &&
742 "Invalid load balance flag on realm: %s entry %d\n",
743 next->realm, next->node);
746 else if((strcasecmp(rptr->realm, next->realm) == 0) &&
747 rptr->ldflag != next->ldflag){
749 "Inconsistent ldflag for realm: %s entries %d and %d.\n",
750 rptr->realm, rptr->node, next->node);
753 else if (next->total > max_config) {
755 "Too many entries (%d) for realm: %s. Max is %d.\n",
756 next->total, next->realm, max_config);