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