import from HEAD:
[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 <netdb.h>
33 #include <limits.h>
34 #include <fcntl.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37
38 #ifdef HAVE_NETINET_IN_H
39 #  include <netinet/in.h>
40 #endif
41
42 #include "radiusd.h"
43 #include "radutmp.h"
44 #include "conffile.h"
45
46 const char *progname;
47 const char *radlog_dir = NULL;
48 const char *radius_dir = NULL;
49 const char *radacct_dir = NULL;
50 const char *radlib_dir = NULL;
51 radlog_dest_t radlog_dest = RADLOG_FILES;
52 int debug_flag = 0;
53 int acct_port;
54 int log_stripped_names;
55 struct main_config_t mainconfig;
56 uint32_t radiusip = INADDR_NONE;
57 static void usage(void);
58
59 struct radutmp_config_t {
60   char *radutmp_fn;
61 } radutmpconfig;
62
63 static CONF_PARSER module_config[] = {
64   { "filename", PW_TYPE_STRING_PTR, 0, &radutmpconfig.radutmp_fn,  RADUTMP },
65   { NULL, -1, 0, NULL, NULL }
66 };
67
68 #define LOCK_LEN sizeof(struct radutmp)
69
70 static int radutmp_lookup(struct radutmp *u, uint32_t nasaddr,
71                 uint32_t port, const char *user)
72 {
73         int fd;
74
75         if ((fd = open(radutmpconfig.radutmp_fn, O_RDONLY|O_CREAT, 0644)) >= 0) {
76                 /*
77                  *      Lock the utmp file.
78                  */
79                 rad_lockfd(fd, LOCK_LEN);
80
81                 /*
82                  *      Find the entry for this NAS / portno combination.
83                  */
84                 while (read(fd, u, sizeof(*u)) == sizeof(*u)) {
85                         if ((nasaddr != 0 && nasaddr != u->nas_address) ||
86                                         (port != u->nas_port) ||
87                                         (user != NULL &&
88                                         strncmp(u->login, user, sizeof u->login) != 0) ||
89                                         u->type != P_LOGIN)
90                                 continue;
91                         /*
92                          *      Match. Zap it.
93                          */
94                         close(fd);
95                         return 1;
96                 }
97                 close(fd);
98         }
99         return 0;
100 }
101 static int do_accton_packet(uint32_t nasaddr);
102 static int do_stop_packet(const struct radutmp *u);
103
104 /*
105  *  Display the syntax for starting this program.
106  */
107 static void usage(void)
108 {
109         fprintf(stderr,
110                         "Usage: %s [-d raddb] [-p acct_port] [-r servername|serverip] termserver [port] [user]\n", progname);
111         fprintf(stderr, "Options:\n\n");
112         fprintf(stderr, "  -d raddb        Set the raddb directory (default is %s)\n", RADIUS_DIR);
113         fprintf(stderr, "  -p acct_port    Accounting port on radius server\n");
114         fprintf(stderr, "  -r radserver    Radius server name or IP address\n");
115         fprintf(stderr, "  termserver      Terminal Server (NAS) name or IP address to match, can be '' for any\n");
116         fprintf(stderr, "  [port]          Terminal Server port to match\n");
117         fprintf(stderr, "  [user]          Login account to match\n");
118         exit(1);
119 }
120
121
122 /*
123  *      Zap a user from the radutmp and radwtmp file.
124  */
125 int main(int argc, char **argv)
126 {
127         CONF_SECTION *cs;
128         NAS *nas;
129         uint32_t ip = 0;
130         uint32_t nas_port = ~0;
131         char *user = NULL;
132         char *s;
133         char buf[256];
134         struct radutmp u;
135         int argval;
136
137         progname = argv[0];
138
139         radius_dir = strdup(RADIUS_DIR);
140
141         /*  Process the options.  */
142         while ((argval = getopt(argc, argv, "d:p:r:")) != EOF) {
143
144                 switch(argval) {
145
146                         case 'd':
147                                 if (radius_dir) free(radius_dir);
148                                 radius_dir = strdup(optarg);
149                                 break;
150                         case 'p':
151                                 acct_port = atoi(optarg);
152                                 break;
153
154                         case 'r':
155                                 if ((radiusip = ip_getaddr(optarg)) == INADDR_NONE) {
156                                         fprintf(stderr, "%s: %s: radius server unknown\n",
157                                                 progname, optarg);
158                                         exit(1);
159                                 }
160                                 break;
161
162                         default:
163                                 usage();
164                                 exit(1);
165                 }
166         }
167
168
169         if (argc == optind) {   /* no terminal server specified */
170                 usage();
171                 exit(1);
172         }
173
174         if (argc > optind + 1) {        /* NAS port given */
175                 s = argv[optind+1];
176                 if (*s == 's' || *s == 'S') s++;
177                 nas_port = strtoul(s, NULL, 10);
178         }
179
180         if (argc > optind + 2) {        /* username (login) given */
181                 user = argv[optind+2];
182         }
183
184         /*
185          *      Find the IP address of the terminal server.
186          */
187         if ((nas = nas_findbyname(argv[optind])) == NULL && argv[optind][0] != 0) {
188                 if ((ip = ip_getaddr(argv[optind])) == INADDR_NONE) {
189                         fprintf(stderr, "%s: host not found.\n", argv[optind]);
190                         exit(1);
191                 }
192         }
193         if (nas != NULL)
194                 ip = nas->ipaddr;
195
196         /*
197          *      Ensure that the configuration is initialized.
198          */
199         memset(&mainconfig, 0, sizeof(mainconfig));
200
201         /* Read radiusd.conf */
202         if (read_mainconfig(0) < 0) {
203                 fprintf(stderr, "%s: Error reading radiusd.conf.\n", argv[0]);
204                 exit(1);
205         }
206
207         /* Read the radutmp section of radiusd.conf */
208         cs = cf_section_sub_find(cf_section_find("modules"), "radutmp");
209         if(!cs) {
210                 fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf!\n",
211                         argv[0]);
212                 exit(1);
213         }
214
215         cf_section_parse(cs, NULL, module_config);
216
217         printf("%s: zapping termserver %s, port %u",
218                 progname, ip_hostname(buf, sizeof(buf), ip), nas_port);
219         if (user != NULL)
220                 printf(", user %s", user);
221         printf("\n");
222
223         if (nas_port == ~0) {
224                 return do_accton_packet(ip);
225         }
226
227         if (!radutmp_lookup(&u, ip, nas_port, user)) {
228                 fprintf(stderr, "Entry not found\n");
229                 return 1;
230         }
231
232         return do_stop_packet(&u);
233 }
234
235 static int getport(const char *name)
236 {
237         struct servent *svp;
238
239         svp = getservbyname(name, "udp");
240         if (svp == NULL) {
241                 return 0;
242         }
243
244         return ntohs(svp->s_port);
245 }
246
247 static const char *getsecret(uint32_t server)
248 {
249         RADCLIENT *cl;
250
251         cl = client_find(server);
252         if (cl == NULL) {
253                 char buf[32];
254                 radlog(L_ERR|L_CONS, "No clients entry for %s",
255                        ip_ntoa(buf,server));
256                 exit(1);
257         }
258         return (const char *)cl->secret;
259 }
260
261 /* Packet-fabrication macros. Don't stare directly at them without protective
262  * eye gear */
263 #define PAIR(n,v,t,e) do { \
264   if(!(vp=paircreate(n, t))) { \
265     radlog(L_ERR|L_CONS, "no memory"); \
266     pairfree(&req->vps); \
267     return 1; \
268   } \
269   vp->e=v; \
270   pairadd(&req->vps, vp); \
271 } while(0)
272 #define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
273 #define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
274 #define STRINGPAIR(n,v) do { \
275   if(!(vp=paircreate(n, PW_TYPE_STRING))) { \
276     radlog(L_ERR|L_CONS, "no memory"); \
277     pairfree(&req->vps); \
278     return 1; \
279   } \
280   strNcpy((char *)vp->strvalue, v, sizeof vp->strvalue); \
281   vp->length=strlen(v); \
282   pairadd(&req->vps, vp); \
283 } while(0)
284
285 static int do_packet(int allports, uint32_t nasaddr, const struct radutmp *u)
286 {
287         int i, retries=5, timeout=3;
288         struct timeval tv;
289         RADIUS_PACKET *req, *rep = NULL;
290         VALUE_PAIR *vp;
291         const char *secret;
292
293         if ((req = rad_alloc(1)) == NULL) {
294                 librad_perror("radzap");
295                 exit(1);
296         }
297         req->id = getpid() & 0xFF;
298         req->code = PW_ACCOUNTING_REQUEST;
299         req->dst_port = acct_port;
300         if(req->dst_port == 0)
301                 req->dst_port = getport("radacct");
302         if(req->dst_port == 0)
303                 req->dst_port = PW_ACCT_UDP_PORT;
304         if (radiusip == INADDR_NONE) {
305                 req->dst_ipaddr = ip_getaddr("localhost");
306         }
307         else {
308                 req->dst_ipaddr = radiusip;
309         }
310         if(!req->dst_ipaddr)
311                 req->dst_ipaddr = 0x7f000001;
312         req->vps = NULL;
313         secret = getsecret(req->dst_ipaddr);
314
315         if(allports != 0) {
316                 INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_ACCOUNTING_OFF);
317                 IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
318                 INTPAIR(PW_ACCT_DELAY_TIME, 0);
319         } else {
320                 char login[sizeof u->login+1];
321                 char session_id[sizeof u->session_id+1];
322                 strNcpy(login, u->login, sizeof login);
323                 strNcpy(session_id, u->session_id, sizeof session_id);
324                 INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
325                 IPPAIR(PW_NAS_IP_ADDRESS, u->nas_address);
326                 INTPAIR(PW_ACCT_DELAY_TIME, 0);
327                 STRINGPAIR(PW_USER_NAME, login);
328                 INTPAIR(PW_NAS_PORT, u->nas_port);
329                 STRINGPAIR(PW_ACCT_SESSION_ID, session_id);
330                 if(u->proto=='P') {
331                         INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
332                         INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
333                 } else if(u->proto=='S') {
334                         INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
335                         INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
336                 } else {
337                         INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
338                 }
339                 IPPAIR(PW_FRAMED_IP_ADDRESS, u->framed_address);
340                 INTPAIR(PW_ACCT_SESSION_TIME, 0);
341                 INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
342                 INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
343                 INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
344                 INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
345         }
346         if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
347                 perror("radzap: socket: ");
348                 exit(1);
349         }
350
351         for (i = 0; i < retries; i++) {
352                 fd_set rdfdesc;
353
354                 rad_send(req, NULL, secret);
355
356                 /* And wait for reply, timing out as necessary */
357                 FD_ZERO(&rdfdesc);
358                 FD_SET(req->sockfd, &rdfdesc);
359
360                 tv.tv_sec = (int)timeout;
361                 tv.tv_usec = 1000000 * (timeout - (int)timeout);
362
363                 /* Something's wrong if we don't get exactly one fd. */
364                 if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) {
365                         continue;
366                 }
367
368                 rep = rad_recv(req->sockfd);
369                 if (rep != NULL) {
370                         break;
371                 } else {        /* NULL: couldn't receive the packet */
372                         librad_perror("radzap:");
373                         exit(1);
374                 }
375         }
376
377         /* No response or no data read (?) */
378         if (i == retries) {
379                 fprintf(stderr, "%s: no response from server\n", progname);
380                 exit(1);
381         }
382
383         if (rad_decode(rep, req, secret) != 0) {
384                 librad_perror("rad_decode");
385                 exit(1);
386         }
387
388         vp_printlist(stdout, rep->vps);
389         return 0;
390 }
391
392 static int do_accton_packet(uint32_t nasaddr)
393 {
394         return do_packet(1, nasaddr, 0);
395 }
396
397 static int do_stop_packet(const struct radutmp *u)
398 {
399         return do_packet(0, 0, u);
400 }