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