xref: /openbsd-src/sbin/iked/config.c (revision 9ca241fcbd1e3e57a03aa8097496cb954222290b)
1*9ca241fcSyasuoka /*	$OpenBSD: config.c,v 1.99 2024/09/15 11:08:50 yasuoka Exp $	*/
245ae9d61Sreyk 
345ae9d61Sreyk /*
465c540d0Spatrick  * Copyright (c) 2019 Tobias Heider <tobias.heider@stusta.de>
5fcebd35dSreyk  * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org>
645ae9d61Sreyk  *
745ae9d61Sreyk  * Permission to use, copy, modify, and distribute this software for any
845ae9d61Sreyk  * purpose with or without fee is hereby granted, provided that the above
945ae9d61Sreyk  * copyright notice and this permission notice appear in all copies.
1045ae9d61Sreyk  *
1145ae9d61Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1245ae9d61Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1345ae9d61Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1445ae9d61Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1545ae9d61Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1645ae9d61Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1745ae9d61Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1845ae9d61Sreyk  */
1945ae9d61Sreyk 
2045ae9d61Sreyk #include <sys/queue.h>
2145ae9d61Sreyk #include <sys/socket.h>
2245ae9d61Sreyk #include <sys/uio.h>
2345ae9d61Sreyk 
2445ae9d61Sreyk #include <stdlib.h>
2545ae9d61Sreyk #include <stdio.h>
2645ae9d61Sreyk #include <unistd.h>
2745ae9d61Sreyk #include <string.h>
2845ae9d61Sreyk #include <signal.h>
2945ae9d61Sreyk #include <errno.h>
3045ae9d61Sreyk #include <err.h>
3145ae9d61Sreyk #include <event.h>
3245ae9d61Sreyk 
33e8b444cdSreyk #include <openssl/evp.h>
34e8b444cdSreyk #include <openssl/pem.h>
35e8b444cdSreyk 
3645ae9d61Sreyk #include "iked.h"
3745ae9d61Sreyk #include "ikev2.h"
3845ae9d61Sreyk 
3945ae9d61Sreyk struct iked_sa *
4045ae9d61Sreyk config_new_sa(struct iked *env, int initiator)
4145ae9d61Sreyk {
4245ae9d61Sreyk 	struct iked_sa	*sa;
4345ae9d61Sreyk 
4445ae9d61Sreyk 	if ((sa = calloc(1, sizeof(*sa))) == NULL)
4545ae9d61Sreyk 		return (NULL);
4645ae9d61Sreyk 
4745ae9d61Sreyk 	TAILQ_INIT(&sa->sa_proposals);
4845ae9d61Sreyk 	TAILQ_INIT(&sa->sa_childsas);
4945ae9d61Sreyk 	TAILQ_INIT(&sa->sa_flows);
50c45fd413Smikeb 	TAILQ_INIT(&sa->sa_requests);
51c45fd413Smikeb 	TAILQ_INIT(&sa->sa_responses);
5245ae9d61Sreyk 	sa->sa_hdr.sh_initiator = initiator;
53ae494144Sreyk 	sa->sa_type = IKED_SATYPE_LOCAL;
5445ae9d61Sreyk 
5545ae9d61Sreyk 	if (initiator)
5645ae9d61Sreyk 		sa->sa_hdr.sh_ispi = config_getspi();
5745ae9d61Sreyk 	else
5845ae9d61Sreyk 		sa->sa_hdr.sh_rspi = config_getspi();
5945ae9d61Sreyk 
6045ae9d61Sreyk 	gettimeofday(&sa->sa_timecreated, NULL);
6145ae9d61Sreyk 	memcpy(&sa->sa_timeused, &sa->sa_timecreated, sizeof(sa->sa_timeused));
6245ae9d61Sreyk 
63b41cc0c8Stobhe 	ikestat_inc(env, ikes_sa_created);
6445ae9d61Sreyk 	return (sa);
6545ae9d61Sreyk }
6645ae9d61Sreyk 
67d09d3a7dSreyk uint64_t
6845ae9d61Sreyk config_getspi(void)
6945ae9d61Sreyk {
70d09d3a7dSreyk 	uint64_t	 spi;
7145ae9d61Sreyk 
720868714eSderaadt 	do {
730868714eSderaadt 		arc4random_buf(&spi, sizeof spi);
740868714eSderaadt 	} while (spi == 0);
7545ae9d61Sreyk 
7645ae9d61Sreyk 	return (spi);
7745ae9d61Sreyk }
7845ae9d61Sreyk 
7945ae9d61Sreyk void
800cdab560Smarkus config_free_kex(struct iked_kex *kex)
810cdab560Smarkus {
820cdab560Smarkus 	if (kex == NULL)
830cdab560Smarkus 		return;
840cdab560Smarkus 
85be2b38f5Sclaudio 	ibuf_free(kex->kex_inonce);
86be2b38f5Sclaudio 	ibuf_free(kex->kex_rnonce);
870cdab560Smarkus 
880cdab560Smarkus 	group_free(kex->kex_dhgroup);
89be2b38f5Sclaudio 	ibuf_free(kex->kex_dhiexchange);
90be2b38f5Sclaudio 	ibuf_free(kex->kex_dhrexchange);
910cdab560Smarkus 
920cdab560Smarkus 	free(kex);
930cdab560Smarkus }
940cdab560Smarkus 
950cdab560Smarkus void
9665c540d0Spatrick config_free_fragments(struct iked_frag *frag)
9765c540d0Spatrick {
9865c540d0Spatrick 	size_t i;
9965c540d0Spatrick 
10065c540d0Spatrick 	if (frag && frag->frag_arr) {
10165c540d0Spatrick 		for (i = 0; i < frag->frag_total; i++) {
10265c540d0Spatrick 			if (frag->frag_arr[i] != NULL)
10365c540d0Spatrick 				free(frag->frag_arr[i]->frag_data);
10465c540d0Spatrick 			free(frag->frag_arr[i]);
10565c540d0Spatrick 		}
10665c540d0Spatrick 		free(frag->frag_arr);
10765c540d0Spatrick 		bzero(frag, sizeof(struct iked_frag));
10865c540d0Spatrick 	}
10965c540d0Spatrick }
11065c540d0Spatrick 
11165c540d0Spatrick void
11245ae9d61Sreyk config_free_sa(struct iked *env, struct iked_sa *sa)
11345ae9d61Sreyk {
114055943a1Stobhe 	int i;
115055943a1Stobhe 
116b3eeacebSmikeb 	timer_del(env, &sa->sa_timer);
117d52b1aceSpatrick 	timer_del(env, &sa->sa_keepalive);
1186e1880a3Smarkus 	timer_del(env, &sa->sa_rekey);
11981bdcbc1Smikeb 
12065c540d0Spatrick 	config_free_fragments(&sa->sa_fragments);
12145ae9d61Sreyk 	config_free_proposals(&sa->sa_proposals, 0);
12245ae9d61Sreyk 	config_free_childsas(env, &sa->sa_childsas, NULL, NULL);
123264f8b22Stobhe 	sa_configure_iface(env, sa, 0);
1249dbd37b8Sreyk 	sa_free_flows(env, &sa->sa_flows);
12545ae9d61Sreyk 
126f36db9c4Syasuoka 	iked_radius_acct_stop(env, sa);
127f36db9c4Syasuoka 
12843be1c05Smarkus 	if (sa->sa_addrpool) {
12943be1c05Smarkus 		(void)RB_REMOVE(iked_addrpool, &env->sc_addrpool, sa);
13043be1c05Smarkus 		free(sa->sa_addrpool);
13143be1c05Smarkus 	}
13219dc8638Spatrick 	if (sa->sa_addrpool6) {
13319dc8638Spatrick 		(void)RB_REMOVE(iked_addrpool6, &env->sc_addrpool6, sa);
13419dc8638Spatrick 		free(sa->sa_addrpool6);
13519dc8638Spatrick 	}
13643be1c05Smarkus 
137b3ef9220Sreyk 	if (sa->sa_policy) {
13832b6fc39Smarkus 		TAILQ_REMOVE(&sa->sa_policy->pol_sapeers, sa, sa_peer_entry);
13945ae9d61Sreyk 		policy_unref(env, sa->sa_policy);
140b3ef9220Sreyk 	}
14145ae9d61Sreyk 
142c45fd413Smikeb 	ikev2_msg_flushqueue(env, &sa->sa_requests);
143c45fd413Smikeb 	ikev2_msg_flushqueue(env, &sa->sa_responses);
144c45fd413Smikeb 
145be2b38f5Sclaudio 	ibuf_free(sa->sa_inonce);
146be2b38f5Sclaudio 	ibuf_free(sa->sa_rnonce);
14745ae9d61Sreyk 
14845ae9d61Sreyk 	group_free(sa->sa_dhgroup);
149be2b38f5Sclaudio 	ibuf_free(sa->sa_dhiexchange);
150be2b38f5Sclaudio 	ibuf_free(sa->sa_dhrexchange);
15145ae9d61Sreyk 
152be2b38f5Sclaudio 	ibuf_free(sa->sa_simult);
15383e6846fSmikeb 
15445ae9d61Sreyk 	hash_free(sa->sa_prf);
15545ae9d61Sreyk 	hash_free(sa->sa_integr);
15645ae9d61Sreyk 	cipher_free(sa->sa_encr);
15745ae9d61Sreyk 
158be2b38f5Sclaudio 	ibuf_free(sa->sa_key_d);
159be2b38f5Sclaudio 	ibuf_free(sa->sa_key_iauth);
160be2b38f5Sclaudio 	ibuf_free(sa->sa_key_rauth);
161be2b38f5Sclaudio 	ibuf_free(sa->sa_key_iencr);
162be2b38f5Sclaudio 	ibuf_free(sa->sa_key_rencr);
163be2b38f5Sclaudio 	ibuf_free(sa->sa_key_iprf);
164be2b38f5Sclaudio 	ibuf_free(sa->sa_key_rprf);
16545ae9d61Sreyk 
166be2b38f5Sclaudio 	ibuf_free(sa->sa_1stmsg);
167be2b38f5Sclaudio 	ibuf_free(sa->sa_2ndmsg);
16845ae9d61Sreyk 
169be2b38f5Sclaudio 	ibuf_free(sa->sa_iid.id_buf);
170be2b38f5Sclaudio 	ibuf_free(sa->sa_rid.id_buf);
171be2b38f5Sclaudio 	ibuf_free(sa->sa_icert.id_buf);
172be2b38f5Sclaudio 	ibuf_free(sa->sa_rcert.id_buf);
173055943a1Stobhe 	for (i = 0; i < IKED_SCERT_MAX; i++)
174be2b38f5Sclaudio 		ibuf_free(sa->sa_scert[i].id_buf);
175be2b38f5Sclaudio 	ibuf_free(sa->sa_localauth.id_buf);
176be2b38f5Sclaudio 	ibuf_free(sa->sa_peerauth.id_buf);
17745ae9d61Sreyk 
178be2b38f5Sclaudio 	ibuf_free(sa->sa_eap.id_buf);
17945ae9d61Sreyk 	free(sa->sa_eapid);
180be2b38f5Sclaudio 	ibuf_free(sa->sa_eapmsk);
181*9ca241fcSyasuoka 	ibuf_free(sa->sa_eapclass);
18245ae9d61Sreyk 
18352b3354cStobhe 	free(sa->sa_cp_addr);
18452b3354cStobhe 	free(sa->sa_cp_addr6);
1859ef39cf4Stobhe 	free(sa->sa_cp_dns);
18652b3354cStobhe 
187160b250fSreyk 	free(sa->sa_tag);
188b41cc0c8Stobhe 
189b41cc0c8Stobhe 	if (sa->sa_state == IKEV2_STATE_ESTABLISHED)
190b41cc0c8Stobhe 		ikestat_dec(env, ikes_sa_established_current);
191b41cc0c8Stobhe 	ikestat_inc(env, ikes_sa_removed);
192b41cc0c8Stobhe 
193f36db9c4Syasuoka 	free(sa->sa_rad_addr);
194f36db9c4Syasuoka 	free(sa->sa_rad_addr6);
195f36db9c4Syasuoka 	iked_radius_request_free(env, sa->sa_radreq);
196f36db9c4Syasuoka 
19745ae9d61Sreyk 	free(sa);
19845ae9d61Sreyk }
19945ae9d61Sreyk 
20045ae9d61Sreyk struct iked_policy *
20145ae9d61Sreyk config_new_policy(struct iked *env)
20245ae9d61Sreyk {
20345ae9d61Sreyk 	struct iked_policy	*pol;
20445ae9d61Sreyk 
20545ae9d61Sreyk 	if ((pol = calloc(1, sizeof(*pol))) == NULL)
20645ae9d61Sreyk 		return (NULL);
20745ae9d61Sreyk 
20832b6fc39Smarkus 	/* XXX caller does this again */
20945ae9d61Sreyk 	TAILQ_INIT(&pol->pol_proposals);
21032b6fc39Smarkus 	TAILQ_INIT(&pol->pol_sapeers);
2111f864a9aStobhe 	TAILQ_INIT(&pol->pol_tssrc);
2121f864a9aStobhe 	TAILQ_INIT(&pol->pol_tsdst);
21332b6fc39Smarkus 	RB_INIT(&pol->pol_flows);
21445ae9d61Sreyk 
21545ae9d61Sreyk 	return (pol);
21645ae9d61Sreyk }
21745ae9d61Sreyk 
21845ae9d61Sreyk void
21945ae9d61Sreyk config_free_policy(struct iked *env, struct iked_policy *pol)
22045ae9d61Sreyk {
22145ae9d61Sreyk 	struct iked_sa		*sa;
2221f864a9aStobhe 	struct iked_ts	*tsi;
22345ae9d61Sreyk 
22445ae9d61Sreyk 	if (pol->pol_flags & IKED_POLICY_REFCNT)
22545ae9d61Sreyk 		goto remove;
22645ae9d61Sreyk 
227ac3a6947Stobhe 	/*
228ac3a6947Stobhe 	 * Remove policy from the sc_policies list, but increment
229ac3a6947Stobhe 	 * refcount for every SA linked for the policy.
230ac3a6947Stobhe 	 */
231ac3a6947Stobhe 	pol->pol_flags |= IKED_POLICY_REFCNT;
232ac3a6947Stobhe 
233e2015428Sreyk 	TAILQ_REMOVE(&env->sc_policies, pol, pol_entry);
23445ae9d61Sreyk 
23532b6fc39Smarkus 	TAILQ_FOREACH(sa, &pol->pol_sapeers, sa_peer_entry) {
23645ae9d61Sreyk 		if (sa->sa_policy == pol)
23745ae9d61Sreyk 			policy_ref(env, pol);
23832b6fc39Smarkus 		else
23932b6fc39Smarkus 			log_warnx("%s: ERROR: sa_policy %p != pol %p",
24032b6fc39Smarkus 			    __func__, sa->sa_policy, pol);
24145ae9d61Sreyk 	}
24245ae9d61Sreyk 
24345ae9d61Sreyk 	if (pol->pol_refcnt)
24445ae9d61Sreyk 		return;
24545ae9d61Sreyk 
24645ae9d61Sreyk  remove:
2471f864a9aStobhe 	while ((tsi = TAILQ_FIRST(&pol->pol_tssrc))) {
2481f864a9aStobhe 		TAILQ_REMOVE(&pol->pol_tssrc, tsi, ts_entry);
2491f864a9aStobhe 		free(tsi);
2501f864a9aStobhe 	}
2511f864a9aStobhe 	while ((tsi = TAILQ_FIRST(&pol->pol_tsdst))) {
2521f864a9aStobhe 		TAILQ_REMOVE(&pol->pol_tsdst, tsi, ts_entry);
2531f864a9aStobhe 		free(tsi);
2541f864a9aStobhe 	}
25545ae9d61Sreyk 	config_free_proposals(&pol->pol_proposals, 0);
256b0eeedd0Smikeb 	config_free_flows(env, &pol->pol_flows);
25745ae9d61Sreyk 	free(pol);
25845ae9d61Sreyk }
25945ae9d61Sreyk 
26045ae9d61Sreyk struct iked_proposal *
261d09d3a7dSreyk config_add_proposal(struct iked_proposals *head, unsigned int id,
262d09d3a7dSreyk     unsigned int proto)
26345ae9d61Sreyk {
26445ae9d61Sreyk 	struct iked_proposal	*pp;
26545ae9d61Sreyk 
26645ae9d61Sreyk 	TAILQ_FOREACH(pp, head, prop_entry) {
26745ae9d61Sreyk 		if (pp->prop_protoid == proto &&
26845ae9d61Sreyk 		    pp->prop_id == id)
26945ae9d61Sreyk 			return (pp);
27045ae9d61Sreyk 	}
27145ae9d61Sreyk 
27245ae9d61Sreyk 	if ((pp = calloc(1, sizeof(*pp))) == NULL)
27345ae9d61Sreyk 		return (NULL);
27445ae9d61Sreyk 
27545ae9d61Sreyk 	pp->prop_protoid = proto;
27645ae9d61Sreyk 	pp->prop_id = id;
27745ae9d61Sreyk 
27845ae9d61Sreyk 	TAILQ_INSERT_TAIL(head, pp, prop_entry);
27945ae9d61Sreyk 
28045ae9d61Sreyk 	return (pp);
28145ae9d61Sreyk }
28245ae9d61Sreyk 
28345ae9d61Sreyk void
284822b336dStobhe config_free_proposal(struct iked_proposals *head, struct iked_proposal *prop)
285822b336dStobhe {
286822b336dStobhe 	TAILQ_REMOVE(head, prop, prop_entry);
287822b336dStobhe 	if (prop->prop_nxforms)
288822b336dStobhe 		free(prop->prop_xforms);
289822b336dStobhe 	free(prop);
290822b336dStobhe }
291822b336dStobhe 
292822b336dStobhe void
293d09d3a7dSreyk config_free_proposals(struct iked_proposals *head, unsigned int proto)
29445ae9d61Sreyk {
2958177f5d5Stobhe 	struct iked_proposal	*prop, *proptmp;
29645ae9d61Sreyk 
2978177f5d5Stobhe 	TAILQ_FOREACH_SAFE(prop, head, prop_entry, proptmp) {
29845ae9d61Sreyk 		/* Free any proposal or only selected SA proto */
29945ae9d61Sreyk 		if (proto != 0 && prop->prop_protoid != proto)
30045ae9d61Sreyk 			continue;
30145ae9d61Sreyk 
30245ae9d61Sreyk 		log_debug("%s: free %p", __func__, prop);
30345ae9d61Sreyk 
304822b336dStobhe 		config_free_proposal(head, prop);
30545ae9d61Sreyk 	}
30645ae9d61Sreyk }
30745ae9d61Sreyk 
30845ae9d61Sreyk void
309b0eeedd0Smikeb config_free_flows(struct iked *env, struct iked_flows *head)
31045ae9d61Sreyk {
3119c3d68f7Stobhe 	struct iked_flow	*flow;
31245ae9d61Sreyk 
3139c3d68f7Stobhe 	while ((flow = RB_MIN(iked_flows, head))) {
31445ae9d61Sreyk 		log_debug("%s: free %p", __func__, flow);
3159dbd37b8Sreyk 		RB_REMOVE(iked_flows, head, flow);
31645ae9d61Sreyk 		flow_free(flow);
31745ae9d61Sreyk 	}
31845ae9d61Sreyk }
31945ae9d61Sreyk 
32045ae9d61Sreyk void
32145ae9d61Sreyk config_free_childsas(struct iked *env, struct iked_childsas *head,
32245ae9d61Sreyk     struct iked_spi *peerspi, struct iked_spi *localspi)
32345ae9d61Sreyk {
324fe856664Smbuhl 	struct iked_childsa	*csa, *csatmp, *ipcomp;
32545ae9d61Sreyk 
32645ae9d61Sreyk 	if (localspi != NULL)
32745ae9d61Sreyk 		bzero(localspi, sizeof(*localspi));
32845ae9d61Sreyk 
3298177f5d5Stobhe 	TAILQ_FOREACH_SAFE(csa, head, csa_entry, csatmp) {
33045ae9d61Sreyk 		if (peerspi != NULL) {
33145ae9d61Sreyk 			/* Only delete matching peer SPIs */
33245ae9d61Sreyk 			if (peerspi->spi != csa->csa_peerspi)
33345ae9d61Sreyk 				continue;
33445ae9d61Sreyk 
33545ae9d61Sreyk 			/* Store assigned local SPI */
33645ae9d61Sreyk 			if (localspi != NULL && localspi->spi == 0)
33745ae9d61Sreyk 				memcpy(localspi, &csa->csa_spi,
33845ae9d61Sreyk 				    sizeof(*localspi));
33945ae9d61Sreyk 		}
34045ae9d61Sreyk 		log_debug("%s: free %p", __func__, csa);
34145ae9d61Sreyk 
34245ae9d61Sreyk 		TAILQ_REMOVE(head, csa, csa_entry);
343b0eeedd0Smikeb 		if (csa->csa_loaded) {
344856dba1dSmikeb 			RB_REMOVE(iked_activesas, &env->sc_activesas, csa);
3458f6f6c19Stobhe 			(void)pfkey_sa_delete(env, csa);
346b0eeedd0Smikeb 		}
347fe856664Smbuhl 		if ((ipcomp = csa->csa_bundled) != NULL) {
348fe856664Smbuhl 			log_debug("%s: free IPCOMP %p", __func__, ipcomp);
349fe856664Smbuhl 			if (ipcomp->csa_loaded)
350fe856664Smbuhl 				(void)pfkey_sa_delete(env, ipcomp);
351fe856664Smbuhl 			childsa_free(ipcomp);
352e7fee6f8Stobhe 		}
35345ae9d61Sreyk 		childsa_free(csa);
354b41cc0c8Stobhe 		ikestat_inc(env, ikes_csa_removed);
35545ae9d61Sreyk 	}
35645ae9d61Sreyk }
35745ae9d61Sreyk 
358822b336dStobhe int
359d09d3a7dSreyk config_add_transform(struct iked_proposal *prop, unsigned int type,
360d09d3a7dSreyk     unsigned int id, unsigned int length, unsigned int keylength)
36145ae9d61Sreyk {
36245ae9d61Sreyk 	struct iked_transform	*xform;
36345ae9d61Sreyk 	struct iked_constmap	*map = NULL;
36445ae9d61Sreyk 	int			 score = 1;
365d09d3a7dSreyk 	unsigned int		 i;
36645ae9d61Sreyk 
36745ae9d61Sreyk 	switch (type) {
36845ae9d61Sreyk 	case IKEV2_XFORMTYPE_ENCR:
36945ae9d61Sreyk 		map = ikev2_xformencr_map;
37045ae9d61Sreyk 		break;
37145ae9d61Sreyk 	case IKEV2_XFORMTYPE_PRF:
37245ae9d61Sreyk 		map = ikev2_xformprf_map;
37345ae9d61Sreyk 		break;
37445ae9d61Sreyk 	case IKEV2_XFORMTYPE_INTEGR:
37545ae9d61Sreyk 		map = ikev2_xformauth_map;
37645ae9d61Sreyk 		break;
37745ae9d61Sreyk 	case IKEV2_XFORMTYPE_DH:
37845ae9d61Sreyk 		map = ikev2_xformdh_map;
37945ae9d61Sreyk 		break;
38045ae9d61Sreyk 	case IKEV2_XFORMTYPE_ESN:
38145ae9d61Sreyk 		map = ikev2_xformesn_map;
38245ae9d61Sreyk 		break;
38345ae9d61Sreyk 	default:
38445ae9d61Sreyk 		log_debug("%s: invalid transform type %d", __func__, type);
385822b336dStobhe 		return (-2);
38645ae9d61Sreyk 	}
38745ae9d61Sreyk 
38845ae9d61Sreyk 	for (i = 0; i < prop->prop_nxforms; i++) {
38945ae9d61Sreyk 		xform = prop->prop_xforms + i;
39045ae9d61Sreyk 		if (xform->xform_type == type &&
39145ae9d61Sreyk 		    xform->xform_id == id &&
39245ae9d61Sreyk 		    xform->xform_length == length)
393822b336dStobhe 			return (0);
39445ae9d61Sreyk 	}
39545ae9d61Sreyk 
39645ae9d61Sreyk 	for (i = 0; i < prop->prop_nxforms; i++) {
39745ae9d61Sreyk 		xform = prop->prop_xforms + i;
39845ae9d61Sreyk 		if (xform->xform_type == type) {
39945ae9d61Sreyk 			switch (type) {
40045ae9d61Sreyk 			case IKEV2_XFORMTYPE_ENCR:
40145ae9d61Sreyk 			case IKEV2_XFORMTYPE_INTEGR:
40245ae9d61Sreyk 				score += 3;
40345ae9d61Sreyk 				break;
40445ae9d61Sreyk 			case IKEV2_XFORMTYPE_DH:
40545ae9d61Sreyk 				score += 2;
40645ae9d61Sreyk 				break;
40745ae9d61Sreyk 			default:
40845ae9d61Sreyk 				score += 1;
40945ae9d61Sreyk 				break;
41045ae9d61Sreyk 			}
41145ae9d61Sreyk 		}
41245ae9d61Sreyk 	}
41345ae9d61Sreyk 
41498a76b0dSderaadt 	if ((xform = reallocarray(prop->prop_xforms,
41598a76b0dSderaadt 	    prop->prop_nxforms + 1, sizeof(*xform))) == NULL) {
416822b336dStobhe 		return (-1);
41745ae9d61Sreyk 	}
41845ae9d61Sreyk 
41945ae9d61Sreyk 	prop->prop_xforms = xform;
42045ae9d61Sreyk 	xform = prop->prop_xforms + prop->prop_nxforms++;
42145ae9d61Sreyk 	bzero(xform, sizeof(*xform));
42245ae9d61Sreyk 
42345ae9d61Sreyk 	xform->xform_type = type;
42445ae9d61Sreyk 	xform->xform_id = id;
42545ae9d61Sreyk 	xform->xform_length = length;
42645ae9d61Sreyk 	xform->xform_keylength = keylength;
42745ae9d61Sreyk 	xform->xform_score = score;
42845ae9d61Sreyk 	xform->xform_map = map;
42945ae9d61Sreyk 
430822b336dStobhe 	return (0);
43145ae9d61Sreyk }
43245ae9d61Sreyk 
43345ae9d61Sreyk struct iked_transform *
434975f0a0eStobhe config_findtransform_ext(struct iked_proposals *props, uint8_t type, int id,
435d09d3a7dSreyk     unsigned int proto)
43645ae9d61Sreyk {
43745ae9d61Sreyk 	struct iked_proposal	*prop;
43845ae9d61Sreyk 	struct iked_transform	*xform;
439d09d3a7dSreyk 	unsigned int		 i;
44045ae9d61Sreyk 
44145ae9d61Sreyk 	/* Search of the first transform with the desired type */
44245ae9d61Sreyk 	TAILQ_FOREACH(prop, props, prop_entry) {
4439be30034Smarkus 		/* Find any proposal or only selected SA proto */
4449be30034Smarkus 		if (proto != 0 && prop->prop_protoid != proto)
4459be30034Smarkus 			continue;
44645ae9d61Sreyk 		for (i = 0; i < prop->prop_nxforms; i++) {
44745ae9d61Sreyk 			xform = prop->prop_xforms + i;
448975f0a0eStobhe 			/* optional lookup of specific transform */
449975f0a0eStobhe 			if (id >= 0 && xform->xform_id != id)
450975f0a0eStobhe 				continue;
45145ae9d61Sreyk 			if (xform->xform_type == type)
45245ae9d61Sreyk 				return (xform);
45345ae9d61Sreyk 		}
45445ae9d61Sreyk 	}
45545ae9d61Sreyk 
45645ae9d61Sreyk 	return (NULL);
45745ae9d61Sreyk }
45845ae9d61Sreyk 
459975f0a0eStobhe struct iked_transform *
460975f0a0eStobhe config_findtransform(struct iked_proposals *props, uint8_t type,
461975f0a0eStobhe     unsigned int proto)
462975f0a0eStobhe {
463975f0a0eStobhe 	return config_findtransform_ext(props, type, -1, proto);
464975f0a0eStobhe }
465975f0a0eStobhe 
46645ae9d61Sreyk struct iked_user *
46745ae9d61Sreyk config_new_user(struct iked *env, struct iked_user *new)
46845ae9d61Sreyk {
46945ae9d61Sreyk 	struct iked_user	*usr, *old;
47045ae9d61Sreyk 
47145ae9d61Sreyk 	if ((usr = calloc(1, sizeof(*usr))) == NULL)
47245ae9d61Sreyk 		return (NULL);
47345ae9d61Sreyk 
47445ae9d61Sreyk 	memcpy(usr, new, sizeof(*usr));
47545ae9d61Sreyk 
47645ae9d61Sreyk 	if ((old = RB_INSERT(iked_users, &env->sc_users, usr)) != NULL) {
47745ae9d61Sreyk 		/* Update the password of an existing user*/
478c2defdfcStobhe 		memcpy(old->usr_pass, new->usr_pass, IKED_PASSWORD_SIZE);
47945ae9d61Sreyk 
48045ae9d61Sreyk 		log_debug("%s: updating user %s", __func__, usr->usr_name);
4816c3f70ddSderaadt 		freezero(usr, sizeof *usr);
48245ae9d61Sreyk 
48345ae9d61Sreyk 		return (old);
48445ae9d61Sreyk 	}
48545ae9d61Sreyk 
48645ae9d61Sreyk 	log_debug("%s: inserting new user %s", __func__, usr->usr_name);
48745ae9d61Sreyk 	return (usr);
48845ae9d61Sreyk }
48945ae9d61Sreyk 
49045ae9d61Sreyk /*
49145ae9d61Sreyk  * Inter-process communication of configuration items.
49245ae9d61Sreyk  */
49345ae9d61Sreyk 
49445ae9d61Sreyk int
495d09d3a7dSreyk config_setcoupled(struct iked *env, unsigned int couple)
496fc20f985Sreyk {
497d09d3a7dSreyk 	unsigned int	 type;
498fc20f985Sreyk 
499fc20f985Sreyk 	type = couple ? IMSG_CTL_COUPLE : IMSG_CTL_DECOUPLE;
500c205e972Sreyk 	proc_compose(&env->sc_ps, PROC_IKEV2, type, NULL, 0);
501fc20f985Sreyk 
502fc20f985Sreyk 	return (0);
503fc20f985Sreyk }
504fc20f985Sreyk 
505fc20f985Sreyk int
506d09d3a7dSreyk config_getcoupled(struct iked *env, unsigned int type)
507fc20f985Sreyk {
5088f6f6c19Stobhe 	return (pfkey_couple(env, &env->sc_sas,
509fc20f985Sreyk 	    type == IMSG_CTL_COUPLE ? 1 : 0));
510fc20f985Sreyk }
511fc20f985Sreyk 
512fc20f985Sreyk int
513d09d3a7dSreyk config_setmode(struct iked *env, unsigned int passive)
514fc20f985Sreyk {
515d09d3a7dSreyk 	unsigned int	 type;
516fc20f985Sreyk 
5173fdfc9aaStobhe 	/*
5183fdfc9aaStobhe 	 * In order to control the startup of the processes,
5193fdfc9aaStobhe 	 * the messages are sent in this order:
5203fdfc9aaStobhe 	 *   PROC_PARENT -> PROC_CERT -> PROC_PARENT -> PROC_IKEV2
5213fdfc9aaStobhe 	 * so PROC_CERT is ready before PROC_IKEV2 is activated.
5223fdfc9aaStobhe 	 */
523fc20f985Sreyk 	type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE;
5243fdfc9aaStobhe 	proc_compose(&env->sc_ps, PROC_CERT, type, NULL, 0);
525fc20f985Sreyk 
526fc20f985Sreyk 	return (0);
527fc20f985Sreyk }
528fc20f985Sreyk 
529fc20f985Sreyk int
530d09d3a7dSreyk config_getmode(struct iked *env, unsigned int type)
531fc20f985Sreyk {
532d09d3a7dSreyk 	uint8_t		 old;
533d09d3a7dSreyk 	unsigned char	*mode[] = { "active", "passive" };
534fc20f985Sreyk 
535fc20f985Sreyk 	old = env->sc_passive ? 1 : 0;
536fc20f985Sreyk 	env->sc_passive = type == IMSG_CTL_PASSIVE ? 1 : 0;
537fc20f985Sreyk 
538fc20f985Sreyk 	if (old == env->sc_passive)
539fc20f985Sreyk 		return (0);
540fc20f985Sreyk 
541fc20f985Sreyk 	log_debug("%s: mode %s -> %s", __func__,
542fc20f985Sreyk 	    mode[old], mode[env->sc_passive]);
543fc20f985Sreyk 
544fc20f985Sreyk 	return (0);
545fc20f985Sreyk }
546fc20f985Sreyk 
547fc20f985Sreyk int
548d09d3a7dSreyk config_setreset(struct iked *env, unsigned int mode, enum privsep_procid id)
54945ae9d61Sreyk {
550c205e972Sreyk 	proc_compose(&env->sc_ps, id, IMSG_CTL_RESET, &mode, sizeof(mode));
55145ae9d61Sreyk 	return (0);
55245ae9d61Sreyk }
55345ae9d61Sreyk 
55445ae9d61Sreyk int
55545ae9d61Sreyk config_getreset(struct iked *env, struct imsg *imsg)
55645ae9d61Sreyk {
557d09d3a7dSreyk 	unsigned int		 mode;
55845ae9d61Sreyk 
55945ae9d61Sreyk 	IMSG_SIZE_CHECK(imsg, &mode);
56045ae9d61Sreyk 	memcpy(&mode, imsg->data, sizeof(mode));
56145ae9d61Sreyk 
56291e971e4Stobhe 	return (config_doreset(env, mode));
56391e971e4Stobhe }
56491e971e4Stobhe 
56591e971e4Stobhe int
56691e971e4Stobhe config_doreset(struct iked *env, unsigned int mode)
56791e971e4Stobhe {
56891e971e4Stobhe 	struct iked_policy	*pol, *poltmp;
56991e971e4Stobhe 	struct iked_sa		*sa;
57091e971e4Stobhe 	struct iked_user	*usr;
57191e971e4Stobhe 
57291e971e4Stobhe 	if (mode == RESET_ALL || mode == RESET_POLICY) {
57345ae9d61Sreyk 		log_debug("%s: flushing policies", __func__);
5748177f5d5Stobhe 		TAILQ_FOREACH_SAFE(pol, &env->sc_policies, pol_entry, poltmp) {
57545ae9d61Sreyk 			config_free_policy(env, pol);
57645ae9d61Sreyk 		}
57745ae9d61Sreyk 	}
57845ae9d61Sreyk 
57991e971e4Stobhe 	if (mode == RESET_ALL || mode == RESET_SA) {
58045ae9d61Sreyk 		log_debug("%s: flushing SAs", __func__);
5819c3d68f7Stobhe 		while ((sa = RB_MIN(iked_sas, &env->sc_sas))) {
582ea5b9487Stobhe 			/* for RESET_SA we try send a DELETE */
583ea5b9487Stobhe 			if (mode == RESET_ALL ||
584ea5b9487Stobhe 			    ikev2_ike_sa_delete(env, sa) != 0) {
5854697d2e3Smarkus 				RB_REMOVE(iked_sas, &env->sc_sas, sa);
586ea67155dStobhe 				if (sa->sa_dstid_entry_valid)
587ea67155dStobhe 					sa_dstid_remove(env, sa);
58845ae9d61Sreyk 				config_free_sa(env, sa);
58945ae9d61Sreyk 			}
59045ae9d61Sreyk 		}
591ea5b9487Stobhe 	}
59245ae9d61Sreyk 
59391e971e4Stobhe 	if (mode == RESET_ALL || mode == RESET_USER) {
59445ae9d61Sreyk 		log_debug("%s: flushing users", __func__);
5959c3d68f7Stobhe 		while ((usr = RB_MIN(iked_users, &env->sc_users))) {
59645ae9d61Sreyk 			RB_REMOVE(iked_users, &env->sc_users, usr);
59745ae9d61Sreyk 			free(usr);
59845ae9d61Sreyk 		}
59945ae9d61Sreyk 	}
60045ae9d61Sreyk 
601f36db9c4Syasuoka 	if (mode == RESET_ALL || mode == RESET_RADIUS) {
602f36db9c4Syasuoka 		struct iked_radserver_req	*req;
603f36db9c4Syasuoka 		struct iked_radserver		*rad, *radt;
604f36db9c4Syasuoka 		struct iked_radcfgmap		*cfg, *cfgt;
605f36db9c4Syasuoka 		struct iked_raddae		*dae, *daet;
606f36db9c4Syasuoka 		struct iked_radclient		*client, *clientt;
607f36db9c4Syasuoka 
608f36db9c4Syasuoka 		TAILQ_FOREACH_SAFE(rad, &env->sc_radauthservers, rs_entry,
609f36db9c4Syasuoka 		    radt) {
610f36db9c4Syasuoka 			close(rad->rs_sock);
611f36db9c4Syasuoka 			event_del(&rad->rs_ev);
612f36db9c4Syasuoka 			TAILQ_REMOVE(&env->sc_radauthservers, rad, rs_entry);
613f36db9c4Syasuoka 			while ((req = TAILQ_FIRST(&rad->rs_reqs)) != NULL)
614f36db9c4Syasuoka 				iked_radius_request_free(env, req);
615f36db9c4Syasuoka 			freezero(rad, sizeof(*rad));
616f36db9c4Syasuoka 		}
617f36db9c4Syasuoka 		TAILQ_FOREACH_SAFE(rad, &env->sc_radacctservers, rs_entry,
618f36db9c4Syasuoka 		    radt) {
619f36db9c4Syasuoka 			close(rad->rs_sock);
620f36db9c4Syasuoka 			event_del(&rad->rs_ev);
621f36db9c4Syasuoka 			TAILQ_REMOVE(&env->sc_radacctservers, rad, rs_entry);
622f36db9c4Syasuoka 			while ((req = TAILQ_FIRST(&rad->rs_reqs)) != NULL)
623f36db9c4Syasuoka 				iked_radius_request_free(env, req);
624f36db9c4Syasuoka 			freezero(rad, sizeof(*rad));
625f36db9c4Syasuoka 		}
626f36db9c4Syasuoka 		TAILQ_FOREACH_SAFE(cfg, &env->sc_radcfgmaps, entry, cfgt) {
627f36db9c4Syasuoka 			TAILQ_REMOVE(&env->sc_radcfgmaps, cfg, entry);
628f36db9c4Syasuoka 			free(cfg);
629f36db9c4Syasuoka 		}
630f36db9c4Syasuoka 		TAILQ_FOREACH_SAFE(dae, &env->sc_raddaes, rd_entry, daet) {
631f36db9c4Syasuoka 			close(dae->rd_sock);
632f36db9c4Syasuoka 			event_del(&dae->rd_ev);
633f36db9c4Syasuoka 			TAILQ_REMOVE(&env->sc_raddaes, dae, rd_entry);
634f36db9c4Syasuoka 			free(dae);
635f36db9c4Syasuoka 		}
636f36db9c4Syasuoka 		TAILQ_FOREACH_SAFE(client, &env->sc_raddaeclients, rc_entry,
637f36db9c4Syasuoka 		    clientt) {
638f36db9c4Syasuoka 			TAILQ_REMOVE(&env->sc_raddaeclients, client, rc_entry);
639f36db9c4Syasuoka 			free(client);
640f36db9c4Syasuoka 		}
641f36db9c4Syasuoka 	}
642f36db9c4Syasuoka 
64345ae9d61Sreyk 	return (0);
64445ae9d61Sreyk }
64545ae9d61Sreyk 
6461ae9ce49Stobhe /*
6471ae9ce49Stobhe  * The first call of this function sets the UDP socket for IKEv2.
6481ae9ce49Stobhe  * The second call is optional, setting the UDP socket used for NAT-T.
6491ae9ce49Stobhe  */
65045ae9d61Sreyk int
65145ae9d61Sreyk config_setsocket(struct iked *env, struct sockaddr_storage *ss,
652f2f2a684Sreyk     in_port_t port, enum privsep_procid id)
65345ae9d61Sreyk {
65445ae9d61Sreyk 	int	 s;
65545ae9d61Sreyk 
65645ae9d61Sreyk 	if ((s = udp_bind((struct sockaddr *)ss, port)) == -1)
65745ae9d61Sreyk 		return (-1);
658bf556abcSreyk 	proc_compose_imsg(&env->sc_ps, id, -1,
659c205e972Sreyk 	    IMSG_UDP_SOCKET, -1, s, ss, sizeof(*ss));
66045ae9d61Sreyk 	return (0);
66145ae9d61Sreyk }
66245ae9d61Sreyk 
66345ae9d61Sreyk int
66445ae9d61Sreyk config_getsocket(struct iked *env, struct imsg *imsg,
66545ae9d61Sreyk     void (*cb)(int, short, void *))
66645ae9d61Sreyk {
6676acea849Stobhe 	struct iked_socket	*sock, **sock0 = NULL, **sock1 = NULL;
66845ae9d61Sreyk 
66945ae9d61Sreyk 	if ((sock = calloc(1, sizeof(*sock))) == NULL)
67045ae9d61Sreyk 		fatal("config_getsocket: calloc");
67145ae9d61Sreyk 
67245ae9d61Sreyk 	IMSG_SIZE_CHECK(imsg, &sock->sock_addr);
67345ae9d61Sreyk 
67445ae9d61Sreyk 	memcpy(&sock->sock_addr, imsg->data, sizeof(sock->sock_addr));
675fecd42b7Sclaudio 	sock->sock_fd = imsg_get_fd(imsg);
67645ae9d61Sreyk 	sock->sock_env = env;
67745ae9d61Sreyk 
678fecd42b7Sclaudio 	log_debug("%s: received socket fd %d", __func__, sock->sock_fd);
679fecd42b7Sclaudio 
680ae494144Sreyk 	switch (sock->sock_addr.ss_family) {
681ae494144Sreyk 	case AF_INET:
6821ae9ce49Stobhe 		sock0 = &env->sc_sock4[0];
6831ae9ce49Stobhe 		sock1 = &env->sc_sock4[1];
684ae494144Sreyk 		break;
685ae494144Sreyk 	case AF_INET6:
6861ae9ce49Stobhe 		sock0 = &env->sc_sock6[0];
6871ae9ce49Stobhe 		sock1 = &env->sc_sock6[1];
688ae494144Sreyk 		break;
689ae494144Sreyk 	default:
6901ae9ce49Stobhe 		fatal("config_getsocket: socket af: %u",
6911ae9ce49Stobhe 		    sock->sock_addr.ss_family);
692ae494144Sreyk 		/* NOTREACHED */
693ae494144Sreyk 	}
6941ae9ce49Stobhe 	if (*sock0 == NULL)
6951ae9ce49Stobhe 		*sock0 = sock;
6961ae9ce49Stobhe 	else if (*sock1 == NULL)
6971ae9ce49Stobhe 		*sock1 = sock;
6981ae9ce49Stobhe 	else
6991ae9ce49Stobhe 		fatalx("%s: too many call", __func__);
700ae494144Sreyk 
70145ae9d61Sreyk 	event_set(&sock->sock_ev, sock->sock_fd,
70245ae9d61Sreyk 	    EV_READ|EV_PERSIST, cb, sock);
70345ae9d61Sreyk 
70445ae9d61Sreyk 	return (0);
70545ae9d61Sreyk }
70645ae9d61Sreyk 
707ac16f2e6Stobhe void
708ac16f2e6Stobhe config_enablesocket(struct iked *env)
709ac16f2e6Stobhe {
710ac16f2e6Stobhe 	struct iked_socket	*sock;
711ac16f2e6Stobhe 	size_t			 i;
712ac16f2e6Stobhe 
713ac16f2e6Stobhe 	for (i = 0; i < nitems(env->sc_sock4); i++)
714ac16f2e6Stobhe 		if ((sock = env->sc_sock4[i]) != NULL)
715ac16f2e6Stobhe 			event_add(&sock->sock_ev, NULL);
716ac16f2e6Stobhe 	for (i = 0; i < nitems(env->sc_sock6); i++)
717ac16f2e6Stobhe 		if ((sock = env->sc_sock6[i]) != NULL)
718ac16f2e6Stobhe 			event_add(&sock->sock_ev, NULL);
719ac16f2e6Stobhe }
720ac16f2e6Stobhe 
72145ae9d61Sreyk int
722ba38eea7Stobhe config_setpfkey(struct iked *env)
72345ae9d61Sreyk {
72445ae9d61Sreyk 	int	 s;
72545ae9d61Sreyk 
7268f6f6c19Stobhe 	if ((s = pfkey_socket(env)) == -1)
72745ae9d61Sreyk 		return (-1);
728ba38eea7Stobhe 	proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1,
729c205e972Sreyk 	    IMSG_PFKEY_SOCKET, -1, s, NULL, 0);
73045ae9d61Sreyk 	return (0);
73145ae9d61Sreyk }
73245ae9d61Sreyk 
73345ae9d61Sreyk int
7346417b90fSreyk config_getpfkey(struct iked *env, struct imsg *imsg)
73545ae9d61Sreyk {
736fecd42b7Sclaudio 	int fd = imsg_get_fd(imsg);
737fecd42b7Sclaudio 
738fecd42b7Sclaudio 	log_debug("%s: received pfkey fd %d", __func__, fd);
739fecd42b7Sclaudio 	pfkey_init(env, fd);
74045ae9d61Sreyk 	return (0);
74145ae9d61Sreyk }
74245ae9d61Sreyk 
74345ae9d61Sreyk int
744f2f2a684Sreyk config_setuser(struct iked *env, struct iked_user *usr, enum privsep_procid id)
74545ae9d61Sreyk {
74645ae9d61Sreyk 	if (env->sc_opts & IKED_OPT_NOACTION) {
74745ae9d61Sreyk 		print_user(usr);
74845ae9d61Sreyk 		return (0);
74945ae9d61Sreyk 	}
75045ae9d61Sreyk 
751c205e972Sreyk 	proc_compose(&env->sc_ps, id, IMSG_CFG_USER, usr, sizeof(*usr));
75245ae9d61Sreyk 	return (0);
75345ae9d61Sreyk }
75445ae9d61Sreyk 
75545ae9d61Sreyk int
75645ae9d61Sreyk config_getuser(struct iked *env, struct imsg *imsg)
75745ae9d61Sreyk {
75845ae9d61Sreyk 	struct iked_user	 usr;
7599b3346f9Stobhe 	int			 ret = -1;
76045ae9d61Sreyk 
76145ae9d61Sreyk 	IMSG_SIZE_CHECK(imsg, &usr);
76245ae9d61Sreyk 	memcpy(&usr, imsg->data, sizeof(usr));
76345ae9d61Sreyk 
7649b3346f9Stobhe 	if (config_new_user(env, &usr) != NULL) {
76545ae9d61Sreyk 		print_user(&usr);
7669b3346f9Stobhe 		ret = 0;
7679b3346f9Stobhe 	}
76845ae9d61Sreyk 
7699b3346f9Stobhe 	explicit_bzero(&usr, sizeof(usr));
7709b3346f9Stobhe 	return (ret);
77145ae9d61Sreyk }
77245ae9d61Sreyk 
77345ae9d61Sreyk int
77445ae9d61Sreyk config_setpolicy(struct iked *env, struct iked_policy *pol,
775f2f2a684Sreyk     enum privsep_procid id)
77645ae9d61Sreyk {
77745ae9d61Sreyk 	struct iked_proposal	*prop;
77845ae9d61Sreyk 	struct iked_transform	*xform;
779fb5e93d4Smikeb 	size_t			 iovcnt, j, c = 0;
78045ae9d61Sreyk 	struct iovec		 iov[IOV_MAX];
78145ae9d61Sreyk 
78245ae9d61Sreyk 	iovcnt = 1;
78345ae9d61Sreyk 	TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) {
78445ae9d61Sreyk 		iovcnt += prop->prop_nxforms + 1;
78545ae9d61Sreyk 	}
78645ae9d61Sreyk 
78745ae9d61Sreyk 	if (iovcnt > IOV_MAX) {
788fb5e93d4Smikeb 		log_warn("%s: too many proposals", __func__);
78945ae9d61Sreyk 		return (-1);
79045ae9d61Sreyk 	}
79145ae9d61Sreyk 
79245ae9d61Sreyk 	iov[c].iov_base = pol;
79345ae9d61Sreyk 	iov[c++].iov_len = sizeof(*pol);
79445ae9d61Sreyk 
79545ae9d61Sreyk 	TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) {
79645ae9d61Sreyk 		iov[c].iov_base = prop;
79745ae9d61Sreyk 		iov[c++].iov_len = sizeof(*prop);
79845ae9d61Sreyk 
79945ae9d61Sreyk 		for (j = 0; j < prop->prop_nxforms; j++) {
80045ae9d61Sreyk 			xform = prop->prop_xforms + j;
80145ae9d61Sreyk 
80245ae9d61Sreyk 			iov[c].iov_base = xform;
80345ae9d61Sreyk 			iov[c++].iov_len = sizeof(*xform);
80445ae9d61Sreyk 		}
80545ae9d61Sreyk 	}
80645ae9d61Sreyk 
80745ae9d61Sreyk 	print_policy(pol);
808e54c4fa7Sreyk 
809e54c4fa7Sreyk 	if (env->sc_opts & IKED_OPT_NOACTION)
81045ae9d61Sreyk 		return (0);
81145ae9d61Sreyk 
812fb5e93d4Smikeb 	if (proc_composev(&env->sc_ps, id, IMSG_CFG_POLICY, iov,
813fb5e93d4Smikeb 	    iovcnt) == -1) {
814fb5e93d4Smikeb 		log_debug("%s: proc_composev failed", __func__);
81545ae9d61Sreyk 		return (-1);
816fb5e93d4Smikeb 	}
817fb5e93d4Smikeb 
818fb5e93d4Smikeb 	return (0);
819fb5e93d4Smikeb }
820fb5e93d4Smikeb 
821fb5e93d4Smikeb int
822fb5e93d4Smikeb config_setflow(struct iked *env, struct iked_policy *pol,
823fb5e93d4Smikeb     enum privsep_procid id)
824fb5e93d4Smikeb {
825fb5e93d4Smikeb 	struct iked_flow	*flow;
826fb5e93d4Smikeb 	struct iovec		 iov[2];
827fb5e93d4Smikeb 
828fb5e93d4Smikeb 	if (env->sc_opts & IKED_OPT_NOACTION)
829fb5e93d4Smikeb 		return (0);
830fb5e93d4Smikeb 
831fb5e93d4Smikeb 	RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
832fb5e93d4Smikeb 		iov[0].iov_base = &pol->pol_id;
833fb5e93d4Smikeb 		iov[0].iov_len = sizeof(pol->pol_id);
834fb5e93d4Smikeb 		iov[1].iov_base = flow;
835fb5e93d4Smikeb 		iov[1].iov_len = sizeof(*flow);
836fb5e93d4Smikeb 
837fb5e93d4Smikeb 		if (proc_composev(&env->sc_ps, id, IMSG_CFG_FLOW,
838fb5e93d4Smikeb 		    iov, 2) == -1) {
839fb5e93d4Smikeb 			log_debug("%s: proc_composev failed", __func__);
840fb5e93d4Smikeb 			return (-1);
841fb5e93d4Smikeb 		}
842fb5e93d4Smikeb 	}
84345ae9d61Sreyk 
84445ae9d61Sreyk 	return (0);
84545ae9d61Sreyk }
84645ae9d61Sreyk 
84745ae9d61Sreyk int
84845ae9d61Sreyk config_getpolicy(struct iked *env, struct imsg *imsg)
84945ae9d61Sreyk {
850e2015428Sreyk 	struct iked_policy	*pol;
85145ae9d61Sreyk 	struct iked_proposal	 pp, *prop;
85253d22e8fStobhe 	struct iked_transform	 xf;
85345ae9d61Sreyk 	off_t			 offset = 0;
854d09d3a7dSreyk 	unsigned int		 i, j;
855d09d3a7dSreyk 	uint8_t			*buf = (uint8_t *)imsg->data;
85645ae9d61Sreyk 
85745ae9d61Sreyk 	IMSG_SIZE_CHECK(imsg, pol);
85845ae9d61Sreyk 	log_debug("%s: received policy", __func__);
85945ae9d61Sreyk 
86045ae9d61Sreyk 	if ((pol = config_new_policy(NULL)) == NULL)
86145ae9d61Sreyk 		fatal("config_getpolicy: new policy");
86245ae9d61Sreyk 
86345ae9d61Sreyk 	memcpy(pol, buf, sizeof(*pol));
86445ae9d61Sreyk 	offset += sizeof(*pol);
86545ae9d61Sreyk 
8661f864a9aStobhe 	TAILQ_INIT(&pol->pol_tssrc);
8671f864a9aStobhe 	TAILQ_INIT(&pol->pol_tsdst);
86845ae9d61Sreyk 	TAILQ_INIT(&pol->pol_proposals);
86932b6fc39Smarkus 	TAILQ_INIT(&pol->pol_sapeers);
8709dbd37b8Sreyk 	RB_INIT(&pol->pol_flows);
87145ae9d61Sreyk 
87245ae9d61Sreyk 	for (i = 0; i < pol->pol_nproposals; i++) {
87345ae9d61Sreyk 		memcpy(&pp, buf + offset, sizeof(pp));
87445ae9d61Sreyk 		offset += sizeof(pp);
87545ae9d61Sreyk 
87645ae9d61Sreyk 		if ((prop = config_add_proposal(&pol->pol_proposals,
87745ae9d61Sreyk 		    pp.prop_id, pp.prop_protoid)) == NULL)
87845ae9d61Sreyk 			fatal("config_getpolicy: add proposal");
87945ae9d61Sreyk 
88045ae9d61Sreyk 		for (j = 0; j < pp.prop_nxforms; j++) {
88145ae9d61Sreyk 			memcpy(&xf, buf + offset, sizeof(xf));
88245ae9d61Sreyk 			offset += sizeof(xf);
88345ae9d61Sreyk 
88453d22e8fStobhe 			if (config_add_transform(prop, xf.xform_type,
88545ae9d61Sreyk 			    xf.xform_id, xf.xform_length,
886822b336dStobhe 			    xf.xform_keylength) != 0)
88745ae9d61Sreyk 				fatal("config_getpolicy: add transform");
88845ae9d61Sreyk 		}
88945ae9d61Sreyk 	}
89045ae9d61Sreyk 
891fb5e93d4Smikeb 	/* Flows are sent separately */
892fb5e93d4Smikeb 	pol->pol_nflows = 0;
89345ae9d61Sreyk 
894e2015428Sreyk 	TAILQ_INSERT_TAIL(&env->sc_policies, pol, pol_entry);
89545ae9d61Sreyk 
896e2015428Sreyk 	if (pol->pol_flags & IKED_POLICY_DEFAULT) {
897e2015428Sreyk 		/* Only one default policy, just free/unref the old one */
898e2015428Sreyk 		if (env->sc_defaultcon != NULL)
899e2015428Sreyk 			config_free_policy(env, env->sc_defaultcon);
90045ae9d61Sreyk 		env->sc_defaultcon = pol;
901e2015428Sreyk 	}
90245ae9d61Sreyk 
90345ae9d61Sreyk 	return (0);
90445ae9d61Sreyk }
905e2015428Sreyk 
906e2015428Sreyk int
907fb5e93d4Smikeb config_getflow(struct iked *env, struct imsg *imsg)
908fb5e93d4Smikeb {
909fb5e93d4Smikeb 	struct iked_policy	*pol;
910fb5e93d4Smikeb 	struct iked_flow	*flow;
911fb5e93d4Smikeb 	off_t			 offset = 0;
912fb5e93d4Smikeb 	unsigned int		 id;
913fb5e93d4Smikeb 	uint8_t			*buf = (uint8_t *)imsg->data;
914fb5e93d4Smikeb 
915fb5e93d4Smikeb 	if (IMSG_DATA_SIZE(imsg) < sizeof(id))
916fb5e93d4Smikeb 		fatalx("bad length imsg received");
917fb5e93d4Smikeb 
918fb5e93d4Smikeb 	memcpy(&id, buf, sizeof(id));
919fb5e93d4Smikeb 	offset += sizeof(id);
920fb5e93d4Smikeb 
921fb5e93d4Smikeb 	TAILQ_FOREACH(pol, &env->sc_policies, pol_entry) {
922fb5e93d4Smikeb 		if (pol->pol_id == id)
923fb5e93d4Smikeb 			break;
924fb5e93d4Smikeb 	}
925fb5e93d4Smikeb 	if (pol == NULL) {
926fb5e93d4Smikeb 		log_warnx("%s: unknown policy %u", __func__, id);
927fb5e93d4Smikeb 		return (-1);
928fb5e93d4Smikeb 	}
929fb5e93d4Smikeb 
930fb5e93d4Smikeb 	if ((flow = calloc(1, sizeof(*flow))) == NULL)
931fb5e93d4Smikeb 		fatal("config_getpolicy: new flow");
932fb5e93d4Smikeb 
933fb5e93d4Smikeb 	memcpy(flow, buf + offset, sizeof(*flow));
934fb5e93d4Smikeb 
935fb5e93d4Smikeb 	if (RB_INSERT(iked_flows, &pol->pol_flows, flow)) {
936fb5e93d4Smikeb 		log_warnx("%s: received duplicate flow", __func__);
937fb5e93d4Smikeb 		free(flow);
938fb5e93d4Smikeb 		return (-1);
939fb5e93d4Smikeb 	}
940fb5e93d4Smikeb 	pol->pol_nflows++;
941fb5e93d4Smikeb 
942fb5e93d4Smikeb 	return (0);
943fb5e93d4Smikeb }
944fb5e93d4Smikeb 
945fb5e93d4Smikeb int
946f2f2a684Sreyk config_setcompile(struct iked *env, enum privsep_procid id)
947e2015428Sreyk {
948e2015428Sreyk 	if (env->sc_opts & IKED_OPT_NOACTION)
949e2015428Sreyk 		return (0);
950e2015428Sreyk 
951c205e972Sreyk 	proc_compose(&env->sc_ps, id, IMSG_COMPILE, NULL, 0);
952e2015428Sreyk 	return (0);
953e2015428Sreyk }
954e2015428Sreyk 
955e2015428Sreyk int
95658afaaa2Stobhe config_getcompile(struct iked *env)
957e2015428Sreyk {
958e2015428Sreyk 	/*
959e2015428Sreyk 	 * Do any necessary steps after configuration, for now we
960e2015428Sreyk 	 * only need to compile the skip steps.
961e2015428Sreyk 	 */
962e2015428Sreyk 	policy_calc_skip_steps(&env->sc_policies);
963e2015428Sreyk 
964e2015428Sreyk 	log_debug("%s: compilation done", __func__);
965e2015428Sreyk 	return (0);
966e2015428Sreyk }
9676d3b905bSmarkus 
9686d3b905bSmarkus int
969421819b6Stobhe config_setstatic(struct iked *env)
970c0b327e6Spatrick {
971421819b6Stobhe 	proc_compose(&env->sc_ps, PROC_IKEV2, IMSG_CTL_STATIC,
972421819b6Stobhe 	    &env->sc_static, sizeof(env->sc_static));
97373cd769dStobhe 	proc_compose(&env->sc_ps, PROC_CERT, IMSG_CTL_STATIC,
97473cd769dStobhe 	    &env->sc_static, sizeof(env->sc_static));
975c0b327e6Spatrick 	return (0);
976c0b327e6Spatrick }
977c0b327e6Spatrick 
978c0b327e6Spatrick int
979421819b6Stobhe config_getstatic(struct iked *env, struct imsg *imsg)
980c0b327e6Spatrick {
981421819b6Stobhe 	IMSG_SIZE_CHECK(imsg, &env->sc_static);
982421819b6Stobhe 	memcpy(&env->sc_static, imsg->data, sizeof(env->sc_static));
983c0b327e6Spatrick 
98443d162a4Stobhe 	log_debug("%s: dpd_check_interval %llu", __func__, env->sc_alive_timeout);
985729f601bStobhe 	log_debug("%s: %senforcesingleikesa", __func__,
986729f601bStobhe 	    env->sc_enforcesingleikesa ? "" : "no ");
987421819b6Stobhe 	log_debug("%s: %sfragmentation", __func__, env->sc_frag ? "" : "no ");
988421819b6Stobhe 	log_debug("%s: %smobike", __func__, env->sc_mobike ? "" : "no ");
989421819b6Stobhe 	log_debug("%s: nattport %u", __func__, env->sc_nattport);
990e3244f00Stobhe 	log_debug("%s: %sstickyaddress", __func__,
991e3244f00Stobhe 	    env->sc_stickyaddress ? "" : "no ");
992421819b6Stobhe 
9938ad617ceStobhe 	ikev2_reset_alive_timer(env);
9948ad617ceStobhe 
995729f601bStobhe 	return (0);
996729f601bStobhe }
997729f601bStobhe 
998729f601bStobhe int
9996d3b905bSmarkus config_setocsp(struct iked *env)
10006d3b905bSmarkus {
1001c973c574Stobhe 	struct iovec		 iov[3];
1002c973c574Stobhe 	int			 iovcnt = 0;
1003c973c574Stobhe 
10046d3b905bSmarkus 	if (env->sc_opts & IKED_OPT_NOACTION)
10056d3b905bSmarkus 		return (0);
10066d3b905bSmarkus 
1007c973c574Stobhe 	iov[0].iov_base = &env->sc_ocsp_tolerate;
1008c973c574Stobhe 	iov[0].iov_len = sizeof(env->sc_ocsp_tolerate);
1009c973c574Stobhe 	iovcnt++;
1010c973c574Stobhe 	iov[1].iov_base = &env->sc_ocsp_maxage;
1011c973c574Stobhe 	iov[1].iov_len = sizeof(env->sc_ocsp_maxage);
1012c973c574Stobhe 	iovcnt++;
1013c973c574Stobhe 	if (env->sc_ocsp_url) {
1014c973c574Stobhe 		iov[2].iov_base = env->sc_ocsp_url;
1015c973c574Stobhe 		iov[2].iov_len = strlen(env->sc_ocsp_url);
1016c973c574Stobhe 		iovcnt++;
1017c973c574Stobhe 	}
1018c973c574Stobhe 	return (proc_composev(&env->sc_ps, PROC_CERT, IMSG_OCSP_CFG,
1019c973c574Stobhe 	    iov, iovcnt));
10206d3b905bSmarkus }
10216d3b905bSmarkus 
10226d3b905bSmarkus int
10236d3b905bSmarkus config_getocsp(struct iked *env, struct imsg *imsg)
10246d3b905bSmarkus {
1025c973c574Stobhe 	size_t		 have, need;
1026229c27f0Stobhe 	uint8_t		*ptr;
1027c973c574Stobhe 
10286d3b905bSmarkus 	free(env->sc_ocsp_url);
1029229c27f0Stobhe 	ptr = (uint8_t *)imsg->data;
1030c973c574Stobhe 	have = IMSG_DATA_SIZE(imsg);
1031c973c574Stobhe 
1032c973c574Stobhe 	/* get tolerate */
1033c973c574Stobhe 	need = sizeof(env->sc_ocsp_tolerate);
1034c973c574Stobhe 	if (have < need)
1035c973c574Stobhe 		fatalx("bad 'tolerate' length imsg received");
1036c973c574Stobhe 	memcpy(&env->sc_ocsp_tolerate, ptr, need);
1037c973c574Stobhe 	ptr += need;
1038c973c574Stobhe 	have -= need;
1039c973c574Stobhe 
1040c973c574Stobhe 	/* get maxage */
1041c973c574Stobhe 	need = sizeof(env->sc_ocsp_maxage);
1042c973c574Stobhe 	if (have < need)
1043c973c574Stobhe 		fatalx("bad 'maxage' length imsg received");
1044c973c574Stobhe 	memcpy(&env->sc_ocsp_maxage, ptr, need);
1045c973c574Stobhe 	ptr += need;
1046c973c574Stobhe 	have -= need;
1047c973c574Stobhe 
1048c973c574Stobhe 	/* get url */
1049c973c574Stobhe 	if (have > 0)
1050c973c574Stobhe 		env->sc_ocsp_url = get_string(ptr, have);
10516d3b905bSmarkus 	else
10526d3b905bSmarkus 		env->sc_ocsp_url = NULL;
1053c973c574Stobhe 	log_debug("%s: ocsp_url %s tolerate %ld maxage %ld", __func__,
1054c973c574Stobhe 	    env->sc_ocsp_url ? env->sc_ocsp_url : "none",
1055c973c574Stobhe 	    env->sc_ocsp_tolerate, env->sc_ocsp_maxage);
10566d3b905bSmarkus 	return (0);
10576d3b905bSmarkus }
1058e8b444cdSreyk 
1059e8b444cdSreyk int
1060e8b444cdSreyk config_setkeys(struct iked *env)
1061e8b444cdSreyk {
1062e8b444cdSreyk 	FILE			*fp = NULL;
1063e8b444cdSreyk 	EVP_PKEY		*key = NULL;
1064e8b444cdSreyk 	struct iked_id		 privkey;
1065e8b444cdSreyk 	struct iked_id		 pubkey;
1066e8b444cdSreyk 	struct iovec		 iov[2];
1067e8b444cdSreyk 	int			 ret = -1;
1068e8b444cdSreyk 
1069e8b444cdSreyk 	memset(&privkey, 0, sizeof(privkey));
1070e8b444cdSreyk 	memset(&pubkey, 0, sizeof(pubkey));
1071e8b444cdSreyk 
1072e8b444cdSreyk 	/* Read private key */
1073e8b444cdSreyk 	if ((fp = fopen(IKED_PRIVKEY, "r")) == NULL) {
1074e8b444cdSreyk 		log_warn("%s: failed to open private key", __func__);
1075e8b444cdSreyk 		goto done;
1076e8b444cdSreyk 	}
1077e8b444cdSreyk 
1078e8b444cdSreyk 	if ((key = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL) {
1079e8b444cdSreyk 		log_warnx("%s: failed to read private key", __func__);
1080e8b444cdSreyk 		goto done;
1081e8b444cdSreyk 	}
1082e8b444cdSreyk 
1083e8b444cdSreyk 	if (ca_privkey_serialize(key, &privkey) != 0) {
1084e8b444cdSreyk 		log_warnx("%s: failed to serialize private key", __func__);
1085e8b444cdSreyk 		goto done;
1086e8b444cdSreyk 	}
1087e8b444cdSreyk 	if (ca_pubkey_serialize(key, &pubkey) != 0) {
1088e8b444cdSreyk 		log_warnx("%s: failed to serialize public key", __func__);
1089e8b444cdSreyk 		goto done;
1090e8b444cdSreyk 	}
1091e8b444cdSreyk 
1092e8b444cdSreyk 	iov[0].iov_base = &privkey;
1093e8b444cdSreyk 	iov[0].iov_len = sizeof(privkey);
1094e8b444cdSreyk 	iov[1].iov_base = ibuf_data(privkey.id_buf);
1095eef6c82aSclaudio 	iov[1].iov_len = ibuf_size(privkey.id_buf);
1096e8b444cdSreyk 
1097e8b444cdSreyk 	if (proc_composev(&env->sc_ps, PROC_CERT, IMSG_PRIVKEY, iov, 2) == -1) {
1098e8b444cdSreyk 		log_warnx("%s: failed to send private key", __func__);
1099e8b444cdSreyk 		goto done;
1100e8b444cdSreyk 	}
1101e8b444cdSreyk 
1102e8b444cdSreyk 	iov[0].iov_base = &pubkey;
1103e8b444cdSreyk 	iov[0].iov_len = sizeof(pubkey);
1104e8b444cdSreyk 	iov[1].iov_base = ibuf_data(pubkey.id_buf);
1105eef6c82aSclaudio 	iov[1].iov_len = ibuf_size(pubkey.id_buf);
1106e8b444cdSreyk 
1107e8b444cdSreyk 	if (proc_composev(&env->sc_ps, PROC_CERT, IMSG_PUBKEY, iov, 2) == -1) {
1108e8b444cdSreyk 		log_warnx("%s: failed to send public key", __func__);
1109e8b444cdSreyk 		goto done;
1110e8b444cdSreyk 	}
1111e8b444cdSreyk 
1112e8b444cdSreyk 	ret = 0;
1113e8b444cdSreyk  done:
1114e8b444cdSreyk 	if (fp != NULL)
1115e8b444cdSreyk 		fclose(fp);
1116e8b444cdSreyk 
1117be2b38f5Sclaudio 	ibuf_free(pubkey.id_buf);
1118be2b38f5Sclaudio 	ibuf_free(privkey.id_buf);
1119e8b444cdSreyk 	EVP_PKEY_free(key);
1120e8b444cdSreyk 
1121e8b444cdSreyk 	return (ret);
1122e8b444cdSreyk }
1123e8b444cdSreyk 
1124e8b444cdSreyk int
1125e8b444cdSreyk config_getkey(struct iked *env, struct imsg *imsg)
1126e8b444cdSreyk {
1127e8b444cdSreyk 	size_t		 len;
1128e8b444cdSreyk 	struct iked_id	 id;
1129e8b444cdSreyk 
1130e8b444cdSreyk 	len = IMSG_DATA_SIZE(imsg);
1131e8b444cdSreyk 	if (len <= sizeof(id))
1132e8b444cdSreyk 		fatalx("%s: invalid key message", __func__);
1133e8b444cdSreyk 
1134e8b444cdSreyk 	memcpy(&id, imsg->data, sizeof(id));
1135e8b444cdSreyk 	if ((id.id_buf = ibuf_new((uint8_t *)imsg->data + sizeof(id),
1136e8b444cdSreyk 	    len - sizeof(id))) == NULL)
1137e8b444cdSreyk 		fatalx("%s: failed to get key", __func__);
1138e8b444cdSreyk 
1139e8b444cdSreyk 	explicit_bzero(imsg->data, len);
1140e8b444cdSreyk 	ca_getkey(&env->sc_ps, &id, imsg->hdr.type);
1141e8b444cdSreyk 
1142e8b444cdSreyk 	return (0);
1143e8b444cdSreyk }
1144f36db9c4Syasuoka 
1145f36db9c4Syasuoka int
1146f36db9c4Syasuoka config_setradauth(struct iked *env)
1147f36db9c4Syasuoka {
1148f36db9c4Syasuoka 	proc_compose(&env->sc_ps, PROC_IKEV2, IMSG_CFG_RADAUTH,
1149f36db9c4Syasuoka 	    &env->sc_radauth, sizeof(env->sc_radauth));
1150f36db9c4Syasuoka 	return (0);
1151f36db9c4Syasuoka }
1152f36db9c4Syasuoka 
1153f36db9c4Syasuoka int
1154f36db9c4Syasuoka config_getradauth(struct iked *env, struct imsg *imsg)
1155f36db9c4Syasuoka {
1156f36db9c4Syasuoka 	if (IMSG_DATA_SIZE(imsg) < sizeof(struct iked_radopts))
1157f36db9c4Syasuoka 		fatalx("%s: invalid radauth message", __func__);
1158f36db9c4Syasuoka 
1159f36db9c4Syasuoka 	memcpy(&env->sc_radauth, imsg->data, sizeof(struct iked_radopts));
1160f36db9c4Syasuoka 
1161f36db9c4Syasuoka 	return (0);
1162f36db9c4Syasuoka }
1163f36db9c4Syasuoka 
1164f36db9c4Syasuoka int
1165f36db9c4Syasuoka config_setradacct(struct iked *env)
1166f36db9c4Syasuoka {
1167f36db9c4Syasuoka 	proc_compose(&env->sc_ps, PROC_IKEV2, IMSG_CFG_RADACCT,
1168f36db9c4Syasuoka 	    &env->sc_radacct, sizeof(env->sc_radacct));
1169f36db9c4Syasuoka 	return (0);
1170f36db9c4Syasuoka }
1171f36db9c4Syasuoka 
1172f36db9c4Syasuoka int
1173f36db9c4Syasuoka config_getradacct(struct iked *env, struct imsg *imsg)
1174f36db9c4Syasuoka {
1175f36db9c4Syasuoka 	if (IMSG_DATA_SIZE(imsg) < sizeof(struct iked_radopts))
1176f36db9c4Syasuoka 		fatalx("%s: invalid radacct message", __func__);
1177f36db9c4Syasuoka 
1178f36db9c4Syasuoka 	memcpy(&env->sc_radacct, imsg->data, sizeof(struct iked_radopts));
1179f36db9c4Syasuoka 
1180f36db9c4Syasuoka 	return (0);
1181f36db9c4Syasuoka }
1182f36db9c4Syasuoka 
1183f36db9c4Syasuoka int
1184f36db9c4Syasuoka config_setradserver(struct iked *env, struct sockaddr *sa, socklen_t salen,
1185f36db9c4Syasuoka     char *secret, int isaccounting)
1186f36db9c4Syasuoka {
1187f36db9c4Syasuoka 	int			 sock = -1;
1188f36db9c4Syasuoka 	struct iovec		 iov[2];
1189f36db9c4Syasuoka 	struct iked_radserver	 server;
1190f36db9c4Syasuoka 
1191f36db9c4Syasuoka 	if (env->sc_opts & IKED_OPT_NOACTION)
1192f36db9c4Syasuoka 		return (0);
1193f36db9c4Syasuoka 	memset(&server, 0, sizeof(server));
1194f36db9c4Syasuoka 	memcpy(&server.rs_sockaddr, sa, salen);
1195f36db9c4Syasuoka 	server.rs_accounting = isaccounting;
1196f36db9c4Syasuoka 	if ((sock = socket(sa->sa_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
1197f36db9c4Syasuoka 		log_warn("%s: socket() failed", __func__);
1198f36db9c4Syasuoka 		goto error;
1199f36db9c4Syasuoka 	}
1200f36db9c4Syasuoka 	if (connect(sock, sa, salen) == -1) {
1201f36db9c4Syasuoka 		log_warn("%s: connect() failed", __func__);
1202f36db9c4Syasuoka 		goto error;
1203f36db9c4Syasuoka 	}
1204f36db9c4Syasuoka 	iov[0].iov_base = &server;
1205f36db9c4Syasuoka 	iov[0].iov_len = offsetof(struct iked_radserver, rs_secret[0]);
1206f36db9c4Syasuoka 	iov[1].iov_base = secret;
1207f36db9c4Syasuoka 	iov[1].iov_len = strlen(secret) + 1;
1208f36db9c4Syasuoka 
1209f36db9c4Syasuoka 	proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, IMSG_CFG_RADSERVER, -1,
1210f36db9c4Syasuoka 	    sock, iov, 2);
1211f36db9c4Syasuoka 
1212f36db9c4Syasuoka 	return (0);
1213f36db9c4Syasuoka  error:
1214f36db9c4Syasuoka 	if (sock >= 0)
1215f36db9c4Syasuoka 		close(sock);
1216f36db9c4Syasuoka 	return (-1);
1217f36db9c4Syasuoka }
1218f36db9c4Syasuoka 
1219f36db9c4Syasuoka int
1220f36db9c4Syasuoka config_getradserver(struct iked *env, struct imsg *imsg)
1221f36db9c4Syasuoka {
1222f36db9c4Syasuoka 	size_t			 len;
1223f36db9c4Syasuoka 	struct iked_radserver	*server;
1224f36db9c4Syasuoka 
1225f36db9c4Syasuoka 	len = IMSG_DATA_SIZE(imsg);
1226f36db9c4Syasuoka 	if (len <= sizeof(*server))
1227f36db9c4Syasuoka 		fatalx("%s: invalid IMSG_CFG_RADSERVER message", __func__);
1228f36db9c4Syasuoka 
1229f36db9c4Syasuoka 	if ((server = calloc(1, len)) == NULL) {
1230f36db9c4Syasuoka 		log_warn("%s: calloc() failed", __func__);
1231f36db9c4Syasuoka 		return (-1);
1232f36db9c4Syasuoka 	}
1233f36db9c4Syasuoka 	memcpy(server, imsg->data, len);
1234f36db9c4Syasuoka 	explicit_bzero(imsg->data, len);
1235f36db9c4Syasuoka 	TAILQ_INIT(&server->rs_reqs);
1236f36db9c4Syasuoka 	server->rs_sock = imsg_get_fd(imsg);
1237f36db9c4Syasuoka 	server->rs_env = env;
1238f36db9c4Syasuoka 
1239f36db9c4Syasuoka 	if (!server->rs_accounting)
1240f36db9c4Syasuoka 		TAILQ_INSERT_TAIL(&env->sc_radauthservers, server, rs_entry);
1241f36db9c4Syasuoka 	else
1242f36db9c4Syasuoka 		TAILQ_INSERT_TAIL(&env->sc_radacctservers, server, rs_entry);
1243f36db9c4Syasuoka 	event_set(&server->rs_ev, server->rs_sock, EV_READ | EV_PERSIST,
1244f36db9c4Syasuoka 	    iked_radius_on_event, server);
1245f36db9c4Syasuoka 	event_add(&server->rs_ev, NULL);
1246f36db9c4Syasuoka 
1247f36db9c4Syasuoka 	return (0);
1248f36db9c4Syasuoka }
1249f36db9c4Syasuoka 
1250f36db9c4Syasuoka int
1251f36db9c4Syasuoka config_setradcfgmap(struct iked *env, int cfg_type, uint32_t vendor_id,
1252f36db9c4Syasuoka     uint8_t attr_type)
1253f36db9c4Syasuoka {
1254f36db9c4Syasuoka 	struct iked_radcfgmap cfgmap;
1255f36db9c4Syasuoka 
1256f36db9c4Syasuoka 	if (env->sc_opts & IKED_OPT_NOACTION)
1257f36db9c4Syasuoka 		return (0);
1258f36db9c4Syasuoka 	memset(&cfgmap, 0, sizeof(cfgmap));
1259f36db9c4Syasuoka 	cfgmap.cfg_type = cfg_type;
1260f36db9c4Syasuoka 	cfgmap.vendor_id = vendor_id;
1261f36db9c4Syasuoka 	cfgmap.attr_type = attr_type;
1262f36db9c4Syasuoka 
1263f36db9c4Syasuoka 	proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, IMSG_CFG_RADCFGMAP, -1,
1264f36db9c4Syasuoka 	    -1, &cfgmap, sizeof(cfgmap));
1265f36db9c4Syasuoka 
1266f36db9c4Syasuoka 	return (0);
1267f36db9c4Syasuoka }
1268f36db9c4Syasuoka 
1269f36db9c4Syasuoka int
1270f36db9c4Syasuoka config_getradcfgmap(struct iked *env, struct imsg *imsg)
1271f36db9c4Syasuoka {
1272f36db9c4Syasuoka 	int			 i;
1273f36db9c4Syasuoka 	size_t			 len;
1274f36db9c4Syasuoka 	struct iked_radcfgmap	*cfgmap, *cfgmap0;
1275f36db9c4Syasuoka 	struct iked_radcfgmaps	 cfgmaps = TAILQ_HEAD_INITIALIZER(cfgmaps);
1276f36db9c4Syasuoka 
1277f36db9c4Syasuoka 	len = IMSG_DATA_SIZE(imsg);
1278f36db9c4Syasuoka 	if (len < sizeof(*cfgmap))
1279f36db9c4Syasuoka 		fatalx("%s: invalid IMSG_CFG_RADCFGMAP message", __func__);
1280f36db9c4Syasuoka 
1281f36db9c4Syasuoka 	if (TAILQ_EMPTY(&env->sc_radcfgmaps)) {
1282f36db9c4Syasuoka 		/* no customized config map yet */
1283f36db9c4Syasuoka 		for (i = 0; radius_cfgmaps[i].cfg_type != 0; i++) {
1284f36db9c4Syasuoka 			if ((cfgmap = calloc(1, len)) == NULL) {
1285f36db9c4Syasuoka 				while ((cfgmap = TAILQ_FIRST(&cfgmaps))
1286f36db9c4Syasuoka 				    != NULL) {
1287f36db9c4Syasuoka 					TAILQ_REMOVE(&cfgmaps, cfgmap, entry);
1288f36db9c4Syasuoka 					free(cfgmap);
1289f36db9c4Syasuoka 				}
1290f36db9c4Syasuoka 				return (-1);
1291f36db9c4Syasuoka 			}
1292f36db9c4Syasuoka 			*cfgmap = radius_cfgmaps[i];
1293f36db9c4Syasuoka 			TAILQ_INSERT_TAIL(&cfgmaps, cfgmap, entry);
1294f36db9c4Syasuoka 		}
1295f36db9c4Syasuoka 		TAILQ_CONCAT(&env->sc_radcfgmaps, &cfgmaps, entry);
1296f36db9c4Syasuoka 	}
1297f36db9c4Syasuoka 
1298f36db9c4Syasuoka 	cfgmap0 = (struct iked_radcfgmap *)imsg->data;
1299f36db9c4Syasuoka 	TAILQ_FOREACH(cfgmap, &env->sc_radcfgmaps, entry) {
1300f36db9c4Syasuoka 		if (cfgmap->vendor_id == cfgmap0->vendor_id &&
1301f36db9c4Syasuoka 		    cfgmap->attr_type == cfgmap0->attr_type) {
1302f36db9c4Syasuoka 			/* override existing config map */
1303f36db9c4Syasuoka 			cfgmap->cfg_type = cfgmap0->cfg_type;
1304f36db9c4Syasuoka 			break;
1305f36db9c4Syasuoka 		}
1306f36db9c4Syasuoka 	}
1307f36db9c4Syasuoka 	if (cfgmap == NULL) {
1308f36db9c4Syasuoka 		if ((cfgmap = calloc(1, len)) == NULL) {
1309f36db9c4Syasuoka 			log_warn("%s: calloc() failed", __func__);
1310f36db9c4Syasuoka 			return (-1);
1311f36db9c4Syasuoka 		}
1312f36db9c4Syasuoka 		memcpy(cfgmap, imsg->data, len);
1313f36db9c4Syasuoka 		TAILQ_INSERT_TAIL(&env->sc_radcfgmaps, cfgmap, entry);
1314f36db9c4Syasuoka 	}
1315f36db9c4Syasuoka 	return (0);
1316f36db9c4Syasuoka }
1317f36db9c4Syasuoka 
1318f36db9c4Syasuoka int
1319f36db9c4Syasuoka config_setraddae(struct iked *env, struct sockaddr *sa, socklen_t salen)
1320f36db9c4Syasuoka {
1321f36db9c4Syasuoka 	int			 sock, on;
1322f36db9c4Syasuoka 	struct iked_raddae	 dae;
1323f36db9c4Syasuoka 
1324f36db9c4Syasuoka 	if (env->sc_opts & IKED_OPT_NOACTION)
1325f36db9c4Syasuoka 		return (0);
1326f36db9c4Syasuoka 	memset(&dae, 0, sizeof(dae));
1327f36db9c4Syasuoka 	memcpy(&dae.rd_sockaddr, sa, salen);
1328f36db9c4Syasuoka 	if ((sock = socket(sa->sa_family, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
1329f36db9c4Syasuoka 		log_warn("%s: socket() failed", __func__);
1330f36db9c4Syasuoka 		goto error;
1331f36db9c4Syasuoka 	}
1332f36db9c4Syasuoka 	on = 1;
1333f36db9c4Syasuoka 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
1334f36db9c4Syasuoka 		log_warn("%s: setsockopt(,,SO_REUSEADDR) failed", __func__);
1335f36db9c4Syasuoka 	/* REUSEPORT is needed because the old sockets may not be closed yet */
1336f36db9c4Syasuoka 	on = 1;
1337f36db9c4Syasuoka 	if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) == -1)
1338f36db9c4Syasuoka 		log_warn("%s: setsockopt(,,SO_REUSEPORT) failed", __func__);
1339f36db9c4Syasuoka 	if (bind(sock, sa, salen) == -1) {
1340f36db9c4Syasuoka 		log_warn("%s: bind() failed", __func__);
1341f36db9c4Syasuoka 		goto error;
1342f36db9c4Syasuoka 	}
1343f36db9c4Syasuoka 
1344f36db9c4Syasuoka 	proc_compose_imsg(&env->sc_ps, PROC_IKEV2, -1, IMSG_CFG_RADDAE, -1,
1345f36db9c4Syasuoka 	    sock, &dae, sizeof(dae));
1346f36db9c4Syasuoka 
1347f36db9c4Syasuoka 	return (0);
1348f36db9c4Syasuoka  error:
1349f36db9c4Syasuoka 	if (sock >= 0)
1350f36db9c4Syasuoka 		close(sock);
1351f36db9c4Syasuoka 	return (-1);
1352f36db9c4Syasuoka }
1353f36db9c4Syasuoka 
1354f36db9c4Syasuoka int
1355f36db9c4Syasuoka config_getraddae(struct iked *env, struct imsg *imsg)
1356f36db9c4Syasuoka {
1357f36db9c4Syasuoka 	struct iked_raddae	*dae;
1358f36db9c4Syasuoka 
1359f36db9c4Syasuoka 	if (IMSG_DATA_SIZE(imsg) < sizeof(*dae))
1360f36db9c4Syasuoka 		fatalx("%s: invalid IMSG_CFG_RADDAE message", __func__);
1361f36db9c4Syasuoka 
1362f36db9c4Syasuoka 	if ((dae = calloc(1, sizeof(*dae))) == NULL) {
1363f36db9c4Syasuoka 		log_warn("%s: calloc() failed", __func__);
1364f36db9c4Syasuoka 		return (-1);
1365f36db9c4Syasuoka 	}
1366f36db9c4Syasuoka 	memcpy(dae, imsg->data, sizeof(*dae));
1367f36db9c4Syasuoka 	dae->rd_sock = imsg_get_fd(imsg);
1368f36db9c4Syasuoka 	dae->rd_env = env;
1369f36db9c4Syasuoka 
1370f36db9c4Syasuoka 	event_set(&dae->rd_ev, dae->rd_sock, EV_READ | EV_PERSIST,
1371f36db9c4Syasuoka 	    iked_radius_dae_on_event, dae);
1372f36db9c4Syasuoka 	event_add(&dae->rd_ev, NULL);
1373f36db9c4Syasuoka 
1374f36db9c4Syasuoka 	TAILQ_INSERT_TAIL(&env->sc_raddaes, dae, rd_entry);
1375f36db9c4Syasuoka 
1376f36db9c4Syasuoka 	return (0);
1377f36db9c4Syasuoka }
1378f36db9c4Syasuoka 
1379f36db9c4Syasuoka int
1380f36db9c4Syasuoka config_setradclient(struct iked *env, struct sockaddr *sa, socklen_t salen,
1381f36db9c4Syasuoka     char *secret)
1382f36db9c4Syasuoka {
1383f36db9c4Syasuoka 	struct iovec		 iov[2];
1384f36db9c4Syasuoka 	struct iked_radclient	 client;
1385f36db9c4Syasuoka 
1386f36db9c4Syasuoka 	if (salen > sizeof(client.rc_sockaddr))
1387f36db9c4Syasuoka 		fatal("%s: invalid salen", __func__);
1388f36db9c4Syasuoka 
1389f36db9c4Syasuoka 	memcpy(&client.rc_sockaddr, sa, salen);
1390f36db9c4Syasuoka 
1391f36db9c4Syasuoka 	iov[0].iov_base = &client;
1392f36db9c4Syasuoka 	iov[0].iov_len = offsetof(struct iked_radclient, rc_secret[0]);
1393f36db9c4Syasuoka 	iov[1].iov_base = secret;
1394f36db9c4Syasuoka 	iov[1].iov_len = strlen(secret);
1395f36db9c4Syasuoka 
1396f36db9c4Syasuoka 	proc_composev_imsg(&env->sc_ps, PROC_IKEV2, -1, IMSG_CFG_RADDAECLIENT,
1397f36db9c4Syasuoka 	    -1, -1, iov, 2);
1398f36db9c4Syasuoka 
1399f36db9c4Syasuoka 	return (0);
1400f36db9c4Syasuoka }
1401f36db9c4Syasuoka 
1402f36db9c4Syasuoka int
1403f36db9c4Syasuoka config_getradclient(struct iked *env, struct imsg *imsg)
1404f36db9c4Syasuoka {
1405f36db9c4Syasuoka 	struct iked_radclient	*client;
1406f36db9c4Syasuoka 	u_int			 len;
1407f36db9c4Syasuoka 
1408f36db9c4Syasuoka 	len = IMSG_DATA_SIZE(imsg);
1409f36db9c4Syasuoka 
1410f36db9c4Syasuoka 	if (len < sizeof(*client))
1411f36db9c4Syasuoka 		fatalx("%s: invalid IMSG_CFG_RADDAE message", __func__);
1412f36db9c4Syasuoka 
1413f36db9c4Syasuoka 	if ((client = calloc(1, len + 1)) == NULL) {
1414f36db9c4Syasuoka 		log_warn("%s: calloc() failed", __func__);
1415f36db9c4Syasuoka 		return (-1);
1416f36db9c4Syasuoka 	}
1417f36db9c4Syasuoka 	memcpy(client, imsg->data, len);
1418f36db9c4Syasuoka 
1419f36db9c4Syasuoka 	TAILQ_INSERT_TAIL(&env->sc_raddaeclients, client, rc_entry);
1420f36db9c4Syasuoka 
1421f36db9c4Syasuoka 	return (0);
1422f36db9c4Syasuoka }
1423