Prefix of /0 is special
[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/radius_snmp.h>
30 #include <freeradius-devel/rad_assert.h>
31
32 #include <sys/stat.h>
33
34 #include <ctype.h>
35 #include <fcntl.h>
36
37 struct radclient_list {
38         /*
39          *      FIXME: One set of trees for IPv4, and another for IPv6?
40          */
41         rbtree_t        *trees[129]; /* for 0..128, inclusive. */
42         int             min_prefix;
43 };
44
45
46 #ifdef WITH_SNMP
47 static rbtree_t         *tree_num;      /* client numbers 0..N */
48 static int              tree_num_max;
49 #endif
50 static RADCLIENT_LIST   *root_clients;
51
52 /*
53  *      Callback for freeing a client.
54  */
55 void client_free(RADCLIENT *client)
56 {
57         free(client->longname);
58         free(client->secret);
59         free(client->shortname);
60         free(client->nastype);
61         free(client->login);
62         free(client->password);
63         free(client->server);
64
65 #ifdef WITH_SNMP
66         free(client->auth);
67         free(client->acct);
68 #endif
69
70         free(client);
71 }
72
73
74 /*
75  *      Callback for comparing two clients.
76  */
77 static int client_ipaddr_cmp(const void *one, const void *two)
78 {
79         const RADCLIENT *a = one;
80         const RADCLIENT *b = two;
81
82         return fr_ipaddr_cmp(&a->ipaddr, &b->ipaddr);
83 }
84
85 #ifdef WITH_SNMP
86 static int client_num_cmp(const void *one, const void *two)
87 {
88         const RADCLIENT *a = one;
89         const RADCLIENT *b = two;
90
91         return (a->number - b->number);
92 }
93 #endif
94
95 /*
96  *      Free a RADCLIENT list.
97  */
98 void clients_free(RADCLIENT_LIST *clients)
99 {
100         int i;
101
102         if (!clients) return;
103
104         for (i = 0; i <= 128; i++) {
105                 if (clients->trees[i]) rbtree_free(clients->trees[i]);
106                 clients->trees[i] = NULL;
107         }
108
109         if (clients == root_clients) {
110 #ifdef WITH_SNMP
111                 if (tree_num) rbtree_free(tree_num);
112                 tree_num = NULL;
113                 tree_num_max = 0;
114 #endif
115                 root_clients = NULL;
116         }
117
118         free(clients);
119 }
120
121 /*
122  *      Return a new, initialized, set of clients.
123  */
124 RADCLIENT_LIST *clients_init(void)
125 {
126         RADCLIENT_LIST *clients = calloc(1, sizeof(RADCLIENT_LIST));
127
128         if (!clients) return NULL;
129
130         clients->min_prefix = 128;
131
132         return clients;
133 }
134
135
136 /*
137  *      Sanity check a client.
138  */
139 static int client_sane(RADCLIENT *client)
140 {
141         switch (client->ipaddr.af) {
142         case AF_INET:
143                 if (client->prefix > 32) {
144                         return 0;
145                 }
146
147                 /*
148                  *      Zero out the subnet bits.
149                  */
150                 if (client->prefix == 0) {
151                         memset(&client->ipaddr.ipaddr.ip4addr, 0,
152                                sizeof(client->ipaddr.ipaddr.ip4addr));
153
154                 } else if (client->prefix < 32) {
155                         uint32_t mask = ~0;
156
157                         mask <<= (32 - client->prefix);
158                         client->ipaddr.ipaddr.ip4addr.s_addr &= htonl(mask);
159                 }
160                 break;
161
162         case AF_INET6:
163                 if (client->prefix > 128) return 0;
164
165                 if (client->prefix == 0) {
166                         memset(&client->ipaddr.ipaddr.ip6addr, 0,
167                                sizeof(client->ipaddr.ipaddr.ip6addr));
168
169                 } else if (client->prefix < 128) {
170                         int i;
171                         uint32_t mask, *addr;
172
173                         addr = (uint32_t *) &client->ipaddr.ipaddr.ip6addr;
174
175                         for (i = client->prefix; i < 128; i += 32) {
176                                 mask = ~0;
177                                 mask <<= ((128 - i) & 0x1f);
178                                 addr[i / 32] &= mask;
179                         }
180                 }
181                 break;
182
183         default:
184                 return 0;
185         }
186
187         return 1;
188 }
189
190
191 /*
192  *      Add a client to the tree.
193  */
194 int client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
195 {
196         if (!client) {
197                 return 0;
198         }
199
200         /*
201          *      If "clients" is NULL, it means add to the global list.
202          */
203         if (!clients) {
204                 /*
205                  *      Initialize it, if not done already.
206                  */
207                 if (!root_clients) {
208                         root_clients = clients_init();
209                         if (!root_clients) return 0;
210                 }
211                 clients = root_clients;
212         }
213
214         if ((client->prefix < 0) || (client->prefix > 128)) {
215                 return 0;
216         }
217
218         if (!client_sane(client)) return 0;
219
220         /*
221          *      Create a tree for it.
222          */
223         if (!clients->trees[client->prefix]) {
224                 clients->trees[client->prefix] = rbtree_create(client_ipaddr_cmp,
225                                                                (void *) client_free, 0);
226                 if (!clients->trees[client->prefix]) {
227                         return 0;
228                 }
229         }
230
231         /*
232          *      Cannot insert the same client twice.
233          */
234         if (rbtree_find(clients->trees[client->prefix], client)) {
235                 radlog(L_ERR, "Failed to add duplicate client %s",
236                        client->shortname);
237                 return 0;
238         }
239
240         /*
241          *      Other error adding client: likely is fatal.
242          */
243         if (!rbtree_insert(clients->trees[client->prefix], client)) {
244                 return 0;
245         }
246
247 #ifdef WITH_SNMP
248         if (!tree_num) {
249                 tree_num = rbtree_create(client_num_cmp, NULL, 0);
250         }
251
252
253         /*
254          *      Catch clients added by rlm_sql.
255          */
256         if (!client->auth) {
257                 client->auth = rad_malloc(sizeof(*client->auth));
258                 memset(client->auth, 0, sizeof(*client->auth));
259         }
260
261         if (!client->acct) {
262                 client->acct = rad_malloc(sizeof(*client->acct));
263                 memset(client->acct, 0, sizeof(*client->acct));
264         }
265
266
267         client->number = tree_num_max;
268         tree_num_max++;
269         if (tree_num) rbtree_insert(tree_num, client);
270 #endif
271
272         if (client->prefix < clients->min_prefix) {
273                 clients->min_prefix = client->prefix;
274         }
275
276         return 1;
277 }
278
279
280 /*
281  *      Find a client in the RADCLIENTS list by number.
282  *      This is a support function for the SNMP code.
283  */
284 RADCLIENT *client_findbynumber(const RADCLIENT_LIST *clients,
285                                int number)
286 {
287 #ifdef WITH_SNMP
288         if (!clients) clients = root_clients;
289
290         if (!clients) return NULL;
291
292         if (number >= tree_num_max) return NULL;
293
294         if (tree_num) {
295                 RADCLIENT myclient;
296
297                 myclient.number = number;
298
299                 return rbtree_finddata(tree_num, &myclient);
300         }
301 #else
302         clients = clients;      /* -Wunused */
303         number = number;        /* -Wunused */
304 #endif
305         return NULL;
306 }
307
308
309 /*
310  *      Find a client in the RADCLIENTS list.
311  */
312 RADCLIENT *client_find(const RADCLIENT_LIST *clients,
313                        const fr_ipaddr_t *ipaddr)
314 {
315         int i, max_prefix;
316         RADCLIENT myclient;
317
318         if (!clients) clients = root_clients;
319
320         if (!clients || !ipaddr) return NULL;
321
322         switch (ipaddr->af) {
323         case AF_INET:
324                 max_prefix = 32;
325                 break;
326
327         case AF_INET6:
328                 max_prefix = 128;
329                 break;
330
331         default :
332                 return NULL;
333         }
334
335         for (i = max_prefix; i >= clients->min_prefix; i--) {
336                 void *data;
337
338                 myclient.prefix = i;
339                 myclient.ipaddr = *ipaddr;
340                 client_sane(&myclient); /* clean up the ipaddress */
341
342                 if (!clients->trees[i]) continue;
343
344                 data = rbtree_finddata(clients->trees[i], &myclient);
345                 if (data) {
346                         return data;
347                 }
348         }
349
350         return NULL;
351 }
352
353
354 /*
355  *      Old wrapper for client_find
356  */
357 RADCLIENT *client_find_old(const fr_ipaddr_t *ipaddr)
358 {
359         return client_find(root_clients, ipaddr);
360 }
361
362 static struct in_addr cl_ip4addr;
363 static struct in6_addr cl_ip6addr;
364
365 static const CONF_PARSER client_config[] = {
366         { "ipaddr",  PW_TYPE_IPADDR,
367           0, &cl_ip4addr,  NULL },
368         { "ipv6addr",  PW_TYPE_IPV6ADDR,
369           0, &cl_ip6addr, NULL },
370         { "netmask",  PW_TYPE_INTEGER,
371           offsetof(RADCLIENT, prefix), 0, NULL },
372
373         { "require_message_authenticator",  PW_TYPE_BOOLEAN,
374           offsetof(RADCLIENT, message_authenticator), 0, "no" },
375
376         { "secret",  PW_TYPE_STRING_PTR,
377           offsetof(RADCLIENT, secret), 0, NULL },
378         { "shortname",  PW_TYPE_STRING_PTR,
379           offsetof(RADCLIENT, shortname), 0, NULL },
380         { "nastype",  PW_TYPE_STRING_PTR,
381           offsetof(RADCLIENT, nastype), 0, NULL },
382         { "login",  PW_TYPE_STRING_PTR,
383           offsetof(RADCLIENT, login), 0, NULL },
384         { "password",  PW_TYPE_STRING_PTR,
385           offsetof(RADCLIENT, password), 0, NULL },
386         { "virtual_server",  PW_TYPE_STRING_PTR,
387           offsetof(RADCLIENT, server), 0, NULL },
388         { "server",  PW_TYPE_STRING_PTR, /* compatability with 2.0-pre */
389           offsetof(RADCLIENT, server), 0, NULL },
390
391         { NULL, -1, 0, NULL, NULL }
392 };
393
394
395 static RADCLIENT *client_parse(CONF_SECTION *cs, int in_server)
396 {
397         RADCLIENT       *c;
398         const char      *name2;
399
400         name2 = cf_section_name2(cs);
401         if (!name2) {
402                 cf_log_err(cf_sectiontoitem(cs),
403                            "Missing client name");
404                 return NULL;
405         }
406
407         /*
408          * The size is fine.. Let's create the buffer
409          */
410         c = rad_malloc(sizeof(*c));
411         memset(c, 0, sizeof(*c));
412         c->cs = cs;
413
414 #ifdef WITH_SNMP
415         c->auth = rad_malloc(sizeof(*c->auth));
416         memset(c->auth, 0, sizeof(*c->auth));
417
418         c->acct = rad_malloc(sizeof(*c->acct));
419         memset(c->acct, 0, sizeof(*c->acct));
420 #endif
421
422         memset(&cl_ip4addr, 0, sizeof(cl_ip4addr));
423         memset(&cl_ip6addr, 0, sizeof(cl_ip6addr));
424         c->prefix = -1;
425
426         if (cf_section_parse(cs, c, client_config) < 0) {
427                 client_free(c);
428                 cf_log_err(cf_sectiontoitem(cs),
429                            "Error parsing client section.");
430                 return NULL;
431         }
432
433         /*
434          *      Global clients can set servers to use,
435          *      per-server clients cannot.
436          */
437         if (in_server && c->server) {
438                 client_free(c);
439                 cf_log_err(cf_sectiontoitem(cs),
440                            "Clients inside of an server section cannot point to a server.");
441                 return NULL;
442         }
443                 
444         /*
445          *      No "ipaddr" or "ipv6addr", use old-style
446          *      "client <ipaddr> {" syntax.
447          */
448         if (!cf_pair_find(cs, "ipaddr") &&
449             !cf_pair_find(cs, "ipv6addr")) {
450                 char *prefix_ptr;
451
452                 prefix_ptr = strchr(name2, '/');
453
454                 /*
455                  *      Look for prefixes.
456                  */
457                 if (prefix_ptr) {
458                         c->prefix = atoi(prefix_ptr + 1);
459                         if ((c->prefix < 0) || (c->prefix > 128)) {
460                                 client_free(c);
461                                 cf_log_err(cf_sectiontoitem(cs),
462                                            "Invalid Prefix value '%s' for IP.",
463                                            prefix_ptr + 1);
464                                 return NULL;
465                         }
466                         /* Replace '/' with '\0' */
467                         *prefix_ptr = '\0';
468                 }
469                         
470                 /*
471                  *      Always get the numeric representation of IP
472                  */
473                 if (ip_hton(name2, AF_UNSPEC, &c->ipaddr) < 0) {
474                         client_free(c);
475                         cf_log_err(cf_sectiontoitem(cs),
476                                    "Failed to look up hostname %s: %s",
477                                    name2, librad_errstr);
478                         return NULL;
479                 }
480
481                 if (prefix_ptr) *prefix_ptr = '/';
482                 c->longname = strdup(name2);
483
484                 if (!c->shortname) c->shortname = strdup(c->longname);
485
486         } else {
487                 char buffer[1024];
488
489                 /*
490                  *      Figure out which one to use.
491                  */
492                 if (cf_pair_find(cs, "ipaddr")) {
493                         c->ipaddr.af = AF_INET;
494                         c->ipaddr.ipaddr.ip4addr = cl_ip4addr;
495
496                         if ((c->prefix < -1) || (c->prefix > 32)) {
497                                 client_free(c);
498                                 cf_log_err(cf_sectiontoitem(cs),
499                                            "Netmask must be between 0 and 32");
500                                 return NULL;
501                         }
502                                 
503                 } else if (cf_pair_find(cs, "ipv6addr")) {
504                         c->ipaddr.af = AF_INET6;
505                         c->ipaddr.ipaddr.ip6addr = cl_ip6addr;
506                                 
507                         if ((c->prefix < -1) || (c->prefix > 128)) {
508                                 client_free(c);
509                                 cf_log_err(cf_sectiontoitem(cs),
510                                            "Netmask must be between 0 and 128");
511                                 return NULL;
512                         }
513                 } else {
514                         cf_log_err(cf_sectiontoitem(cs),
515                                    "No IP address defined for the client");
516                         client_free(c);
517                         return NULL;
518                 }
519
520                 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
521                 c->longname = strdup(buffer);
522
523                 /*
524                  *      Set the short name to the name2
525                  */
526                 if (!c->shortname) c->shortname = strdup(name2);
527         }
528
529         if (c->prefix < 0) switch (c->ipaddr.af) {
530         case AF_INET:
531                 c->prefix = 32;
532                 break;
533         case AF_INET6:
534                 c->prefix = 128;
535                 break;
536         default:
537                 break;
538         }
539
540         if (!c->secret || !*c->secret) {
541 #ifdef WITH_DHCP
542                 const char *value = NULL;
543                 CONF_PAIR *cp = cf_pair_find(cs, "dhcp");
544
545                 if (cp) value = cf_pair_value(cp);
546
547                 /*
548                  *      Secrets aren't needed for DHCP.
549                  */
550                 if (value && (strcmp(value, "yes") == 0)) return c;
551
552 #endif
553                 client_free(c);
554                 cf_log_err(cf_sectiontoitem(cs),
555                            "secret must be at least 1 character long");
556                 return NULL;
557         }
558
559
560         return c;
561 }
562
563 /*
564  *      Create the linked list of clients from the new configuration
565  *      type.  This way we don't have to change too much in the other
566  *      source-files.
567  */
568 RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section)
569 {
570         int             global = FALSE, in_server = FALSE;
571         CONF_SECTION    *cs;
572         RADCLIENT       *c;
573         RADCLIENT_LIST  *clients;
574
575         /*
576          *      Be forgiving.  If there's already a clients, return
577          *      it.  Otherwise create a new one.
578          */
579         clients = cf_data_find(section, "clients");
580         if (clients) return clients;
581
582         clients = clients_init();
583         if (!clients) return NULL;
584
585         if (cf_top_section(section) == section) global = TRUE;
586
587         if (strcmp("server", cf_section_name1(section)) == 0) in_server = TRUE;
588
589         /*
590          *      Associate the clients structure with the section, where
591          *      it will be freed once the section is freed.
592          */
593         if (cf_data_add(section, "clients", clients, (void *) clients_free) < 0) {
594                 cf_log_err(cf_sectiontoitem(section),
595                            "Failed to associate clients with section %s",
596                        cf_section_name1(section));
597                 clients_free(clients);
598                 return NULL;
599         }
600
601         for (cs = cf_subsection_find_next(section, NULL, "client");
602              cs != NULL;
603              cs = cf_subsection_find_next(section, cs, "client")) {
604                 c = client_parse(cs, in_server);
605                 if (!c) {
606                         return NULL;
607                 }
608
609                 /*
610                  *      FIXME: Add the client as data via cf_data_add,
611                  *      for migration issues.
612                  */
613
614                 if (!client_add(clients, c)) {
615                         cf_log_err(cf_sectiontoitem(cs),
616                                    "Failed to add client %s",
617                                    cf_section_name2(cs));
618                         client_free(c);
619                         return NULL;
620                 }
621         }
622
623         /*
624          *      Replace the global list of clients with the new one.
625          *      The old one is still referenced from the original
626          *      configuration, and will be freed when that is freed.
627          */
628         if (global) {
629                 root_clients = clients;
630         }
631
632         return clients;
633 }