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