xref: /openbsd-src/usr.sbin/radiusd/radiusd.c (revision 513cf72f82c16dd38f89b0e7a0ec4a163d87f81f)
1 /*	$OpenBSD: radiusd.c,v 1.46 2024/07/10 16:30:43 yasuoka Exp $	*/
2 
3 /*
4  * Copyright (c) 2013, 2023 Internet Initiative Japan Inc.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <sys/queue.h>
23 #include <sys/socket.h>
24 #include <sys/time.h>
25 #include <sys/uio.h>
26 #include <sys/wait.h>
27 
28 #include <err.h>
29 #include <errno.h>
30 #include <event.h>
31 #include <fcntl.h>
32 #include <fnmatch.h>
33 #include <imsg.h>
34 #include <md5.h>
35 #include <netdb.h>
36 #include <paths.h>
37 #include <pwd.h>
38 #include <signal.h>
39 #include <stdbool.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <syslog.h>
44 #include <unistd.h>
45 
46 #include <radius.h>
47 
48 #include "radiusd.h"
49 #include "radiusd_local.h"
50 #include "log.h"
51 #include "util.h"
52 #include "imsg_subr.h"
53 #include "control.h"
54 
55 static int		 radiusd_start(struct radiusd *);
56 static void		 radiusd_stop(struct radiusd *);
57 static void		 radiusd_free(struct radiusd *);
58 static void		 radiusd_listen_on_event(int, short, void *);
59 static void		 radiusd_listen_handle_packet(struct radiusd_listen *,
60 			    RADIUS_PACKET *, struct sockaddr *, socklen_t);
61 static void		 radiusd_on_sigterm(int, short, void *);
62 static void		 radiusd_on_sigint(int, short, void *);
63 static void		 radiusd_on_sighup(int, short, void *);
64 static void		 radiusd_on_sigchld(int, short, void *);
65 static void		 raidus_query_access_request(struct radius_query *);
66 static void		 radius_query_access_response(struct radius_query *);
67 static void		 raidus_query_accounting_request(
68 			    struct radiusd_accounting *, struct radius_query *);
69 static void		 radius_query_accounting_response(struct radius_query *);
70 static const char	*radius_code_string(int);
71 static const char	*radius_acct_status_type_string(uint32_t);
72 static int		 radiusd_access_response_fixup (struct radius_query *);
73 
74 
75 
76 static void		 radiusd_module_reset_ev_handler(
77 			    struct radiusd_module *);
78 static int		 radiusd_module_imsg_read(struct radiusd_module *);
79 static void		 radiusd_module_imsg(struct radiusd_module *,
80 			    struct imsg *);
81 
82 static struct radiusd_module_radpkt_arg *
83 			 radiusd_module_recv_radpkt(struct radiusd_module *,
84 			    struct imsg *, uint32_t, const char *);
85 static void		 radiusd_module_on_imsg_io(int, short, void *);
86 void			 radiusd_module_start(struct radiusd_module *);
87 void			 radiusd_module_stop(struct radiusd_module *);
88 static void		 radiusd_module_close(struct radiusd_module *);
89 static void		 radiusd_module_userpass(struct radiusd_module *,
90 			    struct radius_query *);
91 static void		 radiusd_module_access_request(struct radiusd_module *,
92 			    struct radius_query *);
93 static void		 radiusd_module_request_decoration(
94 			    struct radiusd_module *, struct radius_query *);
95 static void		 radiusd_module_response_decoration(
96 			    struct radiusd_module *, struct radius_query *);
97 static void		 radiusd_module_account_request(struct radiusd_module *,
98 			    struct radius_query *);
99 static int		 imsg_compose_radius_packet(struct imsgbuf *,
100 			    uint32_t, u_int, RADIUS_PACKET *);
101 static void		 close_stdio(void);
102 
103 static u_int		 radius_query_id_seq = 0;
104 int			 debug = 0;
105 struct radiusd		*radiusd_s = NULL;
106 
107 static __dead void
108 usage(void)
109 {
110 	extern char *__progname;
111 
112 	fprintf(stderr, "usage: %s [-dn] [-f file]\n", __progname);
113 	exit(EXIT_FAILURE);
114 }
115 
116 int
117 main(int argc, char *argv[])
118 {
119 	extern char		*__progname;
120 	const char		*conffile = CONFFILE;
121 	int			 ch, error;
122 	struct radiusd		*radiusd;
123 	bool			 noaction = false;
124 	struct passwd		*pw;
125 
126 	while ((ch = getopt(argc, argv, "df:n")) != -1)
127 		switch (ch) {
128 		case 'd':
129 			debug++;
130 			break;
131 
132 		case 'f':
133 			conffile = optarg;
134 			break;
135 
136 		case 'n':
137 			noaction = true;
138 			break;
139 
140 		default:
141 			usage();
142 			/* NOTREACHED */
143 		}
144 
145 	argc -= optind;
146 	argv += optind;
147 
148 	if (argc != 0)
149 		usage();
150 
151 	if ((radiusd = calloc(1, sizeof(*radiusd))) == NULL)
152 		err(1, "calloc");
153 	radiusd_s = radiusd;
154 	TAILQ_INIT(&radiusd->listen);
155 	TAILQ_INIT(&radiusd->query);
156 
157 	if (!noaction && debug == 0)
158 		daemon(0, 1);	/* pend closing stdio files */
159 
160 	if (parse_config(conffile, radiusd) != 0)
161 		errx(EXIT_FAILURE, "config error");
162 	log_init(debug);
163 	if (noaction) {
164 		fprintf(stderr, "configuration OK\n");
165 		exit(EXIT_SUCCESS);
166 	}
167 
168 	if (debug == 0)
169 		close_stdio(); /* close stdio files now */
170 
171 	if (control_init(RADIUSD_SOCK) == -1)
172 		exit(EXIT_FAILURE);
173 
174 	event_init();
175 
176 	if ((pw = getpwnam(RADIUSD_USER)) == NULL)
177 		errx(EXIT_FAILURE, "user `%s' is not found in password "
178 		    "database", RADIUSD_USER);
179 
180 	if (chroot(pw->pw_dir) == -1)
181 		err(EXIT_FAILURE, "chroot");
182 	if (chdir("/") == -1)
183 		err(EXIT_FAILURE, "chdir(\"/\")");
184 
185 	if (setgroups(1, &pw->pw_gid) ||
186 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
187 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
188 		err(EXIT_FAILURE, "cannot drop privileges");
189 
190 	signal(SIGPIPE, SIG_IGN);
191 	openlog(NULL, LOG_PID, LOG_DAEMON);
192 
193 	signal_set(&radiusd->ev_sigterm, SIGTERM, radiusd_on_sigterm, radiusd);
194 	signal_set(&radiusd->ev_sigint,  SIGINT,  radiusd_on_sigint,  radiusd);
195 	signal_set(&radiusd->ev_sighup,  SIGHUP,  radiusd_on_sighup,  radiusd);
196 	signal_set(&radiusd->ev_sigchld, SIGCHLD, radiusd_on_sigchld, radiusd);
197 
198 	if (radiusd_start(radiusd) != 0)
199 		errx(EXIT_FAILURE, "start failed");
200 	if (control_listen() == -1)
201 		exit(EXIT_FAILURE);
202 
203 	if (pledge("stdio inet", NULL) == -1)
204 		err(EXIT_FAILURE, "pledge");
205 
206 	event_loop(0);
207 
208 	if (radiusd->error != 0)
209 		log_warnx("exiting on error");
210 
211 	radiusd_stop(radiusd);
212 	control_cleanup();
213 
214 	event_loop(0);
215 
216 	error = radiusd->error;
217 	radiusd_free(radiusd);
218 	event_base_free(NULL);
219 
220 	if (error != 0)
221 		exit(EXIT_FAILURE);
222 	else
223 		exit(EXIT_SUCCESS);
224 }
225 
226 static int
227 radiusd_start(struct radiusd *radiusd)
228 {
229 	struct radiusd_listen	*l;
230 	struct radiusd_module	*module;
231 	int			 s, on;
232 	char			 hbuf[NI_MAXHOST];
233 
234 	TAILQ_FOREACH(l, &radiusd->listen, next) {
235 		if (getnameinfo(
236 		    (struct sockaddr *)&l->addr, l->addr.ipv4.sin_len,
237 		    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
238 			log_warn("%s: getnameinfo()", __func__);
239 			goto on_error;
240 		}
241 		if ((s = socket(l->addr.ipv4.sin_family,
242 		    l->stype | SOCK_NONBLOCK, l->sproto)) == -1) {
243 			log_warn("Listen %s port %d is failed: socket()",
244 			    hbuf, (int)htons(l->addr.ipv4.sin_port));
245 			goto on_error;
246 		}
247 
248 		on = 1;
249 		if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))
250 		    == -1)
251 			log_warn("%s: setsockopt(,,SO_REUSEADDR) failed: %m",
252 			    __func__);
253 		if (bind(s, (struct sockaddr *)&l->addr, l->addr.ipv4.sin_len)
254 		    != 0) {
255 			log_warn("Listen %s port %d is failed: bind()",
256 			    hbuf, (int)htons(l->addr.ipv4.sin_port));
257 			close(s);
258 			goto on_error;
259 		}
260 		if (l->addr.ipv4.sin_family == AF_INET)
261 			log_info("Start listening on %s:%d/udp", hbuf,
262 			    (int)ntohs(l->addr.ipv4.sin_port));
263 		else
264 			log_info("Start listening on [%s]:%d/udp", hbuf,
265 			    (int)ntohs(l->addr.ipv4.sin_port));
266 		event_set(&l->ev, s, EV_READ | EV_PERSIST,
267 		    radiusd_listen_on_event, l);
268 		if (event_add(&l->ev, NULL) != 0) {
269 			log_warn("event_add() failed at %s()", __func__);
270 			close(s);
271 			goto on_error;
272 		}
273 		l->sock = s;
274 		l->radiusd = radiusd;
275 	}
276 
277 	signal_add(&radiusd->ev_sigterm, NULL);
278 	signal_add(&radiusd->ev_sigint, NULL);
279 	signal_add(&radiusd->ev_sighup, NULL);
280 	signal_add(&radiusd->ev_sigchld, NULL);
281 
282 	TAILQ_FOREACH(module, &radiusd->module, next) {
283 		if (debug > 0)
284 			radiusd_module_set(module, "_debug", 0, NULL);
285 		radiusd_module_start(module);
286 	}
287 
288 	return (0);
289 on_error:
290 	radiusd->error++;
291 	event_loopbreak();
292 
293 	return (-1);
294 }
295 
296 static void
297 radiusd_stop(struct radiusd *radiusd)
298 {
299 	char			 hbuf[NI_MAXHOST];
300 	struct radiusd_listen	*l;
301 	struct radiusd_module	*module;
302 
303 	TAILQ_FOREACH_REVERSE(l, &radiusd->listen, radiusd_listen_head, next) {
304 		if (l->sock >= 0) {
305 			if (getnameinfo(
306 			    (struct sockaddr *)&l->addr, l->addr.ipv4.sin_len,
307 			    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
308 				strlcpy(hbuf, "error", sizeof(hbuf));
309 			if (l->addr.ipv4.sin_family == AF_INET)
310 				log_info("Stop listening on %s:%d/udp", hbuf,
311 				    (int)ntohs(l->addr.ipv4.sin_port));
312 			else
313 				log_info("Stop listening on [%s]:%d/udp", hbuf,
314 				    (int)ntohs(l->addr.ipv4.sin_port));
315 			event_del(&l->ev);
316 			close(l->sock);
317 		}
318 		l->sock = -1;
319 	}
320 	TAILQ_FOREACH(module, &radiusd->module, next) {
321 		radiusd_module_stop(module);
322 		radiusd_module_close(module);
323 	}
324 	if (signal_pending(&radiusd->ev_sigterm, NULL))
325 		signal_del(&radiusd->ev_sigterm);
326 	if (signal_pending(&radiusd->ev_sigint, NULL))
327 		signal_del(&radiusd->ev_sigint);
328 	if (signal_pending(&radiusd->ev_sighup, NULL))
329 		signal_del(&radiusd->ev_sighup);
330 	if (signal_pending(&radiusd->ev_sigchld, NULL))
331 		signal_del(&radiusd->ev_sigchld);
332 }
333 
334 static void
335 radiusd_free(struct radiusd *radiusd)
336 {
337 	int				 i;
338 	struct radiusd_listen		*listn, *listnt;
339 	struct radiusd_client		*client, *clientt;
340 	struct radiusd_module		*module, *modulet;
341 	struct radiusd_module_ref	*modref, *modreft;
342 	struct radiusd_authentication	*authen, *authent;
343 	struct radiusd_accounting	*acct, *acctt;
344 
345 	TAILQ_FOREACH_SAFE(authen, &radiusd->authen, next, authent) {
346 		TAILQ_REMOVE(&radiusd->authen, authen, next);
347 		free(authen->auth);
348 		TAILQ_FOREACH_SAFE(modref, &authen->deco, next, modreft) {
349 			TAILQ_REMOVE(&authen->deco, modref, next);
350 			free(modref);
351 		}
352 		for (i = 0; authen->username[i] != NULL; i++)
353 			free(authen->username[i]);
354 		free(authen->username);
355 		free(authen);
356 	}
357 	TAILQ_FOREACH_SAFE(acct, &radiusd->account, next, acctt) {
358 		TAILQ_REMOVE(&radiusd->account, acct, next);
359 		free(acct->secret);
360 		free(acct->acct);
361 		TAILQ_FOREACH_SAFE(modref, &acct->deco, next, modreft) {
362 			TAILQ_REMOVE(&acct->deco, modref, next);
363 			free(modref);
364 		}
365 		for (i = 0; acct->username[i] != NULL; i++)
366 			free(acct->username[i]);
367 		free(acct->username);
368 		free(acct);
369 	}
370 	TAILQ_FOREACH_SAFE(module, &radiusd->module, next, modulet) {
371 		TAILQ_REMOVE(&radiusd->module, module, next);
372 		radiusd_module_unload(module);
373 	}
374 	TAILQ_FOREACH_SAFE(client, &radiusd->client, next, clientt) {
375 		TAILQ_REMOVE(&radiusd->client, client, next);
376 		explicit_bzero(client->secret, sizeof(client->secret));
377 		free(client);
378 	}
379 	TAILQ_FOREACH_SAFE(listn, &radiusd->listen, next, listnt) {
380 		TAILQ_REMOVE(&radiusd->listen, listn, next);
381 		free(listn);
382 	}
383 	free(radiusd);
384 }
385 
386 /***********************************************************************
387  * Network event handlers
388  ***********************************************************************/
389 #define IPv4_cmp(_in, _addr, _mask) (				\
390 	((_in)->s_addr & (_mask)->addr.ipv4.s_addr) ==		\
391 	    (_addr)->addr.ipv4.s_addr)
392 #define	s6_addr32(_in6)	((uint32_t *)(_in6)->s6_addr)
393 #define IPv6_cmp(_in6, _addr, _mask) (				\
394 	((s6_addr32(_in6)[3] & (_mask)->addr.addr32[3])		\
395 	    == (_addr)->addr.addr32[3]) &&			\
396 	((s6_addr32(_in6)[2] & (_mask)->addr.addr32[2])		\
397 	    == (_addr)->addr.addr32[2]) &&			\
398 	((s6_addr32(_in6)[1] & (_mask)->addr.addr32[1])		\
399 	    == (_addr)->addr.addr32[1]) &&			\
400 	((s6_addr32(_in6)[0] & (_mask)->addr.addr32[0])		\
401 	    == (_addr)->addr.addr32[0]))
402 
403 static void
404 radiusd_listen_on_event(int fd, short evmask, void *ctx)
405 {
406 	int				 sz;
407 	RADIUS_PACKET			*packet = NULL;
408 	struct sockaddr_storage		 peer;
409 	socklen_t			 peersz;
410 	struct radiusd_listen		*listn = ctx;
411 	static u_char			 buf[65535];
412 
413 	if (evmask & EV_READ) {
414 		peersz = sizeof(peer);
415 		if ((sz = recvfrom(listn->sock, buf, sizeof(buf), 0,
416 		    (struct sockaddr *)&peer, &peersz)) == -1) {
417 			if (errno == EAGAIN)
418 				return;
419 			log_warn("%s: recvfrom() failed", __func__);
420 			return;
421 		}
422 		RADIUSD_ASSERT(peer.ss_family == AF_INET ||
423 		    peer.ss_family == AF_INET6);
424 		if ((packet = radius_convert_packet(buf, sz)) == NULL)
425 			log_warn("%s: radius_convert_packet() failed",
426 			    __func__);
427 		else
428 			radiusd_listen_handle_packet(listn, packet,
429 			    (struct sockaddr *)&peer, peersz);
430 	}
431 }
432 
433 static void
434 radiusd_listen_handle_packet(struct radiusd_listen *listn,
435     RADIUS_PACKET *packet, struct sockaddr *peer, socklen_t peerlen)
436 {
437 	int				 i, req_id, req_code;
438 	static char			 username[256];
439 	char				 peerstr[NI_MAXHOST + NI_MAXSERV + 30];
440 	struct radiusd_authentication	*authen;
441 	struct radiusd_accounting	*accounting;
442 	struct radiusd_client		*client;
443 	struct radius_query		*q = NULL;
444 	uint32_t			 acct_status;
445 #define in(_x)	(((struct sockaddr_in  *)_x)->sin_addr)
446 #define in6(_x)	(((struct sockaddr_in6 *)_x)->sin6_addr)
447 
448 	req_id = radius_get_id(packet);
449 	req_code = radius_get_code(packet);
450 	/* prepare some information about this messages */
451 	if (addrport_tostring(peer, peerlen, peerstr, sizeof(peerstr)) ==
452 	    NULL) {
453 		log_warn("%s: getnameinfo() failed", __func__);
454 		goto on_error;
455 	}
456 
457 	/*
458 	 * Find a matching `client' entry
459 	 */
460 	TAILQ_FOREACH(client, &listn->radiusd->client, next) {
461 		if (client->af != peer->sa_family)
462 			continue;
463 		if (peer->sa_family == AF_INET && IPv4_cmp(
464 		    &in(peer), &client->addr, &client->mask))
465 			break;
466 		else if (peer->sa_family == AF_INET6 && IPv6_cmp(
467 		    &in6(peer), &client->addr, &client->mask))
468 			break;
469 	}
470 	if (client == NULL) {
471 		log_warnx("Received %s(code=%d) from %s id=%d: no `client' "
472 		    "matches", radius_code_string(req_code), req_code, peerstr,
473 		    req_id);
474 		goto on_error;
475 	}
476 
477 	/* Check the request authenticator if accounting */
478 	if ((req_code == RADIUS_CODE_ACCOUNTING_REQUEST ||
479 	    listn->accounting) && radius_check_accounting_request_authenticator(
480 	    packet, client->secret) != 0) {
481 		log_warnx("Received %s(code=%d) from %s id=%d: bad request "
482 		    "authenticator", radius_code_string(req_code), req_code,
483 		    peerstr, req_id);
484 		goto on_error;
485 	}
486 
487 	/* Check the client's Message-Authenticator */
488 	if (client->msgauth_required && !listn->accounting &&
489 	    !radius_has_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR)) {
490 		log_warnx("Received %s(code=%d) from %s id=%d: no message "
491 		    "authenticator", radius_code_string(req_code), req_code,
492 		    peerstr, req_id);
493 		goto on_error;
494 	}
495 
496 	if (radius_has_attr(packet, RADIUS_TYPE_MESSAGE_AUTHENTICATOR) &&
497 	    radius_check_message_authenticator(packet, client->secret) != 0) {
498 		log_warnx("Received %s(code=%d) from %s id=%d: bad message "
499 		    "authenticator", radius_code_string(req_code), req_code,
500 		    peerstr, req_id);
501 		goto on_error;
502 	}
503 
504 	/*
505 	 * Find a duplicate request.  In RFC 2865, it has the same source IP
506 	 * address and source UDP port and Identifier.
507 	 */
508 	TAILQ_FOREACH(q, &listn->radiusd->query, next) {
509 		if (peer->sa_family == q->clientaddr.ss_family &&
510 		    ((peer->sa_family == AF_INET && in(&q->clientaddr).s_addr ==
511 		    in(peer).s_addr) || (peer->sa_family == AF_INET6 &&
512 		    IN6_ARE_ADDR_EQUAL(&in6(&q->clientaddr), &in6(peer)))) &&
513 		    ((struct sockaddr_in *)&q->clientaddr)->sin_port ==
514 		    ((struct sockaddr_in *)peer)->sin_port &&
515 		    req_id == q->req_id)
516 			break;	/* found it */
517 	}
518 	if (q != NULL) {
519 		log_info("Received %s(code=%d) from %s id=%d: duplicate "
520 		    "request by q=%u", radius_code_string(req_code), req_code,
521 		    peerstr, req_id, q->id);
522 		/* XXX RFC 5080 suggests to answer the cached result */
523 		goto on_error;
524 	}
525 
526 	if ((q = calloc(1, sizeof(struct radius_query))) == NULL) {
527 		log_warn("%s: Out of memory", __func__);
528 		goto on_error;
529 	}
530 	if (radius_get_string_attr(packet, RADIUS_TYPE_USER_NAME, username,
531 	    sizeof(username)) != 0) {
532 		log_info("Received %s(code=%d) from %s id=%d: no User-Name "
533 		    "attribute", radius_code_string(req_code), req_code,
534 		    peerstr, req_id);
535 	} else
536 		strlcpy(q->username, username, sizeof(q->username));
537 
538 	q->id = ++radius_query_id_seq;
539 	q->clientaddrlen = peerlen;
540 	memcpy(&q->clientaddr, peer, peerlen);
541 	q->listen = listn;
542 	q->req = packet;
543 	q->client = client;
544 	q->req_id = req_id;
545 	radius_get_authenticator(packet, q->req_auth);
546 	packet = NULL;
547 	TAILQ_INSERT_TAIL(&listn->radiusd->query, q, next);
548 
549 	switch (req_code) {
550 	case RADIUS_CODE_ACCESS_REQUEST:
551 		if (listn->accounting) {
552 			log_info("Received %s(code=%d) from %s id=%d: "
553 			    "ignored because the port is for authentication",
554 			    radius_code_string(req_code), req_code, peerstr,
555 			    req_id);
556 			break;
557 		}
558 		/*
559 		 * Find a matching `authenticate' entry
560 		 */
561 		TAILQ_FOREACH(authen, &listn->radiusd->authen, next) {
562 			for (i = 0; authen->username[i] != NULL; i++) {
563 				if (fnmatch(authen->username[i], username, 0)
564 				    == 0)
565 					goto found;
566 			}
567 		}
568  found:
569 		if (authen == NULL) {
570 			log_warnx("Received %s(code=%d) from %s id=%d "
571 			    "username=%s: no `authenticate' matches.",
572 			    radius_code_string(req_code), req_code, peerstr,
573 			    req_id, username);
574 			goto on_error;
575 		}
576 		q->authen = authen;
577 
578 		if (!MODULE_DO_USERPASS(authen->auth->module) &&
579 		    !MODULE_DO_ACCSREQ(authen->auth->module)) {
580 			log_warnx("Received %s(code=%d) from %s id=%d "
581 			    "username=%s: module `%s' is not running.",
582 			    radius_code_string(req_code), req_code, peerstr,
583 			    req_id, username, authen->auth->module->name);
584 			goto on_error;
585 		}
586 
587 		log_info("Received %s(code=%d) from %s id=%d username=%s "
588 		    "q=%u: `%s' authentication is starting",
589 		    radius_code_string(req_code), req_code, peerstr, q->req_id,
590 		    q->username, q->id, q->authen->auth->module->name);
591 
592 		raidus_query_access_request(q);
593 		return;
594 	case RADIUS_CODE_ACCOUNTING_REQUEST:
595 		if (!listn->accounting) {
596 			log_info("Received %s(code=%d) from %s id=%d: "
597 			    "ignored because the port is for accounting",
598 			    radius_code_string(req_code), req_code, peerstr,
599 			    req_id);
600 			break;
601 		}
602 		if (radius_get_uint32_attr(q->req, RADIUS_TYPE_ACCT_STATUS_TYPE,
603 		    &acct_status) != 0)
604 			acct_status = 0;
605 		/*
606 		 * Find a matching `accounting' entry
607 		 */
608 		TAILQ_FOREACH(accounting, &listn->radiusd->account, next) {
609 			if (acct_status == RADIUS_ACCT_STATUS_TYPE_ACCT_ON ||
610 			    acct_status == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) {
611 				raidus_query_accounting_request(accounting, q);
612 				continue;
613 			}
614 			for (i = 0; accounting->username[i] != NULL; i++) {
615 				if (fnmatch(accounting->username[i], username,
616 				    0) == 0)
617 					break;
618 			}
619 			if (accounting->username[i] == NULL)
620 				continue;
621 			raidus_query_accounting_request(accounting, q);
622 			if (accounting->quick)
623 				break;
624 		}
625 		/* pass NULL to hadnle this self without module */
626 		raidus_query_accounting_request(NULL, q);
627 
628 		if ((q->res = radius_new_response_packet(
629 		    RADIUS_CODE_ACCOUNTING_RESPONSE, q->req)) == NULL)
630 			log_warn("%s: radius_new_response_packet() failed",
631 			    __func__);
632 		else
633 			radius_query_accounting_response(q);
634 		break;
635 	default:
636 		log_info("Received %s(code=%d) from %s id=%d: %s is not "
637 		    "supported in this implementation", radius_code_string(
638 		    req_code), req_code, peerstr, req_id, radius_code_string(
639 		    req_code));
640 		break;
641 	}
642 on_error:
643 	if (packet != NULL)
644 		radius_delete_packet(packet);
645 	if (q != NULL)
646 		radiusd_access_request_aborted(q);
647 #undef in
648 #undef in6
649 }
650 
651 static void
652 raidus_query_access_request(struct radius_query *q)
653 {
654 	struct radiusd_authentication	*authen = q->authen;
655 
656 	/* first or next request decoration */
657 	for (;;) {
658 		if (q->deco == NULL)
659 			q->deco = TAILQ_FIRST(&q->authen->deco);
660 		else
661 			q->deco = TAILQ_NEXT(q->deco, next);
662 		if (q->deco == NULL || MODULE_DO_REQDECO(q->deco->module))
663 			break;
664 	}
665 
666 	if (q->deco != NULL)
667 		radiusd_module_request_decoration(q->deco->module, q);
668 	else {
669 		RADIUSD_ASSERT(authen->auth != NULL);
670 		if (MODULE_DO_ACCSREQ(authen->auth->module))
671 			radiusd_module_access_request(authen->auth->module, q);
672 		else if (MODULE_DO_USERPASS(authen->auth->module))
673 			radiusd_module_userpass(authen->auth->module, q);
674 	}
675 }
676 
677 static void
678 radius_query_access_response(struct radius_query *q)
679 {
680 	int		 sz, res_id, res_code;
681 	char		 buf[NI_MAXHOST + NI_MAXSERV + 30];
682 
683 	/* first or next response decoration */
684 	for (;;) {
685 		if (q->deco == NULL)
686 			q->deco = TAILQ_FIRST(&q->authen->deco);
687 		else
688 			q->deco = TAILQ_NEXT(q->deco, next);
689 		if (q->deco == NULL || MODULE_DO_RESDECO(q->deco->module))
690 			break;
691 	}
692 
693 	if (q->deco != NULL) {
694 		radiusd_module_response_decoration(q->deco->module, q);
695 		return;
696 	}
697 
698 	if (radiusd_access_response_fixup(q) != 0)
699 		goto on_error;
700 
701 	res_id = radius_get_id(q->res);
702 	res_code = radius_get_code(q->res);
703 
704 	/* Reset response/message authenticator */
705 	if (radius_has_attr(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR))
706 		radius_del_attr_all(q->res, RADIUS_TYPE_MESSAGE_AUTHENTICATOR);
707 	radius_put_message_authenticator(q->res, q->client->secret);
708 	radius_set_response_authenticator(q->res, q->client->secret);
709 
710 	log_info("Sending %s(code=%d) to %s id=%u q=%u",
711 	    radius_code_string(res_code), res_code,
712 	    addrport_tostring((struct sockaddr *)&q->clientaddr,
713 		    q->clientaddrlen, buf, sizeof(buf)), res_id, q->id);
714 
715 	if ((sz = sendto(q->listen->sock, radius_get_data(q->res),
716 	    radius_get_length(q->res), 0,
717 	    (struct sockaddr *)&q->clientaddr, q->clientaddrlen)) <= 0)
718 		log_warn("Sending a RADIUS response failed");
719 on_error:
720 	radiusd_access_request_aborted(q);
721 }
722 
723 static void
724 raidus_query_accounting_request(struct radiusd_accounting *accounting,
725     struct radius_query *q)
726 {
727 	int		 req_code;
728 	uint32_t	 acct_status;
729 	char		 buf0[NI_MAXHOST + NI_MAXSERV + 30];
730 
731 	if (accounting != NULL) {
732 		/* handle by the module */
733 		if (MODULE_DO_ACCTREQ(accounting->acct->module))
734 			radiusd_module_account_request(accounting->acct->module,
735 			    q);
736 		return;
737 	}
738 	req_code = radius_get_code(q->req);
739 	if (radius_get_uint32_attr(q->req, RADIUS_TYPE_ACCT_STATUS_TYPE,
740 	    &acct_status) != 0)
741 		acct_status = 0;
742 	log_info("Received %s(code=%d) type=%s(%lu) from %s id=%d username=%s "
743 	    "q=%u", radius_code_string(req_code), req_code,
744 	    radius_acct_status_type_string(acct_status), (unsigned long)
745 	    acct_status, addrport_tostring((struct sockaddr *)&q->clientaddr,
746 	    q->clientaddrlen, buf0, sizeof(buf0)), q->req_id, q->username,
747 	    q->id);
748 }
749 
750 static void
751 radius_query_accounting_response(struct radius_query *q)
752 {
753 	int		 sz, res_id, res_code;
754 	char		 buf[NI_MAXHOST + NI_MAXSERV + 30];
755 
756 	radius_set_response_authenticator(q->res, q->client->secret);
757 	res_id = radius_get_id(q->res);
758 	res_code = radius_get_code(q->res);
759 
760 	log_info("Sending %s(code=%d) to %s id=%u q=%u",
761 	    radius_code_string(res_code), res_code,
762 	    addrport_tostring((struct sockaddr *)&q->clientaddr,
763 		    q->clientaddrlen, buf, sizeof(buf)), res_id, q->id);
764 
765 	if ((sz = sendto(q->listen->sock, radius_get_data(q->res),
766 	    radius_get_length(q->res), 0,
767 	    (struct sockaddr *)&q->clientaddr, q->clientaddrlen)) <= 0)
768 		log_warn("Sending a RADIUS response failed");
769 }
770 /***********************************************************************
771  * Callback functions from the modules
772  ***********************************************************************/
773 void
774 radiusd_access_request_answer(struct radius_query *q)
775 {
776 	const char	*authen_secret = q->authen->auth->module->secret;
777 
778 	radius_set_request_packet(q->res, q->req);
779 
780 	if (authen_secret == NULL) {
781 		/*
782 		 * The module diddn't check the authenticators
783 		 */
784 		if (radius_check_response_authenticator(q->res,
785 		    q->client->secret) != 0) {
786 			log_info("Response from module has bad response "
787 			    "authenticator: id=%d", q->id);
788 			goto on_error;
789 		}
790 		if (radius_has_attr(q->res,
791 		    RADIUS_TYPE_MESSAGE_AUTHENTICATOR) &&
792 		    radius_check_message_authenticator(q->res,
793 		    q->client->secret) != 0) {
794 			log_info("Response from module has bad message "
795 			    "authenticator: id=%d", q->id);
796 			goto on_error;
797 		}
798 	}
799 
800 	RADIUSD_ASSERT(q->deco == NULL);
801 	radius_query_access_response(q);
802 
803 	return;
804 on_error:
805 	radiusd_access_request_aborted(q);
806 }
807 
808 void
809 radiusd_access_request_aborted(struct radius_query *q)
810 {
811 	if (q->req != NULL)
812 		radius_delete_packet(q->req);
813 	if (q->res != NULL)
814 		radius_delete_packet(q->res);
815 	TAILQ_REMOVE(&q->listen->radiusd->query, q, next);
816 	free(q);
817 }
818 
819 /***********************************************************************
820  * Signal handlers
821  ***********************************************************************/
822 static void
823 radiusd_on_sigterm(int fd, short evmask, void *ctx)
824 {
825 	log_info("Received SIGTERM");
826 	event_loopbreak();
827 }
828 
829 static void
830 radiusd_on_sigint(int fd, short evmask, void *ctx)
831 {
832 	log_info("Received SIGINT");
833 	event_loopbreak();
834 }
835 
836 static void
837 radiusd_on_sighup(int fd, short evmask, void *ctx)
838 {
839 	log_info("Received SIGHUP");
840 }
841 
842 static void
843 radiusd_on_sigchld(int fd, short evmask, void *ctx)
844 {
845 	struct radiusd		*radiusd = ctx;
846 	struct radiusd_module	*module;
847 	pid_t			 pid;
848 	int			 status, ndeath = 0;
849 
850 	log_debug("Received SIGCHLD");
851 	while ((pid = wait3(&status, WNOHANG, NULL)) != 0) {
852 		if (pid == -1)
853 			break;
854 		TAILQ_FOREACH(module, &radiusd->module, next) {
855 			if (module->pid == pid) {
856 				if (WIFEXITED(status))
857 					log_warnx("module `%s'(pid=%d) exited "
858 					    "with status %d", module->name,
859 					    (int)pid, WEXITSTATUS(status));
860 				else
861 					log_warnx("module `%s'(pid=%d) exited "
862 					    "by signal %d", module->name,
863 					    (int)pid, WTERMSIG(status));
864 				ndeath++;
865 				break;
866 			}
867 		}
868 		if (!module) {
869 			if (WIFEXITED(status))
870 				log_warnx("unkown child process pid=%d exited "
871 				    "with status %d", (int)pid,
872 				     WEXITSTATUS(status));
873 			else
874 				log_warnx("unkown child process pid=%d exited "
875 				    "by signal %d", (int)pid,
876 				    WTERMSIG(status));
877 		}
878 	}
879 	if (ndeath > 0) {
880 		radiusd->error++;
881 		event_loopbreak();
882 	}
883 }
884 
885 static const char *
886 radius_code_string(int code)
887 {
888 	int			i;
889 	struct _codestrings {
890 		int		 code;
891 		const char	*string;
892 	} codestrings[] = {
893 	    { RADIUS_CODE_ACCESS_REQUEST,	"Access-Request" },
894 	    { RADIUS_CODE_ACCESS_ACCEPT,	"Access-Accept" },
895 	    { RADIUS_CODE_ACCESS_REJECT,	"Access-Reject" },
896 	    { RADIUS_CODE_ACCOUNTING_REQUEST,	"Accounting-Request" },
897 	    { RADIUS_CODE_ACCOUNTING_RESPONSE,	"Accounting-Response" },
898 	    { RADIUS_CODE_ACCESS_CHALLENGE,	"Access-Challenge" },
899 	    { RADIUS_CODE_STATUS_SERVER,	"Status-Server" },
900 	    { RADIUS_CODE_STATUS_CLIENT,	"Status-Client" },
901 	    { -1,				NULL }
902 	};
903 
904 	for (i = 0; codestrings[i].code != -1; i++)
905 		if (codestrings[i].code == code)
906 			return (codestrings[i].string);
907 
908 	return ("Unknown");
909 }
910 
911 static const char *
912 radius_acct_status_type_string(uint32_t type)
913 {
914 	int			i;
915 	struct _typestrings {
916 		uint32_t	 type;
917 		const char	*string;
918 	} typestrings[] = {
919 	    { RADIUS_ACCT_STATUS_TYPE_START,		"Start" },
920 	    { RADIUS_ACCT_STATUS_TYPE_STOP,		"Stop" },
921 	    { RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE,	"Interim-Update" },
922 	    { RADIUS_ACCT_STATUS_TYPE_ACCT_ON,		"Accounting-On" },
923 	    { RADIUS_ACCT_STATUS_TYPE_ACCT_OFF,		"Accounting-Off" },
924 	    { -1,					NULL }
925 	};
926 
927 	for (i = 0; typestrings[i].string != NULL; i++)
928 		if (typestrings[i].type == type)
929 			return (typestrings[i].string);
930 
931 	return ("Unknown");
932 }
933 
934 void
935 radiusd_conf_init(struct radiusd *conf)
936 {
937 
938 	TAILQ_INIT(&conf->listen);
939 	TAILQ_INIT(&conf->module);
940 	TAILQ_INIT(&conf->authen);
941 	TAILQ_INIT(&conf->account);
942 	TAILQ_INIT(&conf->client);
943 
944 	return;
945 }
946 
947 /*
948  * Fix some attributes which depend the secret value.
949  */
950 static int
951 radiusd_access_response_fixup(struct radius_query *q)
952 {
953 	int		 res_id;
954 	size_t		 attrlen;
955 	u_char		 req_auth[16], attrbuf[256];
956 	const char	*authen_secret = q->authen->auth->module->secret;
957 
958 	radius_get_authenticator(q->req, req_auth);
959 
960 	if ((authen_secret != NULL &&
961 	    strcmp(authen_secret, q->client->secret) != 0) ||
962 	    timingsafe_bcmp(q->req_auth, req_auth, 16) != 0) {
963 		const char *olds = q->client->secret;
964 		const char *news = authen_secret;
965 
966 		if (news == NULL)
967 			news = olds;
968 
969 		/* RFC 2865 Tunnel-Password */
970 		attrlen = sizeof(attrbuf);
971 		if (radius_get_raw_attr(q->res, RADIUS_TYPE_TUNNEL_PASSWORD,
972 		    attrbuf, &attrlen) == 0) {
973 			radius_attr_unhide(news, req_auth,
974 			    attrbuf, attrbuf + 3, attrlen - 3);
975 			radius_attr_hide(olds, q->req_auth,
976 			    attrbuf, attrbuf + 3, attrlen - 3);
977 
978 			radius_del_attr_all(q->res,
979 			    RADIUS_TYPE_TUNNEL_PASSWORD);
980 			radius_put_raw_attr(q->res,
981 			    RADIUS_TYPE_TUNNEL_PASSWORD, attrbuf, attrlen);
982 		}
983 
984 		/* RFC 2548 Microsoft MPPE-{Send,Recv}-Key */
985 		attrlen = sizeof(attrbuf);
986 		if (radius_get_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT,
987 		    RADIUS_VTYPE_MPPE_SEND_KEY, attrbuf, &attrlen) == 0) {
988 
989 			/* Re-crypt the KEY */
990 			radius_attr_unhide(news, req_auth,
991 			    attrbuf, attrbuf + 2, attrlen - 2);
992 			radius_attr_hide(olds, q->req_auth,
993 			    attrbuf, attrbuf + 2, attrlen - 2);
994 
995 			radius_del_vs_attr_all(q->res, RADIUS_VENDOR_MICROSOFT,
996 			    RADIUS_VTYPE_MPPE_SEND_KEY);
997 			radius_put_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT,
998 			    RADIUS_VTYPE_MPPE_SEND_KEY, attrbuf, attrlen);
999 		}
1000 		attrlen = sizeof(attrbuf);
1001 		if (radius_get_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT,
1002 		    RADIUS_VTYPE_MPPE_RECV_KEY, attrbuf, &attrlen) == 0) {
1003 
1004 			/* Re-crypt the KEY */
1005 			radius_attr_unhide(news, req_auth,
1006 			    attrbuf, attrbuf + 2, attrlen - 2);
1007 			radius_attr_hide(olds, q->req_auth,
1008 			    attrbuf, attrbuf + 2, attrlen - 2);
1009 
1010 			radius_del_vs_attr_all(q->res, RADIUS_VENDOR_MICROSOFT,
1011 			    RADIUS_VTYPE_MPPE_RECV_KEY);
1012 			radius_put_vs_raw_attr(q->res, RADIUS_VENDOR_MICROSOFT,
1013 			    RADIUS_VTYPE_MPPE_RECV_KEY, attrbuf, attrlen);
1014 		}
1015 	}
1016 
1017 	res_id = radius_get_id(q->res);
1018 	if (res_id != q->req_id) {
1019 		/* authentication server change the id */
1020 		radius_set_id(q->res, q->req_id);
1021 	}
1022 
1023 	return (0);
1024 }
1025 
1026 void
1027 radius_attr_hide(const char *secret, const char *authenticator,
1028     const u_char *salt, u_char *plain, int plainlen)
1029 {
1030 	int	  i, j;
1031 	u_char	  b[16];
1032 	MD5_CTX	  md5ctx;
1033 
1034 	i = 0;
1035 	do {
1036 		MD5Init(&md5ctx);
1037 		MD5Update(&md5ctx, secret, strlen(secret));
1038 		if (i == 0) {
1039 			MD5Update(&md5ctx, authenticator, 16);
1040 			if (salt != NULL)
1041 				MD5Update(&md5ctx, salt, 2);
1042 		} else
1043 			MD5Update(&md5ctx, plain + i - 16, 16);
1044 		MD5Final(b, &md5ctx);
1045 
1046 		for (j = 0; j < 16 && i < plainlen; i++, j++)
1047 			plain[i] ^= b[j];
1048 	} while (i < plainlen);
1049 }
1050 
1051 void
1052 radius_attr_unhide(const char *secret, const char *authenticator,
1053     const u_char *salt, u_char *crypt0, int crypt0len)
1054 {
1055 	int	  i, j;
1056 	u_char	  b[16];
1057 	MD5_CTX	  md5ctx;
1058 
1059 	i = 16 * ((crypt0len - 1) / 16);
1060 	while (i >= 0) {
1061 		MD5Init(&md5ctx);
1062 		MD5Update(&md5ctx, secret, strlen(secret));
1063 		if (i == 0) {
1064 			MD5Update(&md5ctx, authenticator, 16);
1065 			if (salt != NULL)
1066 				MD5Update(&md5ctx, salt, 2);
1067 		} else
1068 			MD5Update(&md5ctx, crypt0 + i - 16, 16);
1069 		MD5Final(b, &md5ctx);
1070 
1071 		for (j = 0; j < 16 && i + j < crypt0len; j++)
1072 			crypt0[i + j] ^= b[j];
1073 		i -= 16;
1074 	}
1075 }
1076 
1077 static struct radius_query *
1078 radiusd_find_query(struct radiusd *radiusd, u_int q_id)
1079 {
1080 	struct radius_query	*q;
1081 
1082 	TAILQ_FOREACH(q, &radiusd->query, next) {
1083 		if (q->id == q_id)
1084 			return (q);
1085 	}
1086 	return (NULL);
1087 }
1088 
1089 int
1090 radiusd_imsg_compose_module(struct radiusd *radiusd, const char *module_name,
1091     uint32_t type, uint32_t id, pid_t pid, int fd, void *data, size_t datalen)
1092 {
1093 	struct radiusd_module	*module;
1094 
1095 	TAILQ_FOREACH(module, &radiusd_s->module, next) {
1096 		if (strcmp(module->name, module_name) == 0)
1097 			break;
1098 	}
1099 	if (module == NULL ||
1100 	    (module->capabilities & RADIUSD_MODULE_CAP_CONTROL) == 0 ||
1101 	    module->fd < 0)
1102 		return (-1);
1103 
1104 	if (imsg_compose(&module->ibuf, type, id, pid, fd, data,
1105 	    datalen) == -1)
1106 		return (-1);
1107 	radiusd_module_reset_ev_handler(module);
1108 
1109 	return (0);
1110 }
1111 
1112 /***********************************************************************
1113  * radiusd module handling
1114  ***********************************************************************/
1115 struct radiusd_module *
1116 radiusd_module_load(struct radiusd *radiusd, const char *path, const char *name)
1117 {
1118 	struct radiusd_module		*module = NULL;
1119 	pid_t				 pid;
1120 	int				 ival, pairsock[] = { -1, -1 };
1121 	const char			*av[3];
1122 	ssize_t				 n;
1123 	struct imsg			 imsg;
1124 
1125 	module = calloc(1, sizeof(struct radiusd_module));
1126 	if (module == NULL)
1127 		fatal("Out of memory");
1128 	module->radiusd = radiusd;
1129 
1130 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pairsock) == -1) {
1131 		log_warn("Could not load module `%s'(%s): pipe()", name, path);
1132 		goto on_error;
1133 	}
1134 
1135 	pid = fork();
1136 	if (pid == -1) {
1137 		log_warn("Could not load module `%s'(%s): fork()", name, path);
1138 		goto on_error;
1139 	}
1140 	if (pid == 0) {
1141 		setsid();
1142 		close(pairsock[0]);
1143 		av[0] = path;
1144 		av[1] = name;
1145 		av[2] = NULL;
1146 		dup2(pairsock[1], STDIN_FILENO);
1147 		dup2(pairsock[1], STDOUT_FILENO);
1148 		close(pairsock[1]);
1149 		closefrom(STDERR_FILENO + 1);
1150 		execv(path, (char * const *)av);
1151 		log_warn("Failed to execute %s", path);
1152 		_exit(EXIT_FAILURE);
1153 	}
1154 	close(pairsock[1]);
1155 
1156 	module->fd = pairsock[0];
1157 	if ((ival = fcntl(module->fd, F_GETFL)) == -1) {
1158 		log_warn("Could not load module `%s': fcntl(F_GETFL)",
1159 		    name);
1160 		goto on_error;
1161 	}
1162 	if (fcntl(module->fd, F_SETFL, ival | O_NONBLOCK) == -1) {
1163 		log_warn(
1164 		    "Could not load module `%s': fcntl(F_SETFL,O_NONBLOCK)",
1165 		    name);
1166 		goto on_error;
1167 	}
1168 	strlcpy(module->name, name, sizeof(module->name));
1169 	module->pid = pid;
1170 	imsg_init(&module->ibuf, module->fd);
1171 
1172 	if (imsg_sync_read(&module->ibuf, MODULE_IO_TIMEOUT) <= 0 ||
1173 	    (n = imsg_get(&module->ibuf, &imsg)) <= 0) {
1174 		log_warnx("Could not load module `%s': module didn't "
1175 		    "respond", name);
1176 		goto on_error;
1177 	}
1178 	if (imsg.hdr.type != IMSG_RADIUSD_MODULE_LOAD) {
1179 		imsg_free(&imsg);
1180 		log_warnx("Could not load module `%s': unknown imsg type=%d",
1181 		    name, imsg.hdr.type);
1182 		goto on_error;
1183 	}
1184 
1185 	module->capabilities =
1186 	    ((struct radiusd_module_load_arg *)imsg.data)->cap;
1187 
1188 	log_debug("Loaded module `%s' successfully.  pid=%d", module->name,
1189 	    module->pid);
1190 	imsg_free(&imsg);
1191 
1192 	return (module);
1193 
1194 on_error:
1195 	free(module);
1196 	if (pairsock[0] >= 0)
1197 		close(pairsock[0]);
1198 	if (pairsock[1] >= 0)
1199 		close(pairsock[1]);
1200 
1201 	return (NULL);
1202 }
1203 
1204 void
1205 radiusd_module_start(struct radiusd_module *module)
1206 {
1207 	int		 datalen;
1208 	struct imsg	 imsg;
1209 	struct timeval	 tv = { 0, 0 };
1210 
1211 	RADIUSD_ASSERT(module->fd >= 0);
1212 	imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_START, 0, 0, -1,
1213 	    NULL, 0);
1214 	imsg_sync_flush(&module->ibuf, MODULE_IO_TIMEOUT);
1215 	if (imsg_sync_read(&module->ibuf, MODULE_IO_TIMEOUT) <= 0 ||
1216 	    imsg_get(&module->ibuf, &imsg) <= 0) {
1217 		log_warnx("Module `%s' could not start: no response",
1218 		    module->name);
1219 		goto on_fail;
1220 	}
1221 
1222 	datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
1223 	if (imsg.hdr.type != IMSG_OK) {
1224 		if (imsg.hdr.type == IMSG_NG) {
1225 			if (datalen > 0)
1226 				log_warnx("Module `%s' could not start: %s",
1227 				    module->name, (char *)imsg.data);
1228 			else
1229 				log_warnx("Module `%s' could not start",
1230 				    module->name);
1231 		} else
1232 			log_warnx("Module `%s' could not started: module "
1233 			    "returned unknown message type %d", module->name,
1234 			    imsg.hdr.type);
1235 		goto on_fail;
1236 	}
1237 
1238 	event_set(&module->ev, module->fd, EV_READ, radiusd_module_on_imsg_io,
1239 	    module);
1240 	event_add(&module->ev, &tv);
1241 	log_debug("Module `%s' started successfully", module->name);
1242 
1243 	return;
1244 on_fail:
1245 	radiusd_module_close(module);
1246 	return;
1247 }
1248 
1249 void
1250 radiusd_module_stop(struct radiusd_module *module)
1251 {
1252 	module->stopped = true;
1253 
1254 	if (module->secret != NULL) {
1255 		freezero(module->secret, strlen(module->secret));
1256 		module->secret = NULL;
1257 	}
1258 
1259 	if (module->fd >= 0) {
1260 		imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_STOP, 0, 0, -1,
1261 		    NULL, 0);
1262 		radiusd_module_reset_ev_handler(module);
1263 	}
1264 }
1265 
1266 static void
1267 radiusd_module_close(struct radiusd_module *module)
1268 {
1269 	if (module->fd >= 0) {
1270 		event_del(&module->ev);
1271 		imsg_clear(&module->ibuf);
1272 		close(module->fd);
1273 		module->fd = -1;
1274 	}
1275 }
1276 
1277 void
1278 radiusd_module_unload(struct radiusd_module *module)
1279 {
1280 	free(module->radpkt);
1281 	radiusd_module_close(module);
1282 	free(module);
1283 }
1284 
1285 static void
1286 radiusd_module_on_imsg_io(int fd, short evmask, void *ctx)
1287 {
1288 	struct radiusd_module	*module = ctx;
1289 	int			 ret;
1290 
1291 	if (evmask & EV_WRITE)
1292 		module->writeready = true;
1293 
1294 	if (evmask & EV_READ) {
1295 		if (radiusd_module_imsg_read(module) == -1)
1296 			goto on_error;
1297 	}
1298 
1299 	while (module->writeready && module->ibuf.w.queued) {
1300 		ret = msgbuf_write(&module->ibuf.w);
1301 		if (ret > 0)
1302 			continue;
1303 		module->writeready = false;
1304 		if (ret == 0 && errno == EAGAIN)
1305 			break;
1306 		log_warn("Failed to write to module `%s': msgbuf_write()",
1307 		    module->name);
1308 		goto on_error;
1309 	}
1310 	radiusd_module_reset_ev_handler(module);
1311 
1312 	return;
1313 on_error:
1314 	radiusd_module_close(module);
1315 }
1316 
1317 static void
1318 radiusd_module_reset_ev_handler(struct radiusd_module *module)
1319 {
1320 	short		 evmask;
1321 	struct timeval	*tvp = NULL, tv = { 0, 0 };
1322 
1323 	RADIUSD_ASSERT(module->fd >= 0);
1324 	event_del(&module->ev);
1325 
1326 	evmask = EV_READ;
1327 	if (module->ibuf.w.queued) {
1328 		if (!module->writeready)
1329 			evmask |= EV_WRITE;
1330 		else
1331 			tvp = &tv;	/* fire immediately */
1332 	}
1333 
1334 	/* module stopped and no event handler is set */
1335 	if (evmask & EV_WRITE && tvp == NULL && module->stopped) {
1336 		/* stop requested and no more to write */
1337 		radiusd_module_close(module);
1338 		return;
1339 	}
1340 
1341 	event_set(&module->ev, module->fd, evmask, radiusd_module_on_imsg_io,
1342 	    module);
1343 	if (event_add(&module->ev, tvp) == -1) {
1344 		log_warn("Could not set event handlers for module `%s': "
1345 		    "event_add()", module->name);
1346 		radiusd_module_close(module);
1347 	}
1348 }
1349 
1350 static int
1351 radiusd_module_imsg_read(struct radiusd_module *module)
1352 {
1353 	int		 n;
1354 	struct imsg	 imsg;
1355 
1356 	if ((n = imsg_read(&module->ibuf)) == -1 || n == 0) {
1357 		if (n == -1 && errno == EAGAIN)
1358 			return (0);
1359 		if (n == -1)
1360 			log_warn("Receiving a message from module `%s' "
1361 			    "failed: imsg_read", module->name);
1362 		/* else closed */
1363 		radiusd_module_close(module);
1364 		return (-1);
1365 	}
1366 	for (;;) {
1367 		if ((n = imsg_get(&module->ibuf, &imsg)) == -1) {
1368 			log_warn("Receiving a message from module `%s' failed: "
1369 			    "imsg_get", module->name);
1370 			return (-1);
1371 		}
1372 		if (n == 0)
1373 			return (0);
1374 		radiusd_module_imsg(module, &imsg);
1375 	}
1376 
1377 	return (0);
1378 }
1379 
1380 static void
1381 radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg)
1382 {
1383 	int			 datalen;
1384 	struct radius_query	*q;
1385 	u_int			 q_id;
1386 
1387 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1388 	switch (imsg->hdr.type) {
1389 	case IMSG_RADIUSD_MODULE_NOTIFY_SECRET:
1390 		if (datalen > 0) {
1391 			module->secret = strdup(imsg->data);
1392 			if (module->secret == NULL)
1393 				log_warn("Could not handle NOTIFY_SECRET "
1394 				    "from `%s'", module->name);
1395 		}
1396 		break;
1397 	case IMSG_RADIUSD_MODULE_USERPASS_OK:
1398 	case IMSG_RADIUSD_MODULE_USERPASS_FAIL:
1399 	    {
1400 		char			*msg = NULL;
1401 		const char		*msgtypestr;
1402 
1403 		msgtypestr = (imsg->hdr.type == IMSG_RADIUSD_MODULE_USERPASS_OK)
1404 		    ? "USERPASS_OK" : "USERPASS_NG";
1405 
1406 		q_id = *(u_int *)imsg->data;
1407 		if (datalen > (ssize_t)sizeof(u_int))
1408 			msg = (char *)(((u_int *)imsg->data) + 1);
1409 
1410 		q = radiusd_find_query(module->radiusd, q_id);
1411 		if (q == NULL) {
1412 			log_warnx("Received %s from `%s', but query id=%u "
1413 			    "unknown", msgtypestr, module->name, q_id);
1414 			break;
1415 		}
1416 
1417 		if ((q->res = radius_new_response_packet(
1418 		    (imsg->hdr.type == IMSG_RADIUSD_MODULE_USERPASS_OK)
1419 		    ? RADIUS_CODE_ACCESS_ACCEPT : RADIUS_CODE_ACCESS_REJECT,
1420 		    q->req)) == NULL) {
1421 			log_warn("radius_new_response_packet() failed");
1422 			radiusd_access_request_aborted(q);
1423 		} else {
1424 			if (msg)
1425 				radius_put_string_attr(q->res,
1426 				    RADIUS_TYPE_REPLY_MESSAGE, msg);
1427 			radius_set_response_authenticator(q->res,
1428 			    q->client->secret);
1429 			radiusd_access_request_answer(q);
1430 		}
1431 		break;
1432 	    }
1433 	case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
1434 	case IMSG_RADIUSD_MODULE_REQDECO_DONE:
1435 	case IMSG_RADIUSD_MODULE_RESDECO_DONE:
1436 	    {
1437 		static struct radiusd_module_radpkt_arg *ans;
1438 		const char *typestr = "unknown";
1439 
1440 		switch (imsg->hdr.type) {
1441 		case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
1442 			typestr = "ACCSREQ_ANSWER";
1443 			break;
1444 		case IMSG_RADIUSD_MODULE_REQDECO_DONE:
1445 			typestr = "REQDECO_DONE";
1446 			break;
1447 		case IMSG_RADIUSD_MODULE_RESDECO_DONE:
1448 			typestr = "RESDECO_DONE";
1449 			break;
1450 		}
1451 
1452 		if (datalen <
1453 		    (ssize_t)sizeof(struct radiusd_module_radpkt_arg)) {
1454 			log_warnx("Received %s message, but length is wrong",
1455 			    typestr);
1456 			break;
1457 		}
1458 		q_id = ((struct radiusd_module_radpkt_arg *)imsg->data)->q_id;
1459 		q = radiusd_find_query(module->radiusd, q_id);
1460 		if (q == NULL) {
1461 			log_warnx("Received %s from %s, but query id=%u "
1462 			    "unknown", typestr, module->name, q_id);
1463 			break;
1464 		}
1465 		if ((ans = radiusd_module_recv_radpkt(module, imsg,
1466 		    imsg->hdr.type, typestr)) != NULL) {
1467 			RADIUS_PACKET *radpkt = NULL;
1468 
1469 			if (module->radpktoff > 0 &&
1470 			    (radpkt = radius_convert_packet(
1471 			    module->radpkt, module->radpktoff)) == NULL) {
1472 				log_warn("q=%u radius_convert_packet() failed",
1473 				    q->id);
1474 				radiusd_access_request_aborted(q);
1475 				break;
1476 			}
1477 			module->radpktoff = 0;
1478 			switch (imsg->hdr.type) {
1479 			case IMSG_RADIUSD_MODULE_REQDECO_DONE:
1480 				if (q->deco == NULL || q->deco->type !=
1481 				    IMSG_RADIUSD_MODULE_REQDECO) {
1482 					log_warnx("q=%u received %s "
1483 					    "but not requested", q->id, typestr);
1484 					if (radpkt != NULL)
1485 						radius_delete_packet(radpkt);
1486 					break;
1487 				}
1488 				if (radpkt != NULL) {
1489 					radius_delete_packet(q->req);
1490 					q->req = radpkt;
1491 				}
1492 				raidus_query_access_request(q);
1493 				break;
1494 			case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
1495 				if (radpkt == NULL) {
1496 					log_warnx("q=%u wrong pkt from module",
1497 					    q->id);
1498 					radiusd_access_request_aborted(q);
1499 					break;
1500 				}
1501 				q->res = radpkt;
1502 				radiusd_access_request_answer(q);
1503 				break;
1504 			case IMSG_RADIUSD_MODULE_RESDECO_DONE:
1505 				if (q->deco == NULL || q->deco->type !=
1506 				    IMSG_RADIUSD_MODULE_RESDECO) {
1507 					log_warnx("q=%u received %s but not "
1508 					    "requested", q->id, typestr);
1509 					if (radpkt != NULL)
1510 						radius_delete_packet(radpkt);
1511 					break;
1512 				}
1513 				if (radpkt != NULL) {
1514 					radius_delete_packet(q->res);
1515 					radius_set_request_packet(radpkt,
1516 					    q->req);
1517 					q->res = radpkt;
1518 				}
1519 				radius_query_access_response(q);
1520 				break;
1521 			}
1522 		}
1523 		break;
1524 	    }
1525 	case IMSG_RADIUSD_MODULE_ACCSREQ_ABORTED:
1526 	    {
1527 		if (datalen < (ssize_t)sizeof(u_int)) {
1528 			log_warnx("Received ACCSREQ_ABORTED message, but "
1529 			    "length is wrong");
1530 			break;
1531 		}
1532 		q_id = *((u_int *)imsg->data);
1533 		q = radiusd_find_query(module->radiusd, q_id);
1534 		if (q == NULL) {
1535 			log_warnx("Received ACCSREQ_ABORT from %s, but query "
1536 			    "id=%u unknown", module->name, q_id);
1537 			break;
1538 		}
1539 		radiusd_access_request_aborted(q);
1540 		break;
1541 	    }
1542 	case IMSG_RADIUSD_MODULE_CTRL_BIND:
1543 		control_conn_bind(imsg->hdr.peerid, module->name);
1544 		break;
1545 	default:
1546 		if (imsg->hdr.peerid != 0)
1547 			control_imsg_relay(imsg);
1548 		else
1549 			RADIUSD_DBG(("Unhandled imsg type=%d from %s",
1550 			    imsg->hdr.type, module->name));
1551 	}
1552 }
1553 
1554 static struct radiusd_module_radpkt_arg *
1555 radiusd_module_recv_radpkt(struct radiusd_module *module, struct imsg *imsg,
1556     uint32_t imsg_type, const char *type_str)
1557 {
1558 	struct radiusd_module_radpkt_arg	*ans;
1559 	int					 datalen, chunklen;
1560 
1561 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1562 	ans = (struct radiusd_module_radpkt_arg *)imsg->data;
1563 	if (module->radpktsiz < ans->pktlen) {
1564 		u_char *nradpkt;
1565 		if ((nradpkt = realloc(module->radpkt, ans->pktlen)) == NULL) {
1566 			log_warn("Could not handle received %s message from "
1567 			    "`%s'", type_str, module->name);
1568 			goto on_fail;
1569 		}
1570 		module->radpkt = nradpkt;
1571 		module->radpktsiz = ans->pktlen;
1572 	}
1573 	chunklen = datalen - sizeof(struct radiusd_module_radpkt_arg);
1574 	if (chunklen > module->radpktsiz - module->radpktoff) {
1575 		log_warnx("Could not handle received %s message from `%s': "
1576 		    "received length is too big", type_str, module->name);
1577 		goto on_fail;
1578 	}
1579 	if (chunklen > 0) {
1580 		memcpy(module->radpkt + module->radpktoff,
1581 		    (caddr_t)(ans + 1), chunklen);
1582 		module->radpktoff += chunklen;
1583 	}
1584 	if (!ans->final)
1585 		return (NULL);	/* again */
1586 	if (module->radpktoff != ans->pktlen) {
1587 		log_warnx("Could not handle received %s message from `%s': "
1588 		    "length is mismatch", type_str, module->name);
1589 		goto on_fail;
1590 	}
1591 
1592 	return (ans);
1593 on_fail:
1594 	module->radpktoff = 0;
1595 	return (NULL);
1596 }
1597 
1598 int
1599 radiusd_module_set(struct radiusd_module *module, const char *name,
1600     int argc, char * const * argv)
1601 {
1602 	struct radiusd_module_set_arg	 arg;
1603 	struct radiusd_module_object	*val;
1604 	int				 i, niov = 0;
1605 	u_char				*buf = NULL, *buf0;
1606 	ssize_t				 n;
1607 	size_t				 bufsiz = 0, bufoff = 0, bufsiz0;
1608 	size_t				 vallen, valsiz;
1609 	struct iovec			 iov[2];
1610 	struct imsg			 imsg;
1611 
1612 	memset(&arg, 0, sizeof(arg));
1613 	arg.nparamval = argc;
1614 	strlcpy(arg.paramname, name, sizeof(arg.paramname));
1615 
1616 	iov[niov].iov_base = &arg;
1617 	iov[niov].iov_len = sizeof(struct radiusd_module_set_arg);
1618 	niov++;
1619 
1620 	for (i = 0; i < argc; i++) {
1621 		vallen = strlen(argv[i]) + 1;
1622 		valsiz = sizeof(struct radiusd_module_object) + vallen;
1623 		if (bufsiz < bufoff + valsiz) {
1624 			bufsiz0 = bufoff + valsiz + 128;
1625 			if ((buf0 = realloc(buf, bufsiz0)) == NULL) {
1626 				log_warn("Failed to set config parameter to "
1627 				    "module `%s': realloc", module->name);
1628 				goto on_error;
1629 			}
1630 			buf = buf0;
1631 			bufsiz = bufsiz0;
1632 			memset(buf + bufoff, 0, bufsiz - bufoff);
1633 		}
1634 		val = (struct radiusd_module_object *)(buf + bufoff);
1635 		val->size = valsiz;
1636 		memcpy(val + 1, argv[i], vallen);
1637 
1638 		bufoff += valsiz;
1639 	}
1640 	iov[niov].iov_base = buf;
1641 	iov[niov].iov_len = bufoff;
1642 	niov++;
1643 
1644 	if (imsg_composev(&module->ibuf, IMSG_RADIUSD_MODULE_SET_CONFIG, 0, 0,
1645 	    -1, iov, niov) == -1) {
1646 		log_warn("Failed to set config parameter to module `%s': "
1647 		    "imsg_composev", module->name);
1648 		goto on_error;
1649 	}
1650 	if (imsg_sync_flush(&module->ibuf, MODULE_IO_TIMEOUT) == -1) {
1651 		log_warn("Failed to set config parameter to module `%s': "
1652 		    "imsg_flush_timeout", module->name);
1653 		goto on_error;
1654 	}
1655 	for (;;) {
1656 		if (imsg_sync_read(&module->ibuf, MODULE_IO_TIMEOUT) <= 0) {
1657 			log_warn("Failed to get reply from module `%s': "
1658 			    "imsg_sync_read", module->name);
1659 			goto on_error;
1660 		}
1661 		if ((n = imsg_get(&module->ibuf, &imsg)) > 0)
1662 			break;
1663 		if (n < 0) {
1664 			log_warn("Failed to get reply from module `%s': "
1665 			    "imsg_get", module->name);
1666 			goto on_error;
1667 		}
1668 	}
1669 	if (imsg.hdr.type == IMSG_NG) {
1670 		log_warnx("Could not set `%s' for module `%s': %s", name,
1671 		    module->name, (char *)imsg.data);
1672 		goto on_error;
1673 	} else if (imsg.hdr.type != IMSG_OK) {
1674 		imsg_free(&imsg);
1675 		log_warnx("Failed to get reply from module `%s': "
1676 		    "unknown imsg type=%d", module->name, imsg.hdr.type);
1677 		goto on_error;
1678 	}
1679 	imsg_free(&imsg);
1680 
1681 	free(buf);
1682 	return (0);
1683 
1684 on_error:
1685 	free(buf);
1686 	return (-1);
1687 }
1688 
1689 static void
1690 radiusd_module_userpass(struct radiusd_module *module, struct radius_query *q)
1691 {
1692 	struct radiusd_module_userpass_arg userpass;
1693 
1694 	memset(&userpass, 0, sizeof(userpass));
1695 	userpass.q_id = q->id;
1696 
1697 	if (radius_get_user_password_attr(q->req, userpass.pass,
1698 	    sizeof(userpass.pass), q->client->secret) == 0)
1699 		userpass.has_pass = true;
1700 	else
1701 		userpass.has_pass = false;
1702 	if (radius_get_string_attr(q->req, RADIUS_TYPE_USER_NAME,
1703 	    userpass.user, sizeof(userpass.user)) != 0) {
1704 		log_warnx("q=%u no User-Name attribute", q->id);
1705 		goto on_error;
1706 	}
1707 	imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_USERPASS, 0, 0, -1,
1708 	    &userpass, sizeof(userpass));
1709 	radiusd_module_reset_ev_handler(module);
1710 	return;
1711 on_error:
1712 	radiusd_access_request_aborted(q);
1713 }
1714 
1715 static void
1716 radiusd_module_access_request(struct radiusd_module *module,
1717     struct radius_query *q)
1718 {
1719 	RADIUS_PACKET				*radpkt;
1720 	char					 pass[256];
1721 
1722 	if ((radpkt = radius_convert_packet(radius_get_data(q->req),
1723 	    radius_get_length(q->req))) == NULL) {
1724 		log_warn("q=%u Could not send ACCSREQ to `%s'", q->id,
1725 		    module->name);
1726 		radiusd_access_request_aborted(q);
1727 		return;
1728 	}
1729 	if (q->client->secret[0] != '\0' && module->secret != NULL &&
1730 	    radius_get_user_password_attr(radpkt, pass, sizeof(pass),
1731 		    q->client->secret) == 0) {
1732 		radius_del_attr_all(radpkt, RADIUS_TYPE_USER_PASSWORD);
1733 		(void)radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD,
1734 		    pass, strlen(pass));
1735 	}
1736 	if (imsg_compose_radius_packet(&module->ibuf,
1737 	    IMSG_RADIUSD_MODULE_ACCSREQ, q->id, radpkt) == -1) {
1738 		log_warn("q=%u Could not send ACCSREQ to `%s'", q->id,
1739 		    module->name);
1740 		radiusd_access_request_aborted(q);
1741 	}
1742 	radiusd_module_reset_ev_handler(module);
1743 	radius_delete_packet(radpkt);
1744 }
1745 
1746 static void
1747 radiusd_module_request_decoration(struct radiusd_module *module,
1748     struct radius_query *q)
1749 {
1750 	if (module->fd < 0) {
1751 		log_warnx("q=%u Could not send REQDECO to `%s': module is "
1752 		    "not running?", q->id, module->name);
1753 		radiusd_access_request_aborted(q);
1754 		return;
1755 	}
1756 	if (imsg_compose_radius_packet(&module->ibuf,
1757 	    IMSG_RADIUSD_MODULE_REQDECO, q->id, q->req) == -1) {
1758 		log_warn("q=%u Could not send REQDECO to `%s'", q->id,
1759 		    module->name);
1760 		radiusd_access_request_aborted(q);
1761 		return;
1762 	}
1763 	RADIUSD_ASSERT(q->deco != NULL);
1764 	q->deco->type = IMSG_RADIUSD_MODULE_REQDECO;
1765 	radiusd_module_reset_ev_handler(module);
1766 }
1767 
1768 static void
1769 radiusd_module_response_decoration(struct radiusd_module *module,
1770     struct radius_query *q)
1771 {
1772 	if (module->fd < 0) {
1773 		log_warnx("q=%u Could not send RESDECO to `%s': module is "
1774 		    "not running?", q->id, module->name);
1775 		radiusd_access_request_aborted(q);
1776 		return;
1777 	}
1778 	if (imsg_compose_radius_packet(&module->ibuf,
1779 	    IMSG_RADIUSD_MODULE_RESDECO0_REQ, q->id, q->req) == -1) {
1780 		log_warn("q=%u Could not send RESDECO0_REQ to `%s'", q->id,
1781 		    module->name);
1782 		radiusd_access_request_aborted(q);
1783 		return;
1784 	}
1785 	if (imsg_compose_radius_packet(&module->ibuf,
1786 	    IMSG_RADIUSD_MODULE_RESDECO, q->id, q->res) == -1) {
1787 		log_warn("q=%u Could not send RESDECO to `%s'", q->id,
1788 		    module->name);
1789 		radiusd_access_request_aborted(q);
1790 		return;
1791 	}
1792 	RADIUSD_ASSERT(q->deco != NULL);
1793 	q->deco->type = IMSG_RADIUSD_MODULE_RESDECO;
1794 	radiusd_module_reset_ev_handler(module);
1795 }
1796 
1797 static void
1798 radiusd_module_account_request(struct radiusd_module *module,
1799     struct radius_query *q)
1800 {
1801 	RADIUS_PACKET				*radpkt;
1802 
1803 	if ((radpkt = radius_convert_packet(radius_get_data(q->req),
1804 	    radius_get_length(q->req))) == NULL) {
1805 		log_warn("q=%u Could not send ACCSREQ to `%s'", q->id,
1806 		    module->name);
1807 		radiusd_access_request_aborted(q);
1808 		return;
1809 	}
1810 	if (imsg_compose_radius_packet(&module->ibuf,
1811 	    IMSG_RADIUSD_MODULE_ACCTREQ, q->id, radpkt) == -1) {
1812 		log_warn("q=%u Could not send ACCTREQ to `%s'", q->id,
1813 		    module->name);
1814 		radiusd_access_request_aborted(q);
1815 	}
1816 	radiusd_module_reset_ev_handler(module);
1817 	radius_delete_packet(radpkt);
1818 }
1819 
1820 static int
1821 imsg_compose_radius_packet(struct imsgbuf *ibuf, uint32_t type, u_int q_id,
1822     RADIUS_PACKET *radpkt)
1823 {
1824 	struct radiusd_module_radpkt_arg	 arg;
1825 	int					 off = 0, len, siz;
1826 	struct iovec				 iov[2];
1827 	const u_char				*pkt;
1828 
1829 	pkt = radius_get_data(radpkt);
1830 	len = radius_get_length(radpkt);
1831 	memset(&arg, 0, sizeof(arg));
1832 	arg.q_id = q_id;
1833 	arg.pktlen = len;
1834 	while (off < len) {
1835 		siz = MAX_IMSGSIZE - sizeof(arg);
1836 		if (len - off > siz)
1837 			arg.final = false;
1838 		else {
1839 			arg.final = true;
1840 			siz = len - off;
1841 		}
1842 		iov[0].iov_base = &arg;
1843 		iov[0].iov_len = sizeof(arg);
1844 		iov[1].iov_base = (caddr_t)pkt + off;
1845 		iov[1].iov_len = siz;
1846 		if (imsg_composev(ibuf, type, 0, 0, -1, iov, 2) == -1)
1847 			return (-1);
1848 		off += siz;
1849 	}
1850 	return (0);
1851 }
1852 
1853 static void
1854 close_stdio(void)
1855 {
1856 	int	fd;
1857 
1858 	if ((fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
1859 		dup2(fd, STDIN_FILENO);
1860 		dup2(fd, STDOUT_FILENO);
1861 		dup2(fd, STDERR_FILENO);
1862 		if (fd > STDERR_FILENO)
1863 			close(fd);
1864 	}
1865 }
1866 
1867 /***********************************************************************
1868  * imsg_event
1869  ***********************************************************************/
1870 struct iovec;
1871 
1872 void
1873 imsg_event_add(struct imsgev *iev)
1874 {
1875 	iev->events = EV_READ;
1876 	if (iev->ibuf.w.queued)
1877 		iev->events |= EV_WRITE;
1878 
1879 	event_del(&iev->ev);
1880 	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
1881 	event_add(&iev->ev, NULL);
1882 }
1883 
1884 int
1885 imsg_compose_event(struct imsgev *iev, uint32_t type, uint32_t peerid,
1886     pid_t pid, int fd, void *data, size_t datalen)
1887 {
1888 	int	ret;
1889 
1890 	if ((ret = imsg_compose(&iev->ibuf, type, peerid,
1891 	    pid, fd, data, datalen)) != -1)
1892 		imsg_event_add(iev);
1893 	return (ret);
1894 }
1895 
1896 int
1897 imsg_composev_event(struct imsgev *iev, uint32_t type, uint32_t peerid,
1898     pid_t pid, int fd, struct iovec *iov, int niov)
1899 {
1900 	int	ret;
1901 
1902 	if ((ret = imsg_composev(&iev->ibuf, type, peerid,
1903 	    pid, fd, iov, niov)) != -1)
1904 		imsg_event_add(iev);
1905 	return (ret);
1906 }
1907