radiusd_ipcp.c revision 1.1
1/*	$OpenBSD: radiusd_ipcp.c,v 1.1 2024/07/09 17:26:14 yasuoka Exp $	*/
2
3/*
4 * Copyright (c) 2024 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 <sys/time.h>
23#include <sys/tree.h>
24#include <arpa/inet.h>
25
26#include <inttypes.h>
27#include <netdb.h>
28#include <db.h>
29#include <err.h>
30#include <errno.h>
31#include <event.h>
32#include <fcntl.h>
33#include <pwd.h>
34#include <radius.h>
35#include <stdbool.h>
36#include <stddef.h>
37#include <stdint.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <time.h>
42#include <unistd.h>
43#include <imsg.h>
44
45#include "radiusd.h"
46#include "radiusd_module.h"
47#include "radiusd_ipcp.h"
48#include "log.h"
49
50#define RADIUSD_IPCP_START_WAIT	60
51
52enum ipcp_address_type {
53	ADDRESS_TYPE_POOL,
54	ADDRESS_TYPE_STATIC
55};
56
57struct ipcp_address {
58	enum ipcp_address_type		 type;
59	struct in_addr			 start;
60	struct in_addr			 end;
61	int				 naddrs;
62	TAILQ_ENTRY(ipcp_address)	 next;
63};
64
65struct user {
66	TAILQ_HEAD(, assigned_ipv4)	 ipv4s;
67	RB_ENTRY(user)			 tree;
68	char				 name[0];
69};
70
71struct module_ipcp_dae;
72
73struct assigned_ipv4 {
74	struct in_addr			 ipv4;
75	unsigned			 seq;
76	char				 session_id[256];
77	char				 auth_method[16];
78	struct user			*user;
79	uint32_t			 session_timeout;
80	struct timespec			 start;
81	struct timespec			 timeout;
82	struct in_addr			 nas_ipv4;
83	struct in6_addr			 nas_ipv6;
84	char				 nas_id[256];
85	const char			*tun_type;
86	union {
87		struct sockaddr_in	 sin4;
88		struct sockaddr_in6	 sin6;
89	}				 tun_client;
90
91	struct timespec			 authtime;
92	RB_ENTRY(assigned_ipv4)		 tree;
93	TAILQ_ENTRY(assigned_ipv4)	 next;
94
95	/* RFC 5176 Dynamic Authorization Extensions for RADIUS */
96	struct module_ipcp_dae		*dae;
97	RADIUS_PACKET			*dae_reqpkt;
98	TAILQ_ENTRY(assigned_ipv4)	 dae_next;
99	int				 dae_ntry;
100	struct event			 dae_evtimer;
101};
102
103struct module_ipcp_ctrlconn {
104	uint32_t			 peerid;
105	TAILQ_ENTRY(module_ipcp_ctrlconn)
106					 next;
107};
108
109struct module_ipcp_dae {
110	struct module_ipcp		*ipcp;
111	int				 sock;
112	char				 nas_id[256];
113	char				 secret[80];
114	union {
115		struct sockaddr_in	 sin4;
116		struct sockaddr_in6	 sin6;
117	}				 nas_addr;
118	struct event			 ev_sock;
119	TAILQ_ENTRY(module_ipcp_dae)	 next;
120	TAILQ_HEAD(, assigned_ipv4)	 reqs;
121};
122
123struct module_ipcp {
124	struct module_base		*base;
125	int				 nsessions;
126	unsigned			 seq;
127	int				 max_sessions;
128	int				 user_max_sessions;
129	int				 start_wait;
130	int				 session_timeout;
131	bool				 no_session_timeout;
132	struct timespec			 uptime;
133	struct in_addr			 name_server[2];
134	struct in_addr			 netbios_server[2];
135	RB_HEAD(assigned_ipv4_tree, assigned_ipv4)
136					 ipv4s;
137	RB_HEAD(user_tree, user)	 users;
138	int				 npools;
139	TAILQ_HEAD(,ipcp_address)	 addrs;
140	TAILQ_HEAD(,module_ipcp_ctrlconn)
141					 ctrls;
142	TAILQ_HEAD(,module_ipcp_dae)	 daes;
143	struct event			 ev_timer;
144};
145
146#ifndef nitems
147#define nitems(_x)    (sizeof((_x)) / sizeof((_x)[0]))
148#endif
149
150#ifndef MAXIMUM
151#define MAXIMUM(_a, _b)	(((_a) > (_b))? (_a) : (_b))
152#endif
153
154static void	 ipcp_init(struct module_ipcp *);
155static void	 ipcp_start(void *);
156static void	 ipcp_stop(void *);
157static void	 ipcp_fini(struct module_ipcp *);
158static void	 ipcp_config_set(void *, const char *, int, char * const *);
159static void	 ipcp_dispatch_control(void *, struct imsg *);
160static int	 ipcp_notice_startstop(struct module_ipcp *,
161		    struct assigned_ipv4 *, int,
162		    struct radiusd_ipcp_statistics *);
163static void	 ipcp_resdeco(void *, u_int, const u_char *, size_t reqlen,
164		    const u_char *, size_t reslen);
165static void	 ipcp_reject(struct module_ipcp *, RADIUS_PACKET *,
166		    unsigned int, RADIUS_PACKET *, int);
167static void	 ipcp_accounting_request(void *, u_int, const u_char *,
168		    size_t);
169
170struct assigned_ipv4
171		*ipcp_ipv4_assign(struct module_ipcp *, struct user *,
172		    struct in_addr);
173static struct assigned_ipv4
174		*ipcp_ipv4_find(struct module_ipcp *, struct in_addr);
175static void	 ipcp_ipv4_release(struct module_ipcp *,
176		    struct assigned_ipv4 *);
177static int	 assigned_ipv4_compar(struct assigned_ipv4 *,
178		    struct assigned_ipv4 *);
179static struct user
180		*ipcp_user_get(struct module_ipcp *, const char *);
181static int	 user_compar(struct user *, struct user *);
182static int	 ipcp_prepare_db(void);
183static int	 ipcp_restore_from_db(struct module_ipcp *);
184static void	 ipcp_put_db(struct module_ipcp *, struct assigned_ipv4 *);
185static void	 ipcp_del_db(struct module_ipcp *, struct assigned_ipv4 *);
186static void	 ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *, int,
187		    struct assigned_ipv4 *);
188static void	 ipcp_on_timer(int, short, void *);
189static void	 ipcp_schedule_timer(struct module_ipcp *);
190static void	 ipcp_dae_send_disconnect_request(struct assigned_ipv4 *);
191static void	 ipcp_dae_request_on_timeout(int, short, void *);
192static void	 ipcp_dae_on_event(int, short, void *);
193static struct ipcp_address
194		*parse_address_range(const char *);
195static const char
196		*radius_tunnel_type_string(unsigned, const char *);
197static const char
198		*radius_terminate_cause_string(unsigned);
199static const char
200		*radius_error_cause_string(unsigned);
201static int	 parse_addr(const char *, int, struct sockaddr *, socklen_t);
202static const char
203		*print_addr(struct sockaddr *, char *, size_t);
204
205RB_PROTOTYPE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree,
206    assigned_ipv4_compar);
207RB_PROTOTYPE_STATIC(user_tree, user, tree, user_compar);
208
209int
210main(int argc, char *argv[])
211{
212	struct module_ipcp	 module_ipcp;
213	struct module_handlers	 handlers = {
214		.start =		ipcp_start,
215		.stop =			ipcp_stop,
216		.config_set =		ipcp_config_set,
217		.response_decoration =	ipcp_resdeco,
218		.accounting_request =	ipcp_accounting_request,
219		.dispatch_control =	ipcp_dispatch_control
220	};
221
222	ipcp_init(&module_ipcp);
223
224	if ((module_ipcp.base = module_create(STDIN_FILENO, &module_ipcp,
225	    &handlers)) == NULL)
226		err(1, "Could not create a module instance");
227
228	if (ipcp_prepare_db() == -1)
229		err(1, "ipcp_prepare_db");
230
231	module_drop_privilege(module_ipcp.base, 1);
232	if (unveil(_PATH_RADIUSD_IPCP_DB, "rw") == -1)
233		err(1, "unveil");
234	if (pledge("stdio inet rpath wpath flock", NULL) == -1)
235		err(1, "pledge");
236	setproctitle("[main]");
237
238	module_load(module_ipcp.base);
239	log_init(0);
240	event_init();
241
242	module_start(module_ipcp.base);
243	event_loop(0);
244
245	ipcp_fini(&module_ipcp);
246
247	event_loop(0);
248
249	exit(EXIT_SUCCESS);
250}
251
252void
253ipcp_init(struct module_ipcp *self)
254{
255	memset(self, 0, sizeof(struct module_ipcp));
256	TAILQ_INIT(&self->addrs);
257	RB_INIT(&self->ipv4s);
258	RB_INIT(&self->users);
259	TAILQ_INIT(&self->ctrls);
260	TAILQ_INIT(&self->daes);
261	self->seq = 1;
262	self->no_session_timeout = true;
263}
264
265void
266ipcp_start(void *ctx)
267{
268	struct module_ipcp	*self = ctx;
269	struct ipcp_address	*addr;
270	struct module_ipcp_dae	*dae;
271	int			 sock;
272
273	if (self->start_wait == 0)
274		self->start_wait = RADIUSD_IPCP_START_WAIT;
275
276	/* count pool address*/
277	TAILQ_FOREACH(addr, &self->addrs, next) {
278		if (addr->type == ADDRESS_TYPE_POOL)
279			self->npools += addr->naddrs;
280	}
281	log_info("number of pooled IP addresses = %d", self->npools);
282
283	if (ipcp_restore_from_db(self) == -1) {
284		module_send_message(self->base, IMSG_NG,
285		    "Restoring the database failed: %s", strerror(errno));
286		module_stop(self->base);
287		return;
288	}
289	ipcp_schedule_timer(self);
290
291	/* prepare socket for DAE */
292	TAILQ_FOREACH(dae, &self->daes, next) {
293		if ((sock = socket(dae->nas_addr.sin4.sin_family,
294		    SOCK_DGRAM, IPPROTO_UDP)) == -1) {
295			log_warn("could not start dae: %s", strerror(errno));
296			return;
297		}
298		if (connect(sock, (struct sockaddr *)&dae->nas_addr,
299		    dae->nas_addr.sin4.sin_len) == -1) {
300			log_warn("could not start dae: %s", strerror(errno));
301			return;
302		}
303		dae->sock = sock;
304		event_set(&dae->ev_sock, sock, EV_READ | EV_PERSIST,
305		    ipcp_dae_on_event, dae);
306		event_add(&dae->ev_sock, NULL);
307	}
308
309	module_send_message(self->base, IMSG_OK, NULL);
310}
311
312void
313ipcp_stop(void *ctx)
314{
315	struct module_ipcp		*self = ctx;
316	struct module_ipcp_dae		*dae;
317
318	/* stop the sockets for DAE */
319	TAILQ_FOREACH(dae, &self->daes, next) {
320		if (dae->sock >= 0) {
321			event_del(&dae->ev_sock);
322			close(dae->sock);
323			dae->sock = -1;
324		}
325	}
326	if (evtimer_pending(&self->ev_timer, NULL))
327		evtimer_del(&self->ev_timer);
328}
329
330void
331ipcp_fini(struct module_ipcp *self)
332{
333	struct assigned_ipv4		*assign, *assignt;
334	struct user			*user, *usert;
335	struct module_ipcp_ctrlconn	*ctrl, *ctrlt;
336	struct module_ipcp_dae		*dae, *daet;
337
338	RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s, assignt)
339		ipcp_ipv4_release(self, assign);
340	RB_FOREACH_SAFE(user, user_tree, &self->users, usert)
341		free(user);
342	TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt)
343		free(ctrl);
344	TAILQ_FOREACH_SAFE(dae, &self->daes, next, daet) {
345		if (dae->sock >= 0) {
346			event_del(&dae->ev_sock);
347			close(dae->sock);
348		}
349		free(dae);
350	}
351	if (evtimer_pending(&self->ev_timer, NULL))
352		evtimer_del(&self->ev_timer);
353	module_destroy(self->base);
354}
355
356void
357ipcp_config_set(void *ctx, const char *name, int argc, char * const * argv)
358{
359	struct module_ipcp	*module = ctx;
360	const char		*errmsg = "none";
361	int			 i;
362	struct ipcp_address	*addr;
363	struct in_addr		 ina;
364	struct module_ipcp_dae	 dae, *dae0;
365
366	if (strcmp(name, "address") == 0) {
367		SYNTAX_ASSERT(argc >= 1,
368		    "specify one of pool, server, nas-select, or user-select");
369		if (strcmp(argv[0], "pool") == 0) {
370			SYNTAX_ASSERT(argc >= 2,
371			    "`address pool' must have one address range at "
372			    "least");
373			addr = TAILQ_FIRST(&module->addrs);
374			for (i = 0; i < argc - 1; i++) {
375				if ((addr = parse_address_range(argv[i + 1]))
376				    == NULL) {
377					module_send_message(module->base,
378					    IMSG_NG, "Invalid address range: "
379					    "%s", argv[i + 1]);
380					return;
381				}
382				addr->type = ADDRESS_TYPE_POOL;
383				TAILQ_INSERT_TAIL(&module->addrs, addr, next);
384			}
385		} else if (strcmp(argv[0], "static") == 0) {
386			SYNTAX_ASSERT(argc >= 2,
387			    "`address static' must have one address range at "
388			    "least");
389			addr = TAILQ_FIRST(&module->addrs);
390			for (i = 0; i < argc - 1; i++) {
391				if ((addr = parse_address_range(argv[i + 1]))
392				    == NULL) {
393					module_send_message(module->base,
394					    IMSG_NG, "Invalid address range: "
395					    "%s", argv[i + 1]);
396					return;
397				}
398				addr->type = ADDRESS_TYPE_STATIC;
399				TAILQ_INSERT_TAIL(&module->addrs, addr, next);
400			}
401		} else
402			SYNTAX_ASSERT(0, "specify pool or static");
403	} else if (strcmp(name, "max-sessions") == 0) {
404		SYNTAX_ASSERT(argc == 1,
405		    "`max-sessions' must have an argument");
406		module->max_sessions = strtonum(argv[0], 0, INT_MAX, &errmsg);
407		if (errmsg != NULL) {
408			module_send_message(module->base, IMSG_NG,
409			    "could not parse `max-sessions': %s", errmsg);
410			return;
411		}
412	} else if (strcmp(name, "user-max-sessions") == 0) {
413		SYNTAX_ASSERT(argc == 1, "`max-session' must have an argument");
414		module->user_max_sessions = strtonum(argv[0], 0, INT_MAX,
415		    &errmsg);
416		if (errmsg != NULL) {
417			module_send_message(module->base, IMSG_NG,
418			    "could not parse `user-max-session': %s", errmsg);
419			return;
420		}
421	} else if (strcmp(name, "start-wait") == 0) {
422		SYNTAX_ASSERT(argc == 1, "`start-wait' must have an argument");
423		module->start_wait = strtonum(argv[0], 1, INT_MAX, &errmsg);
424		if (errmsg != NULL) {
425			module_send_message(module->base, IMSG_NG,
426			    "could not parse `start-wait': %s", errmsg);
427			return;
428		}
429	} else if (strcmp(name, "name-server") == 0) {
430		SYNTAX_ASSERT(argc == 1 || argc == 2,
431		    "specify 1 or 2 addresses for `name-server'");
432		for (i = 0; i < argc; i++) {
433			if (inet_aton(argv[i], &ina) != 1) {
434				module_send_message(module->base, IMSG_NG,
435				    "Invalid IP address: %s", argv[i]);
436				return;
437			}
438			if (module->name_server[0].s_addr == 0)
439				module->name_server[0] = ina;
440			else if (module->name_server[1].s_addr == 0)
441				module->name_server[1] = ina;
442			else
443				SYNTAX_ASSERT(0,
444				    "too many `name-server' is configured");
445		}
446	} else if (strcmp(name, "netbios-server") == 0) {
447		SYNTAX_ASSERT(argc == 1 || argc == 2,
448		    "specify 1 or 2 addresses for `name-server'");
449		for (i = 0; i < argc; i++) {
450			if (inet_aton(argv[i], &ina) != 1) {
451				module_send_message(module->base, IMSG_NG,
452				    "Invalid IP address: %s", argv[i]);
453				return;
454			}
455			if (module->netbios_server[0].s_addr == 0)
456				module->netbios_server[0] = ina;
457			else if (module->netbios_server[1].s_addr == 0)
458				module->netbios_server[1] = ina;
459			else
460				SYNTAX_ASSERT(0,
461				    "too many `name-server' is configured");
462		}
463	} else if (strcmp(name, "session-timeout") == 0) {
464		SYNTAX_ASSERT(argc == 1,
465		    "`session-timeout' must have an argument");
466		if (strcmp(argv[0], "radius") == 0) {
467			module->no_session_timeout = false;
468			module->session_timeout = 0;
469		} else {
470			module->no_session_timeout = false;
471			module->session_timeout = strtonum(argv[0], 1, INT_MAX,
472			    &errmsg);
473			if (errmsg != NULL) {
474				module_send_message(module->base, IMSG_NG,
475				    "could not parse `session-timeout': %s",
476				    errmsg);
477				return;
478			}
479		}
480	} else if (strcmp(name, "dae") == 0) {
481		if (!(argc >= 1 || strcmp(argv[1], "server") == 0)) {
482			module_send_message(module->base, IMSG_NG,
483			    "`%s' is unknown", argv[1]);
484			return;
485		}
486		i = 1;
487		SYNTAX_ASSERT(i < argc, "no address[:port] for dae server");
488		if (i < argc &&
489		    parse_addr(argv[i], AF_UNSPEC, (struct sockaddr *)
490		    &dae.nas_addr, sizeof(dae.nas_addr)) == -1) {
491			module_send_message(module->base, IMSG_NG,
492			    "failed to parse dae server's address, %s",
493			    argv[i]);
494			return;
495		}
496		if (ntohs(dae.nas_addr.sin4.sin_port) == 0)
497			dae.nas_addr.sin4.sin_port =
498			    htons(RADIUS_DAE_DEFAULT_PORT);
499		i++;
500		SYNTAX_ASSERT(i < argc, "no secret for dae server");
501		if (strlcpy(dae.secret, argv[i++], sizeof(dae.secret)) >=
502		    sizeof(dae.secret)) {
503			module_send_message(module->base, IMSG_NG,
504			    "dae server's secret must be < %d bytes",
505			    (int)sizeof(dae.secret) - 1);
506			return;
507		}
508		if (i < argc)
509			strlcpy(dae.nas_id, argv[i++], sizeof(dae.nas_id));
510		if ((dae0 = calloc(1, sizeof(struct module_ipcp_dae))) == NULL)
511		{
512			module_send_message(module->base, IMSG_NG,
513			    "%s", strerror(errno));
514			return;
515		}
516		*dae0 = dae;
517		TAILQ_INIT(&dae0->reqs);
518		TAILQ_INSERT_TAIL(&module->daes, dae0, next);
519	} else if (strcmp(name, "_debug") == 0)
520		log_init(1);
521	else if (strncmp(name, "_", 1) == 0)
522		/* ignore */;
523	else {
524		module_send_message(module->base, IMSG_NG,
525		    "Unknown config parameter name `%s'", name);
526		return;
527	}
528	module_send_message(module->base, IMSG_OK, NULL);
529
530	return;
531 syntax_error:
532	module_send_message(module->base, IMSG_NG, "%s", errmsg);
533}
534
535void
536ipcp_dispatch_control(void *ctx, struct imsg *imsg)
537{
538	struct module_ipcp		*self = ctx;
539	struct assigned_ipv4		*assign;
540	struct radiusd_ipcp_db_dump	*dump;
541	struct module_ipcp_ctrlconn	*ctrl, *ctrlt;
542	int				 i;
543	size_t				 dumpsiz;
544	u_int				 datalen;
545	unsigned			 seq;
546
547	datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
548	switch (imsg->hdr.type) {
549	case IMSG_RADIUSD_MODULE_CTRL_UNBIND:
550		TAILQ_FOREACH_SAFE(ctrl, &self->ctrls, next, ctrlt) {
551			if (ctrl->peerid == imsg->hdr.peerid) {
552				TAILQ_REMOVE(&self->ctrls, ctrl, next);
553				free(ctrl);
554				break;
555			}
556		}
557		break;
558	case IMSG_RADIUSD_MODULE_IPCP_MONITOR:
559	case IMSG_RADIUSD_MODULE_IPCP_DUMP_AND_MONITOR:
560		if ((ctrl = calloc(1, sizeof(struct module_ipcp_ctrlconn)))
561		    == NULL) {
562			log_warn("%s: calloc()", __func__);
563			goto fail;
564		}
565		ctrl->peerid = imsg->hdr.peerid;
566		TAILQ_INSERT_TAIL(&self->ctrls, ctrl, next);
567		module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_CTRL_BIND,
568		    imsg->hdr.peerid, 0, -1, NULL, 0);
569		if (imsg->hdr.type == IMSG_RADIUSD_MODULE_IPCP_MONITOR)
570			break;
571		/* FALLTROUGH */
572	case IMSG_RADIUSD_MODULE_IPCP_DUMP:
573		dumpsiz = MAX_IMSGSIZE;
574		if ((dump = calloc(1, dumpsiz)) == NULL) {
575			log_warn("%s: calloc()", __func__);
576			goto fail;
577		}
578		i = 0;
579		RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) {
580			if (!timespecisset(&assign->start))
581				/* not started yet */
582				continue;
583			ipcp_db_dump_fill_record(dump, i++, assign);
584			if (RB_NEXT(assigned_ipv4_tree, &self->ipv4s, assign)
585			    == NULL)
586				break;
587			if (offsetof(struct radiusd_ipcp_db_dump,
588			    records[i + 1]) >= dumpsiz) {
589				module_imsg_compose(self->base,
590				    IMSG_RADIUSD_MODULE_IPCP_DUMP,
591				    imsg->hdr.peerid, 0, -1,
592				    dump, offsetof(struct radiusd_ipcp_db_dump,
593				    records[i]));
594				i = 0;
595			}
596		}
597		dump->islast = 1;
598		module_imsg_compose(self->base, IMSG_RADIUSD_MODULE_IPCP_DUMP,
599		    imsg->hdr.peerid, 0, -1, dump, offsetof(
600		    struct radiusd_ipcp_db_dump, records[i]));
601		freezero(dump ,dumpsiz);
602		break;
603	case IMSG_RADIUSD_MODULE_IPCP_DISCONNECT:
604		if (datalen < sizeof(unsigned)) {
605			log_warn("%s: received "
606			    "IMSG_RADIUSD_MODULE_IPCP_DISCONNECT message size "
607			    "is wrong", __func__);
608			goto fail;
609		}
610		seq = *(unsigned *)imsg->data;
611		RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) {
612			if (!timespecisset(&assign->start))
613				/* not started yet */
614				continue;
615			if (assign->seq == seq)
616				break;
617		}
618		if (assign == NULL)
619			log_warnx("Disconnect seq=%u requested, but the "
620			    "session is not found", seq);
621		else {
622			if (assign->dae == NULL)
623				log_warnx("Disconnect seq=%u requested, but "
624				    "DAE is not configured", assign->seq);
625			else {
626				log_info("Disconnect id=%u requested",
627				    assign->seq);
628				ipcp_dae_send_disconnect_request(assign);
629			}
630		}
631		break;
632	}
633	return;
634 fail:
635	module_stop(self->base);
636}
637
638int
639ipcp_notice_startstop(struct module_ipcp *self, struct assigned_ipv4 *assign,
640    int start, struct radiusd_ipcp_statistics *stat)
641{
642	struct module_ipcp_ctrlconn	*ctrl;
643	struct radiusd_ipcp_db_dump	*dump;
644	size_t				 dumpsiz;
645	struct iovec			 iov[2];
646	int				 niov = 0;
647
648	dumpsiz = offsetof(struct radiusd_ipcp_db_dump, records[1]);
649	if ((dump = calloc(1, dumpsiz)) == NULL) {
650		log_warn("%s: calloc()", __func__);
651		return (-1);
652	}
653	dump->islast = 1;
654	ipcp_db_dump_fill_record(dump, 0, assign);
655
656	iov[niov].iov_base = dump;
657	iov[niov].iov_len = dumpsiz;
658	if (start == 0) {
659		iov[++niov].iov_base = stat;
660		iov[niov].iov_len = sizeof(struct radiusd_ipcp_statistics);
661	}
662	TAILQ_FOREACH(ctrl, &self->ctrls, next)
663		module_imsg_composev(self->base,
664		    (start)? IMSG_RADIUSD_MODULE_IPCP_START :
665		    IMSG_RADIUSD_MODULE_IPCP_STOP, ctrl->peerid, 0, -1, iov,
666		    niov + 1);
667	freezero(dump, dumpsiz);
668	return (0);
669}
670
671void
672ipcp_resdeco(void *ctx, u_int q_id, const u_char *req, size_t reqlen,
673    const u_char *res, size_t reslen)
674{
675	struct module_ipcp	*self = ctx;
676	RADIUS_PACKET		*radres = NULL, *radreq = NULL;
677	struct in_addr		 addr4;
678	const struct in_addr	 mask4 = { .s_addr = 0xffffffffUL };
679	int			 res_code, msraserr = 935;
680	struct ipcp_address	*addr;
681	int			 i, j, n;
682	bool			 found = false;
683	char			 username[256], buf[128];
684	struct user		*user = NULL;
685	struct assigned_ipv4	*assigned = NULL, *assign;
686
687	clock_gettime(CLOCK_BOOTTIME, &self->uptime);
688
689	if ((radres = radius_convert_packet(res, reslen)) == NULL) {
690		log_warn("%s: radius_convert_packet() failed", __func__);
691		goto fatal;
692	}
693	res_code = radius_get_code(radres);
694	if (res_code != RADIUS_CODE_ACCESS_ACCEPT)
695		goto accept;
696
697	if ((radreq = radius_convert_packet(req, reqlen)) == NULL) {
698		log_warn("%s: radius_convert_packet() failed", __func__);
699		goto fatal;
700	}
701
702	/*
703	 * prefer User-Name of the response rather than the request,
704	 * since it must be the authenticated user.
705	 */
706	if (radius_get_string_attr(radres, RADIUS_TYPE_USER_NAME, username,
707	    sizeof(username)) != 0 &&
708	    radius_get_string_attr(radreq, RADIUS_TYPE_USER_NAME, username,
709	    sizeof(username)) != 0) {
710		log_warnx("q=%u unexpected request: no user-name", q_id);
711		goto fatal;
712	}
713
714	if ((addr = TAILQ_FIRST(&self->addrs)) != NULL) {
715		/* The address assignment is configured */
716
717		if ((user = ipcp_user_get(self, username)) == NULL) {
718			log_warn("%s: ipcp_user_get()", __func__);
719			goto fatal;
720		}
721
722		msraserr = 935;
723		if (self->max_sessions != 0) {
724			if (self->nsessions >= self->max_sessions) {
725				log_info("q=%u rejected: number of "
726				    "sessions reached the limit(%d)", q_id,
727				    self->max_sessions);
728				goto reject;
729			}
730		}
731		if (self->user_max_sessions != 0) {
732			n = 0;
733			TAILQ_FOREACH(assign, &user->ipv4s, next)
734				n++;
735			if (n >= self->user_max_sessions) {
736				log_info("q=%u rejected: number of "
737				    "sessions per a user reached the limit(%d)",
738				    q_id, self->user_max_sessions);
739				goto reject;
740			}
741		}
742
743		msraserr = 716;
744		if (radius_get_ipv4_attr(radres,
745		    RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4) == 0) {
746			if (ipcp_ipv4_find(self, addr4) != NULL)
747				log_info("q=%u rejected: server requested IP "
748				    "address is busy", q_id);
749			else {
750				/* compare in host byte order */
751				addr4.s_addr = ntohl(addr4.s_addr);
752				TAILQ_FOREACH(addr, &self->addrs, next) {
753					if (addr->type != ADDRESS_TYPE_STATIC &&
754					    addr->type != ADDRESS_TYPE_POOL)
755						continue;
756					if (addr->start.s_addr <= addr4.s_addr
757					    && addr4.s_addr <= addr->end.s_addr)
758						break;
759				}
760				if (addr == NULL)
761					log_info("q=%u rejected: server "
762					    "requested IP address is out of "
763					    "the range", q_id);
764				else
765					found = true;
766				/* revert the addr to the network byte order */
767				addr4.s_addr = htonl(addr4.s_addr);
768			}
769			if (!found)
770				goto reject;
771		} else {
772			n = arc4random() % self->npools;
773			i = 0;
774			TAILQ_FOREACH(addr, &self->addrs, next) {
775				if (addr->type == ADDRESS_TYPE_POOL) {
776					if (i <= n && n < i + addr->naddrs) {
777						j = n - i;
778						break;
779					}
780					i += addr->naddrs;
781				}
782			}
783			for (i = 0; i < self->npools; i++, j++) {
784				if (addr == NULL)
785					break;
786				if (j >= addr->naddrs) { /* next pool */
787					if ((addr = TAILQ_NEXT(addr, next))
788					    == NULL)
789						addr = TAILQ_FIRST(
790						    &self->addrs);
791					j = 0;
792				}
793				addr4.s_addr = htonl(addr->start.s_addr + j);
794				if (ipcp_ipv4_find(self, addr4) == NULL) {
795					found = true;
796					break;
797				}
798			}
799			if (!found) {
800				log_info("q=%u rejected: ran out of the "
801				    "address pool", q_id);
802				goto reject;
803			}
804		}
805		if ((assigned = ipcp_ipv4_assign(self, user, addr4)) == NULL) {
806			log_warn("%s: ipcp_ipv4_assign()", __func__);
807			goto fatal;
808		}
809		radius_set_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_NETMASK,
810		    mask4);
811		radius_del_attr_all(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS);
812		radius_put_ipv4_attr(radres, RADIUS_TYPE_FRAMED_IP_ADDRESS,
813		    addr4);
814		log_info("q=%u Assign %s for %s", q_id,
815		    inet_ntop(AF_INET, &addr4, buf, sizeof(buf)), username);
816		if (radius_has_attr(radreq, RADIUS_TYPE_USER_PASSWORD))
817			strlcpy(assigned->auth_method, "PAP",
818			    sizeof(assigned->auth_method));
819		else if (radius_has_attr(radreq, RADIUS_TYPE_CHAP_PASSWORD))
820			strlcpy(assigned->auth_method, "CHAP",
821			    sizeof(assigned->auth_method));
822		else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT,
823		    RADIUS_VTYPE_MS_CHAP_RESPONSE))
824			strlcpy(assigned->auth_method, "MS-CHAP",
825			    sizeof(assigned->auth_method));
826		else if (radius_has_vs_attr(radreq, RADIUS_VENDOR_MICROSOFT,
827		    RADIUS_VTYPE_MS_CHAP2_RESPONSE))
828			strlcpy(assigned->auth_method, "MS-CHAP-V2",
829			    sizeof(assigned->auth_method));
830		else if (radius_has_attr(radreq, RADIUS_TYPE_EAP_MESSAGE))
831			strlcpy(assigned->auth_method, "EAP",
832			    sizeof(assigned->auth_method));
833	}
834
835	if (self->name_server[0].s_addr != 0) {
836		addr4.s_addr = htonl(self->name_server[0].s_addr);
837		radius_del_vs_attr_all(radres,
838		    RADIUS_VENDOR_MICROSOFT,
839		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER);
840		radius_put_vs_ipv4_attr(radres,
841		    RADIUS_VENDOR_MICROSOFT,
842		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER, self->name_server[0]);
843	}
844	if (self->name_server[1].s_addr != 0) {
845		addr4.s_addr = htonl(self->name_server[1].s_addr);
846		radius_del_vs_attr_all(radres,
847		    RADIUS_VENDOR_MICROSOFT,
848		    RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER);
849		radius_put_vs_ipv4_attr(radres,
850		    RADIUS_VENDOR_MICROSOFT,
851		    RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER, self->name_server[1]);
852	}
853	if (self->netbios_server[0].s_addr != 0) {
854		addr4.s_addr = htonl(self->netbios_server[0].s_addr);
855		radius_del_vs_attr_all(radres,
856		    RADIUS_VENDOR_MICROSOFT,
857		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER);
858		radius_put_vs_ipv4_attr(radres,
859		    RADIUS_VENDOR_MICROSOFT,
860		    RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER,
861		    self->netbios_server[0]);
862	}
863	if (self->netbios_server[1].s_addr != 0) {
864		addr4.s_addr = htonl(self->netbios_server[1].s_addr);
865		radius_del_vs_attr_all(radres,
866		    RADIUS_VENDOR_MICROSOFT,
867		    RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER);
868		radius_put_vs_ipv4_attr(radres,
869		    RADIUS_VENDOR_MICROSOFT,
870		    RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER,
871		    self->netbios_server[1]);
872	}
873	if (!self->no_session_timeout &&
874	    radius_has_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT)) {
875		radius_get_uint32_attr(radres, RADIUS_TYPE_SESSION_TIMEOUT,
876		    &assigned->session_timeout);
877		/* we handle this session-timeout */
878		radius_del_attr_all(radres, RADIUS_TYPE_SESSION_TIMEOUT);
879	}
880
881 accept:
882	if (module_resdeco_done(self->base, q_id, radius_get_data(radres),
883	    radius_get_length(radres)) == -1) {
884		log_warn("%s: module_resdeco_done() failed", __func__);
885		module_stop(self->base);
886	}
887	if (radreq != NULL)
888		radius_delete_packet(radreq);
889	radius_delete_packet(radres);
890	return;
891 reject:
892	ipcp_reject(self, radreq, q_id, radres, msraserr);
893	radius_delete_packet(radreq);
894	radius_delete_packet(radres);
895	return;
896 fatal:
897	if (radreq != NULL)
898		radius_delete_packet(radreq);
899	if (radres != NULL)
900		radius_delete_packet(radres);
901	module_stop(self->base);
902}
903
904void
905ipcp_reject(struct module_ipcp *self, RADIUS_PACKET *reqp, unsigned int q_id,
906    RADIUS_PACKET *orig_resp, int mserr)
907{
908	bool			 is_eap, is_mschap, is_mschap2;
909	uint8_t			 attr[256];
910	size_t			 attrlen;
911	RADIUS_PACKET		*resp;
912	struct {
913		uint8_t		 code;
914		uint8_t		 id;
915		uint16_t	 length;
916	} __packed		 eap;
917
918	resp = radius_new_response_packet(RADIUS_CODE_ACCESS_REJECT, reqp);
919	if (resp == NULL) {
920		log_warn("%s: radius_new_response_packet() failed", __func__);
921		module_accsreq_aborted(self->base, q_id);
922		return;
923	}
924
925	is_eap = radius_has_attr(reqp, RADIUS_TYPE_EAP_MESSAGE);
926	if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT,
927	    RADIUS_VTYPE_MS_CHAP_RESPONSE, attr, &attrlen) == 0)
928		is_mschap = true;
929	else if (radius_get_vs_raw_attr(reqp, RADIUS_VENDOR_MICROSOFT,
930	    RADIUS_VTYPE_MS_CHAP2_RESPONSE, attr, &attrlen) == 0)
931		is_mschap2 = true;
932
933	if (is_eap) {
934		memset(&eap, 0, sizeof(eap));	/* just in case */
935		eap.code = 1;	/* EAP Request */
936		attrlen = sizeof(attr);
937		if (orig_resp != NULL && radius_get_raw_attr(orig_resp,
938		    RADIUS_TYPE_EAP_MESSAGE, &attr, &attrlen) == 0)
939			eap.id = attr[1];
940		else
941			eap.id = 0;
942		eap.length = htons(sizeof(eap));
943		radius_put_raw_attr(resp, RADIUS_TYPE_EAP_MESSAGE, &eap,
944		    ntohs(eap.length));
945	} else if (is_mschap || is_mschap2) {
946		attr[0] = attr[1];	/* Copy the ident of the request */
947		snprintf(attr + 1, sizeof(attr) - 1, "E=%d R=0 V=3", mserr);
948		radius_put_vs_raw_attr(resp, RADIUS_VENDOR_MICROSOFT,
949		    RADIUS_VTYPE_MS_CHAP_ERROR, attr, strlen(attr + 1) + 1);
950	}
951
952	module_resdeco_done(self->base, q_id, radius_get_data(resp),
953	    radius_get_length(resp));
954	radius_delete_packet(resp);
955}
956
957/***********************************************************************
958 * RADIUS Accounting
959 ***********************************************************************/
960void
961ipcp_accounting_request(void *ctx, u_int q_id, const u_char *pkt,
962    size_t pktlen)
963{
964	RADIUS_PACKET		*radpkt = NULL;
965	int			 code, af;
966	uint32_t		 type, delay, uval;
967	struct in_addr		 addr4, nas_ipv4;
968	struct in6_addr		 nas_ipv6, ipv6_zero;
969	struct module_ipcp	*self = ctx;
970	struct assigned_ipv4	*assign, *assignt;
971	char			 username[256], nas_id[256], buf[256],
972				    buf1[80];
973	struct timespec		 dur;
974	struct radiusd_ipcp_statistics
975				 stat;
976	struct module_ipcp_dae	*dae;
977
978	clock_gettime(CLOCK_BOOTTIME, &self->uptime);
979
980	if ((radpkt = radius_convert_packet(pkt, pktlen)) == NULL) {
981		log_warn("%s: radius_convert_packet() failed", __func__);
982		module_stop(self->base);
983		return;
984	}
985	code = radius_get_code(radpkt);
986	if (code != RADIUS_CODE_ACCOUNTING_REQUEST &&
987	    code != RADIUS_CODE_ACCOUNTING_RESPONSE)
988		goto out;
989
990	if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_STATUS_TYPE, &type)
991	    != 0)
992		goto out;
993
994	/* identifier for the NAS */
995	memset(&ipv6_zero, 0, sizeof(ipv6_zero));
996	memset(&nas_ipv4, 0, sizeof(nas_ipv4));
997	memset(&nas_ipv6, 0, sizeof(nas_ipv6));
998	memset(&nas_id, 0, sizeof(nas_id));
999
1000	radius_get_ipv4_attr(radpkt, RADIUS_TYPE_NAS_IP_ADDRESS, &nas_ipv4);
1001	radius_get_ipv6_attr(radpkt, RADIUS_TYPE_NAS_IPV6_ADDRESS, &nas_ipv6);
1002	radius_get_string_attr(radpkt, RADIUS_TYPE_NAS_IDENTIFIER, nas_id,
1003	    sizeof(nas_id));
1004
1005	if (nas_ipv4.s_addr == 0 && IN6_ARE_ADDR_EQUAL(&nas_ipv6, &ipv6_zero) &&
1006	    nas_id[0] == '\0') {
1007		log_warnx("q=%u no NAS-IP-Address, NAS-IPV6-Address, or "
1008		    "NAS-Identifier", q_id);
1009		goto out;
1010	}
1011
1012	if (type == RADIUS_ACCT_STATUS_TYPE_ACCT_ON ||
1013	    type == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) {
1014		/*
1015		 * NAS or daemon is restarted.  Delete all assigned records
1016		 * from it
1017		 */
1018		RB_FOREACH_SAFE(assign, assigned_ipv4_tree, &self->ipv4s,
1019		    assignt) {
1020			if (assign->nas_ipv4.s_addr != nas_ipv4.s_addr ||
1021			    !IN6_ARE_ADDR_EQUAL(&assign->nas_ipv6, &nas_ipv6) ||
1022			    strcmp(assign->nas_id, nas_id) != 0)
1023				continue;
1024			log_info("Delete record for %s", inet_ntop(AF_INET,
1025			    &assign->ipv4, buf, sizeof(buf)));
1026			ipcp_del_db(self, assign);
1027			ipcp_ipv4_release(self, assign);
1028		}
1029		return;
1030	}
1031
1032	if (radius_get_ipv4_attr(radpkt, RADIUS_TYPE_FRAMED_IP_ADDRESS, &addr4)
1033	    != 0)
1034		goto out;
1035	if (radius_get_string_attr(radpkt, RADIUS_TYPE_USER_NAME, username,
1036	    sizeof(username)) != 0)
1037		goto out;
1038	if ((assign = ipcp_ipv4_find(self, addr4)) == NULL)
1039		/* not assigned by this */
1040		goto out;
1041
1042	if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_DELAY_TIME, &delay)
1043	    != 0)
1044		delay = 0;
1045
1046	if (type == RADIUS_ACCT_STATUS_TYPE_START) {
1047		assign->start = self->uptime;
1048		assign->start.tv_sec -= delay;
1049
1050		if (!self->no_session_timeout && (self->session_timeout > 0 ||
1051		    assign->session_timeout > 0)) {
1052			assign->timeout = assign->start;
1053			if (self->session_timeout > 0)
1054				assign->timeout.tv_sec += self->session_timeout;
1055			else
1056				assign->timeout.tv_sec +=
1057				    assign->session_timeout;
1058		}
1059		assign->nas_ipv4 = nas_ipv4;
1060		assign->nas_ipv4 = nas_ipv4;
1061		strlcpy(assign->nas_id, nas_id, sizeof(assign->nas_id));
1062
1063		if (radius_get_string_attr(radpkt, RADIUS_TYPE_ACCT_SESSION_ID,
1064		    assign->session_id, sizeof(assign->session_id)) != 0)
1065			assign->session_id[0] = '\0';
1066		if (radius_get_uint32_attr(radpkt, RADIUS_TYPE_TUNNEL_TYPE,
1067		    &uval) == 0)
1068			assign->tun_type = radius_tunnel_type_string(uval,
1069			    NULL);
1070		if (assign->tun_type == NULL)
1071			assign->tun_type = "";
1072
1073		/*
1074		 * Get "tunnel from" from Tunnel-Client-Endpoint or Calling-
1075		 * Station-Id
1076		 */
1077		af = AF_UNSPEC;
1078		if (radius_get_string_attr(radpkt,
1079		    RADIUS_TYPE_TUNNEL_CLIENT_ENDPOINT, buf, sizeof(buf)) == 0)
1080		    {
1081			if (radius_get_uint32_attr(radpkt,
1082			    RADIUS_TYPE_TUNNEL_MEDIUM_TYPE, &uval) == 0) {
1083				if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV4)
1084					af = AF_INET;
1085				else if (uval == RADIUS_TUNNEL_MEDIUM_TYPE_IPV6)
1086					af = AF_INET6;
1087			}
1088			parse_addr(buf, af, (struct sockaddr *)
1089			    &assign->tun_client, sizeof(assign->tun_client));
1090		}
1091		if (assign->tun_client.sin4.sin_family == 0 &&
1092		    radius_get_string_attr(radpkt,
1093		    RADIUS_TYPE_CALLING_STATION_ID, buf, sizeof(buf)) == 0)
1094			parse_addr(buf, af, (struct sockaddr *)
1095			    &assign->tun_client, sizeof(assign->tun_client));
1096
1097		TAILQ_FOREACH(dae, &self->daes, next) {
1098			if (dae->nas_id[0] == '\0' ||
1099			    strcmp(dae->nas_id, assign->nas_id) == 0)
1100				break;
1101		}
1102		assign->dae = dae;
1103
1104		ipcp_put_db(self, assign);
1105		ipcp_schedule_timer(self);
1106
1107		if (ipcp_notice_startstop(self, assign, 1, NULL) != 0)
1108			goto fail;
1109		log_info("Start seq=%u user=%s duration=%dsec session=%s "
1110		    "tunnel=%s from=%s auth=%s ip=%s", assign->seq,
1111		    assign->user->name, delay, assign->session_id,
1112		    assign->tun_type, print_addr((struct sockaddr *)
1113		    &assign->tun_client, buf1, sizeof(buf1)),
1114		    assign->auth_method, inet_ntop(AF_INET, &addr4, buf,
1115		    sizeof(buf)));
1116	} else if (type == RADIUS_ACCT_STATUS_TYPE_STOP) {
1117		memset(&stat, 0, sizeof(stat));
1118
1119		dur = self->uptime;
1120		dur.tv_sec -= delay;
1121		timespecsub(&dur, &assign->start, &dur);
1122
1123		if (radius_get_uint32_attr(radpkt,
1124		    RADIUS_TYPE_ACCT_INPUT_OCTETS, &uval) == 0)
1125			stat.ibytes = uval;
1126		if (radius_get_uint32_attr(radpkt,
1127		    RADIUS_TYPE_ACCT_INPUT_GIGAWORDS, &uval) == 0)
1128			stat.ibytes = ((uint64_t)uval << 32) | stat.ibytes;
1129		if (radius_get_uint32_attr(radpkt,
1130		    RADIUS_TYPE_ACCT_OUTPUT_OCTETS, &uval) == 0)
1131			stat.obytes = uval;
1132		if (radius_get_uint32_attr(radpkt,
1133		    RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS, &uval) == 0)
1134			stat.obytes = ((uint64_t)uval << 32) | stat.obytes;
1135		radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_INPUT_PACKETS,
1136		    &stat.ipackets);
1137		radius_get_uint32_attr(radpkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS,
1138		    &stat.opackets);
1139
1140		if (radius_get_uint32_attr(radpkt,
1141		    RADIUS_TYPE_ACCT_TERMINATE_CAUSE, &uval) == 0)
1142			strlcpy(stat.cause, radius_terminate_cause_string(uval),
1143			    sizeof(stat.cause));
1144
1145		log_info("Stop seq=%u user=%s duration=%lldsec session=%s "
1146		    "tunnel=%s from=%s auth=%s ip=%s datain=%"PRIu64"bytes,%"
1147		    PRIu32"packets dataout=%"PRIu64"bytes,%"PRIu32"packets "
1148		    "cause=\"%s\"",
1149		    assign->seq, assign->user->name, dur.tv_sec,
1150		    assign->session_id, assign->tun_type, print_addr(
1151		    (struct sockaddr *)&assign->tun_client, buf1, sizeof(buf1)),
1152		    assign->auth_method, inet_ntop(AF_INET, &addr4, buf,
1153		    sizeof(buf)), stat.ibytes, stat.ipackets, stat.obytes,
1154		    stat.opackets, stat.cause);
1155
1156		ipcp_del_db(self, assign);
1157		if (ipcp_notice_startstop(self, assign, 0, &stat) != 0)
1158			goto fail;
1159		ipcp_ipv4_release(self, ipcp_ipv4_find(self, addr4));
1160	}
1161 out:
1162	radius_delete_packet(radpkt);
1163	return;
1164 fail:
1165	module_stop(self->base);
1166	radius_delete_packet(radpkt);
1167	return;
1168}
1169
1170/***********************************************************************
1171 * On memory database to manage IP address assignment
1172 ***********************************************************************/
1173struct assigned_ipv4 *
1174ipcp_ipv4_assign(struct module_ipcp *self, struct user *user,
1175    struct in_addr ina)
1176{
1177	struct assigned_ipv4 *ip;
1178
1179	ip = calloc(1, sizeof(struct assigned_ipv4));
1180	if (ip == NULL) {
1181		log_warn("%s: calloc()", __func__);
1182		return (NULL);
1183	}
1184	ip->ipv4 = ina;
1185	ip->user = user;
1186	ip->authtime = self->uptime;
1187	RB_INSERT(assigned_ipv4_tree, &self->ipv4s, ip);
1188	TAILQ_INSERT_TAIL(&user->ipv4s, ip, next);
1189	self->nsessions++;
1190	ip->seq = self->seq++;
1191
1192	return (ip);
1193}
1194
1195struct assigned_ipv4 *
1196ipcp_ipv4_find(struct module_ipcp *self, struct in_addr ina)
1197{
1198	struct assigned_ipv4	 key, *ret;
1199	struct timespec		 dif;
1200
1201	key.ipv4 = ina;
1202	ret = RB_FIND(assigned_ipv4_tree, &self->ipv4s, &key);
1203	if (ret != NULL && ret->start.tv_sec == 0) {
1204		/* not yet assigned */
1205		timespecsub(&self->uptime, &ret->authtime, &dif);
1206		if (dif.tv_sec >= self->start_wait) {
1207			/* assumed NAS finally didn't use the address */
1208			TAILQ_REMOVE(&ret->user->ipv4s, ret, next);
1209			RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, ret);
1210			free(ret);
1211			ret = NULL;
1212			self->nsessions--;
1213		}
1214	}
1215	return (ret);
1216}
1217
1218void
1219ipcp_ipv4_release(struct module_ipcp *self, struct assigned_ipv4 *assign)
1220{
1221	if (assign != NULL) {
1222		TAILQ_REMOVE(&assign->user->ipv4s, assign, next);
1223		RB_REMOVE(assigned_ipv4_tree, &self->ipv4s, assign);
1224		self->nsessions--;
1225		if (assign->dae != NULL) {
1226			if (assign->dae_ntry > 0) {
1227				TAILQ_REMOVE(&assign->dae->reqs, assign,
1228				    dae_next);
1229				if (evtimer_pending(&assign->dae_evtimer, NULL))
1230					evtimer_del(&assign->dae_evtimer);
1231			}
1232		}
1233		if (assign->dae_reqpkt != NULL)
1234			radius_delete_packet(assign->dae_reqpkt);
1235		if (evtimer_pending(&assign->dae_evtimer, NULL))
1236			evtimer_del(&assign->dae_evtimer);
1237		free(assign);
1238	}
1239}
1240
1241int
1242assigned_ipv4_compar(struct assigned_ipv4 *a, struct assigned_ipv4 *b)
1243{
1244	return (b->ipv4.s_addr - a->ipv4.s_addr);
1245}
1246
1247struct user *
1248ipcp_user_get(struct module_ipcp *self, const char *username)
1249{
1250	struct {
1251		struct user	 user;
1252		char		 name[256];
1253	} key;
1254	struct user		*elm;
1255
1256	strlcpy(key.user.name, username, 256);
1257	elm = RB_FIND(user_tree, &self->users, &key.user);
1258	if (elm == NULL) {
1259		if ((elm = calloc(1, offsetof(struct user, name[
1260		    strlen(username) + 1]))) == NULL)
1261			return (NULL);
1262		memcpy(elm->name, username, strlen(username));
1263		RB_INSERT(user_tree, &self->users, elm);
1264		TAILQ_INIT(&elm->ipv4s);
1265	}
1266
1267	return (elm);
1268}
1269
1270int
1271user_compar(struct user *a, struct user *b)
1272{
1273	return (strcmp(a->name, b->name));
1274}
1275
1276RB_GENERATE_STATIC(assigned_ipv4_tree, assigned_ipv4, tree,
1277    assigned_ipv4_compar);
1278RB_GENERATE_STATIC(user_tree, user, tree, user_compar);
1279
1280/***********************************************************************
1281 * DB for the persistent over processes
1282 ***********************************************************************/
1283int
1284ipcp_prepare_db(void)
1285{
1286	struct passwd	*pw;
1287	DB		*db;
1288
1289	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_CREAT | O_RDWR | O_EXLOCK,
1290	    0600, DB_BTREE, NULL)) == NULL)
1291		return (-1);
1292	if ((pw = getpwnam(RADIUSD_USER)) == NULL)
1293		return (-1);
1294	fchown(db->fd(db), pw->pw_uid, pw->pw_gid);
1295	db->close(db);
1296
1297	return (0);
1298}
1299
1300int
1301ipcp_restore_from_db(struct module_ipcp *self)
1302{
1303	DB			*db;
1304	DBT			 key, val;
1305	char			 keybuf[128];
1306	struct user		*user;
1307	struct radiusd_ipcp_db_record
1308				*record;
1309	struct assigned_ipv4	*assigned;
1310	struct in_addr		 ipv4;
1311	struct module_ipcp_dae	*dae;
1312
1313	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDONLY | O_SHLOCK, 0600,
1314	    DB_BTREE, NULL)) == NULL)
1315		return (-1);
1316
1317	key.data = "ipv4/";
1318	key.size = 5;
1319	if (db->seq(db, &key, &val, R_CURSOR) == 0) {
1320		do {
1321			if (key.size >= sizeof(keybuf))
1322				break;
1323			memcpy(keybuf, key.data, key.size);
1324			keybuf[key.size] = '\0';
1325			if (strncmp(keybuf, "ipv4/", 5) != 0)
1326				break;
1327			inet_pton(AF_INET, keybuf + 5, &ipv4);
1328			record = (struct radiusd_ipcp_db_record *)val.data;
1329			if ((user = ipcp_user_get(self, record->username))
1330			    == NULL)
1331				return (-1);
1332			if ((assigned = ipcp_ipv4_assign(self, user, ipv4))
1333			    == NULL)
1334				return (-1);
1335			self->seq = MAXIMUM(assigned->seq + 1, self->seq);
1336			assigned->seq = record->seq;
1337			strlcpy(assigned->auth_method, record->auth_method,
1338			    sizeof(assigned->auth_method));
1339			strlcpy(assigned->session_id, record->session_id,
1340			    sizeof(assigned->session_id));
1341			assigned->start = record->start;
1342			assigned->timeout = record->timeout;
1343			assigned->nas_ipv4 = record->nas_ipv4;
1344			assigned->nas_ipv6 = record->nas_ipv6;
1345			strlcpy(assigned->nas_id, record->nas_id,
1346			    sizeof(assigned->nas_id));
1347			assigned->tun_type = radius_tunnel_type_string(0,
1348			    record->tun_type);
1349			memcpy(&assigned->tun_client, &record->tun_client,
1350			    sizeof(assigned->tun_client));
1351
1352			TAILQ_FOREACH(dae, &self->daes, next) {
1353				if (dae->nas_id[0] == '\0' ||
1354				    strcmp(dae->nas_id, assigned->nas_id) == 0)
1355					break;
1356			}
1357			assigned->dae = dae;
1358		} while (db->seq(db, &key, &val, R_NEXT) == 0);
1359	}
1360	db->close(db);
1361
1362	return (0);
1363}
1364
1365void
1366ipcp_put_db(struct module_ipcp *self, struct assigned_ipv4 *assigned)
1367{
1368	DB			*db;
1369	DBT			 key, val;
1370	char			 keybuf[128];
1371	struct radiusd_ipcp_db_record
1372				 record;
1373
1374	strlcpy(keybuf, "ipv4/", sizeof(keybuf));
1375	inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5);
1376	key.data = keybuf;
1377	key.size = strlen(keybuf);
1378	strlcpy(record.session_id, assigned->session_id,
1379	    sizeof(record.session_id));
1380	strlcpy(record.auth_method, assigned->auth_method,
1381	    sizeof(record.auth_method));
1382	strlcpy(record.username, assigned->user->name, sizeof(record.username));
1383	record.seq = assigned->seq;
1384	record.start = assigned->start;
1385	record.timeout = assigned->timeout;
1386	record.nas_ipv4 = assigned->nas_ipv4;
1387	record.nas_ipv6 = assigned->nas_ipv6;
1388	strlcpy(record.nas_id, assigned->nas_id, sizeof(record.nas_id));
1389	if (assigned->tun_type != NULL)
1390		strlcpy(record.tun_type, assigned->tun_type,
1391		    sizeof(record.tun_type));
1392	memcpy(&record.tun_client, &assigned->tun_client,
1393	    sizeof(record.tun_client));
1394
1395	val.data = &record;
1396	val.size = sizeof(record);
1397	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600,
1398	    DB_BTREE, NULL)) == NULL)
1399		return;
1400	db->put(db, &key, &val, 0);
1401	db->close(db);
1402}
1403
1404void
1405ipcp_del_db(struct module_ipcp *self, struct assigned_ipv4 *assigned)
1406{
1407	DB			*db;
1408	DBT			 key;
1409	char			 keybuf[128];
1410
1411	strlcpy(keybuf, "ipv4/", sizeof(keybuf));
1412	inet_ntop(AF_INET, &assigned->ipv4, keybuf + 5, sizeof(keybuf) - 5);
1413	key.data = keybuf;
1414	key.size = strlen(keybuf);
1415
1416	if ((db = dbopen(_PATH_RADIUSD_IPCP_DB, O_RDWR | O_EXLOCK, 0600,
1417	    DB_BTREE, NULL)) == NULL)
1418		return;
1419	db->del(db, &key, 0);
1420	db->close(db);
1421}
1422
1423void
1424ipcp_db_dump_fill_record(struct radiusd_ipcp_db_dump *dump, int idx,
1425    struct assigned_ipv4 *assign)
1426{
1427	dump->records[idx].af = AF_INET;
1428	dump->records[idx].addr.ipv4 = assign->ipv4;
1429	dump->records[idx].rec.seq = assign->seq;
1430	strlcpy(dump->records[idx].rec.session_id, assign->session_id,
1431	    sizeof(dump->records[idx].rec.session_id));
1432	strlcpy(dump->records[idx].rec.auth_method, assign->auth_method,
1433	    sizeof(dump->records[idx].rec.auth_method));
1434	strlcpy(dump->records[idx].rec.username, assign->user->name,
1435	    sizeof(dump->records[idx].rec.username));
1436	dump->records[idx].rec.start = assign->start;
1437	dump->records[idx].rec.timeout = assign->timeout;
1438	dump->records[idx].rec.nas_ipv4 = assign->nas_ipv4;
1439	dump->records[idx].rec.nas_ipv6 = assign->nas_ipv6;
1440	strlcpy(dump->records[idx].rec.nas_id, assign->nas_id,
1441	    sizeof(dump->records[idx].rec.nas_id));
1442	if (assign->tun_type != NULL)
1443		strlcpy(dump->records[idx].rec.tun_type, assign->tun_type,
1444		    sizeof(dump->records[idx].rec.tun_type));
1445	memcpy(&dump->records[idx].rec.tun_client, &assign->tun_client,
1446	    sizeof(dump->records[idx].rec.tun_client));
1447}
1448
1449/***********************************************************************
1450 * Timer
1451 ***********************************************************************/
1452void
1453ipcp_on_timer(int fd, short ev, void *ctx)
1454{
1455	struct module_ipcp *self = ctx;
1456
1457	clock_gettime(CLOCK_BOOTTIME, &self->uptime);
1458	ipcp_schedule_timer(self);
1459}
1460
1461void
1462ipcp_schedule_timer(struct module_ipcp *self)
1463{
1464	struct assigned_ipv4	*assign, *min_assign = NULL;
1465	struct timespec		 tsd;
1466	struct timeval		 tv;
1467
1468	/* check session timeout */
1469	RB_FOREACH(assign, assigned_ipv4_tree, &self->ipv4s) {
1470		if (assign->timeout.tv_sec == 0)
1471			continue;
1472		if (timespeccmp(&assign->timeout, &self->uptime, <=)) {
1473			log_info("Reached session timeout seq=%u", assign->seq);
1474			ipcp_dae_send_disconnect_request(assign);
1475			memset(&assign->timeout, 0, sizeof(assign->timeout));
1476			ipcp_put_db(self, assign);
1477		}
1478		if (min_assign == NULL ||
1479		    timespeccmp(&min_assign->timeout, &assign->timeout, >))
1480			min_assign = assign;
1481	}
1482	if (evtimer_pending(&self->ev_timer, NULL))
1483		evtimer_del(&self->ev_timer);
1484
1485	if (min_assign != NULL) {
1486		timespecsub(&min_assign->timeout, &self->uptime, &tsd);
1487		TIMESPEC_TO_TIMEVAL(&tv, &tsd);
1488		evtimer_set(&self->ev_timer, ipcp_on_timer, self);
1489		evtimer_add(&self->ev_timer, &tv);
1490	}
1491}
1492
1493/***********************************************************************
1494 * Dynamic Authorization Extension for RAIDUS (RFC 5176)
1495 ***********************************************************************/
1496static const int dae_request_timeouts[] = { 2, 4, 8, 8 };
1497
1498void
1499ipcp_dae_send_disconnect_request(struct assigned_ipv4 *assign)
1500{
1501	RADIUS_PACKET		*reqpkt = NULL;
1502	struct timeval		 tv;
1503	char			 buf[80];
1504
1505	if (assign->dae == NULL)
1506		return;		/* DAE is not configured */
1507
1508	if (assign->dae_ntry == 0)
1509
1510	if (assign->dae_reqpkt != NULL) {
1511		radius_delete_packet(assign->dae_reqpkt);
1512		assign->dae_reqpkt = NULL;
1513	}
1514
1515	reqpkt = radius_new_request_packet(RADIUS_CODE_DISCONNECT_REQUEST);
1516
1517	radius_put_string_attr(reqpkt, RADIUS_TYPE_ACCT_SESSION_ID,
1518	    assign->session_id);
1519
1520	radius_set_accounting_request_authenticator(reqpkt,
1521	    assign->dae->secret);
1522
1523	if (radius_send(assign->dae->sock, reqpkt, 0) < 0)
1524		log_warn("%s: sendto: %m", __func__);
1525
1526	if (assign->dae_ntry == 0)
1527		log_info("Sending Disconnect-Request seq=%u to %s",
1528		    assign->seq, print_addr((struct sockaddr *)
1529		    &assign->dae->nas_addr, buf, sizeof(buf)));
1530
1531	assign->dae_reqpkt = reqpkt;
1532	tv.tv_sec = dae_request_timeouts[assign->dae_ntry];
1533	tv.tv_usec = 0;
1534	evtimer_set(&assign->dae_evtimer, ipcp_dae_request_on_timeout, assign);
1535	evtimer_add(&assign->dae_evtimer, &tv);
1536
1537	if (assign->dae_ntry++ == 0)
1538		TAILQ_INSERT_TAIL(&assign->dae->reqs, assign, dae_next);
1539}
1540
1541void
1542ipcp_dae_request_on_timeout(int fd, short ev, void *ctx)
1543{
1544	struct assigned_ipv4	*assign = ctx;
1545	char			 buf[80];
1546
1547	if (assign->dae_ntry >= (int)nitems(dae_request_timeouts))
1548		log_warnx("No answer for Disconnect-Request seq=%u from %s",
1549		    assign->seq, print_addr((struct sockaddr *)
1550		    &assign->dae->nas_addr, buf, sizeof(buf)));
1551	else
1552		ipcp_dae_send_disconnect_request(assign);
1553}
1554
1555void
1556ipcp_dae_on_event(int fd, short ev, void *ctx)
1557{
1558	struct module_ipcp_dae	*dae = ctx;
1559	RADIUS_PACKET		*radres = NULL;
1560	int			 code;
1561	uint32_t		 u32;
1562	struct assigned_ipv4	*assign;
1563	char			 buf[80], causestr[80];
1564	const char		*cause;
1565
1566	if ((ev & EV_READ) == 0)
1567		return;
1568
1569	if ((radres = radius_recv(dae->sock, 0)) == NULL) {
1570		if (errno == EAGAIN)
1571			return;
1572		log_warn("Failed to receive from %s", print_addr(
1573		    (struct sockaddr *)&dae->nas_addr, buf, sizeof(buf)));
1574		return;
1575	}
1576	TAILQ_FOREACH(assign, &dae->reqs, dae_next) {
1577		if (radius_get_id(assign->dae_reqpkt) == radius_get_id(radres))
1578			break;
1579	}
1580	if (assign == NULL) {
1581		log_warnx("Received RADIUS packet from %s has unknown id=%d",
1582		    print_addr((struct sockaddr *)&dae->nas_addr, buf,
1583		    sizeof(buf)), radius_get_id(radres));
1584		return;
1585	}
1586
1587	radius_set_request_packet(radres, assign->dae_reqpkt);
1588	if ((radius_check_response_authenticator(radres, dae->secret)) != 0) {
1589		log_warnx("Received RADIUS packet for seq=%u from %s has a bad "
1590		    "authenticator", assign->seq, print_addr(
1591			(struct sockaddr *)&dae->nas_addr, buf,
1592		    sizeof(buf)));
1593		return;
1594	}
1595	causestr[0] = '\0';
1596	if (radius_get_uint32_attr(radres, RADIUS_TYPE_ERROR_CAUSE, &u32) == 0){
1597		cause = radius_error_cause_string(u32);
1598		if (cause != NULL)
1599			snprintf(causestr, sizeof(causestr), " cause=%u(%s)",
1600			    u32, cause);
1601		else
1602			snprintf(causestr, sizeof(causestr), " cause=%u", u32);
1603	}
1604
1605	code = radius_get_code(radres);
1606	switch (code) {
1607	case RADIUS_CODE_DISCONNECT_ACK:
1608		log_info("Received Disconnect-ACK for seq=%u from %s%s",
1609		    assign->seq, print_addr((struct sockaddr *)
1610		    &dae->nas_addr, buf, sizeof(buf)), cause);
1611		evtimer_del(&assign->dae_evtimer);
1612		break;
1613	case RADIUS_CODE_DISCONNECT_NAK:
1614		log_warnx("Received Disconnect-NAK for seq=%u from %s%s",
1615		    assign->seq, print_addr((struct sockaddr *)
1616		    &dae->nas_addr, buf, sizeof(buf)), cause);
1617		evtimer_del(&assign->dae_evtimer);
1618		break;
1619	default:
1620		log_warn("Received unknown code=%d for id=%u from %s",
1621		    code, assign->seq, print_addr((struct sockaddr *)
1622		    &dae->nas_addr, buf, sizeof(buf)));
1623		break;
1624	}
1625}
1626
1627/***********************************************************************
1628 * Miscellaneous functions
1629 ***********************************************************************/
1630struct ipcp_address *
1631parse_address_range(const char *range)
1632{
1633	char			*buf, *sep;
1634	int			 masklen;
1635	uint32_t		 mask;
1636	struct in_addr		 start, end;
1637	struct ipcp_address	*ret;
1638	const char		*errstr;
1639
1640	buf = strdup(range);
1641	if (buf == NULL)
1642		goto error;
1643	if ((sep = strchr(buf, '-')) != NULL) {
1644		*sep = '\0';
1645		if (inet_aton(buf, &start) != 1)
1646			goto error;
1647		else if (inet_aton(++sep, &end) != 1)
1648			goto error;
1649		start.s_addr = ntohl(start.s_addr);
1650		end.s_addr = ntohl(end.s_addr);
1651	} else {
1652		if ((sep = strchr(buf, '/')) != NULL) {
1653			*sep = '\0';
1654			if (inet_aton(buf, &start) != 1)
1655				goto error;
1656			masklen = strtonum(++sep, 0, 32, &errstr);
1657			if (errstr != NULL)
1658				goto error;
1659		} else {
1660			if (inet_aton(buf, &start) != 1)
1661				goto error;
1662			masklen = 32;
1663		}
1664		mask = 0xFFFFFFFFUL;
1665		if (masklen < 32)
1666			mask <<= (32 - masklen);
1667		start.s_addr = ntohl(start.s_addr) & mask;
1668		if (masklen == 32)
1669			end = start;
1670		else if (masklen == 31)
1671			end.s_addr = start.s_addr + 1;
1672		else {
1673			end.s_addr = start.s_addr + (1 << (32 - masklen)) - 2;
1674			start.s_addr = start.s_addr + 1;
1675		}
1676	}
1677	free(buf);
1678	if ((ret = calloc(1, sizeof(struct ipcp_address))) == NULL)
1679		return (NULL);
1680	ret->start = start;
1681	ret->end = end;
1682	ret->naddrs = end.s_addr - start.s_addr + 1;
1683	return (ret);
1684 error:
1685	free(buf);
1686	return (NULL);
1687}
1688
1689const char *
1690radius_tunnel_type_string(unsigned val, const char *label)
1691{
1692	unsigned int		 i;
1693	struct {
1694		const unsigned	 constval;
1695		const char	*label;
1696	} tunnel_types[] = {
1697		{ RADIUS_TUNNEL_TYPE_PPTP,	"PPTP" },
1698		{ RADIUS_TUNNEL_TYPE_L2F,	"L2F" },
1699		{ RADIUS_TUNNEL_TYPE_L2TP,	"L2TP" },
1700		{ RADIUS_TUNNEL_TYPE_ATMP,	"ATMP" },
1701		{ RADIUS_TUNNEL_TYPE_VTP,	"VTP" },
1702		{ RADIUS_TUNNEL_TYPE_AH,	"AH" },
1703		{ RADIUS_TUNNEL_TYPE_IP,	"IP" },
1704		{ RADIUS_TUNNEL_TYPE_MOBILE,	"MIN-IP-IP" },
1705		{ RADIUS_TUNNEL_TYPE_ESP,	"ESP" },
1706		{ RADIUS_TUNNEL_TYPE_GRE,	"GRE" },
1707		{ RADIUS_TUNNEL_TYPE_VDS,	"DVS" },
1708		/* [MS-RNAS] 3.3.5.1.9 Tunnel-Type */
1709		{ RADIUS_VENDOR_MICROSOFT << 8 | 1,
1710						"SSTP" }
1711	};
1712
1713	if (label != NULL) {	/* for conversion to the const value */
1714		for (i = 0; i < nitems(tunnel_types); i++) {
1715			if (strcmp(tunnel_types[i].label, label) == 0)
1716				return (tunnel_types[i].label);
1717		}
1718	}
1719
1720	for (i = 0; i < nitems(tunnel_types); i++) {
1721		if (tunnel_types[i].constval == val)
1722			return (tunnel_types[i].label);
1723	}
1724
1725	return (NULL);
1726}
1727
1728const char *
1729radius_terminate_cause_string(unsigned val)
1730{
1731	unsigned int		 i;
1732	struct {
1733		const unsigned	 constval;
1734		const char	*label;
1735	} terminate_causes[] = {
1736	    { RADIUS_TERMNATE_CAUSE_USER_REQUEST,	"User Request" },
1737	    { RADIUS_TERMNATE_CAUSE_LOST_CARRIER,	"Lost Carrier" },
1738	    { RADIUS_TERMNATE_CAUSE_LOST_SERVICE,	"Lost Service" },
1739	    { RADIUS_TERMNATE_CAUSE_IDLE_TIMEOUT,	"Idle Timeout" },
1740	    { RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT,	"Session Timeout" },
1741	    { RADIUS_TERMNATE_CAUSE_ADMIN_RESET,	"Admin Reset" },
1742	    { RADIUS_TERMNATE_CAUSE_ADMIN_REBOOT,	"Admin Reboot" },
1743	    { RADIUS_TERMNATE_CAUSE_PORT_ERROR,		"Port Error" },
1744	    { RADIUS_TERMNATE_CAUSE_NAS_ERROR,		"NAS Error" },
1745	    { RADIUS_TERMNATE_CAUSE_NAS_RESET,		"NAS Request" },
1746	    { RADIUS_TERMNATE_CAUSE_NAS_REBOOT,		"NAS Reboot" },
1747	    { RADIUS_TERMNATE_CAUSE_PORT_UNNEEDED,	"Port Unneeded" },
1748	    { RADIUS_TERMNATE_CAUSE_PORT_PREEMPTED,	"Port Preempted" },
1749	    { RADIUS_TERMNATE_CAUSE_PORT_SUSPENDED,	"Port Suspended" },
1750	    { RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL,	"Service Unavailable" },
1751	    { RADIUS_TERMNATE_CAUSE_CALLBACK,		"Callback" },
1752	    { RADIUS_TERMNATE_CAUSE_USER_ERROR,		"User Error" },
1753	    { RADIUS_TERMNATE_CAUSE_HOST_REQUEST,	"Host Request" },
1754	};
1755
1756	for (i = 0; i < nitems(terminate_causes); i++) {
1757		if (terminate_causes[i].constval == val)
1758			return (terminate_causes[i].label);
1759	}
1760
1761	return (NULL);
1762}
1763
1764const char *
1765radius_error_cause_string(unsigned val)
1766{
1767	unsigned int		 i;
1768	struct {
1769		const unsigned	 constval;
1770		const char	*label;
1771	} error_causes[] = {
1772	    { RADIUS_ERROR_CAUSE_RESIDUAL_SESSION_REMOVED,
1773	      "Residual Session Context Removed" },
1774	    { RADIUS_ERROR_CAUSE_INVALID_EAP_PACKET,
1775	      "Invalid EAP Packet (Ignored)" },
1776	    { RADIUS_ERROR_CAUSE_UNSUPPORTED_ATTRIBUTE,
1777	      "Unsupported Attribute" },
1778	    { RADIUS_ERROR_CAUSE_MISSING_ATTRIBUTE,
1779	      "Missing Attribute" },
1780	    { RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH,
1781	      "NAS Identification Mismatch" },
1782	    { RADIUS_ERROR_CAUSE_INVALID_REQUEST,
1783	      "Invalid Request" },
1784	    { RADIUS_ERROR_CAUSE_UNSUPPORTED_SERVICE,
1785	      "Unsupported Service" },
1786	    { RADIUS_ERROR_CAUSE_UNSUPPORTED_EXTENSION,
1787	      "Unsupported Extension" },
1788	    { RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE,
1789	      "Invalid Attribute Valu" },
1790	    { RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED,
1791	      "Administratively Prohibited" },
1792	    { RADIUS_ERROR_CAUSE_REQUEST_NOT_ROUTABLE,
1793	      "Request Not Routable (Proxy)" },
1794	    { RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND,
1795	      "Session Context Not Found" },
1796	    { RADIUS_ERROR_CAUSE_SESSION_NOT_REMOVABLE,
1797	      "Session Context Not Removable" },
1798	    { RADIUS_ERROR_CAUSE_OTHER_PROXY_PROCESSING_ERROR,
1799	      "Other Proxy Processing Error" },
1800	    { RADIUS_ERROR_CAUSE_RESOURCES_UNAVAILABLE,
1801	      "Resources Unavailable" },
1802	    { RADIUS_ERROR_CAUSE_REQUEST_INITIATED,
1803	      "equest Initiated" },
1804	    { RADIUS_ERROR_CAUSE_MULTI_SELECTION_UNSUPPORTED,
1805	      "Multiple Session Selection Unsupported" }
1806	};
1807
1808	for (i = 0; i < nitems(error_causes); i++) {
1809		if (error_causes[i].constval == val)
1810			return (error_causes[i].label);
1811	}
1812
1813	return (NULL);
1814}
1815
1816int
1817parse_addr(const char *str0, int af, struct sockaddr *sa, socklen_t salen)
1818{
1819	int		 error;
1820	char		*str, *end, *colon, *colon0, *addr = NULL, *port = NULL;
1821	char		*sb, *sb0;
1822	struct addrinfo	 hints, *ai;
1823
1824	if ((str = strdup(str0)) == NULL)
1825		return (-1);
1826	if (*str == '[' && (end = strchr(str + 1, ']')) != NULL) {
1827		addr = str + 1;
1828		*end = '\0';
1829		if (*(end + 1) == ':')
1830			port = end + 2;
1831		else if (*(end + 1) == '[' && (sb = strrchr(end + 2, ']'))
1832		    != NULL) {
1833			port = end + 2;
1834			*sb = '\0';
1835		}
1836	} else if ((sb0 = strchr(str, '[')) != NULL &&
1837	    (sb = strrchr(sb0 + 1, ']')) != NULL && sb0 < sb) {
1838		addr = str;
1839		*sb0 = '\0';
1840		port = sb0 + 1;
1841		*sb = '\0';
1842	} else if ((colon0 = strchr(str, ':')) != NULL &&
1843	    (colon = strrchr(str, ':')) != NULL && colon0 == colon) {
1844		/* has one : */
1845		addr = str;
1846		*colon = '\0';
1847		port = colon + 1;
1848	} else {
1849		addr = str;
1850		port = NULL;
1851	}
1852
1853	memset(&hints, 0, sizeof(hints));
1854	hints.ai_family = af;
1855	hints.ai_socktype = SOCK_DGRAM;
1856	hints.ai_flags = AI_NUMERICHOST;
1857	if (port != NULL)
1858		hints.ai_flags |= AI_NUMERICSERV;
1859	if ((error = getaddrinfo(addr, port, &hints, &ai)) != 0) {
1860		free(str);
1861		return (-1);
1862	}
1863	if (salen < ai->ai_addrlen) {
1864		freeaddrinfo(ai);
1865		free(str);
1866		return (-1);
1867	}
1868	memcpy(sa, ai->ai_addr, ai->ai_addrlen);
1869	freeaddrinfo(ai);
1870
1871	return (0);
1872}
1873
1874const char *
1875print_addr(struct sockaddr *sa, char *buf, size_t bufsiz)
1876{
1877	int	noport, ret;
1878	char	hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
1879
1880	if (ntohs(((struct sockaddr_in *)sa)->sin_port) == 0) {
1881		noport = 1;
1882		ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
1883		    NI_NUMERICHOST);
1884	} else {
1885		noport = 0;
1886		ret = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf,
1887		    sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV);
1888	}
1889	if (ret != 0)
1890		return "";
1891	if (noport)
1892		strlcpy(buf, hbuf, bufsiz);
1893	else if (sa->sa_family == AF_INET6)
1894		snprintf(buf, bufsiz, "[%s]:%s", hbuf, sbuf);
1895	else
1896		snprintf(buf, bufsiz, "%s:%s", hbuf, sbuf);
1897
1898	return (buf);
1899}
1900