]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/proposal.c
ipsec-34.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / proposal.c
1 /* $Id: proposal.c,v 1.13.8.5 2005/07/28 05:05:52 manubsd Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/queue.h>
38
39 #include <netinet/in.h>
40 #ifdef HAVE_NETINET6_IPSEC
41 # include <netinet6/ipsec.h>
42 #else
43 # include <netinet/ipsec.h>
44 #endif
45
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <errno.h>
50
51 #include "var.h"
52 #include "misc.h"
53 #include "vmbuf.h"
54 #include "plog.h"
55 #include "sockmisc.h"
56 #include "debug.h"
57
58 #include "policy.h"
59 #include "pfkey.h"
60 #include "isakmp_var.h"
61 #include "isakmp.h"
62 #include "ipsec_doi.h"
63 #include "algorithm.h"
64 #include "proposal.h"
65 #include "sainfo.h"
66 #include "localconf.h"
67 #include "remoteconf.h"
68 #include "oakley.h"
69 #include "handler.h"
70 #include "strnames.h"
71 #include "gcmalloc.h"
72 #ifdef ENABLE_NATT
73 #include "nattraversal.h"
74 #endif
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(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
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
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 *
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
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 *
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 npr1 = npr2 = 0;
315 for (pr1 = pp1->head; pr1; pr1 = pr1->next)
316 npr1++;
317 for (pr2 = pp2->head; pr2; pr2 = pr2->next)
318 npr2++;
319 if (npr1 != npr2)
320 goto err;
321
322 /* check protocol order */
323 pr1 = pp1->head;
324 pr2 = pp2->head;
325
326 while (1) {
327 if (!ordermatters) {
328 /*
329 * XXX does not work if we have multiple proposals
330 * with the same proto_id
331 */
332 switch (side) {
333 case RESPONDER:
334 if (!pr2)
335 break;
336 for (pr1 = pp1->head; pr1; pr1 = pr1->next) {
337 if (pr1->proto_id == pr2->proto_id)
338 break;
339 }
340 break;
341 case INITIATOR:
342 if (!pr1)
343 break;
344 for (pr2 = pp2->head; pr2; pr2 = pr2->next) {
345 if (pr2->proto_id == pr1->proto_id)
346 break;
347 }
348 break;
349 }
350 }
351 if (!pr1 || !pr2)
352 break;
353
354 if (pr1->proto_id != pr2->proto_id) {
355 plog(LLV_ERROR, LOCATION, NULL,
356 "proto_id mismatched: "
357 "my:%s peer:%s\n",
358 s_ipsecdoi_proto(pr2->proto_id),
359 s_ipsecdoi_proto(pr1->proto_id));
360 goto err;
361 }
362 spisizematch = 0;
363 if (pr1->spisize == pr2->spisize)
364 spisizematch = 1;
365 else if (pr1->proto_id == IPSECDOI_PROTO_IPCOMP) {
366 /*
367 * draft-shacham-ippcp-rfc2393bis-05.txt:
368 * need to accept 16bit and 32bit SPI (CPI) for IPComp.
369 */
370 if (pr1->spisize == sizeof(u_int16_t) &&
371 pr2->spisize == sizeof(u_int32_t)) {
372 spisizematch = 1;
373 } else if (pr2->spisize == sizeof(u_int16_t) &&
374 pr1->spisize == sizeof(u_int32_t)) {
375 spisizematch = 1;
376 }
377 if (spisizematch) {
378 plog(LLV_ERROR, LOCATION, NULL,
379 "IPComp SPI size promoted "
380 "from 16bit to 32bit\n");
381 }
382 }
383 if (!spisizematch) {
384 plog(LLV_ERROR, LOCATION, NULL,
385 "spisize mismatched: "
386 "my:%d peer:%d\n",
387 (int)pr2->spisize, (int)pr1->spisize);
388 goto err;
389 }
390
391 #ifdef ENABLE_NATT
392 if ((ph1->natt_flags & NAT_DETECTED) &&
393 natt_udp_encap (pr2->encmode))
394 {
395 plog(LLV_INFO, LOCATION, NULL, "Adjusting my encmode %s->%s\n",
396 s_ipsecdoi_encmode(pr2->encmode),
397 s_ipsecdoi_encmode(pr2->encmode - ph1->natt_options->mode_udp_diff));
398 pr2->encmode -= ph1->natt_options->mode_udp_diff;
399 pr2->udp_encap = 1;
400 }
401
402 if ((ph1->natt_flags & NAT_DETECTED) &&
403 natt_udp_encap (pr1->encmode))
404 {
405 plog(LLV_INFO, LOCATION, NULL, "Adjusting peer's encmode %s(%d)->%s(%d)\n",
406 s_ipsecdoi_encmode(pr1->encmode),
407 pr1->encmode,
408 s_ipsecdoi_encmode(pr1->encmode - ph1->natt_options->mode_udp_diff),
409 pr1->encmode - ph1->natt_options->mode_udp_diff);
410 pr1->encmode -= ph1->natt_options->mode_udp_diff;
411 pr1->udp_encap = 1;
412 }
413 #endif
414
415 if (pr1->encmode != pr2->encmode) {
416 plog(LLV_ERROR, LOCATION, NULL,
417 "encmode mismatched: "
418 "my:%s peer:%s\n",
419 s_ipsecdoi_encmode(pr2->encmode),
420 s_ipsecdoi_encmode(pr1->encmode));
421 goto err;
422 }
423
424 for (tr1 = pr1->head; tr1; tr1 = tr1->next) {
425 for (tr2 = pr2->head; tr2; tr2 = tr2->next) {
426 if (cmpsatrns(pr1->proto_id, tr1, tr2) == 0)
427 goto found;
428 }
429 }
430
431 goto err;
432
433 found:
434 newpr = newsaproto();
435 if (newpr == NULL) {
436 plog(LLV_ERROR, LOCATION, NULL,
437 "failed to allocate saproto.\n");
438 goto err;
439 }
440 newpr->proto_id = pr1->proto_id;
441 newpr->spisize = pr1->spisize;
442 newpr->encmode = pr1->encmode;
443 newpr->spi = pr2->spi; /* copy my SPI */
444 newpr->spi_p = pr1->spi; /* copy peer's SPI */
445 newpr->reqid_in = pr2->reqid_in;
446 newpr->reqid_out = pr2->reqid_out;
447 #ifdef ENABLE_NATT
448 newpr->udp_encap = pr1->udp_encap | pr2->udp_encap;
449 #endif
450
451 newtr = newsatrns();
452 if (newtr == NULL) {
453 plog(LLV_ERROR, LOCATION, NULL,
454 "failed to allocate satrns.\n");
455 goto err;
456 }
457 newtr->trns_no = tr1->trns_no;
458 newtr->trns_id = tr1->trns_id;
459 newtr->encklen = tr1->encklen;
460 newtr->authtype = tr1->authtype;
461
462 inssatrns(newpr, newtr);
463 inssaproto(newpp, newpr);
464
465 pr1 = pr1->next;
466 pr2 = pr2->next;
467 }
468
469 /* XXX should check if we have visited all items or not */
470 if (!ordermatters) {
471 switch (side) {
472 case RESPONDER:
473 if (!pr2)
474 pr1 = NULL;
475 break;
476 case INITIATOR:
477 if (!pr1)
478 pr2 = NULL;
479 break;
480 }
481 }
482
483 /* should be matched all protocols in a proposal */
484 if (pr1 != NULL || pr2 != NULL)
485 goto err;
486
487 return newpp;
488
489 err:
490 flushsaprop(newpp);
491 return NULL;
492 }
493
494 /* take a single match between saprop. returns 0 if pp1 equals to pp2. */
495 int
496 cmpsaprop(pp1, pp2)
497 const struct saprop *pp1, *pp2;
498 {
499 if (pp1->pfs_group != pp2->pfs_group) {
500 plog(LLV_WARNING, LOCATION, NULL,
501 "pfs_group mismatch. mine:%d peer:%d\n",
502 pp1->pfs_group, pp2->pfs_group);
503 /* FALLTHRU */
504 }
505
506 if (pp1->lifetime > pp2->lifetime) {
507 plog(LLV_WARNING, LOCATION, NULL,
508 "less lifetime proposed. mine:%d peer:%d\n",
509 (int)pp1->lifetime, (int)pp2->lifetime);
510 /* FALLTHRU */
511 }
512 if (pp1->lifebyte > pp2->lifebyte) {
513 plog(LLV_WARNING, LOCATION, NULL,
514 "less lifebyte proposed. mine:%d peer:%d\n",
515 pp1->lifebyte, pp2->lifebyte);
516 /* FALLTHRU */
517 }
518
519 return 0;
520 }
521
522 /*
523 * take a single match between satrns. returns 0 if tr1 equals to tr2.
524 * tr1: peer's satrns
525 * tr2: my satrns
526 */
527 int
528 cmpsatrns(proto_id, tr1, tr2)
529 int proto_id;
530 const struct satrns *tr1, *tr2;
531 {
532 if (tr1->trns_id != tr2->trns_id) {
533 plog(LLV_WARNING, LOCATION, NULL,
534 "trns_id mismatched: "
535 "my:%s peer:%s\n",
536 s_ipsecdoi_trns(proto_id, tr2->trns_id),
537 s_ipsecdoi_trns(proto_id, tr1->trns_id));
538 return 1;
539 }
540
541 if (tr1->authtype != tr2->authtype) {
542 plog(LLV_WARNING, LOCATION, NULL,
543 "authtype mismatched: "
544 "my:%s peer:%s\n",
545 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr2->authtype),
546 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr1->authtype));
547 return 1;
548 }
549
550 /* XXX
551 * At this moment for interoperability, the responder obey
552 * the initiator. It should be defined a notify message.
553 */
554 if (tr1->encklen > tr2->encklen) {
555 plog(LLV_WARNING, LOCATION, NULL,
556 "less key length proposed, "
557 "mine:%d peer:%d. Use initiaotr's one.\n",
558 tr2->encklen, tr1->encklen);
559 /* FALLTHRU */
560 }
561
562 return 0;
563 }
564
565 int
566 set_satrnsbysainfo(pr, sainfo)
567 struct saproto *pr;
568 struct sainfo *sainfo;
569 {
570 struct sainfoalg *a, *b;
571 struct satrns *newtr;
572 int t;
573
574 switch (pr->proto_id) {
575 case IPSECDOI_PROTO_IPSEC_AH:
576 if (sainfo->algs[algclass_ipsec_auth] == NULL) {
577 plog(LLV_ERROR, LOCATION, NULL,
578 "no auth algorithm found\n");
579 goto err;
580 }
581 t = 1;
582 for (a = sainfo->algs[algclass_ipsec_auth]; a; a = a->next) {
583
584 if (a->alg == IPSECDOI_ATTR_AUTH_NONE)
585 continue;
586
587 /* allocate satrns */
588 newtr = newsatrns();
589 if (newtr == NULL) {
590 plog(LLV_ERROR, LOCATION, NULL,
591 "failed to allocate satrns.\n");
592 goto err;
593 }
594
595 newtr->trns_no = t++;
596 newtr->trns_id = ipsecdoi_authalg2trnsid(a->alg);
597 newtr->authtype = a->alg;
598
599 inssatrns(pr, newtr);
600 }
601 break;
602 case IPSECDOI_PROTO_IPSEC_ESP:
603 if (sainfo->algs[algclass_ipsec_enc] == NULL) {
604 plog(LLV_ERROR, LOCATION, NULL,
605 "no encryption algorithm found\n");
606 goto err;
607 }
608 t = 1;
609 for (a = sainfo->algs[algclass_ipsec_enc]; a; a = a->next) {
610 for (b = sainfo->algs[algclass_ipsec_auth]; b; b = b->next) {
611 /* allocate satrns */
612 newtr = newsatrns();
613 if (newtr == NULL) {
614 plog(LLV_ERROR, LOCATION, NULL,
615 "failed to allocate satrns.\n");
616 goto err;
617 }
618
619 newtr->trns_no = t++;
620 newtr->trns_id = a->alg;
621 newtr->encklen = a->encklen;
622 newtr->authtype = b->alg;
623
624 inssatrns(pr, newtr);
625 }
626 }
627 break;
628 case IPSECDOI_PROTO_IPCOMP:
629 if (sainfo->algs[algclass_ipsec_comp] == NULL) {
630 plog(LLV_ERROR, LOCATION, NULL,
631 "no ipcomp algorithm found\n");
632 goto err;
633 }
634 t = 1;
635 for (a = sainfo->algs[algclass_ipsec_comp]; a; a = a->next) {
636
637 /* allocate satrns */
638 newtr = newsatrns();
639 if (newtr == NULL) {
640 plog(LLV_ERROR, LOCATION, NULL,
641 "failed to allocate satrns.\n");
642 goto err;
643 }
644
645 newtr->trns_no = t++;
646 newtr->trns_id = a->alg;
647 newtr->authtype = IPSECDOI_ATTR_AUTH_NONE; /*no auth*/
648
649 inssatrns(pr, newtr);
650 }
651 break;
652 default:
653 plog(LLV_ERROR, LOCATION, NULL,
654 "unknown proto_id (%d).\n", pr->proto_id);
655 goto err;
656 }
657
658 /* no proposal found */
659 if (pr->head == NULL) {
660 plog(LLV_ERROR, LOCATION, NULL, "no algorithms found.\n");
661 return -1;
662 }
663
664 return 0;
665
666 err:
667 flushsatrns(pr->head);
668 return -1;
669 }
670
671 struct saprop *
672 aproppair2saprop(p0)
673 struct prop_pair *p0;
674 {
675 struct prop_pair *p, *t;
676 struct saprop *newpp;
677 struct saproto *newpr;
678 struct satrns *newtr;
679 u_int8_t *spi;
680
681 if (p0 == NULL)
682 return NULL;
683
684 /* allocate ipsec a sa proposal */
685 newpp = newsaprop();
686 if (newpp == NULL) {
687 plog(LLV_ERROR, LOCATION, NULL,
688 "failed to allocate saprop.\n");
689 return NULL;
690 }
691 newpp->prop_no = p0->prop->p_no;
692 /* lifetime & lifebyte must be updated later */
693
694 for (p = p0; p; p = p->next) {
695
696 /* allocate ipsec sa protocol */
697 newpr = newsaproto();
698 if (newpr == NULL) {
699 plog(LLV_ERROR, LOCATION, NULL,
700 "failed to allocate saproto.\n");
701 goto err;
702 }
703
704 /* check spi size */
705 /* XXX should be handled isakmp cookie */
706 if (sizeof(newpr->spi) < p->prop->spi_size) {
707 plog(LLV_ERROR, LOCATION, NULL,
708 "invalid spi size %d.\n", p->prop->spi_size);
709 goto err;
710 }
711
712 /*
713 * XXX SPI bits are left-filled, for use with IPComp.
714 * we should be switching to variable-length spi field...
715 */
716 newpr->proto_id = p->prop->proto_id;
717 newpr->spisize = p->prop->spi_size;
718 memset(&newpr->spi, 0, sizeof(newpr->spi));
719 spi = (u_int8_t *)&newpr->spi;
720 spi += sizeof(newpr->spi);
721 spi -= p->prop->spi_size;
722 memcpy(spi, p->prop + 1, p->prop->spi_size);
723 newpr->reqid_in = 0;
724 newpr->reqid_out = 0;
725
726 for (t = p; t; t = t->tnext) {
727
728 plog(LLV_DEBUG, LOCATION, NULL,
729 "prop#=%d prot-id=%s spi-size=%d "
730 "#trns=%d trns#=%d trns-id=%s\n",
731 t->prop->p_no,
732 s_ipsecdoi_proto(t->prop->proto_id),
733 t->prop->spi_size, t->prop->num_t,
734 t->trns->t_no,
735 s_ipsecdoi_trns(t->prop->proto_id,
736 t->trns->t_id));
737
738 /* allocate ipsec sa transform */
739 newtr = newsatrns();
740 if (newtr == NULL) {
741 plog(LLV_ERROR, LOCATION, NULL,
742 "failed to allocate satrns.\n");
743 goto err;
744 }
745
746 if (ipsecdoi_t2satrns(t->trns, newpp, newpr, newtr) < 0) {
747 flushsaprop(newpp);
748 return NULL;
749 }
750
751 inssatrns(newpr, newtr);
752 }
753
754 /*
755 * If the peer does not specify encryption mode, use
756 * transport mode by default. This is to conform to
757 * draft-shacham-ippcp-rfc2393bis-08.txt (explicitly specifies
758 * that unspecified == transport), as well as RFC2407
759 * (unspecified == implementation dependent default).
760 */
761 if (newpr->encmode == 0)
762 newpr->encmode = IPSECDOI_ATTR_ENC_MODE_TRNS;
763
764 inssaproto(newpp, newpr);
765 }
766
767 return newpp;
768
769 err:
770 flushsaprop(newpp);
771 return NULL;
772 }
773
774 void
775 flushsaprop(head)
776 struct saprop *head;
777 {
778 struct saprop *p, *save;
779
780 for (p = head; p != NULL; p = save) {
781 save = p->next;
782 flushsaproto(p->head);
783 racoon_free(p);
784 }
785
786 return;
787 }
788
789 void
790 flushsaproto(head)
791 struct saproto *head;
792 {
793 struct saproto *p, *save;
794
795 for (p = head; p != NULL; p = save) {
796 save = p->next;
797 flushsatrns(p->head);
798 vfree(p->keymat);
799 vfree(p->keymat_p);
800 racoon_free(p);
801 }
802
803 return;
804 }
805
806 void
807 flushsatrns(head)
808 struct satrns *head;
809 {
810 struct satrns *p, *save;
811
812 for (p = head; p != NULL; p = save) {
813 save = p->next;
814 racoon_free(p);
815 }
816
817 return;
818 }
819
820 /*
821 * print multiple proposals
822 */
823 void
824 printsaprop(pri, pp)
825 const int pri;
826 const struct saprop *pp;
827 {
828 const struct saprop *p;
829
830 if (pp == NULL) {
831 plog(pri, LOCATION, NULL, "(null)");
832 return;
833 }
834
835 for (p = pp; p; p = p->next) {
836 printsaprop0(pri, p);
837 }
838
839 return;
840 }
841
842 /*
843 * print one proposal.
844 */
845 void
846 printsaprop0(pri, pp)
847 int pri;
848 const struct saprop *pp;
849 {
850 const struct saproto *p;
851
852 if (pp == NULL)
853 return;
854
855 for (p = pp->head; p; p = p->next) {
856 printsaproto(pri, p);
857 }
858
859 return;
860 }
861
862 void
863 printsaproto(pri, pr)
864 const int pri;
865 const struct saproto *pr;
866 {
867 struct satrns *tr;
868
869 if (pr == NULL)
870 return;
871
872 plog(pri, LOCATION, NULL,
873 " (proto_id=%s spisize=%d spi=%08lx spi_p=%08lx "
874 "encmode=%s reqid=%d:%d)\n",
875 s_ipsecdoi_proto(pr->proto_id),
876 (int)pr->spisize,
877 (unsigned long)ntohl(pr->spi),
878 (unsigned long)ntohl(pr->spi_p),
879 s_ipsecdoi_attr_v(IPSECDOI_ATTR_ENC_MODE, pr->encmode),
880 (int)pr->reqid_in, (int)pr->reqid_out);
881
882 for (tr = pr->head; tr; tr = tr->next) {
883 printsatrns(pri, pr->proto_id, tr);
884 }
885
886 return;
887 }
888
889 void
890 printsatrns(pri, proto_id, tr)
891 const int pri;
892 const int proto_id;
893 const struct satrns *tr;
894 {
895 if (tr == NULL)
896 return;
897
898 switch (proto_id) {
899 case IPSECDOI_PROTO_IPSEC_AH:
900 plog(pri, LOCATION, NULL,
901 " (trns_id=%s authtype=%s)\n",
902 s_ipsecdoi_trns(proto_id, tr->trns_id),
903 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
904 break;
905 case IPSECDOI_PROTO_IPSEC_ESP:
906 plog(pri, LOCATION, NULL,
907 " (trns_id=%s encklen=%d authtype=%s)\n",
908 s_ipsecdoi_trns(proto_id, tr->trns_id),
909 tr->encklen,
910 s_ipsecdoi_attr_v(IPSECDOI_ATTR_AUTH, tr->authtype));
911 break;
912 case IPSECDOI_PROTO_IPCOMP:
913 plog(pri, LOCATION, NULL,
914 " (trns_id=%s)\n",
915 s_ipsecdoi_trns(proto_id, tr->trns_id));
916 break;
917 default:
918 plog(pri, LOCATION, NULL,
919 "(unknown proto_id %d)\n", proto_id);
920 }
921
922 return;
923 }
924
925 void
926 print_proppair0(pri, p, level)
927 int pri;
928 struct prop_pair *p;
929 int level;
930 {
931 char spc[21];
932
933 memset(spc, ' ', sizeof(spc));
934 spc[sizeof(spc) - 1] = '\0';
935 if (level < 20) {
936 spc[level] = '\0';
937 }
938
939 plog(pri, LOCATION, NULL,
940 "%s%p: next=%p tnext=%p\n", spc, p, p->next, p->tnext);
941 if (p->next)
942 print_proppair0(pri, p->next, level + 1);
943 if (p->tnext)
944 print_proppair0(pri, p->tnext, level + 1);
945 }
946
947 void
948 print_proppair(pri, p)
949 int pri;
950 struct prop_pair *p;
951 {
952 print_proppair0(pri, p, 1);
953 }
954
955 int
956 set_proposal_from_policy(iph2, sp_main, sp_sub)
957 struct ph2handle *iph2;
958 struct secpolicy *sp_main, *sp_sub;
959 {
960 struct saprop *newpp;
961 struct ipsecrequest *req;
962 int encmodesv = IPSEC_MODE_TRANSPORT; /* use only when complex_bundle */
963
964 newpp = newsaprop();
965 if (newpp == NULL) {
966 plog(LLV_ERROR, LOCATION, NULL,
967 "failed to allocate saprop.\n");
968 goto err;
969 }
970 newpp->prop_no = 1;
971 newpp->lifetime = iph2->sainfo->lifetime;
972 newpp->lifebyte = iph2->sainfo->lifebyte;
973 newpp->pfs_group = iph2->sainfo->pfs_group;
974
975 if (lcconf->complex_bundle)
976 goto skip1;
977
978 /*
979 * decide the encryption mode of this SA bundle.
980 * the mode becomes tunnel mode when there is even one policy
981 * of tunnel mode in the SPD. otherwise the mode becomes
982 * transport mode.
983 */
984 encmodesv = IPSEC_MODE_TRANSPORT;
985 for (req = sp_main->req; req; req = req->next) {
986 if (req->saidx.mode == IPSEC_MODE_TUNNEL) {
987 encmodesv = pfkey2ipsecdoi_mode(req->saidx.mode);
988 #ifdef ENABLE_NATT
989 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
990 encmodesv += iph2->ph1->natt_options->mode_udp_diff;
991 #endif
992 break;
993 }
994 }
995
996 skip1:
997 for (req = sp_main->req; req; req = req->next) {
998 struct saproto *newpr;
999 caddr_t paddr = NULL;
1000
1001 /*
1002 * check if SA bundle ?
1003 * nested SAs negotiation is NOT supported.
1004 * me +--- SA1 ---+ peer1
1005 * me +--- SA2 --------------+ peer2
1006 */
1007 #ifdef __linux__
1008 if (req->saidx.src.ss_family && req->saidx.dst.ss_family) {
1009 #else
1010 if (req->saidx.src.ss_len && req->saidx.dst.ss_len) {
1011 #endif
1012 /* check the end of ip addresses of SA */
1013 if (iph2->side == INITIATOR)
1014 paddr = (caddr_t)&req->saidx.dst;
1015 else
1016 paddr = (caddr_t)&req->saidx.src;
1017 }
1018
1019 /* allocate ipsec sa protocol */
1020 newpr = newsaproto();
1021 if (newpr == NULL) {
1022 plog(LLV_ERROR, LOCATION, NULL,
1023 "failed to allocate saproto.\n");
1024 goto err;
1025 }
1026
1027 newpr->proto_id = ipproto2doi(req->saidx.proto);
1028 if (newpr->proto_id == IPSECDOI_PROTO_IPCOMP)
1029 newpr->spisize = 2;
1030 else
1031 newpr->spisize = 4;
1032 if (lcconf->complex_bundle) {
1033 newpr->encmode = pfkey2ipsecdoi_mode(req->saidx.mode);
1034 #ifdef ENABLE_NATT
1035 if (iph2->ph1 && (iph2->ph1->natt_flags & NAT_DETECTED))
1036 newpr->encmode += iph2->ph1->natt_options->mode_udp_diff;
1037 #endif
1038 }
1039 else
1040 newpr->encmode = encmodesv;
1041
1042 if (iph2->side == INITIATOR)
1043 newpr->reqid_out = req->saidx.reqid;
1044 else
1045 newpr->reqid_in = req->saidx.reqid;
1046
1047 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
1048 plog(LLV_ERROR, LOCATION, NULL,
1049 "failed to get algorithms.\n");
1050 goto err;
1051 }
1052
1053 /* set new saproto */
1054 inssaprotorev(newpp, newpr);
1055 }
1056
1057 /* get reqid_in from inbound policy */
1058 if (sp_sub) {
1059 struct saproto *pr;
1060
1061 req = sp_sub->req;
1062 pr = newpp->head;
1063 while (req && pr) {
1064 if (iph2->side == INITIATOR)
1065 pr->reqid_in = req->saidx.reqid;
1066 else
1067 pr->reqid_out = req->saidx.reqid;
1068 pr = pr->next;
1069 req = req->next;
1070 }
1071 if (pr || req) {
1072 plog(LLV_NOTIFY, LOCATION, NULL,
1073 "There is a difference "
1074 "between the in/out bound policies in SPD.\n");
1075 }
1076 }
1077
1078 iph2->proposal = newpp;
1079
1080 printsaprop0(LLV_DEBUG, newpp);
1081
1082 return 0;
1083 err:
1084 return -1;
1085 }
1086
1087 /*
1088 * generate a policy from peer's proposal.
1089 * this function unconditionally chooses the first proposal the in SA payload
1090 * passed by peer.
1091 */
1092 int
1093 set_proposal_from_proposal(iph2)
1094 struct ph2handle *iph2;
1095 {
1096 struct saprop *newpp = NULL, *pp0, *pp_peer = NULL;
1097 struct saproto *newpr = NULL, *pr;
1098 struct prop_pair **pair;
1099 int error = -1;
1100 int i;
1101
1102 /* get proposal pair */
1103 pair = get_proppair(iph2->sa, IPSECDOI_TYPE_PH2);
1104 if (pair == NULL)
1105 goto end;
1106
1107 /*
1108 * make my proposal according as the client proposal.
1109 * XXX assumed there is only one proposal even if it's the SA bundle.
1110 */
1111 for (i = 0; i < MAXPROPPAIRLEN; i++) {
1112 if (pair[i] == NULL)
1113 continue;
1114 pp_peer = aproppair2saprop(pair[i]);
1115 if (pp_peer == NULL)
1116 goto end;
1117
1118 pp0 = newsaprop();
1119 if (pp0 == NULL) {
1120 plog(LLV_ERROR, LOCATION, NULL,
1121 "failed to allocate saprop.\n");
1122 goto end;
1123 }
1124 pp0->prop_no = 1;
1125 pp0->lifetime = iph2->sainfo->lifetime;
1126 pp0->lifebyte = iph2->sainfo->lifebyte;
1127 pp0->pfs_group = iph2->sainfo->pfs_group;
1128
1129 if (pp_peer->next != NULL) {
1130 plog(LLV_ERROR, LOCATION, NULL,
1131 "pp_peer is inconsistency, ignore it.\n");
1132 /*FALLTHROUGH*/
1133 }
1134
1135 for (pr = pp_peer->head; pr; pr = pr->next) {
1136
1137 newpr = newsaproto();
1138 if (newpr == NULL) {
1139 plog(LLV_ERROR, LOCATION, NULL,
1140 "failed to allocate saproto.\n");
1141 goto end;
1142 }
1143 newpr->proto_id = pr->proto_id;
1144 newpr->spisize = pr->spisize;
1145 newpr->encmode = pr->encmode;
1146 newpr->spi = 0;
1147 newpr->spi_p = pr->spi; /* copy peer's SPI */
1148 newpr->reqid_in = 0;
1149 newpr->reqid_out = 0;
1150 }
1151
1152 if (set_satrnsbysainfo(newpr, iph2->sainfo) < 0) {
1153 plog(LLV_ERROR, LOCATION, NULL,
1154 "failed to get algorithms.\n");
1155 goto end;
1156 }
1157
1158 inssaproto(pp0, newpr);
1159 inssaprop(&newpp, pp0);
1160 }
1161
1162 plog(LLV_DEBUG, LOCATION, NULL, "make a proposal from peer's:\n");
1163 printsaprop0(LLV_DEBUG, newpp);
1164
1165 iph2->proposal = newpp;
1166
1167 error = 0;
1168
1169 end:
1170 if (error && newpp)
1171 flushsaprop(newpp);
1172
1173 if (pp_peer)
1174 flushsaprop(pp_peer);
1175 free_proppair(pair);
1176 return error;
1177 }
1178
1179 int
1180 tunnel_mode_prop(p)
1181 struct saprop *p;
1182 {
1183 struct saproto *pr;
1184
1185 for (pr = p->head; pr; pr = pr->next)
1186 if (pr->encmode == IPSECDOI_ATTR_ENC_MODE_TUNNEL)
1187 return 1;
1188 return 0;
1189 }