ad79b216aa4314e2cdd936af8ff9d51441b19aea
[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          *      Duplicate?
224          */
225         if (!rbtree_insert(clients->trees[client->prefix], client)) {
226                 return 0;
227         }
228
229 #ifdef WITH_SNMP
230         if (!tree_num) {
231                 tree_num = rbtree_create(client_num_cmp, NULL, 0);
232         }
233
234
235         /*
236          *      Catch clients added by rlm_sql.
237          */
238         if (!client->auth) {
239                 client->auth = rad_malloc(sizeof(*client->auth));
240                 memset(client->auth, 0, sizeof(*client->auth));
241         }
242
243         if (!client->acct) {
244                 client->acct = rad_malloc(sizeof(*client->acct));
245                 memset(client->acct, 0, sizeof(*client->acct));
246         }
247
248
249         client->number = tree_num_max;
250         tree_num_max++;
251         if (tree_num) rbtree_insert(tree_num, client);
252 #endif
253
254         if (client->prefix < clients->min_prefix) {
255                 clients->min_prefix = client->prefix;
256         }
257
258         return 1;
259 }
260
261
262 /*
263  *      Find a client in the RADCLIENTS list by number.
264  *      This is a support function for the SNMP code.
265  */
266 RADCLIENT *client_findbynumber(const RADCLIENT_LIST *clients,
267                                int number)
268 {
269 #ifdef WITH_SNMP
270         if (!clients) clients = root_clients;
271
272         if (!clients) return NULL;
273
274         if (number >= tree_num_max) return NULL;
275
276         if (tree_num) {
277                 RADCLIENT myclient;
278
279                 myclient.number = number;
280
281                 return rbtree_finddata(tree_num, &myclient);
282         }
283 #else
284         clients = clients;      /* -Wunused */
285         number = number;        /* -Wunused */
286 #endif
287         return NULL;
288 }
289
290
291 /*
292  *      Find a client in the RADCLIENTS list.
293  */
294 RADCLIENT *client_find(const RADCLIENT_LIST *clients,
295                        const fr_ipaddr_t *ipaddr)
296 {
297         int i, max_prefix;
298         RADCLIENT myclient;
299
300         if (!clients) clients = root_clients;
301
302         if (!clients || !ipaddr) return NULL;
303
304         switch (ipaddr->af) {
305         case AF_INET:
306                 max_prefix = 32;
307                 break;
308
309         case AF_INET6:
310                 max_prefix = 128;
311                 break;
312
313         default :
314                 return NULL;
315         }
316
317         for (i = max_prefix; i >= clients->min_prefix; i--) {
318                 void *data;
319
320                 myclient.prefix = i;
321                 myclient.ipaddr = *ipaddr;
322                 client_sane(&myclient); /* clean up the ipaddress */
323
324                 if (!clients->trees[i]) continue;
325
326                 data = rbtree_finddata(clients->trees[i], &myclient);
327                 if (data) {
328                         return data;
329                 }
330         }
331
332         return NULL;
333 }
334
335
336 /*
337  *      Old wrapper for client_find
338  */
339 RADCLIENT *client_find_old(const fr_ipaddr_t *ipaddr)
340 {
341         return client_find(root_clients, ipaddr);
342 }
343
344
345 /*
346  *      Find the name of a client (prefer short name).
347  */
348 const char *client_name(const RADCLIENT_LIST *clients,
349                         const fr_ipaddr_t *ipaddr)
350 {
351         /* We don't call this unless we should know about the client. */
352         RADCLIENT *cl;
353         char host_ipaddr[128];
354
355         if ((cl = client_find(clients, ipaddr)) != NULL) {
356                 if (cl->shortname && cl->shortname[0])
357                         return cl->shortname;
358                 else
359                         return cl->longname;
360         }
361
362         /*
363          * this isn't normally reachable, but if a loggable event happens just
364          * after a client list change and a HUP, then we may not know this
365          * information any more.
366          *
367          * If you see lots of these, then there's something wrong.
368          */
369         radlog(L_ERR, "Trying to look up name of unknown client %s.\n",
370                ip_ntoh(ipaddr, host_ipaddr, sizeof(host_ipaddr)));
371
372         return "UNKNOWN-CLIENT";
373 }
374
375 const char *client_name_old(const fr_ipaddr_t *ipaddr)
376 {
377         return client_name(root_clients, ipaddr);
378 }
379
380 static struct in_addr cl_ip4addr;
381 static struct in6_addr cl_ip6addr;
382
383 static const CONF_PARSER client_config[] = {
384         { "ipaddr",  PW_TYPE_IPADDR,
385           0, &cl_ip4addr,  NULL },
386         { "ipv6addr",  PW_TYPE_IPV6ADDR,
387           0, &cl_ip6addr, NULL },
388         { "netmask",  PW_TYPE_INTEGER,
389           offsetof(RADCLIENT, prefix), 0, NULL },
390
391         { "require_message_authenticator",  PW_TYPE_BOOLEAN,
392           offsetof(RADCLIENT, message_authenticator), 0, "no" },
393
394         { "secret",  PW_TYPE_STRING_PTR,
395           offsetof(RADCLIENT, secret), 0, NULL },
396         { "shortname",  PW_TYPE_STRING_PTR,
397           offsetof(RADCLIENT, shortname), 0, NULL },
398         { "nastype",  PW_TYPE_STRING_PTR,
399           offsetof(RADCLIENT, nastype), 0, NULL },
400         { "login",  PW_TYPE_STRING_PTR,
401           offsetof(RADCLIENT, login), 0, NULL },
402         { "password",  PW_TYPE_STRING_PTR,
403           offsetof(RADCLIENT, password), 0, NULL },
404         { "virtual_server",  PW_TYPE_STRING_PTR,
405           offsetof(RADCLIENT, server), 0, NULL },
406         { "server",  PW_TYPE_STRING_PTR, /* compatability with 2.0-pre */
407           offsetof(RADCLIENT, server), 0, NULL },
408
409         { NULL, -1, 0, NULL, NULL }
410 };
411
412
413 static RADCLIENT *client_parse(CONF_SECTION *cs, int global)
414 {
415         RADCLIENT       *c;
416         const char      *name2;
417
418         name2 = cf_section_name2(cs);
419         if (!name2) {
420                 cf_log_err(cf_sectiontoitem(cs),
421                            "Missing client name");
422                 return NULL;
423         }
424
425         /*
426          * The size is fine.. Let's create the buffer
427          */
428         c = rad_malloc(sizeof(*c));
429         memset(c, 0, sizeof(*c));
430         c->cs = cs;
431
432 #ifdef WITH_SNMP
433         c->auth = rad_malloc(sizeof(*c->auth));
434         memset(c->auth, 0, sizeof(*c->auth));
435
436         c->acct = rad_malloc(sizeof(*c->acct));
437         memset(c->acct, 0, sizeof(*c->acct));
438 #endif
439
440         memset(&cl_ip4addr, 0, sizeof(cl_ip4addr));
441         memset(&cl_ip6addr, 0, sizeof(cl_ip6addr));
442         c->prefix = -1;
443
444         if (cf_section_parse(cs, c, client_config) < 0) {
445                 client_free(c);
446                 cf_log_err(cf_sectiontoitem(cs),
447                            "Error parsing client section.");
448                 return NULL;
449         }
450
451         /*
452          *      Global clients can set servers to use,
453          *      per-server clients cannot.
454          */
455         if (!global && c->server) {
456                 client_free(c);
457                 cf_log_err(cf_sectiontoitem(cs),
458                            "Clients inside of an server section cannot point to a server.");
459                 return NULL;
460         }
461                 
462         /*
463          *      No "ipaddr" or "ipv6addr", use old-style
464          *      "client <ipaddr> {" syntax.
465          */
466         if (!cf_pair_find(cs, "ipaddr") &&
467             !cf_pair_find(cs, "ipv6addr")) {
468                 char *prefix_ptr;
469
470                 prefix_ptr = strchr(name2, '/');
471
472                 /*
473                  *      Look for prefixes.
474                  */
475                 if (prefix_ptr) {
476                         c->prefix = atoi(prefix_ptr + 1);
477                         if ((c->prefix < 0) || (c->prefix > 128)) {
478                                 client_free(c);
479                                 cf_log_err(cf_sectiontoitem(cs),
480                                            "Invalid Prefix value '%s' for IP.",
481                                            prefix_ptr + 1);
482                                 return NULL;
483                         }
484                         /* Replace '/' with '\0' */
485                         *prefix_ptr = '\0';
486                 }
487                         
488                 /*
489                  *      Always get the numeric representation of IP
490                  */
491                 if (ip_hton(name2, AF_UNSPEC, &c->ipaddr) < 0) {
492                         client_free(c);
493                         cf_log_err(cf_sectiontoitem(cs),
494                                    "Failed to look up hostname %s: %s",
495                                    name2, librad_errstr);
496                         return NULL;
497                 }
498
499                 if (prefix_ptr) *prefix_ptr = '/';
500                 c->longname = strdup(name2);
501
502                 if (!c->shortname) c->shortname = strdup(c->longname);
503
504         } else {
505                 char buffer[1024];
506
507                 /*
508                  *      Figure out which one to use.
509                  */
510                 if (cf_pair_find(cs, "ipaddr")) {
511                         c->ipaddr.af = AF_INET;
512                         c->ipaddr.ipaddr.ip4addr = cl_ip4addr;
513
514                         if ((c->prefix < -1) || (c->prefix > 32)) {
515                                 client_free(c);
516                                 cf_log_err(cf_sectiontoitem(cs),
517                                            "Netmask must be between 0 and 32");
518                                 return NULL;
519                         }
520                                 
521                 } else if (cf_pair_find(cs, "ipv6addr")) {
522                         c->ipaddr.af = AF_INET6;
523                         c->ipaddr.ipaddr.ip6addr = cl_ip6addr;
524                                 
525                         if ((c->prefix < -1) || (c->prefix > 128)) {
526                                 client_free(c);
527                                 cf_log_err(cf_sectiontoitem(cs),
528                                            "Netmask must be between 0 and 128");
529                                 return NULL;
530                         }
531                 } else {
532                         cf_log_err(cf_sectiontoitem(cs),
533                                    "No IP address defined for the client");
534                         client_free(c);
535                         return NULL;
536                 }
537
538                 ip_ntoh(&c->ipaddr, buffer, sizeof(buffer));
539                 c->longname = strdup(buffer);
540
541                 /*
542                  *      Set the short name to the name2
543                  */
544                 if (!c->shortname) c->shortname = strdup(name2);
545         }
546
547         if (c->prefix < 0) switch (c->ipaddr.af) {
548         case AF_INET:
549                 c->prefix = 32;
550                 break;
551         case AF_INET6:
552                 c->prefix = 128;
553                 break;
554         default:
555                 break;
556         }
557
558         return c;
559 }
560
561 /*
562  *      Create the linked list of clients from the new configuration
563  *      type.  This way we don't have to change too much in the other
564  *      source-files.
565  */
566 RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section)
567 {
568         int             global = FALSE;
569         CONF_SECTION    *cs;
570         RADCLIENT       *c;
571         RADCLIENT_LIST  *clients;
572
573         /*
574          *      Be forgiving.  If there's already a clients, return
575          *      it.  Otherwise create a new one.
576          */
577         clients = cf_data_find(section, "clients");
578         if (clients) return clients;
579
580         clients = clients_init();
581         if (!clients) return NULL;
582
583         if (cf_top_section(section) == section) global = TRUE;
584
585         /*
586          *      Associate the clients structure with the section, where
587          *      it will be freed once the section is freed.
588          */
589         if (cf_data_add(section, "clients", clients, (void *) clients_free) < 0) {
590                 cf_log_err(cf_sectiontoitem(section),
591                            "Failed to associate clients with section %s",
592                        cf_section_name1(section));
593                 clients_free(clients);
594                 return NULL;
595         }
596
597         for (cs = cf_subsection_find_next(section, NULL, "client");
598              cs != NULL;
599              cs = cf_subsection_find_next(section, cs, "client")) {
600                 c = client_parse(cs, global);
601                 if (!c) {
602                         return NULL;
603                 }
604
605                 /*
606                  *      FIXME: Add the client as data via cf_data_add,
607                  *      for migration issues.
608                  */
609
610                 if (!client_add(clients, c)) {
611                         cf_log_err(cf_sectiontoitem(cs),
612                                    "Failed to add client %s",
613                                    cf_section_name2(cs));
614                         client_free(c);
615                         return NULL;
616                 }
617         }
618
619         /*
620          *      Replace the global list of clients with the new one.
621          *      The old one is still referenced from the original
622          *      configuration, and will be freed when that is freed.
623          */
624         if (global) {
625                 root_clients = clients;
626         }
627
628         return clients;
629 }