Fix a little header problem
[freeradius.git] / src / main / radzap.c
1 /*
2  * radzap.c     Zap a user from the radutmp and radwtmp file.
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  Alan DeKok <aland@ox.org>
22  */
23
24 #include        "autoconf.h"
25 #include        "libradius.h"
26
27 #include        <sys/file.h>
28
29 #include        <stdio.h>
30 #include        <stdlib.h>
31 #include        <string.h>
32 #include        <fcntl.h>
33 #include        <netdb.h>
34 #include        <limits.h>
35 #include        <sys/types.h>
36 #include        <sys/socket.h>
37
38 #if HAVE_NETINET_IN_H
39 #  include      <netinet/in.h>
40 #endif
41
42 #if HAVE_MALLOC_H
43 #  include      <malloc.h>
44 #endif
45
46 #include        "radiusd.h"
47 #include        "radutmp.h"
48
49 /* FIXME: Some of the following are unused and just there to make the linker
50  * happy. Also all of log.o is linked in mainly to make the linker happy. */
51 int debug_flag = 0;
52 const char *progname;
53 const char *radlog_dir = NULL;
54 const char *radius_dir = NULL;
55 #if 0
56 int auth_port; /* Not really used */
57 #endif
58 int acct_port = 0;
59
60 #define LOCK_LEN sizeof(struct radutmp)
61
62 /*
63  *      Internal wrapper for locking, to minimize the number of ifdef's
64  *      in the source. Copied from rlm_radutmp.c (was src/main/radutmp.c),
65  *      perhaps these wrappers should be #defined in radutmp.h
66  *
67  *      Lock the utmp file, prefer lockf() over flock()
68  */
69 static void radutmp_lock(int fd)
70 {
71 #if defined(F_LOCK) && !defined(BSD)
72         (void)lockf(fd, F_LOCK, LOCK_LEN);
73 #else
74         (void)flock(fd, LOCK_EX);
75 #endif
76 }
77
78 /*
79  *      Internal wrapper for unlocking, to minimize the number of ifdef's
80  *      in the source.
81  *
82  *      Unlock the utmp file, prefer lockf() over flock()
83  */
84 static void radutmp_unlock(int fd)
85 {
86 #if defined(F_LOCK) && !defined(BSD)
87         (void)lockf(fd, F_ULOCK, LOCK_LEN);
88 #else
89         (void)flock(fd, LOCK_UN);
90 #endif
91 }
92
93 static int radutmp_lookup(struct radutmp *u, uint32_t nasaddr, int port,
94                           const char *user)
95 {
96         int             fd;
97
98         if ((fd = open(RADUTMP, O_RDONLY|O_CREAT, 0644)) >= 0) {
99                 /*
100                  *      Lock the utmp file, prefer lockf() over flock().
101                  */
102                 radutmp_lock(fd);
103
104                 /*
105                  *      Find the entry for this NAS / portno combination.
106                  */
107                 while (read(fd, u, sizeof(*u)) == sizeof(*u)) {
108                         if ((nasaddr != 0 && nasaddr != u->nas_address) ||
109                               (port >= 0  && port    != u->nas_port) ||
110                               (user != NULL &&
111                                strncmp(u->login, user, sizeof u->login) != 0) ||
112                                u->type != P_LOGIN)
113                                 continue;
114                         /*
115                          *      Match. Zap it.
116                          */
117                         close(fd);
118                         return 1;
119                 }
120                 close(fd);
121         }
122         return 0;
123 }
124 static int do_accton_packet(uint32_t nasaddr);
125 static int do_stop_packet(const struct radutmp *u);
126
127 /*
128  *      Zap a user from the radutmp and radwtmp file.
129  */
130 int main(int argc, char **argv)
131 {
132         NAS     *nas;
133         uint32_t ip = 0;
134         int     nas_port = -1;
135         char    *user = NULL;
136         char    *s;
137         char    buf[256];
138         struct radutmp u;
139
140         progname = argv[0];
141         --argc, ++argv;
142         if (argc > 1 && !strcmp(argv[0], "-p")) {
143                 acct_port = atoi(argv[1]);
144                 argc -= 2, argv+=2;
145         }
146         if (argc < 1 || argc > 3 || argv[1][0] == '-') {
147                 fprintf(stderr, "Usage: radzap termserver [port] [user]\n");
148                 fprintf(stderr, "       radzap is only an admin tool to clean the radutmp file!\n");
149                 exit(1);
150         }
151         if (argc > 1) {
152                 s = argv[1];
153                 if (*s == 's' || *s == 'S') s++;
154                 nas_port = atoi(s);
155         }
156         if (argc > 2) user     = argv[2];
157
158         radius_dir = strdup(RADIUS_DIR);
159
160         /*
161          *      Read the "naslist" file.
162          */
163         sprintf(buf, "%s/%s", RADIUS_DIR, RADIUS_NASLIST);
164         if (read_naslist_file(buf) < 0)
165                 exit(1);
166
167         /*
168          *      Find the IP address of the terminal server.
169          */
170         if ((nas = nas_findbyname(argv[0])) == NULL && argv[0][0] != 0) {
171                 if ((ip = ip_getaddr(argv[0])) == INADDR_NONE) {
172                         fprintf(stderr, "%s: host not found.\n", argv[0]);
173                         exit(1);
174                 }
175         }
176         if (nas) ip = nas->ipaddr;
177
178         printf("radzap: zapping termserver %s, port %d",
179                 ip_hostname(buf, sizeof(buf), ip), nas_port);
180         if (user) printf(", user %s", user);
181         printf("\n");
182
183         if(nas_port < 0) {
184                 return do_accton_packet(ip);
185         }
186
187         if(!radutmp_lookup(&u, ip, nas_port, user)) {
188                 fprintf(stderr, "Entry not found\n");
189                 return 1;
190         }
191
192         return do_stop_packet(&u);
193 }
194
195 static int getport(const char *name)
196 {
197         struct  servent         *svp;
198
199         svp = getservbyname (name, "udp");
200         if (!svp) {
201                 return 0;
202         }
203
204         return ntohs(svp->s_port);
205 }
206
207 static const char *getlocalhostsecret(void)
208 {
209         RADCLIENT *cl;
210         char fn[PATH_MAX];
211         snprintf(fn, sizeof fn, "%s/%s", radius_dir, RADIUS_CLIENTS);
212         if(read_clients_file(fn)<0) {
213                 radlog(L_ERR|L_CONS, "Errors reading clients");
214                 exit(1);
215         }
216         cl=client_find(htonl(INADDR_LOOPBACK));
217         if(!cl) {
218                 radlog(L_ERR|L_CONS, "No clients entry for localhost");
219                 exit(1);
220         }
221         return (const char *)cl->secret;
222 }
223
224 /* Packet-fabrication macros. Don't stare directly at them without protective
225  * eye gear */
226 #define PAIR(n,v,t,e) do { \
227   if(!(vp=paircreate(n, t))) { \
228     radlog(L_ERR|L_CONS, "no memory"); \
229     pairfree(&req->vps); \
230     return 1; \
231   } \
232   vp->e=v; \
233   pairadd(&req->vps, vp); \
234 } while(0)
235 #define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
236 #define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
237 #define STRINGPAIR(n,v) do { \
238   if(!(vp=paircreate(n, PW_TYPE_STRING))) { \
239     radlog(L_ERR|L_CONS, "no memory"); \
240     pairfree(&req->vps); \
241     return 1; \
242   } \
243   strNcpy((char *)vp->strvalue, v, sizeof vp->strvalue); \
244   vp->length=strlen(v); \
245   pairadd(&req->vps, vp); \
246 } while(0)
247
248 static int do_packet(int allports, uint32_t nasaddr, const struct radutmp *u)
249 {
250         int i, retries=5, timeout=3;
251         struct timeval tv;
252         RADIUS_PACKET *req, *rep;
253         VALUE_PAIR *vp;
254         const char *secret=getlocalhostsecret();
255
256         if ((req = rad_alloc(1)) == NULL) {
257                 librad_perror("radzap");
258                 exit(1);
259         }
260         req->id = getpid() & 0xFF;
261         req->code = PW_ACCOUNTING_REQUEST;
262         req->dst_port = acct_port;
263         if(req->dst_port == 0) req->dst_port = getport("radacct");
264         if(req->dst_port == 0) req->dst_port = PW_ACCT_UDP_PORT;
265         req->dst_ipaddr = ip_getaddr("localhost");
266         if(!req->dst_ipaddr) req->dst_ipaddr = 0x7f000001;
267         req->vps = NULL;
268
269         if(allports) {
270                 INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_ACCOUNTING_OFF);
271                 IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
272                 INTPAIR(PW_ACCT_DELAY_TIME, 0);
273         } else {
274                 char login[sizeof u->login+1];
275                 char session_id[sizeof u->session_id+1];
276                 strNcpy(login, u->login, sizeof login);
277                 strNcpy(session_id, u->session_id, sizeof session_id);
278                 INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
279                 IPPAIR(PW_NAS_IP_ADDRESS, u->nas_address);
280                 INTPAIR(PW_ACCT_DELAY_TIME, 0);
281                 STRINGPAIR(PW_USER_NAME, login);
282                 INTPAIR(PW_NAS_PORT_ID, u->nas_port);
283                 STRINGPAIR(PW_ACCT_SESSION_ID, session_id);
284                 if(u->proto=='P') {
285                   INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
286                   INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
287                 } else if(u->proto=='S') {
288                   INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
289                   INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
290                 } else {
291                   INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
292                 }
293                 IPPAIR(PW_FRAMED_IP_ADDRESS, u->framed_address);
294                 INTPAIR(PW_ACCT_SESSION_TIME, 0);
295                 INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
296                 INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
297                 INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
298                 INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
299         }
300         if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
301                 perror("radzap: socket: ");
302                 exit(1);
303         }
304
305         for (i = 0; i < retries; i++) {
306                 fd_set          rdfdesc;
307
308                 rad_send(req, secret);
309
310                 /* And wait for reply, timing out as necessary */
311                 FD_ZERO(&rdfdesc);
312                 FD_SET(req->sockfd, &rdfdesc);
313
314                 tv.tv_sec = (int)timeout;
315                 tv.tv_usec = 1000000 * (timeout - (int)timeout);
316
317                 /* Something's wrong if we don't get exactly one fd. */
318                 if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) {
319                         continue;
320                 }
321
322                 rep = rad_recv(req->sockfd);
323                 if (rep != NULL) {
324                         break;
325                 } else {        /* NULL: couldn't receive the packet */
326                         librad_perror("radzap:");
327                         exit(1);
328                 }
329         }
330
331         /* No response or no data read (?) */
332         if (i == retries) {
333                 fprintf(stderr, "radzap: no response from server\n");
334                 exit(1);
335         }
336
337         if (rad_decode(rep, req, secret) != 0) {
338                 librad_perror("rad_decode");
339                 exit(1);
340         }
341
342         vp_printlist(stdout, rep->vps);
343         return 0;
344 }
345
346 static int do_accton_packet(uint32_t nasaddr)
347 {
348   return do_packet(1, nasaddr, 0);
349 }
350
351 static int do_stop_packet(const struct radutmp *u)
352 {
353   return do_packet(0, 0, u);
354 }
355
356 #if 0
357 /* FIXME: Not called. Needed for files.o to link. Ick */
358 int setup_modules(void); /* -Wmissing-prototypes */
359 int setup_modules(void)
360 {
361   abort();
362 }
363
364 /* FIXME: Not called. Needed for files.o to link. Ick */
365 int read_radius_conf_file(void); /* -Wmissing-prototypes */
366 int read_radius_conf_file(void)
367 {
368   abort();
369 }
370 #endif