import from HEAD:
[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                         radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
178                                         file, lineno, hostnm);
179                         return -1;
180                 }
181                 c->netmask = htonl(mask);
182                 c->ipaddr &= c->netmask; /* addr & mask are in network order */
183
184                 strcpy((char *)c->secret, secret);
185                 strcpy(c->shortname, shortnm);
186
187                 /*
188                  *      Only do DNS lookups for machines.  Just print
189                  *      the network as the long name.
190                  */
191                 if ((~mask) == 0) {
192                         NAS *nas;
193                         ip_hostname(c->longname, sizeof(c->longname), c->ipaddr);
194
195                         /*
196                          *      Pull information over from the NAS.
197                          */
198                         nas = nas_find(c->ipaddr);
199                         if (nas) {
200                                 /*
201                                  *      No short name in the 'clients' file,
202                                  *      try copying one over from the
203                                  *      'naslist' file.
204                                  */
205                                 if (c->shortname[0] == '\0') {
206                                         strcpy(c->shortname, nas->shortname);
207                                 }
208
209                                 /*
210                                  *  Copy the nastype over, too.
211                                  */
212                                 strcpy(c->nastype, nas->nastype);
213                         }
214                 } else {
215                         hostnm[strlen(hostnm)] = '/';
216                         strNcpy(c->longname, hostnm, sizeof(c->longname));
217                 }
218
219                 c->next = mainconfig.clients;
220                 mainconfig.clients = c;
221         }
222         fclose(fp);
223
224         if (got_clients) {
225                 radlog(L_INFO, "Using deprecated clients file.  Support for this will go away soon.");
226         }
227
228         return 0;
229 }
230
231
232 /*
233  *      Find a client in the RADCLIENTS list.
234  */
235 RADCLIENT *client_find(uint32_t ipaddr)
236 {
237         RADCLIENT *cl;
238         RADCLIENT *match = NULL;
239
240         for (cl = mainconfig.clients; cl; cl = cl->next) {
241                 if ((ipaddr & cl->netmask) == cl->ipaddr) {
242                         if ((!match) ||
243                             (ntohl(cl->netmask) > ntohl(match->netmask))) {
244                                 match = cl;
245                         }
246                 }
247         }
248
249         return match;
250 }
251
252 /*
253  *      Walk the RADCLIENT list displaying the clients.  This function
254  *      is for debugging purposes.
255  */
256 void client_walk(void)
257 {
258         RADCLIENT *cl;
259         char host_ipaddr[16];
260
261         for (cl = mainconfig.clients; cl != NULL; cl = cl->next)
262                 radlog(L_ERR, "client: client_walk: %s\n",
263                                 ip_ntoa(host_ipaddr, cl->ipaddr));
264 }
265
266 /*
267  *      Find the name of a client (prefer short name).
268  */
269 const char *client_name(uint32_t ipaddr)
270 {
271         /* We don't call this unless we should know about the client. */
272         RADCLIENT *cl;
273         char host_ipaddr[16];
274
275         if ((cl = client_find(ipaddr)) != NULL) {
276                 if (cl->shortname[0])
277                         return cl->shortname;
278                 else
279                         return cl->longname;
280         }
281
282         /*
283          * this isn't normally reachable, but if a loggable event happens just
284          * after a client list change and a HUP, then we may not know this
285          * information any more.
286          *
287          * If you see lots of these, then there's something wrong.
288          */
289         radlog(L_ERR, "Trying to look up name of unknown client %s.\n",
290                ip_ntoa(host_ipaddr, ipaddr));
291
292         return "UNKNOWN-CLIENT";
293 }