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