void pluto_do_crypto_op(struct pluto_crypto_req *r, int helpernum) { DBG(DBG_CONTROL , DBG_log("helper %d doing %s op id: %u" , helpernum , enum_show(&pluto_cryptoop_names, r->pcr_type) , r->pcr_id)); #else void pluto_do_crypto_op(struct pluto_crypto_req *r) { DBG(DBG_CONTROL , DBG_log("helper %d doing %s op id: %u" , pc_helper_num , enum_show(&pluto_cryptoop_names, r->pcr_type) , r->pcr_id)); #endif #ifdef DEBUG { char *d = getenv("PLUTO_CRYPTO_HELPER_DELAY"); if(d != NULL) { int delay=atoi(d); DBG_log("helper is pausing for %d seconds", delay); sleep(delay); } } #endif /* now we have the entire request in the buffer, process it */ switch(r->pcr_type) { case pcr_build_kenonce: calc_ke(r); calc_nonce(r); break; case pcr_build_nonce: calc_nonce(r); break; case pcr_compute_dh_iv: calc_dh_iv(r); break; case pcr_compute_dh: calc_dh(r); break; case pcr_compute_dh_v2: calc_dh_v2(r); break; case pcr_rsa_sign: case pcr_rsa_check: case pcr_x509cert_fetch: case pcr_x509crl_fetch: break; } }
static void pluto_do_crypto_op(struct pluto_crypto_req *r, int helpernum) { struct timeval tv0; gettimeofday(&tv0, NULL); const char *story = NULL; DBG(DBG_CONTROL, DBG_log("crypto helper %d doing %s; request ID %u", helpernum, enum_show(&pluto_cryptoop_names, r->pcr_type), r->pcr_id)); if (crypto_helper_delay > 0) { DBG_log("crypto helper is pausing for %u seconds", crypto_helper_delay); sleep(crypto_helper_delay); } /* now we have the entire request in the buffer, process it */ switch (r->pcr_type) { case pcr_build_ke_and_nonce: calc_ke(r); /* FALL THROUGH */ case pcr_build_nonce: calc_nonce(r); break; case pcr_compute_dh_iv: calc_dh_iv(r); break; case pcr_compute_dh: calc_dh(r); break; case pcr_compute_dh_v2: calc_dh_v2(r, &story); break; } DBG(DBG_CONTROL, { struct timeval tv1; unsigned long tv_diff; gettimeofday(&tv1, NULL); tv_diff = (tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec); DBG_log("crypto helper %d finished %s%s; request ID %u time elapsed %ld usec", helpernum, enum_show(&pluto_cryptoop_names, r->pcr_type), (story != NULL) ? story : "", r->pcr_id, tv_diff)); } }
/* send the request, make sure it all goes down. */ static bool crypto_write_request(struct pluto_crypto_worker *w ,struct pluto_crypto_req *r) { unsigned char *wdat = (unsigned char *)r; int wlen = r->pcr_len; int cnt; DBG(DBG_CONTROL , DBG_log("asking helper %d to do %s op on seq: %u (len=%u, pcw_work=%d)" , w->pcw_helpernum , enum_show(&pluto_cryptoop_names, r->pcr_type) , r->pcr_id, (unsigned int)r->pcr_len, w->pcw_work+1)); do { errno=0; cnt = write(w->pcw_pipe, wdat, wlen); if(cnt <= 0) { openswan_log("write to helper failed: cnt=%d err=%s\n", cnt, strerror(errno)); return FALSE; } if(DBGP(DBG_CONTROL) || cnt != wlen) { DBG_log("crypto helper write of request: cnt=%d<wlen=%d. \n", cnt, wlen); } wlen -= cnt; wdat += cnt; } while(wlen > 0); return TRUE; }
/** Compute DH shared secret from our local secret and the peer's public value. * We make the leap that the length should be that of the group * (see quoted passage at start of ACCEPT_KE). */ static void calc_dh_shared(chunk_t *shared, const chunk_t g , const MP_INT *sec , const struct oakley_group_desc *group) { MP_INT mp_g, mp_shared; struct timeval tv0, tv1; unsigned long tv_diff; gettimeofday(&tv0, NULL); n_to_mpz(&mp_g, g.ptr, g.len); mpz_init(&mp_shared); mpz_powm(&mp_shared, &mp_g, sec, group->modulus); mpz_clear(&mp_g); *shared = mpz_to_n(&mp_shared, group->bytes); mpz_clear(&mp_shared); gettimeofday(&tv1, NULL); tv_diff=(tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec); DBG(DBG_CRYPT, DBG_log("calc_dh_shared(): time elapsed (%s): %ld usec" , enum_show(&oakley_group_names, group->group) , tv_diff); );
/* * This routine places an event in the event list. */ void event_schedule(enum event_type type, time_t tm, struct state *st) { struct event *ev = alloc_thing(struct event, "struct event in event_schedule()"); passert(tm >= 0); ev->ev_type = type; ev->ev_time = tm + now(); ev->ev_state = st; /* If the event is associated with a state, put a backpointer to the * event in the state object, so we can find and delete the event * if we need to (for example, if we receive a reply). */ if (st != NULL) { if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) { passert(st->st_dpd_event == NULL); st->st_dpd_event = ev; } else if (type == EVENT_v2_LIVENESS) { passert(st->st_liveness_event == NULL); st->st_liveness_event = ev; } else { passert(st->st_event == NULL); st->st_event = ev; } } DBG(DBG_CONTROL, { if (st == NULL) { DBG_log( "inserting event %s, timeout in %lu seconds", enum_show(&timer_event_names, type), (unsigned long)tm); } else { DBG_log( "inserting event %s, timeout in %lu seconds for #%lu", enum_show(&timer_event_names, type), (unsigned long)tm, ev->ev_state->st_serialno); } });
void ikev2_decode_cert(struct msg_digest *md) { struct payload_digest *p; for (p = md->chain[ISAKMP_NEXT_v2CERT]; p != NULL; p = p->next) { struct ikev2_cert *const v2cert = &p->payload.v2cert; chunk_t blob; time_t valid_until; blob.ptr = p->pbs.cur; blob.len = pbs_left(&p->pbs); if (v2cert->isac_enc == CERT_X509_SIGNATURE) { x509cert_t cert2 = empty_x509cert; if (parse_x509cert(blob, 0, &cert2)) { if (verify_x509cert(&cert2, strict_crl_policy, &valid_until)) { DBG(DBG_X509 | DBG_PARSING, DBG_log("Public key validated") ) add_x509_public_key(NULL, &cert2, valid_until, DAL_SIGNED); } else { plog("X.509 certificate rejected"); } free_generalNames(cert2.subjectAltName, FALSE); free_generalNames(cert2.crlDistributionPoints, FALSE); } else plog("Syntax error in X.509 certificate"); } else if (v2cert->isac_enc == CERT_PKCS7_WRAPPED_X509) { x509cert_t *cert2 = NULL; if (parse_pkcs7_cert(blob, &cert2)) store_x509certs(&cert2, strict_crl_policy); else plog("Syntax error in PKCS#7 wrapped X.509 certificates"); } else { loglog(RC_LOG_SERIOUS, "ignoring %s certificate payload", enum_show(&ikev2_cert_type_names, v2cert->isac_enc)); DBG_cond_dump_chunk(DBG_PARSING, "CERT:\n", blob); } } }
/* * Show IKE algorithms for * - this connection (result from ike= string) * - newest SA */ void ike_alg_show_connection(struct connection *c, const char *instance) { char buf[256]; struct state *st; if (c->alg_info_ike) { alg_info_snprint(buf, sizeof(buf), (struct alg_info *)c->alg_info_ike); whack_log(RC_COMMENT , "\"%s\"%s: IKE algorithms wanted: %s" , c->name , instance , buf); } if (c->alg_info_ike) { alg_info_snprint_ike(buf, sizeof(buf), c->alg_info_ike); whack_log(RC_COMMENT , "\"%s\"%s: IKE algorithms found: %s" , c->name , instance , buf); } st = state_with_serialno(c->newest_isakmp_sa); if (st) whack_log(RC_COMMENT , "\"%s\"%s: IKE algorithm newest: %s_%d-%s-%s" , c->name , instance , enum_show(&oakley_enc_names, st->st_oakley.encrypt) +7 /* strlen("OAKLEY_") */ /* , st->st_oakley.encrypter->keydeflen */ , st->st_oakley.enckeylen , enum_show(&oakley_hash_names, st->st_oakley.hash) +7 /* strlen("OAKLEY_") */ , enum_show(&oakley_group_names, st->st_oakley.group->group) +13 /* strlen("OAKLEY_GROUP_") */ ); }
/* * extracts the certificate to be sent to the peer */ chunk_t get_mycert(cert_t cert) { switch (cert.type) { case CERT_NONE: return empty_chunk; /* quietly forget about it */ case CERT_X509_SIGNATURE: return cert.u.x509->certificate; default: loglog(RC_LOG_SERIOUS,"get_mycert: Unknown certificate type: " "%s (%d)", enum_show(&cert_type_names, cert.type), cert.type); return empty_chunk; } }
/* send the request, make sure it all goes down. */ static bool crypto_write_request(struct pluto_crypto_worker *w, const struct pluto_crypto_req *r) { const unsigned char *wdat = (unsigned char *)r; size_t wlen = r->pcr_len; passert(wlen == sizeof(*r)); DBG(DBG_CONTROL, DBG_log("asking crypto helper %d to do %s; request ID %u (len=%zu, pcw_work=%d)", w->pcw_helpernum, enum_show(&pluto_cryptoop_names, r->pcr_type), r->pcr_id, r->pcr_len, w->pcw_work)); while (wlen > 0) { ssize_t cnt = write(w->pcw_master_fd, wdat, wlen); if (cnt < 0) { libreswan_log( "write to crypto helper %d failed: cnt=%d err=%s", w->pcw_helpernum, (int)cnt, strerror(errno)); return FALSE; } if (cnt == 0) { /* Not clear why this would happen. Socket full? */ libreswan_log( "write to crypto helper %d failed to write any bytes", w->pcw_helpernum); return FALSE; } if ((size_t)cnt != wlen) { libreswan_log("short write to crypto helper %d (%zu of %zu bytes); will continue", w->pcw_helpernum, (size_t)cnt, wlen); } wlen -= cnt; wdat += cnt; } return TRUE; }
/* * Decode the CR payload of Phase 1. */ void decode_cr(struct msg_digest *md, generalName_t **requested_ca) { struct payload_digest *p; for (p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next) { struct isakmp_cr *const cr = &p->payload.cr; chunk_t ca_name; ca_name.len = pbs_left(&p->pbs); ca_name.ptr = (ca_name.len > 0)? p->pbs.cur : NULL; DBG_cond_dump_chunk(DBG_PARSING, "CR", ca_name); if (cr->isacr_type == CERT_X509_SIGNATURE) { if (ca_name.len > 0) { generalName_t *gn; if (!is_asn1(ca_name)) continue; gn = alloc_thing(generalName_t, "generalName"); clonetochunk(ca_name, ca_name.ptr,ca_name.len, "ca name"); gn->kind = GN_DIRECTORY_NAME; gn->name = ca_name; gn->next = *requested_ca; *requested_ca = gn; } DBG(DBG_PARSING | DBG_CONTROL, char buf[IDTOA_BUF]; dntoa_or_null(buf, IDTOA_BUF, ca_name, "%any"); DBG_log("requested CA: '%s'", buf); ) } else loglog(RC_LOG_SERIOUS, "ignoring %s certificate request payload", enum_show(&cert_type_names, cr->isacr_type)); }
/* delete a state object */ void delete_state(struct state *st) { struct connection *const c = st->st_connection; struct state *old_cur_state = cur_state == st? NULL : cur_state; openswan_log("deleting state #%lu (%s)", st->st_serialno, enum_show(&state_names, st->st_state)); /* * for most IKEv2 things, we may have further things to do after marking the state deleted, * so we do not actually free it here at all, but back in the main loop when all the work is done. */ if(st->st_ikev2) { /* child sa*/ if(st->st_clonedfrom != 0) { DBG(DBG_CONTROL, DBG_log("received request to delete child state")); if(st->st_state == STATE_CHILDSA_DEL) { DBG(DBG_CONTROL, DBG_log("now deleting the child state")); } else { /* Only send request if child sa is established * otherwise continue with deletion */ if(IS_CHILD_SA_ESTABLISHED(st)) { DBG(DBG_CONTROL, DBG_log("sending Child SA delete equest")); send_delete(st); change_state(st, STATE_CHILDSA_DEL); /* actual deletion when we receive peer response*/ return; } } } else { DBG(DBG_CONTROL, DBG_log("considering request to delete IKE parent state")); /* parent sa */ if(st->st_state == STATE_IKESA_DEL) { DBG(DBG_CONTROL, DBG_log("now deleting the IKE (or parent) state")); } else { /* Another check to verify if a secured * INFORMATIONAL exchange can be sent or not */ if(st->st_skey_ei.ptr && st->st_skey_ai.ptr && st->st_skey_er.ptr && st->st_skey_ar.ptr) { DBG(DBG_CONTROL, DBG_log("sending IKE SA delete request")); send_delete(st); change_state(st, STATE_IKESA_DEL); /* actual deletion when we receive peer response*/ return; } } } } /* If DPD is enabled on this state object, clear any pending events */ if(st->st_dpd_event != NULL) delete_dpd_event(st); /* if there is a suspended state transition, disconnect us */ if (st->st_suspended_md != NULL) { passert(st->st_suspended_md->st == st); DBG(DBG_CONTROL, DBG_log("disconnecting state #%lu from md", st->st_serialno)); st->st_suspended_md->st = NULL; } /* tell the other side of any IPSEC SAs that are going down */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state) || IS_ISAKMP_SA_ESTABLISHED(st->st_state)) send_delete(st); delete_event(st); /* delete any pending timer event */ /* Ditch anything pending on ISAKMP SA being established. * Note: this must be done before the unhash_state to prevent * flush_pending_by_state inadvertently and prematurely * deleting our connection. */ flush_pending_by_state(st); /* if there is anything in the cryptographic queue, then remove this * state from it. */ delete_cryptographic_continuation(st); /* effectively, this deletes any ISAKMP SA that this state represents */ unhash_state(st); /* tell kernel to delete any IPSEC SA * ??? we ought to tell peer to delete IPSEC SAs */ if (IS_IPSEC_SA_ESTABLISHED(st->st_state) || IS_CHILD_SA_ESTABLISHED(st)) delete_ipsec_sa(st, FALSE); else if (IS_ONLY_INBOUND_IPSEC_SA_ESTABLISHED(st->st_state)) delete_ipsec_sa(st, TRUE); if (c->newest_ipsec_sa == st->st_serialno) c->newest_ipsec_sa = SOS_NOBODY; if (c->newest_isakmp_sa == st->st_serialno) c->newest_isakmp_sa = SOS_NOBODY; /* * fake a state change here while we are still associated with a * connection. Without this the state logging (when enabled) cannot * work out what happened. */ fake_state(st, STATE_UNDEFINED); st->st_connection = NULL; /* we might be about to free it */ cur_state = old_cur_state; /* without st_connection, st isn't complete */ connection_discard(c); change_state(st, STATE_UNDEFINED); release_whack(st); change_state(st, STATE_CHILDSA_DEL); }
cur_state = old_cur_state; #ifdef DEBUG set_debugging(old_cur_debugging); #endif } } } } } static void delete_state_function(struct state *this , struct connection *c UNUSED , void *arg UNUSED) { openswan_log("deleting state (%s)" , enum_show(&state_names, this->st_state)); if(this->st_event != NULL) delete_event(this); delete_state(this); } /* * delete all states that were created for a given connection. * if relations == TRUE, then also delete states that share * the same phase 1 SA. */ static bool same_phase1_sa_relations(struct state *this , struct connection *c, void *arg , int pass UNUSED) { so_serial_t *pparent_sa = (so_serial_t *)arg;
/* MUST BE THREAD-SAFE */ static PK11SymKey *calc_dh_shared(const chunk_t g, /* converted to SECItem */ /*const*/ SECKEYPrivateKey *privk, /* NSS doesn't do const */ const struct oakley_group_desc *group, const SECKEYPublicKey *local_pubk) { struct timeval tv0; SECKEYPublicKey *remote_pubk; SECItem nss_g; PK11SymKey *dhshared; PRArenaPool *arena; SECStatus status; unsigned int dhshared_len; DBG(DBG_CRYPT, DBG_log("Started DH shared-secret computation in NSS:")); gettimeofday(&tv0, NULL); arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); passert(arena != NULL); remote_pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); remote_pubk->arena = arena; remote_pubk->keyType = dhKey; remote_pubk->pkcs11Slot = NULL; remote_pubk->pkcs11ID = CK_INVALID_HANDLE; nss_g.data = g.ptr; nss_g.len = (unsigned int)g.len; nss_g.type = siBuffer; status = SECITEM_CopyItem(remote_pubk->arena, &remote_pubk->u.dh.prime, &local_pubk->u.dh.prime); passert(status == SECSuccess); status = SECITEM_CopyItem(remote_pubk->arena, &remote_pubk->u.dh.base, &local_pubk->u.dh.base); passert(status == SECSuccess); status = SECITEM_CopyItem(remote_pubk->arena, &remote_pubk->u.dh.publicValue, &nss_g); passert(status == SECSuccess); dhshared = PK11_PubDerive(privk, remote_pubk, PR_FALSE, NULL, NULL, CKM_DH_PKCS_DERIVE, CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, group->bytes, lsw_return_nss_password_file_info()); passert(dhshared != NULL); dhshared_len = PK11_GetKeyLength(dhshared); if (group->bytes > dhshared_len) { DBG(DBG_CRYPT, DBG_log("Dropped %lu leading zeros", group->bytes - dhshared_len)); chunk_t zeros; PK11SymKey *newdhshared; CK_KEY_DERIVATION_STRING_DATA string_params; SECItem params; zeros = hmac_pads(0x00, group->bytes - dhshared_len); params.data = (unsigned char *)&string_params; params.len = sizeof(string_params); string_params.pData = zeros.ptr; string_params.ulLen = zeros.len; newdhshared = PK11_Derive(dhshared, CKM_CONCATENATE_DATA_AND_BASE, ¶ms, CKM_CONCATENATE_DATA_AND_BASE, CKA_DERIVE, 0); passert(newdhshared != NULL); PK11_FreeSymKey(dhshared); dhshared = newdhshared; freeanychunk(zeros); } else { DBG(DBG_CRYPT, DBG_log("Dropped no leading zeros %d", dhshared_len)); } /* nss_symkey_log(dhshared, "dhshared"); */ DBG(DBG_CRYPT, { struct timeval tv1; unsigned long tv_diff; gettimeofday(&tv1, NULL); tv_diff = (tv1.tv_sec - tv0.tv_sec) * 1000000 + (tv1.tv_usec - tv0.tv_usec); DBG_log("calc_dh_shared(): time elapsed (%s): %ld usec", enum_show(&oakley_group_names, group->group), tv_diff); });
static void doi_log_cert_thinking(struct msg_digest *md UNUSED, u_int16_t auth, enum ike_cert_type certtype, enum certpolicy policy, bool gotcertrequest, bool send_cert) { DBG(DBG_CONTROL, DBG_log("thinking about whether to send my certificate:")); DBG(DBG_CONTROL, { char esb[ENUM_SHOW_BUF_LEN]; DBG_log(" I have RSA key: %s cert.type: %s ", enum_showb(&oakley_auth_names, auth, esb, sizeof(esb)), enum_show(&ike_cert_type_names, certtype)); }); DBG(DBG_CONTROL, DBG_log(" sendcert: %s and I did%s get a certificate request ", enum_show(&certpolicy_type_names, policy), gotcertrequest ? "" : " not")); DBG(DBG_CONTROL, DBG_log(" so %ssend cert.", send_cert ? "" : "do not ")); if (!send_cert) { if (auth == OAKLEY_PRESHARED_KEY) DBG(DBG_CONTROL, DBG_log("I did not send a certificate because digital signatures are not being used. (PSK)")); else if (certtype == CERT_NONE)
/* print a host struct * * This code assumes that the network and host structure * members have the same alignment and size! This requires * that all padding be explicit. */ void DBG_print_struct(const char *label, const void *struct_ptr , struct_desc *sd, bool len_meaningful) { bool immediate = FALSE; const u_int8_t *inp = struct_ptr; field_desc *fp; DBG_log("%s%s:", label, sd->name); for (fp = sd->fields; fp->field_type != ft_end; fp++) { int i = fp->size; u_int32_t n = 0; switch (fp->field_type) { case ft_mbz: /* must be zero */ inp += i; break; case ft_nat: /* natural number (may be 0) */ case ft_len: /* length of this struct and any following crud */ case ft_lv: /* length/value field of attribute */ case ft_enum: /* value from an enumeration */ case ft_loose_enum: /* value from an enumeration with only some names known */ case ft_af_enum: /* Attribute Format + value from an enumeration */ case ft_set: /* bits representing set */ switch (i) { case 8/BITS_PER_BYTE: n = *(const u_int8_t *)inp; break; case 16/BITS_PER_BYTE: n = *(const u_int16_t *)inp; break; case 32/BITS_PER_BYTE: n = *(const u_int32_t *)inp; break; default: impossible(); } switch (fp->field_type) { case ft_len: /* length of this struct and any following crud */ case ft_lv: /* length/value field of attribute */ if (!immediate && !len_meaningful) break; /* FALL THROUGH */ case ft_nat: /* natural number (may be 0) */ DBG_log(" %s: %lu", fp->name, (unsigned long)n); break; case ft_af_enum: /* Attribute Format + value from an enumeration */ if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV) immediate = TRUE; /* FALL THROUGH */ case ft_enum: /* value from an enumeration */ case ft_loose_enum: /* value from an enumeration with only some names known */ DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n)); break; case ft_set: /* bits representing set */ DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n)); break; default: impossible(); break; } inp += i; break; case ft_raw: /* bytes to be left in network-order */ { char m[50]; /* arbitrary limit on name width in log */ snprintf(m, sizeof(m), " %s:", fp->name); DBG_dump(m, inp, i); inp += i; } break; default: impossible(); break; } } }
static int initiate_a_connection(struct connection *c , void *arg) { struct initiate_stuff *is = (struct initiate_stuff *)arg; int whackfd = is->whackfd; lset_t moredebug = is->moredebug; enum crypto_importance importance = is->importance; int success = 0; set_cur_connection(c); /* turn on any extra debugging asked for */ c->extra_debugging |= moredebug; if (!oriented(*c)) { loglog(RC_ORIENT, "We cannot identify ourselves with either end of this connection."); } else if (NEVER_NEGOTIATE(c->policy)) { loglog(RC_INITSHUNT , "cannot initiate an authby=never connection"); } else if (c->kind != CK_PERMANENT) { if (isanyaddr(&c->spd.that.host_addr)) { #ifdef DYNAMICDNS if (c->dnshostname != NULL) { loglog(RC_NOPEERIP, "cannot initiate connection without resolved dynamic peer IP address, will keep retrying"); success = 1; c->policy |= POLICY_UP; } else #endif loglog(RC_NOPEERIP, "cannot initiate connection without knowing peer IP address (kind=%s)" , enum_show(&connection_kind_names, c->kind)); } else loglog(RC_WILDCARD, "cannot initiate connection with ID wildcards (kind=%s)" , enum_show(&connection_kind_names, c->kind)); } else { /* We will only request an IPsec SA if policy isn't empty * (ignoring Main Mode items). * This is a fudge, but not yet important. * If we are to proceed asynchronously, whackfd will be NULL_FD. */ c->policy |= POLICY_UP; if(c->policy & (POLICY_ENCRYPT|POLICY_AUTHENTICATE)) { struct alg_info_esp *alg = c->alg_info_esp; struct db_sa *phase2_sa = kernel_alg_makedb(c->policy, alg, TRUE); if(alg != NULL && phase2_sa == NULL) { whack_log(RC_NOALGO, "can not initiate: no acceptable kernel algorithms loaded"); reset_cur_connection(); close_any(is->whackfd); return 0; } free_sa(phase2_sa); } { whackfd = dup(whackfd); ipsecdoi_initiate(whackfd, c, c->policy, 1 , SOS_NOBODY, importance , NULL_POLICY ); success = 1; } } reset_cur_connection(); return success; }