config.c revision 1.13
1/*	$OpenBSD: config.c,v 1.13 2011/07/05 19:59:00 tedu Exp $	*/
2/*	$vantronix: config.c,v 1.30 2010/05/28 15:34:35 reyk Exp $	*/
3
4/*
5 * Copyright (c) 2010 Reyk Floeter <reyk@vantronix.net>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <sys/param.h>
21#include <sys/types.h>
22#include <sys/queue.h>
23#include <sys/wait.h>
24#include <sys/socket.h>
25#include <sys/uio.h>
26
27#include <net/if.h>
28#include <netinet/in_systm.h>
29#include <netinet/in.h>
30#include <netinet/ip.h>
31#include <netinet/tcp.h>
32#include <arpa/inet.h>
33
34#include <stdlib.h>
35#include <stdio.h>
36#include <unistd.h>
37#include <string.h>
38#include <getopt.h>
39#include <signal.h>
40#include <errno.h>
41#include <err.h>
42#include <pwd.h>
43#include <event.h>
44
45#include "iked.h"
46#include "ikev2.h"
47
48struct iked_sa *
49config_new_sa(struct iked *env, int initiator)
50{
51	struct iked_sa	*sa;
52
53	if ((sa = calloc(1, sizeof(*sa))) == NULL)
54		return (NULL);
55
56	TAILQ_INIT(&sa->sa_proposals);
57	TAILQ_INIT(&sa->sa_childsas);
58	TAILQ_INIT(&sa->sa_flows);
59	sa->sa_hdr.sh_initiator = initiator;
60	sa->sa_type = IKED_SATYPE_LOCAL;
61
62	if (initiator)
63		sa->sa_hdr.sh_ispi = config_getspi();
64	else
65		sa->sa_hdr.sh_rspi = config_getspi();
66
67	gettimeofday(&sa->sa_timecreated, NULL);
68	memcpy(&sa->sa_timeused, &sa->sa_timecreated, sizeof(sa->sa_timeused));
69
70	return (sa);
71}
72
73u_int64_t
74config_getspi(void)
75{
76	u_int64_t	 spi;
77
78	spi = ((u_int64_t)arc4random() << 32) | arc4random();
79	if (spi == 0)
80		return (config_getspi());
81
82	return (spi);
83}
84
85void
86config_free_sa(struct iked *env, struct iked_sa *sa)
87{
88	(void)RB_REMOVE(iked_sas, &env->sc_sas, sa);
89
90	config_free_proposals(&sa->sa_proposals, 0);
91	config_free_childsas(env, &sa->sa_childsas, NULL, NULL);
92	sa_free_flows(env, &sa->sa_flows);
93
94	if (sa->sa_policy) {
95		(void)RB_REMOVE(iked_sapeers, &sa->sa_policy->pol_sapeers, sa);
96		policy_unref(env, sa->sa_policy);
97	}
98
99	ibuf_release(sa->sa_inonce);
100	ibuf_release(sa->sa_rnonce);
101
102	if (sa->sa_dhgroup != NULL)
103		group_free(sa->sa_dhgroup);
104	ibuf_release(sa->sa_dhiexchange);
105	ibuf_release(sa->sa_dhrexchange);
106
107	hash_free(sa->sa_prf);
108	hash_free(sa->sa_integr);
109	cipher_free(sa->sa_encr);
110
111	ibuf_release(sa->sa_key_d);
112	ibuf_release(sa->sa_key_iauth);
113	ibuf_release(sa->sa_key_rauth);
114	ibuf_release(sa->sa_key_iencr);
115	ibuf_release(sa->sa_key_rencr);
116	ibuf_release(sa->sa_key_iprf);
117	ibuf_release(sa->sa_key_rprf);
118
119	ibuf_release(sa->sa_1stmsg);
120	ibuf_release(sa->sa_2ndmsg);
121
122	ibuf_release(sa->sa_iid.id_buf);
123	ibuf_release(sa->sa_rid.id_buf);
124	ibuf_release(sa->sa_icert.id_buf);
125	ibuf_release(sa->sa_rcert.id_buf);
126
127	ibuf_release(sa->sa_eap.id_buf);
128	if (sa->sa_eapid != NULL)
129		free(sa->sa_eapid);
130	ibuf_release(sa->sa_eapmsk);
131
132	free(sa);
133}
134
135struct iked_policy *
136config_new_policy(struct iked *env)
137{
138	struct iked_policy	*pol;
139
140	if ((pol = calloc(1, sizeof(*pol))) == NULL)
141		return (NULL);
142
143	TAILQ_INIT(&pol->pol_proposals);
144	RB_INIT(&pol->pol_sapeers);
145
146	return (pol);
147}
148
149void
150config_free_policy(struct iked *env, struct iked_policy *pol)
151{
152	struct iked_sa		*sa;
153
154	if (pol->pol_flags & IKED_POLICY_REFCNT)
155		goto remove;
156
157	TAILQ_REMOVE(&env->sc_policies, pol, pol_entry);
158
159	RB_FOREACH(sa, iked_sapeers, &pol->pol_sapeers) {
160		/* Remove from the policy tree, but keep for existing SAs */
161		if (sa->sa_policy == pol)
162			policy_ref(env, pol);
163	}
164
165	if (pol->pol_refcnt)
166		return;
167
168 remove:
169	config_free_proposals(&pol->pol_proposals, 0);
170	config_free_flows(env, &pol->pol_flows);
171	free(pol);
172}
173
174struct iked_proposal *
175config_add_proposal(struct iked_proposals *head, u_int id, u_int proto)
176{
177	struct iked_proposal	*pp;
178
179	TAILQ_FOREACH(pp, head, prop_entry) {
180		if (pp->prop_protoid == proto &&
181		    pp->prop_id == id)
182			return (pp);
183	}
184
185	if ((pp = calloc(1, sizeof(*pp))) == NULL)
186		return (NULL);
187
188	pp->prop_protoid = proto;
189	pp->prop_id = id;
190
191	TAILQ_INSERT_TAIL(head, pp, prop_entry);
192
193	return (pp);
194}
195
196void
197config_free_proposals(struct iked_proposals *head, u_int proto)
198{
199	struct iked_proposal	*prop, *next;
200
201	for (prop = TAILQ_FIRST(head); prop != NULL; prop = next) {
202		next = TAILQ_NEXT(prop, prop_entry);
203
204		/* Free any proposal or only selected SA proto */
205		if (proto != 0 && prop->prop_protoid != proto)
206			continue;
207
208		log_debug("%s: free %p", __func__, prop);
209
210		TAILQ_REMOVE(head, prop, prop_entry);
211		if (prop->prop_nxforms)
212			free(prop->prop_xforms);
213		free(prop);
214	}
215}
216
217void
218config_free_flows(struct iked *env, struct iked_flows *head)
219{
220	struct iked_flow	*flow, *next;
221
222	for (flow = RB_MIN(iked_flows, head); flow != NULL; flow = next) {
223		next = RB_NEXT(iked_flows, head, flow);
224		log_debug("%s: free %p", __func__, flow);
225		RB_REMOVE(iked_flows, head, flow);
226		flow_free(flow);
227	}
228}
229
230void
231config_free_childsas(struct iked *env, struct iked_childsas *head,
232    struct iked_spi *peerspi, struct iked_spi *localspi)
233{
234	struct iked_childsa	*csa, *nextcsa;
235
236	if (localspi != NULL)
237		bzero(localspi, sizeof(*localspi));
238
239	for (csa = TAILQ_FIRST(head); csa != NULL; csa = nextcsa) {
240		nextcsa = TAILQ_NEXT(csa, csa_entry);
241
242		if (peerspi != NULL) {
243			/* Only delete matching peer SPIs */
244			if (peerspi->spi != csa->csa_peerspi)
245				continue;
246
247			/* Store assigned local SPI */
248			if (localspi != NULL && localspi->spi == 0)
249				memcpy(localspi, &csa->csa_spi,
250				    sizeof(*localspi));
251		}
252		log_debug("%s: free %p", __func__, csa);
253
254		TAILQ_REMOVE(head, csa, csa_entry);
255		if (csa->csa_loaded) {
256			RB_REMOVE(iked_activesas, &env->sc_activesas, csa);
257			(void)pfkey_sa_delete(env->sc_pfkey, csa);
258		}
259		childsa_free(csa);
260	}
261}
262
263struct iked_transform *
264config_add_transform(struct iked_proposal *prop, u_int type,
265    u_int id, u_int length, u_int keylength)
266{
267	struct iked_transform	*xform;
268	struct iked_constmap	*map = NULL;
269	int			 score = 1;
270	u_int			 i;
271
272	switch (type) {
273	case IKEV2_XFORMTYPE_ENCR:
274		map = ikev2_xformencr_map;
275		break;
276	case IKEV2_XFORMTYPE_PRF:
277		map = ikev2_xformprf_map;
278		break;
279	case IKEV2_XFORMTYPE_INTEGR:
280		map = ikev2_xformauth_map;
281		break;
282	case IKEV2_XFORMTYPE_DH:
283		map = ikev2_xformdh_map;
284		break;
285	case IKEV2_XFORMTYPE_ESN:
286		map = ikev2_xformesn_map;
287		break;
288	default:
289		log_debug("%s: invalid transform type %d", __func__, type);
290		return (NULL);
291	}
292
293	for (i = 0; i < prop->prop_nxforms; i++) {
294		xform = prop->prop_xforms + i;
295		if (xform->xform_type == type &&
296		    xform->xform_id == id &&
297		    xform->xform_length == length)
298			return (xform);
299	}
300
301	for (i = 0; i < prop->prop_nxforms; i++) {
302		xform = prop->prop_xforms + i;
303		if (xform->xform_type == type) {
304			switch (type) {
305			case IKEV2_XFORMTYPE_ENCR:
306			case IKEV2_XFORMTYPE_INTEGR:
307				score += 3;
308				break;
309			case IKEV2_XFORMTYPE_DH:
310				score += 2;
311				break;
312			default:
313				score += 1;
314				break;
315			}
316		}
317	}
318
319	if ((xform = realloc(prop->prop_xforms,
320	    (prop->prop_nxforms + 1) * sizeof(*xform))) == NULL) {
321		return (NULL);
322	}
323
324	prop->prop_xforms = xform;
325	xform = prop->prop_xforms + prop->prop_nxforms++;
326	bzero(xform, sizeof(*xform));
327
328	xform->xform_type = type;
329	xform->xform_id = id;
330	xform->xform_length = length;
331	xform->xform_keylength = keylength;
332	xform->xform_score = score;
333	xform->xform_map = map;
334
335	return (xform);
336}
337
338struct iked_transform *
339config_findtransform(struct iked_proposals *props, u_int8_t type)
340{
341	struct iked_proposal	*prop;
342	struct iked_transform	*xform;
343	u_int			 i;
344
345	/* Search of the first transform with the desired type */
346	TAILQ_FOREACH(prop, props, prop_entry) {
347		for (i = 0; i < prop->prop_nxforms; i++) {
348			xform = prop->prop_xforms + i;
349			if (xform->xform_type == type)
350				return (xform);
351		}
352	}
353
354	return (NULL);
355}
356
357struct iked_user *
358config_new_user(struct iked *env, struct iked_user *new)
359{
360	struct iked_user	*usr, *old;
361
362	if ((usr = calloc(1, sizeof(*usr))) == NULL)
363		return (NULL);
364
365	memcpy(usr, new, sizeof(*usr));
366
367	if ((old = RB_INSERT(iked_users, &env->sc_users, usr)) != NULL) {
368		/* Update the password of an existing user*/
369		memcpy(old, new, sizeof(*old));
370
371		log_debug("%s: updating user %s", __func__, usr->usr_name);
372		free(usr);
373
374		return (old);
375	}
376
377	log_debug("%s: inserting new user %s", __func__, usr->usr_name);
378	return (usr);
379}
380
381/*
382 * Inter-process communication of configuration items.
383 */
384
385int
386config_setcoupled(struct iked *env, u_int couple)
387{
388	u_int	 type;
389
390	type = couple ? IMSG_CTL_COUPLE : IMSG_CTL_DECOUPLE;
391	proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0);
392	proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0);
393
394	return (0);
395}
396
397int
398config_getcoupled(struct iked *env, u_int type)
399{
400	return (pfkey_couple(env->sc_pfkey, &env->sc_sas,
401	    type == IMSG_CTL_COUPLE ? 1 : 0));
402}
403
404int
405config_setmode(struct iked *env, u_int passive)
406{
407	u_int	 type;
408
409	type = passive ? IMSG_CTL_PASSIVE : IMSG_CTL_ACTIVE;
410	proc_compose_imsg(env, PROC_IKEV1, type, -1, NULL, 0);
411	proc_compose_imsg(env, PROC_IKEV2, type, -1, NULL, 0);
412
413	return (0);
414}
415
416int
417config_getmode(struct iked *env, u_int type)
418{
419	u_int8_t	 old;
420	u_char		*mode[] = { "active", "passive" };
421
422	old = env->sc_passive ? 1 : 0;
423	env->sc_passive = type == IMSG_CTL_PASSIVE ? 1 : 0;
424
425	if (old == env->sc_passive)
426		return (0);
427
428	log_debug("%s: mode %s -> %s", __func__,
429	    mode[old], mode[env->sc_passive]);
430
431	return (0);
432}
433
434int
435config_setreset(struct iked *env, u_int mode, enum privsep_procid id)
436{
437	proc_compose_imsg(env, id, IMSG_CTL_RESET, -1, &mode, sizeof(mode));
438	return (0);
439}
440
441int
442config_getreset(struct iked *env, struct imsg *imsg)
443{
444	struct iked_policy	*pol, *nextpol;
445	struct iked_sa		*sa, *nextsa;
446	struct iked_user	*usr, *nextusr;
447	u_int			 mode;
448
449	IMSG_SIZE_CHECK(imsg, &mode);
450	memcpy(&mode, imsg->data, sizeof(mode));
451
452	if (mode == RESET_ALL || mode == RESET_POLICY) {
453		log_debug("%s: flushing policies", __func__);
454		for (pol = TAILQ_FIRST(&env->sc_policies);
455		    pol != NULL; pol = nextpol) {
456			nextpol = TAILQ_NEXT(pol, pol_entry);
457			config_free_policy(env, pol);
458		}
459	}
460
461	if (mode == RESET_ALL || mode == RESET_SA) {
462		log_debug("%s: flushing SAs", __func__);
463		for (sa = RB_MIN(iked_sas, &env->sc_sas);
464		    sa != NULL; sa = nextsa) {
465			nextsa = RB_NEXT(iked_sas, &env->sc_sas, sa);
466			config_free_sa(env, sa);
467		}
468	}
469
470	if (mode == RESET_ALL || mode == RESET_USER) {
471		log_debug("%s: flushing users", __func__);
472		for (usr = RB_MIN(iked_users, &env->sc_users);
473		    usr != NULL; usr = nextusr) {
474			nextusr = RB_NEXT(iked_users, &env->sc_users, usr);
475			RB_REMOVE(iked_users, &env->sc_users, usr);
476			free(usr);
477		}
478	}
479
480	return (0);
481}
482
483int
484config_setsocket(struct iked *env, struct sockaddr_storage *ss,
485    in_port_t port, enum privsep_procid id)
486{
487	int	 s;
488
489	if ((s = udp_bind((struct sockaddr *)ss, port)) == -1)
490		return (-1);
491	proc_compose_imsg(env, id, IMSG_UDP_SOCKET, s,
492	    ss, sizeof(*ss));
493	return (0);
494}
495
496int
497config_getsocket(struct iked *env, struct imsg *imsg,
498    void (*cb)(int, short, void *))
499{
500	struct iked_socket	*sock, **sptr;
501
502	log_debug("%s: received socket fd %d", __func__, imsg->fd);
503
504	if ((sock = calloc(1, sizeof(*sock))) == NULL)
505		fatal("config_getsocket: calloc");
506
507	IMSG_SIZE_CHECK(imsg, &sock->sock_addr);
508
509	memcpy(&sock->sock_addr, imsg->data, sizeof(sock->sock_addr));
510	sock->sock_fd = imsg->fd;
511	sock->sock_env = env;
512
513	switch (sock->sock_addr.ss_family) {
514	case AF_INET:
515		sptr = &env->sc_sock4;
516		break;
517	case AF_INET6:
518		sptr = &env->sc_sock6;
519		break;
520	default:
521		fatal("config_getsocket: socket af");
522		/* NOTREACHED */
523	}
524	if (*sptr == NULL)
525		*sptr = sock;
526
527	event_set(&sock->sock_ev, sock->sock_fd,
528	    EV_READ|EV_PERSIST, cb, sock);
529	event_add(&sock->sock_ev, NULL);
530
531	return (0);
532}
533
534int
535config_setpfkey(struct iked *env, enum privsep_procid id)
536{
537	int	 s;
538
539	if ((s = pfkey_socket()) == -1)
540		return (-1);
541	proc_compose_imsg(env, id, IMSG_PFKEY_SOCKET, s, NULL, 0);
542	return (0);
543}
544
545int
546config_getpfkey(struct iked *env, struct imsg *imsg)
547{
548	log_debug("%s: received pfkey fd %d", __func__, imsg->fd);
549	pfkey_init(env, imsg->fd);
550	return (0);
551}
552
553int
554config_setuser(struct iked *env, struct iked_user *usr, enum privsep_procid id)
555{
556	if (env->sc_opts & IKED_OPT_NOACTION) {
557		print_user(usr);
558		return (0);
559	}
560
561	proc_compose_imsg(env, id, IMSG_CFG_USER, -1, usr, sizeof(*usr));
562	return (0);
563}
564
565int
566config_getuser(struct iked *env, struct imsg *imsg)
567{
568	struct iked_user	 usr;
569
570	IMSG_SIZE_CHECK(imsg, &usr);
571	memcpy(&usr, imsg->data, sizeof(usr));
572
573	if (config_new_user(env, &usr) == NULL)
574		return (-1);
575
576	print_user(&usr);
577
578	return (0);
579}
580
581int
582config_setpolicy(struct iked *env, struct iked_policy *pol,
583    enum privsep_procid id)
584{
585	struct iked_proposal	*prop;
586	struct iked_flow	*flow;
587	struct iked_transform	*xform;
588	size_t			 size, iovcnt, j, c = 0;
589	struct iovec		 iov[IOV_MAX];
590
591	iovcnt = 1;
592	size = sizeof(*pol);
593	TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) {
594		size += (prop->prop_nxforms * sizeof(*xform)) +
595		    (sizeof(*prop));
596		iovcnt += prop->prop_nxforms + 1;
597	}
598
599	size += pol->pol_nflows * sizeof(*flow);
600	iovcnt += pol->pol_nflows;
601
602	if (iovcnt > IOV_MAX) {
603		log_warn("%s: too many proposals/flows", __func__);
604		return (-1);
605	}
606
607	iov[c].iov_base = pol;
608	iov[c++].iov_len = sizeof(*pol);
609
610	TAILQ_FOREACH(prop, &pol->pol_proposals, prop_entry) {
611		iov[c].iov_base = prop;
612		iov[c++].iov_len = sizeof(*prop);
613
614		for (j = 0; j < prop->prop_nxforms; j++) {
615			xform = prop->prop_xforms + j;
616
617			iov[c].iov_base = xform;
618			iov[c++].iov_len = sizeof(*xform);
619		}
620	}
621
622	RB_FOREACH(flow, iked_flows, &pol->pol_flows) {
623		iov[c].iov_base = flow;
624		iov[c++].iov_len = sizeof(*flow);
625	}
626
627	if (env->sc_opts & IKED_OPT_NOACTION) {
628		print_policy(pol);
629		return (0);
630	}
631
632	if (proc_composev_imsg(env, id, IMSG_CFG_POLICY, -1,
633	    iov, iovcnt) == -1)
634		return (-1);
635
636	return (0);
637}
638
639int
640config_getpolicy(struct iked *env, struct imsg *imsg)
641{
642	struct iked_policy	*pol;
643	struct iked_proposal	 pp, *prop;
644	struct iked_transform	 xf, *xform;
645	struct iked_flow	*flow;
646	off_t			 offset = 0;
647	u_int			 i, j;
648	u_int8_t		*buf = (u_int8_t *)imsg->data;
649
650	IMSG_SIZE_CHECK(imsg, pol);
651	log_debug("%s: received policy", __func__);
652
653	if ((pol = config_new_policy(NULL)) == NULL)
654		fatal("config_getpolicy: new policy");
655
656	memcpy(pol, buf, sizeof(*pol));
657	offset += sizeof(*pol);
658
659	TAILQ_INIT(&pol->pol_proposals);
660	RB_INIT(&pol->pol_flows);
661
662	for (i = 0; i < pol->pol_nproposals; i++) {
663		memcpy(&pp, buf + offset, sizeof(pp));
664		offset += sizeof(pp);
665
666		if ((prop = config_add_proposal(&pol->pol_proposals,
667		    pp.prop_id, pp.prop_protoid)) == NULL)
668			fatal("config_getpolicy: add proposal");
669
670		for (j = 0; j < pp.prop_nxforms; j++) {
671			memcpy(&xf, buf + offset, sizeof(xf));
672			offset += sizeof(xf);
673
674			if ((xform = config_add_transform(prop, xf.xform_type,
675			    xf.xform_id, xf.xform_length,
676			    xf.xform_keylength)) == NULL)
677				fatal("config_getpolicy: add transform");
678		}
679	}
680
681	for (i = 0; i < pol->pol_nflows; i++) {
682		if ((flow = calloc(1, sizeof(*flow))) == NULL)
683			fatal("config_getpolicy: new flow");
684
685		memcpy(flow, buf + offset, sizeof(*flow));
686		offset += sizeof(*flow);
687
688		RB_INSERT(iked_flows, &pol->pol_flows, flow);
689	}
690
691	TAILQ_INSERT_TAIL(&env->sc_policies, pol, pol_entry);
692
693	if (pol->pol_flags & IKED_POLICY_DEFAULT) {
694		/* Only one default policy, just free/unref the old one */
695		if (env->sc_defaultcon != NULL)
696			config_free_policy(env, env->sc_defaultcon);
697		env->sc_defaultcon = pol;
698	}
699
700	print_policy(pol);
701
702	return (0);
703}
704
705int
706config_setcompile(struct iked *env, enum privsep_procid id)
707{
708	if (env->sc_opts & IKED_OPT_NOACTION)
709		return (0);
710
711	proc_compose_imsg(env, id, IMSG_COMPILE, -1, NULL, 0);
712	return (0);
713}
714
715int
716config_getcompile(struct iked *env, struct imsg *imsg)
717{
718	/*
719	 * Do any necessary steps after configuration, for now we
720	 * only need to compile the skip steps.
721	 */
722	policy_calc_skip_steps(&env->sc_policies);
723
724	log_debug("%s: compilation done", __func__);
725	return (0);
726}
727