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