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