Pop it rather than just peeking it
[freeradius.git] / src / main / client.c
1 /*
2  * client.c     Read clients 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  */
24
25 #include <freeradius-devel/ident.h>
26 RCSID("$Id$")
27
28 #include <freeradius-devel/radiusd.h>
29 #include <freeradius-devel/rad_assert.h>
30
31 #include <sys/stat.h>
32
33 #include <ctype.h>
34 #include <fcntl.h>
35
36 #ifdef WITH_DYNAMIC_CLIENTS
37 #ifdef HAVE_DIRENT_H
38 #include <dirent.h>
39 #endif
40 #endif
41
42 struct radclient_list {
43         /*
44          *      FIXME: One set of trees for IPv4, and another for IPv6?
45          */
46         rbtree_t        *trees[129]; /* for 0..128, inclusive. */
47         int             min_prefix;
48 };
49
50
51 #ifdef WITH_STATS
52 static rbtree_t         *tree_num = NULL;     /* client numbers 0..N */
53 static int              tree_num_max = 0;
54 #endif
55 static RADCLIENT_LIST   *root_clients = NULL;
56
57 #ifdef WITH_DYNAMIC_CLIENTS
58 static fr_fifo_t        *deleted_clients = NULL;
59 #endif
60
61 /*
62  *      Callback for freeing a client.
63  */
64 void client_free(RADCLIENT *client)
65 {
66 #ifdef WITH_DYNAMIC_CLIENTS
67         if (client->dynamic == 2) {
68                 time_t now;
69
70                 if (!deleted_clients) {
71                         deleted_clients = fr_fifo_create(1024,
72                                                          (void *) client_free);
73                         if (!deleted_clients) return; /* MEMLEAK */
74                 }
75
76                 /*
77                  *      Mark it as in the fifo, and remember when we
78                  *      pushed it.
79                  */
80                 client->dynamic = 3;
81                 client->created = now = time(NULL); /* re-set it */
82                 fr_fifo_push(deleted_clients, client);
83
84                 /*
85                  *      Peek at the head of the fifo.  If it might
86                  *      still be in use, return.  Otherwise, pop it
87                  *      from the queue and delete it.
88                  */
89                 client = fr_fifo_peek(deleted_clients);
90                 if ((client->created + 120) >= now) return;
91
92                 client = fr_fifo_pop(deleted_clients);
93                 rad_assert(client != NULL);
94         }
95 #endif
96
97         free(client->longname);
98         free(client->secret);
99         free(client->shortname);
100         free(client->nastype);
101         free(client->login);
102         free(client->password);
103         free(client->server);
104
105 #ifdef WITH_STATS
106         free(client->auth);
107 #ifdef WITH_ACCOUNTING
108         free(client->acct);
109 #endif
110 #endif
111
112 #ifdef WITH_DYNAMIC_CLIENTS
113         free(client->client_server);
114 #endif
115
116         free(client);
117 }
118
119 /*
120  *      Callback for comparing two clients.
121  */
122 static int client_ipaddr_cmp(const void *one, const void *two)
123 {
124         const RADCLIENT *a = one;
125         const RADCLIENT *b = two;
126
127         return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
128 }
129
130 #ifdef WITH_STATS
131 static int client_num_cmp(const void *one, const void *two)
132 {
133         const RADCLIENT *a = one;
134         const RADCLIENT *b = two;
135
136         return (a->number - b->number);
137 }
138 #endif
139
140 /*
141  *      Free a RADCLIENT list.
142  */
143 void clients_free(RADCLIENT_LIST *clients)
144 {
145         int i;
146
147         if (!clients) return;
148
149         for (i = 0; i <= 128; i++) {
150                 if (clients->trees[i]) rbtree_free(clients->trees[i]);
151                 clients->trees[i] = NULL;
152         }
153
154         if (clients == root_clients) {
155 #ifdef WITH_STATS
156                 if (tree_num) rbtree_free(tree_num);
157                 tree_num = NULL;
158                 tree_num_max = 0;
159 #endif
160                 root_clients = NULL;
161         }
162
163 #ifdef WITH_DYNAMIC_CLIENTS
164         /*
165          *      FIXME: No fr_fifo_delete()
166          */
167 #endif
168
169         free(clients);
170 }
171
172 /*
173  *      Return a new, initialized, set of clients.
174  */
175 RADCLIENT_LIST *clients_init(void)
176 {
177         RADCLIENT_LIST *clients = calloc(1, sizeof(RADCLIENT_LIST));
178
179         if (!clients) return NULL;
180
181         clients->min_prefix = 128;
182
183         return clients;
184 }
185
186
187 /*
188  *      Sanity check a client.
189  */
190 static int client_sane(RADCLIENT *client)
191 {
192         switch (client->ipaddr.af) {
193         case AF_INET:
194                 if (client->prefix > 32) {
195                         return 0;
196                 }
197
198                 /*
199                  *      Zero out the subnet bits.
200                  */
201                 if (client->prefix == 0) {
202                         memset(&client->ipaddr.ipaddr.ip4addr, 0,
203                                sizeof(client->ipaddr.ipaddr.ip4addr));
204
205                 } else if (client->prefix < 32) {
206                         uint32_t mask = ~0;
207
208                         mask <<= (32 - client->prefix);
209                         client->ipaddr.ipaddr.ip4addr.s_addr &= htonl(mask);
210                 }
211                 break;
212
213         case AF_INET6:
214                 if (client->prefix > 128) return 0;
215
216                 if (client->prefix == 0) {
217                         memset(&client->ipaddr.ipaddr.ip6addr, 0,
218                                sizeof(client->ipaddr.ipaddr.ip6addr));
219
220                 } else if (client->prefix < 128) {
221                         int i;
222                         uint32_t mask, *addr;
223
224                         addr = (uint32_t *) &client->ipaddr.ipaddr.ip6addr;
225
226                         for (i = client->prefix; i < 128; i += 32) {
227                                 mask = ~0;
228                                 mask <<= ((128 - i) & 0x1f);
229                                 addr[i / 32] &= mask;
230                         }
231                 }
232                 break;
233
234         default:
235                 return 0;
236         }
237
238         return 1;
239 }
240
241
242 /*
243  *      Add a client to the tree.
244  */
245 int client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
246 {
247         if (!client) {
248                 return 0;
249         }
250
251         /*
252          *      If "clients" is NULL, it means add to the global list.
253          */
254         if (!clients) {
255                 /*
256                  *      Initialize it, if not done already.
257                  */
258                 if (!root_clients) {
259                         root_clients = clients_init();
260                         if (!root_clients) return 0;
261                 }
262                 clients = root_clients;
263         }
264
265         if ((client->prefix < 0) || (client->prefix > 128)) {
266                 return 0;
267         }
268
269         if (!client_sane(client)) return 0;
270
271         /*
272          *      Create a tree for it.
273          */
274         if (!clients->trees[client->prefix]) {
275                 clients->trees[client->prefix] = rbtree_create(client_ipaddr_cmp,
276                                                                (void *) client_free, 0);
277                 if (!clients->trees[client->prefix]) {
278                         return 0;
279                 }
280         }
281
282         /*
283          *      Cannot insert the same client twice.
284          */
285         if (rbtree_find(clients->trees[client->prefix], client)) {
286                 radlog(L_ERR, "Failed to add duplicate client %s",
287                        client->shortname);
288                 return 0;
289         }
290
291         /*
292          *      Other error adding client: likely is fatal.
293          */
294         if (!rbtree_insert(clients->trees[client->prefix], client)) {
295                 return 0;
296         }
297
298 #ifdef WITH_STATS
299         if (!tree_num) {
300                 tree_num = rbtree_create(client_num_cmp, NULL, 0);
301         }
302
303
304         /*
305          *      Catch clients added by rlm_sql.
306          */
307         if (!client->auth) {
308                 client->auth = rad_malloc(sizeof(*client->auth));
309                 memset(client->auth, 0, sizeof(*client->auth));
310         }
311
312 #ifdef WITH_ACCOUNTING
313         if (!client->acct) {
314                 client->acct = rad_malloc(sizeof(*client->acct));
315                 memset(client->acct, 0, sizeof(*client->acct));
316         }
317 #endif
318
319 #ifdef WITH_DYNAMIC_CLIENTS
320         /*
321          *      More catching of clients added by rlm_sql.
322          *
323          *      The sql modules sets the dynamic flag BEFORE calling
324          *      us.  The client_create() function sets it AFTER
325          *      calling us.
326          */
327         if (client->dynamic && (client->lifetime == 0)) {
328                 RADCLIENT *network;
329
330                 /*
331                  *      If there IS an enclosing network,
332                  *      inherit the lifetime from it.
333                  */
334                 network = client_find(clients, &client->ipaddr);
335                 if (network) {
336                         client->lifetime = network->lifetime;
337                 }
338         }
339 #endif
340
341         client->number = tree_num_max;
342         tree_num_max++;
343         if (tree_num) rbtree_insert(tree_num, client);
344 #endif
345
346         if (client->prefix < clients->min_prefix) {
347                 clients->min_prefix = client->prefix;
348         }
349
350         return 1;
351 }
352
353
354 #ifdef WITH_DYNAMIC_CLIENTS
355 void client_delete(RADCLIENT_LIST *clients, RADCLIENT *client)
356 {
357         if (!clients || !client) return;
358
359         rad_assert((client->prefix >= 0) && (client->prefix <= 128));
360
361         client->dynamic = 2;    /* signal to client_free */
362
363         rbtree_deletebydata(tree_num, client);
364         rbtree_deletebydata(clients->trees[client->prefix], client);
365 }
366 #endif
367
368
369 /*
370  *      Find a client in the RADCLIENTS list by number.
371  *      This is a support function for the statistics code.
372  */
373 RADCLIENT *client_findbynumber(const RADCLIENT_LIST *clients,
374                                int number)
375 {
376 #ifdef WITH_STATS
377         if (!clients) clients = root_clients;
378
379         if (!clients) return NULL;
380
381         if (number >= tree_num_max) return NULL;
382
383         if (tree_num) {
384                 RADCLIENT myclient;
385
386                 myclient.number = number;
387
388                 return rbtree_finddata(tree_num, &myclient);
389         }
390 #else
391         clients = clients;      /* -Wunused */
392         number = number;        /* -Wunused */
393 #endif
394         return NULL;
395 }
396
397
398 /*
399  *      Find a client in the RADCLIENTS list.
400  */
401 RADCLIENT *client_find(const RADCLIENT_LIST *clients,
402                        const fr_ipaddr_t *ipaddr)
403 {
404         int i, max_prefix;
405         RADCLIENT myclient;
406
407         if (!clients) clients = root_clients;
408
409         if (!clients || !ipaddr) return NULL;
410
411         switch (ipaddr->af) {
412         case AF_INET:
413                 max_prefix = 32;
414                 break;
415
416         case AF_INET6:
417                 max_prefix = 128;
418                 break;
419
420         default :
421                 return NULL;
422         }
423
424         for (i = max_prefix; i >= clients->min_prefix; i--) {
425                 void *data;
426
427                 myclient.prefix = i;
428                 myclient.ipaddr = *ipaddr;
429                 client_sane(&myclient); /* clean up the ipaddress */
430
431                 if (!clients->trees[i]) continue;
432
433                 data = rbtree_finddata(clients->trees[i], &myclient);
434                 if (data) {
435                         return data;
436                 }
437         }
438
439         return NULL;
440 }
441
442
443 /*
444  *      Old wrapper for client_find
445  */
446 RADCLIENT *client_find_old(const fr_ipaddr_t *ipaddr)
447 {
448         return client_find(root_clients, ipaddr);
449 }
450
451 static struct in_addr cl_ip4addr;
452 static struct in6_addr cl_ip6addr;
453
454 static const CONF_PARSER client_config[] = {
455         { "ipaddr",  PW_TYPE_IPADDR,
456           0, &cl_ip4addr,  NULL },
457         { "ipv6addr",  PW_TYPE_IPV6ADDR,
458           0, &cl_ip6addr, NULL },
459         { "netmask",  PW_TYPE_INTEGER,
460           offsetof(RADCLIENT, prefix), 0, NULL },
461
462         { "require_message_authenticator",  PW_TYPE_BOOLEAN,
463           offsetof(RADCLIENT, message_authenticator), 0, "no" },
464
465         { "secret",  PW_TYPE_STRING_PTR,
466           offsetof(RADCLIENT, secret), 0, NULL },
467         { "shortname",  PW_TYPE_STRING_PTR,
468           offsetof(RADCLIENT, shortname), 0, NULL },
469         { "nastype",  PW_TYPE_STRING_PTR,
470           offsetof(RADCLIENT, nastype), 0, NULL },
471         { "login",  PW_TYPE_STRING_PTR,
472           offsetof(RADCLIENT, login), 0, NULL },
473         { "password",  PW_TYPE_STRING_PTR,
474           offsetof(RADCLIENT, password), 0, NULL },
475         { "virtual_server",  PW_TYPE_STRING_PTR,
476           offsetof(RADCLIENT, server), 0, NULL },
477         { "server",  PW_TYPE_STRING_PTR, /* compatability with 2.0-pre */
478           offsetof(RADCLIENT, server), 0, NULL },
479
480 #ifdef WITH_DYNAMIC_CLIENTS
481         { "dynamic_clients",  PW_TYPE_STRING_PTR,
482           offsetof(RADCLIENT, client_server), 0, NULL },
483         { "lifetime",  PW_TYPE_INTEGER,
484           offsetof(RADCLIENT, lifetime), 0, NULL },
485 #endif
486
487 #ifdef WITH_COA
488         { "coa_server",  PW_TYPE_STRING_PTR,
489           offsetof(RADCLIENT, coa_name), 0, NULL },
490 #endif
491
492         { NULL, -1, 0, NULL, NULL }
493 };
494
495
496 static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server)
497 {
498         RADCLIENT       *c;
499         const char      *name2;
500
501         name2 = cf_section_name2(cs);
502         if (!name2) {
503                 cf_log_err(cf_sectiontoitem(cs),
504                            "Missing client name");
505                 return NULL;
506         }
507
508         /*
509          * The size is fine.. Let's create the buffer
510          */
511         c = rad_malloc(sizeof(*c));
512         memset(c, 0, sizeof(*c));
513         c->cs = cs;
514
515 #ifdef WITH_STATS
516         c->auth = rad_malloc(sizeof(*c->auth));
517         memset(c->auth, 0, sizeof(*c->auth));
518
519 #ifdef WITH_ACCOUNTING
520         c->acct = rad_malloc(sizeof(*c->acct));
521         memset(c->acct, 0, sizeof(*c->acct));
522 #endif
523 #endif
524
525         memset(&cl_ip4addr, 0, sizeof(cl_ip4addr));
526         memset(&cl_ip6addr, 0, sizeof(cl_ip6addr));
527         c->prefix = -1;
528
529         if (cf_section_parse(cs, c, client_config) < 0) {
530                 client_free(c);
531                 cf_log_err(cf_sectiontoitem(cs),
532                            "Error parsing client section.");
533                 return NULL;
534         }
535
536         /*
537          *      Global clients can set servers to use,
538          *      per-server clients cannot.
539          */
540         if (in_server && c->server) {
541                 client_free(c);
542                 cf_log_err(cf_sectiontoitem(cs),
543                            "Clients inside of an server section cannot point to a server.");
544                 return NULL;
545         }
546                 
547         /*
548          *      No "ipaddr" or "ipv6addr", use old-style
549          *      "client <ipaddr> {" syntax.
550          */
551         if (!cf_pair_find(cs, "ipaddr") &&
552             !cf_pair_find(cs, "ipv6addr")) {
553                 char *prefix_ptr;
554
555                 prefix_ptr = strchr(name2, '/');
556
557                 /*
558                  *      Look for prefixes.
559                  */
560                 if (prefix_ptr) {
561                         c->prefix = atoi(prefix_ptr + 1);
562                         if ((c->prefix < 0) || (c->prefix > 128)) {
563                                 client_free(c);
564                                 cf_log_err(cf_sectiontoitem(cs),
565                                            "Invalid Prefix value '%s' for IP.",
566                                            prefix_ptr + 1);
567                                 return NULL;
568                         }
569                         /* Replace '/' with '\0' */
570                         *prefix_ptr = '\0';
571                 }
572                         
573                 /*
574                  *      Always get the numeric representation of IP
575                  */
576                 if (ip_hton(name2, AF_UNSPEC, &c->ipaddr) < 0) {
577                         client_free(c);
578                         cf_log_err(cf_sectiontoitem(cs),
579                                    "Failed to look up hostname %s: %s",
580                                    name2, fr_strerror());
581                         return NULL;
582                 }
583
584                 if (prefix_ptr) *prefix_ptr = '/';
585                 c->longname = strdup(name2);
586
587                 if (!c->shortname) c->shortname = strdup(c->longname);
588
589         } else {
590                 char buffer[1024];
591
592                 /*
593                  *      Figure out which one to use.
594                  */
595                 if (cf_pair_find(cs, "ipaddr")) {
596                         c->ipaddr.af = AF_INET;
597                         c->ipaddr.ipaddr.ip4addr = cl_ip4addr;
598
599                         if ((c->prefix < -1) || (c->prefix > 32)) {
600                                 client_free(c);
601                                 cf_log_err(cf_sectiontoitem(cs),
602                                            "Netmask must be between 0 and 32");
603                                 return NULL;
604                         }
605                                 
606                 } else if (cf_pair_find(cs, "ipv6addr")) {
607                         c->ipaddr.af = AF_INET6;
608                         c->ipaddr.ipaddr.ip6addr = cl_ip6addr;
609                                 
610                         if ((c->prefix < -1) || (c->prefix > 128)) {
611                                 client_free(c);
612                                 cf_log_err(cf_sectiontoitem(cs),
613                                            "Netmask must be between 0 and 128");
614                                 return NULL;
615                         }
616                 } else {
617                         cf_log_err(cf_sectiontoitem(cs),
618                                    "No IP address defined for the client");
619                         client_free(c);
620                         return NULL;
621                 }
622
623                 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
624                 c->longname = strdup(buffer);
625
626                 /*
627                  *      Set the short name to the name2
628                  */
629                 if (!c->shortname) c->shortname = strdup(name2);
630         }
631
632         if (c->prefix < 0) switch (c->ipaddr.af) {
633         case AF_INET:
634                 c->prefix = 32;
635                 break;
636         case AF_INET6:
637                 c->prefix = 128;
638                 break;
639         default:
640                 break;
641         }
642
643 #ifdef WITH_DYNAMIC_CLIENTS
644         if (c->client_server) {
645                 free(c->secret);
646                 c->secret = strdup("testing123");
647
648                 if (((c->ipaddr.af == AF_INET) &&
649                      (c->prefix == 32)) ||
650                     ((c->ipaddr.af == AF_INET6) &&
651                      (c->prefix == 128))) {
652                         cf_log_err(cf_sectiontoitem(cs),
653                                    "Dynamic clients MUST be a network, not a single IP address.");
654                         client_free(c);
655                         return NULL;
656                 }
657
658                 return c;
659         }
660 #endif
661
662         if (!c->secret || !*c->secret) {
663 #ifdef WITH_DHCP
664                 const char *value = NULL;
665                 CONF_PAIR *cp = cf_pair_find(cs, "dhcp");
666
667                 if (cp) value = cf_pair_value(cp);
668
669                 /*
670                  *      Secrets aren't needed for DHCP.
671                  */
672                 if (value && (strcmp(value, "yes") == 0)) return c;
673
674 #endif
675                 client_free(c);
676                 cf_log_err(cf_sectiontoitem(cs),
677                            "secret must be at least 1 character long");
678                 return NULL;
679         }
680
681 #ifdef WITH_COA
682         /*
683          *      Point the client to the home server pool, OR to the
684          *      home server.  This gets around the problem of figuring
685          *      out which port to use.
686          */
687         if (c->coa_name) {
688                 c->coa_pool = home_pool_byname(c->coa_name, HOME_TYPE_COA);
689                 if (!c->coa_pool) {
690                         c->coa_server = home_server_byname(c->coa_name);
691                 }
692                 if (!c->coa_server) {
693                         client_free(c);
694                         cf_log_err(cf_sectiontoitem(cs), "No such home_server or home_server_pool \"%s\"", c->coa_name);
695                         return NULL;
696                 }
697         }
698 #endif
699
700         return c;
701 }
702
703
704 /*
705  *      Create the linked list of clients from the new configuration
706  *      type.  This way we don't have to change too much in the other
707  *      source-files.
708  */
709 RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section)
710 {
711         int             global = FALSE, in_server = FALSE;
712         CONF_SECTION    *cs;
713         RADCLIENT       *c;
714         RADCLIENT_LIST  *clients;
715
716         /*
717          *      Be forgiving.  If there's already a clients, return
718          *      it.  Otherwise create a new one.
719          */
720         clients = cf_data_find(section, "clients");
721         if (clients) return clients;
722
723         clients = clients_init();
724         if (!clients) return NULL;
725
726         if (cf_top_section(section) == section) global = TRUE;
727
728         if (strcmp("server", cf_section_name1(section)) == 0) in_server = TRUE;
729
730         /*
731          *      Associate the clients structure with the section, where
732          *      it will be freed once the section is freed.
733          */
734         if (cf_data_add(section, "clients", clients, (void *) clients_free) < 0) {
735                 cf_log_err(cf_sectiontoitem(section),
736                            "Failed to associate clients with section %s",
737                        cf_section_name1(section));
738                 clients_free(clients);
739                 return NULL;
740         }
741
742         for (cs = cf_subsection_find_next(section, NULL, "client");
743              cs != NULL;
744              cs = cf_subsection_find_next(section, cs, "client")) {
745                 c = client_parse(cs, in_server);
746                 if (!c) {
747                         return NULL;
748                 }
749
750                 /*
751                  *      FIXME: Add the client as data via cf_data_add,
752                  *      for migration issues.
753                  */
754
755 #ifdef WITH_DYNAMIC_CLIENTS
756 #ifdef HAVE_DIRENT_H
757                 if (c->client_server) {
758                         const char *value;
759                         CONF_PAIR *cp;
760                         DIR             *dir;
761                         struct dirent   *dp;
762                         struct stat stat_buf;
763                         char buf2[2048];
764
765                         /*
766                          *      Find the directory where individual
767                          *      client definitions are stored.
768                          */
769                         cp = cf_pair_find(cs, "directory");
770                         if (!cp) goto add_client;
771                         
772                         value = cf_pair_value(cp);
773                         if (!value) {
774                                 cf_log_err(cf_sectiontoitem(cs),
775                                            "The \"directory\" entry must not be empty");
776                                 client_free(c);
777                                 return NULL;
778                         }
779
780                         DEBUG("including dynamic clients in %s", value);
781                         
782                         dir = opendir(value);
783                         if (!dir) {
784                                 cf_log_err(cf_sectiontoitem(cs), "Error reading directory %s: %s", value, strerror(errno));
785                                 client_free(c);
786                                 return NULL;
787                         }
788                         
789                         /*
790                          *      Read the directory, ignoring "." files.
791                          */
792                         while ((dp = readdir(dir)) != NULL) {
793                                 const char *p;
794                                 RADCLIENT *dc;
795
796                                 if (dp->d_name[0] == '.') continue;
797
798                                 /*
799                                  *      Check for valid characters
800                                  */
801                                 for (p = dp->d_name; *p != '\0'; p++) {
802                                         if (isalpha((int)*p) ||
803                                             isdigit((int)*p) ||
804                                             (*p == ':') ||
805                                             (*p == '.')) continue;
806                                                 break;
807                                 }
808                                 if (*p != '\0') continue;
809
810                                 snprintf(buf2, sizeof(buf2), "%s/%s",
811                                          value, dp->d_name);
812
813                                 if ((stat(buf2, &stat_buf) != 0) ||
814                                     S_ISDIR(stat_buf.st_mode)) continue;
815
816                                 dc = client_read(buf2, in_server, TRUE);
817                                 if (!dc) {
818                                         cf_log_err(cf_sectiontoitem(cs),
819                                                    "Failed reading client file \"%s\"", buf2);
820                                         client_free(c);
821                                         return NULL;
822                                 }
823
824                                 /*
825                                  *      Validate, and add to the list.
826                                  */
827                                 if (!client_validate(clients, c, dc)) {
828                                         
829                                         client_free(c);
830                                         return NULL;
831                                 }
832                         } /* loop over the directory */
833                 }
834 #endif /* HAVE_DIRENT_H */
835 #endif /* WITH_DYNAMIC_CLIENTS */
836
837         add_client:
838                 if (!client_add(clients, c)) {
839                         cf_log_err(cf_sectiontoitem(cs),
840                                    "Failed to add client %s",
841                                    cf_section_name2(cs));
842                         client_free(c);
843                         return NULL;
844                 }
845
846         }
847
848         /*
849          *      Replace the global list of clients with the new one.
850          *      The old one is still referenced from the original
851          *      configuration, and will be freed when that is freed.
852          */
853         if (global) {
854                 root_clients = clients;
855         }
856
857         return clients;
858 }
859
860 #ifdef WITH_DYNAMIC_CLIENTS
861 /*
862  *      We overload this structure a lot.
863  */
864 static const CONF_PARSER dynamic_config[] = {
865         { "FreeRADIUS-Client-IP-Address",  PW_TYPE_IPADDR,
866           offsetof(RADCLIENT, ipaddr), 0, NULL },
867         { "FreeRADIUS-Client-IPv6-Address",  PW_TYPE_IPV6ADDR,
868           offsetof(RADCLIENT, ipaddr), 0, NULL },
869
870         { "FreeRADIUS-Client-Require-MA",  PW_TYPE_BOOLEAN,
871           offsetof(RADCLIENT, message_authenticator), NULL, NULL },
872
873         { "FreeRADIUS-Client-Secret",  PW_TYPE_STRING_PTR,
874           offsetof(RADCLIENT, secret), 0, "" },
875         { "FreeRADIUS-Client-Shortname",  PW_TYPE_STRING_PTR,
876           offsetof(RADCLIENT, shortname), 0, "" },
877         { "FreeRADIUS-Client-NAS-Type",  PW_TYPE_STRING_PTR,
878           offsetof(RADCLIENT, nastype), 0, NULL },
879         { "FreeRADIUS-Client-Virtual-Server",  PW_TYPE_STRING_PTR,
880           offsetof(RADCLIENT, server), 0, NULL },
881
882         { NULL, -1, 0, NULL, NULL }
883 };
884
885
886 int client_validate(RADCLIENT_LIST *clients, RADCLIENT *master, RADCLIENT *c)
887 {
888         char buffer[128];
889
890         /*
891          *      No virtual server defined.  Inherit the parent's
892          *      definition.
893          */
894         if (master->server && !c->server) {
895                 c->server = strdup(master->server);
896         }
897
898         /*
899          *      If the client network isn't global (not tied to a
900          *      virtual server), then ensure that this clients server
901          *      is the same as the enclosing networks virtual server.
902          */
903         if (master->server &&
904              (strcmp(master->server, c->server) != 0)) {
905                 DEBUG("- Cannot add client %s: Virtual server %s is not the same as the virtual server for the network.",
906                       ip_ntoh(&c->ipaddr,
907                               buffer, sizeof(buffer)),
908                       c->server);
909
910                 goto error;
911         }
912
913         if (!client_add(clients, c)) {
914                 DEBUG("- Cannot add client %s: Internal error",
915                       ip_ntoh(&c->ipaddr,
916                               buffer, sizeof(buffer)));
917
918                 goto error;
919         }
920
921         /*
922          *      Initialize the remaining fields.
923          */
924         c->dynamic = TRUE;
925         c->lifetime = master->lifetime;
926         c->created = time(NULL);
927         c->longname = strdup(c->shortname);
928
929         DEBUG("- Added client %s with shared secret %s",
930               ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)),
931               c->secret);
932
933         return 1;
934
935  error:
936         client_free(c);
937         return 0;
938 }
939
940
941 RADCLIENT *client_create(RADCLIENT_LIST *clients, REQUEST *request)
942 {
943         int i, *pi;
944         char **p;
945         RADCLIENT *c;
946         char buffer[128];
947
948         if (!clients || !request) return NULL;
949
950         c = rad_malloc(sizeof(*c));
951         memset(c, 0, sizeof(*c));
952         c->cs = request->client->cs;
953         c->ipaddr.af = AF_UNSPEC;
954
955         for (i = 0; dynamic_config[i].name != NULL; i++) {
956                 DICT_ATTR *da;
957                 VALUE_PAIR *vp;
958
959                 da = dict_attrbyname(dynamic_config[i].name);
960                 if (!da) {
961                         DEBUG("- Cannot add client %s: attribute \"%s\"is not in the dictionary",
962                               ip_ntoh(&request->packet->src_ipaddr,
963                                       buffer, sizeof(buffer)),
964                               dynamic_config[i].name);
965                 error:
966                         client_free(c);
967                         return NULL;
968                 }
969
970                 vp = pairfind(request->config_items, da->attr);
971                 if (!vp) {
972                         /*
973                          *      Not required.  Skip it.
974                          */
975                         if (!dynamic_config[i].dflt) continue;
976                         
977                         DEBUG("- Cannot add client %s: Required attribute \"%s\" is missing.",  
978                               ip_ntoh(&request->packet->src_ipaddr,
979                                       buffer, sizeof(buffer)),
980                               dynamic_config[i].name);
981                         goto error;
982                 }
983
984                 switch (dynamic_config[i].type) {
985                 case PW_TYPE_IPADDR:
986                         c->ipaddr.af = AF_INET;
987                         c->ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
988                         c->prefix = 32;
989                         break;
990
991                 case PW_TYPE_IPV6ADDR:
992                         c->ipaddr.af = AF_INET6;
993                         c->ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
994                         c->prefix = 128;
995                         break;
996
997                 case PW_TYPE_STRING_PTR:
998                         p = (char **) ((char *) c + dynamic_config[i].offset);
999                         if (*p) free(*p);
1000                         *p = strdup(vp->vp_strvalue);
1001                         break;
1002
1003                 case PW_TYPE_BOOLEAN:
1004                         pi = (int *) ((char *) c + dynamic_config[i].offset);
1005                         *pi = vp->vp_integer;
1006                         break;
1007
1008                 default:
1009                         goto error;
1010                 }
1011         }
1012
1013         if (c->ipaddr.af == AF_UNSPEC) {
1014                 DEBUG("- Cannot add client %s: No IP address was specified.",
1015                       ip_ntoh(&request->packet->src_ipaddr,
1016                               buffer, sizeof(buffer)));
1017
1018                 goto error;
1019         }
1020
1021         if (fr_ipaddr_cmp(&request->packet->src_ipaddr, &c->ipaddr) != 0) {
1022                 char buf2[128];
1023
1024                 DEBUG("- Cannot add client %s: IP address %s do not match",
1025                       ip_ntoh(&request->packet->src_ipaddr,
1026                               buffer, sizeof(buffer)),
1027                       ip_ntoh(&c->ipaddr,
1028                               buf2, sizeof(buf2)));                   
1029                 goto error;
1030         }
1031
1032         if (!client_validate(clients, request->client, c)) {
1033                 return NULL;
1034         }
1035
1036         return c;
1037 }
1038
1039 /*
1040  *      Read a client definition from the given filename.
1041  */
1042 RADCLIENT *client_read(const char *filename, int in_server, int flag)
1043 {
1044         const char *p;
1045         RADCLIENT *c;
1046         CONF_SECTION *cs;
1047         char buffer[256];
1048
1049         if (!filename) return NULL;
1050
1051         cs = cf_file_read(filename);
1052         if (!cs) return NULL;
1053
1054         c = client_parse(cf_section_sub_find(cs, "client"), in_server);
1055
1056         p = strrchr(filename, FR_DIR_SEP);
1057         if (p) {
1058                 p++;
1059         } else {
1060                 p = filename;
1061         }
1062
1063         if (!flag) return c;
1064
1065         /*
1066          *      Additional validations
1067          */
1068         ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
1069         if (strcmp(p, buffer) != 0) {
1070                 DEBUG("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p);
1071                 client_free(c);
1072                 return NULL;
1073         }
1074
1075
1076
1077         return c;
1078 }
1079 #endif