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