Initial revision
[freeradius.git] / src / main / files.c
1 /*
2  * files.c      Read config files into memory.
3  *
4  * Version:     @(#)files.c  2.52  10-Aug-1999  miquels@cistron.nl
5  *
6  */
7
8 char files_sccsid[] =
9 "@(#)files.c    2.52 Copyright 1999 Cistron Internet Services B.V.";
10
11 #include        "autoconf.h"
12
13 #include        <sys/types.h>
14 #include        <sys/socket.h>
15 #include        <sys/time.h>
16 #include        <sys/stat.h>
17 #include        <netinet/in.h>
18
19 #include        <stdio.h>
20 #include        <stdlib.h>
21 #include        <string.h>
22 #include        <netdb.h>
23 #include        <time.h>
24 #include        <ctype.h>
25 #include        <fcntl.h>
26
27 #if HAVE_MALLOC_H
28 #  include      <malloc.h>
29 #endif
30
31 #include        "radiusd.h"
32 #include        "modules.h"
33
34 CLIENT                  *clients;
35 REALM                   *realms;
36
37
38 /*
39  *      Free a PAIR_LIST
40  */
41 void pairlist_free(PAIR_LIST **pl)
42 {
43         PAIR_LIST *p, *next;
44
45         for (p = *pl; p; p = next) {
46                 if (p->name) free(p->name);
47                 if (p->check) pairfree(p->check);
48                 if (p->reply) pairfree(p->reply);
49                 next = p->next;
50                 free(p);
51         }
52         *pl = NULL;
53 }
54
55
56 /*
57  *      Fixup a check line.
58  *      If Password or Crypt-Password is set, but there is no
59  *      Auth-Type, add one (kludge!).
60  */
61 static void auth_type_fixup(VALUE_PAIR *check)
62 {
63         VALUE_PAIR      *vp;
64         VALUE_PAIR      *c = NULL;
65         int             n = 0;
66
67         /*
68          *      See if a password is present. Return right away
69          *      if we see Auth-Type.
70          */
71         for (vp = check; vp; vp = vp->next) {
72                 if (vp->attribute == PW_AUTHTYPE)
73                         return;
74                 if (vp->attribute == PW_PASSWORD) {
75                         c = vp;
76                         n = PW_AUTHTYPE_LOCAL;
77                 }
78                 if (vp->attribute == PW_CRYPT_PASSWORD) {
79                         c = vp;
80                         n = PW_AUTHTYPE_CRYPT;
81                 }
82         }
83
84         if (c == NULL)
85                 return;
86
87         /*
88          *      Add an Auth-Type attribute.
89          *      FIXME: put Auth-Type _first_ (doesn't matter now,
90          *      might matter some day).
91          *      
92          */
93         if ((vp = paircreate(PW_AUTHTYPE, PW_TYPE_INTEGER)) == NULL) {
94                 log(L_CONS|L_ERR, "no memory");
95                 exit(1);
96         }
97         vp->lvalue = n;
98
99         vp->next = c->next;
100         c->next = vp;
101
102 }
103
104
105 #define FIND_MODE_NAME  0
106 #define FIND_MODE_REPLY 1
107
108 /*
109  *      Read the users, huntgroups or hints file.
110  *      Return a PAIR_LIST.
111  */
112 PAIR_LIST *pairlist_read(char *file, int complain)
113 {
114         FILE            *fp;
115         int             mode = FIND_MODE_NAME;
116         char            entry[256];
117         char            buffer[256];
118         char            *ptr, *s;
119         VALUE_PAIR      *check_tmp;
120         VALUE_PAIR      *reply_tmp;
121         PAIR_LIST       *pl = NULL, *last = NULL, *t;
122         int             lineno = 0;
123         int             old_lineno = 0;
124
125         /*
126          *      Open the table
127          */
128         if ((fp = fopen(file, "r")) == NULL) {
129                 if (!complain) return NULL;
130                 log(L_CONS|L_ERR, "Couldn't open %s for reading", file);
131                 return NULL;
132         }
133
134         /*
135          *      Read the entire file into memory for speed.
136          */
137         while(fgets(buffer, sizeof(buffer), fp) != (char *)NULL) {
138                 lineno++;
139                 if (buffer[0] == '#' || buffer[0] == '\n') continue;
140 parse_again:
141                 if(mode == FIND_MODE_NAME) {
142                         /*
143                          *      Find the entry starting with the users name
144                          */
145                         if (isspace(buffer[0])) continue;
146
147                         ptr = buffer;
148                         getword(&ptr, entry, sizeof(entry));
149
150                         /*
151                          *      Include another file if we see
152                          *      $INCLUDE filename
153                          */
154                         if (strcasecmp(entry, "$include") == 0) {
155                                 while(isspace(*ptr))
156                                         ptr++;
157                                 s = ptr;
158                                 while (!isspace(*ptr))
159                                         ptr++;
160                                 *ptr = 0;
161                                 if ((t = pairlist_read(s, 1)) == NULL)
162                                         continue;
163                                 if (last)
164                                         last->next = t;
165                                 else
166                                         pl = t;
167                                 last = t;
168                                 while (last && last->next)
169                                         last = last->next;
170                                 continue;
171                         }
172
173                         /*
174                          *      Parse the check values
175                          */
176                         check_tmp = NULL;
177                         reply_tmp = NULL;
178                         old_lineno = lineno;
179                         if(userparse(ptr, &check_tmp) != 0) {
180                                 log(L_ERR|L_CONS,
181                                 "%s[%d]: Parse error (check) for entry %s",
182                                         file, lineno, entry);
183                                 fclose(fp);
184                                 return NULL;
185                         }
186                         mode = FIND_MODE_REPLY;
187                 }
188                 else {
189                         if(*buffer == ' ' || *buffer == '\t') {
190                                 /*
191                                  *      Parse the reply values
192                                  */
193                                 if (userparse(buffer, &reply_tmp)!=0) {
194                                         log(L_ERR|L_CONS,
195                                 "%s[%d]: Parse error (reply) for entry %s",
196                                                 file, lineno, entry);
197                                         fclose(fp);
198                                         return NULL;
199                                 }
200                         }
201                         else {
202                                 /*
203                                  *      Done with this entry...
204                                  */
205                                 if ((t = malloc(sizeof(PAIR_LIST))) == NULL) {
206                                         perror(progname);
207                                         exit(1);
208                                 }
209                                 auth_type_fixup(check_tmp);
210                                 memset(t, 0, sizeof(*t));
211                                 t->name = strdup(entry);
212                                 t->check = check_tmp;
213                                 t->reply = reply_tmp;
214                                 t->lineno = old_lineno;
215                                 check_tmp = NULL;
216                                 reply_tmp = NULL;
217                                 if (last)
218                                         last->next = t;
219                                 else
220                                         pl = t;
221                                 last = t;
222
223                                 mode = FIND_MODE_NAME;
224                                 if (buffer[0] != 0)
225                                         goto parse_again;
226                         }
227                 }
228         }
229         /*
230          *      Make sure that we also read the last line of the file!
231          */
232         if (mode == FIND_MODE_REPLY) {
233                 buffer[0] = 0;
234                 goto parse_again;
235         }
236         fclose(fp);
237
238         return pl;
239 }
240
241
242 /*
243  *      Debug code.
244  */
245 #if 0
246 static void debug_pair_list(PAIR_LIST *pl)
247 {
248         VALUE_PAIR *vp;
249
250         while(pl) {
251                 printf("Pair list: %s\n", pl->name);
252                 printf("** Check:\n");
253                 for(vp = pl->check; vp; vp = vp->next) {
254                         printf("    ");
255                         fprint_attr_val(stdout, vp);
256                         printf("\n");
257                 }
258                 printf("** Reply:\n");
259                 for(vp = pl->reply; vp; vp = vp->next) {
260                         printf("    ");
261                         fprint_attr_val(stdout, vp);
262                         printf("\n");
263                 }
264                 pl = pl->next;
265         }
266 }
267 #endif
268
269 /*
270  *      Free a CLIENT list.
271  */
272 static void clients_free(CLIENT *cl)
273 {
274         CLIENT *next;
275
276         while(cl) {
277                 next = cl->next;
278                 free(cl);
279                 cl = next;
280         }
281 }
282
283
284 /*
285  *      Read the clients file.
286  */
287 int read_clients_file(char *file)
288 {
289         FILE    *fp;
290         char    buffer[256];
291         char    hostnm[128];
292         char    secret[32];
293         char    shortnm[32];
294         int     lineno = 0;
295         char    *p;
296         CLIENT  *c;
297
298         clients_free(clients);
299         clients = NULL;
300
301         if ((fp = fopen(file, "r")) == NULL) {
302                 log(L_CONS|L_ERR, "cannot open %s", file);
303                 return -1;
304         }
305         while(fgets(buffer, 256, fp) != NULL) {
306                 lineno++;
307                 if (buffer[0] == '#' || buffer[0] == '\n')
308                         continue;
309                 p = buffer;
310
311                 if (!getword(&p, hostnm, sizeof(hostnm)) ||
312                     !getword(&p, secret, sizeof(secret))) {
313                         log(L_ERR, "%s[%d]: syntax error", file, lineno);
314                         continue;
315                 }
316                 (void)getword(&p, shortnm, sizeof(shortnm));
317
318                 if ((c = malloc(sizeof(CLIENT))) == NULL) {
319                         log(L_CONS|L_ERR, "%s[%d]: out of memory",
320                                 file, lineno);
321                         return -1;
322                 }
323
324                 c->ipaddr = ip_getaddr(hostnm);
325                 strcpy(c->secret, secret);
326                 strcpy(c->shortname, shortnm);
327                 strcpy(c->longname, ip_hostname(c->ipaddr));
328
329                 c->next = clients;
330                 clients = c;
331         }
332         fclose(fp);
333
334         return 0;
335 }
336
337
338 /*
339  *      Find a client in the CLIENTS list.
340  */
341 CLIENT *client_find(UINT4 ipaddr)
342 {
343         CLIENT *cl;
344
345         for(cl = clients; cl; cl = cl->next)
346                 if (ipaddr == cl->ipaddr)
347                         break;
348
349         return cl;
350 }
351
352
353 /*
354  *      Find the name of a client (prefer short name).
355  */
356 char *client_name(UINT4 ipaddr)
357 {
358         CLIENT *cl;
359
360         if ((cl = client_find(ipaddr)) != NULL) {
361                 if (cl->shortname[0])
362                         return cl->shortname;
363                 else
364                         return cl->longname;
365         }
366         return ip_hostname(ipaddr);
367 }
368
369 #ifndef BUILDDBM /* HACK HACK */
370
371 /*
372  *      Free a REALM list.
373  */
374 static void realm_free(REALM *cl)
375 {
376         REALM *next;
377
378         while(cl) {
379                 next = cl->next;
380                 free(cl);
381                 cl = next;
382         }
383 }
384
385
386 /*
387  *      Read the realms file.
388  */
389 int read_realms_file(char *file)
390 {
391         FILE    *fp;
392         char    buffer[256];
393         char    realm[32];
394         char    hostnm[128];
395         char    opts[32];
396         char    *s, *p;
397         int     lineno = 0;
398         REALM   *c;
399
400         realm_free(realms);
401         realms = NULL;
402
403         if ((fp = fopen(file, "r")) == NULL) {
404 #if 1 /* For now - realms file is not obligatory */
405                 return 0;
406 #else
407                 log(L_CONS|L_ERR, "cannot open %s", file);
408                 return -1;
409 #endif
410         }
411         while(fgets(buffer, 256, fp) != NULL) {
412                 lineno++;
413                 if (buffer[0] == '#' || buffer[0] == '\n')
414                         continue;
415                 p = buffer;
416                 if (!getword(&p, realm, sizeof(realm)) ||
417                     !getword(&p, hostnm, sizeof(hostnm))) {
418                         log(L_ERR, "%s[%d]: syntax error", file, lineno);
419                         continue;
420                 }
421
422                 if ((c = malloc(sizeof(REALM))) == NULL) {
423                         log(L_CONS|L_ERR, "%s[%d]: out of memory",
424                                 file, lineno);
425                         return -1;
426                 }
427                 memset(c, 0, sizeof(REALM));
428
429                 if ((s = strchr(hostnm, ':')) != NULL) {
430                         *s++ = 0;
431                         c->auth_port = atoi(s);
432                         c->acct_port = c->auth_port + 1;
433                 } else {
434                         c->auth_port = auth_port;
435                         c->acct_port = acct_port;
436                 }
437                 if (strcmp(hostnm, "LOCAL") != 0)
438                         c->ipaddr = ip_getaddr(hostnm);
439                 strcpy(c->realm, realm);
440                 strcpy(c->server, hostnm);
441                 c->striprealm = 1;
442
443                 while (getword(&p, opts, sizeof(opts))) {
444                         if (strcmp(opts, "nostrip") == 0)
445                                 c->striprealm = 0;
446                         if (strstr(opts, "noacct") != NULL)
447                                 c->acct_port = 0;
448                 }
449
450                 c->next = realms;
451                 realms = c;
452         }
453         fclose(fp);
454
455         return 0;
456 }
457 #endif
458
459 /*
460  *      Find a realm in the REALM list.
461  */
462 REALM *realm_find(char *realm)
463 {
464         REALM *cl;
465
466         for(cl = realms; cl; cl = cl->next)
467                 if (strcmp(cl->realm, realm) == 0)
468                         break;
469         if (cl) return cl;
470         for(cl = realms; cl; cl = cl->next)
471                 if (strcmp(cl->realm, "DEFAULT") == 0)
472                         break;
473         return cl;
474 }
475
476
477 #ifndef BUILDDBM /* HACK HACK */
478
479 /*
480  *      (Re-) read the configuration files.
481  */
482 int read_config_files()
483 {
484         char buffer[256];
485
486         /* Initialize the dictionary */
487         if (dict_init(radius_dir, RADIUS_DICTIONARY) != 0) {
488                 log(L_ERR|L_CONS, "Errors reading dictionary");
489                 return -1;
490         }
491
492         sprintf(buffer, "%s/%s", radius_dir, RADIUS_MODULES);
493         if (read_modules_file(buffer) < 0) {
494                 log(L_ERR|L_CONS, "Errors reading modules");
495                 return -1;
496         }
497         sprintf(buffer, "%s/%s", radius_dir, RADIUS_CLIENTS);
498         if (read_clients_file(buffer) < 0) {
499                 log(L_ERR|L_CONS, "Errors reading clients");
500                 return -1;
501         }
502         sprintf(buffer, "%s/%s", radius_dir, RADIUS_NASLIST);
503         if (read_naslist_file(buffer) < 0) {
504                 log(L_ERR|L_CONS, "Errors reading naslist");
505                 return -1;
506         }
507         sprintf(buffer, "%s/%s", radius_dir, RADIUS_REALMS);
508         if (read_realms_file(buffer) < 0) {
509                 log(L_ERR|L_CONS, "Errors reading realms");
510                 return -1;
511         }
512
513         return 0;
514 }
515
516 #endif
517