xref: /openbsd-src/sbin/iked/radius.c (revision 9ca241fcbd1e3e57a03aa8097496cb954222290b)
1 /*	$OpenBSD: radius.c,v 1.13 2024/09/15 11:08:50 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 
45 void	 iked_radius_request_send(struct iked *, void *);
46 void	 iked_radius_fill_attributes(struct iked_sa *, RADIUS_PACKET *);
47 void	 iked_radius_config(struct iked_radserver_req *, const RADIUS_PACKET *,
48 	    int, uint32_t, uint8_t);
49 void	 iked_radius_acct_request(struct iked *, struct iked_sa *, uint8_t);
50 
51 const 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 
65 int
66 iked_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 
129 void
130 iked_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 
146 void
147 iked_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 		radius_delete_packet(pkt);
181 		return;
182 	}
183 
184 	radius_set_request_packet(pkt, req->rr_reqpkt);
185 	if (radius_check_response_authenticator(pkt, server->rs_secret) != 0) {
186 		log_info("%s: received an invalid RADIUS message: bad "
187 		    "response authenticator", __func__);
188 		radius_delete_packet(pkt);
189 		return;
190 	}
191 	if (req->rr_accounting) {
192 		/* accounting */
193 		code = radius_get_code(pkt);
194 		switch (code) {
195 		case RADIUS_CODE_ACCOUNTING_RESPONSE: /* Expected */
196 			break;
197 		default:
198 			log_info("%s: received an invalid RADIUS message: "
199 			    "code %u", __func__, (unsigned)code);
200 		}
201 		radius_delete_packet(pkt);
202 		iked_radius_request_free(env, 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 		radius_delete_packet(pkt);
211 		return;
212 	}
213 
214 	timer_del(env, &req->rr_timer);
215 	req->rr_ntry = 0;
216 
217 	if (req->rr_sa == NULL)
218 		goto fail;
219 
220 	code = radius_get_code(pkt);
221 	switch (code) {
222 	case RADIUS_CODE_ACCESS_CHALLENGE:
223 		if (radius_get_raw_attr_ptr(pkt, RADIUS_TYPE_STATE, &attrval,
224 		    &attrlen) != 0) {
225 			log_info("%s: received an invalid RADIUS message: no "
226 			    "state attribute", __func__);
227 			goto fail;
228 		}
229 		if (req->rr_state != NULL &&
230 		    ibuf_set(req->rr_state, 0, attrval, attrlen) != 0) {
231 			ibuf_free(req->rr_state);
232 			req->rr_state = NULL;
233 		}
234 		if (req->rr_state == NULL &&
235 		    (req->rr_state = ibuf_new(attrval, attrlen)) == NULL) {
236 			log_info("%s: ibuf_new() failed: %s", __func__,
237 			    strerror(errno));
238 			goto fail;
239 		}
240 		break;
241 	case RADIUS_CODE_ACCESS_ACCEPT:
242 		log_info("%s: received Access-Accept for %s",
243 		    SPI_SA(req->rr_sa, __func__), req->rr_user);
244 		/* Try to retrieve the EAP MSK from the RADIUS response */
245 		if (radius_get_eap_msk(pkt, eapmsk, &eapmsksiz,
246 		    server->rs_secret) == 0) {
247 			ibuf_free(req->rr_sa->sa_eapmsk);
248 			if ((req->rr_sa->sa_eapmsk = ibuf_new(eapmsk,
249 			    eapmsksiz)) == NULL) {
250 				log_info("%s: ibuf_new() failed: %s", __func__,
251 				    strerror(errno));
252 				goto fail;
253 			}
254 		} else
255 			log_debug("Could not retrieve the EAP MSK from the "
256 			    "RADIUS message");
257 
258 		free(req->rr_sa->sa_eapid);
259 		/* The EAP identity might be protected (RFC 3748 7.3) */
260 		if (radius_get_string_attr(pkt, RADIUS_TYPE_USER_NAME,
261 		    username, sizeof(username)) == 0 &&
262 		    strcmp(username, req->rr_user) != 0) {
263 			/*
264 			 * The Access-Accept might have a User-Name.  It
265 			 * should be used for Accounting (RFC 2865 5.1).
266 			 */
267 			free(req->rr_user);
268 			req->rr_sa->sa_eapid = strdup(username);
269 		} else
270 			req->rr_sa->sa_eapid = req->rr_user;
271 		req->rr_user = NULL;
272 
273 		if (radius_get_raw_attr_ptr(pkt, RADIUS_TYPE_CLASS, &attrval,
274 		    &attrlen) == 0) {
275 			ibuf_free(req->rr_sa->sa_eapclass);
276 			if ((req->rr_sa->sa_eapclass = ibuf_new(attrval,
277 			    attrlen)) == NULL) {
278 				log_info("%s: ibuf_new() failed: %s", __func__,
279 				    strerror(errno));
280 			}
281 		}
282 
283 		sa_state(env, req->rr_sa, IKEV2_STATE_AUTH_SUCCESS);
284 
285 		/* Map RADIUS attributes to cp */
286 		if (TAILQ_EMPTY(&env->sc_radcfgmaps)) {
287 			for (i = 0; radius_cfgmaps[i].cfg_type != 0; i++) {
288 				cfgmap = &radius_cfgmaps[i];
289 				iked_radius_config(req, pkt, cfgmap->cfg_type,
290 				    cfgmap->vendor_id, cfgmap->attr_type);
291 			}
292 		} else {
293 			TAILQ_FOREACH(cfgmap, &env->sc_radcfgmaps, entry)
294 				iked_radius_config(req, pkt, cfgmap->cfg_type,
295 				    cfgmap->vendor_id, cfgmap->attr_type);
296 		}
297 
298 		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
299 		req->rr_server = NULL;
300 		break;
301 	case RADIUS_CODE_ACCESS_REJECT:
302 		log_info("%s: received Access-Reject for %s",
303 		    SPI_SA(req->rr_sa, __func__), req->rr_user);
304 		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
305 		req->rr_server = NULL;
306 		break;
307 	default:
308 		log_debug("%s: received an invalid RADIUS message: code %u",
309 		    __func__, (unsigned)code);
310 		break;
311 	}
312 
313 	/* get the length first */
314 	if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE, NULL,
315 	    &attrlen) != 0) {
316 		log_info("%s: failed to retrieve the EAP message", __func__);
317 		goto fail;
318 	}
319 	/* allocate a buffer */
320 	if ((e = ibuf_new(NULL, attrlen)) == NULL) {
321 		log_info("%s: ibuf_new() failed: %s", __func__,
322 		    strerror(errno));
323 		goto fail;
324 	}
325 	/* copy the message to the buffer */
326 	if (radius_get_raw_attr_cat(pkt, RADIUS_TYPE_EAP_MESSAGE,
327 	    ibuf_data(e), &attrlen) != 0) {
328 		ibuf_free(e);
329 		log_info("%s: failed to retrieve the EAP message", __func__);
330 		goto fail;
331 	}
332 	radius_delete_packet(pkt);
333 	ikev2_send_ike_e(env, req->rr_sa, e, IKEV2_PAYLOAD_EAP,
334 	    IKEV2_EXCHANGE_IKE_AUTH, 1);
335 	ibuf_free(e);
336 	/* keep request for challenge state and config parameters */
337 	req->rr_reqid = -1;	/* release reqid */
338 	return;
339  fail:
340 	radius_delete_packet(pkt);
341 	if (req->rr_server != NULL)
342 		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
343 	req->rr_server = NULL;
344 	if (req->rr_sa != NULL) {
345 		ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed");
346 		sa_free(env, req->rr_sa);
347 	}
348 }
349 
350 void
351 iked_radius_request_send(struct iked *env, void *ctx)
352 {
353 	struct iked_radserver_req	*req = ctx, *req0;
354 	struct iked_radserver		*server = req->rr_server;
355 	const int			 timeouts[] = { 2, 4, 8 };
356 	uint8_t				 seq;
357 	int				 i, max_tries, max_failovers;
358 	struct sockaddr_storage		 ss;
359 	socklen_t			 sslen;
360 	struct iked_radservers		*radservers;
361 	struct timespec			 now;
362 
363 	if (!req->rr_accounting) {
364 		max_tries = env->sc_radauth.max_tries;
365 		max_failovers = env->sc_radauth.max_failovers;
366 		radservers = &env->sc_radauthservers;
367 	} else {
368 		max_tries = env->sc_radacct.max_tries;
369 		max_failovers = env->sc_radacct.max_failovers;
370 		radservers = &env->sc_radacctservers;
371 	}
372 
373 	if (req->rr_ntry > max_tries) {
374 		req->rr_ntry = 0;
375 		log_info("%s: RADIUS server %s failed", __func__,
376 		    print_addr(&server->rs_sockaddr));
377  next_server:
378 		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
379 		req->rr_server = NULL;
380 		if (req->rr_nfailover >= max_failovers ||
381 		    TAILQ_NEXT(server, rs_entry) == NULL) {
382 			log_info("%s: No more RADIUS server", __func__);
383 			goto fail;
384 		} else if (req->rr_state != NULL) {
385 			log_info("%s: Can't change RADIUS server: "
386 			    "client has a state already", __func__);
387 			goto fail;
388 		} else {
389 			TAILQ_REMOVE(radservers, server, rs_entry);
390 			TAILQ_INSERT_TAIL(radservers, server, rs_entry);
391 			server = TAILQ_FIRST(radservers);
392 			log_info("%s: RADIUS server %s is active",
393 			    __func__, print_addr(&server->rs_sockaddr));
394 		}
395 		req->rr_nfailover++;
396 	}
397 
398 	if (req->rr_server != NULL &&
399 	    req->rr_server != TAILQ_FIRST(radservers)) {
400 		/* Current server is marked fail */
401 		if (req->rr_state != NULL || req->rr_nfailover >= max_failovers)
402 			goto fail; /* can't fail over */
403 		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
404 		req->rr_server = NULL;
405 		req->rr_nfailover++;
406 	}
407 
408 	if (req->rr_server == NULL) {
409 		/* Select a new server */
410 		server = TAILQ_FIRST(radservers);
411 		if (server == NULL) {
412 			log_info("%s: No RADIUS server is configured",
413 			    __func__);
414 			goto fail;
415 		}
416 		TAILQ_INSERT_TAIL(&server->rs_reqs, req, rr_entry);
417 		req->rr_server = server;
418 
419 		/* Prepare NAS-IP-Address */
420 		if (server->rs_nas_ipv4.s_addr == INADDR_ANY &&
421 		    IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6)) {
422 			sslen = sizeof(ss);
423 			if (getsockname(server->rs_sock, (struct sockaddr *)&ss,
424 			    &sslen) == 0) {
425 				if (ss.ss_family == AF_INET)
426 					server->rs_nas_ipv4 =
427 					    ((struct sockaddr_in *)&ss)
428 					    ->sin_addr;
429 				else
430 					server->rs_nas_ipv6 =
431 					    ((struct sockaddr_in6 *)&ss)
432 					    ->sin6_addr;
433 			}
434 		}
435 	}
436 	if (req->rr_ntry == 0) {
437 		/* decide the ID */
438 		seq = ++server->rs_reqseq;
439 		for (i = 0; i <= UCHAR_MAX; i++) {
440 			TAILQ_FOREACH(req0, &server->rs_reqs, rr_entry) {
441 				if (req0->rr_reqid == -1)
442 					continue;
443 				if (req0->rr_reqid == seq)
444 					break;
445 			}
446 			if (req0 == NULL)
447 				break;
448 			seq++;
449 		}
450 		if (i > UCHAR_MAX) {
451 			log_info("%s: RADIUS server %s failed.  Too many "
452 			    "pending requests", __func__,
453 			    print_addr(&server->rs_sockaddr));
454 			if (TAILQ_NEXT(server, rs_entry) != NULL)
455 				goto next_server;
456 			goto fail;
457 		}
458 		req->rr_reqid = seq;
459 		radius_set_id(req->rr_reqpkt, req->rr_reqid);
460 	}
461 
462 	if (server->rs_nas_ipv4.s_addr != INADDR_ANY)
463 		radius_put_ipv4_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IP_ADDRESS,
464 		    server->rs_nas_ipv4);
465 	else if (!IN6_IS_ADDR_UNSPECIFIED(&server->rs_nas_ipv6))
466 		radius_put_ipv6_attr(req->rr_reqpkt,
467 		    RADIUS_TYPE_NAS_IPV6_ADDRESS, &server->rs_nas_ipv6);
468 	/* Identifier */
469 	radius_put_string_attr(req->rr_reqpkt, RADIUS_TYPE_NAS_IDENTIFIER,
470 	    IKED_NAS_ID);
471 
472 	if (req->rr_accounting) {
473 		if (req->rr_ntry == 0 && req->rr_nfailover == 0)
474 			radius_put_uint32_attr(req->rr_reqpkt,
475 			    RADIUS_TYPE_ACCT_DELAY_TIME, 0);
476 		else {
477 			clock_gettime(CLOCK_MONOTONIC, &now);
478 			timespecsub(&now, &req->rr_accttime, &now);
479 			radius_put_uint32_attr(req->rr_reqpkt,
480 			    RADIUS_TYPE_ACCT_DELAY_TIME, now.tv_sec);
481 		}
482 		radius_set_accounting_request_authenticator(req->rr_reqpkt,
483 		    server->rs_secret);
484 	} else {
485 		radius_put_message_authenticator(req->rr_reqpkt,
486 		    server->rs_secret);
487 	}
488 
489 	if (radius_send(server->rs_sock, req->rr_reqpkt, 0) < 0)
490 		log_info("%s: sending a RADIUS message failed: %s", __func__,
491 		    strerror(errno));
492 
493 	if (req->rr_ntry >= (int)nitems(timeouts))
494 		timer_add(env, &req->rr_timer, timeouts[nitems(timeouts) - 1]);
495 	else
496 		timer_add(env, &req->rr_timer, timeouts[req->rr_ntry]);
497 	req->rr_ntry++;
498 	return;
499  fail:
500 	if (req->rr_server != NULL)
501 		TAILQ_REMOVE(&server->rs_reqs, req, rr_entry);
502 	req->rr_server = NULL;
503 	if (req->rr_sa != NULL) {
504 		ikev2_ike_sa_setreason(req->rr_sa, "RADIUS request failed");
505 		sa_free(env, req->rr_sa);
506 	}
507 }
508 
509 void
510 iked_radius_fill_attributes(struct iked_sa *sa, RADIUS_PACKET *pkt)
511 {
512 	/* NAS Port Type = Virtual */
513 	radius_put_uint32_attr(pkt,
514 	    RADIUS_TYPE_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_VIRTUAL);
515 	/* Service Type =  Framed */
516 	radius_put_uint32_attr(pkt, RADIUS_TYPE_SERVICE_TYPE,
517 	    RADIUS_SERVICE_TYPE_FRAMED);
518 	/* Tunnel Type = EAP */
519 	radius_put_uint32_attr(pkt, RADIUS_TYPE_TUNNEL_TYPE,
520 	    RADIUS_TUNNEL_TYPE_ESP);
521 
522 	radius_put_string_attr(pkt, RADIUS_TYPE_CALLED_STATION_ID,
523 	    print_addr(&sa->sa_local.addr));
524 	radius_put_string_attr(pkt, RADIUS_TYPE_CALLING_STATION_ID,
525 	    print_addr(&sa->sa_peer.addr));
526 }
527 
528 void
529 iked_radius_config(struct iked_radserver_req *req, const RADIUS_PACKET *pkt,
530     int cfg_type, uint32_t vendor_id, uint8_t attr_type)
531 {
532 	unsigned int		 i;
533 	struct iked_sa		*sa = req->rr_sa;
534 	struct in_addr		 ia4;
535 	struct in6_addr		 ia6;
536 	struct sockaddr_in	*sin4;
537 	struct sockaddr_in6	*sin6;
538 	struct iked_addr	*addr;
539 	struct iked_cfg		*ikecfg;
540 
541 	for (i = 0; i < sa->sa_policy->pol_ncfg; i++) {
542 		ikecfg = &sa->sa_policy->pol_cfg[i];
543 		if (ikecfg->cfg_type == cfg_type &&
544 		    ikecfg->cfg_type != IKEV2_CFG_INTERNAL_IP4_ADDRESS)
545 			return;	/* use config rather than radius */
546 	}
547 	switch (cfg_type) {
548 	case IKEV2_CFG_INTERNAL_IP4_ADDRESS:
549 	case IKEV2_CFG_INTERNAL_IP4_NETMASK:
550 	case IKEV2_CFG_INTERNAL_IP4_DNS:
551 	case IKEV2_CFG_INTERNAL_IP4_NBNS:
552 	case IKEV2_CFG_INTERNAL_IP4_DHCP:
553 	case IKEV2_CFG_INTERNAL_IP4_SERVER:
554 		if (vendor_id == 0 && radius_has_attr(pkt, attr_type))
555 			radius_get_ipv4_attr(pkt, attr_type, &ia4);
556 		else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id,
557 		    attr_type))
558 			radius_get_vs_ipv4_attr(pkt, vendor_id, attr_type,
559 			    &ia4);
560 		else
561 			break; /* no attribute contained */
562 
563 		if (cfg_type == IKEV2_CFG_INTERNAL_IP4_NETMASK) {
564 			/*
565 			 * This assumes IKEV2_CFG_INTERNAL_IP4_ADDRESS is
566 			 * called before IKEV2_CFG_INTERNAL_IP4_NETMASK
567 			 */
568 			if (sa->sa_rad_addr == NULL) {
569 				/*
570 				 * RFC 7296, IKEV2_CFG_INTERNAL_IP4_NETMASK
571 				 * must be used with
572 				 * IKEV2_CFG_INTERNAL_IP4_ADDRESS
573 				 */
574 				break;
575 			}
576 			if (ia4.s_addr == 0) {
577 				log_debug("%s: netmask is wrong", __func__);
578 				break;
579 			}
580 			if (ia4.s_addr == htonl(0))
581 				sa->sa_rad_addr->addr_mask = 0;
582 			else
583 				sa->sa_rad_addr->addr_mask =
584 				    33 - ffs(ntohl(ia4.s_addr));
585 			if (sa->sa_rad_addr->addr_mask < 32)
586 				sa->sa_rad_addr->addr_net = 1;
587 		}
588 		if (cfg_type == IKEV2_CFG_INTERNAL_IP4_ADDRESS) {
589 			if ((addr = calloc(1, sizeof(*addr))) == NULL) {
590 				log_warn("%s: calloc", __func__);
591 				return;
592 			}
593 			sa->sa_rad_addr = addr;
594 		} else {
595 			req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY;
596 			req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type;
597 			addr = &req->rr_cfg[req->rr_ncfg].cfg.address;
598 			req->rr_ncfg++;
599 		}
600 		addr->addr_af = AF_INET;
601 		sin4 = (struct sockaddr_in *)&addr->addr;
602 		sin4->sin_family = AF_INET;
603 		sin4->sin_len = sizeof(struct sockaddr_in);
604 		sin4->sin_addr = ia4;
605 		break;
606 	case IKEV2_CFG_INTERNAL_IP6_ADDRESS:
607 	case IKEV2_CFG_INTERNAL_IP6_DNS:
608 	case IKEV2_CFG_INTERNAL_IP6_NBNS:
609 	case IKEV2_CFG_INTERNAL_IP6_DHCP:
610 	case IKEV2_CFG_INTERNAL_IP6_SERVER:
611 		if (vendor_id == 0 && radius_has_attr(pkt, attr_type))
612 			radius_get_ipv6_attr(pkt, attr_type, &ia6);
613 		else if (vendor_id != 0 && radius_has_vs_attr(pkt, vendor_id,
614 		    attr_type))
615 			radius_get_vs_ipv6_attr(pkt, vendor_id, attr_type,
616 			    &ia6);
617 		else
618 			break; /* no attribute contained */
619 
620 		if (cfg_type == IKEV2_CFG_INTERNAL_IP6_ADDRESS) {
621 			if ((addr = calloc(1, sizeof(*addr))) == NULL) {
622 				log_warn("%s: calloc", __func__);
623 				return;
624 			}
625 			sa->sa_rad_addr = addr;
626 		} else {
627 			req->rr_cfg[req->rr_ncfg].cfg_action = IKEV2_CP_REPLY;
628 			req->rr_cfg[req->rr_ncfg].cfg_type = cfg_type;
629 			addr = &req->rr_cfg[req->rr_ncfg].cfg.address;
630 			req->rr_ncfg++;
631 		}
632 		addr->addr_af = AF_INET;
633 		sin6 = (struct sockaddr_in6 *)&addr->addr;
634 		sin6->sin6_family = AF_INET6;
635 		sin6->sin6_len = sizeof(struct sockaddr_in6);
636 		sin6->sin6_addr = ia6;
637 		break;
638 	}
639 	return;
640 }
641 
642 void
643 iked_radius_acct_on(struct iked *env)
644 {
645 	if (TAILQ_EMPTY(&env->sc_radacctservers))
646 		return;
647 	if (env->sc_radaccton == 0) {	/* trigger once */
648 		iked_radius_acct_request(env, NULL,
649 		    RADIUS_ACCT_STATUS_TYPE_ACCT_ON);
650 		env->sc_radaccton = 1;
651 	}
652 }
653 
654 void
655 iked_radius_acct_off(struct iked *env)
656 {
657 	iked_radius_acct_request(env, NULL, RADIUS_ACCT_STATUS_TYPE_ACCT_OFF);
658 }
659 
660 void
661 iked_radius_acct_start(struct iked *env, struct iked_sa *sa)
662 {
663 	iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_START);
664 }
665 
666 void
667 iked_radius_acct_stop(struct iked *env, struct iked_sa *sa)
668 {
669 	iked_radius_acct_request(env, sa, RADIUS_ACCT_STATUS_TYPE_STOP);
670 }
671 
672 void
673 iked_radius_acct_request(struct iked *env, struct iked_sa *sa, uint8_t stype)
674 {
675 	struct iked_radserver_req	*req;
676 	RADIUS_PACKET			*pkt;
677 	struct iked_addr		*addr4 = NULL;
678 	struct iked_addr		*addr6 = NULL;
679 	struct in_addr			 mask4;
680 	char				 sa_id[IKED_ID_SIZE];
681 	char				 sid[16 + 1];
682 	struct timespec			 now;
683 	int				 cause;
684 
685 	if (TAILQ_EMPTY(&env->sc_radacctservers))
686 		return;
687 	/*
688 	 * In RFC2866 5.6, "Users who are delivered service without
689 	 * being authenticated SHOULD NOT generate Accounting records
690 	 */
691 	if (sa != NULL && sa->sa_eapid == NULL) {
692 		/* fallback to IKEID for accounting */
693 		if (ikev2_print_id(IKESA_DSTID(sa), sa_id, sizeof(sa_id)) != -1)
694 			sa->sa_eapid = strdup(sa_id);
695 		if (sa->sa_eapid == NULL)
696 			return;
697 	}
698 
699 	if ((req = calloc(1, sizeof(struct iked_radserver_req))) == NULL) {
700 		log_debug("%s: calloc faile for iked_radserver_req: %s",
701 		    __func__, strerror(errno));
702 		return;
703 	}
704 	req->rr_accounting = 1;
705 	clock_gettime(CLOCK_MONOTONIC, &now);
706 	req->rr_accttime = now;
707 	timer_set(env, &req->rr_timer, iked_radius_request_send, req);
708 
709 	if ((pkt = radius_new_request_packet(RADIUS_CODE_ACCOUNTING_REQUEST))
710 	    == NULL) {
711 		log_debug("%s: radius_new_request_packet failed %s", __func__,
712 		    strerror(errno));
713 		return;
714 	}
715 
716 	/* RFC 2866  5.1. Acct-Status-Type */
717 	radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_STATUS_TYPE, stype);
718 
719 	if (sa == NULL) {
720 		/* ASSERT(stype == RADIUS_ACCT_STATUS_TYPE_ACCT_ON ||
721 		    stype == RADIUS_ACCT_STATUS_TYPE_ACCT_OFF) */
722 		req->rr_reqpkt = pkt;
723 		req->rr_ntry = 0;
724 		iked_radius_request_send(env, req);
725 		return;
726 	}
727 
728 	iked_radius_fill_attributes(sa, pkt);
729 
730 	radius_put_string_attr(pkt, RADIUS_TYPE_USER_NAME, sa->sa_eapid);
731 
732 	/* RFC 2866  5.5. Acct-Session-Id */
733 	snprintf(sid, sizeof(sid), "%016llx",
734 	    (unsigned long long)sa->sa_hdr.sh_ispi);
735 	radius_put_string_attr(pkt, RADIUS_TYPE_ACCT_SESSION_ID, sid);
736 
737 	/* Accounting Request must have Framed-IP-Address */
738 	addr4 = sa->sa_addrpool;
739 	if (addr4 != NULL) {
740 		radius_put_ipv4_attr(pkt, RADIUS_TYPE_FRAMED_IP_ADDRESS,
741 		    ((struct sockaddr_in *)&addr4->addr)->sin_addr);
742 		if (addr4->addr_mask != 0) {
743 			mask4.s_addr = htonl(
744 			    0xFFFFFFFFUL << (32 - addr4->addr_mask));
745 			radius_put_ipv4_attr(pkt,
746 			    RADIUS_TYPE_FRAMED_IP_NETMASK, mask4);
747 		}
748 	}
749 	addr6 = sa->sa_addrpool6;
750 	if (addr6 != NULL)
751 		radius_put_ipv6_attr(pkt, RADIUS_TYPE_FRAMED_IPV6_ADDRESS,
752 		    &((struct sockaddr_in6 *)&addr6->addr)->sin6_addr);
753 
754 	/* RFC2866 5.6 Acct-Authentic */
755 	radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_AUTHENTIC,
756 	    (sa->sa_radreq != NULL)? RADIUS_ACCT_AUTHENTIC_RADIUS :
757 	    RADIUS_ACCT_AUTHENTIC_LOCAL);
758 
759 	switch (stype) {
760 	case RADIUS_ACCT_STATUS_TYPE_START:
761 		if (req->rr_sa && req->rr_sa->sa_eapclass != NULL)
762 			radius_put_raw_attr(pkt, RADIUS_TYPE_CLASS,
763 			    ibuf_data(req->rr_sa->sa_eapclass),
764 			    ibuf_size(req->rr_sa->sa_eapclass));
765 		break;
766 	case RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE:
767 	case RADIUS_ACCT_STATUS_TYPE_STOP:
768 		/* RFC 2866 5.7.  Acct-Session-Time */
769 		timespecsub(&now, &sa->sa_starttime, &now);
770 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_SESSION_TIME,
771 		    now.tv_sec);
772 		/* RFC 2866 5.10 Acct-Terminate-Cause */
773 		cause = RADIUS_TERMNATE_CAUSE_SERVICE_UNAVAIL;
774 		if (sa->sa_reason) {
775 			if (strcmp(sa->sa_reason, "received delete") == 0) {
776 				cause = RADIUS_TERMNATE_CAUSE_USER_REQUEST;
777 			} else if (strcmp(sa->sa_reason, "SA rekeyed") == 0) {
778 				cause = RADIUS_TERMNATE_CAUSE_SESSION_TIMEOUT;
779 			} else if (strncmp(sa->sa_reason, "retransmit",
780 			    strlen("retransmit")) == 0) {
781 				cause = RADIUS_TERMNATE_CAUSE_LOST_SERVICE;
782 			} else if (strcmp(sa->sa_reason,
783 			    "disconnect requested") == 0) {
784 				cause = RADIUS_TERMNATE_CAUSE_ADMIN_RESET;
785 			}
786 		}
787 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_TERMINATE_CAUSE,
788 		    cause);
789 		/* I/O statistics {Input,Output}-{Packets,Octets,Gigawords} */
790 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_PACKETS,
791 		    sa->sa_stats.sas_ipackets);
792 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_PACKETS,
793 		    sa->sa_stats.sas_opackets);
794 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_OCTETS,
795 		    sa->sa_stats.sas_ibytes & 0xffffffffUL);
796 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_OCTETS,
797 		    sa->sa_stats.sas_obytes & 0xffffffffUL);
798 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_INPUT_GIGAWORDS,
799 		    sa->sa_stats.sas_ibytes >> 32);
800 		radius_put_uint32_attr(pkt, RADIUS_TYPE_ACCT_OUTPUT_GIGAWORDS,
801 		    sa->sa_stats.sas_obytes >> 32);
802 		break;
803 	}
804 	req->rr_reqpkt = pkt;
805 	req->rr_ntry = 0;
806 	iked_radius_request_send(env, req);
807 }
808 
809 void
810 iked_radius_dae_on_event(int fd, short ev, void *ctx)
811 {
812 	struct iked_raddae	*dae = ctx;
813 	struct iked		*env = dae->rd_env;
814 	RADIUS_PACKET		*req = NULL, *res = NULL;
815 	struct sockaddr_storage	 ss;
816 	socklen_t		 sslen;
817 	struct iked_radclient	*client;
818 	struct iked_sa		*sa = NULL;
819 	char			 attr[256], username[256];
820 	char			*endp, *reason, *nakcause = NULL;
821 	int			 code, n = 0;
822 	uint64_t		 ispi = 0;
823 	uint32_t		 u32, cause = 0;
824 	struct iked_addr	*addr4 = NULL;
825 
826 	reason = "disconnect requested";
827 
828 	sslen = sizeof(ss);
829 	req = radius_recvfrom(dae->rd_sock, 0, (struct sockaddr *)&ss, &sslen);
830 	if (req == NULL) {
831 		log_warn("%s: receiving a RADIUS message failed: %s", __func__,
832 		    strerror(errno));
833 		return;
834 	}
835 	TAILQ_FOREACH(client, &env->sc_raddaeclients, rc_entry) {
836 		if (sockaddr_cmp((struct sockaddr *)&client->rc_sockaddr,
837 		    (struct sockaddr *)&ss, -1) == 0)
838 			break;
839 	}
840 	if (client == NULL) {
841 		log_warnx("%s: received RADIUS message from %s: "
842 		    "unknown client", __func__, print_addr(&ss));
843 		goto out;
844 	}
845 
846 	if (radius_check_accounting_request_authenticator(req,
847 	    client->rc_secret) != 0) {
848 		log_warnx("%s: received an invalid RADIUS message from %s: bad "
849 		    "response authenticator", __func__, print_addr(&ss));
850 		goto out;
851 	}
852 
853 	if ((code = radius_get_code(req)) != RADIUS_CODE_DISCONNECT_REQUEST) {
854 		/* Code other than Disconnect-Request is not supported */
855 		if (code == RADIUS_CODE_COA_REQUEST) {
856 			code = RADIUS_CODE_COA_NAK;
857 			cause = RADIUS_ERROR_CAUSE_ADMINISTRATIVELY_PROHIBITED;
858 			nakcause = "Coa-Request is not supported";
859 			goto send;
860 		}
861 		log_warnx("%s: received an invalid RADIUS message "
862 		    "from %s: unknown code %d", __func__,
863 		    print_addr(&ss), code);
864 		goto out;
865 	}
866 
867 	log_info("received Disconnect-Request from %s", print_addr(&ss));
868 
869 	if (radius_get_string_attr(req, RADIUS_TYPE_NAS_IDENTIFIER, attr,
870 	    sizeof(attr)) == 0 && strcmp(attr, IKED_NAS_ID) != 0) {
871 		cause = RADIUS_ERROR_CAUSE_NAS_IDENTIFICATION_MISMATCH;
872 		nakcause = "NAS-Identifier is not matched";
873 		goto search_done;
874 	}
875 
876 	/* prepare User-Name attribute */
877 	memset(username, 0, sizeof(username));
878 	radius_get_string_attr(req, RADIUS_TYPE_USER_NAME, username,
879 	    sizeof(username));
880 
881 	if (radius_get_string_attr(req, RADIUS_TYPE_ACCT_SESSION_ID, attr,
882 	    sizeof(attr)) == 0) {
883 		/* the client is to disconnect a session */
884 		ispi = strtoull(attr, &endp, 16);
885 		if (attr[0] == '\0' || *endp != '\0' || errno == ERANGE ||
886 		    ispi == ULLONG_MAX) {
887 			cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
888 			nakcause = "Session-Id is wrong";
889 			goto search_done;
890 
891 		}
892 		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
893 			if (sa->sa_hdr.sh_ispi == ispi)
894 				break;
895 		}
896 		if (sa == NULL)
897 			goto search_done;
898 		if (username[0] != '\0' && (sa->sa_eapid == NULL ||
899 		    strcmp(username, sa->sa_eapid) != 0)) {
900 			/* specified User-Name attribute is mismatched */
901 			cause = RADIUS_ERROR_CAUSE_INVALID_ATTRIBUTE_VALUE;
902 			nakcause = "User-Name is not matched";
903 			goto search_done;
904 		}
905 		ikev2_ike_sa_setreason(sa, reason);
906 		ikev2_ike_sa_delete(env, sa);
907 		n++;
908 	} else if (username[0] != '\0') {
909 		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
910 			if (sa->sa_eapid != NULL &&
911 			    strcmp(sa->sa_eapid, username) == 0) {
912 				ikev2_ike_sa_setreason(sa, reason);
913 				ikev2_ike_sa_delete(env, sa);
914 				n++;
915 			}
916 		}
917 	} else if (radius_get_uint32_attr(req, RADIUS_TYPE_FRAMED_IP_ADDRESS,
918 	    &u32) == 0) {
919 		RB_FOREACH(sa, iked_sas, &env->sc_sas) {
920 			addr4 = sa->sa_addrpool;
921 			if (addr4 != NULL) {
922 				if (u32 == ((struct sockaddr_in *)&addr4->addr)
923 				    ->sin_addr.s_addr) {
924 					ikev2_ike_sa_setreason(sa, reason);
925 					ikev2_ike_sa_delete(env, sa);
926 					n++;
927 				}
928 			}
929 		}
930 	}
931  search_done:
932 	if (n > 0)
933 		code = RADIUS_CODE_DISCONNECT_ACK;
934 	else {
935 		if (nakcause == NULL)
936 			nakcause = "session not found";
937 		if (cause == 0)
938 			cause = RADIUS_ERROR_CAUSE_SESSION_NOT_FOUND;
939 		code = RADIUS_CODE_DISCONNECT_NAK;
940 	}
941  send:
942 	res = radius_new_response_packet(code, req);
943 	if (res == NULL) {
944 		log_warn("%s: radius_new_response_packet", __func__);
945 		goto out;
946 	}
947 	if (cause != 0)
948 		radius_put_uint32_attr(res, RADIUS_TYPE_ERROR_CAUSE, cause);
949 	radius_set_response_authenticator(res, client->rc_secret);
950 	if (radius_sendto(dae->rd_sock, res, 0, (struct sockaddr *)&ss, sslen)
951 	    == -1)
952 		log_warn("%s: sendto", __func__);
953 	log_info("send %s for %s%s%s",
954 	    (code == RADIUS_CODE_DISCONNECT_ACK)? "Disconnect-ACK" :
955 	    (code == RADIUS_CODE_DISCONNECT_NAK)? "Disconnect-NAK" : "CoA-NAK",
956 	    print_addr(&ss), (nakcause)? ": " : "", (nakcause)? nakcause : "");
957  out:
958 	radius_delete_packet(req);
959 	if (res != NULL)
960 		radius_delete_packet(res);
961 }
962