summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/isakmpd/pf_key_v2.c371
1 files changed, 334 insertions, 37 deletions
diff --git a/sbin/isakmpd/pf_key_v2.c b/sbin/isakmpd/pf_key_v2.c
index b61f44f0aca..bb9b8ed22b8 100644
--- a/sbin/isakmpd/pf_key_v2.c
+++ b/sbin/isakmpd/pf_key_v2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_key_v2.c,v 1.50 2001/04/24 07:27:37 niklas Exp $ */
+/* $OpenBSD: pf_key_v2.c,v 1.51 2001/05/05 00:55:13 angelos Exp $ */
/* $EOM: pf_key_v2.c,v 1.79 2000/12/12 00:33:19 niklas Exp $ */
/*
@@ -126,6 +126,9 @@ static void pf_key_v2_notify (struct pf_key_v2_msg *);
static struct pf_key_v2_msg *pf_key_v2_read (u_int32_t);
static u_int32_t pf_key_v2_seq (void);
static u_int32_t pf_key_v2_write (struct pf_key_v2_msg *);
+static int pf_key_v2_remove_conf (char *);
+static int pf_key_v2_conf_refhandle (int, char *);
+static int pf_key_v2_conf_refinc (int, char *);
/* The socket to use for PF_KEY interactions. */
static int pf_key_v2_socket;
@@ -738,7 +741,8 @@ pf_key_v2_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src,
* parameters for the incoming SA, and cleared otherwise.
*/
int
-pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming)
+pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming,
+ struct sa *isakmp_sa)
{
struct sadb_msg msg;
struct sadb_sa ssa;
@@ -746,6 +750,7 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming)
struct sadb_address *addr = 0;
struct sadb_key *key = 0;
struct sockaddr *src, *dst;
+ struct sadb_ident *sid = 0;
int dstlen, srclen, keylen, hashlen, err;
struct pf_key_v2_msg *update = 0, *ret = 0;
struct ipsec_proto *iproto = proto->data;
@@ -1090,7 +1095,120 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming)
key = 0;
}
- /* XXX Here can identity and sensitivity extensions be setup. */
+ /* Setup identity extensions */
+ if (isakmp_sa->id_i)
+ {
+ len = isakmp_sa->id_i_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1;
+
+ sid = calloc (PF_KEY_V2_ROUND (len) + sizeof *sid, sizeof (u_int8_t));
+ if (!sid)
+ goto cleanup;
+
+ sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)
+ + PF_KEY_V2_ROUND (len) / PF_KEY_V2_CHUNK;
+ if (isakmp_sa->initiator)
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
+ else
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
+
+ switch (isakmp_sa->id_i[0])
+ {
+ case IPSEC_ID_FQDN:
+ memcpy (sid + 1,
+ isakmp_sa->id_i + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ len - 1);
+ sid->sadb_ident_type = SADB_IDENTTYPE_FQDN;
+ break;
+
+ case IPSEC_ID_USER_FQDN:
+ memcpy (sid + 1,
+ isakmp_sa->id_i + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ len - 1);
+ sid->sadb_ident_type = SADB_IDENTTYPE_MBOX;
+ break;
+
+ case IPSEC_ID_KEY_ID:
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV4_RANGE:
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ case IPSEC_ID_IPV6_ADDR:
+ case IPSEC_ID_IPV6_RANGE:
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ /* XXX PREFIX */
+ case IPSEC_ID_DER_ASN1_DN:
+ /* XXX FQDN ? */
+ default:
+ goto nosid;
+ }
+
+ if (pf_key_v2_msg_add (update, (struct sadb_ext *)sid,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ sid = 0;
+
+ nosid:
+ if (sid)
+ free (sid);
+ }
+
+ if (isakmp_sa->id_r)
+ {
+ len = isakmp_sa->id_r_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1;
+
+ sid = calloc (PF_KEY_V2_ROUND (len) + sizeof *sid, sizeof (u_int8_t));
+ if (!sid)
+ goto cleanup;
+
+ sid->sadb_ident_len = ((sizeof *sid) / PF_KEY_V2_CHUNK)
+ + PF_KEY_V2_ROUND (len) / PF_KEY_V2_CHUNK;
+ if (isakmp_sa->initiator)
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_DST;
+ else
+ sid->sadb_ident_exttype = SADB_EXT_IDENTITY_SRC;
+
+ switch (isakmp_sa->id_r[0])
+ {
+ case IPSEC_ID_FQDN:
+ memcpy (sid + 1,
+ isakmp_sa->id_r + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ len - 1);
+ sid->sadb_ident_type = SADB_IDENTTYPE_FQDN;
+ break;
+
+ case IPSEC_ID_USER_FQDN:
+ memcpy (sid + 1,
+ isakmp_sa->id_r + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
+ len - 1);
+ sid->sadb_ident_type = SADB_IDENTTYPE_MBOX;
+ break;
+
+ case IPSEC_ID_KEY_ID:
+ case IPSEC_ID_IPV4_ADDR:
+ case IPSEC_ID_IPV4_RANGE:
+ case IPSEC_ID_IPV4_ADDR_SUBNET:
+ case IPSEC_ID_IPV6_ADDR:
+ case IPSEC_ID_IPV6_RANGE:
+ case IPSEC_ID_IPV6_ADDR_SUBNET:
+ /* XXX PREFIX */
+ case IPSEC_ID_DER_ASN1_DN:
+ /* XXX FQDN ? */
+ default:
+ goto nodid;
+ }
+
+ if (pf_key_v2_msg_add (update, (struct sadb_ext *)sid,
+ PF_KEY_V2_NODE_MALLOCED) == -1)
+ goto cleanup;
+ sid = 0;
+
+ nodid:
+ if (sid)
+ free (sid);
+ }
+
+ /* XXX Setup credentials */
+
+ /* XXX Here can sensitivity extensions be setup. */
/* XXX IPv4 specific. */
LOG_DBG ((LOG_SYSDEP, 10, "pf_key_v2_set_spi: satype %d dst %s SPI 0x%x",
@@ -1134,6 +1252,8 @@ pf_key_v2_set_spi (struct sa *sa, struct proto *proto, int incoming)
return 0;
cleanup:
+ if (sid)
+ free (sid);
if (addr)
free (addr);
if (life)
@@ -1719,6 +1839,129 @@ pf_key_v2_enable_sa (struct sa *sa, struct sa *isakmp_sa)
return error;
}
+/* Increase reference count of refcounted sections. */
+static int
+pf_key_v2_conf_refinc (int af, char *section)
+{
+ unsigned char conn[22];
+ int num;
+
+ if (section == NULL)
+ return 0;
+
+ num = conf_get_num (section, "Refcount", 0);
+ if (num == 0)
+ return 0;
+
+ sprintf (conn, "%d", num + 1);
+ conf_set (af, section, "Refcount", conn, 1, 0);
+ return 0;
+}
+
+/*
+ * Return 0 if the section didn't exist or was removed, non-zero otherwise.
+ * Don't touch non-refcounted (statically defined) sections.
+ */
+static int
+pf_key_v2_conf_refhandle (int af, char *section)
+{
+ unsigned char conn[22];
+ int num;
+
+ if (section == NULL)
+ return 0;
+
+ num = conf_get_num (section, "Refcount", 0);
+ if (num == 1)
+ {
+ conf_remove_section (af, section);
+ num--;
+ }
+ else
+ if (num != 0)
+ {
+ sprintf (conn, "%d", num - 1);
+ conf_set (af, section, "Refcount", conn, 1, 0);
+ }
+
+ return num;
+}
+
+/* Remove all dynamically-established configuration entries */
+static int
+pf_key_v2_remove_conf(char *section)
+{
+ char *ikepeer, *localid, *remoteid, *configname;
+ struct conf_list_node *attr;
+ struct conf_list *attrs;
+ int af;
+
+ if (section == NULL)
+ return 0;
+
+ if (!conf_get_str (section, "Phase"))
+ return 0;
+
+ /* Only remove dynamically-established entries */
+ attrs = conf_get_list (section, "Flags");
+ if (attrs)
+ {
+ for (attr = TAILQ_FIRST (&attrs->fields); attr;
+ attr = TAILQ_NEXT (attr, link))
+ if (!strcasecmp (attr->field, "__ondemand"))
+ goto passed;
+
+ conf_free_list (attrs);
+ }
+
+ return 0;
+
+ passed:
+ conf_free_list (attrs);
+
+ af = conf_begin ();
+
+ configname = conf_get_str (section, "Configuration");
+
+ if (pf_key_v2_conf_refhandle (af, section))
+ {
+ conf_end (af, 1);
+ return 0;
+ }
+
+ conf_remove_section (af, configname);
+
+ localid = conf_get_str (section, "Local-ID");
+ remoteid = conf_get_str (section, "Remote-ID");
+ ikepeer = conf_get_str (section, "ISAKMP-peer");
+
+ /* These are the Phase 2 Local/Remote IDs */
+ pf_key_v2_conf_refhandle (af, localid);
+ pf_key_v2_conf_refhandle (af, remoteid);
+
+ if (ikepeer)
+ {
+ remoteid = conf_get_str (ikepeer, "Remote-ID");
+ localid = conf_get_str (ikepeer, "ID");
+ configname = conf_get_str (ikepeer, "Configuration");
+
+ if (pf_key_v2_conf_refhandle (af, ikepeer))
+ {
+ conf_end (af, 1);
+ return 0;
+ }
+
+ pf_key_v2_conf_refhandle (af, configname);
+
+ /* Phase 1 IDs */
+ pf_key_v2_conf_refhandle (af, localid);
+ pf_key_v2_conf_refhandle (af, remoteid);
+ }
+
+ conf_end (af, 1);
+ return 0;
+}
+
/* Disable a flow given a SA. */
static int
pf_key_v2_disable_sa (struct sa *sa, int incoming)
@@ -1797,6 +2040,14 @@ pf_key_v2_delete_spi (struct sa *sa, struct proto *proto, int incoming)
&& !(sa->flags & SA_FLAG_ONDEMAND))
pf_key_v2_disable_sa (sa, incoming);
+ if (sa->name && !(sa->flags & SA_FLAG_REPLACED))
+ {
+ LOG_DBG ((LOG_SYSDEP, 50,
+ "pf_key_v2_delete_spi: removing configuration %s",
+ sa->name));
+ pf_key_v2_remove_conf (sa->name);
+ }
+
msg.sadb_msg_type = SADB_DELETE;
switch (proto->proto)
{
@@ -1923,6 +2174,16 @@ pf_key_v2_stayalive (struct exchange *exchange, void *vconn, int fail)
sa = sa_lookup_by_name (conn, 2);
if (sa)
sa->flags |= SA_FLAG_STAYALIVE;
+
+ /*
+ * Remove failed configuration entry -- call twice because it is
+ * created with a Refcount of 2.
+ */
+ if (fail && exchange->name)
+ {
+ pf_key_v2_remove_conf (exchange->name);
+ pf_key_v2_remove_conf (exchange->name);
+ }
}
/* Check if a connection CONN exists, otherwise establish it. */
@@ -2355,21 +2616,22 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
pwd = NULL;
/* Set the section if it doesn't already exist */
+ af = conf_begin ();
if (!conf_get_str (srcid, "ID-type"))
{
- af = conf_begin ();
- if (conf_set (af, srcid, "ID-type", prefstring, 0, 0)
+ if (conf_set (af, srcid, "ID-type", prefstring, 1, 0)
+ || conf_set (af, srcid, "Refcount", "1", 1, 0)
|| conf_set (af, srcid, "Name",
srcid + strlen ("ID:/") + strlen (prefstring),
- 0, 0))
+ 1, 0))
{
conf_end (af, 0);
goto fail;
}
-
- conf_end (af, 1);
}
-
+ else
+ pf_key_v2_conf_refinc (af, srcid);
+ conf_end (af, 1);
break;
default:
@@ -2460,21 +2722,22 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
pwd = NULL;
/* Set the section if it doesn't already exist */
+ af = conf_begin ();
if (!conf_get_str (dstid, "ID-type"))
{
- af = conf_begin ();
- if (conf_set (af, dstid, "ID-type", prefstring, 0, 0)
+ if (conf_set (af, dstid, "ID-type", prefstring, 1, 0)
+ || conf_set (af, dstid, "Refcount", "1", 1, 0)
|| conf_set (af, dstid, "Name",
dstid + strlen ("ID:/") + strlen (prefstring),
- 0, 0))
+ 1, 0))
{
conf_end (af, 0);
goto fail;
}
-
- conf_end (af, 1);
}
-
+ else
+ pf_key_v2_conf_refinc (af, dstid);
+ conf_end (af, 1);
break;
default:
@@ -2494,8 +2757,8 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
/* Get a new connection sequence number */
for (;; connection_seq++)
{
- sprintf (conn, "Connection-%d", connection_seq);
- sprintf (configname, "Config-Phase2-%d", connection_seq);
+ sprintf (conn, "Connection-%u", connection_seq);
+ sprintf (configname, "Config-Phase2-%u", connection_seq);
/* Does it exist ? */
if (!conf_get_str (conn, "Phase")
@@ -2509,6 +2772,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
* - ISAKMP-peer
* - Local-ID/Remote-ID (if provided)
* - Acquire-ID (sequence number of kernel message, e.g., PF_KEYv2)
+ * - Configuration
*
* Also set the following section:
* [Peer-dstaddr(/srcaddr)(-srcid)(/dstid)]
@@ -2543,10 +2807,14 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
srcaddr ? srcbuf : "", srcid ? "-" : "", srcid ? srcid : "",
dstid ? (srcid ? "/" : "-/") : "", dstid ? dstid : "");
- /* Set the IPsec connection section */
+ /*
+ * Set the IPsec connection section. Refcount is set to 2, because
+ * it will be linked both to the incoming and the outgoing SA.
+ */
af = conf_begin ();
if (conf_set (af, conn, "Phase", "2", 0, 0)
- || conf_set (af, conn, "Flags", "__ondemand", 0 ,0)
+ || conf_set (af, conn, "Flags", "__ondemand", 0 , 0)
+ || conf_set (af, conn, "Refcount", "2", 0 , 0)
|| conf_set (af, conn, "ISAKMP-peer", peer, 0, 0))
{
conf_end (af, 0);
@@ -2562,7 +2830,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
}
/* Set Phase 2 IDs -- this is the Local-ID section */
- sprintf (lname, "Phase2-ID:%s/%s/%d/%d", ssflow, ssmask, tproto, sport);
+ sprintf (lname, "Phase2-ID:%s/%s/%u/%u", ssflow, ssmask, tproto, sport);
if (conf_set (af, conn, "Local-ID", lname, 0, 0))
{
conf_end (af, 0);
@@ -2571,6 +2839,12 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
if (!conf_get_str (lname, "ID-type"))
{
+ if (conf_set (af, lname, "Refcount", "1", 0, 0))
+ {
+ conf_end (af, 0);
+ goto fail;
+ }
+
if (shostflag)
{
if (conf_set (af, lname, "ID-type", "IPV4_ADDR", 0, 0)
@@ -2592,7 +2866,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
}
if (tproto)
{
- sprintf (tmbuf, "%d", tproto);
+ sprintf (tmbuf, "%u", tproto);
if (conf_set (af, lname, "Protocol", tmbuf, 0, 0))
{
conf_end (af, 0);
@@ -2601,7 +2875,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
if (sport)
{
- sprintf (tmbuf, "%d", ntohs (sport));
+ sprintf (tmbuf, "%u", ntohs (sport));
if (conf_set (af, lname, "Port", tmbuf, 0, 0))
{
conf_end (af, 0);
@@ -2610,9 +2884,11 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
}
}
}
+ else
+ pf_key_v2_conf_refinc (af, lname);
/* Set Remote-ID section */
- sprintf (dname, "Phase2-ID:%s/%s/%d/%d", sdflow, sdmask, tproto, dport);
+ sprintf (dname, "Phase2-ID:%s/%s/%u/%u", sdflow, sdmask, tproto, dport);
if (conf_set (af, conn, "Remote-ID", dname, 0, 0))
{
conf_end (af, 0);
@@ -2621,6 +2897,12 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
if (!conf_get_str (dname, "ID-type"))
{
+ if (conf_set (af, dname, "Refcount", "1", 0, 0))
+ {
+ conf_end (af, 0);
+ goto fail;
+ }
+
if (dhostflag)
{
if (conf_set (af, dname, "ID-type", "IPV4_ADDR", 0, 0)
@@ -2643,7 +2925,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
if (tproto)
{
- sprintf (tmbuf, "%d", tproto);
+ sprintf (tmbuf, "%u", tproto);
if (conf_set (af, dname, "Protocol", tmbuf, 0, 0))
{
conf_end (af, 0);
@@ -2652,7 +2934,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
if (dport)
{
- sprintf (tmbuf, "%d", ntohs (dport));
+ sprintf (tmbuf, "%u", ntohs (dport));
if (conf_set (af, dname, "Port", tmbuf, 0, 0))
{
conf_end (af, 0);
@@ -2661,6 +2943,8 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
}
}
}
+ else
+ pf_key_v2_conf_refinc (af, dname);
/*
* XXX
@@ -2676,18 +2960,36 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
}
if (conf_set (af, configname, "Exchange_type", "Quick_mode", 0, 0)
- || conf_set (af, configname, "DOI", "IPSEC", 0, 0)
- || conf_set (af, configname, "Suites",
- "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0))
+ || conf_set (af, configname, "DOI", "IPSEC", 0, 0))
{
conf_end (af, 0);
goto fail;
}
+ if (conf_get_str ("General", "Default-Phase-2-Suites"))
+ {
+ if (conf_set (af, configname, "Suites",
+ conf_get_str ("General", "Default-Phase-2-Suites"), 0, 0))
+ {
+ conf_end (af, 0);
+ goto fail;
+ }
+ }
+ else
+ {
+ if (conf_set (af, configname, "Suites",
+ "QM-ESP-3DES-SHA-PFS-SUITE", 0, 0))
+ {
+ conf_end (af, 0);
+ goto fail;
+ }
+ }
+
/* Set the ISAKMP-peer section */
if (!conf_get_str (peer, "Phase"))
{
if (conf_set (af, peer, "Phase", "1", 0, 0)
+ || conf_set (af, peer, "Refcount", "1", 0, 0)
|| conf_set (af, peer, "Address", dstbuf, 0, 0))
{
conf_end (af, 0);
@@ -2713,6 +3015,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
{
if (conf_set (af, confname, "Exchange_Type", "ID_PROT", 0, 0)
|| conf_set (af, confname, "DOI", "IPSEC", 0, 0)
+ || conf_set (af, confname, "Refcount", "1", 0, 0)
|| conf_set (af, confname, "Transforms", "3DES-SHA-RSA_SIG", 0,
0))
{
@@ -2720,6 +3023,8 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
goto fail;
}
}
+ else
+ pf_key_v2_conf_refinc (af, confname);
/* The ID we should use in Phase 1 */
if (srcid && conf_set (af, peer, "ID", srcid, 0, 0))
@@ -2736,9 +3041,7 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
}
}
else
- {
- /* Phase 1 tag exists, there's nothing more we need to do */
- }
+ pf_key_v2_conf_refinc (af, peer);
/* All done */
conf_end (af, 1);
@@ -2746,12 +3049,6 @@ pf_key_v2_acquire (struct pf_key_v2_msg *pmsg)
/* Let's rock */
pf_key_v2_connection_check (conn);
- /*
- * XXX Need to implement cleanup of sections after SAs expire. In
- * particular, we need to expire the IPsec connection section; we
- * could keep the ISAKMP-peer, Local-ID/Remote-ID sections.
- */
-
/* Fall-through to cleanup */
fail:
if (ret)