2 * radzap.c Zap a user from the radutmp and radwtmp file.
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.
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.
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
20 * Copyright 2000 The FreeRADIUS server project
21 * Copyright 2000 Alan DeKok <aland@ox.org>
25 #include "libradius.h"
35 #include <sys/types.h>
36 #include <sys/socket.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
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;
55 int log_stripped_names;
56 struct main_config_t mainconfig;
57 uint32_t radiusip = INADDR_NONE;
58 static void usage(void);
60 struct radutmp_config_t {
64 static CONF_PARSER module_config[] = {
65 { "filename", PW_TYPE_STRING_PTR, 0, &radutmpconfig.radutmp_fn, RADUTMP },
66 { NULL, -1, 0, NULL, NULL }
69 #define LOCK_LEN sizeof(struct radutmp)
71 static int radutmp_lookup(struct radutmp *u, uint32_t nasaddr,
72 uint32_t port, const char *user)
76 if ((fd = open(radutmpconfig.radutmp_fn, O_RDONLY|O_CREAT, 0644)) >= 0) {
80 rad_lockfd(fd, LOCK_LEN);
83 * Find the entry for this NAS / portno combination.
85 while (read(fd, u, sizeof(*u)) == sizeof(*u)) {
86 if ((nasaddr != 0 && nasaddr != u->nas_address) ||
87 (port != u->nas_port) ||
89 strncmp(u->login, user, sizeof u->login) != 0) ||
102 static int do_accton_packet(uint32_t nasaddr);
103 static int do_stop_packet(const struct radutmp *u);
106 * Display the syntax for starting this program.
108 static void usage(void)
111 "Usage: %s [-d raddb] [-p acct_port] [-r servername|serverip] termserver [port] [user]\n", progname);
112 fprintf(stderr, "Options:\n\n");
113 fprintf(stderr, " -d raddb Set the raddb directory (default is %s)\n", RADIUS_DIR);
114 fprintf(stderr, " -p acct_port Accounting port on radius server\n");
115 fprintf(stderr, " -r radserver Radius server name or IP address\n");
116 fprintf(stderr, " termserver Terminal Server (NAS) name or IP address to match, can be '' for any\n");
117 fprintf(stderr, " [port] Terminal Server port to match\n");
118 fprintf(stderr, " [user] Login account to match\n");
124 * Zap a user from the radutmp and radwtmp file.
126 int main(int argc, char **argv)
131 uint32_t nas_port = ~0;
140 radius_dir = strdup(RADIUS_DIR);
142 /* Process the options. */
143 while ((argval = getopt(argc, argv, "d:p:r:")) != EOF) {
148 if (radius_dir) free(radius_dir);
149 radius_dir = strdup(optarg);
152 acct_port = atoi(optarg);
156 if ((radiusip = ip_getaddr(optarg)) == INADDR_NONE) {
157 fprintf(stderr, "%s: %s: radius server unknown\n",
170 if (argc == optind) { /* no terminal server specified */
175 if (argc > optind + 1) { /* NAS port given */
177 if (*s == 's' || *s == 'S') s++;
178 nas_port = strtoul(s, NULL, 10);
181 if (argc > optind + 2) { /* username (login) given */
182 user = argv[optind+2];
186 * Find the IP address of the terminal server.
188 if ((nas = nas_findbyname(argv[optind])) == NULL && argv[optind][0] != 0) {
189 if ((ip = ip_getaddr(argv[optind])) == INADDR_NONE) {
190 fprintf(stderr, "%s: host not found.\n", argv[optind]);
198 * Ensure that the configuration is initialized.
200 memset(&mainconfig, 0, sizeof(mainconfig));
202 /* Read radiusd.conf */
203 if (read_mainconfig(0) < 0) {
204 fprintf(stderr, "%s: Error reading radiusd.conf.\n", argv[0]);
208 /* Read the radutmp section of radiusd.conf */
209 cs = cf_section_sub_find(cf_section_find("modules"), "radutmp");
211 fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf!\n",
216 cf_section_parse(cs, NULL, module_config);
218 printf("%s: zapping termserver %s, port %u",
219 progname, ip_hostname(buf, sizeof(buf), ip), nas_port);
221 printf(", user %s", user);
224 if (nas_port == ~0) {
225 return do_accton_packet(ip);
228 if (!radutmp_lookup(&u, ip, nas_port, user)) {
229 fprintf(stderr, "Entry not found\n");
233 return do_stop_packet(&u);
236 static int getport(const char *name)
240 svp = getservbyname(name, "udp");
245 return ntohs(svp->s_port);
248 static const char *getsecret(uint32_t server)
252 cl = client_find(server);
255 radlog(L_ERR|L_CONS, "No clients entry for %s",
256 ip_ntoa(buf,server));
259 return (const char *)cl->secret;
262 /* Packet-fabrication macros. Don't stare directly at them without protective
264 #define PAIR(n,v,t,e) do { \
265 if(!(vp=paircreate(n, t))) { \
266 radlog(L_ERR|L_CONS, "no memory"); \
267 pairfree(&req->vps); \
271 pairadd(&req->vps, vp); \
273 #define INTPAIR(n,v) PAIR(n,v,PW_TYPE_INTEGER,lvalue)
274 #define IPPAIR(n,v) PAIR(n,v,PW_TYPE_IPADDR,lvalue)
275 #define STRINGPAIR(n,v) do { \
276 if(!(vp=paircreate(n, PW_TYPE_STRING))) { \
277 radlog(L_ERR|L_CONS, "no memory"); \
278 pairfree(&req->vps); \
281 strNcpy((char *)vp->strvalue, v, sizeof vp->strvalue); \
282 vp->length=strlen(v); \
283 pairadd(&req->vps, vp); \
286 static int do_packet(int allports, uint32_t nasaddr, const struct radutmp *u)
288 int i, retries=5, timeout=3;
290 RADIUS_PACKET *req, *rep = NULL;
294 if ((req = rad_alloc(1)) == NULL) {
295 librad_perror("radzap");
298 req->id = getpid() & 0xFF;
299 req->code = PW_ACCOUNTING_REQUEST;
300 req->dst_port = acct_port;
301 if(req->dst_port == 0)
302 req->dst_port = getport("radacct");
303 if(req->dst_port == 0)
304 req->dst_port = PW_ACCT_UDP_PORT;
305 if (radiusip == INADDR_NONE) {
306 req->dst_ipaddr = ip_getaddr("localhost");
309 req->dst_ipaddr = radiusip;
312 req->dst_ipaddr = 0x7f000001;
314 secret = getsecret(req->dst_ipaddr);
317 INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_ACCOUNTING_OFF);
318 IPPAIR(PW_NAS_IP_ADDRESS, nasaddr);
319 INTPAIR(PW_ACCT_DELAY_TIME, 0);
321 char login[sizeof u->login+1];
322 char session_id[sizeof u->session_id+1];
323 strNcpy(login, u->login, sizeof login);
324 strNcpy(session_id, u->session_id, sizeof session_id);
325 INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP);
326 IPPAIR(PW_NAS_IP_ADDRESS, u->nas_address);
327 INTPAIR(PW_ACCT_DELAY_TIME, 0);
328 STRINGPAIR(PW_USER_NAME, login);
329 INTPAIR(PW_NAS_PORT, u->nas_port);
330 STRINGPAIR(PW_ACCT_SESSION_ID, session_id);
332 INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
333 INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP);
334 } else if(u->proto=='S') {
335 INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER);
336 INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP);
338 INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */
340 IPPAIR(PW_FRAMED_IP_ADDRESS, u->framed_address);
341 INTPAIR(PW_ACCT_SESSION_TIME, 0);
342 INTPAIR(PW_ACCT_INPUT_OCTETS, 0);
343 INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0);
344 INTPAIR(PW_ACCT_INPUT_PACKETS, 0);
345 INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0);
347 if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
348 perror("radzap: socket: ");
352 for (i = 0; i < retries; i++) {
355 rad_send(req, NULL, secret);
357 /* And wait for reply, timing out as necessary */
359 FD_SET(req->sockfd, &rdfdesc);
361 tv.tv_sec = (int)timeout;
362 tv.tv_usec = 1000000 * (timeout - (int)timeout);
364 /* Something's wrong if we don't get exactly one fd. */
365 if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) {
369 rep = rad_recv(req->sockfd);
372 } else { /* NULL: couldn't receive the packet */
373 librad_perror("radzap:");
378 /* No response or no data read (?) */
380 fprintf(stderr, "%s: no response from server\n", progname);
384 if (rad_decode(rep, req, secret) != 0) {
385 librad_perror("rad_decode");
389 vp_printlist(stdout, rep->vps);
393 static int do_accton_packet(uint32_t nasaddr)
395 return do_packet(1, nasaddr, 0);
398 static int do_stop_packet(const struct radutmp *u)
400 return do_packet(0, 0, u);