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