GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/radiusd/radiusd_radius/../radiusd_radius.c Lines: 0 264 0.0 %
Date: 2017-11-07 Branches: 0 118 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: radiusd_radius.c,v 1.13 2017/05/30 16:30: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/queue.h>
21
#include <sys/socket.h>
22
#include <netinet/in.h>
23
24
#include <err.h>
25
#include <errno.h>
26
#include <event.h>
27
#include <fcntl.h>
28
#include <stdbool.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <syslog.h>
33
#include <unistd.h>
34
35
#include <radius.h>
36
37
#include "radiusd.h"
38
#include "radiusd_module.h"
39
#include "util.h"
40
#include "log.h"
41
42
struct radius_server {
43
	struct module_radius		*module;
44
	int				 sock;
45
	union {
46
		struct sockaddr_in6	 sin6;
47
		struct sockaddr_in	 sin4;
48
	}				 addr;
49
	union {
50
		struct sockaddr_in6	 sin6;
51
		struct sockaddr_in	 sin4;
52
	}				 local;
53
	struct event			 ev;
54
	u_char				 req_id_seq;
55
};
56
57
struct module_radius {
58
	struct module_base		*base;
59
	struct radius_server		 server[4];
60
	char				 secret[RADIUSD_SECRET_MAX];
61
	u_int				 nserver;
62
	u_int				 curr_server;
63
	u_int				 req_timeout;
64
	u_int				 max_tries;
65
	u_int				 max_failovers;
66
	u_int				 nfailover;
67
	TAILQ_HEAD(,module_radius_req)	 req;
68
};
69
70
struct module_radius_req {
71
	struct module_radius		*module;
72
	struct radius_server		*server;
73
	u_int				 q_id;
74
	RADIUS_PACKET			*q_pkt;
75
	u_int				 ntry;
76
	u_int				 nfailover;
77
	u_char				 req_id;
78
	struct event			 ev;
79
	TAILQ_ENTRY(module_radius_req)	 next;
80
};
81
82
static void	 module_radius_init(struct module_radius *);
83
static void	 module_radius_config_set(void *, const char *, int,
84
		    char * const *);
85
static void	 module_radius_start(void *);
86
static void	 module_radius_stop(void *);
87
static void	 module_radius_access_request(void *, u_int, const u_char *,
88
		    size_t);
89
static int	 radius_server_start(struct radius_server *);
90
static void	 radius_server_stop(struct radius_server *);
91
static void	 radius_server_on_event(int, short, void *);
92
static void	 radius_server_on_fail(struct radius_server *, const char *);
93
static void	 module_radius_req_send(struct module_radius_req *);
94
static int	 module_radius_req_reset_event(struct module_radius_req *);
95
static void	 module_radius_req_on_timeout(int, short, void *);
96
static void	 module_radius_req_on_success(struct module_radius_req *,
97
		    const u_char *, size_t);
98
static void	 module_radius_req_on_failure(struct module_radius_req *);
99
100
static void	 module_radius_req_free(struct module_radius_req *);
101
static void	 module_radius_req_select_server(struct module_radius_req *);
102
103
static void	 module_radius_req_reset_msgauth(struct module_radius_req *);
104
static void	 module_radius_log(struct module_radius *, int, const char *, ...);
105
106
static struct module_handlers module_radius_handlers = {
107
	.config_set = module_radius_config_set,
108
	.start = module_radius_start,
109
	.stop = module_radius_stop,
110
	.access_request = module_radius_access_request
111
};
112
113
#ifndef nitems
114
#define nitems(_x)    (sizeof((_x)) / sizeof((_x)[0]))
115
#endif
116
117
int
118
main(int argc, char *argv[])
119
{
120
	static struct module_radius module_radius;
121
122
	module_radius_init(&module_radius);
123
	openlog(NULL, LOG_PID, LOG_DAEMON);
124
125
	if ((module_radius.base = module_create(
126
	    STDIN_FILENO, &module_radius, &module_radius_handlers)) == NULL)
127
		err(1, "Could not create a module instance");
128
	module_drop_privilege(module_radius.base);
129
	setproctitle("[main]");
130
131
	module_load(module_radius.base);
132
	log_init(0);
133
	event_init();
134
135
	if (pledge("stdio inet flock rpath cpath wpath", NULL) == -1)
136
		err(EXIT_FAILURE, "pledge");
137
138
	module_start(module_radius.base);
139
	event_loop(0);
140
141
	exit(EXIT_SUCCESS);
142
}
143
144
static void
145
module_radius_init(struct module_radius *module)
146
{
147
	memset(module, 0, sizeof(struct module_radius));
148
	TAILQ_INIT(&module->req);
149
}
150
151
static void
152
module_radius_config_set(void *ctx, const char *paramname, int paramvalc,
153
    char * const * paramvalv)
154
{
155
	const char		*errmsg = NULL;
156
	struct addrinfo		*res;
157
	struct module_radius	*module = ctx;
158
159
	if (strcmp(paramname, "server") == 0) {
160
		SYNTAX_ASSERT(paramvalc == 1,
161
		    "`server' must have just one argument");
162
		SYNTAX_ASSERT(module->nserver < (int)nitems(module->server),
163
		    "number of server reached limit");
164
165
		if (addrport_parse(paramvalv[0], IPPROTO_UDP, &res) != 0)
166
			SYNTAX_ASSERT(0, "could not parse address and port");
167
		memcpy(&module->server[module->nserver].addr, res->ai_addr,
168
		    res->ai_addrlen);
169
170
		if (ntohs(module->server[module->nserver].addr.sin4.sin_port)
171
		    == 0)
172
			module->server[module->nserver].addr.sin4.sin_port
173
			    = htons(RADIUS_DEFAULT_PORT);
174
175
		module->server[module->nserver].sock = -1;
176
		module->nserver++;
177
		freeaddrinfo(res);
178
	} else if (strcmp(paramname, "request-timeout") == 0) {
179
		SYNTAX_ASSERT(paramvalc == 1,
180
		    "`request-timeout' must have just one argument");
181
		module->req_timeout = (int)strtonum(paramvalv[0], 0,
182
		    UINT16_MAX, &errmsg);
183
		if (module->req_timeout == 0 && errmsg != NULL) {
184
			module_send_message(module->base, IMSG_NG,
185
			    "`request-timeout must be 0-%d", UINT16_MAX);
186
			return;
187
		}
188
	} else if (strcmp(paramname, "max-tries") == 0) {
189
		SYNTAX_ASSERT(paramvalc == 1,
190
		    "`max-tries' must have just one argument");
191
		module->max_tries = (int)strtonum(paramvalv[0], 0,
192
		    UINT16_MAX, &errmsg);
193
		if (module->max_tries == 0 && errmsg != NULL) {
194
			module_send_message(module->base, IMSG_NG,
195
			    "`max-tries must be 0-%d", UINT16_MAX);
196
			return;
197
		}
198
199
	} else if (strcmp(paramname, "max-failovers") == 0) {
200
		SYNTAX_ASSERT(paramvalc == 1,
201
		    "`max-failovers' must have just one argument");
202
		module->max_failovers = (int)strtonum(paramvalv[0], 0,
203
		    UINT16_MAX, &errmsg);
204
		if (module->max_failovers == 0 && errmsg != NULL) {
205
			module_send_message(module->base, IMSG_NG,
206
			    "`max-failovers' must be 0-%d", UINT16_MAX);
207
			return;
208
		}
209
	} else if (strcmp(paramname, "secret") == 0) {
210
		SYNTAX_ASSERT(paramvalc == 1,
211
		    "`secret' must have just one argument");
212
		if (strlcpy(module->secret, paramvalv[0],
213
		    sizeof(module->secret)) >= sizeof(module->secret)) {
214
			module_send_message(module->base, IMSG_NG,
215
			    "`secret' length must be 0-%lu",
216
			    (u_long) sizeof(module->secret) - 1);
217
			return;
218
		}
219
	} else {
220
		module_send_message(module->base, IMSG_NG,
221
		    "Unknown config parameter name `%s'", paramname);
222
		return;
223
	}
224
	module_send_message(module->base, IMSG_OK, NULL);
225
226
	return;
227
syntax_error:
228
	module_send_message(module->base, IMSG_NG, "%s", errmsg);
229
}
230
231
static void
232
module_radius_start(void *ctx)
233
{
234
	u_int			 i;
235
	struct module_radius	*module = ctx;
236
237
	if (module->nserver <= 0) {
238
		module_send_message(module->base, IMSG_NG,
239
			"module `radius' needs one `server' at least");
240
		return;
241
	}
242
243
	for (i = 0; i < module->nserver; i++) {
244
		module->server[i].module = module;
245
		if (radius_server_start(&module->server[i]) != 0) {
246
			module_send_message(module->base, IMSG_NG,
247
				"module `radius' failed to start one of "
248
				"the servers");
249
			return;
250
		}
251
	}
252
	module_send_message(module->base, IMSG_OK, NULL);
253
254
	if (module->secret[0] != '\0')
255
		module_notify_secret(module->base, module->secret);
256
}
257
258
static void
259
module_radius_stop(void *ctx)
260
{
261
	u_int				 i;
262
	struct module_radius_req	*req, *treq;
263
	struct module_radius		*module = ctx;
264
265
	TAILQ_FOREACH_SAFE(req, &module->req, next, treq)
266
		module_radius_req_on_failure(req);
267
268
	for (i = 0; i < module->nserver; i++)
269
		radius_server_stop(&module->server[i]);
270
}
271
272
static void
273
module_radius_access_request(void *ctx, u_int q_id, const u_char *pkt,
274
    size_t pktlen)
275
{
276
	struct module_radius		*module = ctx;
277
	struct module_radius_req	*req;
278
	u_char				 attrbuf[256];
279
	ssize_t				 attrlen;
280
281
	req = calloc(1, sizeof(struct module_radius_req));
282
	if (req == NULL) {
283
		module_radius_log(module, LOG_WARNING,
284
		    "%s: Out of memory: %m", __func__);
285
		goto on_fail;
286
	}
287
288
	req->ntry = 0;
289
	req->module = module;
290
	req->q_id = q_id;
291
	if ((req->q_pkt = radius_convert_packet(pkt, pktlen)) == NULL) {
292
		module_radius_log(module, LOG_WARNING,
293
		    "%s: radius_convert_packet() failed: %m", __func__);
294
		goto on_fail;
295
	}
296
	evtimer_set(&req->ev, module_radius_req_on_timeout, req);
297
	TAILQ_INSERT_TAIL(&req->module->req, req, next);
298
299
	/*
300
	 * radiusd decrypt User-Password attribute.  crypt it again with our
301
	 * secret.
302
	 */
303
	attrlen = sizeof(attrbuf);
304
	if (module->secret[0] != '\0' &&
305
	    radius_get_raw_attr(req->q_pkt, RADIUS_TYPE_USER_PASSWORD,
306
		    attrbuf, &attrlen) == 0) {
307
		attrbuf[attrlen] = '\0';
308
		radius_del_attr_all(req->q_pkt, RADIUS_TYPE_USER_PASSWORD);
309
		radius_put_user_password_attr(req->q_pkt, attrbuf,
310
		    module->secret);
311
	}
312
313
	/* select current server */
314
	module_radius_req_select_server(req);
315
316
	module_radius_req_send(req);
317
318
	return;
319
320
on_fail:
321
	free(req);
322
	module_accsreq_aborted(module->base, q_id);
323
}
324
325
/*
326
 * radius_server
327
 */
328
static int
329
radius_server_start(struct radius_server *server)
330
{
331
	socklen_t	 locallen;
332
	char		 buf0[NI_MAXHOST + NI_MAXSERV + 32];
333
	char		 buf1[NI_MAXHOST + NI_MAXSERV + 32];
334
335
	if ((server->sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0))
336
	    < 0) {
337
		module_radius_log(server->module, LOG_WARNING,
338
		    "%s: socket() failed", __func__);
339
		goto on_error;
340
	}
341
	if (connect(server->sock, (struct sockaddr *)&server->addr,
342
		server->addr.sin4.sin_len) != 0) {
343
		module_radius_log(server->module, LOG_WARNING,
344
		    "%s: connect to %s failed", __func__,
345
		    addrport_tostring((struct sockaddr *)&server->addr,
346
			server->addr.sin4.sin_len, buf1, sizeof(buf1)));
347
		goto on_error;
348
	}
349
	locallen = sizeof(server->local);
350
	if (getsockname(server->sock, (struct sockaddr *)&server->local,
351
	    &locallen) != 0) {
352
		module_radius_log(server->module, LOG_WARNING,
353
		    "%s: getsockanme() failed", __func__);
354
		goto on_error;
355
	}
356
	module_radius_log(server->module, LOG_INFO,
357
	    "Use %s to send requests for %s",
358
	    addrport_tostring((struct sockaddr *)&server->local,
359
		    locallen, buf0, sizeof(buf0)),
360
	    addrport_tostring((struct sockaddr *)&server->addr,
361
		    server->addr.sin4.sin_len, buf1, sizeof(buf1)));
362
363
	event_set(&server->ev, server->sock, EV_READ | EV_PERSIST,
364
	    radius_server_on_event, server);
365
	if (event_add(&server->ev, NULL)) {
366
		module_radius_log(server->module, LOG_WARNING,
367
		    "%s: event_add() failed", __func__);
368
		goto on_error;
369
	}
370
371
	return (0);
372
on_error:
373
	if (server->sock >= 0)
374
		close(server->sock);
375
	server->sock = -1;
376
	return (-1);
377
}
378
379
static void
380
radius_server_stop(struct radius_server *server)
381
{
382
	event_del(&server->ev);
383
	if (server->sock >= 0)
384
		close(server->sock);
385
	server->sock = -1;
386
}
387
388
static void
389
radius_server_on_event(int fd, short evmask, void *ctx)
390
{
391
	int				 sz, res_id;
392
	u_char				 pkt[65535];
393
	char				 buf[NI_MAXHOST + NI_MAXSERV + 32];
394
	struct radius_server		*server = ctx;
395
	RADIUS_PACKET			*radpkt = NULL;
396
	struct module_radius_req	*req;
397
	struct sockaddr			*peer;
398
399
	peer = (struct sockaddr *)&server->addr;
400
	if ((sz = recv(server->sock, pkt, sizeof(pkt), 0)) == -1) {
401
		if (errno == EAGAIN)
402
			return;
403
		module_radius_log(server->module, LOG_WARNING,
404
		    "server=%s recv() failed: %m",
405
		    addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)));
406
		return;
407
	}
408
	if ((radpkt = radius_convert_packet(pkt, sz)) == NULL) {
409
		module_radius_log(server->module, LOG_WARNING,
410
		    "server=%s could not convert the received message to a "
411
		    "RADIUS packet object: %m",
412
		    addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)));
413
		return;
414
	}
415
	res_id = radius_get_id(radpkt);
416
	TAILQ_FOREACH(req, &server->module->req, next) {
417
		if (req->server == server && req->req_id == res_id)
418
			break;
419
	}
420
	if (req == NULL) {
421
		module_radius_log(server->module, LOG_WARNING,
422
		    "server=%s Received radius message has unknown id=%d",
423
		    addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)),
424
		    res_id);
425
		goto out;
426
	}
427
	radius_set_request_packet(radpkt, req->q_pkt);
428
429
	if (server->module->secret[0] != '\0') {
430
		if (radius_check_response_authenticator(radpkt,
431
		    server->module->secret) != 0) {
432
			module_radius_log(server->module, LOG_WARNING,
433
			    "server=%s Received radius message(id=%d) has bad "
434
			    "authenticator",
435
			    addrport_tostring(peer, peer->sa_len, buf,
436
			    sizeof(buf)), res_id);
437
			goto out;
438
		}
439
		if (radius_has_attr(radpkt,
440
		    RADIUS_TYPE_MESSAGE_AUTHENTICATOR) &&
441
		    radius_check_message_authenticator(radpkt,
442
			    server->module->secret) != 0) {
443
			module_radius_log(server->module, LOG_WARNING,
444
			    "server=%s Received radius message(id=%d) has bad "
445
			    "message authenticator",
446
			    addrport_tostring(peer, peer->sa_len, buf,
447
			    sizeof(buf)), res_id);
448
			goto out;
449
		}
450
	}
451
452
	module_radius_log(server->module, LOG_INFO,
453
	    "q=%u received a response from server %s", req->q_id,
454
	    addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)));
455
456
	module_radius_req_on_success(req, radius_get_data(radpkt),
457
	    radius_get_length(radpkt));
458
out:
459
	if (radpkt != NULL)
460
		radius_delete_packet(radpkt);
461
}
462
463
static void
464
radius_server_on_fail(struct radius_server *server, const char *failmsg)
465
{
466
	char		 buf0[NI_MAXHOST + NI_MAXSERV + 32];
467
	char		 buf1[NI_MAXHOST + NI_MAXSERV + 32];
468
	struct sockaddr	*caddr, *naddr;
469
470
	caddr = (struct sockaddr *)&server->addr;
471
	if (server->module->nserver <= 1) {
472
		module_radius_log(server->module, LOG_WARNING,
473
		    "Server %s failed: %s",
474
		    addrport_tostring(caddr, caddr->sa_len, buf0, sizeof(buf0)),
475
		    failmsg);
476
		return;
477
	}
478
	server->module->curr_server++;
479
	server->module->curr_server %= server->module->nserver;
480
	naddr = (struct sockaddr *)
481
	    &server->module->server[server->module->curr_server].addr;
482
483
	module_radius_log(server->module, LOG_WARNING,
484
	    "Server %s failed: %s  Fail over to %s",
485
	    addrport_tostring(caddr, caddr->sa_len, buf0, sizeof(buf0)),
486
	    failmsg,
487
	    addrport_tostring(naddr, naddr->sa_len, buf1, sizeof(buf1)));
488
}
489
490
/* module_radius_req */
491
492
static void
493
module_radius_req_send(struct module_radius_req *req)
494
{
495
	int		 sz;
496
	struct sockaddr	*peer;
497
	char		 msg[BUFSIZ];
498
499
	peer = (struct sockaddr *)&req->server->addr;
500
	if ((sz = send(req->server->sock, radius_get_data(req->q_pkt),
501
	    radius_get_length(req->q_pkt), 0)) < 0) {
502
		module_radius_log(req->module, LOG_WARNING,
503
		    "Sending RADIUS query q=%u to %s failed: %m",
504
		    req->q_id,
505
		    addrport_tostring(peer, peer->sa_len, msg, sizeof(msg)));
506
		/* retry anyway */
507
	}
508
	module_radius_log(req->module, LOG_INFO,
509
	    "Send RADIUS query q=%u id=%d to %s successfully",
510
	    req->q_id, req->req_id,
511
	    addrport_tostring(peer, peer->sa_len, msg, sizeof(msg)));
512
	if (module_radius_req_reset_event(req) != -1)
513
		req->ntry++;
514
}
515
516
static int
517
module_radius_req_reset_event(struct module_radius_req *req)
518
{
519
	struct timeval	 tv;
520
	static int	 timeouts[] = { 2, 4, 8 };
521
522
	tv.tv_usec = 0;
523
	if (req->module->req_timeout != 0)
524
		tv.tv_sec = req->module->req_timeout;
525
	else {
526
		if (req->ntry < nitems(timeouts))
527
			tv.tv_sec = timeouts[req->ntry];
528
		else
529
			tv.tv_sec = timeouts[nitems(timeouts) - 1];
530
	}
531
	if (evtimer_add(&req->ev, &tv) != 0) {
532
		module_radius_log(req->module, LOG_WARNING,
533
		    "Cannot proccess the request for q=%u: "
534
		    "evtimer_add() failed: %m", req->q_id);
535
		module_radius_req_on_failure(req);
536
		return (-1);
537
	}
538
	return (0);
539
}
540
541
static void
542
module_radius_req_on_timeout(int fd, short evmask, void *ctx)
543
{
544
	struct module_radius_req	*req = ctx;
545
	char				 msg[BUFSIZ];
546
547
548
	if (req->module->max_tries <= req->ntry) {
549
		snprintf(msg, sizeof(msg), "q=%u didn't response RADIUS query "
550
		    "%d time%s", req->q_id, req->ntry,
551
		    (req->ntry > 0)? "s" : "");
552
		radius_server_on_fail(req->server, msg);
553
		if (++req->nfailover >= req->module->max_failovers) {
554
			module_radius_log(req->module,
555
			    LOG_WARNING, "RADIUS query q=%u time out",
556
			    req->q_id);
557
			module_radius_req_on_failure(req);
558
			return;
559
		}
560
		/* select the next server */
561
		module_radius_req_select_server(req);
562
	}
563
	module_radius_req_send(req);
564
}
565
566
static void
567
module_radius_req_on_success(struct module_radius_req *req,
568
    const u_char *pkt, size_t pktlen)
569
{
570
	module_accsreq_answer(req->module->base, req->q_id, 1, pkt, pktlen);
571
	module_radius_req_free(req);
572
}
573
574
static void
575
module_radius_req_on_failure(struct module_radius_req *req)
576
{
577
	module_accsreq_aborted(req->module->base, req->q_id);
578
	module_radius_req_free(req);
579
}
580
581
582
static void
583
module_radius_req_free(struct module_radius_req *req)
584
{
585
	evtimer_del(&req->ev);
586
	TAILQ_REMOVE(&req->module->req, req, next);
587
	if (req->q_pkt != NULL)
588
		radius_delete_packet(req->q_pkt);
589
	free(req);
590
}
591
592
static void
593
module_radius_req_select_server(struct module_radius_req *req)
594
{
595
	req->server = &req->module->server[req->module->curr_server];
596
	req->ntry = 0;
597
	req->req_id = req->server->req_id_seq++;
598
	radius_set_id(req->q_pkt, req->req_id);
599
	module_radius_req_reset_msgauth(req);
600
}
601
602
static void
603
module_radius_req_reset_msgauth(struct module_radius_req *req)
604
{
605
	if (radius_has_attr(req->q_pkt, RADIUS_TYPE_MESSAGE_AUTHENTICATOR))
606
		radius_del_attr_all(req->q_pkt,
607
		    RADIUS_TYPE_MESSAGE_AUTHENTICATOR);
608
	if (req->module->secret[0] != '\0')
609
		radius_put_message_authenticator(req->q_pkt,
610
		    req->module->secret);
611
}
612
613
static void
614
module_radius_log(struct module_radius *module, int pri, const char *fmt, ...)
615
{
616
	char		fmt0[BUFSIZ];
617
	va_list		va;
618
619
	snprintf(fmt0, sizeof(fmt0), "radius: %s", fmt);
620
	va_start(va, fmt);
621
	vlog(pri, fmt0, va);
622
	va_end(va);
623
}