GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/radiusd/radiusd/../radiusd.c Lines: 0 750 0.0 %
Date: 2017-11-13 Branches: 0 439 0.0 %

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