1a80a3d64ce994590d0e42f4890b88e54aab23cf
[freeradius.git] / src / main / client.c
1 /*
2  * files.c      Read config files 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Miquel van Smoorenburg <miquels@cistron.nl>
22  * Copyright 2000  Alan DeKok <aland@ox.org>
23  */
24
25 static const char rcsid[] = "$Id$";
26
27 #include "autoconf.h"
28 #include "libradius.h"
29
30 #include <sys/stat.h>
31
32 #ifdef HAVE_NETINET_IN_H
33 #       include <netinet/in.h>
34 #endif
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <netdb.h>
39 #include <ctype.h>
40 #include <fcntl.h>
41
42 #include "radiusd.h"
43 #include "conffile.h"
44
45 /*
46  *      Free a RADCLIENT list.
47  */
48 void clients_free(RADCLIENT *cl)
49 {
50         RADCLIENT *next;
51
52         while(cl) {
53                 next = cl->next;
54                 free(cl);
55                 cl = next;
56         }
57 }
58
59
60 /*
61  *      Read the clients file.
62  */
63 int read_clients_file(const char *file)
64 {
65         FILE *fp;
66         RADCLIENT *c;
67         char buffer[256];
68         char hostnm[256];
69         char secret[256];
70         char shortnm[256];
71         uint32_t mask;
72         int lineno = 0;
73         char *p;
74         int got_clients = FALSE;
75
76         clients_free(mainconfig.clients);
77         mainconfig.clients = NULL;
78
79         if ((fp = fopen(file, "r")) == NULL) {
80                 /* The clients file is no longer required.  All configuration
81                    information is read from radiusd.conf and friends.  If
82                    clients exists it will be used, but if it doesn't no harm
83                    done. */
84                 return 0;
85         }
86
87         while(fgets(buffer, 256, fp) != NULL) {
88                 lineno++;
89                 if (!feof(fp) && (strchr(buffer, '\n') == NULL)) {
90                         radlog(L_ERR, "%s[%d]: line too long", file, lineno);
91                         return -1;
92                 }
93
94                 /*
95                  *      Skip whitespace.
96                  */
97                 p = buffer;
98                 while (*p &&
99                                 ((*p == ' ') || (*p == '\t')))
100                         p++;
101
102                 /*
103                  *      Skip comments and blank lines.
104                  */
105                 if ((*p == '#') || (*p == '\n') || (*p == '\r'))
106                         continue;
107
108                 if (!getword(&p, hostnm, sizeof(hostnm)) ||
109                                 !getword(&p, secret, sizeof(secret))) {
110                         radlog(L_ERR, "%s[%d]: unexpected end of line",
111                                         file, lineno);
112                         return -1;
113                 }
114
115                 (void)getword(&p, shortnm, sizeof(shortnm));
116
117                 /*
118                  *      Look for a mask in the hostname
119                  */
120                 p = strchr(hostnm, '/');
121                 mask = ~0;
122
123                 if (p) {
124                         int mask_length;
125
126                         *p = '\0';
127                         p++;
128
129                         mask_length = atoi(p);
130                         if ((mask_length < 0) || (mask_length > 32)) {
131                                 radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.",
132                                        file, lineno, p);
133                                 return -1;
134                         }
135
136                         if (mask_length == 0) {
137                                 mask = 0;
138                         } else {
139                                 mask = ~0 << (32 - mask_length);
140                         }
141                 }
142
143                 /*
144                  *      Double-check lengths to be sure they're sane
145                  */
146                 if (strlen(hostnm) >= sizeof(c->longname)) {
147                         radlog(L_ERR, "%s[%d]: host name of length %d is greater than the allowed maximum of %d.",
148                                file, lineno,
149                                (int) strlen(hostnm),
150                                (int) sizeof(c->longname) - 1);
151                         return -1;
152                 }
153                 if (strlen(secret) >= sizeof(c->secret)) {
154                         radlog(L_ERR, "%s[%d]: secret of length %d is greater than the allowed maximum of %d.",
155                                file, lineno,
156                                (int) strlen(secret),
157                                (int) sizeof(c->secret) - 1);
158                         return -1;
159                 }
160                 if (strlen(shortnm) > sizeof(c->shortname)) {
161                         radlog(L_ERR, "%s[%d]: short name of length %d is greater than the allowed maximum of %d.",
162                                file, lineno,
163                                (int) strlen(shortnm),
164                                (int) sizeof(c->shortname) - 1);
165                         return -1;
166                 }
167
168                 /*
169                  *      It should be OK now, let's create the buffer.
170                  */
171                 got_clients = TRUE;
172                 c = rad_malloc(sizeof(RADCLIENT));
173                 memset(c, 0, sizeof(*c));
174
175                 c->ipaddr = ip_getaddr(hostnm);
176                 if (c->ipaddr == INADDR_NONE) {
177                         clients_free(c);
178                         radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
179                                         file, lineno, hostnm);
180                         return -1;
181                 }
182                 c->netmask = htonl(mask);
183                 c->ipaddr &= c->netmask; /* addr & mask are in network order */
184
185                 strcpy((char *)c->secret, secret);
186                 strcpy(c->shortname, shortnm);
187
188                 /*
189                  *      Only do DNS lookups for machines.  Just print
190                  *      the network as the long name.
191                  */
192                 if ((~mask) == 0) {
193                         NAS *nas;
194                         ip_hostname(c->longname, sizeof(c->longname), c->ipaddr);
195
196                         /*
197                          *      Pull information over from the NAS.
198                          */
199                         nas = nas_find(c->ipaddr);
200                         if (nas) {
201                                 /*
202                                  *      No short name in the 'clients' file,
203                                  *      try copying one over from the
204                                  *      'naslist' file.
205                                  */
206                                 if (c->shortname[0] == '\0') {
207                                         strcpy(c->shortname, nas->shortname);
208                                 }
209
210                                 /*
211                                  *  Copy the nastype over, too.
212                                  */
213                                 strcpy(c->nastype, nas->nastype);
214                         }
215                 } else {
216                         hostnm[strlen(hostnm)] = '/';
217                         strNcpy(c->longname, hostnm, sizeof(c->longname));
218                 }
219
220                 c->next = mainconfig.clients;
221                 mainconfig.clients = c;
222         }
223         fclose(fp);
224
225         if (got_clients) {
226                 radlog(L_INFO, "Using deprecated clients file.  Support for this will go away soon.");
227         }
228
229         return 0;
230 }
231
232
233 /*
234  *      Find a client in the RADCLIENTS list.
235  */
236 RADCLIENT *client_find(uint32_t ipaddr)
237 {
238         RADCLIENT *cl;
239         RADCLIENT *match = NULL;
240
241         for (cl = mainconfig.clients; cl; cl = cl->next) {
242                 if ((ipaddr & cl->netmask) == cl->ipaddr) {
243                         if ((!match) ||
244                             (ntohl(cl->netmask) > ntohl(match->netmask))) {
245                                 match = cl;
246                         }
247                 }
248         }
249
250         return match;
251 }
252
253 /*
254  *      Walk the RADCLIENT list displaying the clients.  This function
255  *      is for debugging purposes.
256  */
257 void client_walk(void)
258 {
259         RADCLIENT *cl;
260         char host_ipaddr[16];
261
262         for (cl = mainconfig.clients; cl != NULL; cl = cl->next)
263                 radlog(L_ERR, "client: client_walk: %s\n",
264                                 ip_ntoa(host_ipaddr, cl->ipaddr));
265 }
266
267 /*
268  *      Find the name of a client (prefer short name).
269  */
270 const char *client_name(uint32_t ipaddr)
271 {
272         /* We don't call this unless we should know about the client. */
273         RADCLIENT *cl;
274         char host_ipaddr[16];
275
276         if ((cl = client_find(ipaddr)) != NULL) {
277                 if (cl->shortname[0])
278                         return cl->shortname;
279                 else
280                         return cl->longname;
281         }
282
283         /*
284          * this isn't normally reachable, but if a loggable event happens just
285          * after a client list change and a HUP, then we may not know this
286          * information any more.
287          *
288          * If you see lots of these, then there's something wrong.
289          */
290         radlog(L_ERR, "Trying to look up name of unknown client %s.\n",
291                ip_ntoa(host_ipaddr, ipaddr));
292
293         return "UNKNOWN-CLIENT";
294 }