1/*	$NetBSD: proposal.c,v 1.13.4.2 2008/07/22 13:25:42 vanhu Exp $	*/
2
3/* $Id: proposal.c,v 1.13.4.2 2008/07/22 13:25:42 vanhu Exp $ */
4
5/*
6 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the project nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "config.h"
35
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <sys/queue.h>
40
41#include <netinet/in.h>
42#include PATH_IPSEC_H
43
44#include <stdlib.h>
45#include <stdio.h>
46#include <string.h>
47#include <errno.h>
48
49#include "var.h"
50#include "misc.h"
51#include "vmbuf.h"
52#include "plog.h"
53#include "sockmisc.h"
54#include "debug.h"
55
56#include "policy.h"
57#include "pfkey.h"
58#include "isakmp_var.h"
59#include "isakmp.h"
60#include "ipsec_doi.h"
61#include "algorithm.h"
62#include "proposal.h"
63#include "sainfo.h"
64#include "localconf.h"
65#include "remoteconf.h"
66#include "oakley.h"
67#include "handler.h"
68#include "strnames.h"
69#include "gcmalloc.h"
70#ifdef ENABLE_NATT
71#include "nattraversal.h"
72#endif
73
74static uint g_nextreqid = 1;
75
76/* %%%
77 * modules for ipsec sa spec
78 */
79struct saprop *
80newsaprop()
81{
82	struct saprop *new;
83
84	new = racoon_calloc(1, sizeof(*new));
85	if (new == NULL)
86		return NULL;
87
88	return new;
89}
90
91struct saproto *
92newsaproto()
93{
94	struct saproto *new;
95
96	new = racoon_calloc(1, sizeof(*new));
97	if (new == NULL)
98		return NULL;
99
100	return new;
101}
102
103/* set saprop to last part of the prop tree */
104void
105inssaprop(head, new)
106	struct saprop **head;
107	struct saprop *new;
108{
109	struct saprop *p;
110
111	if (*head == NULL) {
112		*head = new;
113		return;
114	}
115
116	for (p = *head; p->next; p = p->next)
117		;
118	p->next = new;
119
120	return;
121}
122
123/* set saproto to the end of the proto tree in saprop */
124void
125inssaproto(pp, new)
126	struct saprop *pp;
127	struct saproto *new;
128{
129	struct saproto *p;
130
131	for (p = pp->head; p && p->next; p = p->next)
132		;
133	if (p == NULL)
134		pp->head = new;
135	else
136		p->next = new;
137
138	return;
139}
140
141/* set saproto to the top of the proto tree in saprop */
142void
143inssaprotorev(pp, new)
144      struct saprop *pp;
145      struct saproto *new;
146{
147      new->next = pp->head;
148      pp->head = new;
149
150      return;
151}
152
153struct satrns *
154newsatrns()
155{
156	struct satrns *new;
157
158	new = racoon_calloc(1, sizeof(*new));
159	if (new == NULL)
160		return NULL;
161
162	return new;
163}
164
165/* set saproto to last part of the proto tree in saprop */
166void
167inssatrns(pr, new)
168	struct saproto *pr;
169	struct satrns *new;
170{
171	struct satrns *tr;
172
173	for (tr = pr->head; tr && tr->next; tr = tr->next)
174		;
175	if (tr == NULL)
176		pr->head = new;
177	else
178		tr->next = new;
179
180	return;
181}
182
183/*
184 * take a single match between saprop.  allocate a new proposal and return it
185 * for future use (like picking single proposal from a bundle).
186 *	pp1: peer's proposal.
187 *	pp2: my proposal.
188 * NOTE: In the case of initiator, must be ensured that there is no
189 * modification of the proposal by calling cmp_aproppair_i() before
190 * this function.
191 * XXX cannot understand the comment!
192 */
193struct saprop *
194cmpsaprop_alloc(ph1, pp1, pp2, side)
195	struct ph1handle *ph1;
196	const struct saprop *pp1, *pp2;
197	int side;
198{
199	struct saprop *newpp = NULL;
200	struct saproto *pr1, *pr2, *newpr = NULL;
201	struct satrns *tr1, *tr2, *newtr;
202	const int ordermatters = 0;
203	int npr1, npr2;
204	int spisizematch;
205
206	newpp = newsaprop();
207	if (newpp == NULL) {
208		plog(LLV_ERROR, LOCATION, NULL,
209			"failed to allocate saprop.\n");
210		return NULL;
211	}
212	newpp->prop_no = pp1->prop_no;
213
214	/* see proposal.h about lifetime/key length and PFS selection. */
215
216	/* check time/bytes lifetime and PFS */
217	switch (ph1->rmconf->pcheck_level) {
218	case PROP_CHECK_OBEY:
219		newpp->lifetime = pp1->lifetime;
220		newpp->lifebyte = pp1->lifebyte;
221		newpp->pfs_group = pp1->pfs_group;
222		break;
223
224	case PROP_CHECK_STRICT:
225		if (pp1->lifetime > pp2->lifetime) {
226			plog(LLV_ERROR, LOCATION, NULL,
227				"long lifetime proposed: "
228				"my:%d peer:%d\n",
229				(int)pp2->lifetime, (int)pp1->lifetime);
230			goto err;
231		}
232		if (pp1->lifebyte > pp2->lifebyte) {
233			plog(LLV_ERROR, LOCATION, NULL,
234				"long lifebyte proposed: "
235				"my:%d peer:%d\n",
236				pp2->lifebyte, pp1->lifebyte);
237			goto err;
238		}
239		newpp->lifetime = pp1->lifetime;
240		newpp->lifebyte = pp1->lifebyte;
241
242    prop_pfs_check:
243		if (pp2->pfs_group != 0 && pp1->pfs_group != pp2->pfs_group) {
244			plog(LLV_ERROR, LOCATION, NULL,
245				"pfs group mismatched: "
246				"my:%d peer:%d\n",
247				pp2->pfs_group, pp1->pfs_group);
248			goto err;
249		}
250		newpp->pfs_group = pp1->pfs_group;
251		break;
252
253	case PROP_CHECK_CLAIM:
254		/* lifetime */
255		if (pp1->lifetime <= pp2->lifetime) {
256			newpp->lifetime = pp1->lifetime;
257		} else {
258			newpp->lifetime = pp2->lifetime;
259			newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
260			plog(LLV_NOTIFY, LOCATION, NULL,
261				"use own lifetime: "
262				"my:%d peer:%d\n",
263				(int)pp2->lifetime, (int)pp1->lifetime);
264		}
265
266		/* lifebyte */
267		if (pp1->lifebyte > pp2->lifebyte) {
268			newpp->lifebyte = pp2->lifebyte;
269			newpp->claim |= IPSECDOI_ATTR_SA_LD_TYPE_SEC;
270			plog(LLV_NOTIFY, LOCATION, NULL,
271				"use own lifebyte: "
272				"my:%d peer:%d\n",
273				pp2->lifebyte, pp1->lifebyte);
274		}
275		newpp->lifebyte = pp1->lifebyte;
276
277    		goto prop_pfs_check;
278		break;
279
280	case PROP_CHECK_EXACT:
281		if (pp1->lifetime != pp2->lifetime) {
282			plog(LLV_ERROR, LOCATION, NULL,
283				"lifetime mismatched: "
284				"my:%d peer:%d\n",
285				(int)pp2->lifetime, (int)pp1->lifetime);
286			goto err;
287		}
288
289		if (pp1->lifebyte != pp2->lifebyte) {
290			plog(LLV_ERROR, LOCATION, NULL,
291				"lifebyte mismatched: "
292				"my:%d peer:%d\n",
293				pp2->lifebyte, pp1->lifebyte);
294			goto err;
295		}
296		if (pp1->pfs_group != pp2->pfs_group) {
297			plog(LLV_ERROR, LOCATION, NULL,
298				"pfs group mismatched: "
299				"my:%d peer:%d\n",
300				pp2->pfs_group, pp1->pfs_group);
301			goto err;
302		}
303		newpp->lifetime = pp1->lifetime;
304		newpp->lifebyte = pp1->lifebyte;
305		newpp->pfs_group = pp1->pfs_group;
306		break;
307
308	default:
309		plog(LLV_ERROR, LOCATION, NULL,
310			"invalid pcheck_level why?.\n");
311		goto err;
312	}
313
314#ifdef HAVE_SECCTX
315	/* check the security_context properties.
316	 * It is possible for one side to have a security context
317	 * and the other side doesn't. If so, this is an error.
318	 */
319
320	if (*pp1->sctx.ctx_str && !(*pp2->sctx.ctx_str)) {
321		plog(LLV_ERROR, LOCATION, NULL,
322		     "My proposal missing security context\n");
323		goto err;
324	}
325	if (!(*pp1->sctx.ctx_str) && *pp2->sctx.ctx_str) {
326		plog(LLV_ERROR, LOCATION, NULL,
327		     "Peer is missing security context\n");
328		goto err;
329	}
330
331	if (*pp1->sctx.ctx_str && *pp2->sctx.ctx_str) {
332		if (pp1->sctx.ctx_doi == pp2->sctx.ctx_doi)
333			newpp->sctx.ctx_doi = pp1->sctx.ctx_doi;
334		else {
335			plog(LLV_ERROR, LOCATION, NULL,
336			     "sec doi mismatched: my:%d peer:%d\n",
337			     pp2->sctx.ctx_doi, pp1->sctx.ctx_doi);
338			     goto err;
339		}
340
341		if (pp1->sctx.ctx_alg == pp2->sctx.ctx_alg)
342			newpp->sctx.ctx_alg = pp1->sctx.ctx_alg;
343		else {
344			plog(LLV_ERROR, LOCATION, NULL,
345			     "sec alg mismatched: my:%d peer:%d\n",
346			     pp2->sctx.ctx_alg, pp1->sctx.ctx_alg);
347			goto err;
348		}
349
350		if ((pp1->sctx.ctx_strlen != pp2->sctx.ctx_strlen) ||
351		     memcmp(pp1->sctx.ctx_str, pp2->sctx.ctx_str,
352		     pp1->sctx.ctx_strlen) != 0) {
353			plog(LLV_ERROR, LOCATION, NULL,
354			     "sec ctx string mismatched: my:%s peer:%s\n",
355			     pp2->sctx.ctx_str, pp1->sctx.ctx_str);
356				goto err;
357		} else {
358			newpp->sctx.ctx_strlen = pp1->sctx.ctx_strlen;
359			memcpy(newpp->sctx.ctx_str, pp1->sctx.ctx_str,
360				pp1->sctx.ctx_strlen);
361		}
362	}
363#endif /* HAVE_SECCTX */
364
365	npr1 = npr2 = 0;
366	for (pr1 = pp1->head; pr1; pr1 = pr1->next)
367		npr1++;
368	for (pr2 = pp2->head; pr2; pr2 = pr2->next)
369		npr2++;
370	if (npr1 != npr2)
371		goto err;
372
373	/* check protocol order */
374	pr1 = pp1->head;
375	pr2 = pp2->head;
376
377	while (1) {
378		if (!ordermatters) {
379			/*
380			 * XXX does not work if we have multiple proposals
381			 * with the same proto_id
382			 */
383			switch (side) {
384			case RESPONDER:
385				if (!pr2)
386					break;
387				for (pr1 = pp1->head; pr1; pr1 = pr1->next) {
388					if (pr1->proto_id == pr2->proto_id)
389						break;
390				}
391				break;
392			case INITIATOR:
393				if (!pr1)
394					break;
395				for (pr2 = pp2->head; pr2; pr2 = pr2->next) {
396					if (pr2->proto_id == pr1->proto_id)
397						break;
398				}
399				break;
400			}
401		}
402		if (!pr1 || !pr2)
403			break;
404
405		if (pr1->proto_id != pr2->proto_id) {
406			plog(LLV_ERROR, LOCATION, NULL,
407				"proto_id mismatched: "
408				"my:%s peer:%s\n",
409				s_ipsecdoi_proto(pr2->proto_id),
410				s_ipsecdoi_proto(pr1->proto_id));
411			goto err;
412		}
413		spisizematch = 0;
414		if (pr1->spisize == pr2->spisize)
415			spisizematch = 1;
416		else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) {
417			/*
418			 * draft-shacham-ippcp-rfc2393bis-05.txt:
419			 * need to accept 16bit and 32bit SPI (CPI) for IPComp.
420			 */
421			if (pr1->spisize == sizeof(u_int16_t) &&
422			    pr2->spisize == sizeof(u_int32_t)) {
423				spisizematch = 1;
424			} else if (pr2->spisize == sizeof(u_int16_t) &&
425				 pr1->spisize == sizeof(u_int32_t)) {
426				spisizematch = 1;
427			}
428			if (spisizematch) {
429				plog(LLV_ERROR, LOCATION, NULL,
430				    "IPComp SPI size promoted "
431				    "from 16bit to 32bit\n");
432			}
433		}
434		if (!spisizematch) {
435			plog(LLV_ERROR, LOCATION, NULL,
436				"spisize mismatched: "
437				"my:%d peer:%d\n",
438				(int)pr2->spisize, (int)pr1->spisize);
439			goto err;
440		}
441
442#ifdef ENABLE_NATT
443		if ((ph1->natt_flags & NAT_DETECTED) &&
444		    natt_udp_encap (pr2->encmode))
445		{
446			plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n",
447			     s_ipsecdoi_encmode(pr2->encmode),
448			     s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff));
449			pr2->encmode -= ph1->natt_options->mode_udp_diff;
450			pr2->udp_encap = 1;
451		}
452
453		if ((ph1->natt_flags & NAT_DETECTED) &&
454		    natt_udp_encap (pr1->encmode))
455		{
456			plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
457			     s_ipsecdoi_encmode(pr1->encmode),
458			     pr1->encmode,
459			     s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff),
460			     pr1->encmode - ph1->natt_options->mode_udp_diff);
461			pr1->encmode -= ph1->natt_options->mode_udp_diff;
462			pr1->udp_encap = 1;
463		}
464#endif
465
466		if (pr1->encmode != pr2->encmode) {
467			plog(LLV_ERROR, LOCATION, NULL,
468				"encmode mismatched: "
469				"my:%s peer:%s\n",
470				s_ipsecdoi_encmode(pr2->encmode),
471				s_ipsecdoi_encmode(pr1->encmode));
472			goto err;
473		}
474
475		for (tr1 = pr1->head; tr1; tr1 = tr1->next) {
476			for (tr2 = pr2->head; tr2; tr2 = tr2->next) {
477				if (cmpsatrns(pr1->proto_id, tr1, tr2, ph1->rmconf->pcheck_level) == 0)
478					goto found;
479			}
480		}
481
482		goto err;
483
484	    found:
485		newpr = newsaproto();
486		if (newpr == NULL) {
487			plog(LLV_ERROR, LOCATION, NULL,
488				"failed to allocate saproto.\n");
489			goto err;
490		}
491		newpr->proto_id = pr1->proto_id;
492		newpr->spisize = pr1->spisize;
493		newpr->encmode = pr1->encmode;
494		newpr->spi = pr2->spi;		/* copy my SPI */
495		newpr->spi_p = pr1->spi;	/* copy peer's SPI */
496		newpr->reqid_in = pr2->reqid_in;
497		newpr->reqid_out = pr2->reqid_out;
498#ifdef ENABLE_NATT
499		newpr->udp_encap = pr1->udp_encap | pr2->udp_encap;
500#endif
501
502		newtr = newsatrns();
503		if (newtr == NULL) {
504			plog(LLV_ERROR, LOCATION, NULL,
505				"failed to allocate satrns.\n");
506			racoon_free(newpr);
507			goto err;
508		}
509		newtr->trns_no = tr1->trns_no;
510		newtr->trns_id = tr1->trns_id;
511		newtr->encklen = tr1->encklen;
512		newtr->authtype = tr1->authtype;
513
514		inssatrns(newpr, newtr);
515		inssaproto(newpp, newpr);
516
517		pr1 = pr1->next;
518		pr2 = pr2->next;
519	}
520
521	/* XXX should check if we have visited all items or not */
522	if (!ordermatters) {
523		switch (side) {
524		case RESPONDER:
525			if (!pr2)
526				pr1 = NULL;
527			break;
528		case INITIATOR:
529			if (!pr1)
530				pr2 = NULL;
531			break;
532		}
533	}
534
535	/* should be matched all protocols in a proposal */
536	if (pr1 != NULL || pr2 != NULL)
537		goto err;
538
539	return newpp;
540
541err:
542	flushsaprop(newpp);
543	return NULL;
544}
545
546/* take a single match between saprop.  returns 0 if pp1 equals to pp2. */
547int
548cmpsaprop(pp1, pp2)
549	const struct saprop *pp1, *pp2;
550{
551	if (pp1->pfs_group != pp2->pfs_group) {
552		plog(LLV_WARNING, LOCATION, NULL,
553			"pfs_group mismatch. mine:%d peer:%d\n",
554			pp1->pfs_group, pp2->pfs_group);
555		/* FALLTHRU */
556	}
557
558	if (pp1->lifetime > pp2->lifetime) {
559		plog(LLV_WARNING, LOCATION, NULL,
560			"less lifetime proposed. mine:%d peer:%d\n",
561			(int)pp1->lifetime, (int)pp2->lifetime);
562		/* FALLTHRU */
563	}
564	if (pp1->lifebyte > pp2->lifebyte) {
565		plog(LLV_WARNING, LOCATION, NULL,
566			"less lifebyte proposed. mine:%d peer:%d\n",
567			pp1->lifebyte, pp2->lifebyte);
568		/* FALLTHRU */
569	}
570
571	return 0;
572}
573
574/*
575 * take a single match between satrns.  returns 0 if tr1 equals to tr2.
576 * tr1: peer's satrns
577 * tr2: my satrns
578 */
579int
580cmpsatrns(proto_id, tr1, tr2, check_level)
581	int proto_id;
582	const struct satrns *tr1, *tr2;
583	int check_level;
584{
585	if (tr1->trns_id != tr2->trns_id) {
586		plog(LLV_WARNING, LOCATION, NULL,
587			"trns_id mismatched: "
588			"my:%s peer:%s\n",
589			s_ipsecdoi_trns(proto_id, tr2->trns_id),
590			s_ipsecdoi_trns(proto_id, tr1->trns_id));
591		return 1;
592	}
593
594	if (tr1->authtype != tr2->authtype) {
595		plog(LLV_WARNING, LOCATION, NULL,
596			"authtype mismatched: "
597			"my:%s peer:%s\n",
598			s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype),
599			s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype));
600		return 1;
601	}
602
603	/* Check key length regarding checkmode
604	 * XXX Shall we send some kind of notify message when key length rejected ?
605	 */
606	switch(check_level){
607	case PROP_CHECK_OBEY:
608		return 0;
609		break;
610
611	case PROP_CHECK_STRICT:
612		/* FALLTHROUGH */
613	case PROP_CHECK_CLAIM:
614		if (tr1->encklen < tr2->encklen) {
615		plog(LLV_WARNING, LOCATION, NULL,
616				 "low key length proposed, "
617				 "mine:%d peer:%d.\n",
618			tr2->encklen, tr1->encklen);
619			return 1;
620		}
621		break;
622	case PROP_CHECK_EXACT:
623		if (tr1->encklen != tr2->encklen) {
624			plog(LLV_WARNING, LOCATION, NULL,
625				 "key length mismatched, "
626				 "mine:%d peer:%d.\n",
627				 tr2->encklen, tr1->encklen);
628			return 1;
629		}
630		break;
631	}
632
633	return 0;
634}
635
636int
637set_satrnsbysainfo(pr, sainfo)
638	struct saproto *pr;
639	struct sainfo *sainfo;
640{
641	struct sainfoalg *a, *b;
642	struct satrns *newtr;
643	int t;
644
645	switch (pr->proto_id) {
646	case IPSECDOI_PROTO_IPSEC_AH:
647		if (sainfo->algs[algclass_ipsec_auth] == NULL) {
648			plog(LLV_ERROR, LOCATION, NULL,
649				"no auth algorithm found\n");
650			goto err;
651		}
652		t = 1;
653		for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) {
654
655			if (a->alg == IPSECDOI_ATTR_AUTH_NONE)
656				continue;
657
658			/* allocate satrns */
659			newtr = newsatrns();
660			if (newtr == NULL) {
661				plog(LLV_ERROR, LOCATION, NULL,
662					"failed to allocate satrns.\n");
663				goto err;
664			}
665
666			newtr->trns_no = t++;
667			newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg);
668			newtr->authtype = a->alg;
669
670			inssatrns(pr, newtr);
671		}
672		break;
673	case IPSECDOI_PROTO_IPSEC_ESP:
674		if (sainfo->algs[algclass_ipsec_enc] == NULL) {
675			plog(LLV_ERROR, LOCATION, NULL,
676				"no encryption algorithm found\n");
677			goto err;
678		}
679		t = 1;
680		for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) {
681			for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) {
682				/* allocate satrns */
683				newtr = newsatrns();
684				if (newtr == NULL) {
685					plog(LLV_ERROR, LOCATION, NULL,
686						"failed to allocate satrns.\n");
687					goto err;
688				}
689
690				newtr->trns_no = t++;
691				newtr->trns_id = a->alg;
692				newtr->encklen = a->encklen;
693				newtr->authtype = b->alg;
694
695				inssatrns(pr, newtr);
696			}
697		}
698		break;
699	case IPSECDOI_PROTO_IPCOMP:
700		if (sainfo->algs[algclass_ipsec_comp] == NULL) {
701			plog(LLV_ERROR, LOCATION, NULL,
702				"no ipcomp algorithm found\n");
703			goto err;
704		}
705		t = 1;
706		for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) {
707
708			/* allocate satrns */
709			newtr = newsatrns();
710			if (newtr == NULL) {
711				plog(LLV_ERROR, LOCATION, NULL,
712					"failed to allocate satrns.\n");
713				goto err;
714			}
715
716			newtr->trns_no = t++;
717			newtr->trns_id = a->alg;
718			newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/
719
720			inssatrns(pr, newtr);
721		}
722		break;
723	default:
724		plog(LLV_ERROR, LOCATION, NULL,
725			"unknown proto_id (%d).\n", pr->proto_id);
726		goto err;
727	}
728
729	/* no proposal found */
730	if (pr->head == NULL) {
731		plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n");
732		return -1;
733	}
734
735	return 0;
736
737err:
738	flushsatrns(pr->head);
739	return -1;
740}
741
742struct saprop *
743aproppair2saprop(p0)
744	struct prop_pair *p0;
745{
746	struct prop_pair *p, *t;
747	struct saprop *newpp;
748	struct saproto *newpr;
749	struct satrns *newtr;
750	u_int8_t *spi;
751
752	if (p0 == NULL)
753		return NULL;
754
755	/* allocate ipsec a sa proposal */
756	newpp = newsaprop();
757	if (newpp == NULL) {
758		plog(LLV_ERROR, LOCATION, NULL,
759			"failed to allocate saprop.\n");
760		return NULL;
761	}
762	newpp->prop_no = p0->prop->p_no;
763	/* lifetime & lifebyte must be updated later */
764
765	for (p = p0; p; p = p->next) {
766
767		/* allocate ipsec sa protocol */
768		newpr = newsaproto();
769		if (newpr == NULL) {
770			plog(LLV_ERROR, LOCATION, NULL,
771				"failed to allocate saproto.\n");
772			goto err;
773		}
774
775		/* check spi size */
776		/* XXX should be handled isakmp cookie */
777		if (sizeof(newpr->spi) < p->prop->spi_size) {
778			plog(LLV_ERROR, LOCATION, NULL,
779				"invalid spi size %d.\n", p->prop->spi_size);
780			racoon_free(newpr);
781			goto err;
782		}
783
784		/*
785		 * XXX SPI bits are left-filled, for use with IPComp.
786		 * we should be switching to variable-length spi field...
787		 */
788		newpr->proto_id = p->prop->proto_id;
789		newpr->spisize = p->prop->spi_size;
790		memset(&newpr->spi, 0, sizeof(newpr->spi));
791		spi = (u_int8_t *)&newpr->spi;
792		spi += sizeof(newpr->spi);
793		spi -= p->prop->spi_size;
794		memcpy(spi, p->prop + 1, p->prop->spi_size);
795		newpr->reqid_in = 0;
796		newpr->reqid_out = 0;
797
798		for (t = p; t; t = t->tnext) {
799
800			plog(LLV_DEBUG, LOCATION, NULL,
801				"prop#=%d prot-id=%s spi-size=%d "
802				"#trns=%d trns#=%d trns-id=%s\n",
803				t->prop->p_no,
804				s_ipsecdoi_proto(t->prop->proto_id),
805				t->prop->spi_size, t->prop->num_t,
806				t->trns->t_no,
807				s_ipsecdoi_trns(t->prop->proto_id,
808				t->trns->t_id));
809
810			/* allocate ipsec sa transform */
811			newtr = newsatrns();
812			if (newtr == NULL) {
813				plog(LLV_ERROR, LOCATION, NULL,
814					"failed to allocate satrns.\n");
815				racoon_free(newpr);
816				goto err;
817			}
818
819			if (ipsecdoi_t2satrns(t->trns,
820			    newpp, newpr, newtr) < 0) {
821				flushsaprop(newpp);
822				racoon_free(newtr);
823				racoon_free(newpr);
824				return NULL;
825			}
826
827			inssatrns(newpr, newtr);
828		}
829
830		/*
831		 * If the peer does not specify encryption mode, use
832		 * transport mode by default.  This is to conform to
833		 * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies
834		 * that unspecified == transport), as well as RFC2407
835		 * (unspecified == implementation dependent default).
836		 */
837		if (newpr->encmode == 0)
838			newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
839
840		inssaproto(newpp, newpr);
841	}
842
843	return newpp;
844
845err:
846	flushsaprop(newpp);
847	return NULL;
848}
849
850void
851flushsaprop(head)
852	struct saprop *head;
853{
854	struct saprop *p, *save;
855
856	for (p = head; p != NULL; p = save) {
857		save = p->next;
858		flushsaproto(p->head);
859		racoon_free(p);
860	}
861
862	return;
863}
864
865void
866flushsaproto(head)
867	struct saproto *head;
868{
869	struct saproto *p, *save;
870
871	for (p = head; p != NULL; p = save) {
872		save = p->next;
873		flushsatrns(p->head);
874		vfree(p->keymat);
875		vfree(p->keymat_p);
876		racoon_free(p);
877	}
878
879	return;
880}
881
882void
883flushsatrns(head)
884	struct satrns *head;
885{
886	struct satrns *p, *save;
887
888	for (p = head; p != NULL; p = save) {
889		save = p->next;
890		racoon_free(p);
891	}
892
893	return;
894}
895
896/*
897 * print multiple proposals
898 */
899void
900printsaprop(pri, pp)
901	const int pri;
902	const struct saprop *pp;
903{
904	const struct saprop *p;
905
906	if (pp == NULL) {
907		plog(pri, LOCATION, NULL, "(null)");
908		return;
909	}
910
911	for (p = pp; p; p = p->next) {
912		printsaprop0(pri, p);
913	}
914
915	return;
916}
917
918/*
919 * print one proposal.
920 */
921void
922printsaprop0(pri, pp)
923	int pri;
924	const struct saprop *pp;
925{
926	const struct saproto *p;
927
928	if (pp == NULL)
929		return;
930
931	for (p = pp->head; p; p = p->next) {
932		printsaproto(pri, p);
933	}
934
935	return;
936}
937
938void
939printsaproto(pri, pr)
940	const int pri;
941	const struct saproto *pr;
942{
943	struct satrns *tr;
944
945	if (pr == NULL)
946		return;
947
948	plog(pri, LOCATION, NULL,
949		" (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx "
950		"encmode=%s reqid=%d:%d)\n",
951		s_ipsecdoi_proto(pr->proto_id),
952		(int)pr->spisize,
953		(unsigned long)ntohl(pr->spi),
954		(unsigned long)ntohl(pr->spi_p),
955		s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode),
956		(int)pr->reqid_in, (int)pr->reqid_out);
957
958	for (tr = pr->head; tr; tr = tr->next) {
959		printsatrns(pri, pr->proto_id, tr);
960	}
961
962	return;
963}
964
965void
966printsatrns(pri, proto_id, tr)
967	const int pri;
968	const int proto_id;
969	const struct satrns *tr;
970{
971	if (tr == NULL)
972		return;
973
974	switch (proto_id) {
975	case IPSECDOI_PROTO_IPSEC_AH:
976		plog(pri, LOCATION, NULL,
977			"  (trns_id=%s authtype=%s)\n",
978			s_ipsecdoi_trns(proto_id, tr->trns_id),
979			s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
980		break;
981	case IPSECDOI_PROTO_IPSEC_ESP:
982		plog(pri, LOCATION, NULL,
983			"  (trns_id=%s encklen=%d authtype=%s)\n",
984			s_ipsecdoi_trns(proto_id, tr->trns_id),
985			tr->encklen,
986			s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
987		break;
988	case IPSECDOI_PROTO_IPCOMP:
989		plog(pri, LOCATION, NULL,
990			"  (trns_id=%s)\n",
991			s_ipsecdoi_trns(proto_id, tr->trns_id));
992		break;
993	default:
994		plog(pri, LOCATION, NULL,
995			"(unknown proto_id %d)\n", proto_id);
996	}
997
998	return;
999}
1000
1001void
1002print_proppair0(pri, p, level)
1003	int pri;
1004	struct prop_pair *p;
1005	int level;
1006{
1007	char spc[21];
1008
1009	memset(spc, ' ', sizeof(spc));
1010	spc[sizeof(spc) - 1] = '\0';
1011	if (level < 20) {
1012		spc[level] = '\0';
1013	}
1014
1015	plog(pri, LOCATION, NULL,
1016		"%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext);
1017	if (p->next)
1018		print_proppair0(pri, p->next, level + 1);
1019	if (p->tnext)
1020		print_proppair0(pri, p->tnext, level + 1);
1021}
1022
1023void
1024print_proppair(pri, p)
1025	int pri;
1026	struct prop_pair *p;
1027{
1028	print_proppair0(pri, p, 1);
1029}
1030
1031int
1032set_proposal_from_policy(iph2, sp_main, sp_sub)
1033	struct ph2handle *iph2;
1034	struct secpolicy *sp_main, *sp_sub;
1035{
1036	struct saprop *newpp;
1037	struct ipsecrequest *req;
1038	int encmodesv = IPSECDOI_ATTR_ENC_MODE_TRNS; /* use only when complex_bundle */
1039
1040	newpp = newsaprop();
1041	if (newpp == NULL) {
1042		plog(LLV_ERROR, LOCATION, NULL,
1043			"failed to allocate saprop.\n");
1044		goto err;
1045	}
1046	newpp->prop_no = 1;
1047	newpp->lifetime = iph2->sainfo->lifetime;
1048	newpp->lifebyte = iph2->sainfo->lifebyte;
1049	newpp->pfs_group = iph2->sainfo->pfs_group;
1050
1051	if (lcconf->complex_bundle)
1052		goto skip1;
1053
1054	/*
1055	 * decide the encryption mode of this SA bundle.
1056	 * the mode becomes tunnel mode when there is even one policy
1057	 * of tunnel mode in the SPD.  otherwise the mode becomes
1058	 * transport mode.
1059	 */
1060	for (req = sp_main->req; req; req = req->next) {
1061		if (req->saidx.mode == IPSEC_MODE_TUNNEL) {
1062			encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode);
1063#ifdef ENABLE_NATT
1064			if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1065				encmodesv += iph2->ph1->natt_options->mode_udp_diff;
1066#endif
1067			break;
1068		}
1069	}
1070
1071    skip1:
1072	for (req = sp_main->req; req; req = req->next) {
1073		struct saproto *newpr;
1074		caddr_t paddr = NULL;
1075
1076		/*
1077		 * check if SA bundle ?
1078		 * nested SAs negotiation is NOT supported.
1079		 *       me +--- SA1 ---+ peer1
1080		 *       me +--- SA2 --------------+ peer2
1081		 */
1082#ifdef __linux__
1083		if (req->saidx.src.ss_family && req->saidx.dst.ss_family) {
1084#else
1085		if (req->saidx.src.ss_len && req->saidx.dst.ss_len) {
1086#endif
1087			/* check the end of ip addresses of SA */
1088			if (iph2->side == INITIATOR)
1089				paddr = (caddr_t)&req->saidx.dst;
1090			else
1091				paddr = (caddr_t)&req->saidx.src;
1092		}
1093
1094		/* allocate ipsec sa protocol */
1095		newpr = newsaproto();
1096		if (newpr == NULL) {
1097			plog(LLV_ERROR, LOCATION, NULL,
1098				"failed to allocate saproto.\n");
1099			goto err;
1100		}
1101
1102		newpr->proto_id = ipproto2doi(req->saidx.proto);
1103		if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP)
1104			newpr->spisize = 2;
1105		else
1106			newpr->spisize = 4;
1107		if (lcconf->complex_bundle) {
1108			newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
1109#ifdef ENABLE_NATT
1110			if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1111				newpr->encmode +=
1112				    iph2->ph1->natt_options->mode_udp_diff;
1113#endif
1114		}
1115		else
1116			newpr->encmode = encmodesv;
1117
1118		if (iph2->side == INITIATOR)
1119			newpr->reqid_out = req->saidx.reqid;
1120		else
1121			newpr->reqid_in = req->saidx.reqid;
1122
1123		if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
1124			plog(LLV_ERROR, LOCATION, NULL,
1125				"failed to get algorithms.\n");
1126			racoon_free(newpr);
1127			goto err;
1128		}
1129
1130		/* set new saproto */
1131		inssaprotorev(newpp, newpr);
1132	}
1133
1134	/* get reqid_in from inbound policy */
1135	if (sp_sub) {
1136		struct saproto *pr;
1137
1138		req = sp_sub->req;
1139		pr = newpp->head;
1140		while (req && pr) {
1141			if (iph2->side == INITIATOR)
1142				pr->reqid_in = req->saidx.reqid;
1143			else
1144				pr->reqid_out = req->saidx.reqid;
1145			pr = pr->next;
1146			req = req->next;
1147		}
1148		if (pr || req) {
1149			plog(LLV_NOTIFY, LOCATION, NULL,
1150				"There is a difference "
1151				"between the in/out bound policies in SPD.\n");
1152		}
1153	}
1154
1155	iph2->proposal = newpp;
1156
1157	printsaprop0(LLV_DEBUG, newpp);
1158
1159	return 0;
1160err:
1161	flushsaprop(newpp);
1162	return -1;
1163}
1164
1165/*
1166 * generate a policy from peer's proposal.
1167 * this function unconditionally choices first proposal in SA payload
1168 * passed by peer.
1169 */
1170int
1171set_proposal_from_proposal(iph2)
1172	struct ph2handle *iph2;
1173{
1174        struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
1175	struct saproto *newpr = NULL, *pr;
1176	struct prop_pair **pair;
1177	int error = -1;
1178	int i;
1179
1180	/* get proposal pair */
1181	pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
1182	if (pair == NULL)
1183		goto end;
1184
1185	/*
1186	 * make my proposal according as the client proposal.
1187	 * XXX assumed there is only one proposal even if it's the SA bundle.
1188	 */
1189        for (i = 0; i < MAXPROPPAIRLEN; i++) {
1190                if (pair[i] == NULL)
1191                        continue;
1192
1193		if (pp_peer != NULL)
1194			flushsaprop(pp_peer);
1195
1196		pp_peer = aproppair2saprop(pair[i]);
1197		if (pp_peer == NULL)
1198			goto end;
1199
1200		pp0 = newsaprop();
1201		if (pp0 == NULL) {
1202			plog(LLV_ERROR, LOCATION, NULL,
1203				"failed to allocate saprop.\n");
1204			goto end;
1205		}
1206		pp0->prop_no = 1;
1207		pp0->lifetime = iph2->sainfo->lifetime;
1208		pp0->lifebyte = iph2->sainfo->lifebyte;
1209		pp0->pfs_group = iph2->sainfo->pfs_group;
1210
1211#ifdef HAVE_SECCTX
1212		if (*pp_peer->sctx.ctx_str) {
1213			pp0->sctx.ctx_doi = pp_peer->sctx.ctx_doi;
1214			pp0->sctx.ctx_alg = pp_peer->sctx.ctx_alg;
1215			pp0->sctx.ctx_strlen = pp_peer->sctx.ctx_strlen;
1216			memcpy(pp0->sctx.ctx_str, pp_peer->sctx.ctx_str,
1217			       pp_peer->sctx.ctx_strlen);
1218		}
1219#endif /* HAVE_SECCTX */
1220
1221		if (pp_peer->next != NULL) {
1222			plog(LLV_ERROR, LOCATION, NULL,
1223				"pp_peer is inconsistency, ignore it.\n");
1224			/*FALLTHROUGH*/
1225		}
1226
1227		for (pr = pp_peer->head; pr; pr = pr->next)
1228		{
1229			struct remoteconf *conf;
1230
1231			newpr = newsaproto();
1232			if (newpr == NULL)
1233			{
1234				plog(LLV_ERROR, LOCATION, NULL,
1235					"failed to allocate saproto.\n");
1236				racoon_free(pp0);
1237				goto end;
1238			}
1239			newpr->proto_id = pr->proto_id;
1240			newpr->spisize = pr->spisize;
1241			newpr->encmode = pr->encmode;
1242			newpr->spi = 0;
1243			newpr->spi_p = pr->spi;     /* copy peer's SPI */
1244			newpr->reqid_in = 0;
1245			newpr->reqid_out = 0;
1246
1247			conf = getrmconf(iph2->dst);
1248			if (conf != NULL &&
1249				conf->gen_policy == GENERATE_POLICY_UNIQUE){
1250				newpr->reqid_in = g_nextreqid ;
1251				newpr->reqid_out = g_nextreqid ++;
1252				/*
1253				 * XXX there is a (very limited)
1254				 * risk of reusing the same reqid
1255				 * as another SP entry for the same peer
1256				 */
1257				if(g_nextreqid >= IPSEC_MANUAL_REQID_MAX)
1258					g_nextreqid = 1;
1259			}else{
1260				newpr->reqid_in = 0;
1261				newpr->reqid_out = 0;
1262			}
1263
1264			if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0)
1265			{
1266				plog(LLV_ERROR, LOCATION, NULL,
1267					"failed to get algorithms.\n");
1268				racoon_free(newpr);
1269				racoon_free(pp0);
1270				goto end;
1271			}
1272			inssaproto(pp0, newpr);
1273		}
1274
1275		inssaprop(&newpp, pp0);
1276        }
1277
1278	plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n");
1279	printsaprop0(LLV_DEBUG, newpp);
1280
1281	iph2->proposal = newpp;
1282
1283	error = 0;
1284
1285end:
1286	if (error && newpp)
1287		flushsaprop(newpp);
1288
1289	if (pp_peer)
1290		flushsaprop(pp_peer);
1291	if (pair)
1292		free_proppair(pair);
1293	return error;
1294}
1295