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