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