radius.c revision 1.3
1/*	$OpenBSD: radius.c,v 1.3 2024/07/13 12:22:46 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 <arpa/inet.h>
24#include <netinet/ip_ipsp.h>
25
26#include <endian.h>
27#include <event.h>
28#include <errno.h>
29#include <imsg.h>
30#include <limits.h>
31#include <netinet/in.h>
32#include <radius.h>
33#include <stdint.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <strings.h>
38#include <time.h>
39
40#include "iked.h"
41#include "eap.h"
42#include "ikev2.h"
43#include "types.h"
44
45void	 iked_radius_request_send(struct iked *, void *);
46void	 iked_radius_fill_attributes(struct iked_sa *, RADIUS_PACKET *);
47void	 iked_radius_config(struct iked_radserver_req *, const RADIUS_PACKET *,
48	    int, uint32_t, uint8_t);
49void	 iked_radius_acct_request(struct iked *, struct iked_sa *, uint8_t);
50
51const struct iked_radcfgmap radius_cfgmaps[] = {
52    { IKEV2_CFG_INTERNAL_IP4_ADDRESS, 0, RADIUS_TYPE_FRAMED_IP_ADDRESS },
53    { IKEV2_CFG_INTERNAL_IP4_NETMASK, 0, RADIUS_TYPE_FRAMED_IP_NETMASK },
54    { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT,
55	RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER },
56    { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT,
57	RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER },
58    { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT,
59	RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER },
60    { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT,
61	RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER },
62    { 0 }
63};
64
65int
66iked_radius_request(struct iked *env, struct iked_sa *sa,
67    struct iked_message *msg)
68{
69	struct eap_message		*eap;
70	RADIUS_PACKET			*pkt;
71	size_t				 len;
72
73	eap = ibuf_data(msg->msg_eapmsg);
74	len = betoh16(eap->eap_length);
75	if (eap->eap_code != EAP_CODE_RESPONSE) {
76		log_debug("%s: eap_code is not response %u", __func__,
77		    (unsigned)eap->eap_code);
78		return -1;
79	}
80
81	if (eap->eap_type == EAP_TYPE_IDENTITY) {
82		if ((sa->sa_radreq = calloc(1,
83		    sizeof(struct iked_radserver_req))) == NULL) {
84			log_debug(
85			    "%s: calloc failed for iked_radserver_req: %s",
86			    __func__, strerror(errno));
87			return (-1);
88		}
89		timer_set(env, &sa->sa_radreq->rr_timer,
90		    iked_radius_request_send, sa->sa_radreq);
91		sa->sa_radreq->rr_user = strdup(msg->msg_eap.eam_identity);
92	}
93
94	if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST))
95	    == NULL) {
96		log_debug("%s: radius_new_request_packet failed %s", __func__,
97		    strerror(errno));
98		return -1;
99	}
100
101	radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME,
102	    sa->sa_radreq->rr_user);
103	if (sa->sa_radreq->rr_state != NULL)
104		radius_put_raw_attr(pkt, RADIUS_TYPE_STATE,
105		    ibuf_data(sa->sa_radreq->rr_state),
106		    ibuf_size(sa->sa_radreq->rr_state));
107
108	if (radius_put_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE,
109	    (uint8_t *)eap, len) == -1) {
110		log_debug("%s: radius_put_raw_attr_cat failed %s", __func__,
111		    strerror(errno));
112		return -1;
113	}
114
115	iked_radius_fill_attributes(sa, pkt);
116
117	/* save the request, it'll be needed for message authentication */
118	if (sa->sa_radreq->rr_reqpkt != NULL)
119		radius_delete_packet(sa->sa_radreq->rr_reqpkt);
120	sa->sa_radreq->rr_reqpkt = pkt;
121	sa->sa_radreq->rr_sa = sa;
122	sa->sa_radreq->rr_ntry = 0;
123
124	iked_radius_request_send(env, sa->sa_radreq);
125
126	return 0;
127}
128
129void
130iked_radius_request_free(struct iked *env, struct iked_radserver_req *req)
131{
132	if (req == NULL)
133		return;
134	timer_del(env, &req->rr_timer);
135	free(req->rr_user);
136	ibuf_free(req->rr_state);
137	if (req->rr_reqpkt)
138		radius_delete_packet(req->rr_reqpkt);
139	if (req->rr_sa)
140		req->rr_sa->sa_radreq = NULL;
141	if (req->rr_server)
142		TAILQ_REMOVE(&req->rr_server->rs_reqs, req, rr_entry);
143	free(req);
144}
145
146void
147iked_radius_on_event(int fd, short ev, void *ctx)
148{
149	struct iked			*env;
150	struct iked_radserver		*server = ctx;
151	struct iked_radserver_req	*req;
152	const struct iked_radcfgmap	*cfgmap;
153	RADIUS_PACKET			*pkt;
154	int				 i, resid;
155	struct ibuf			*e;
156	const void			*attrval;
157	size_t				 attrlen;
158	uint8_t				 code;
159	char				 username[256];
160	u_char				 eapmsk[128];
161	/* RFC 3748 defines the MSK minimum size is 64 bytes */
162	size_t				 eapmsksiz = sizeof(eapmsk);
163
164	env = server->rs_env;
165	pkt = radius_recv(server->rs_sock, 0);
166	if (pkt == NULL) {
167		log_info("%s: receiving a RADIUS message failed: %s", __func__,
168		    strerror(errno));
169		return;
170	}
171	resid = radius_get_id(pkt);
172
173	TAILQ_FOREACH(req, &server->rs_reqs, rr_entry) {
174		if (req->rr_reqid == resid)
175			break;
176	}
177	if (req == NULL) {
178		log_debug("%s: received an unknown RADIUS message: id=%u",
179		    __func__, (unsigned)resid);
180		return;
181	}
182
183	radius_set_request_packet(pkt, req->rr_reqpkt);
184	if (radius_check_response_authenticator(pkt, server->rs_secret) != 0) {
185		log_info("%s: received an invalid RADIUS message: bad "
186		    "response authenticator", __func__);
187		return;
188	}
189	if (req->rr_accounting) {
190		/* accounting */
191		code = radius_get_code(pkt);
192		switch (code) {
193		case RADIUS_CODE_ACCOUNTING_RESPONSE: /* Expected */
194			break;
195		default:
196			log_info("%s: received an invalid RADIUS message: "
197			    "code %u", __func__, (unsigned)code);
198		}
199		timer_del(env, &req->rr_timer);
200		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
201		req->rr_server = NULL;
202		free(req);
203		return;
204	}
205
206	/* authentication */
207	if (radius_check_message_authenticator(pkt, server->rs_secret) != 0) {
208		log_info("%s: received an invalid RADIUS message: bad "
209		    "message authenticator", __func__);
210		return;
211	}
212
213	timer_del(env, &req->rr_timer);
214	req->rr_ntry = 0;
215
216	if (req->rr_sa == NULL)
217		goto fail;
218
219	code = radius_get_code(pkt);
220	switch (code) {
221	case RADIUS_CODE_ACCESS_CHALLENGE:
222		if (radius_get_raw_attr_ptr(pkt, RADIUS_TYPE_STATE, &attrval,
223		    &attrlen) != 0) {
224			log_info("%s: received an invalid RADIUS message: no "
225			    "state attribute", __func__);
226			goto fail;
227		}
228		if ((req->rr_state != NULL &&
229		    ibuf_set(req->rr_state, 0, attrval, attrlen) != 0) ||
230		    (req->rr_state = ibuf_new(attrval, attrlen)) == NULL) {
231			log_info("%s: ibuf_new() failed: %s", __func__,
232			    strerror(errno));
233			goto fail;
234		}
235		break;
236	case RADIUS_CODE_ACCESS_ACCEPT:
237		log_info("%s: received Access-Accept for %s",
238		    SPI_SA(req->rr_sa, __func__), req->rr_user);
239		/* Try to retrieve the EAP MSK from the RADIUS response */
240		if (radius_get_eap_msk(pkt, eapmsk, &eapmsksiz,
241		    server->rs_secret) == 0) {
242			ibuf_free(req->rr_sa->sa_eapmsk);
243			if ((req->rr_sa->sa_eapmsk = ibuf_new(eapmsk,
244			    eapmsksiz)) == NULL) {
245				log_info("%s: ibuf_new() failed: %s", __func__,
246				    strerror(errno));
247				goto fail;
248			}
249		} else
250			log_debug("Could not retrieve the EAP MSK from the "
251			    "RADIUS message");
252
253		free(req->rr_sa->sa_eapid);
254		/* The EAP identity might be protected (RFC 3748 7.3) */
255		if (radius_get_string_attr(pkt, RADIUS_TYPE_USER_NAME,
256		    username, sizeof(username)) == 0 &&
257		    strcmp(username, req->rr_user) != 0) {
258			/*
259			 * The Access-Accept might have a User-Name.  It
260			 * should be used for Accouting (RFC 2865 5.1).
261			 */
262			free(req->rr_user);
263			req->rr_sa->sa_eapid = strdup(username);
264		} else
265			req->rr_sa->sa_eapid = req->rr_user;
266		req->rr_user = NULL;
267
268		sa_state(env, req->rr_sa, IKEV2_STATE_AUTH_SUCCESS);
269
270		/* Map RADIUS attributes to cp */
271		if (TAILQ_EMPTY(&env->sc_radcfgmaps)) {
272			for (i = 0; radius_cfgmaps[i].cfg_type != 0; i++) {
273				cfgmap = &radius_cfgmaps[i];
274				iked_radius_config(req, pkt, cfgmap->cfg_type,
275				    cfgmap->vendor_id, cfgmap->attr_type);
276			}
277		} else {
278			TAILQ_FOREACH(cfgmap, &env->sc_radcfgmaps, entry)
279				iked_radius_config(req, pkt, cfgmap->cfg_type,
280				    cfgmap->vendor_id, cfgmap->attr_type);
281		}
282
283		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
284		req->rr_server = NULL;
285		break;
286	case RADIUS_CODE_ACCESS_REJECT:
287		log_info("%s: received Access-Reject for %s",
288		    SPI_SA(req->rr_sa, __func__), req->rr_user);
289		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
290		req->rr_server = NULL;
291		break;
292	default:
293		log_debug("%s: received an invalid RADIUS message: code %u",
294		    __func__, (unsigned)code);
295		break;
296	}
297
298	/* get the length first */
299	if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, NULL,
300	    &attrlen) != 0) {
301		log_info("%s: failed to retrieve the EAP message", __func__);
302		goto fail;
303	}
304	/* allocate a buffer */
305	if ((e = ibuf_new(NULL, attrlen)) == NULL) {
306		log_info("%s: ibuf_new() failed: %s", __func__,
307		    strerror(errno));
308		goto fail;
309	}
310	/* copy the message to the buffer */
311	if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE,
312	    ibuf_data(e), &attrlen) != 0) {
313		ibuf_free(e);
314		log_info("%s: failed to retrieve the EAP message", __func__);
315		goto fail;
316	}
317	ikev2_send_ike_e(env, req->rr_sa, e, IKEV2_PAYLOAD_EAP,
318	    IKEV2_EXCHANGE_IKE_AUTH, 1);
319	return;
320 fail:
321	if (req->rr_server != NULL)
322		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
323	req->rr_server = NULL;
324	if (req->rr_sa != NULL) {
325		ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed");
326		sa_free(env, req->rr_sa);
327	}
328}
329
330void
331iked_radius_request_send(struct iked *env, void *ctx)
332{
333	struct iked_radserver_req	*req = ctx, *req0;
334	struct iked_radserver		*server = req->rr_server;
335	const int			 timeouts[] = { 2, 4, 8 };
336	uint8_t				 seq;
337	int				 i, max_tries, max_failovers;
338	struct sockaddr_storage		 ss;
339	socklen_t			 sslen;
340	struct iked_radservers		*radservers;
341	struct timespec			 now;
342
343	if (!req->rr_accounting) {
344		max_tries = env->sc_radauth.max_tries;
345		max_failovers = env->sc_radauth.max_failovers;
346		radservers = &env->sc_radauthservers;
347	} else {
348		max_tries = env->sc_radacct.max_tries;
349		max_failovers = env->sc_radacct.max_failovers;
350		radservers = &env->sc_radacctservers;
351	}
352
353	if (req->rr_ntry > max_tries) {
354		req->rr_ntry = 0;
355		log_info("%s: RADIUS server %s failed", __func__,
356		    print_addr(&server->rs_sockaddr));
357 next_server:
358		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
359		req->rr_server = NULL;
360		if (req->rr_nfailover >= max_failovers ||
361		    TAILQ_NEXT(server, rs_entry) == NULL) {
362			log_info("%s: No more RADIUS server", __func__);
363			goto fail;
364		} else if (req->rr_state != NULL) {
365			log_info("%s: Can't change RADIUS server: "
366			    "client has a state already", __func__);
367			goto fail;
368		} else {
369			TAILQ_REMOVE(radservers, server, rs_entry);
370			TAILQ_INSERT_TAIL(radservers, server, rs_entry);
371			server = TAILQ_FIRST(radservers);
372			log_info("%s: RADIUS server %s is active",
373			    __func__, print_addr(&server->rs_sockaddr));
374		}
375		req->rr_nfailover++;
376	}
377
378	if (req->rr_server != NULL &&
379	    req->rr_server != TAILQ_FIRST(radservers)) {
380		/* Current server is marked fail */
381		if (req->rr_state != NULL || req->rr_nfailover >= max_failovers)
382			goto fail; /* can't fail over */
383		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
384		req->rr_server = NULL;
385		req->rr_nfailover++;
386	}
387
388	if (req->rr_server == NULL) {
389		/* Select a new server */
390		server = TAILQ_FIRST(radservers);
391		if (server == NULL) {
392			log_info("%s: No RADIUS server is configured",
393			    __func__);
394			goto fail;
395		}
396		TAILQ_INSERT_TAIL(&server->rs_reqs, req, rr_entry);
397		req->rr_server = server;
398
399		/* Prepare NAS-IP-Address */
400		if (server->rs_nas_ipv4.s_addr == INADDR_ANY &&
401		    IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6)) {
402			sslen = sizeof(ss);
403			if (getsockname(server->rs_sock, (struct sockaddr *)&ss,
404			    &sslen) == 0) {
405				if (ss.ss_family == AF_INET)
406					server->rs_nas_ipv4 =
407					    ((struct sockaddr_in *)&ss)
408					    ->sin_addr;
409				else
410					server->rs_nas_ipv6 =
411					    ((struct sockaddr_in6 *)&ss)
412					    ->sin6_addr;
413			}
414		}
415	}
416	if (req->rr_ntry == 0) {
417		/* decide the ID */
418		seq = ++server->rs_reqseq;
419		for (i = 0; i < UCHAR_MAX; i++) {
420			TAILQ_FOREACH(req0, &server->rs_reqs, rr_entry) {
421				if (req0->rr_reqid == seq)
422					break;
423			}
424			if (req0 == NULL)
425				break;
426			seq++;
427		}
428		if (i >= UCHAR_MAX) {
429			log_info("%s: RADIUS server %s failed.  Too many "
430			    "pending requests", __func__,
431			    print_addr(&server->rs_sockaddr));
432			if (TAILQ_NEXT(server, rs_entry) != NULL)
433				goto next_server;
434			goto fail;
435		}
436		req->rr_reqid = seq;
437		radius_set_id(req->rr_reqpkt, req->rr_reqid);
438	}
439
440	if (server->rs_nas_ipv4.s_addr != INADDR_ANY)
441		radius_put_ipv4_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IP_ADDRESS,
442		    server->rs_nas_ipv4);
443	else if (!IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6))
444		radius_put_ipv6_attr(req->rr_reqpkt,
445		    RADIUS_TYPE_NAS_IPV6_ADDRESS, &server->rs_nas_ipv6);
446	/* Identifier */
447	radius_put_string_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IDENTIFIER,
448	    IKED_NAS_ID);
449
450	if (req->rr_accounting) {
451		if (req->rr_ntry == 0 && req->rr_nfailover == 0)
452			radius_put_uint32_attr(req->rr_reqpkt,
453			    RADIUS_TYPE_ACCT_DELAY_TIME, 0);
454		else {
455			clock_gettime(CLOCK_MONOTONIC, &now);
456			timespecsub(&now, &req->rr_accttime, &now);
457			radius_put_uint32_attr(req->rr_reqpkt,
458			    RADIUS_TYPE_ACCT_DELAY_TIME, now.tv_sec);
459		}
460		radius_set_accounting_request_authenticator(req->rr_reqpkt,
461		    server->rs_secret);
462	} else {
463		radius_put_message_authenticator(req->rr_reqpkt,
464		    server->rs_secret);
465	}
466
467	if (radius_send(server->rs_sock, req->rr_reqpkt, 0) < 0)
468		log_info("%s: sending a RADIUS message failed: %s", __func__,
469		    strerror(errno));
470
471	if (req->rr_ntry >= (int)nitems(timeouts))
472		timer_add(env, &req->rr_timer, timeouts[nitems(timeouts) - 1]);
473	else
474		timer_add(env, &req->rr_timer, timeouts[req->rr_ntry]);
475	req->rr_ntry++;
476	return;
477 fail:
478	if (req->rr_server != NULL)
479		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
480	req->rr_server = NULL;
481	if (req->rr_sa != NULL) {
482		ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed");
483		sa_free(env, req->rr_sa);
484	}
485}
486
487void
488iked_radius_fill_attributes(struct iked_sa *sa, RADIUS_PACKET *pkt)
489{
490	/* NAS Port Type = Virtual */
491	radius_put_uint32_attr(pkt,
492	    RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL);
493	/* Service Type =  Framed */
494	radius_put_uint32_attr(pkt, RADIUS_TYPE_SERVICE_TYPE,
495	    RADIUS_SERVICE_TYPE_FRAMED);
496	/* Tunnel Type = EAP */
497	radius_put_uint32_attr(pkt, RADIUS_TYPE_TUNNEL_TYPE,
498	    RADIUS_TUNNEL_TYPE_ESP);
499
500	radius_put_string_attr(pkt, RADIUS_TYPE_CALLED_STATION_ID,
501	    print_addr(&sa->sa_local.addr));
502	radius_put_string_attr(pkt, RADIUS_TYPE_CALLING_STATION_ID,
503	    print_addr(&sa->sa_peer.addr));
504}
505
506void
507iked_radius_config(struct iked_radserver_req *req, const RADIUS_PACKET *pkt,
508    int cfg_type, uint32_t vendor_id, uint8_t attr_type)
509{
510	unsigned int		 i;
511	struct iked_sa		*sa = req->rr_sa;
512	struct in_addr		 ia4;
513	struct in6_addr		 ia6;
514	struct sockaddr_in	*sin4;
515	struct sockaddr_in6	*sin6;
516	struct iked_addr	*addr;
517	struct iked_cfg		*ikecfg;
518
519	for (i = 0; i < sa->sa_policy->pol_ncfg; i++) {
520		ikecfg = &sa->sa_policy->pol_cfg[i];
521		if (ikecfg->cfg_type == cfg_type &&
522		    ikecfg->cfg_type != IKEV2_CFG_INTERNAL_IP4_ADDRESS)
523			return;	/* use config rather than radius */
524	}
525	switch (cfg_type) {
526	case IKEV2_CFG_INTERNAL_IP4_ADDRESS:
527	case IKEV2_CFG_INTERNAL_IP4_NETMASK:
528	case IKEV2_CFG_INTERNAL_IP4_DNS:
529	case IKEV2_CFG_INTERNAL_IP4_NBNS:
530	case IKEV2_CFG_INTERNAL_IP4_DHCP:
531	case IKEV2_CFG_INTERNAL_IP4_SERVER:
532		if (vendor_id == 0 && radius_has_attr(pkt, attr_type))
533			radius_get_ipv4_attr(pkt, attr_type, &ia4);
534		else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id,
535		    attr_type))
536			radius_get_vs_ipv4_attr(pkt, vendor_id, attr_type,
537			    &ia4);
538		else
539			break; /* no attribute contained */
540
541		if (cfg_type == IKEV2_CFG_INTERNAL_IP4_NETMASK) {
542			/*
543			 * This assumes IKEV2_CFG_INTERNAL_IP4_ADDRESS is
544			 * called before IKEV2_CFG_INTERNAL_IP4_NETMASK
545			 */
546			if (sa->sa_rad_addr == NULL) {
547				/*
548				 * RFC 7296, IKEV2_CFG_INTERNAL_IP4_NETMASK
549				 * must be used with
550				 * IKEV2_CFG_INTERNAL_IP4_ADDRESS
551				 */
552				break;
553			}
554			if (ia4.s_addr == 0) {
555				log_debug("%s: netmask is wrong", __func__);
556				break;
557			}
558			if (ia4.s_addr == htonl(0))
559				sa->sa_rad_addr->addr_mask = 0;
560			else
561				sa->sa_rad_addr->addr_mask =
562				    33 - ffs(ntohl(ia4.s_addr));
563			if (sa->sa_rad_addr->addr_mask < 32)
564				sa->sa_rad_addr->addr_net = 1;
565		}
566		if (cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS) {
567			if ((addr = calloc(1, sizeof(*addr))) == NULL) {
568				log_warn("%s: calloc", __func__);
569				return;
570			}
571			sa->sa_rad_addr = addr;
572		} else {
573			req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY;
574			req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type;
575			addr = &req->rr_cfg[req->rr_ncfg].cfg.address;
576			req->rr_ncfg++;
577		}
578		addr->addr_af = AF_INET;
579		sin4 = (struct sockaddr_in *)&addr->addr;
580		sin4->sin_family = AF_INET;
581		sin4->sin_len = sizeof(struct sockaddr_in);
582		sin4->sin_addr = ia4;
583		break;
584	case IKEV2_CFG_INTERNAL_IP6_ADDRESS:
585	case IKEV2_CFG_INTERNAL_IP6_DNS:
586	case IKEV2_CFG_INTERNAL_IP6_NBNS:
587	case IKEV2_CFG_INTERNAL_IP6_DHCP:
588	case IKEV2_CFG_INTERNAL_IP6_SERVER:
589		if (vendor_id == 0 && radius_has_attr(pkt, attr_type))
590			radius_get_ipv6_attr(pkt, attr_type, &ia6);
591		else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id,
592		    attr_type))
593			radius_get_vs_ipv6_attr(pkt, vendor_id, attr_type,
594			    &ia6);
595		else
596			break; /* no attribute contained */
597
598		if (cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS) {
599			if ((addr = calloc(1, sizeof(*addr))) == NULL) {
600				log_warn("%s: calloc", __func__);
601				return;
602			}
603			sa->sa_rad_addr = addr;
604		} else {
605			req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY;
606			req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type;
607			addr = &req->rr_cfg[req->rr_ncfg].cfg.address;
608			req->rr_ncfg++;
609		}
610		addr->addr_af = AF_INET;
611		sin6 = (struct sockaddr_in6 *)&addr->addr;
612		sin6->sin6_family = AF_INET6;
613		sin6->sin6_len = sizeof(struct sockaddr_in6);
614		sin6->sin6_addr = ia6;
615		break;
616	}
617	return;
618}
619
620void
621iked_radius_acct_on(struct iked *env)
622{
623	if (TAILQ_EMPTY(&env->sc_radacctservers))
624		return;
625	if (env->sc_radaccton == 0) {	/* trigger once */
626		iked_radius_acct_request(env, NULL,
627		    RADIUS_ACCT_STATUS_TYPE_ACCT_ON);
628		env->sc_radaccton = 1;
629	}
630}
631
632void
633iked_radius_acct_off(struct iked *env)
634{
635	iked_radius_acct_request(env, NULL, RADIUS_ACCT_STATUS_TYPE_ACCT_OFF);
636}
637
638void
639iked_radius_acct_start(struct iked *env, struct iked_sa *sa)
640{
641	iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_START);
642}
643
644void
645iked_radius_acct_stop(struct iked *env, struct iked_sa *sa)
646{
647	iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_STOP);
648}
649
650void
651iked_radius_acct_request(struct iked *env, struct iked_sa *sa, uint8_t stype)
652{
653	struct iked_radserver_req	*req;
654	RADIUS_PACKET			*pkt;
655	struct iked_addr		*addr4 = NULL;
656	struct iked_addr		*addr6 = NULL;
657	struct in_addr			 mask4;
658	char				 sa_id[IKED_ID_SIZE];
659	char				 sid[16 + 1];
660	struct timespec			 now;
661	int				 cause;
662
663	if (TAILQ_EMPTY(&env->sc_radacctservers))
664		return;
665	/*
666	 * In RFC2866 5.6, "Users who are delivered service without
667	 * being authenticated SHOULD NOT generate Accounting records
668	 */
669	if (sa != NULL && sa->sa_eapid == NULL) {
670		/* fallback to IKEID for accounting */
671		if (ikev2_print_id(IKESA_DSTID(sa), sa_id, sizeof(sa_id)) != -1)
672			sa->sa_eapid = strdup(sa_id);
673		if (sa->sa_eapid == NULL)
674			return;
675	}
676
677	if ((req = calloc(1, sizeof(struct iked_radserver_req))) == NULL) {
678		log_debug("%s: calloc faile for iked_radserver_req: %s",
679		    __func__, strerror(errno));
680		return;
681	}
682	req->rr_accounting = 1;
683	clock_gettime(CLOCK_MONOTONIC, &now);
684	req->rr_accttime = now;
685	timer_set(env, &req->rr_timer, iked_radius_request_send, req);
686
687	if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST))
688	    == NULL) {
689		log_debug("%s: radius_new_request_packet failed %s", __func__,
690		    strerror(errno));
691		return;
692	}
693
694	/* RFC 2866  5.1. Acct-Status-Type */
695	radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE, stype);
696
697	if (sa == NULL) {
698		/* ASSERT(stype == RADIUS_ACCT_STATUS_TYPE_ACCT_ON ||
699		    stype == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) */
700		req->rr_reqpkt = pkt;
701		req->rr_ntry = 0;
702		iked_radius_request_send(env, req);
703		return;
704	}
705
706	iked_radius_fill_attributes(sa, pkt);
707
708	radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME, sa->sa_eapid);
709
710	/* RFC 2866  5.5. Acct-Session-Id */
711	snprintf(sid, sizeof(sid), "%016llx",
712	    (unsigned long long)sa->sa_hdr.sh_ispi);
713	radius_put_string_attr(pkt, RADIUS_TYPE_ACCT_SESSION_ID, sid);
714
715	/* Accounting Request must have Framed-IP-Address */
716	addr4 = sa->sa_addrpool;
717	if (addr4 != NULL) {
718		radius_put_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS,
719		    ((struct sockaddr_in *)&addr4->addr)->sin_addr);
720		if (addr4->addr_mask != 0) {
721			mask4.s_addr = htonl(
722			    0xFFFFFFFFUL << (32 - addr4->addr_mask));
723			radius_put_ipv4_attr(pkt,
724			    RADIUS_TYPE_FRAMED_IP_NETMASK, mask4);
725		}
726	}
727	addr6 = sa->sa_addrpool6;
728	if (addr6 != NULL)
729		radius_put_ipv6_attr(pkt, RADIUS_TYPE_FRAMED_IPV6_ADDRESS,
730		    &((struct sockaddr_in6 *)&addr6->addr)->sin6_addr);
731
732	/* RFC2866 5.6 Acct-Authentic */
733	radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_AUTHENTIC,
734	    (sa->sa_radreq != NULL)? RADIUS_ACCT_AUTHENTIC_RADIUS :
735	    RADIUS_ACCT_AUTHENTIC_LOCAL);
736
737	switch (stype) {
738	case RADIUS_ACCT_STATUS_TYPE_START:
739		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE,
740		    RADIUS_ACCT_STATUS_TYPE_START);
741		break;
742	case RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE:
743	case RADIUS_ACCT_STATUS_TYPE_STOP:
744		/* RFC 2866 5.7.  Acct-Session-Time */
745		timespecsub(&now, &sa->sa_starttime, &now);
746		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_SESSION_TIME,
747		    now.tv_sec);
748		/* RFC 2866 5.10 Acct-Terminate-Cause */
749		cause = RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL;
750		if (sa->sa_reason) {
751			if (strcmp(sa->sa_reason, "received delete") == 0) {
752				cause = RADIUS_TERMNATE_CAUSE_USER_REQUEST;
753			} else if (strcmp(sa->sa_reason, "SA rekeyed") == 0) {
754				cause = RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT;
755			} else if (strncmp(sa->sa_reason, "retransmit",
756			    strlen("retransmit")) == 0) {
757				cause = RADIUS_TERMNATE_CAUSE_LOST_SERVICE;
758			} else if (strcmp(sa->sa_reason,
759			    "disconnect requested") == 0) {
760				cause = RADIUS_TERMNATE_CAUSE_ADMIN_RESET;
761			}
762		}
763		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_TERMINATE_CAUSE,
764		    cause);
765		/* I/O statistics {Input,Output}-{Packets,Octets,Gigawords} */
766		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_PACKETS,
767		    sa->sa_stats.sas_ipackets);
768		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS,
769		    sa->sa_stats.sas_opackets);
770		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_OCTETS,
771		    sa->sa_stats.sas_ibytes & 0xffffffffUL);
772		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_OCTETS,
773		    sa->sa_stats.sas_obytes & 0xffffffffUL);
774		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_GIGAWORDS,
775		    sa->sa_stats.sas_ibytes >> 32);
776		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS,
777		    sa->sa_stats.sas_obytes >> 32);
778		break;
779	}
780	req->rr_reqpkt = pkt;
781	req->rr_ntry = 0;
782	iked_radius_request_send(env, req);
783}
784
785void
786iked_radius_dae_on_event(int fd, short ev, void *ctx)
787{
788	struct iked_raddae	*dae = ctx;
789	struct iked		*env = dae->rd_env;
790	RADIUS_PACKET		*req = NULL, *res = NULL;
791	struct sockaddr_storage	 ss;
792	socklen_t		 sslen;
793	struct iked_radclient	*client;
794	struct iked_sa		*sa = NULL;
795	char			 attr[256], username[256];
796	char			*endp, *reason, *nakcause = NULL;
797	int			 code, n = 0;
798	uint64_t		 ispi = 0;
799	uint32_t		 u32, cause = 0;
800	struct iked_addr	*addr4 = NULL;
801
802	reason = "disconnect requested";
803
804	sslen = sizeof(ss);
805	req = radius_recvfrom(dae->rd_sock, 0, (struct sockaddr *)&ss, &sslen);
806	if (req == NULL) {
807		log_warn("%s: receiving a RADIUS message failed: %s", __func__,
808		    strerror(errno));
809		return;
810	}
811	TAILQ_FOREACH(client, &env->sc_raddaeclients, rc_entry) {
812		if (sockaddr_cmp((struct sockaddr *)&client->rc_sockaddr,
813		    (struct sockaddr *)&ss, -1) == 0)
814			break;
815	}
816	if (client == NULL) {
817		log_warnx("%s: received RADIUS message from %s: "
818		    "unknown client", __func__, print_addr(&ss));
819		goto out;
820	}
821
822	if (radius_check_accounting_request_authenticator(req,
823	    client->rc_secret) != 0) {
824		log_warnx("%s: received an invalid RADIUS message from %s: bad "
825		    "response authenticator", __func__, print_addr(&ss));
826		goto out;
827	}
828
829	if ((code = radius_get_code(req)) != RADIUS_CODE_DISCONNECT_REQUEST) {
830		/* Code other than Disconnect-Request is not supported */
831		if (code == RADIUS_CODE_COA_REQUEST) {
832			code = RADIUS_CODE_COA_NAK;
833			cause = RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED;
834			nakcause = "Coa-Request is not supprted";
835			goto send;
836		}
837		log_warnx("%s: received an invalid RADIUS message "
838		    "from %s: unknown code %d", __func__,
839		    print_addr(&ss), code);
840		goto out;
841	}
842
843	log_info("received Disconnect-Request from %s", print_addr(&ss));
844
845	if (radius_get_string_attr(req, RADIUS_TYPE_NAS_IDENTIFIER, attr,
846	    sizeof(attr)) == 0 && strcmp(attr, IKED_NAS_ID) != 0) {
847		cause = RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH;
848		nakcause = "NAS-Identifier is not matched";
849		goto search_done;
850	}
851
852	/* prepare User-Name attribute */
853	memset(username, 0, sizeof(username));
854	radius_get_string_attr(req, RADIUS_TYPE_USER_NAME, username,
855	    sizeof(username));
856
857	if (radius_get_string_attr(req, RADIUS_TYPE_ACCT_SESSION_ID, attr,
858	    sizeof(attr)) == 0) {
859		/* the client is to disconnect a session */
860		ispi = strtoull(attr, &endp, 16);
861		if (attr[0] == '\0' || *endp != '\0' || errno == ERANGE ||
862		    ispi == ULLONG_MAX) {
863			cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
864			nakcause = "Session-Id is wrong";
865			goto search_done;
866
867		}
868		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
869			if (sa->sa_hdr.sh_ispi == ispi)
870				break;
871		}
872		if (sa == NULL)
873			goto search_done;
874		if (username[0] != '\0' && (sa->sa_eapid == NULL ||
875		    strcmp(username, sa->sa_eapid) != 0)) {
876			/* specified User-Name attribute is mismatched */
877			cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
878			nakcause = "User-Name is not matched";
879			goto search_done;
880		}
881		ikev2_ike_sa_setreason(sa, reason);
882		ikev2_ike_sa_delete(env, sa);
883		n++;
884	} else if (username[0] != '\0') {
885		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
886			if (sa->sa_eapid != NULL &&
887			    strcmp(sa->sa_eapid, username) == 0) {
888				ikev2_ike_sa_setreason(sa, reason);
889				ikev2_ike_sa_delete(env, sa);
890				n++;
891			}
892		}
893	} else if (radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS,
894	    &u32) == 0) {
895		addr4 = sa->sa_addrpool;
896		if (addr4 != NULL) {
897			RB_FOREACH(sa, iked_sas, &env->sc_sas) {
898				if (u32 == ((struct sockaddr_in *)&addr4->addr)
899				    ->sin_addr.s_addr) {
900					ikev2_ike_sa_setreason(sa, reason);
901					ikev2_ike_sa_delete(env, sa);
902					n++;
903				}
904			}
905		}
906	}
907 search_done:
908	if (n > 0)
909		code = RADIUS_CODE_DISCONNECT_ACK;
910	else {
911		if (nakcause == NULL)
912			nakcause = "session not found";
913		if (cause == 0)
914			cause = RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND;
915		code = RADIUS_CODE_DISCONNECT_NAK;
916	}
917 send:
918	res = radius_new_response_packet(code, req);
919	if (res == NULL) {
920		log_warn("%s: radius_new_response_packet", __func__);
921		goto out;
922	}
923	if (cause != 0)
924		radius_put_uint32_attr(res, RADIUS_TYPE_ERROR_CAUSE, cause);
925	radius_set_response_authenticator(res, client->rc_secret);
926	if (radius_sendto(dae->rd_sock, res, 0, (struct sockaddr *)&ss, sslen)
927	    == -1)
928		log_warn("%s: sendto", __func__);
929	log_info("send %s for %s%s%s",
930	    (code == RADIUS_CODE_DISCONNECT_ACK)? "Disconnect-ACK" :
931	    (code == RADIUS_CODE_DISCONNECT_NAK)? "Disconnect-NAK" : "CoA-NAK",
932	    print_addr(&ss), (nakcause)? ": " : "", (nakcause)? nakcause : "");
933 out:
934	radius_delete_packet(req);
935	if (res != NULL)
936		radius_delete_packet(res);
937}
938/*	$OpenBSD: radius.c,v 1.3 2024/07/13 12:22:46 yasuoka Exp $	*/
939
940/*
941 * Copyright (c) 2024 Internet Initiative Japan Inc.
942 *
943 * Permission to use, copy, modify, and distribute this software for any
944 * purpose with or without fee is hereby granted, provided that the above
945 * copyright notice and this permission notice appear in all copies.
946 *
947 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
948 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
949 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
950 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
951 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
952 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
953 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
954 */
955
956#include <sys/types.h>
957#include <sys/queue.h>
958#include <sys/socket.h>
959#include <sys/time.h>
960#include <arpa/inet.h>
961#include <netinet/ip_ipsp.h>
962
963#include <endian.h>
964#include <event.h>
965#include <errno.h>
966#include <imsg.h>
967#include <limits.h>
968#include <netinet/in.h>
969#include <radius.h>
970#include <stdint.h>
971#include <stdio.h>
972#include <stdlib.h>
973#include <string.h>
974#include <strings.h>
975#include <time.h>
976
977#include "iked.h"
978#include "eap.h"
979#include "ikev2.h"
980#include "types.h"
981
982void	 iked_radius_request_send(struct iked *, void *);
983void	 iked_radius_fill_attributes(struct iked_sa *, RADIUS_PACKET *);
984void	 iked_radius_config(struct iked_radserver_req *, const RADIUS_PACKET *,
985	    int, uint32_t, uint8_t);
986void	 iked_radius_acct_request(struct iked *, struct iked_sa *, uint8_t);
987
988const struct iked_radcfgmap radius_cfgmaps[] = {
989    { IKEV2_CFG_INTERNAL_IP4_ADDRESS, 0, RADIUS_TYPE_FRAMED_IP_ADDRESS },
990    { IKEV2_CFG_INTERNAL_IP4_NETMASK, 0, RADIUS_TYPE_FRAMED_IP_NETMASK },
991    { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT,
992	RADIUS_VTYPE_MS_PRIMARY_DNS_SERVER },
993    { IKEV2_CFG_INTERNAL_IP4_DNS, RADIUS_VENDOR_MICROSOFT,
994	RADIUS_VTYPE_MS_SECONDARY_DNS_SERVER },
995    { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT,
996	RADIUS_VTYPE_MS_PRIMARY_NBNS_SERVER },
997    { IKEV2_CFG_INTERNAL_IP4_NBNS, RADIUS_VENDOR_MICROSOFT,
998	RADIUS_VTYPE_MS_SECONDARY_NBNS_SERVER },
999    { 0 }
1000};
1001
1002int
1003iked_radius_request(struct iked *env, struct iked_sa *sa,
1004    struct iked_message *msg)
1005{
1006	struct eap_message		*eap;
1007	RADIUS_PACKET			*pkt;
1008	size_t				 len;
1009
1010	eap = ibuf_data(msg->msg_eapmsg);
1011	len = betoh16(eap->eap_length);
1012	if (eap->eap_code != EAP_CODE_RESPONSE) {
1013		log_debug("%s: eap_code is not response %u", __func__,
1014		    (unsigned)eap->eap_code);
1015		return -1;
1016	}
1017
1018	if (eap->eap_type == EAP_TYPE_IDENTITY) {
1019		if ((sa->sa_radreq = calloc(1,
1020		    sizeof(struct iked_radserver_req))) == NULL) {
1021			log_debug(
1022			    "%s: calloc failed for iked_radserver_req: %s",
1023			    __func__, strerror(errno));
1024			return (-1);
1025		}
1026		timer_set(env, &sa->sa_radreq->rr_timer,
1027		    iked_radius_request_send, sa->sa_radreq);
1028		sa->sa_radreq->rr_user = strdup(msg->msg_eap.eam_identity);
1029	}
1030
1031	if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST))
1032	    == NULL) {
1033		log_debug("%s: radius_new_request_packet failed %s", __func__,
1034		    strerror(errno));
1035		return -1;
1036	}
1037
1038	radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME,
1039	    sa->sa_radreq->rr_user);
1040	if (sa->sa_radreq->rr_state != NULL)
1041		radius_put_raw_attr(pkt, RADIUS_TYPE_STATE,
1042		    ibuf_data(sa->sa_radreq->rr_state),
1043		    ibuf_size(sa->sa_radreq->rr_state));
1044
1045	if (radius_put_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE,
1046	    (uint8_t *)eap, len) == -1) {
1047		log_debug("%s: radius_put_raw_attr_cat failed %s", __func__,
1048		    strerror(errno));
1049		return -1;
1050	}
1051
1052	iked_radius_fill_attributes(sa, pkt);
1053
1054	/* save the request, it'll be needed for message authentication */
1055	if (sa->sa_radreq->rr_reqpkt != NULL)
1056		radius_delete_packet(sa->sa_radreq->rr_reqpkt);
1057	sa->sa_radreq->rr_reqpkt = pkt;
1058	sa->sa_radreq->rr_sa = sa;
1059	sa->sa_radreq->rr_ntry = 0;
1060
1061	iked_radius_request_send(env, sa->sa_radreq);
1062
1063	return 0;
1064}
1065
1066void
1067iked_radius_request_free(struct iked *env, struct iked_radserver_req *req)
1068{
1069	if (req == NULL)
1070		return;
1071	timer_del(env, &req->rr_timer);
1072	free(req->rr_user);
1073	ibuf_free(req->rr_state);
1074	if (req->rr_reqpkt)
1075		radius_delete_packet(req->rr_reqpkt);
1076	if (req->rr_sa)
1077		req->rr_sa->sa_radreq = NULL;
1078	if (req->rr_server)
1079		TAILQ_REMOVE(&req->rr_server->rs_reqs, req, rr_entry);
1080	free(req);
1081}
1082
1083void
1084iked_radius_on_event(int fd, short ev, void *ctx)
1085{
1086	struct iked			*env;
1087	struct iked_radserver		*server = ctx;
1088	struct iked_radserver_req	*req;
1089	const struct iked_radcfgmap	*cfgmap;
1090	RADIUS_PACKET			*pkt;
1091	int				 i, resid;
1092	struct ibuf			*e;
1093	const void			*attrval;
1094	size_t				 attrlen;
1095	uint8_t				 code;
1096	char				 username[256];
1097	u_char				 eapmsk[128];
1098	/* RFC 3748 defines the MSK minimum size is 64 bytes */
1099	size_t				 eapmsksiz = sizeof(eapmsk);
1100
1101	env = server->rs_env;
1102	pkt = radius_recv(server->rs_sock, 0);
1103	if (pkt == NULL) {
1104		log_info("%s: receiving a RADIUS message failed: %s", __func__,
1105		    strerror(errno));
1106		return;
1107	}
1108	resid = radius_get_id(pkt);
1109
1110	TAILQ_FOREACH(req, &server->rs_reqs, rr_entry) {
1111		if (req->rr_reqid == resid)
1112			break;
1113	}
1114	if (req == NULL) {
1115		log_debug("%s: received an unknown RADIUS message: id=%u",
1116		    __func__, (unsigned)resid);
1117		return;
1118	}
1119
1120	radius_set_request_packet(pkt, req->rr_reqpkt);
1121	if (radius_check_response_authenticator(pkt, server->rs_secret) != 0) {
1122		log_info("%s: received an invalid RADIUS message: bad "
1123		    "response authenticator", __func__);
1124		return;
1125	}
1126	if (req->rr_accounting) {
1127		/* accounting */
1128		code = radius_get_code(pkt);
1129		switch (code) {
1130		case RADIUS_CODE_ACCOUNTING_RESPONSE: /* Expected */
1131			break;
1132		default:
1133			log_info("%s: received an invalid RADIUS message: "
1134			    "code %u", __func__, (unsigned)code);
1135		}
1136		timer_del(env, &req->rr_timer);
1137		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
1138		req->rr_server = NULL;
1139		free(req);
1140		return;
1141	}
1142
1143	/* authentication */
1144	if (radius_check_message_authenticator(pkt, server->rs_secret) != 0) {
1145		log_info("%s: received an invalid RADIUS message: bad "
1146		    "message authenticator", __func__);
1147		return;
1148	}
1149
1150	timer_del(env, &req->rr_timer);
1151	req->rr_ntry = 0;
1152
1153	if (req->rr_sa == NULL)
1154		goto fail;
1155
1156	code = radius_get_code(pkt);
1157	switch (code) {
1158	case RADIUS_CODE_ACCESS_CHALLENGE:
1159		if (radius_get_raw_attr_ptr(pkt, RADIUS_TYPE_STATE, &attrval,
1160		    &attrlen) != 0) {
1161			log_info("%s: received an invalid RADIUS message: no "
1162			    "state attribute", __func__);
1163			goto fail;
1164		}
1165		if ((req->rr_state != NULL &&
1166		    ibuf_set(req->rr_state, 0, attrval, attrlen) != 0) ||
1167		    (req->rr_state = ibuf_new(attrval, attrlen)) == NULL) {
1168			log_info("%s: ibuf_new() failed: %s", __func__,
1169			    strerror(errno));
1170			goto fail;
1171		}
1172		break;
1173	case RADIUS_CODE_ACCESS_ACCEPT:
1174		log_info("%s: received Access-Accept for %s",
1175		    SPI_SA(req->rr_sa, __func__), req->rr_user);
1176		/* Try to retrieve the EAP MSK from the RADIUS response */
1177		if (radius_get_eap_msk(pkt, eapmsk, &eapmsksiz,
1178		    server->rs_secret) == 0) {
1179			ibuf_free(req->rr_sa->sa_eapmsk);
1180			if ((req->rr_sa->sa_eapmsk = ibuf_new(eapmsk,
1181			    eapmsksiz)) == NULL) {
1182				log_info("%s: ibuf_new() failed: %s", __func__,
1183				    strerror(errno));
1184				goto fail;
1185			}
1186		} else
1187			log_debug("Could not retrieve the EAP MSK from the "
1188			    "RADIUS message");
1189
1190		free(req->rr_sa->sa_eapid);
1191		/* The EAP identity might be protected (RFC 3748 7.3) */
1192		if (radius_get_string_attr(pkt, RADIUS_TYPE_USER_NAME,
1193		    username, sizeof(username)) == 0 &&
1194		    strcmp(username, req->rr_user) != 0) {
1195			/*
1196			 * The Access-Accept might have a User-Name.  It
1197			 * should be used for Accouting (RFC 2865 5.1).
1198			 */
1199			free(req->rr_user);
1200			req->rr_sa->sa_eapid = strdup(username);
1201		} else
1202			req->rr_sa->sa_eapid = req->rr_user;
1203		req->rr_user = NULL;
1204
1205		sa_state(env, req->rr_sa, IKEV2_STATE_AUTH_SUCCESS);
1206
1207		/* Map RADIUS attributes to cp */
1208		if (TAILQ_EMPTY(&env->sc_radcfgmaps)) {
1209			for (i = 0; radius_cfgmaps[i].cfg_type != 0; i++) {
1210				cfgmap = &radius_cfgmaps[i];
1211				iked_radius_config(req, pkt, cfgmap->cfg_type,
1212				    cfgmap->vendor_id, cfgmap->attr_type);
1213			}
1214		} else {
1215			TAILQ_FOREACH(cfgmap, &env->sc_radcfgmaps, entry)
1216				iked_radius_config(req, pkt, cfgmap->cfg_type,
1217				    cfgmap->vendor_id, cfgmap->attr_type);
1218		}
1219
1220		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
1221		req->rr_server = NULL;
1222		break;
1223	case RADIUS_CODE_ACCESS_REJECT:
1224		log_info("%s: received Access-Reject for %s",
1225		    SPI_SA(req->rr_sa, __func__), req->rr_user);
1226		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
1227		req->rr_server = NULL;
1228		break;
1229	default:
1230		log_debug("%s: received an invalid RADIUS message: code %u",
1231		    __func__, (unsigned)code);
1232		break;
1233	}
1234
1235	/* get the length first */
1236	if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, NULL,
1237	    &attrlen) != 0) {
1238		log_info("%s: failed to retrieve the EAP message", __func__);
1239		goto fail;
1240	}
1241	/* allocate a buffer */
1242	if ((e = ibuf_new(NULL, attrlen)) == NULL) {
1243		log_info("%s: ibuf_new() failed: %s", __func__,
1244		    strerror(errno));
1245		goto fail;
1246	}
1247	/* copy the message to the buffer */
1248	if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE,
1249	    ibuf_data(e), &attrlen) != 0) {
1250		ibuf_free(e);
1251		log_info("%s: failed to retrieve the EAP message", __func__);
1252		goto fail;
1253	}
1254	ikev2_send_ike_e(env, req->rr_sa, e, IKEV2_PAYLOAD_EAP,
1255	    IKEV2_EXCHANGE_IKE_AUTH, 1);
1256	return;
1257 fail:
1258	if (req->rr_server != NULL)
1259		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
1260	req->rr_server = NULL;
1261	if (req->rr_sa != NULL) {
1262		ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed");
1263		sa_free(env, req->rr_sa);
1264	}
1265}
1266
1267void
1268iked_radius_request_send(struct iked *env, void *ctx)
1269{
1270	struct iked_radserver_req	*req = ctx, *req0;
1271	struct iked_radserver		*server = req->rr_server;
1272	const int			 timeouts[] = { 2, 4, 8 };
1273	uint8_t				 seq;
1274	int				 i, max_tries, max_failovers;
1275	struct sockaddr_storage		 ss;
1276	socklen_t			 sslen;
1277	struct iked_radservers		*radservers;
1278	struct timespec			 now;
1279
1280	if (!req->rr_accounting) {
1281		max_tries = env->sc_radauth.max_tries;
1282		max_failovers = env->sc_radauth.max_failovers;
1283		radservers = &env->sc_radauthservers;
1284	} else {
1285		max_tries = env->sc_radacct.max_tries;
1286		max_failovers = env->sc_radacct.max_failovers;
1287		radservers = &env->sc_radacctservers;
1288	}
1289
1290	if (req->rr_ntry > max_tries) {
1291		req->rr_ntry = 0;
1292		log_info("%s: RADIUS server %s failed", __func__,
1293		    print_addr(&server->rs_sockaddr));
1294 next_server:
1295		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
1296		req->rr_server = NULL;
1297		if (req->rr_nfailover >= max_failovers ||
1298		    TAILQ_NEXT(server, rs_entry) == NULL) {
1299			log_info("%s: No more RADIUS server", __func__);
1300			goto fail;
1301		} else if (req->rr_state != NULL) {
1302			log_info("%s: Can't change RADIUS server: "
1303			    "client has a state already", __func__);
1304			goto fail;
1305		} else {
1306			TAILQ_REMOVE(radservers, server, rs_entry);
1307			TAILQ_INSERT_TAIL(radservers, server, rs_entry);
1308			server = TAILQ_FIRST(radservers);
1309			log_info("%s: RADIUS server %s is active",
1310			    __func__, print_addr(&server->rs_sockaddr));
1311		}
1312		req->rr_nfailover++;
1313	}
1314
1315	if (req->rr_server != NULL &&
1316	    req->rr_server != TAILQ_FIRST(radservers)) {
1317		/* Current server is marked fail */
1318		if (req->rr_state != NULL || req->rr_nfailover >= max_failovers)
1319			goto fail; /* can't fail over */
1320		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
1321		req->rr_server = NULL;
1322		req->rr_nfailover++;
1323	}
1324
1325	if (req->rr_server == NULL) {
1326		/* Select a new server */
1327		server = TAILQ_FIRST(radservers);
1328		if (server == NULL) {
1329			log_info("%s: No RADIUS server is configured",
1330			    __func__);
1331			goto fail;
1332		}
1333		TAILQ_INSERT_TAIL(&server->rs_reqs, req, rr_entry);
1334		req->rr_server = server;
1335
1336		/* Prepare NAS-IP-Address */
1337		if (server->rs_nas_ipv4.s_addr == INADDR_ANY &&
1338		    IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6)) {
1339			sslen = sizeof(ss);
1340			if (getsockname(server->rs_sock, (struct sockaddr *)&ss,
1341			    &sslen) == 0) {
1342				if (ss.ss_family == AF_INET)
1343					server->rs_nas_ipv4 =
1344					    ((struct sockaddr_in *)&ss)
1345					    ->sin_addr;
1346				else
1347					server->rs_nas_ipv6 =
1348					    ((struct sockaddr_in6 *)&ss)
1349					    ->sin6_addr;
1350			}
1351		}
1352	}
1353	if (req->rr_ntry == 0) {
1354		/* decide the ID */
1355		seq = ++server->rs_reqseq;
1356		for (i = 0; i < UCHAR_MAX; i++) {
1357			TAILQ_FOREACH(req0, &server->rs_reqs, rr_entry) {
1358				if (req0->rr_reqid == seq)
1359					break;
1360			}
1361			if (req0 == NULL)
1362				break;
1363			seq++;
1364		}
1365		if (i >= UCHAR_MAX) {
1366			log_info("%s: RADIUS server %s failed.  Too many "
1367			    "pending requests", __func__,
1368			    print_addr(&server->rs_sockaddr));
1369			if (TAILQ_NEXT(server, rs_entry) != NULL)
1370				goto next_server;
1371			goto fail;
1372		}
1373		req->rr_reqid = seq;
1374		radius_set_id(req->rr_reqpkt, req->rr_reqid);
1375	}
1376
1377	if (server->rs_nas_ipv4.s_addr != INADDR_ANY)
1378		radius_put_ipv4_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IP_ADDRESS,
1379		    server->rs_nas_ipv4);
1380	else if (!IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6))
1381		radius_put_ipv6_attr(req->rr_reqpkt,
1382		    RADIUS_TYPE_NAS_IPV6_ADDRESS, &server->rs_nas_ipv6);
1383	/* Identifier */
1384	radius_put_string_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IDENTIFIER,
1385	    "OpenIKED");
1386
1387	if (req->rr_accounting) {
1388		if (req->rr_ntry == 0 && req->rr_nfailover == 0)
1389			radius_put_uint32_attr(req->rr_reqpkt,
1390			    RADIUS_TYPE_ACCT_DELAY_TIME, 0);
1391		else {
1392			clock_gettime(CLOCK_MONOTONIC, &now);
1393			timespecsub(&now, &req->rr_accttime, &now);
1394			radius_put_uint32_attr(req->rr_reqpkt,
1395			    RADIUS_TYPE_ACCT_DELAY_TIME, now.tv_sec);
1396		}
1397		radius_set_accounting_request_authenticator(req->rr_reqpkt,
1398		    server->rs_secret);
1399	} else {
1400		radius_put_message_authenticator(req->rr_reqpkt,
1401		    server->rs_secret);
1402	}
1403
1404	if (radius_send(server->rs_sock, req->rr_reqpkt, 0) < 0)
1405		log_info("%s: sending a RADIUS message failed: %s", __func__,
1406		    strerror(errno));
1407
1408	if (req->rr_ntry >= (int)nitems(timeouts))
1409		timer_add(env, &req->rr_timer, timeouts[nitems(timeouts) - 1]);
1410	else
1411		timer_add(env, &req->rr_timer, timeouts[req->rr_ntry]);
1412	req->rr_ntry++;
1413	return;
1414 fail:
1415	if (req->rr_server != NULL)
1416		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
1417	req->rr_server = NULL;
1418	if (req->rr_sa != NULL) {
1419		ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed");
1420		sa_free(env, req->rr_sa);
1421	}
1422}
1423
1424void
1425iked_radius_fill_attributes(struct iked_sa *sa, RADIUS_PACKET *pkt)
1426{
1427	/* NAS Port Type = Virtual */
1428	radius_put_uint32_attr(pkt,
1429	    RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL);
1430	/* Service Type =  Framed */
1431	radius_put_uint32_attr(pkt, RADIUS_TYPE_SERVICE_TYPE,
1432	    RADIUS_SERVICE_TYPE_FRAMED);
1433	/* Tunnel Type = EAP */
1434	radius_put_uint32_attr(pkt, RADIUS_TYPE_TUNNEL_TYPE,
1435	    RADIUS_TUNNEL_TYPE_ESP);
1436
1437	radius_put_string_attr(pkt, RADIUS_TYPE_CALLED_STATION_ID,
1438	    print_addr(&sa->sa_local.addr));
1439	radius_put_string_attr(pkt, RADIUS_TYPE_CALLING_STATION_ID,
1440	    print_addr(&sa->sa_peer.addr));
1441}
1442
1443void
1444iked_radius_config(struct iked_radserver_req *req, const RADIUS_PACKET *pkt,
1445    int cfg_type, uint32_t vendor_id, uint8_t attr_type)
1446{
1447	unsigned int		 i;
1448	struct iked_sa		*sa = req->rr_sa;
1449	struct in_addr		 ia4;
1450	struct in6_addr		 ia6;
1451	struct sockaddr_in	*sin4;
1452	struct sockaddr_in6	*sin6;
1453	struct iked_addr	*addr;
1454	struct iked_cfg		*ikecfg;
1455
1456	for (i = 0; i < sa->sa_policy->pol_ncfg; i++) {
1457		ikecfg = &sa->sa_policy->pol_cfg[i];
1458		if (ikecfg->cfg_type == cfg_type &&
1459		    ikecfg->cfg_type != IKEV2_CFG_INTERNAL_IP4_ADDRESS)
1460			return;	/* use config rather than radius */
1461	}
1462	switch (cfg_type) {
1463	case IKEV2_CFG_INTERNAL_IP4_ADDRESS:
1464	case IKEV2_CFG_INTERNAL_IP4_NETMASK:
1465	case IKEV2_CFG_INTERNAL_IP4_DNS:
1466	case IKEV2_CFG_INTERNAL_IP4_NBNS:
1467	case IKEV2_CFG_INTERNAL_IP4_DHCP:
1468	case IKEV2_CFG_INTERNAL_IP4_SERVER:
1469		if (vendor_id == 0 && radius_has_attr(pkt, attr_type))
1470			radius_get_ipv4_attr(pkt, attr_type, &ia4);
1471		else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id,
1472		    attr_type))
1473			radius_get_vs_ipv4_attr(pkt, vendor_id, attr_type,
1474			    &ia4);
1475		else
1476			break; /* no attribute contained */
1477
1478		if (cfg_type == IKEV2_CFG_INTERNAL_IP4_NETMASK) {
1479			/*
1480			 * This assumes IKEV2_CFG_INTERNAL_IP4_ADDRESS is
1481			 * called before IKEV2_CFG_INTERNAL_IP4_NETMASK
1482			 */
1483			if (sa->sa_rad_addr == NULL) {
1484				/*
1485				 * RFC 7296, IKEV2_CFG_INTERNAL_IP4_NETMASK
1486				 * must be used with
1487				 * IKEV2_CFG_INTERNAL_IP4_ADDRESS
1488				 */
1489				break;
1490			}
1491			if (ia4.s_addr == 0) {
1492				log_debug("%s: netmask is wrong", __func__);
1493				break;
1494			}
1495			if (ia4.s_addr == htonl(0))
1496				sa->sa_rad_addr->addr_mask = 0;
1497			else
1498				sa->sa_rad_addr->addr_mask =
1499				    33 - ffs(ntohl(ia4.s_addr));
1500			if (sa->sa_rad_addr->addr_mask < 32)
1501				sa->sa_rad_addr->addr_net = 1;
1502		}
1503		if (cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS) {
1504			if ((addr = calloc(1, sizeof(*addr))) == NULL) {
1505				log_warn("%s: calloc", __func__);
1506				return;
1507			}
1508			sa->sa_rad_addr = addr;
1509		} else {
1510			req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY;
1511			req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type;
1512			addr = &req->rr_cfg[req->rr_ncfg].cfg.address;
1513			req->rr_ncfg++;
1514		}
1515		addr->addr_af = AF_INET;
1516		sin4 = (struct sockaddr_in *)&addr->addr;
1517		sin4->sin_family = AF_INET;
1518		sin4->sin_len = sizeof(struct sockaddr_in);
1519		sin4->sin_addr = ia4;
1520		break;
1521	case IKEV2_CFG_INTERNAL_IP6_ADDRESS:
1522	case IKEV2_CFG_INTERNAL_IP6_DNS:
1523	case IKEV2_CFG_INTERNAL_IP6_NBNS:
1524	case IKEV2_CFG_INTERNAL_IP6_DHCP:
1525	case IKEV2_CFG_INTERNAL_IP6_SERVER:
1526		if (vendor_id == 0 && radius_has_attr(pkt, attr_type))
1527			radius_get_ipv6_attr(pkt, attr_type, &ia6);
1528		else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id,
1529		    attr_type))
1530			radius_get_vs_ipv6_attr(pkt, vendor_id, attr_type,
1531			    &ia6);
1532		else
1533			break; /* no attribute contained */
1534
1535		if (cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS) {
1536			if ((addr = calloc(1, sizeof(*addr))) == NULL) {
1537				log_warn("%s: calloc", __func__);
1538				return;
1539			}
1540			sa->sa_rad_addr = addr;
1541		} else {
1542			req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY;
1543			req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type;
1544			addr = &req->rr_cfg[req->rr_ncfg].cfg.address;
1545			req->rr_ncfg++;
1546		}
1547		addr->addr_af = AF_INET;
1548		sin6 = (struct sockaddr_in6 *)&addr->addr;
1549		sin6->sin6_family = AF_INET6;
1550		sin6->sin6_len = sizeof(struct sockaddr_in6);
1551		sin6->sin6_addr = ia6;
1552		break;
1553	}
1554	return;
1555}
1556
1557void
1558iked_radius_acct_on(struct iked *env)
1559{
1560	if (TAILQ_EMPTY(&env->sc_radacctservers))
1561		return;
1562	if (env->sc_radaccton == 0) {	/* trigger once */
1563		iked_radius_acct_request(env, NULL,
1564		    RADIUS_ACCT_STATUS_TYPE_ACCT_ON);
1565		env->sc_radaccton = 1;
1566	}
1567}
1568
1569void
1570iked_radius_acct_off(struct iked *env)
1571{
1572	iked_radius_acct_request(env, NULL, RADIUS_ACCT_STATUS_TYPE_ACCT_OFF);
1573}
1574
1575void
1576iked_radius_acct_start(struct iked *env, struct iked_sa *sa)
1577{
1578	iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_START);
1579}
1580
1581void
1582iked_radius_acct_stop(struct iked *env, struct iked_sa *sa)
1583{
1584	iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_STOP);
1585}
1586
1587void
1588iked_radius_acct_request(struct iked *env, struct iked_sa *sa, uint8_t stype)
1589{
1590	struct iked_radserver_req	*req;
1591	RADIUS_PACKET			*pkt;
1592	struct iked_addr		*addr4 = NULL;
1593	struct iked_addr		*addr6 = NULL;
1594	struct in_addr			 mask4;
1595	char				 sa_id[IKED_ID_SIZE];
1596	char				 sid[16 + 1];
1597	struct timespec			 now;
1598	int				 cause;
1599
1600	if (TAILQ_EMPTY(&env->sc_radacctservers))
1601		return;
1602	/*
1603	 * In RFC2866 5.6, "Users who are delivered service without
1604	 * being authenticated SHOULD NOT generate Accounting records
1605	 */
1606	if (sa != NULL && sa->sa_eapid == NULL) {
1607		/* fallback to IKEID for accounting */
1608		if (ikev2_print_id(IKESA_DSTID(sa), sa_id, sizeof(sa_id)) != -1)
1609			sa->sa_eapid = strdup(sa_id);
1610		if (sa->sa_eapid == NULL)
1611			return;
1612	}
1613
1614	if ((req = calloc(1, sizeof(struct iked_radserver_req))) == NULL) {
1615		log_debug("%s: calloc faile for iked_radserver_req: %s",
1616		    __func__, strerror(errno));
1617		return;
1618	}
1619	req->rr_accounting = 1;
1620	clock_gettime(CLOCK_MONOTONIC, &now);
1621	req->rr_accttime = now;
1622	timer_set(env, &req->rr_timer, iked_radius_request_send, req);
1623
1624	if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST))
1625	    == NULL) {
1626		log_debug("%s: radius_new_request_packet failed %s", __func__,
1627		    strerror(errno));
1628		return;
1629	}
1630
1631	/* RFC 2866  5.1. Acct-Status-Type */
1632	radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE, stype);
1633
1634	if (sa == NULL) {
1635		/* ASSERT(stype == RADIUS_ACCT_STATUS_TYPE_ACCT_ON ||
1636		    stype == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) */
1637		req->rr_reqpkt = pkt;
1638		req->rr_ntry = 0;
1639		iked_radius_request_send(env, req);
1640		return;
1641	}
1642
1643	iked_radius_fill_attributes(sa, pkt);
1644
1645	radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME, sa->sa_eapid);
1646
1647	/* RFC 2866  5.5. Acct-Session-Id */
1648	snprintf(sid, sizeof(sid), "%016llx",
1649	    (unsigned long long)sa->sa_hdr.sh_ispi);
1650	radius_put_string_attr(pkt, RADIUS_TYPE_ACCT_SESSION_ID, sid);
1651
1652	/* Accounting Request must have Framed-IP-Address */
1653	addr4 = sa->sa_addrpool;
1654	if (addr4 != NULL) {
1655		radius_put_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS,
1656		    ((struct sockaddr_in *)&addr4->addr)->sin_addr);
1657		if (addr4->addr_mask != 0) {
1658			mask4.s_addr = htonl(
1659			    0xFFFFFFFFUL << (32 - addr4->addr_mask));
1660			radius_put_ipv4_attr(pkt,
1661			    RADIUS_TYPE_FRAMED_IP_NETMASK, mask4);
1662		}
1663	}
1664	addr6 = sa->sa_addrpool6;
1665	if (addr6 != NULL)
1666		radius_put_ipv6_attr(pkt, RADIUS_TYPE_FRAMED_IPV6_ADDRESS,
1667		    &((struct sockaddr_in6 *)&addr6->addr)->sin6_addr);
1668
1669	/* RFC2866 5.6 Acct-Authentic */
1670	radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_AUTHENTIC,
1671	    (sa->sa_radreq != NULL)? RADIUS_ACCT_AUTHENTIC_RADIUS :
1672	    RADIUS_ACCT_AUTHENTIC_LOCAL);
1673
1674	switch (stype) {
1675	case RADIUS_ACCT_STATUS_TYPE_START:
1676		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE,
1677		    RADIUS_ACCT_STATUS_TYPE_START);
1678		break;
1679	case RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE:
1680	case RADIUS_ACCT_STATUS_TYPE_STOP:
1681		/* RFC 2866 5.7.  Acct-Session-Time */
1682		timespecsub(&now, &sa->sa_starttime, &now);
1683		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_SESSION_TIME,
1684		    now.tv_sec);
1685		/* RFC 2866 5.10 Acct-Terminate-Cause */
1686		cause = RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL;
1687		if (sa->sa_reason) {
1688			if (strcmp(sa->sa_reason, "received delete") == 0) {
1689				cause = RADIUS_TERMNATE_CAUSE_USER_REQUEST;
1690			} else if (strcmp(sa->sa_reason, "SA rekeyed") == 0) {
1691				cause = RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT;
1692			} else if (strncmp(sa->sa_reason, "retransmit",
1693			    strlen("retransmit")) == 0) {
1694				cause = RADIUS_TERMNATE_CAUSE_LOST_SERVICE;
1695			} else if (strcmp(sa->sa_reason,
1696			    "disconnect requested") == 0) {
1697				cause = RADIUS_TERMNATE_CAUSE_ADMIN_RESET;
1698			}
1699		}
1700		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_TERMINATE_CAUSE,
1701		    cause);
1702		/* I/O statistics {Input,Output}-{Packets,Octets,Gigawords} */
1703		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_PACKETS,
1704		    sa->sa_stats.sas_ipackets);
1705		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS,
1706		    sa->sa_stats.sas_opackets);
1707		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_OCTETS,
1708		    sa->sa_stats.sas_ibytes & 0xffffffffUL);
1709		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_OCTETS,
1710		    sa->sa_stats.sas_obytes & 0xffffffffUL);
1711		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_GIGAWORDS,
1712		    sa->sa_stats.sas_ibytes >> 32);
1713		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS,
1714		    sa->sa_stats.sas_obytes >> 32);
1715		break;
1716	}
1717	req->rr_reqpkt = pkt;
1718	req->rr_ntry = 0;
1719	iked_radius_request_send(env, req);
1720}
1721
1722void
1723iked_radius_dae_on_event(int fd, short ev, void *ctx)
1724{
1725	struct iked_raddae	*dae = ctx;
1726	struct iked		*env = dae->rd_env;
1727	RADIUS_PACKET		*req = NULL, *res = NULL;
1728	struct sockaddr_storage	 ss;
1729	socklen_t		 sslen;
1730	struct iked_radclient	*client;
1731	struct iked_sa		*sa = NULL;
1732	char			 attr[256], *endp, *reason;
1733	const char		*cp;
1734	int			 code, n = 0;
1735	uint64_t		 ispi = 0;
1736	uint32_t		 u32, cause = 0;
1737	struct iked_addr	*addr4 = NULL;
1738
1739	reason = "disconnect requested";
1740
1741	sslen = sizeof(ss);
1742	req = radius_recvfrom(dae->rd_sock, 0, (struct sockaddr *)&ss, &sslen);
1743	if (req == NULL) {
1744		log_warn("%s: receiving a RADIUS message failed: %s", __func__,
1745		    strerror(errno));
1746		return;
1747	}
1748	TAILQ_FOREACH(client, &env->sc_raddaeclients, rc_entry) {
1749		if (sockaddr_cmp((struct sockaddr *)&client->rc_sockaddr,
1750		    (struct sockaddr *)&ss, -1) == 0)
1751			break;
1752	}
1753	if (client == NULL) {
1754		log_warnx("%s: received RADIUS message from %s: "
1755		    "unknown client", __func__, print_addr(&ss));
1756		goto out;
1757	}
1758
1759	if (radius_check_accounting_request_authenticator(req,
1760	    client->rc_secret) != 0) {
1761		log_warnx("%s: received an invalid RADIUS message from %s: bad "
1762		    "response authenticator", __func__, print_addr(&ss));
1763		goto out;
1764	}
1765
1766	if ((code = radius_get_code(req)) != RADIUS_CODE_DISCONNECT_REQUEST) {
1767		/* Code other than Disconnect-Request is not supported */
1768		if (code == RADIUS_CODE_COA_REQUEST) {
1769			log_info("received CoA-Request from %s",
1770			    print_addr(&ss));
1771			code = RADIUS_CODE_COA_NAK;
1772			cause = RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED;
1773			goto send;
1774		}
1775		log_warnx("%s: received an invalid RADIUS message "
1776		    "from %s: unknown code %d", __func__,
1777		    print_addr(&ss), code);
1778		goto out;
1779	}
1780
1781	log_info("received Disconnect-Request from %s", print_addr(&ss));
1782
1783	if (radius_get_string_attr(req, RADIUS_TYPE_ACCT_SESSION_ID, attr,
1784	    sizeof(attr)) == 0) {
1785		ispi = strtoull(attr, &endp, 16);
1786		if (attr[0] != '\0' && *endp == '\0' && errno != ERANGE &&
1787		    ispi != ULLONG_MAX) {
1788			RB_FOREACH(sa, iked_sas, &env->sc_sas) {
1789				if (sa->sa_hdr.sh_ispi == ispi) {
1790					ikev2_ike_sa_setreason(sa, reason);
1791					ikev2_ike_sa_delete(env, sa);
1792					n++;
1793				}
1794			}
1795		}
1796	}
1797	if (radius_get_string_attr(req, RADIUS_TYPE_USER_NAME, attr,
1798	    sizeof(attr)) == 0) {
1799		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
1800			if (sa->sa_eapid != NULL &&
1801			    strcmp(sa->sa_eapid, attr) == 0) {
1802				ikev2_ike_sa_setreason(sa, reason);
1803				ikev2_ike_sa_delete(env, sa);
1804				n++;
1805			}
1806		}
1807	}
1808	if (radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS, &u32)
1809	     == 0) {
1810		addr4 = sa->sa_addrpool;
1811		if (addr4 != NULL) {
1812			RB_FOREACH(sa, iked_sas, &env->sc_sas) {
1813				if (u32 == ((struct sockaddr_in *)&addr4->addr)
1814				    ->sin_addr.s_addr) {
1815					ikev2_ike_sa_setreason(sa, reason);
1816					ikev2_ike_sa_delete(env, sa);
1817					n++;
1818				}
1819			}
1820		}
1821	}
1822	if (radius_get_string_attr(req, RADIUS_TYPE_CALLED_STATION_ID, attr,
1823	    sizeof(attr)) != 0) {
1824		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
1825			cp = print_addr(&sa->sa_local.addr);
1826			if (strcmp(cp, attr) == 0) {
1827				ikev2_ike_sa_setreason(sa, reason);
1828				ikev2_ike_sa_delete(env, sa);
1829				n++;
1830			}
1831		}
1832	}
1833	if (radius_get_string_attr(req, RADIUS_TYPE_CALLING_STATION_ID, attr,
1834	    sizeof(attr)) != 0) {
1835		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
1836			cp = print_addr(&sa->sa_peer.addr);
1837			if (strcmp(cp, attr) == 0) {
1838				ikev2_ike_sa_setreason(sa, reason);
1839				ikev2_ike_sa_delete(env, sa);
1840				n++;
1841			}
1842		}
1843	}
1844
1845	if (n > 0)
1846		code = RADIUS_CODE_DISCONNECT_ACK;
1847	else {
1848		code = RADIUS_CODE_DISCONNECT_ACK;
1849		cause = RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND;
1850	}
1851 send:
1852	res = radius_new_response_packet(code, req);
1853	if (res == NULL) {
1854		log_warn("%s: radius_new_response_packet", __func__);
1855		goto out;
1856	}
1857	radius_set_response_authenticator(res, client->rc_secret);
1858	if (cause != 0)
1859		radius_put_uint32_attr(res, RADIUS_TYPE_ERROR_CAUSE, cause);
1860	if (radius_sendto(dae->rd_sock, res, 0, (struct sockaddr *)&ss, sslen)
1861	    == -1)
1862		log_warn("%s: sendto", __func__);
1863	log_info("send %s for %s",
1864	    (code == RADIUS_CODE_DISCONNECT_ACK)? "Disconnect-ACK" :
1865	    (code == RADIUS_CODE_DISCONNECT_NAK)? "Disconnect-NAK" : "CoA-NAK",
1866	    print_addr(&ss));
1867 out:
1868	radius_delete_packet(req);
1869	if (res != NULL)
1870		radius_delete_packet(res);
1871}
1872