diff options
Diffstat (limited to 'src/starter/starterwhack.c')
-rw-r--r-- | src/starter/starterwhack.c | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/src/starter/starterwhack.c b/src/starter/starterwhack.c new file mode 100644 index 000000000..42328849a --- /dev/null +++ b/src/starter/starterwhack.c @@ -0,0 +1,369 @@ +/* strongSwan whack functions to communicate with pluto (whack.c) + * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security + * + * 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: starterwhack.c,v 1.17 2006/04/17 10:32:36 as Exp $ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stddef.h> +#include <unistd.h> +#include <errno.h> + +#include <freeswan.h> + +#include <constants.h> +#include <defs.h> +#include <log.h> +#include <whack.h> + +#include "starterwhack.h" +#include "confread.h" +#include "files.h" + +static int +pack_str (char **p, char **next, char **roof) +{ + const char *s = (*p==NULL) ? "" : *p; /* note: NULL becomes ""! */ + size_t len = strlen(s) + 1; + + if ((*roof - *next) < len) + { + return 0; /* not enough space */ + } + else + { + strcpy(*next, s); + *next += len; + *p = NULL; /* don't send pointers on the wire! */ + return 1; + } +} + +static int +send_whack_msg (whack_message_t *msg) +{ + struct sockaddr_un ctl_addr = { AF_UNIX, PLUTO_CTL_FILE }; + int sock; + ssize_t len; + char *str_next, *str_roof; + + /* pack strings */ + str_next = (char *)msg->string; + str_roof = (char *)&msg->string[sizeof(msg->string)]; + + if (!pack_str(&msg->name, &str_next, &str_roof) + || !pack_str(&msg->left.id, &str_next, &str_roof) + || !pack_str(&msg->left.cert, &str_next, &str_roof) + || !pack_str(&msg->left.ca, &str_next, &str_roof) + || !pack_str(&msg->left.groups, &str_next, &str_roof) + || !pack_str(&msg->left.updown, &str_next, &str_roof) + || !pack_str(&msg->left.virt, &str_next, &str_roof) + || !pack_str(&msg->right.id, &str_next, &str_roof) + || !pack_str(&msg->right.cert, &str_next, &str_roof) + || !pack_str(&msg->right.ca, &str_next, &str_roof) + || !pack_str(&msg->right.groups, &str_next, &str_roof) + || !pack_str(&msg->right.updown, &str_next, &str_roof) + || !pack_str(&msg->right.virt, &str_next, &str_roof) + || !pack_str(&msg->keyid, &str_next, &str_roof) + || !pack_str(&msg->myid, &str_next, &str_roof) + || !pack_str(&msg->cacert, &str_next, &str_roof) + || !pack_str(&msg->ldaphost, &str_next, &str_roof) + || !pack_str(&msg->ldapbase, &str_next, &str_roof) + || !pack_str(&msg->crluri, &str_next, &str_roof) + || !pack_str(&msg->crluri2, &str_next, &str_roof) + || !pack_str(&msg->ocspuri, &str_next, &str_roof) + || !pack_str(&msg->ike, &str_next, &str_roof) + || !pack_str(&msg->esp, &str_next, &str_roof) + || !pack_str(&msg->sc_data, &str_next, &str_roof) + || (str_roof - str_next < msg->keyval.len)) + { + plog("send_wack_msg(): can't pack strings"); + return -1; + } + if (msg->keyval.ptr) + memcpy(str_next, msg->keyval.ptr, msg->keyval.len); + msg->keyval.ptr = NULL; + str_next += msg->keyval.len; + len = str_next - (char *)msg; + + /* connect to pluto ctl */ + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) + { + plog("socket() failed: %s", strerror(errno)); + return -1; + } + if (connect(sock, (struct sockaddr *)&ctl_addr, + offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) + { + plog("connect(pluto_ctl) failed: %s", strerror(errno)); + close(sock); + return -1; + } + + /* send message */ + if (write(sock, msg, len) != len) + { + plog("write(pluto_ctl) failed: %s", strerror(errno)); + close(sock); + return -1; + } + + /* TODO: read reply */ + close(sock); + return 0; +} + +static void +init_whack_msg(whack_message_t *msg) +{ + memset(msg, 0, sizeof(whack_message_t)); + msg->magic = WHACK_MAGIC; +} + +static char * +connection_name(starter_conn_t *conn) +{ + /* if connection name is '%auto', create a new name like conn_xxxxx */ + static char buf[32]; + + if (streq(conn->name, "%auto")) + { + sprintf(buf, "conn_%ld", conn->id); + return buf; + } + return conn->name; +} + +static void +set_whack_end(whack_end_t *w, starter_end_t *end) +{ + w->id = end->id; + w->cert = end->cert; + w->ca = end->ca; + w->groups = end->groups; + w->host_addr = end->addr; + w->host_nexthop = end->nexthop; + w->host_srcip = end->srcip; + w->has_client = end->has_client; + + if (w->has_client) + w->client = end->subnet; + else + w->client.addr.u.v4.sin_family = addrtypeof(&w->host_addr); + + w->has_client_wildcard = end->has_client_wildcard; + w->has_port_wildcard = end->has_port_wildcard; + w->has_srcip = end->has_srcip; + w->has_natip = end->has_natip; + w->modecfg = end->modecfg; + w->hostaccess = end->hostaccess; + w->sendcert = end->sendcert; + w->updown = end->updown; + w->host_port = IKE_UDP_PORT; + w->port = end->port; + w->protocol = end->protocol; + w->virt = end->virt; + + if (w->port != 0) + { + int port = htons(w->port); + + setportof(port, &w->host_addr); + setportof(port, &w->client.addr); + } +} + +static int +starter_whack_add_pubkey (starter_conn_t *conn, starter_end_t *end +, const char *lr) +{ + const char *err; + static char keyspace[1024 + 4]; + whack_message_t msg; + + init_whack_msg(&msg); + + msg.whack_key = TRUE; + msg.pubkey_alg = PUBKEY_ALG_RSA; + if (end->id && end->rsakey) + { + /* special values to ignore */ + if (streq(end->rsakey, "") + || streq(end->rsakey, "%none") + || streq(end->rsakey, "%cert") + || streq(end->rsakey, "0x00")) + { + return 0; + } + msg.keyid = end->id; + err = atobytes(end->rsakey, 0, keyspace, sizeof(keyspace), &msg.keyval.len); + if (err) + { + plog("conn %s/%s: rsakey malformed [%s]", connection_name(conn), lr, err); + return 1; + } + else + { + msg.keyval.ptr = keyspace; + return send_whack_msg(&msg); + } + } + return 0; +} + +int +starter_whack_add_conn(starter_conn_t *conn) +{ + whack_message_t msg; + int r; + + init_whack_msg(&msg); + + msg.whack_connection = TRUE; + msg.name = connection_name(conn); + + msg.ikev1 = conn->keyexchange != KEY_EXCHANGE_IKEV2; + msg.addr_family = conn->addr_family; + msg.tunnel_addr_family = conn->tunnel_addr_family; + msg.sa_ike_life_seconds = conn->sa_ike_life_seconds; + msg.sa_ipsec_life_seconds = conn->sa_ipsec_life_seconds; + msg.sa_rekey_margin = conn->sa_rekey_margin; + msg.sa_rekey_fuzz = conn->sa_rekey_fuzz; + msg.sa_keying_tries = conn->sa_keying_tries; + msg.policy = conn->policy; + + set_whack_end(&msg.left, &conn->left); + set_whack_end(&msg.right, &conn->right); + + msg.esp = conn->esp; + msg.ike = conn->ike; + msg.pfsgroup = conn->pfsgroup; + + /* taken from pluto/whack.c */ + if (msg.pfsgroup) + { + char esp_buf[256]; + + snprintf(esp_buf, sizeof (esp_buf), "%s;%s" + , msg.esp ? msg.esp : "" + , msg.pfsgroup ? msg.pfsgroup : ""); + msg.esp = esp_buf; + + DBG(DBG_CONTROL, + DBG_log("Setting --esp=%s", msg.esp) + ) + } + msg.dpd_delay = conn->dpd_delay; + msg.dpd_timeout = conn->dpd_timeout; + msg.dpd_action = conn->dpd_action; +/* msg.dpd_count = conn->dpd_count; not supported yet by strongSwan */ + + r = send_whack_msg(&msg); + + if (r == 0 && (conn->policy & POLICY_RSASIG)) + { + r += starter_whack_add_pubkey (conn, &conn->left, "left"); + r += starter_whack_add_pubkey (conn, &conn->right, "right"); + } + + return r; +} + +int +starter_whack_del_conn(starter_conn_t *conn) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_delete = TRUE; + msg.name = connection_name(conn); + return send_whack_msg(&msg); +} + +int +starter_whack_route_conn(starter_conn_t *conn) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_route = TRUE; + msg.name = connection_name(conn); + return send_whack_msg(&msg); +} + +int +starter_whack_initiate_conn(starter_conn_t *conn) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_initiate = TRUE; + msg.whack_async = TRUE; + msg.name = connection_name(conn); + return send_whack_msg(&msg); +} + +int +starter_whack_listen(void) +{ + whack_message_t msg; + init_whack_msg(&msg); + msg.whack_listen = TRUE; + return send_whack_msg(&msg); +} + +int starter_whack_shutdown(void) +{ + whack_message_t msg; + + init_whack_msg(&msg); + msg.whack_shutdown = TRUE; + return send_whack_msg(&msg); +} + +int +starter_whack_add_ca(starter_ca_t *ca) +{ + whack_message_t msg; + + init_whack_msg(&msg); + + msg.whack_ca = TRUE; + msg.name = ca->name; + msg.cacert = ca->cacert; + msg.ldaphost = ca->ldaphost; + msg.ldapbase = ca->ldapbase; + msg.crluri = ca->crluri; + msg.crluri2 = ca->crluri2; + msg.ocspuri = ca->ocspuri; + msg.whack_strict = ca->strict; + + return send_whack_msg(&msg); +} + +int +starter_whack_del_ca(starter_ca_t *ca) +{ + whack_message_t msg; + + init_whack_msg(&msg); + + msg.whack_delete = TRUE; + msg.whack_ca = TRUE; + msg.name = ca->name; + + return send_whack_msg(&msg); +} |