Move RADCLIENT* in mainconfig to rbtree's. This means that
[freeradius.git] / src / main / files.c
1 /*
2  * files.c      Read config files into memory.
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  */
24
25 static const char rcsid[] = "$Id$";
26
27 #include "autoconf.h"
28
29 #include <sys/stat.h>
30
31 #ifdef HAVE_NETINET_IN_H
32 #       include <netinet/in.h>
33 #endif
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <netdb.h>
38 #include <ctype.h>
39 #include <fcntl.h>
40
41 #include "radiusd.h"
42 #include "rad_assert.h"
43
44 /*
45  *      Free a PAIR_LIST
46  */
47 void pairlist_free(PAIR_LIST **pl)
48 {
49         PAIR_LIST *p, *next;
50
51         for (p = *pl; p; p = next) {
52                 if (p->name) free(p->name);
53                 if (p->check) pairfree(&p->check);
54                 if (p->reply) pairfree(&p->reply);
55                 next = p->next;
56                 free(p);
57         }
58         *pl = NULL;
59 }
60
61
62 #define FIND_MODE_NAME  0
63 #define FIND_MODE_REPLY 1
64
65 /*
66  *      Read the users, huntgroups or hints file.
67  *      Return a PAIR_LIST.
68  */
69 int pairlist_read(const char *file, PAIR_LIST **list, int complain)
70 {
71         FILE *fp;
72         int mode = FIND_MODE_NAME;
73         char entry[256];
74         char buffer[8192];
75         char *ptr, *s;
76         VALUE_PAIR *check_tmp;
77         VALUE_PAIR *reply_tmp;
78         PAIR_LIST *pl = NULL, *t;
79         PAIR_LIST **last = &pl;
80         int lineno = 0;
81         int old_lineno = 0;
82         LRAD_TOKEN parsecode;
83         char newfile[8192];
84
85         /*
86          *      Open the file.  The error message should be a little
87          *      more useful...
88          */
89         if ((fp = fopen(file, "r")) == NULL) {
90                 if (!complain)
91                         return -1;
92                 radlog(L_CONS|L_ERR, "Couldn't open %s for reading: %s",
93                                 file, strerror(errno));
94                 return -1;
95         }
96
97         parsecode = T_EOL;
98         /*
99          *      Read the entire file into memory for speed.
100          */
101         while(fgets(buffer, sizeof(buffer), fp) != NULL) {
102                 lineno++;
103                 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
104                         radlog(L_ERR, "%s[%d]: line too long", file, lineno);
105                         pairlist_free(&pl);
106                         return -1;
107                 }
108                 if (buffer[0] == '#' || buffer[0] == '\n') continue;
109
110                 /*
111                  *      If the line contains nothing but whitespace,
112                  *      ignore it.
113                  */
114                 ptr = buffer;
115                 while ((ptr[0] == ' ') ||
116                        (ptr[0] == '\t') ||
117                        (ptr[0] == '\r') ||
118                        (ptr[0] == '\n')) {
119                         ptr++;
120                 }
121                 if (ptr[0] == '\0') continue;
122
123 parse_again:
124                 if(mode == FIND_MODE_NAME) {
125                         /*
126                          *      Find the entry starting with the users name
127                          */
128                         if (isspace((int) buffer[0]))  {
129                                 if (parsecode != T_EOL) {
130                                         radlog(L_ERR|L_CONS,
131                                                "%s[%d]: Unexpected trailing comma for entry %s",
132                                                file, lineno, entry);
133                                         fclose(fp);
134                                         return -1;
135                                 }
136                                 continue;
137                         }
138
139                         ptr = buffer;
140                         getword(&ptr, entry, sizeof(entry));
141
142                         /*
143                          *      Include another file if we see
144                          *      $INCLUDE filename
145                          */
146                         if (strcasecmp(entry, "$include") == 0) {
147                                 while(isspace((int) *ptr))
148                                         ptr++;
149                                 s = ptr;
150                                 while (!isspace((int) *ptr))
151                                         ptr++;
152                                 *ptr = 0;
153
154                                 /*
155                                  *      If it's an absolute pathname,
156                                  *      then use it verbatim.
157                                  *
158                                  *      If not, then make the $include
159                                  *      files *relative* to the current
160                                  *      file.
161                                  */
162                                 if (*s != '/') {
163                                         strNcpy(newfile, file,
164                                                 sizeof(newfile));
165                                         ptr = strrchr(newfile, '/');
166                                         strcpy(ptr + 1, s);
167                                         s = newfile;
168                                 }
169
170                                 t = NULL;
171                                 if (pairlist_read(s, &t, 0) != 0) {
172                                         pairlist_free(&pl);
173                                         radlog(L_ERR|L_CONS,
174                                                "%s[%d]: Could not open included file %s: %s",
175                                                file, lineno, s, strerror(errno));
176                                         fclose(fp);
177                                 return -1;
178                                 }
179                                 *last = t;
180
181                                 /*
182                                  *      t may be NULL, it may have one
183                                  *      entry, or it may be a linked list
184                                  *      of entries.  Go to the end of the
185                                  *      list.
186                                  */
187                                 while (*last)
188                                         last = &((*last)->next);
189                                 continue;
190                         }
191
192                         /*
193                          *      Parse the check values
194                          */
195                         check_tmp = NULL;
196                         reply_tmp = NULL;
197                         old_lineno = lineno;
198                         parsecode = userparse(ptr, &check_tmp);
199                         if (parsecode == T_OP_INVALID) {
200                                 pairlist_free(&pl);
201                                 radlog(L_ERR|L_CONS,
202                                 "%s[%d]: Parse error (check) for entry %s: %s",
203                                         file, lineno, entry, librad_errstr);
204                                 fclose(fp);
205                                 return -1;
206                         } else if (parsecode == T_COMMA) {
207                                 radlog(L_ERR|L_CONS,
208                                        "%s[%d]: Unexpected trailing comma in check item list for entry %s",
209                                        file, lineno, entry);
210                                 fclose(fp);
211                                 return -1;
212                         }
213                         mode = FIND_MODE_REPLY;
214                         parsecode = T_COMMA;
215                 }
216                 else {
217                         if(*buffer == ' ' || *buffer == '\t') {
218                                 if (parsecode != T_COMMA) {
219                                         radlog(L_ERR|L_CONS,
220                                                "%s[%d]: Syntax error: Previous line is missing a trailing comma for entry %s",
221                                                file, lineno, entry);
222                                         fclose(fp);
223                                         return -1;
224                                 }
225
226                                 /*
227                                  *      Parse the reply values
228                                  */
229                                 parsecode = userparse(buffer, &reply_tmp);
230                                 /* valid tokens are 1 or greater */
231                                 if (parsecode < 1) {
232                                         pairlist_free(&pl);
233                                         radlog(L_ERR|L_CONS,
234                                                "%s[%d]: Parse error (reply) for entry %s: %s",
235                                                file, lineno, entry, librad_errstr);
236                                         fclose(fp);
237                                         return -1;
238                                 }
239                         }
240                         else {
241                                 /*
242                                  *      Done with this entry...
243                                  */
244                                 t = rad_malloc(sizeof(PAIR_LIST));
245
246                                 memset(t, 0, sizeof(*t));
247                                 t->name = strdup(entry);
248                                 t->check = check_tmp;
249                                 t->reply = reply_tmp;
250                                 t->lineno = old_lineno;
251                                 check_tmp = NULL;
252                                 reply_tmp = NULL;
253
254                                 *last = t;
255                                 last = &(t->next);
256
257                                 mode = FIND_MODE_NAME;
258                                 if (buffer[0] != 0)
259                                         goto parse_again;
260                         }
261                 }
262         }
263         /*
264          *      Make sure that we also read the last line of the file!
265          */
266         if (mode == FIND_MODE_REPLY) {
267                 buffer[0] = 0;
268                 goto parse_again;
269         }
270         fclose(fp);
271
272         *list = pl;
273         return 0;
274 }
275
276
277 /*
278  *      Debug code.
279  */
280 #if 0
281 static void debug_pair_list(PAIR_LIST *pl)
282 {
283         VALUE_PAIR *vp;
284
285         while(pl) {
286                 printf("Pair list: %s\n", pl->name);
287                 printf("** Check:\n");
288                 for(vp = pl->check; vp; vp = vp->next) {
289                         printf("    ");
290                         fprint_attr_val(stdout, vp);
291                         printf("\n");
292                 }
293                 printf("** Reply:\n");
294                 for(vp = pl->reply; vp; vp = vp->next) {
295                         printf("    ");
296                         fprint_attr_val(stdout, vp);
297                         printf("\n");
298                 }
299                 pl = pl->next;
300         }
301 }
302 #endif
303
304 #ifndef BUILDDBM /* HACK HACK */
305
306 /*
307  *      Free a REALM list.
308  */
309 void realm_free(REALM *cl)
310 {
311         REALM *next;
312
313         while(cl) {
314                 next = cl->next;
315                 free(cl);
316                 cl = next;
317         }
318 }
319
320 /*
321  *      Read the realms file.
322  */
323 int read_realms_file(const char *file)
324 {
325         FILE *fp;
326         char buffer[256];
327         char realm[256];
328         char hostnm[256];
329         char opts[256];
330         char *s, *p;
331         int lineno = 0;
332         REALM *c, **tail;
333         int got_realm = FALSE;
334
335         realm_free(mainconfig.realms);
336         mainconfig.realms = NULL;
337         tail = &mainconfig.realms;
338
339         if ((fp = fopen(file, "r")) == NULL) {
340                 /* The realms file is not mandatory.  If it exists it will
341                    be used, however, since the new style config files are
342                    more robust and flexible they are more likely to get used.
343                    So this is a non-fatal error.  */
344                 return 0;
345         }
346
347         while(fgets(buffer, 256, fp) != NULL) {
348                 lineno++;
349                 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
350                         radlog(L_ERR, "%s[%d]: line too long", file, lineno);
351                         return -1;
352                 }
353                 if (buffer[0] == '#' || buffer[0] == '\n')
354                         continue;
355                 p = buffer;
356                 if (!getword(&p, realm, sizeof(realm)) ||
357                                 !getword(&p, hostnm, sizeof(hostnm))) {
358                         radlog(L_ERR, "%s[%d]: syntax error", file, lineno);
359                         continue;
360                 }
361
362                 got_realm = TRUE;
363                 c = rad_malloc(sizeof(REALM));
364                 memset(c, 0, sizeof(REALM));
365
366                 if ((s = strchr(hostnm, ':')) != NULL) {
367                         *s++ = 0;
368                         c->auth_port = atoi(s);
369                         c->acct_port = c->auth_port + 1;
370                 } else {
371                         c->auth_port = PW_AUTH_UDP_PORT;
372                         c->acct_port = PW_ACCT_UDP_PORT;
373                 }
374
375                 if (strcmp(hostnm, "LOCAL") == 0) {
376                         /*
377                          *      Local realms don't have an IP address,
378                          *      secret, or port.
379                          */
380                         c->ipaddr.af = c->acct_ipaddr.af = AF_INET;
381                         c->ipaddr.ipaddr.ip4addr.s_addr = c->acct_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
382                         c->secret[0] = '\0';
383                         c->auth_port = 0;
384                         c->acct_port = 0;
385
386                 } else {
387                         RADCLIENT *client;
388
389                         if (ip_hton(hostnm, AF_INET, &c->ipaddr) < 0) {
390                                 radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
391                                        file, lineno, hostnm);
392                                 return -1;
393                         }
394                         c->acct_ipaddr = c->ipaddr;
395
396                         /*
397                          *      Find the remote server in the "clients" list.
398                          *      If we can't find it, there's a big problem...
399                          */
400                         client = client_find_old(&c->ipaddr);
401                         if (client == NULL) {
402                           radlog(L_CONS|L_ERR, "%s[%d]: Cannot find 'clients' file entry of remote server %s for realm \"%s\"",
403                                  file, lineno, hostnm, realm);
404                           return -1;
405                         }
406                         memcpy(c->secret, client->secret, sizeof(c->secret));
407                 }
408
409                 /*
410                  *      Double-check lengths to be sure they're sane
411                  */
412                 if (strlen(hostnm) >= sizeof(c->server)) {
413                         radlog(L_ERR, "%s[%d]: server name of length %d is greater than the allowed maximum of %d.",
414                                file, lineno,
415                                (int) strlen(hostnm),
416                                (int) sizeof(c->server) - 1);
417                         return -1;
418                 }
419                 if (strlen(realm) > sizeof(c->realm)) {
420                         radlog(L_ERR, "%s[%d]: realm of length %d is greater than the allowed maximum of %d.",
421                                file, lineno,
422                                (int) strlen(realm),
423                                (int) sizeof(c->realm) - 1);
424                         return -1;
425                 }
426
427                 /*
428                  *      OK, they're sane, copy them over.
429                  */
430                 strcpy(c->realm, realm);
431                 strcpy(c->server, hostnm);
432                 c->striprealm = TRUE;
433                 c->active = TRUE;
434                 c->acct_active = TRUE;
435
436                 while (getword(&p, opts, sizeof(opts))) {
437                         if (strcmp(opts, "nostrip") == 0)
438                                 c->striprealm = FALSE;
439                         if (strstr(opts, "noacct") != NULL)
440                                 c->acct_port = 0;
441                         if (strstr(opts, "trusted") != NULL)
442                                 c->trusted = 1;
443                         if (strstr(opts, "notrealm") != NULL)
444                                 c->notrealm = 1;
445                         if (strstr(opts, "notsuffix") != NULL)
446                                 c->notrealm = 1;
447                 }
448
449                 c->next = NULL;
450                 *tail = c;
451                 tail = &c->next;
452         }
453         fclose(fp);
454
455         /*
456          *      Complain only if the realms file has content.
457          */
458         if (got_realm) {
459                 radlog(L_INFO, "Using deprecated realms file.  Support for this will go away soon.");
460         }
461
462         return 0;
463 }
464 #endif /* BUILDDBM */
465
466 /*
467  * Mark a host inactive
468  */
469 void realm_disable(uint32_t ipaddr, int port)
470 {
471         REALM *cl;
472         time_t now;
473
474         now = time(NULL);
475         for(cl = mainconfig.realms; cl; cl = cl->next) {
476                 if (cl->ipaddr.af != AF_INET) rad_assert(0 == 1);
477
478                 if ((ipaddr == cl->ipaddr.ipaddr.ip4addr.s_addr) &&
479                     (port == cl->auth_port)) {
480                         /*
481                          *      If we've received a reply (any reply)
482                          *      from the home server in the time spent
483                          *      re-sending this request, then don't mark
484                          *      the realm as dead.
485                          */
486                         if (cl->last_reply > (( now - mainconfig.proxy_retry_delay * mainconfig.proxy_retry_count ))) {
487                                 continue;
488                         }
489
490                         cl->active = FALSE;
491                         cl->wakeup = now + mainconfig.proxy_dead_time;
492                         radlog(L_PROXY, "marking authentication server %s:%d for realm %s dead",
493                                 cl->server, port, cl->realm);
494                 } else if ((ipaddr == cl->acct_ipaddr.ipaddr.ip4addr.s_addr) &&
495                            (port == cl->acct_port)) {
496                         if (cl->last_reply > (( now - mainconfig.proxy_retry_delay * mainconfig.proxy_retry_count ))) {
497                                 continue;
498                         }
499
500                         cl->acct_active = FALSE;
501                         cl->acct_wakeup = now + mainconfig.proxy_dead_time;
502                         radlog(L_PROXY, "marking accounting server %s:%d for realm %s dead",
503                                 cl->acct_server, port, cl->realm);
504                 }
505         }
506 }
507
508 /*
509  *      Find a realm in the REALM list.
510  */
511 REALM *realm_find(const char *realm, int accounting)
512 {
513         REALM *cl;
514         REALM *default_realm = NULL;
515         time_t now;
516         int dead_match = 0;
517
518         now = time(NULL);
519
520         /*
521          *      If we're passed a NULL realm pointer,
522          *      then look for a "NULL" realm string.
523          */
524         if (realm == NULL) {
525                 realm = "NULL";
526         }
527
528         for (cl = mainconfig.realms; cl; cl = cl->next) {
529                 /*
530                  *      Wake up any sleeping realm.
531                  */
532                 if (cl->wakeup <= now) {
533                         cl->active = TRUE;
534                 }
535                 if (cl->acct_wakeup <= now) {
536                         cl->acct_active = TRUE;
537                 }
538
539                 /*
540                  *      Asked for auth/acct, and the auth/acct server
541                  *      is not active.  Skip it.
542                  */
543                 if ((!accounting && !cl->active) ||
544                     (accounting && !cl->acct_active)) {
545
546                         /*
547                          *      We've been asked to NOT fall through
548                          *      to the DEFAULT realm if there are
549                          *      exact matches for this realm which are
550                          *      dead.
551                          */
552                         if ((!mainconfig.proxy_fallback) &&
553                             (strcasecmp(cl->realm, realm) == 0)) {
554                                 dead_match = 1;
555                         }
556                         continue;
557                 }
558
559                 /*
560                  *      If it matches exactly, return it.
561                  *
562                  *      Note that we just want ONE live realm
563                  *      here.  We don't care about round-robin, or
564                  *      scatter techniques, as that's more properly
565                  *      the responsibility of the proxying code.
566                  */
567                 if (strcasecmp(cl->realm, realm) == 0) {
568                         return cl;
569                 }
570
571                 /*
572                  *      No default realm, try to set one.
573                  */
574                 if ((default_realm == NULL) &&
575                     (strcmp(cl->realm, "DEFAULT") == 0)) {
576                   default_realm = cl;
577                 }
578         } /* loop over all realms */
579
580         /*
581          *      There WAS one or more matches which were marked dead,
582          *      AND there were NO live matches, AND we've been asked
583          *      to NOT fall through to the DEFAULT realm.  Therefore,
584          *      we return NULL, which means "no match found".
585          */
586         if (!mainconfig.proxy_fallback && dead_match) {
587                 if (mainconfig.wake_all_if_all_dead) {
588                         REALM *rcl = NULL;
589                         for (cl = mainconfig.realms; cl; cl = cl->next) {
590                                 if(strcasecmp(cl->realm,realm) == 0) {
591                                         if (!accounting && !cl->active) {
592                                                 cl->active = TRUE;
593                                                 rcl = cl;
594                                         }
595                                         else if (accounting &&
596                                                  !cl->acct_active) {
597                                                 cl->acct_active = TRUE;
598                                                 rcl = cl;
599                                         }
600                                 }
601                         }
602                         return rcl;
603                 }
604                 else {
605                         return NULL;
606                 }
607         }
608
609         /*      If we didn't find the realm 'NULL' don't return the
610          *      DEFAULT entry.
611          */
612         if ((strcmp(realm, "NULL")) == 0) {
613           return NULL;
614         }
615
616         /*
617          *      Didn't find anything that matched exactly, return the
618          *      DEFAULT realm.  We also return the DEFAULT realm if
619          *      all matching realms were marked dead, and we were
620          *      asked to fall through to the DEFAULT realm in this
621          *      case.
622          */
623         return default_realm;
624 }
625
626 /*
627  *      Find a realm for a proxy reply by proxy's IP
628  *
629  *      Note that we don't do anything else.
630  */
631 REALM *realm_findbyaddr(uint32_t ipaddr, int port)
632 {
633         REALM *cl;
634
635         /*
636          *      Note that we do NOT check for inactive realms!
637          *
638          *      The purpose of this code is simply to find a matching
639          *      source IP/Port pair, for a home server which is allowed
640          *      to send us proxy replies.  If we get a reply, then it
641          *      doesn't matter if we think the realm is inactive.
642          */
643         for (cl = mainconfig.realms; cl != NULL; cl = cl->next) {
644                 if (cl->ipaddr.af != AF_INET) rad_assert(0 == 1);
645
646                 if ((ipaddr == cl->ipaddr.ipaddr.ip4addr.s_addr) &&
647                     (port == cl->auth_port)) {
648                         return cl;
649
650                 } else if ((ipaddr == cl->acct_ipaddr.ipaddr.ip4addr.s_addr) &&
651                            (port == cl->acct_port)) {
652                         return cl;
653                 }
654         }
655
656         return NULL;
657 }
658