Changed comments calling the code Cistron to FreeRADIUS. Corrected some
[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 #if 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 RADCLIENT *clients;
46
47 /*
48  *      Free a RADCLIENT list.
49  */
50 static void clients_free(RADCLIENT *cl)
51 {
52         RADCLIENT *next;
53
54         while(cl) {
55                 next = cl->next;
56                 free(cl);
57                 cl = next;
58         }
59 }
60
61
62 /*
63  *      Read the clients file.
64  */
65 int read_clients_file(const char *file)
66 {
67         FILE *fp;
68         RADCLIENT *c;
69         char buffer[256];
70         char hostnm[256];
71         char secret[256];
72         char shortnm[256];
73         uint32_t mask;
74         int lineno = 0;
75         char *p;
76
77         clients_free(clients);
78         clients = NULL;
79
80         if ((fp = fopen(file, "r")) == NULL) {
81                 /* The clients file is no longer required.  All configuration
82                    information is read from radiusd.conf and friends.  If
83                    clients exists it will be used, but if it doesn't no harm
84                    done. */
85                 return 0;
86         }
87
88         while(fgets(buffer, 256, fp) != NULL) {
89                 lineno++;
90                 if (strchr(buffer, '\n') == NULL) {
91                         radlog(L_ERR, "%s[%d]: line too long", file, lineno);
92                         return -1;
93                 }
94
95                 /*
96                  *      Skip whitespace.
97                  */
98                 p = buffer;
99                 while (*p &&
100                                 ((*p == ' ') || (*p == '\t'))) 
101                         p++;
102
103                 /*
104                  *      Skip comments and blank lines.
105                  */
106                 if ((*p == '#') || (*p == '\n') || (*p == '\r'))
107                         continue;
108
109                 if (!getword(&p, hostnm, sizeof(hostnm)) ||
110                                 !getword(&p, secret, sizeof(secret))) {
111                         radlog(L_ERR, "%s[%d]: unexpected end of line",
112                                         file, lineno);
113                         return -1;
114                 }
115
116                 (void)getword(&p, shortnm, sizeof(shortnm));
117
118                 /*
119                  *      Look for a mask in the hostname
120                  */
121                 p = strchr(hostnm, '/');
122                 mask = ~0;
123
124                 if (p) {
125                         int i, mask_length;
126
127                         *p = '\0';
128                         p++;
129
130                         mask_length = atoi(p);
131                         if ((mask_length <= 0) || (mask_length > 32)) {
132                                 radlog(L_ERR, "%s[%d]: Invalid value '%s' for IP network mask.",
133                                                 file, lineno, p);
134                                 return -1;
135                         }
136
137                         mask = (1 << 31);
138                         for (i = 1; i < mask_length; i++) {
139                                 mask |= (mask >> 1);
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                                         strlen(hostnm), 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                                         strlen(secret), sizeof(c->secret) - 1);
156                         return -1;
157                 }
158                 if (strlen(shortnm) > sizeof(c->shortname)) {
159                         radlog(L_ERR, "%s[%d]: short name of length %d is greater than the allowed maximum of %d.",
160                                         file, lineno,
161                                         strlen(shortnm), sizeof(c->shortname) - 1);
162                         return -1;
163                 }
164                 
165                 /*
166                  *      It should be OK now, let's create the buffer.
167                  */
168                 c = rad_malloc(sizeof(RADCLIENT));
169
170                 c->ipaddr = ip_getaddr(hostnm);
171                 if (c->ipaddr == INADDR_NONE) {
172                         radlog(L_CONS|L_ERR, "%s[%d]: Failed to look up hostname %s",
173                                         file, lineno, hostnm);
174                         return -1;
175                 }
176                 c->netmask = htonl(mask);
177                 c->ipaddr &= mask;
178
179                 strcpy((char *)c->secret, secret);
180                 strcpy(c->shortname, shortnm);
181
182                 /*
183                  *      Only do DNS lookups for machines.  Just print
184                  *      the network as the long name.
185                  */
186                 if (c->netmask == ~0) {
187                         ip_hostname(c->longname, sizeof(c->longname), c->ipaddr);
188                 } else {
189                         hostnm[strlen(hostnm)] = '/';
190                         strNcpy(c->longname, hostnm, sizeof(c->longname));
191                 }
192
193                 c->next = clients;
194                 clients = c;
195         }
196         fclose(fp);
197
198         return 0;
199 }
200
201
202 /*
203  *      Find a client in the RADCLIENTS list.
204  */
205 RADCLIENT *client_find(uint32_t ipaddr)
206 {
207         RADCLIENT *cl;
208         RADCLIENT *match = NULL;
209
210         for(cl = clients; cl; cl = cl->next) {
211                 if ((ipaddr & cl->netmask) == cl->ipaddr) {
212                         if ((!match) ||
213                                         (ntohl(cl->netmask) > ntohl(match->netmask))) {
214                                 match = cl;
215                         }
216                 }
217         }
218
219         return match;
220 }
221
222 /*
223  *      Walk the RADCLIENT list displaying the clients.  This function
224  *      is for debugging purposes.
225  */
226 void client_walk(void) 
227 {
228         RADCLIENT *cl;
229         char host_ipaddr[16];
230
231         for (cl = clients; cl != NULL; cl = cl->next)
232                 radlog(L_ERR, "client: client_walk: %s\n",
233                                 ip_ntoa(host_ipaddr, cl->ipaddr));
234 }
235
236 /*
237  *      Find the name of a client (prefer short name).
238  */
239 const char *client_name(uint32_t ipaddr)
240 {
241         RADCLIENT *cl;
242
243         if ((cl = client_find(ipaddr)) != NULL) {
244                 if (cl->shortname[0])
245                         return cl->shortname;
246                 else
247                         return cl->longname;
248         }
249
250         /*
251          *      We should NEVER reach this piece of code, as we should
252          *      NEVER be looking up client names for clients we don't know!
253          */
254         radlog(L_ERR, "ERROR!  Unreachable code reached, at %s:%d", __FILE__, __LINE__);
255
256         return "UNKNOWN-CLIENT";
257 }