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