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