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