Annotation of embedaddon/ipsec-tools/src/racoon/proposal.c, revision 1.1
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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>