c8a7d6a4fbce1aa1dc3d494f067658202e918d1c
[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
75         clients_free(mainconfig.clients);
76         mainconfig.clients = NULL;
77
78         if ((fp = fopen(file, "r")) == NULL) {
79                 /* The clients file is no longer required.  All configuration
80                    information is read from radiusd.conf and friends.  If
81                    clients exists it will be used, but if it doesn't no harm
82                    done. */
83                 return 0;
84         }
85         radlog(L_INFO, "Using deprecated clients file.  Support for this will go away soon.");
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 i, 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                         mask = (1 << 31);
137                         for (i = 1; i < mask_length; i++) {
138                                 mask |= (mask >> 1);
139                         }
140                 }
141
142                 /*
143                  *      Double-check lengths to be sure they're sane
144                  */
145                 if (strlen(hostnm) >= sizeof(c->longname)) {
146                         radlog(L_ERR, "%s[%d]: host name of length %d is greater than the allowed maximum of %d.",
147                                file, lineno,
148                                (int) strlen(hostnm),
149                                (int) sizeof(c->longname) - 1);
150                         return -1;
151                 }
152                 if (strlen(secret) >= sizeof(c->secret)) {
153                         radlog(L_ERR, "%s[%d]: secret of length %d is greater than the allowed maximum of %d.",
154                                file, lineno,
155                                (int) strlen(secret),
156                                (int) sizeof(c->secret) - 1);
157                         return -1;
158                 }
159                 if (strlen(shortnm) > sizeof(c->shortname)) {
160                         radlog(L_ERR, "%s[%d]: short name of length %d is greater than the allowed maximum of %d.",
161                                file, lineno,
162                                (int) strlen(shortnm),
163                                (int) sizeof(c->shortname) - 1);
164                         return -1;
165                 }
166                 
167                 /*
168                  *      It should be OK now, let's create the buffer.
169                  */
170                 c = rad_malloc(sizeof(RADCLIENT));
171                 memset(c, 0, sizeof(*c));
172
173                 c->ipaddr = ip_getaddr(hostnm);
174                 if (c->ipaddr == INADDR_NONE) {
175                         radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
176                                         file, lineno, hostnm);
177                         return -1;
178                 }
179                 c->netmask = htonl(mask);
180                 c->ipaddr &= c->netmask; /* addr & mask are in network order */
181
182                 strcpy((char *)c->secret, secret);
183                 strcpy(c->shortname, shortnm);
184
185                 /*
186                  *      Only do DNS lookups for machines.  Just print
187                  *      the network as the long name.
188                  */
189                 if ((~mask) == 0) {
190                         NAS *nas;
191                         ip_hostname(c->longname, sizeof(c->longname), c->ipaddr);
192
193                         /*
194                          *      Pull information over from the NAS.
195                          */
196                         nas = nas_find(c->ipaddr);
197                         if (nas) {
198                                 /*
199                                  *      No short name in the 'clients' file,
200                                  *      try copying one over from the
201                                  *      'naslist' file.
202                                  */
203                                 if (c->shortname[0] == '\0') {
204                                         strcpy(c->shortname, nas->shortname);
205                                 }
206
207                                 /*
208                                  *  Copy the nastype over, too.
209                                  */
210                                 strcpy(c->nastype, nas->nastype);
211                         }
212                 } else {
213                         hostnm[strlen(hostnm)] = '/';
214                         strNcpy(c->longname, hostnm, sizeof(c->longname));
215                 }
216
217                 c->next = mainconfig.clients;
218                 mainconfig.clients = c;
219         }
220         fclose(fp);
221
222         return 0;
223 }
224
225
226 /*
227  *      Find a client in the RADCLIENTS list.
228  */
229 RADCLIENT *client_find(uint32_t ipaddr)
230 {
231         RADCLIENT *cl;
232         RADCLIENT *match = NULL;
233
234         for (cl = mainconfig.clients; cl; cl = cl->next) {
235                 if ((ipaddr & cl->netmask) == cl->ipaddr) {
236                         if ((!match) ||
237                             (ntohl(cl->netmask) > ntohl(match->netmask))) {
238                                 match = cl;
239                         }
240                 }
241         }
242
243         return match;
244 }
245
246 /*
247  *      Walk the RADCLIENT list displaying the clients.  This function
248  *      is for debugging purposes.
249  */
250 void client_walk(void) 
251 {
252         RADCLIENT *cl;
253         char host_ipaddr[16];
254
255         for (cl = mainconfig.clients; cl != NULL; cl = cl->next)
256                 radlog(L_ERR, "client: client_walk: %s\n",
257                                 ip_ntoa(host_ipaddr, cl->ipaddr));
258 }
259
260 /*
261  *      Find the name of a client (prefer short name).
262  */
263 const char *client_name(uint32_t ipaddr)
264 {
265         /* We don't call this unless we should know about the client. */
266         RADCLIENT *cl;
267         char host_ipaddr[16];
268
269         if ((cl = client_find(ipaddr)) != NULL) {
270                 if (cl->shortname[0])
271                         return cl->shortname;
272                 else
273                         return cl->longname;
274         }
275         
276         /* 
277          * this isn't normally reachable, but if a loggable event happens just 
278          * after a client list change and a HUP, then we may not know this 
279          * information any more.
280          *
281          * If you see lots of these, then there's something wrong.
282          */
283         radlog(L_ERR, "Trying to look up name of unknown client %s.\n",
284                ip_ntoa(host_ipaddr, ipaddr));
285
286         return "UNKNOWN-CLIENT";
287 }