📄 spdb_struct.c
字号:
/* Security Policy Data Base (such as it is) * Copyright (C) 1998-2001 D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: spdb_struct.c,v 1.8 2004/12/09 18:13:08 mcr Exp $ */#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/queue.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "oswlog.h"#include "defs.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h" /* needs id.h */#include "state.h"#include "packet.h"#include "keys.h"#include "kernel.h" /* needs connections.h */#include "log.h"#include "spdb.h"#include "whack.h" /* for RC_LOG_SERIOUS */#include "sha1.h"#include "md5.h"#include "crypto.h" /* requires sha1.h and md5.h */#include "alg_info.h"#include "kernel_alg.h"#include "ike_alg.h"#include "db_ops.h"#ifdef NAT_TRAVERSAL#include "nat_traversal.h"#endif/** output an attribute (within an SA) */boolout_attr(int type , unsigned long val , struct_desc *attr_desc , enum_names **attr_val_descs USED_BY_DEBUG , pb_stream *pbs){ struct isakmp_attribute attr; if (val >> 16 == 0) { /* short value: use TV form */ attr.isaat_af_type = type | ISAKMP_ATTR_AF_TV; attr.isaat_lv = val; if (!out_struct(&attr, attr_desc, pbs, NULL)) return FALSE; } else { /* This is a real fudge! Since we rarely use long attributes * and since this is the only place where we can cause an * ISAKMP message length to be other than a multiple of 4 octets, * we force the length of the value to be a multiple of 4 octets. * Furthermore, we only handle values up to 4 octets in length. * Voila: a fixed format! */ pb_stream val_pbs; u_int32_t nval = htonl(val); attr.isaat_af_type = type | ISAKMP_ATTR_AF_TLV; if (!out_struct(&attr, attr_desc, pbs, &val_pbs) || !out_raw(&nval, sizeof(nval), &val_pbs, "long attribute value")) return FALSE; close_output_pbs(&val_pbs); } DBG(DBG_EMITTING, enum_names *d = attr_val_descs[type]; if (d != NULL) DBG_log(" [%lu is %s]" , val, enum_show(d, val))); return TRUE;}#define return_on(var, val) do { var=val;goto return_out; } while(0);/** * Output an SA, as described by a db_sa. * This has the side-effect of allocating SPIs for us. * */boolout_sa(pb_stream *outs , struct db_sa *sadb , struct state *st , bool oakley_mode , bool aggressive_mode UNUSED , u_int8_t np){ pb_stream sa_pbs; int pcn; bool ret = FALSE; bool ah_spi_generated = FALSE , esp_spi_generated = FALSE , ipcomp_cpi_generated = FALSE; struct db_sa *revised_sadb; if(oakley_mode) { revised_sadb=oakley_alg_makedb(st->st_connection->alg_info_ike , sadb , aggressive_mode ? 1 : -1); } else { revised_sadb=kernel_alg_makedb(st->st_connection->alg_info_esp); } if(revised_sadb != NULL) { sadb = revised_sadb; } /* SA header out */ { struct isakmp_sa sa; sa.isasa_np = np; st->st_doi = sa.isasa_doi = ISAKMP_DOI_IPSEC; /* all we know */ if (!out_struct(&sa, &isakmp_sa_desc, outs, &sa_pbs)) return_on(ret, FALSE); } /* within SA: situation out */ st->st_situation = SIT_IDENTITY_ONLY; if (!out_struct(&st->st_situation, &ipsec_sit_desc, &sa_pbs, NULL)) return_on(ret, FALSE); /* within SA: Proposal Payloads * * Multiple Proposals with the same number are simultaneous * (conjuncts) and must deal with different protocols (AH or ESP). * Proposals with different numbers are alternatives (disjuncts), * in preference order. * Proposal numbers must be monotonic. * See RFC 2408 "ISAKMP" 4.2 */ for (pcn = 0; pcn < sadb->prop_conj_cnt; pcn++) { struct db_prop_conj *pc; int pn; int valid_prop_cnt; pc = &sadb->prop_conjs[pcn]; /* * figure out how many proposals we are going to make, * so we'll know when we are finished! This repeats some calculations * but this seems like the best method to avoid empty proposals. */ valid_prop_cnt = 0; for (pn = 0; pn < pc->prop_cnt; pn++) { struct db_prop *p; p = &pc->props[pn]; valid_prop_cnt++; } DBG(DBG_EMITTING, DBG_log("out_sa pcn: %d has %d valid proposals", pcn, valid_prop_cnt)); for (pn = 0; pn < pc->prop_cnt; pn++) { struct db_prop *p; pb_stream proposal_pbs; struct isakmp_proposal proposal; struct_desc *trans_desc; struct_desc *attr_desc; enum_names **attr_val_descs; int tn; bool tunnel_mode; /* * set the tunnel_mode bit on the last proposal only, and * only if we are trying to negotiate tunnel mode in the first * place. */ tunnel_mode = (valid_prop_cnt == 1) && (st->st_policy & POLICY_TUNNEL); /* * pick the part of the proposal we are trying to work on */ p = &pc->props[pn]; proposal.isap_proposal = pcn; proposal.isap_protoid = p->protoid; proposal.isap_spisize = oakley_mode ? 0 : p->protoid == PROTO_IPCOMP ? IPCOMP_CPI_SIZE : IPSEC_DOI_SPI_SIZE; DBG(DBG_EMITTING, DBG_log("out_sa pcn: %d pn: %d<%d valid_count: %d", pcn, pn, pc->prop_cnt, valid_prop_cnt)); /* but, skip things if the transform count is zero */ if(p->trans_cnt == 0) continue; /* Proposal header */ if(--valid_prop_cnt > 0) { proposal.isap_np = ISAKMP_NEXT_P; } else { proposal.isap_np = ISAKMP_NEXT_NONE; } proposal.isap_notrans = p->trans_cnt; if (!out_struct(&proposal, &isakmp_proposal_desc , &sa_pbs, &proposal_pbs)) return_on(ret, FALSE); /* Per-protocols stuff: * Set trans_desc. * Set attr_desc. * Set attr_val_descs. * If not oakley_mode, emit SPI. * We allocate SPIs on demand. * All ESPs in an SA will share a single SPI. * All AHs in an SAwill share a single SPI. * AHs' SPI will be distinct from ESPs'. * This latter is needed because KLIPS doesn't * use the protocol when looking up a (dest, protocol, spi). * ??? If multiple ESPs are composed, how should their SPIs * be allocated? */ { ipsec_spi_t *spi_ptr = NULL; int proto = 0; bool *spi_generated; switch (p->protoid) { case PROTO_ISAKMP: passert(oakley_mode); trans_desc = &isakmp_isakmp_transform_desc; attr_desc = &isakmp_oakley_attribute_desc; attr_val_descs = oakley_attr_val_descs; /* no SPI needed */ break; case PROTO_IPSEC_AH: passert(!oakley_mode); trans_desc = &isakmp_ah_transform_desc; attr_desc = &isakmp_ipsec_attribute_desc; attr_val_descs = ipsec_attr_val_descs; spi_ptr = &st->st_ah.our_spi; spi_generated = &ah_spi_generated; proto = IPPROTO_AH; break; case PROTO_IPSEC_ESP: passert(!oakley_mode); trans_desc = &isakmp_esp_transform_desc; attr_desc = &isakmp_ipsec_attribute_desc; attr_val_descs = ipsec_attr_val_descs; spi_ptr = &st->st_esp.our_spi; spi_generated = &esp_spi_generated; proto = IPPROTO_ESP; break; case PROTO_IPCOMP: passert(!oakley_mode); trans_desc = &isakmp_ipcomp_transform_desc; attr_desc = &isakmp_ipsec_attribute_desc; attr_val_descs = ipsec_attr_val_descs; /* a CPI isn't quite the same as an SPI * so we use specialized code to emit it. */ if (!ipcomp_cpi_generated) { st->st_ipcomp.our_spi = get_my_cpi( &st->st_connection->spd, tunnel_mode); if (st->st_ipcomp.our_spi == 0) return_on(ret, FALSE); /* problem generating CPI */ ipcomp_cpi_generated = TRUE; } /* CPI is stored in network low order end of an * ipsec_spi_t. So we start a couple of bytes in. */ if (!out_raw((u_char *)&st->st_ipcomp.our_spi + IPSEC_DOI_SPI_SIZE - IPCOMP_CPI_SIZE , IPCOMP_CPI_SIZE , &proposal_pbs, "CPI")) return_on(ret, FALSE); break; default: bad_case(p->protoid); } if (spi_ptr != NULL) { if (!*spi_generated) { *spi_ptr = get_ipsec_spi(0 , proto , &st->st_connection->spd , tunnel_mode); if (*spi_ptr == 0) return FALSE; *spi_generated = TRUE; } if (!out_raw((u_char *)spi_ptr, IPSEC_DOI_SPI_SIZE , &proposal_pbs, "SPI")) return_on(ret, FALSE); } } /* within proposal: Transform Payloads */ for (tn = 0; tn != p->trans_cnt; tn++) { struct db_trans *t = &p->trans[tn]; pb_stream trans_pbs; struct isakmp_transform trans; int an; trans.isat_np = (tn == p->trans_cnt - 1) ? ISAKMP_NEXT_NONE : ISAKMP_NEXT_T; trans.isat_transnum = tn; trans.isat_transid = t->transid; if (!out_struct(&trans, trans_desc, &proposal_pbs, &trans_pbs)) return_on(ret, FALSE); /* Within tranform: Attributes. */ /* For Phase 2 / Quick Mode, GROUP_DESCRIPTION is * automatically generated because it must be the same * in every transform. Except IPCOMP. */ if (p->protoid != PROTO_IPCOMP && st->st_pfs_group != NULL) { passert(!oakley_mode); passert(st->st_pfs_group != &unset_group); out_attr(GROUP_DESCRIPTION, st->st_pfs_group->group , attr_desc, attr_val_descs , &trans_pbs); } /* automatically generate duration * and, for Phase 2 / Quick Mode, encapsulation. */ if (oakley_mode) { out_attr(OAKLEY_LIFE_TYPE, OAKLEY_LIFE_SECONDS , attr_desc, attr_val_descs , &trans_pbs); out_attr(OAKLEY_LIFE_DURATION , st->st_connection->sa_ike_life_seconds , attr_desc, attr_val_descs , &trans_pbs); } else { /* RFC 2407 (IPSEC DOI) 4.5 specifies that * the default is "unspecified (host-dependent)". * This makes little sense, so we always specify it. * * Unlike other IPSEC transforms, IPCOMP defaults * to Transport Mode, so we can exploit the default * (draft-shacham-ippcp-rfc2393bis-05.txt 4.1). */ if (p->protoid != PROTO_IPCOMP || st->st_policy & POLICY_TUNNEL) {#ifdef NAT_TRAVERSAL#ifndef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT if ((st->nat_traversal & NAT_T_DETECTED) && (!(st->st_policy & POLICY_TUNNEL))) { /* Inform user that we will not respect policy and only * propose Tunnel Mode */ loglog(RC_LOG_SERIOUS, "NAT-Traversal: " "Transport Mode not allowed due to security concerns -- " "using Tunnel mode. Rebuild Openswan with USE_NAT_TRAVERSAL_TRANSPORT_MODE=true in Makefile.inc to support transport mode."); }#endif#endif out_attr(ENCAPSULATION_MODE#ifdef NAT_TRAVERSAL#ifdef I_KNOW_TRANSPORT_MODE_HAS_SECURITY_CONCERN_BUT_I_WANT_IT , NAT_T_ENCAPSULATION_MODE(st,st->st_policy)#else /* If NAT-T is detected, use UDP_TUNNEL as long as Transport * Mode has security concerns. * * User has been informed of that */ , NAT_T_ENCAPSULATION_MODE(st,POLICY_TUNNEL)#endif#else /* ! NAT_TRAVERSAL */ , st->st_policy & POLICY_TUNNEL ? ENCAPSULATION_MODE_TUNNEL : ENCAPSULATION_MODE_TRANSPORT#endif , attr_desc, attr_val_descs , &trans_pbs); } out_attr(SA_LIFE_TYPE, SA_LIFE_TYPE_SECONDS , attr_desc, attr_val_descs , &trans_pbs); out_attr(SA_LIFE_DURATION , st->st_connection->sa_ipsec_life_seconds , attr_desc, attr_val_descs , &trans_pbs); } /* spit out attributes from table */ for (an = 0; an != t->attr_cnt; an++) { struct db_attr *a = &t->attrs[an]; out_attr(a->type, a->val , attr_desc, attr_val_descs , &trans_pbs); } close_output_pbs(&trans_pbs); } close_output_pbs(&proposal_pbs); } /* end of a conjunction of proposals */ } close_output_pbs(&sa_pbs); ret = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -