radius.c revision 1.5
1/*	$OpenBSD: radius.c,v 1.5 2024/07/13 14:08:53 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	    "OpenIKED");
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], *endp, *reason;
796	const char		*cp;
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			log_info("received CoA-Request from %s",
833			    print_addr(&ss));
834			code = RADIUS_CODE_COA_NAK;
835			cause = RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED;
836			goto send;
837		}
838		log_warnx("%s: received an invalid RADIUS message "
839		    "from %s: unknown code %d", __func__,
840		    print_addr(&ss), code);
841		goto out;
842	}
843
844	log_info("received Disconnect-Request from %s", print_addr(&ss));
845
846	if (radius_get_string_attr(req, RADIUS_TYPE_ACCT_SESSION_ID, attr,
847	    sizeof(attr)) == 0) {
848		ispi = strtoull(attr, &endp, 16);
849		if (attr[0] != '\0' && *endp == '\0' && errno != ERANGE &&
850		    ispi != ULLONG_MAX) {
851			RB_FOREACH(sa, iked_sas, &env->sc_sas) {
852				if (sa->sa_hdr.sh_ispi == ispi) {
853					ikev2_ike_sa_setreason(sa, reason);
854					ikev2_ike_sa_delete(env, sa);
855					n++;
856				}
857			}
858		}
859	}
860	if (radius_get_string_attr(req, RADIUS_TYPE_USER_NAME, attr,
861	    sizeof(attr)) == 0) {
862		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
863			if (sa->sa_eapid != NULL &&
864			    strcmp(sa->sa_eapid, attr) == 0) {
865				ikev2_ike_sa_setreason(sa, reason);
866				ikev2_ike_sa_delete(env, sa);
867				n++;
868			}
869		}
870	}
871	if (radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS, &u32)
872	     == 0) {
873		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
874			addr4 = sa->sa_addrpool;
875			if (addr4 != NULL) {
876				if (u32 == ((struct sockaddr_in *)&addr4->addr)
877				    ->sin_addr.s_addr) {
878					ikev2_ike_sa_setreason(sa, reason);
879					ikev2_ike_sa_delete(env, sa);
880					n++;
881				}
882			}
883		}
884	}
885	if (radius_get_string_attr(req, RADIUS_TYPE_CALLED_STATION_ID, attr,
886	    sizeof(attr)) != 0) {
887		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
888			cp = print_addr(&sa->sa_local.addr);
889			if (strcmp(cp, attr) == 0) {
890				ikev2_ike_sa_setreason(sa, reason);
891				ikev2_ike_sa_delete(env, sa);
892				n++;
893			}
894		}
895	}
896	if (radius_get_string_attr(req, RADIUS_TYPE_CALLING_STATION_ID, attr,
897	    sizeof(attr)) != 0) {
898		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
899			cp = print_addr(&sa->sa_peer.addr);
900			if (strcmp(cp, attr) == 0) {
901				ikev2_ike_sa_setreason(sa, reason);
902				ikev2_ike_sa_delete(env, sa);
903				n++;
904			}
905		}
906	}
907
908	if (n > 0)
909		code = RADIUS_CODE_DISCONNECT_ACK;
910	else {
911		code = RADIUS_CODE_DISCONNECT_ACK;
912		cause = RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND;
913	}
914 send:
915	res = radius_new_response_packet(code, req);
916	if (res == NULL) {
917		log_warn("%s: radius_new_response_packet", __func__);
918		goto out;
919	}
920	radius_set_response_authenticator(res, client->rc_secret);
921	if (cause != 0)
922		radius_put_uint32_attr(res, RADIUS_TYPE_ERROR_CAUSE, cause);
923	if (radius_sendto(dae->rd_sock, res, 0, (struct sockaddr *)&ss, sslen)
924	    == -1)
925		log_warn("%s: sendto", __func__);
926	log_info("send %s for %s",
927	    (code == RADIUS_CODE_DISCONNECT_ACK)? "Disconnect-ACK" :
928	    (code == RADIUS_CODE_DISCONNECT_NAK)? "Disconnect-NAK" : "CoA-NAK",
929	    print_addr(&ss));
930 out:
931	radius_delete_packet(req);
932	if (res != NULL)
933		radius_delete_packet(res);
934}
935