xref: /openbsd-src/usr.sbin/radiusd/radiusd.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /*	$OpenBSD: radiusd.c,v 1.22 2018/10/09 03:35:44 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-Client" },
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 	if (module->secret != NULL) {
1070 		freezero(module->secret, strlen(module->secret));
1071 		module->secret = NULL;
1072 	}
1073 
1074 	if (module->fd >= 0) {
1075 		imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_STOP, 0, 0, -1,
1076 		    NULL, 0);
1077 		radiusd_module_reset_ev_handler(module);
1078 	}
1079 }
1080 
1081 static void
1082 radiusd_module_close(struct radiusd_module *module)
1083 {
1084 	if (module->fd >= 0) {
1085 		event_del(&module->ev);
1086 		imsg_clear(&module->ibuf);
1087 		close(module->fd);
1088 		module->fd = -1;
1089 	}
1090 }
1091 
1092 void
1093 radiusd_module_unload(struct radiusd_module *module)
1094 {
1095 	free(module->radpkt);
1096 	radiusd_module_close(module);
1097 	free(module);
1098 }
1099 
1100 static void
1101 radiusd_module_on_imsg_io(int fd, short evmask, void *ctx)
1102 {
1103 	struct radiusd_module	*module = ctx;
1104 	int			 ret;
1105 
1106 	if (evmask & EV_WRITE)
1107 		module->writeready = true;
1108 
1109 	if (evmask & EV_READ || module->ibuf.r.wpos > IMSG_HEADER_SIZE) {
1110 		if (radiusd_module_imsg_read(module,
1111 		    (evmask & EV_READ)? true : false) == -1)
1112 			goto on_error;
1113 	}
1114 
1115 	while (module->writeready && module->ibuf.w.queued) {
1116 		ret = msgbuf_write(&module->ibuf.w);
1117 		if (ret > 0)
1118 			continue;
1119 		module->writeready = false;
1120 		if (ret == 0 && errno == EAGAIN)
1121 			break;
1122 		log_warn("Failed to write to module `%s': msgbuf_write()",
1123 		    module->name);
1124 		goto on_error;
1125 	}
1126 	radiusd_module_reset_ev_handler(module);
1127 
1128 	return;
1129 on_error:
1130 	radiusd_module_close(module);
1131 }
1132 
1133 static void
1134 radiusd_module_reset_ev_handler(struct radiusd_module *module)
1135 {
1136 	short		 evmask;
1137 	struct timeval	*tvp = NULL, tv = { 0, 0 };
1138 
1139 	RADIUSD_ASSERT(module->fd >= 0);
1140 	event_del(&module->ev);
1141 
1142 	evmask = EV_READ;
1143 	if (module->ibuf.w.queued) {
1144 		if (!module->writeready)
1145 			evmask |= EV_WRITE;
1146 		else
1147 			tvp = &tv;	/* fire immediately */
1148 	} else if (module->ibuf.r.wpos > IMSG_HEADER_SIZE)
1149 		tvp = &tv;		/* fire immediately */
1150 
1151 	/* module stopped and no event handler is set */
1152 	if (evmask & EV_WRITE && tvp == NULL && module->stopped) {
1153 		/* stop requested and no more to write */
1154 		radiusd_module_close(module);
1155 		return;
1156 	}
1157 
1158 	event_set(&module->ev, module->fd, evmask, radiusd_module_on_imsg_io,
1159 	    module);
1160 	if (event_add(&module->ev, tvp) == -1) {
1161 		log_warn("Could not set event handlers for module `%s': "
1162 		    "event_add()", module->name);
1163 		radiusd_module_close(module);
1164 	}
1165 }
1166 
1167 static int
1168 radiusd_module_imsg_read(struct radiusd_module *module, bool doread)
1169 {
1170 	int		 n;
1171 	struct imsg	 imsg;
1172 
1173 	if (doread) {
1174 		if ((n = imsg_read(&module->ibuf)) == -1 || n == 0) {
1175 			if (n == -1 && errno == EAGAIN)
1176 				return (0);
1177 			if (n == -1)
1178 				log_warn("Receiving a message from module `%s' "
1179 				    "failed: imsg_read", module->name);
1180 			/* else closed */
1181 			radiusd_module_close(module);
1182 			return (-1);
1183 		}
1184 	}
1185 	for (;;) {
1186 		if ((n = imsg_get(&module->ibuf, &imsg)) == -1) {
1187 			log_warn("Receiving a message from module `%s' failed: "
1188 			    "imsg_get", module->name);
1189 			return (-1);
1190 		}
1191 		if (n == 0)
1192 			return (0);
1193 		radiusd_module_imsg(module, &imsg);
1194 	}
1195 
1196 	return (0);
1197 }
1198 
1199 static void
1200 radiusd_module_imsg(struct radiusd_module *module, struct imsg *imsg)
1201 {
1202 	int			 datalen;
1203 	struct radius_query	*q;
1204 	u_int			 q_id;
1205 
1206 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1207 	switch (imsg->hdr.type) {
1208 	case IMSG_RADIUSD_MODULE_NOTIFY_SECRET:
1209 		if (datalen > 0) {
1210 			module->secret = strdup(imsg->data);
1211 			if (module->secret == NULL)
1212 				log_warn("Could not handle NOTIFY_SECRET "
1213 				    "from `%s'", module->name);
1214 		}
1215 		break;
1216 	case IMSG_RADIUSD_MODULE_USERPASS_OK:
1217 	case IMSG_RADIUSD_MODULE_USERPASS_FAIL:
1218 	    {
1219 		char			*msg = NULL;
1220 		const char		*msgtypestr;
1221 
1222 		msgtypestr = (imsg->hdr.type == IMSG_RADIUSD_MODULE_USERPASS_OK)
1223 		    ? "USERPASS_OK" : "USERPASS_NG";
1224 
1225 		q_id = *(u_int *)imsg->data;
1226 		if (datalen > (ssize_t)sizeof(u_int))
1227 			msg = (char *)(((u_int *)imsg->data) + 1);
1228 
1229 		q = radiusd_find_query(module->radiusd, q_id);
1230 		if (q == NULL) {
1231 			log_warnx("Received %s from `%s', but query id=%u "
1232 			    "unknown", msgtypestr, module->name, q_id);
1233 			break;
1234 		}
1235 
1236 		if ((q->res = radius_new_response_packet(
1237 		    (imsg->hdr.type == IMSG_RADIUSD_MODULE_USERPASS_OK)
1238 		    ? RADIUS_CODE_ACCESS_ACCEPT : RADIUS_CODE_ACCESS_REJECT,
1239 		    q->req)) == NULL) {
1240 			log_warn("radius_new_response_packet() failed");
1241 			radiusd_access_request_aborted(q);
1242 		} else {
1243 			if (msg)
1244 				radius_put_string_attr(q->res,
1245 				    RADIUS_TYPE_REPLY_MESSAGE, msg);
1246 			radius_set_response_authenticator(q->res,
1247 			    q->client->secret);
1248 			radiusd_access_request_answer(q);
1249 		}
1250 		break;
1251 	    }
1252 	case IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER:
1253 	    {
1254 		static struct radiusd_module_radpkt_arg *ans;
1255 		if (datalen <
1256 		    (ssize_t)sizeof(struct radiusd_module_radpkt_arg)) {
1257 			log_warnx("Received ACCSREQ_ANSWER message, but "
1258 			    "length is wrong");
1259 			break;
1260 		}
1261 		q_id = ((struct radiusd_module_radpkt_arg *)imsg->data)->q_id;
1262 		q = radiusd_find_query(module->radiusd, q_id);
1263 		if (q == NULL) {
1264 			log_warnx("Received ACCSREQ_ANSWER from %s, but query "
1265 			    "id=%u unknown", module->name, q_id);
1266 			break;
1267 		}
1268 		if ((ans = radiusd_module_recv_radpkt(module, imsg,
1269 		    IMSG_RADIUSD_MODULE_ACCSREQ_ANSWER,
1270 		    "ACCSREQ_ANSWER")) != NULL) {
1271 			q->res = radius_convert_packet(
1272 			    module->radpkt, module->radpktoff);
1273 			q->res_modified = ans->modified;
1274 			radiusd_access_request_answer(q);
1275 			module->radpktoff = 0;
1276 		}
1277 		break;
1278 	    }
1279 	case IMSG_RADIUSD_MODULE_ACCSREQ_ABORTED:
1280 	    {
1281 		q_id = *((u_int *)imsg->data);
1282 		q = radiusd_find_query(module->radiusd, q_id);
1283 		if (q == NULL) {
1284 			log_warnx("Received ACCSREQ_ABORT from %s, but query "
1285 			    "id=%u unknown", module->name, q_id);
1286 			break;
1287 		}
1288 		radiusd_access_request_aborted(q);
1289 		break;
1290 	    }
1291 	default:
1292 		RADIUSD_DBG(("Unhandled imsg type=%d",
1293 		    imsg->hdr.type));
1294 	}
1295 }
1296 
1297 static struct radiusd_module_radpkt_arg *
1298 radiusd_module_recv_radpkt(struct radiusd_module *module, struct imsg *imsg,
1299     uint32_t imsg_type, const char *type_str)
1300 {
1301 	struct radiusd_module_radpkt_arg	*ans;
1302 	int					 datalen, chunklen;
1303 
1304 	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
1305 	ans = (struct radiusd_module_radpkt_arg *)imsg->data;
1306 	if (module->radpktsiz < ans->datalen) {
1307 		u_char *nradpkt;
1308 		if ((nradpkt = realloc(module->radpkt, ans->datalen)) == NULL) {
1309 			log_warn("Could not handle received %s message from "
1310 			    "`%s'", type_str, module->name);
1311 			goto on_fail;
1312 		}
1313 		module->radpkt = nradpkt;
1314 		module->radpktsiz = ans->datalen;
1315 	}
1316 	chunklen = datalen - sizeof(struct radiusd_module_radpkt_arg);
1317 	if (chunklen > module->radpktsiz - module->radpktoff) {
1318 		log_warnx("Could not handle received %s message from `%s': "
1319 		    "received length is too big", type_str, module->name);
1320 		goto on_fail;
1321 	}
1322 	memcpy(module->radpkt + module->radpktoff,
1323 	    (caddr_t)(ans + 1), chunklen);
1324 	module->radpktoff += chunklen;
1325 	if (!ans->final)
1326 		return (NULL);	/* again */
1327 	if (module->radpktoff != module->radpktsiz) {
1328 		log_warnx("Could not handle received %s message from `%s': "
1329 		    "length is mismatch", type_str, module->name);
1330 		goto on_fail;
1331 	}
1332 
1333 	return (ans);
1334 on_fail:
1335 	module->radpktoff = 0;
1336 	return (NULL);
1337 }
1338 
1339 int
1340 radiusd_module_set(struct radiusd_module *module, const char *name,
1341     int argc, char * const * argv)
1342 {
1343 	struct radiusd_module_set_arg	 arg;
1344 	struct radiusd_module_object	*val;
1345 	int				 i, niov = 0;
1346 	u_char				*buf = NULL, *buf0;
1347 	ssize_t				 n;
1348 	size_t				 bufsiz = 0, bufoff = 0, bufsiz0;
1349 	size_t				 vallen, valsiz;
1350 	struct iovec			 iov[2];
1351 	struct imsg			 imsg;
1352 
1353 	memset(&arg, 0, sizeof(arg));
1354 	arg.nparamval = argc;
1355 	strlcpy(arg.paramname, name, sizeof(arg.paramname));
1356 
1357 	iov[niov].iov_base = &arg;
1358 	iov[niov].iov_len = sizeof(struct radiusd_module_set_arg);
1359 	niov++;
1360 
1361 	for (i = 0; i < argc; i++) {
1362 		vallen = strlen(argv[i]) + 1;
1363 		valsiz = sizeof(struct radiusd_module_object) + vallen;
1364 		if (bufsiz < bufoff + valsiz) {
1365 			bufsiz0 = bufoff + valsiz + 128;
1366 			if ((buf0 = realloc(buf, bufsiz0)) == NULL) {
1367 				log_warn("Failed to set config parameter to "
1368 				    "module `%s': realloc", module->name);
1369 				goto on_error;
1370 			}
1371 			buf = buf0;
1372 			bufsiz = bufsiz0;
1373 			memset(buf + bufoff, 0, bufsiz - bufoff);
1374 		}
1375 		val = (struct radiusd_module_object *)(buf + bufoff);
1376 		val->size = valsiz;
1377 		memcpy(val + 1, argv[i], vallen);
1378 
1379 		bufoff += valsiz;
1380 	}
1381 	iov[niov].iov_base = buf;
1382 	iov[niov].iov_len = bufoff;
1383 	niov++;
1384 
1385 	if (imsg_composev(&module->ibuf, IMSG_RADIUSD_MODULE_SET_CONFIG, 0, 0,
1386 	    -1, iov, niov) == -1) {
1387 		log_warn("Failed to set config parameter to module `%s': "
1388 		    "imsg_composev", module->name);
1389 		goto on_error;
1390 	}
1391 	if (imsg_sync_flush(&module->ibuf, MODULE_IO_TIMEOUT) == -1) {
1392 		log_warn("Failed to set config parameter to module `%s': "
1393 		    "imsg_flush_timeout", module->name);
1394 		goto on_error;
1395 	}
1396 	for (;;) {
1397 		if (imsg_sync_read(&module->ibuf, MODULE_IO_TIMEOUT) <= 0) {
1398 			log_warn("Failed to get reply from module `%s': "
1399 			    "imsg_sync_read", module->name);
1400 			goto on_error;
1401 		}
1402 		if ((n = imsg_get(&module->ibuf, &imsg)) > 0)
1403 			break;
1404 		if (n < 0) {
1405 			log_warn("Failed to get reply from module `%s': "
1406 			    "imsg_get", module->name);
1407 			goto on_error;
1408 		}
1409 	}
1410 	if (imsg.hdr.type == IMSG_NG) {
1411 		log_warnx("Could not set `%s' for module `%s': %s", name,
1412 		    module->name, (char *)imsg.data);
1413 		goto on_error;
1414 	} else if (imsg.hdr.type != IMSG_OK) {
1415 		imsg_free(&imsg);
1416 		log_warnx("Failed to get reply from module `%s': "
1417 		    "unknown imsg type=%d", module->name, imsg.hdr.type);
1418 		goto on_error;
1419 	}
1420 	imsg_free(&imsg);
1421 
1422 	free(buf);
1423 	return (0);
1424 
1425 on_error:
1426 	free(buf);
1427 	return (-1);
1428 }
1429 
1430 static void
1431 radiusd_module_userpass(struct radiusd_module *module, struct radius_query *q)
1432 {
1433 	struct radiusd_module_userpass_arg userpass;
1434 
1435 	memset(&userpass, 0, sizeof(userpass));
1436 	userpass.q_id = q->id;
1437 
1438 	if (radius_get_user_password_attr(q->req, userpass.pass,
1439 	    sizeof(userpass.pass), q->client->secret) == 0)
1440 		userpass.has_pass = true;
1441 	else
1442 		userpass.has_pass = false;
1443 
1444 	if (strlcpy(userpass.user, q->username, sizeof(userpass.user))
1445 	    >= sizeof(userpass.user)) {
1446 		log_warnx("Could request USERPASS to module `%s': "
1447 		    "User-Name too long", module->name);
1448 		goto on_error;
1449 	}
1450 	imsg_compose(&module->ibuf, IMSG_RADIUSD_MODULE_USERPASS, 0, 0, -1,
1451 	    &userpass, sizeof(userpass));
1452 	radiusd_module_reset_ev_handler(module);
1453 	return;
1454 on_error:
1455 	radiusd_access_request_aborted(q);
1456 }
1457 
1458 static void
1459 radiusd_module_access_request(struct radiusd_module *module,
1460     struct radius_query *q)
1461 {
1462 	struct radiusd_module_radpkt_arg	 accsreq;
1463 	struct iovec				 iov[2];
1464 	int					 off = 0, len, siz;
1465 	const u_char				*pkt;
1466 	RADIUS_PACKET				*radpkt;
1467 	char					 pass[256];
1468 
1469 	if ((radpkt = radius_convert_packet(radius_get_data(q->req),
1470 	    radius_get_length(q->req))) == NULL) {
1471 		log_warn("Could not send ACCSREQ for `%s'", module->name);
1472 		return;
1473 	}
1474 	if (q->client->secret[0] != '\0' && module->secret != NULL &&
1475 	    radius_get_user_password_attr(radpkt, pass, sizeof(pass),
1476 		    q->client->secret) == 0) {
1477 		radius_del_attr_all(radpkt, RADIUS_TYPE_USER_PASSWORD);
1478 		(void)radius_put_raw_attr(radpkt, RADIUS_TYPE_USER_PASSWORD,
1479 		    pass, strlen(pass));
1480 	}
1481 
1482 	pkt = radius_get_data(radpkt);
1483 	len = radius_get_length(radpkt);
1484 	memset(&accsreq, 0, sizeof(accsreq));
1485 	accsreq.q_id = q->id;
1486 	while (off < len) {
1487 		siz = MAX_IMSGSIZE - sizeof(accsreq);
1488 		if (len - off > siz) {
1489 			accsreq.final = false;
1490 			accsreq.datalen = siz;
1491 		} else {
1492 			accsreq.final = true;
1493 			accsreq.datalen = len - off;
1494 		}
1495 		iov[0].iov_base = &accsreq;
1496 		iov[0].iov_len = sizeof(accsreq);
1497 		iov[1].iov_base = (caddr_t)pkt + off;
1498 		iov[1].iov_len = accsreq.datalen;
1499 		imsg_composev(&module->ibuf, IMSG_RADIUSD_MODULE_ACCSREQ, 0, 0,
1500 		    -1, iov, 2);
1501 		off += accsreq.datalen;
1502 	}
1503 	radiusd_module_reset_ev_handler(module);
1504 	radius_delete_packet(radpkt);
1505 
1506 	return;
1507 }
1508