• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
74 static uint g_nextreqid = 1;
75 
76 /* %%%
77  * modules for ipsec sa spec
78  */
79 struct saprop *
newsaprop()80 newsaprop()
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 
91 struct saproto *
newsaproto()92 newsaproto()
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 */
104 void
inssaprop(head,new)105 inssaprop(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 */
124 void
inssaproto(pp,new)125 inssaproto(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 */
142 void
inssaprotorev(pp,new)143 inssaprotorev(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 
153 struct satrns *
newsatrns()154 newsatrns()
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 */
166 void
inssatrns(pr,new)167 inssatrns(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  */
193 struct saprop *
cmpsaprop_alloc(ph1,pp1,pp2,side)194 cmpsaprop_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 
541 err:
542 	flushsaprop(newpp);
543 	return NULL;
544 }
545 
546 /* take a single match between saprop.  returns 0 if pp1 equals to pp2. */
547 int
cmpsaprop(pp1,pp2)548 cmpsaprop(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  */
579 int
cmpsatrns(proto_id,tr1,tr2,check_level)580 cmpsatrns(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 
636 int
set_satrnsbysainfo(pr,sainfo)637 set_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 
737 err:
738 	flushsatrns(pr->head);
739 	return -1;
740 }
741 
742 struct saprop *
aproppair2saprop(p0)743 aproppair2saprop(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 
845 err:
846 	flushsaprop(newpp);
847 	return NULL;
848 }
849 
850 void
flushsaprop(head)851 flushsaprop(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 
865 void
flushsaproto(head)866 flushsaproto(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 
882 void
flushsatrns(head)883 flushsatrns(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  */
899 void
printsaprop(pri,pp)900 printsaprop(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  */
921 void
printsaprop0(pri,pp)922 printsaprop0(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 
938 void
printsaproto(pri,pr)939 printsaproto(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 
965 void
printsatrns(pri,proto_id,tr)966 printsatrns(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 
1001 void
print_proppair0(pri,p,level)1002 print_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 
1023 void
print_proppair(pri,p)1024 print_proppair(pri, p)
1025 	int pri;
1026 	struct prop_pair *p;
1027 {
1028 	print_proppair0(pri, p, 1);
1029 }
1030 
1031 int
set_proposal_from_policy(iph2,sp_main,sp_sub)1032 set_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;
1160 err:
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  */
1170 int
set_proposal_from_proposal(iph2)1171 set_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 
1285 end:
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