diff options
author | Martin Willi <martin@strongswan.org> | 2006-05-04 07:55:42 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2006-05-04 07:55:42 +0000 |
commit | 9820c0e208fa5c7467fb89b1bda86ced6962e02f (patch) | |
tree | ff3ac9872ada7a2b52358d797395574211ff9c68 | |
parent | 8744148f554275cbeb1510018971cc936dd9aeb2 (diff) | |
download | strongswan-9820c0e208fa5c7467fb89b1bda86ced6962e02f.tar.bz2 strongswan-9820c0e208fa5c7467fb89b1bda86ced6962e02f.tar.xz |
- applied patch from andreas
- pem loading
- secrets file parsing
- ikev2 testcase
- some other additions here and there
41 files changed, 1207 insertions, 815 deletions
@@ -1,3 +1,18 @@ +strongswan-4.0.0 +---------------- + +- initial support of the IKEv2 protocol. Connections in + ipsec.conf designated by keyexchange=ikev2 are negotiated + by the new IKEv2 charon keying daemon whereas those marked + by keyexchange=ikev1 or the default keyexchange=ike are + handled thy the IKEv1 pluto keying daemon. Currently only + a limited subset of functions are available with IKEv2 + (Default AES encryption, authentication based on locally + imported X.509 certificates, unencrypted private RSA keys + in PKCS#1 file format, limited functionality of the ipsec + status command). + + strongswan-2.7.0 ---------------- @@ -1,5 +1,5 @@ --------------------------- - strongSwan - Installation + strongSwan - Installation --------------------------- @@ -11,9 +11,7 @@ Contents 2.1 libcurl 2.2 OpenLDAP 2.3 PKCS#11 smartcard library modules - 3. Building strongSwan with a Linux 2.4 kernel - 4. Updating strongSwan with a Linux 2.4 kernel - 5. Building strongSwan with a Linux 2.6 kernel + 3. Building and running strongSwan with a Linux 2.6 kernel 1. Required packages @@ -125,9 +123,9 @@ Contents in "Makefile.inc" # Uncomment this line if using OpenSC <= 0.9.6 - PKCS11_DEFAULT_LIB=\"/usr/lib/pkcs11/opensc-pkcs11.so\" + # PKCS11_DEFAULT_LIB=\"/usr/lib/pkcs11/opensc-pkcs11.so\" # Uncomment tis line if using OpenSC >= 0.10.0 - #PKCS11_DEFAULT_LIB=\"usr/lib/opensc-pkcs11.so\" + PKCS11_DEFAULT_LIB=\"usr/lib/opensc-pkcs11.so\" This default path to the easily-obtainable OpenSC library module can be simply overridden during run-time by specifying an alternative path in @@ -141,80 +139,9 @@ Contents USE="smartcard usb -pam -X" emerge strongswan -3. Building strongSwan with a Linux 2.4 kernel - ------------------------------------------- - * Building strongSwan with a Linux 2.4 kernel requires the presence of the - matching kernel sources referenced via the symbolic link /usr/src/linux. - The use of the vanilla kernel sources from ftp.kernel.org is strongly - recommended. - - Before building strongSwan you must have compiled the kernel sources at - least once: - - make menuconfig; make dep; make bzImage; make modules - - * Now change into the strongswan-2.x.x source directory. - - First uncomment any desired compile options in "programs/pluto/Makefile" - (see section 2. Optional packages). - - Then in the top source directory type - - make menumod - - This command applies an ESP_IN_UDP encapsulation patch which is required - for NAT-Traversal to the kernel sources. - - In the "Networking options" menu set - - <M> IP Security Protocol (strongSwan IPsec) - - in order to build KLIPS as a loadable kernel module "ipsec.o". Do not - forget to save the modified configuration file when leaving "menumod". - - The strongSwan userland programs are now automatically built and - installed, whereas the ipsec.o kernel module and the crypto modules - are only built and must be installed with the command - - make minstall - - * If you intend to use the NAT-Traversal feature then you must compile the - patched kernel sources again by executing - - make bzImage - - and then install and boot the modified kernel. - - * Next add your connections to "/etc/ipsec.conf" and start strongSwan with - - ipsec setup start - - -4. Updating strongSwan with a Linux 2.4 kernel - ------------------------------------------- - - * If you have already successfully installed strongSwan and want to update - to a newer version then the following shortcut can be taken: - - First uncomment any desired compile options in "programs/pluto/Makefile" - (see section 2. Optional packages). - - Then in the strongwan-2.x.x top directory type - - make programs; make install - - followed by - - make module; make minstall - - * You can then start the updated strongSwan version with - - ipsec setup restart - - -5. Building strongSwan with a Linux 2.6 kernel - ------------------------------------------- +3. Building and running strongSwan with a Linux 2.6 kernel + ------------------------------------------------------- * Because the Linux 2.6 kernel comes with a built-in native IPsec stack, you won't need to build the strongSwan kernel modules. Please make sure @@ -225,25 +152,30 @@ Contents o esp4 o ipcomp o xfrm_user + o xfrm_tunnel Also the built-in kernel Cryptoapi modules with selected encryption and hash algorithms should be available. - * First uncomment any desired compile options in "programs/pluto/Makefile" - (see section 2. Optional packages). + * First select any desired compile options in "Makefile.inc" (see section 2. + Optional packages). Then in the strongwan-4.x.x top directory type - Then in the strongwan-2.x.x top directory type - - make programs + make followed by make install - * Next add your connections to "etc/ipsec.conf" and start strongSwan with + * Next add your connections to "/etc/ipsec.conf" and your secrets to + "/etc/ipsec.secrets". Connections that are to be negotiated by the new + IKEv2 charon keying daemon should be designated by "keyexchange=ikev2" and + those by the IKEv1 pluto keying daemon either by "keyexchange=ikev1" or + the default "keyexchange=ike". + + * At last start strongSwan with - ipsec setup start + ipsec start ----------------------------------------------------------------------------- -This file is RCSID $Id: INSTALL,v 1.8 2006/01/22 16:22:23 as Exp $ +This file is RCSID $Id: INSTALL,v 1.9 2006/05/01 16:02:37 as Exp $ diff --git a/README.pluto b/README.pluto index d40d887a3..e9ebfee02 100644 --- a/README.pluto +++ b/README.pluto @@ -2650,7 +2650,7 @@ and can be used when the following prerequisites are fulfilled: - Linux 2.4.x kernel, KLIPS IPsec stack, and arbitrary iptables version. Filtering of tunneled traffic is based on ipsecN interfaces. - - Linux 2.4.16 kernel or newer, native NETKEY IPsec stack, and + - Linux 2.6.16 kernel or newer, native NETKEY IPsec stack, and iptables-1.3.5 or newer. Filtering of tunneled traffic is based on IPsec policy matching rules. diff --git a/src/charon/charon/config/credentials/local_credential_store.c b/src/charon/charon/config/credentials/local_credential_store.c index dc6cb6c50..e4fa1aa26 100644 --- a/src/charon/charon/config/credentials/local_credential_store.c +++ b/src/charon/charon/config/credentials/local_credential_store.c @@ -22,13 +22,16 @@ #include <sys/stat.h> #include <dirent.h> +#include <string.h> #include "local_credential_store.h" +#include <utils/lexparser.h> #include <utils/linked_list.h> #include <utils/logger_manager.h> #include <crypto/x509.h> +#define PATH_BUF 256 typedef struct key_entry_t key_entry_t; @@ -138,9 +141,9 @@ static rsa_private_key_t *get_rsa_private_key(private_local_credential_store_t * } /** - * Implements local_credential_store_t.load_private_keys + * Implements local_credential_store_t.load_certificates */ -static void load_certificates(private_local_credential_store_t *this, char *path) +static void load_certificates(private_local_credential_store_t *this, const char *path) { struct dirent* entry; struct stat stb; @@ -154,7 +157,8 @@ static void load_certificates(private_local_credential_store_t *this, char *path } while ((entry = readdir(dir)) != NULL) { - char file[256]; + char file[PATH_BUF]; + snprintf(file, sizeof(file), "%s/%s", path, entry->d_name); if (stat(file, &stb) == -1) @@ -168,7 +172,6 @@ static void load_certificates(private_local_credential_store_t *this, char *path if (cert) { this->certificates->insert_last(this->certificates, (void*)cert); - this->logger->log(this->logger, CONTROL|LEVEL1, "loaded certificate \"%s\"", file); } else { @@ -218,55 +221,118 @@ static identification_t *get_id_for_private_key(private_local_credential_store_t /** * Implements local_credential_store_t.load_private_keys */ -static void load_private_keys(private_local_credential_store_t *this, char *path) +static void load_private_keys(private_local_credential_store_t *this, const char *secretsfile, const char *defaultpath) { - struct dirent* entry; - struct stat stb; - DIR* dir; - rsa_private_key_t *key; - - dir = opendir(path); - if (dir == NULL) { - this->logger->log(this->logger, ERROR, "error opening private key directory \"%s\"", path); - return; - } - while ((entry = readdir(dir)) != NULL) + FILE *fd = fopen(secretsfile, "r"); + + if (fd) { - char file[256]; - snprintf(file, sizeof(file), "%s/%s", path, entry->d_name); - - if (stat(file, &stb) == -1) - { - continue; - } - /* try to parse all regular files */ - if (stb.st_mode & S_IFREG) + int bytes; + int line_nr = 0; + chunk_t chunk, src, line; + + this->logger->log(this->logger, CONTROL, "loading secrets from \"%s\"", secretsfile); + + fseek(fd, 0, SEEK_END); + chunk.len = ftell(fd); + rewind(fd); + chunk.ptr = malloc(chunk.len); + bytes = fread(chunk.ptr, 1, chunk.len, fd); + fclose(fd); + + src = chunk; + + while (fetchline(&src, &line)) { - key = rsa_private_key_create_from_file(file, NULL); - if (key) + chunk_t ids, token; + + line_nr++; + + if (!eat_whitespace(&line)) { - key_entry_t *entry; - identification_t *id = get_id_for_private_key(this, key); - if (!id) + continue; + } + if (!extract_token(&ids, ':', &line)) + { + this->logger->log(this->logger, ERROR, "line %d: missing ':' separator", line_nr); + goto error; + } + if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line)) + { + this->logger->log(this->logger, ERROR, "line %d: missing token", line_nr); + goto error; + } + if (match("RSA", &token)) + { + char path[PATH_BUF]; + chunk_t filename; + + err_t ugh = extract_value(&filename, &line); + + if (ugh != NULL) + { + this->logger->log(this->logger, ERROR, "line %d: %s", line_nr, ugh); + goto error; + } + if (filename.len == 0) + { + this->logger->log(this->logger, ERROR, + "line %d: empty filename", line_nr); + goto error; + } + if (*filename.ptr == '/') + { + /* absolute path name */ + snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr); + } + else { - this->logger->log(this->logger, ERROR, - "no certificate found for private key \"%s\", skipped", file); - key->destroy(key); - continue; + /* relative path name */ + snprintf(path, sizeof(path), "%s/%.*s", defaultpath, filename.len, filename.ptr); } - entry = malloc_thing(key_entry_t); - entry->key = key; - entry->id = id; - this->private_keys->insert_last(this->private_keys, (void*)entry); - this->logger->log(this->logger, CONTROL|LEVEL1, "loaded private key \"%s\"", file); + + rsa_private_key_t *key = rsa_private_key_create_from_file(path, NULL); + if (key) + { + key_entry_t *entry; + identification_t *id = get_id_for_private_key(this, key); + + if (!id) + { + this->logger->log(this->logger, ERROR, + "no certificate found for private key \"%s\", skipped", path); + key->destroy(key); + continue; + } + entry = malloc_thing(key_entry_t); + entry->key = key; + entry->id = id; + this->private_keys->insert_last(this->private_keys, (void*)entry); + } + } + else if (match("PSK", &token)) + { + + } + else if (match("PIN", &token)) + { + } else { - this->logger->log(this->logger, ERROR, "private key \"%s\" invalid, skipped", file); + this->logger->log(this->logger, ERROR, + "line %d: token must be either RSA, PSK, or PIN", + line_nr, token.len); + goto error; } } +error: + free(chunk.ptr); + } + else + { + this->logger->log(this->logger, ERROR, "could not open file '%s'", secretsfile); } - closedir(dir); } /** @@ -302,8 +368,8 @@ local_credential_store_t * local_credential_store_create() this->public.credential_store.get_shared_secret = (status_t(*)(credential_store_t*,identification_t*,chunk_t*))get_shared_secret; this->public.credential_store.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,identification_t*))get_rsa_private_key; this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key; - this->public.load_certificates = (void(*)(local_credential_store_t*,char*))load_certificates; - this->public.load_private_keys = (void(*)(local_credential_store_t*,char*))load_private_keys; + this->public.load_certificates = (void(*)(local_credential_store_t*,const char*))load_certificates; + this->public.load_private_keys = (void(*)(local_credential_store_t*,const char*, const char*))load_private_keys; this->public.credential_store.destroy = (void(*)(credential_store_t*))destroy; /* private variables */ diff --git a/src/charon/charon/config/credentials/local_credential_store.h b/src/charon/charon/config/credentials/local_credential_store.h index ab9ef88d7..64438b378 100644 --- a/src/charon/charon/config/credentials/local_credential_store.h +++ b/src/charon/charon/config/credentials/local_credential_store.h @@ -57,7 +57,7 @@ struct local_credential_store_t { * @param this calling object * @param path directory to load certificates from */ - void (*load_certificates) (local_credential_store_t *this, char *path); + void (*load_certificates) (local_credential_store_t *this, const char *path); /** * @brief Loads RSA private keys from a folder. @@ -66,10 +66,11 @@ struct local_credential_store_t { * other gets ignored. Further, a certificate for the specific private * key must already be loaded to get the ID from. * - * @param this calling object - * @param path directory to load keys from + * @param this calling object + * @param secretsfile file where secrets are stored + * @param defaultpath default directory for private keys */ - void (*load_private_keys) (local_credential_store_t *this, char *path); + void (*load_private_keys) (local_credential_store_t *this, const char *secretsfile, const char *defaultpath); }; /** diff --git a/src/charon/charon/daemon.c b/src/charon/charon/daemon.c index 4b0ea54e8..f3d9fecdb 100644 --- a/src/charon/charon/daemon.c +++ b/src/charon/charon/daemon.c @@ -179,7 +179,7 @@ static void initialize(private_daemon_t *this) /* load keys & certs */ cred_store->load_certificates(cred_store, CERTIFICATE_DIR); - cred_store->load_private_keys(cred_store, PRIVATE_KEY_DIR); + cred_store->load_private_keys(cred_store, SECRETS_FILE, PRIVATE_KEY_DIR); /* start building threads, we are multi-threaded NOW */ diff --git a/src/charon/charon/daemon.h b/src/charon/charon/daemon.h index 5aee21fdb..5cad1339b 100644 --- a/src/charon/charon/daemon.h +++ b/src/charon/charon/daemon.h @@ -203,11 +203,18 @@ #define PID_FILE "/var/run/charon.pid" /** + * Configuration directory + * + * @ingroup charon + */ +#define CONFIG_DIR "/etc" + +/** * Directory of IPsec relevant files * * @ingroup charon */ -#define IPSEC_DIR "/etc/ipsec.d" +#define IPSEC_DIR CONFIG_DIR "/ipsec.d" /** * Directory for private keys @@ -223,6 +230,12 @@ */ #define CERTIFICATE_DIR IPSEC_DIR "/certs" +/** + * Secrets files + * + * @ingroup charon + */ +#define SECRETS_FILE CONFIG_DIR "/ipsec.secrets" typedef struct daemon_t daemon_t; diff --git a/src/charon/charon/threads/stroke_interface.c b/src/charon/charon/threads/stroke_interface.c index eeb14cd94..0a7ba80a6 100755 --- a/src/charon/charon/threads/stroke_interface.c +++ b/src/charon/charon/threads/stroke_interface.c @@ -241,8 +241,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) my_id = my_id->clone(my_id); cert->destroy(cert); this->logger->log(this->logger, CONTROL, - "defined a valid certificate, using its ID \"%s\"", - my_id->get_string(my_id)); + "valid certificate with ID \"%s\"", + my_id->get_string(my_id)); } } if (msg->add_conn.other.cert) @@ -257,8 +257,8 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) other_id = other_id->clone(other_id); cert->destroy(cert); this->logger->log(this->logger, CONTROL, - "defined a valid certificate, using its ID \"%s\"", - other_id->get_string(other_id)); + "valid certificate with ID \"%s\"", + other_id->get_string(other_id)); } } @@ -308,7 +308,7 @@ static void stroke_initiate(private_stroke_t *this, stroke_msg_t *msg) connection = charon->connections->get_connection_by_name(charon->connections, msg->initiate.name); if (connection == NULL) { - this->stroke_logger->log(this->stroke_logger, ERROR, "could not find a connection named \"%s\"", msg->initiate.name); + this->stroke_logger->log(this->stroke_logger, ERROR, "no connection named \"%s\"", msg->initiate.name); } else { diff --git a/src/charon/lib/asn1/asn1.c b/src/charon/lib/asn1/asn1.c index c847461b6..e894999fb 100644 --- a/src/charon/lib/asn1/asn1.c +++ b/src/charon/lib/asn1/asn1.c @@ -21,8 +21,6 @@ #include <utils/logger_manager.h> -static logger_t *logger; - /* Names of the months */ static const char* months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", @@ -87,7 +85,18 @@ static const asn1Object_t algorithmIdentifierObjects[] = { #define ALGORITHM_ID_PARAMETERS 2 #define ALGORITHM_ID_ROOF 3 -/* +static logger_t *logger = NULL; + +/** + * initializes the ASN.1 logger + */ +static void asn1_init_logger() +{ + if (logger == NULL) + logger = logger_manager->get_logger(logger_manager, ASN1); +} + +/** * return the ASN.1 encoded algorithm identifier */ chunk_t asn1_algorithmIdentifier(int oid) @@ -109,7 +118,7 @@ chunk_t asn1_algorithmIdentifier(int oid) } } -/* +/** * If the oid is listed in the oid_names table then the corresponding * position in the oid_names table is returned otherwise -1 is returned */ @@ -141,7 +150,7 @@ int known_oid(chunk_t object) return -1; } -/* +/** * Decodes the length in bytes of an ASN.1 object */ u_int asn1_length(chunk_t *blob) @@ -188,7 +197,7 @@ u_int asn1_length(chunk_t *blob) return len; } -/* +/** * determines if a character string is of type ASN.1 printableString */ bool is_printablestring(chunk_t str) @@ -205,9 +214,9 @@ bool is_printablestring(chunk_t str) return TRUE; } -/* +/** * Display a date either in local or UTC time - * TODO: Does not seem to be thread save + * TODO: Does not seem to be thread safe */ char* timetoa(const time_t *time, bool utc) { @@ -225,7 +234,7 @@ char* timetoa(const time_t *time, bool utc) return buf; } -/* +/** * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time */ time_t asn1totime(const chunk_t *utctime, asn1_t type) @@ -300,19 +309,20 @@ time_t asn1totime(const chunk_t *utctime, asn1_t type) return mktime(&t) - timezone - tz_offset; } -/* +/** * Initializes the internal context of the ASN.1 parser */ void asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0, bool implicit) { - logger = logger_manager->get_logger(logger_manager, ASN1); + asn1_init_logger(); + ctx->blobs[0] = blob; ctx->level0 = level0; ctx->implicit = implicit; memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr)); } -/* +/** * print the value of an ASN.1 simple object */ static void debug_asn1_simple_object(chunk_t object, asn1_t type) @@ -348,7 +358,7 @@ static void debug_asn1_simple_object(chunk_t object, asn1_t type) logger->log_chunk(logger, RAW|LEVEL1, "", object); } -/* +/** * Parses and extracts the next ASN.1 object */ bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx) @@ -479,7 +489,7 @@ bool extract_object(asn1Object_t const *objects, u_int *objectID, chunk_t *objec return TRUE; } -/* +/** * parse an ASN.1 simple type */ bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const char* name) @@ -515,7 +525,7 @@ bool parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level, const c return TRUE; } -/* +/** * extracts an algorithmIdentifier */ int parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters) @@ -558,6 +568,8 @@ bool is_asn1(chunk_t blob) u_int len; u_char tag = *blob.ptr; + asn1_init_logger(); + if (tag != ASN1_SEQUENCE && tag != ASN1_SET) { logger->log(logger, ERROR|LEVEL2, " file content is not binary ASN.1"); @@ -572,7 +584,7 @@ bool is_asn1(chunk_t blob) return TRUE; } -/* +/** * codes ASN.1 lengths up to a size of 16'777'215 bytes */ void code_asn1_length(size_t length, chunk_t *code) @@ -605,7 +617,7 @@ void code_asn1_length(size_t length, chunk_t *code) } } -/* +/** * build an empty asn.1 object with tag and length fields already filled in */ u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen) @@ -634,7 +646,7 @@ u_char* build_asn1_object(chunk_t *object, asn1_t type, size_t datalen) return pos; } -/* +/** * build a simple ASN.1 object */ chunk_t asn1_simple_object(asn1_t tag, chunk_t content) @@ -648,7 +660,8 @@ chunk_t asn1_simple_object(asn1_t tag, chunk_t content) return object; } -/* Build an ASN.1 object from a variable number of individual chunks. +/** + * Build an ASN.1 object from a variable number of individual chunks. * Depending on the mode, chunks either are moved ('m') or copied ('c'). */ chunk_t asn1_wrap(asn1_t type, const char *mode, ...) @@ -696,7 +709,7 @@ chunk_t asn1_wrap(asn1_t type, const char *mode, ...) return construct; } -/* +/** * convert a MP integer into a DER coded ASN.1 object */ chunk_t asn1_integer_from_mpz(const mpz_t value) @@ -709,7 +722,7 @@ chunk_t asn1_integer_from_mpz(const mpz_t value) return asn1_wrap(ASN1_INTEGER, "m", n); } -/* +/** * convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format */ chunk_t timetoasn1(const time_t *time, asn1_t type) diff --git a/src/charon/lib/asn1/pem.c b/src/charon/lib/asn1/pem.c index b02268dd9..d3a6986eb 100755 --- a/src/charon/lib/asn1/pem.c +++ b/src/charon/lib/asn1/pem.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2005 Jan Hutter, Martin Willi - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur * * 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 @@ -21,14 +20,27 @@ #include <stddef.h> #include <sys/types.h> +#include "asn1.h" #include "pem.h" #include "ttodata.h" +#include <utils/lexparser.h> +#include <utils/logger_manager.h> #include <crypto/hashers/hasher.h> #include <crypto/crypters/crypter.h> +static logger_t *logger = NULL; -/* +/** + * initializes the PEM logger + */ +static void pem_init_logger() +{ + if (logger == NULL) + logger = logger_manager->get_logger(logger_manager, ASN1); +} + +/** * check the presence of a pattern in a character string */ static bool present(const char* pattern, chunk_t* ch) @@ -44,15 +56,7 @@ static bool present(const char* pattern, chunk_t* ch) return FALSE; } -/* - * compare string with chunk - */ -static bool match(const char *pattern, const chunk_t *ch) -{ - return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0; -} - -/* +/** * find a boundary of the form -----tag name----- */ static bool find_boundary(const char* tag, chunk_t *line) @@ -73,6 +77,8 @@ static bool find_boundary(const char* tag, chunk_t *line) { if (present("-----", line)) { + logger->log(logger, CONTROL|LEVEL2, + " -----%s %.*s-----", tag, (int)name.len, name.ptr); return TRUE; } line->ptr++; line->len--; name.len++; @@ -81,92 +87,15 @@ static bool find_boundary(const char* tag, chunk_t *line) } /* - * eat whitespace - */ -static void eat_whitespace(chunk_t *src) -{ - while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t')) - { - src->ptr++; src->len--; - } -} - -/* - * extracts a token ending with a given termination symbol - */ -static bool extract_token(chunk_t *token, char termination, chunk_t *src) -{ - u_char *eot = memchr(src->ptr, termination, src->len); - - /* initialize empty token */ - *token = CHUNK_INITIALIZER; - - if (eot == NULL) /* termination symbol not found */ - { - return FALSE; - } - - /* extract token */ - token->ptr = src->ptr; - token->len = (u_int)(eot - src->ptr); - - /* advance src pointer after termination symbol */ - src->ptr = eot + 1; - src->len -= (token->len + 1); - - return TRUE; -} - -/* - * extracts a name: value pair from the PEM header - */ -static bool extract_parameter(chunk_t *name, chunk_t *value, chunk_t *line) -{ - /* extract name */ - if (!extract_token(name,':', line)) - { - return FALSE; - } - - eat_whitespace(line); - - /* extract value */ - *value = *line; - return TRUE; -} - -/* - * fetches a new line terminated by \n or \r\n - */ -static bool fetchline(chunk_t *src, chunk_t *line) -{ - if (src->len == 0) /* end of src reached */ - return FALSE; - - if (extract_token(line, '\n', src)) - { - if (line->len > 0 && *(line->ptr + line->len -1) == '\r') - line->len--; /* remove optional \r */ - } - else /*last line ends without newline */ - { - *line = *src; - src->ptr += src->len; - src->len = 0; - } - return TRUE; -} - -/* * decrypts a DES-EDE-CBC encrypted data block */ -static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase) +static err_t pem_decrypt(chunk_t *blob, chunk_t *iv, const char *passphrase) { hasher_t *hasher; crypter_t *crypter; chunk_t hash; chunk_t decrypted; - chunk_t pass = {passphrase, strlen(passphrase)}; + chunk_t pass = {(char*)passphrase, strlen(passphrase)}; chunk_t key = {alloca(24), 24}; u_int8_t padding, *last_padding_pos, *first_padding_pos; @@ -203,11 +132,11 @@ static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase) while (--last_padding_pos > first_padding_pos) { if (*last_padding_pos != padding) - return FALSE; + return "invalid passphrase"; } /* remove padding */ blob->len -= padding; - return TRUE; + return NULL; } /* Converts a PEM encoded file into its binary form @@ -215,7 +144,7 @@ static status_t pem_decrypt(chunk_t *blob, chunk_t *iv, char *passphrase) * RFC 1421 Privacy Enhancement for Electronic Mail, February 1993 * RFC 934 Message Encapsulation, January 1985 */ -status_t pemtobin(chunk_t *blob, char *pass) +err_t pem_to_bin(chunk_t *blob, const char *passphrase, bool *pgp) { typedef enum { PEM_PRE = 0, @@ -244,6 +173,8 @@ status_t pemtobin(chunk_t *blob, char *pass) iv.ptr = iv_buf; iv.len = 0; + pem_init_logger(); + while (fetchline(&src, &line)) { if (state == PEM_PRE) @@ -277,8 +208,9 @@ status_t pemtobin(chunk_t *blob, char *pass) continue; } - /* we are looking for a name: value pair */ - if (!extract_parameter(&name, &value, &line)) + /* we are looking for a parameter: value pair */ + logger->log(logger, CONTROL|LEVEL2, " %.*s", (int)line.len, line.ptr); + if (!extract_parameter_value(&name, &value, &line)) continue; if (match("Proc-Type", &name) && *value.ptr == '4') @@ -294,12 +226,12 @@ status_t pemtobin(chunk_t *blob, char *pass) /* we support DES-EDE3-CBC encrypted files, only */ if (!match("DES-EDE3-CBC", &dek)) - return NOT_SUPPORTED; + return "encryption algorithm not supported"; eat_whitespace(&value); ugh = ttodata(value.ptr, value.len, 16, iv.ptr, 16, &len); if (ugh) - return PARSE_ERROR; + return "error in IV"; iv.len = len; } @@ -316,6 +248,17 @@ status_t pemtobin(chunk_t *blob, char *pass) data = line; } + /* check for PGP armor checksum */ + if (*data.ptr == '=') + { + *pgp = TRUE; + data.ptr++; + data.len--; + logger->log(logger, CONTROL|LEVEL2, " Armor checksum: %.*s", + (int)data.len, data.ptr); + continue; + } + ugh = ttodata(data.ptr, data.len, 64, dst.ptr, blob->len - dst.len, &len); if (ugh) { @@ -334,10 +277,68 @@ status_t pemtobin(chunk_t *blob, char *pass) blob->len = dst.len; if (state != PEM_POST) - return PARSE_ERROR; + return "file coded in unknown format, discarded"; + + return (encrypted)? pem_decrypt(blob, &iv, passphrase) : NULL; +} + +/* load a coded key or certificate file with autodetection + * of binary DER or base64 PEM ASN.1 formats and armored PGP format + */ +bool pem_asn1_load_file(const char *filename, const char *passphrase, + const char *type, chunk_t *blob, bool *pgp) +{ + err_t ugh = NULL; + + FILE *fd = fopen(filename, "r"); + + pem_init_logger(); + + if (fd) + { + int bytes; + fseek(fd, 0, SEEK_END ); + blob->len = ftell(fd); + rewind(fd); + blob->ptr = malloc(blob->len); + bytes = fread(blob->ptr, 1, blob->len, fd); + fclose(fd); + logger->log(logger, CONTROL, "loaded %s file '%s' (%d bytes)", type, filename, bytes); + + *pgp = FALSE; + + /* try DER format */ + if (is_asn1(*blob)) + { + logger->log(logger, CONTROL|LEVEL1, " file coded in DER format"); + return TRUE; + } + + /* try PEM format */ + ugh = pem_to_bin(blob, passphrase, pgp); + + if (ugh == NULL) + { + if (*pgp) + { + logger->log(logger, CONTROL|LEVEL1, " file coded in armored PGP format"); + return TRUE; + } + if (is_asn1(*blob)) + { + logger->log(logger, CONTROL|LEVEL1, " file coded in PEM format"); + return TRUE; + } + ugh = "file coded in unknown format, discarded"; + } - if (encrypted) - return pem_decrypt(blob, &iv, pass); + /* a conversion error has occured */ + logger->log(logger, ERROR, " %s", ugh); + chunk_free(blob); + } else - return SUCCESS; + { + logger->log(logger, ERROR, "could not open %s file '%s'", type, filename); + } + return FALSE; } diff --git a/src/charon/lib/asn1/pem.h b/src/charon/lib/asn1/pem.h index a4332fd34..30621fa24 100755 --- a/src/charon/lib/asn1/pem.h +++ b/src/charon/lib/asn1/pem.h @@ -1,6 +1,5 @@ /* - * Copyright (C) 2006 Martin Willi - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2001-2004 Andreas Steffen, Zuercher Hochschule Winterthur * * 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 @@ -20,6 +19,9 @@ #include <types.h> -status_t pemtobin(chunk_t *blob, char *pass); +err_t pem_to_bin(chunk_t *blob, const char *passphrase, bool *pgp); + +bool pem_asn1_load_file(const char *filename, const char *passphrase, + const char *type, chunk_t *blob, bool *pgp); #endif /*PEM_H_*/ diff --git a/src/charon/lib/asn1/ttodata.h b/src/charon/lib/asn1/ttodata.h index d57244ef5..b2b5adefd 100644 --- a/src/charon/lib/asn1/ttodata.h +++ b/src/charon/lib/asn1/ttodata.h @@ -22,8 +22,6 @@ #define TTODATAV_IGNORESPACE (1<<1) /* ignore spaces in base64 encodings*/ #define TTODATAV_SPACECOUNTS 0 /* do not ignore spaces in base64 */ -typedef const char *err_t; /* error message, or NULL for success */ - err_t ttodata(const char *src, size_t srclen, int base, char *buf, size_t buflen, size_t *needed); diff --git a/src/charon/lib/crypto/rsa/rsa_private_key.c b/src/charon/lib/crypto/rsa/rsa_private_key.c index 358653f0e..86a38cbfe 100644 --- a/src/charon/lib/crypto/rsa/rsa_private_key.c +++ b/src/charon/lib/crypto/rsa/rsa_private_key.c @@ -29,6 +29,7 @@ #include <daemon.h> #include <asn1/asn1.h> +#include <asn1/pem.h> /* * Oids for hash algorithms are defined in @@ -736,37 +737,17 @@ rsa_private_key_t *rsa_private_key_create_from_chunk(chunk_t blob) /* * see header - * TODO: PEM files */ rsa_private_key_t *rsa_private_key_create_from_file(char *filename, char *passphrase) { - chunk_t chunk; - struct stat stb; - FILE *file; - char *buffer; - - if (stat(filename, &stb) == -1) - { - return NULL; - } - - buffer = alloca(stb.st_size); - - file = fopen(filename, "r"); - if (file == NULL) - { - return NULL; - } - - if (fread(buffer, stb.st_size, 1, file) != 1) - { - fclose(file); + bool pgp = FALSE; + chunk_t chunk = CHUNK_INITIALIZER; + rsa_private_key_t *key = NULL; + + if (!pem_asn1_load_file(filename, passphrase, "private key", &chunk, &pgp)) return NULL; - } - fclose(file); - - chunk.ptr = buffer; - chunk.len = stb.st_size; - - return rsa_private_key_create_from_chunk(chunk); + + key = rsa_private_key_create_from_chunk(chunk); + free(chunk.ptr); + return key; } diff --git a/src/charon/lib/crypto/x509.c b/src/charon/lib/crypto/x509.c index 86a595618..91f9f191e 100755 --- a/src/charon/lib/crypto/x509.c +++ b/src/charon/lib/crypto/x509.c @@ -28,13 +28,11 @@ #include "x509.h" #include <daemon.h> -#include <asn1/asn1.h> #include <asn1/oid.h> +#include <asn1/asn1.h> +#include <asn1/pem.h> #include <utils/logger_manager.h> -typedef const char *err_t; /* error message, or NULL for success */ - - #define BUF_LEN 512 #define RSA_MIN_OCTETS (512 / 8) #define RSA_MIN_OCTETS_UGH "RSA modulus too small for security: less than 512 bits" @@ -905,33 +903,14 @@ x509_t *x509_create_from_chunk(chunk_t chunk) */ x509_t *x509_create_from_file(char *filename) { - struct stat stb; - FILE *file; - char *buffer; - chunk_t chunk; - - if (stat(filename, &stb) == -1) - { - return NULL; - } - - buffer = alloca(stb.st_size); - - file = fopen(filename, "r"); - if (file == NULL) - { - return NULL; - } - - if (fread(buffer, stb.st_size, 1, file) == -1) - { - fclose(file); + bool pgp = FALSE; + chunk_t chunk = CHUNK_INITIALIZER; + x509_t *cert = NULL; + + if (!pem_asn1_load_file(filename, "", "certificate", &chunk, &pgp)) return NULL; - } - fclose(file); - - chunk.ptr = buffer; - chunk.len = stb.st_size; - - return x509_create_from_chunk(chunk); + + cert = x509_create_from_chunk(chunk); + free(chunk.ptr); + return cert; } diff --git a/src/charon/lib/types.h b/src/charon/lib/types.h index 0e0782b31..4af9bc43d 100644 --- a/src/charon/lib/types.h +++ b/src/charon/lib/types.h @@ -37,6 +37,11 @@ typedef int bool; #define FALSE 0 #define TRUE 1 +/** + * error message, or NULL for success + */ +typedef const char *err_t; + typedef enum status_t status_t; /** diff --git a/src/charon/lib/utils/Makefile.utils b/src/charon/lib/utils/Makefile.utils index 1c82283d7..c04f3b1df 100644 --- a/src/charon/lib/utils/Makefile.utils +++ b/src/charon/lib/utils/Makefile.utils @@ -18,10 +18,14 @@ LIB_OBJS+= $(BUILD_DIR)leak_detective.o $(BUILD_DIR)leak_detective.o : $(UTILS_DIR)leak_detective.c $(UTILS_DIR)leak_detective.h $(CC) $(CFLAGS) -c -o $@ $< +LIB_OBJS+= $(BUILD_DIR)lexparser.o +$(BUILD_DIR)lexparser.o : $(UTILS_DIR)lexparser.c $(UTILS_DIR)lexparser.h + $(CC) $(CFLAGS) -c -o $@ $< + LIB_OBJS+= $(BUILD_DIR)linked_list.o $(BUILD_DIR)linked_list.o : $(UTILS_DIR)linked_list.c $(UTILS_DIR)linked_list.h $(CC) $(CFLAGS) -c -o $@ $< - + LIB_OBJS+= $(BUILD_DIR)logger.o $(BUILD_DIR)logger.o : $(UTILS_DIR)logger.c $(UTILS_DIR)logger.h $(CC) $(CFLAGS) -c -o $@ $< diff --git a/src/charon/lib/utils/lexparser.c b/src/charon/lib/utils/lexparser.c new file mode 100644 index 000000000..e3bb3d1f9 --- /dev/null +++ b/src/charon/lib/utils/lexparser.c @@ -0,0 +1,135 @@ +/** + * @file lexparser.c + * + * @brief lexical parser for text-based configuration files + * + */ + +/* + * Copyright (C) 2001-2006 Andreas Steffen, Zuercher Hochschule Winterthur + * + * 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. + */ + +#include <string.h> + +#include "lexparser.h" + + +/** + * eat whitespace + */ +bool eat_whitespace(chunk_t *src) +{ + while (src->len > 0 && (*src->ptr == ' ' || *src->ptr == '\t')) + { + src->ptr++; src->len--; + } + return src->len > 0 && *src->ptr != '#'; +} + +/** + * compare string with chunk + */ +bool match(const char *pattern, const chunk_t *ch) +{ + return ch->len == strlen(pattern) && strncmp(pattern, ch->ptr, ch->len) == 0; +} + +/** + * extracts a token ending with a given termination symbol + */ +bool extract_token(chunk_t *token, const char termination, chunk_t *src) +{ + u_char *eot = memchr(src->ptr, termination, src->len); + + /* initialize empty token */ + *token = CHUNK_INITIALIZER; + + if (eot == NULL) /* termination symbol not found */ + { + return FALSE; + } + + /* extract token */ + token->ptr = src->ptr; + token->len = (u_int)(eot - src->ptr); + + /* advance src pointer after termination symbol */ + src->ptr = eot + 1; + src->len -= (token->len + 1); + + return TRUE; +} + +/** + * fetches a new line terminated by \n or \r\n + */ +bool fetchline(chunk_t *src, chunk_t *line) +{ + if (src->len == 0) /* end of src reached */ + return FALSE; + + if (extract_token(line, '\n', src)) + { + if (line->len > 0 && *(line->ptr + line->len -1) == '\r') + line->len--; /* remove optional \r */ + } + else /*last line ends without newline */ + { + *line = *src; + src->ptr += src->len; + src->len = 0; + } + return TRUE; +} + +err_t extract_value(chunk_t *value, chunk_t *line) +{ + char delimiter = ' '; + + if (!eat_whitespace(line)) + { + return "missing value"; + } + if (*line->ptr == '\'' || *line->ptr == '"') + { + delimiter = *line->ptr; + line->ptr++; line->len--; + } + if (!extract_token(value, delimiter, line)) + { + if (delimiter == ' ') + { + *value = *line; + } + else + { + return "missing second delimiter"; + } + } + return NULL; +} + +/** + * extracts a parameter: value pair + */ +err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line) +{ + /* extract name */ + if (!extract_token(name,':', line)) + { + return "missing ':'"; + } + + /* extract value */ + return extract_value(value, line); +} diff --git a/src/charon/lib/utils/lexparser.h b/src/charon/lib/utils/lexparser.h new file mode 100644 index 000000000..29c1bf701 --- /dev/null +++ b/src/charon/lib/utils/lexparser.h @@ -0,0 +1,57 @@ +/** + * @file lexparser.h + * + * @brief lexical parser for text-based configuration files + * + */ + +/* + * Copyright (C) 2001-2006 Andreas Steffen, Zuercher Hochschule Winterthur + * + * 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. + */ + +#include <types.h> + +/** + * @brief Eats whitespace + */ +bool eat_whitespace(chunk_t *src); + +/** + * @brief Compare null-terminated pattern with chunk + */ +bool match(const char *pattern, const chunk_t *ch); + +/** + * @brief Extracts a token ending with a given termination symbol + */ +bool extract_token(chunk_t *token, const char termination, chunk_t *src); + +/** + * @brief Fetches a new text line terminated by \n or \r\n + */ +bool fetchline(chunk_t *src, chunk_t *line); + +/** + * @brief Extracts a value that might be single or double quoted + */ +err_t extract_value(chunk_t *value, chunk_t *line); + +/** + * @brief extracts a name: value pair from a text line + */ +err_t extract_name_value(chunk_t *name, chunk_t *value, chunk_t *line); + +/** + * @brief extracts a parameter: value from a text line + */ +err_t extract_parameter_value(chunk_t *name, chunk_t *value, chunk_t *line); diff --git a/src/charon/lib/utils/logger.c b/src/charon/lib/utils/logger.c index fdaeddff0..151fbfd50 100644 --- a/src/charon/lib/utils/logger.c +++ b/src/charon/lib/utils/logger.c @@ -132,11 +132,15 @@ static void prepend_prefix(private_logger_t *this, log_level_t loglevel, const c */ static int get_priority(log_level_t loglevel) { + if (loglevel & ERROR) + { + return LOG_AUTHPRIV|LOG_ERR; + } if (loglevel & AUDIT) { return LOG_AUTHPRIV|LOG_INFO; } - return LOG_DAEMON|LOG_DEBUG; + return LOG_AUTHPRIV|LOG_DEBUG; } /** diff --git a/src/charon/stroke/stroke.c b/src/charon/stroke/stroke.c index 9ecda0413..7a734a05f 100644 --- a/src/charon/stroke/stroke.c +++ b/src/charon/stroke/stroke.c @@ -239,19 +239,21 @@ static void exit_usage(char *error) int main(int argc, char *argv[]) { int res; + char *op; if (argc < 2) { exit_usage(NULL); } - if (strcmp(argv[1], "status") == 0 || - strcmp(argv[1], "statusall") == 0) + op = argv[1]; + + if (strcmp(op, "status") == 0 || + strcmp(op, "statusall") == 0) { - res = show_status(argv[1], argc > 2 ? argv[2] : NULL); + res = show_status(op, argc > 2 ? argv[2] : NULL); } - - else if (strcmp(argv[1], "up") == 0) + else if (strcmp(op, "up") == 0) { if (argc < 3) { @@ -259,7 +261,7 @@ int main(int argc, char *argv[]) } res = initiate_connection(argv[2]); } - else if (strcmp(argv[1], "down") == 0) + else if (strcmp(op, "down") == 0) { if (argc < 3) { @@ -267,7 +269,7 @@ int main(int argc, char *argv[]) } res = terminate_connection(argv[2]); } - else if (strcmp(argv[1], "add") == 0) + else if (strcmp(op, "add") == 0) { if (argc < 11) { @@ -279,7 +281,7 @@ int main(int argc, char *argv[]) argv[7], argv[8], atoi(argv[9]), atoi(argv[10])); } - else if (strcmp(argv[1], "logtype") == 0) + else if (strcmp(op, "logtype") == 0) { if (argc < 5) { @@ -287,7 +289,7 @@ int main(int argc, char *argv[]) } res = set_logtype(argv[2], argv[3], atoi(argv[4])); } - else if (strcmp(argv[1], "loglevel") == 0) + else if (strcmp(op, "loglevel") == 0) { if (argc < 4) { diff --git a/src/ipsec/distro.txt b/src/ipsec/distro.txt index 80f4192a4..8c1ad8a38 100644 --- a/src/ipsec/distro.txt +++ b/src/ipsec/distro.txt @@ -1 +1,2 @@ -distributed by Andreas Steffen <andreas.steffen@strongswan.org> +distributed by the Institute of Internet Technologies and Applications +University of Applied Sciences Rapperswil, Switzerland (ITA-HSR) diff --git a/src/ipsec/ipsec.in b/src/ipsec/ipsec.in index 04156e8ae..1a5006eed 100755 --- a/src/ipsec/ipsec.in +++ b/src/ipsec/ipsec.in @@ -1,6 +1,7 @@ #! /bin/sh # prefix command to run stuff from our programs directory # Copyright (C) 1998-2002 Henry Spencer. +# Copyright (C) 2006 Andreas Steffen # # 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 @@ -26,6 +27,7 @@ IPSEC_DIR="$IPSEC_LIBDIR" export IPSEC_DIR IPSEC_CONFS IPSEC_LIBDIR IPSEC_EXECDIR IPSEC_STARTER_PID="/var/run/starter.pid" +IPSEC_PLUTO_PID="/var/run/pluto.pid" IPSEC_CHARON_PID="/var/run/charon.pid" # standardize PATH, and export it for everything else's benefit @@ -123,10 +125,13 @@ case "$1" in ;; down) shift - $IPSEC_EXECDIR/whack --name "$1" --terminate + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack --name "$1" --terminate + fi if test -e $IPSEC_CHARON_PID then - $IPSEC_EXECDIR/stroke down "$1" + $IPSEC_EXECDIR/stroke down "$1" fi exit 0 ;; @@ -138,16 +143,22 @@ rereadcacerts|rereadaacerts|rereadocspcerts|\ rereadacerts|rereadcrls|rereadall) op="$1" shift - $IPSEC_EXECDIR/whack "$@" "--$op" - if test -e $IPSEC_CHARON_PID + if test -e $IPSEC_PLUTO_PID then - $IPSEC_EXECDIR/stroke "$op" - fi + $IPSEC_EXECDIR/whack "$@" "--$op" + fi + #if test -e $IPSEC_CHARON_PID + #then + # $IPSEC_EXECDIR/stroke "$op" + #fi exit 0 ;; ready) shift - $IPSEC_EXECDIR/whack --listen + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack --listen + fi exit 0 ;; reload) @@ -170,19 +181,28 @@ restart) route|unroute) op="$1" shift - $IPSEC_EXECDIR/whack --name "$1" "--$op" + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack --name "$1" "--$op" + fi exit 0 ;; scencrypt|scdecrypt) op="$1" shift - $IPSEC_EXECDIR/whack "--$op" "$@" + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack "--$op" "$@" + fi exit 0 ;; secrets) - $IPSEC_EXECDIR/whack --rereadsecrets - exit 0 - ;; + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack --rereadsecrets + fi + exit 0 + ;; start) shift exec $IPSEC_EXECDIR/starter "$@" @@ -192,17 +212,23 @@ status|statusall) shift if test $# -eq 0 then - $IPSEC_EXECDIR/whack "--$op" - if test -e $IPSEC_CHARON_PID - then - $IPSEC_EXECDIR/stroke "$op" - fi + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack "--$op" + fi + if test -e $IPSEC_CHARON_PID + then + $IPSEC_EXECDIR/stroke "$op" + fi else - $IPSEC_EXECDIR/whack --name "$1" "--$op" - if test -e $IPSEC_CHARON_PID - then - $IPSEC_EXECDIR/stroke "$op" "$1" - fi + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack --name "$1" "--$op" + fi + if test -e $IPSEC_CHARON_PID + then + $IPSEC_EXECDIR/stroke "$op" "$1" + fi fi exit 0 ;; @@ -218,7 +244,10 @@ stop) ;; up) shift - $IPSEC_EXECDIR/whack --name "$1" --initiate + if test -e $IPSEC_PLUTO_PID + then + $IPSEC_EXECDIR/whack --name "$1" --initiate + fi if test -e $IPSEC_CHARON_PID then $IPSEC_EXECDIR/stroke up "$1" @@ -228,10 +257,10 @@ up) update) if test -e $IPSEC_STARTER_PID then - echo "Updating strongSwan IPsec configuration..." >&2 - kill -s HUP `cat $IPSEC_STARTER_PID` + echo "Updating strongSwan IPsec configuration..." >&2 + kill -s HUP `cat $IPSEC_STARTER_PID` else - echo "ipsec starter is not running" >&2 + echo "ipsec starter is not running" >&2 fi exit 0 ;; @@ -241,7 +270,7 @@ version|--version) echo "See \`ipsec --copyright' for copyright information." if [ -f $IPSEC_LIBDIR/distro.txt ] then - cat $IPSEC_LIBDIR/distro.txt + cat $IPSEC_LIBDIR/distro.txt fi exit 0 ;; diff --git a/src/pluto/connections.c b/src/pluto/connections.c index 263bdbd1e..6cf6a6a8b 100644 --- a/src/pluto/connections.c +++ b/src/pluto/connections.c @@ -11,7 +11,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: connections.c,v 1.42 2006/04/22 21:59:20 as Exp $ + * RCSID $Id: connections.c,v 1.43 2006/04/29 18:16:02 as Exp $ */ #include <string.h> @@ -4022,7 +4022,7 @@ show_connections_status(bool all, const char *name) /* sort it! */ qsort(array, count, sizeof(struct connection *), connection_compare_qsort); - for (i=0; i<count; i++) + for (i = 0; i < count; i++) { const char *ifn; char instance[1 + 10 + 1]; @@ -4076,7 +4076,7 @@ show_connections_status(bool all, const char *name) if (c->spd.that.groups != NULL) { char buf[BUF_LEN]; - + format_groups(c->spd.that.groups, buf, BUF_LEN); whack_log(RC_COMMENT , "\"%s\"%s: groups: %s" @@ -4097,7 +4097,7 @@ show_connections_status(bool all, const char *name) , (unsigned long) c->sa_keying_tries); /* show DPD parameters if defined */ - + if (c->dpd_action != DPD_ACTION_NONE) whack_log(RC_COMMENT , "\"%s\"%s: dpd_action: %s;" @@ -4141,6 +4141,9 @@ show_connections_status(bool all, const char *name) kernel_alg_show_connection(c, instance); } } + if (count > 0) + whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ + pfree(array); } diff --git a/src/pluto/kernel.c b/src/pluto/kernel.c index 5d7c5f78a..d2070c0d4 100644 --- a/src/pluto/kernel.c +++ b/src/pluto/kernel.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: kernel.c,v 1.25 2006/04/17 14:58:09 as Exp $ + * RCSID $Id: kernel.c,v 1.26 2006/04/29 18:16:02 as Exp $ */ #include <stddef.h> @@ -934,6 +934,8 @@ show_shunt_status(void) , ourst, ourport, hist, hisport, sat, bs->transport_proto , prio, bs->why); } + if (bare_shunts != NULL) + whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ } /* Setup an IPsec route entry. diff --git a/src/pluto/log.c b/src/pluto/log.c index 137e92980..73ffceccd 100644 --- a/src/pluto/log.c +++ b/src/pluto/log.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: log.c,v 1.7 2005/07/11 18:33:45 as Exp $ + * RCSID $Id: log.c,v 1.8 2006/04/29 18:16:02 as Exp $ */ #include <stdio.h> @@ -770,13 +770,11 @@ show_status(bool all, const char *name) show_ifaces_status(); show_myid_status(); show_debug_status(); + whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ } - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ show_connections_status(all, name); - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ show_states_status(name); #ifdef KLIPS - whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ show_shunt_status(); #endif } diff --git a/src/pluto/state.c b/src/pluto/state.c index 5957654e3..0781d2eb3 100644 --- a/src/pluto/state.c +++ b/src/pluto/state.c @@ -12,7 +12,7 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * RCSID $Id: state.c,v 1.12 2006/04/03 15:49:36 as Exp $ + * RCSID $Id: state.c,v 1.13 2006/04/29 18:16:02 as Exp $ */ #include <stdio.h> @@ -902,6 +902,8 @@ show_states_status(const char *name) if (IS_PHASE1(st->st_state)) show_pending_phase2(st->st_connection->host_pair, st); } + if (count > 0) + whack_log(RC_COMMENT, BLANK_FORMAT); /* spacer */ /* free the array */ pfree(array); diff --git a/src/pluto/vendor.c b/src/pluto/vendor.c index 51931c239..1616fed28 100644 --- a/src/pluto/vendor.c +++ b/src/pluto/vendor.c @@ -198,7 +198,8 @@ static struct vid_struct _vid_tab[] = { /* * strongSwan */ - DEC_MD5_VID(STRONGSWAN, "strongSwan 2.7.0") + DEC_MD5_VID(STRONGSWAN, "strongSwan 4.0.0") + DEC_MD5_VID(STRONGSWAN_2_7_0, "strongSwan 2.7.0") DEC_MD5_VID(STRONGSWAN_2_6_4, "strongSwan 2.6.4") DEC_MD5_VID(STRONGSWAN_2_6_3, "strongSwan 2.6.3") DEC_MD5_VID(STRONGSWAN_2_6_2, "strongSwan 2.6.2") diff --git a/src/pluto/vendor.h b/src/pluto/vendor.h index d6b414be2..7c2030d76 100644 --- a/src/pluto/vendor.h +++ b/src/pluto/vendor.h @@ -76,6 +76,7 @@ enum known_vendorid { VID_STRONGSWAN_2_6_2 = 55, VID_STRONGSWAN_2_6_3 = 56, VID_STRONGSWAN_2_6_4 = 57, + VID_STRONGSWAN_2_7_0 = 58, /* 101 - 200 : NAT-Traversal */ VID_NATT_STENBERG_01 =101, diff --git a/src/starter/confread.h b/src/starter/confread.h index a3b1b7379..9793a55a5 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -40,6 +40,12 @@ typedef enum { STATE_INVALID } starter_state_t; +typedef enum { + KEY_EXCHANGE_IKE, + KEY_EXCHANGE_IKEV1, + KEY_EXCHANGE_IKEV2 +} keyexchange_t; + typedef struct starter_end starter_end_t; struct starter_end { @@ -89,7 +95,7 @@ struct starter_conn { startup_t startup; starter_state_t state; - int keyexchange; + keyexchange_t keyexchange; lset_t policy; time_t sa_ike_life_seconds; time_t sa_ipsec_life_seconds; diff --git a/src/starter/starter.c b/src/starter/starter.c index 4b4e23fb3..1f857ce44 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -36,6 +36,7 @@ #include "confread.h" #include "files.h" #include "starterwhack.h" +#include "starterstroke.h" #include "invokepluto.h" #include "invokecharon.h" #include "netkey.h" @@ -47,564 +48,583 @@ #define FLAG_ACTION_RELOAD 0x04 #define FLAG_ACTION_QUIT 0x08 #define FLAG_ACTION_LISTEN 0x10 -#ifdef IKEV2 #define FLAG_ACTION_START_CHARON 0x20 -#endif /* IKEV2 */ static unsigned int _action_ = 0; static void fsig(int signal) { - switch (signal) - { - case SIGCHLD: + switch (signal) { - int status; - pid_t pid; - char *name = NULL; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) - { - if (pid == starter_pluto_pid()) - name = " (Pluto)"; + case SIGCHLD: + { + int status; + pid_t pid; + char *name = NULL; + + while ((pid = waitpid(-1, &status, WNOHANG)) > 0) + { + if (pid == starter_pluto_pid()) + name = " (Pluto)"; #ifdef IKEV2 - if (pid == starter_charon_pid()) - name = " (Charon)"; + if (pid == starter_charon_pid()) + name = " (Charon)"; #endif /* IKEV2 */ - if (WIFSIGNALED(status)) - DBG(DBG_CONTROL, - DBG_log("child %d%s has been killed by sig %d\n", - pid, name?name:"", WTERMSIG(status)) - ) - else if (WIFSTOPPED(status)) - DBG(DBG_CONTROL, - DBG_log("child %d%s has been stopped by sig %d\n", - pid, name?name:"", WSTOPSIG(status)) - ) - else if (WIFEXITED(status)) - DBG(DBG_CONTROL, - DBG_log("child %d%s has quit (exit code %d)\n", - pid, name?name:"", WEXITSTATUS(status)) - ) - else - DBG(DBG_CONTROL, - DBG_log("child %d%s has quit", pid, name?name:"") - ) - - if (pid == starter_pluto_pid()) - starter_pluto_sigchild(pid); + if (WIFSIGNALED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has been killed by sig %d\n", + pid, name?name:"", WTERMSIG(status)) + ) + else if (WIFSTOPPED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has been stopped by sig %d\n", + pid, name?name:"", WSTOPSIG(status)) + ) + else if (WIFEXITED(status)) + DBG(DBG_CONTROL, + DBG_log("child %d%s has quit (exit code %d)\n", + pid, name?name:"", WEXITSTATUS(status)) + ) + else + DBG(DBG_CONTROL, + DBG_log("child %d%s has quit", pid, name?name:"") + ) + + if (pid == starter_pluto_pid()) + starter_pluto_sigchild(pid); #ifdef IKEV2 - if (pid == starter_charon_pid()) - starter_charon_sigchild(pid); + if (pid == starter_charon_pid()) + starter_charon_sigchild(pid); #endif /* IKEV2 */ - } - } - break; + } + } + break; case SIGPIPE: - /** ignore **/ - break; + /** ignore **/ + break; case SIGALRM: - _action_ |= FLAG_ACTION_START_PLUTO; + _action_ |= FLAG_ACTION_START_PLUTO; #ifdef IKEV2 - _action_ |= FLAG_ACTION_START_CHARON; + _action_ |= FLAG_ACTION_START_CHARON; #endif /* IKEV2 */ - break; + break; case SIGHUP: - _action_ |= FLAG_ACTION_UPDATE; - break; + _action_ |= FLAG_ACTION_UPDATE; + break; case SIGTERM: case SIGQUIT: case SIGINT: _action_ |= FLAG_ACTION_QUIT; - break; + break; case SIGUSR1: - _action_ |= FLAG_ACTION_RELOAD; - _action_ |= FLAG_ACTION_UPDATE; - break; + _action_ |= FLAG_ACTION_RELOAD; + _action_ |= FLAG_ACTION_UPDATE; + break; default: - plog("fsig(): unknown signal %d -- investigate", signal); - break; + plog("fsig(): unknown signal %d -- investigate", signal); + break; } } static void usage(char *name) { - fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] " - "[--debug|--debug-more|--debug-all]\n"); - exit(1); + fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>] " + "[--debug|--debug-more|--debug-all]\n"); + exit(1); } int main (int argc, char **argv) { - starter_config_t *cfg = NULL; - starter_config_t *new_cfg; - starter_conn_t *conn, *conn2; - starter_ca_t *ca, *ca2; + starter_config_t *cfg = NULL; + starter_config_t *new_cfg; + starter_conn_t *conn, *conn2; + starter_ca_t *ca, *ca2; - struct stat stb; + struct stat stb; - char *err = NULL; - int i; - int id = 1; - struct timeval tv; - unsigned long auto_update = 0; - time_t last_reload; - bool no_fork = FALSE; + char *err = NULL; + int i; + int id = 1; + struct timeval tv; + unsigned long auto_update = 0; + time_t last_reload; + bool no_fork = FALSE; - /* global variables defined in log.h */ - log_to_stderr = TRUE; - base_debugging = DBG_NONE; + /* global variables defined in log.h */ + log_to_stderr = TRUE; + base_debugging = DBG_NONE; /* parse command line */ - for (i = 1; i < argc; i++) - { - if (streq(argv[i], "--debug")) + for (i = 1; i < argc; i++) { - base_debugging |= DBG_CONTROL; + if (streq(argv[i], "--debug")) + { + base_debugging |= DBG_CONTROL; + } + else if (streq(argv[i], "--debug-more")) + { + base_debugging |= DBG_CONTROLMORE; + } + else if (streq(argv[i], "--debug-all")) + { + base_debugging |= DBG_ALL; + } + else if (streq(argv[i], "--nofork")) + { + no_fork = TRUE; + } + else if (streq(argv[i], "--auto-update") && i+1 < argc) + { + auto_update = atoi(argv[++i]); + if (!auto_update) + usage(argv[0]); + } + else + { + usage(argv[0]); + } } - else if (streq(argv[i], "--debug-more")) + + /* Init */ + init_log("ipsec_starter"); + cur_debugging = base_debugging; + + signal(SIGHUP, fsig); + signal(SIGCHLD, fsig); + signal(SIGPIPE, fsig); + signal(SIGINT, fsig); + signal(SIGTERM, fsig); + signal(SIGQUIT, fsig); + signal(SIGALRM, fsig); + signal(SIGUSR1, fsig); + + plog("Starting strongSwan IPsec %s [starter]...", ipsec_version_code()); + + /* verify that we can start */ + if (getuid() != 0) { - base_debugging |= DBG_CONTROLMORE; + plog("permission denied (must be superuser)"); + exit(1); } - else if (streq(argv[i], "--debug-all")) + + if (stat(PLUTO_PID_FILE, &stb) == 0) { - base_debugging |= DBG_ALL; + plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE); } - else if (streq(argv[i], "--nofork")) + else { - no_fork = TRUE; + _action_ |= FLAG_ACTION_START_PLUTO; } - else if (streq(argv[i], "--auto-update") && i+1 < argc) +#ifdef IKEV2 + if (stat(CHARON_PID_FILE, &stb) == 0) { - auto_update = atoi(argv[++i]); - if (!auto_update) - usage(argv[0]); + plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE); } else { - usage(argv[0]); + _action_ |= FLAG_ACTION_START_CHARON; } - } - - /* Init */ - init_log("ipsec_starter"); - cur_debugging = base_debugging; - - signal(SIGHUP, fsig); - signal(SIGCHLD, fsig); - signal(SIGPIPE, fsig); - signal(SIGINT, fsig); - signal(SIGTERM, fsig); - signal(SIGQUIT, fsig); - signal(SIGALRM, fsig); - signal(SIGUSR1, fsig); - - - plog("Starting strongSwan IPsec %s [starter]...", ipsec_version_code()); - - /* verify that we can start */ - if (getuid() != 0) - { - plog("permission denied (must be superuser)"); - exit(1); - } - - if (stat(PLUTO_PID_FILE, &stb) == 0) - { - plog("pluto is already running (%s exists) -- skipping pluto start", PLUTO_PID_FILE); - } - else - { - _action_ |= FLAG_ACTION_START_PLUTO; - } -#ifdef IKEV2 - if (stat(CHARON_PID_FILE, &stb) == 0) - { - plog("charon is already running (%s exists) -- skipping charon start", CHARON_PID_FILE); - } - else - { - _action_ |= FLAG_ACTION_START_CHARON; - } #endif /* IKEV2 */ - if (stat(DEV_RANDOM, &stb) != 0) - { - plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); - exit(1); - } - - if (stat(DEV_URANDOM, &stb)!= 0) - { - plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); - exit(1); - } + if (stat(DEV_RANDOM, &stb) != 0) + { + plog("unable to start strongSwan IPsec -- no %s!", DEV_RANDOM); + exit(1); + } - cfg = confread_load(CONFIG_FILE); - if (!cfg) - { - plog("unable to start strongSwan -- errors in config"); - exit(1); - } + if (stat(DEV_URANDOM, &stb)!= 0) + { + plog("unable to start strongSwan IPsec -- no %s!", DEV_URANDOM); + exit(1); + } - /* determine if we have a native netkey IPsec stack */ - if (!starter_netkey_init()) - { - plog("nor netkey IPSec stack detected"); - exit(1); - } + cfg = confread_load(CONFIG_FILE); + if (!cfg) + { + plog("unable to start strongSwan -- errors in config"); + exit(1); + } - last_reload = time(NULL); + /* determine if we have a native netkey IPsec stack */ + if (!starter_netkey_init()) + { + plog("nor netkey IPSec stack detected"); + exit(1); + } - if (stat(MY_PID_FILE, &stb) == 0) - { - plog("starter is already running (%s exists) -- no fork done", MY_PID_FILE); - exit(0); - } + last_reload = time(NULL); - /* fork if we're not debugging stuff */ - if (!no_fork) - { - log_to_stderr = FALSE; + if (stat(MY_PID_FILE, &stb) == 0) + { + plog("starter is already running (%s exists) -- no fork done", MY_PID_FILE); + exit(0); + } - switch (fork()) + /* fork if we're not debugging stuff */ + if (!no_fork) { - case 0: - { - int fnull = open("/dev/null", O_RDWR); + log_to_stderr = FALSE; - if (fnull >= 0) + switch (fork()) { - dup2(fnull, STDIN_FILENO); - dup2(fnull, STDOUT_FILENO); - dup2(fnull, STDERR_FILENO); - close(fnull); + case 0: + { + int fnull = open("/dev/null", O_RDWR); + + if (fnull >= 0) + { + dup2(fnull, STDIN_FILENO); + dup2(fnull, STDOUT_FILENO); + dup2(fnull, STDERR_FILENO); + close(fnull); + } + } + break; + case -1: + plog("can't fork: %s", strerror(errno)); + break; + default: + exit(0); } - } - break; - case -1: - plog("can't fork: %s", strerror(errno)); - break; - default: - exit(0); - } } /* save pid file in /var/run/starter.pid */ { - FILE *fd = fopen(MY_PID_FILE, "w"); + FILE *fd = fopen(MY_PID_FILE, "w"); - if (fd) - { - fprintf(fd, "%u\n", getpid()); - fclose(fd); - } + if (fd) + { + fprintf(fd, "%u\n", getpid()); + fclose(fd); + } } for (;;) { - /* - * Stop pluto/charon (if started) and exit - */ - if (_action_ & FLAG_ACTION_QUIT) - { - if (starter_pluto_pid()) - starter_stop_pluto(); + /* + * Stop pluto/charon (if started) and exit + */ + if (_action_ & FLAG_ACTION_QUIT) + { + if (starter_pluto_pid()) + starter_stop_pluto(); #ifdef IKEV2 - if (starter_charon_pid()) - starter_stop_charon(); -#endif IKEV2 - starter_netkey_cleanup(); - confread_free(cfg); - unlink(MY_PID_FILE); - unlink(INFO_FILE); + if (starter_charon_pid()) + starter_stop_charon(); +#endif /* IKEV2 */ + starter_netkey_cleanup(); + confread_free(cfg); + unlink(MY_PID_FILE); + unlink(INFO_FILE); #ifdef LEAK_DETECTIVE - report_leaks(); + report_leaks(); #endif /* LEAK_DETECTIVE */ - close_log(); - plog("ipsec starter stopped"); - exit(0); - } + close_log(); + plog("ipsec starter stopped"); + exit(0); + } - /* - * Delete all connections. Will be added below - */ - if (_action_ & FLAG_ACTION_RELOAD) - { - if (starter_pluto_pid()) - { - for (conn = cfg->conn_first; conn; conn = conn->next) + /* + * Delete all connections. Will be added below + */ + if (_action_ & FLAG_ACTION_RELOAD) { - if (conn->state == STATE_ADDED) - { - starter_whack_del_conn(conn); + if (starter_pluto_pid()) + { + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + { #ifdef IKEV2 - starter_stroke_del_conn(conn); + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + starter_stroke_del_conn(conn); + } #endif /* IKEV2 */ - conn->state = STATE_TO_ADD; - } - } - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_ADDED) - { - starter_whack_del_ca(ca); - ca->state = STATE_TO_ADD; - } - } - } - _action_ &= ~FLAG_ACTION_RELOAD; - } - - /* - * Update configuration - */ - if (_action_ & FLAG_ACTION_UPDATE) - { - err = NULL; - DBG(DBG_CONTROL, - DBG_log("Reloading config...") - ) - new_cfg = confread_load(CONFIG_FILE); - - if (new_cfg) - { - /* Switch to new config. New conn will be loaded below */ - if (!starter_cmp_defaultroute(&new_cfg->defaultroute - , &cfg->defaultroute)) - { - _action_ |= FLAG_ACTION_LISTEN; + else + { + starter_whack_del_conn(conn); + } + conn->state = STATE_TO_ADD; + } + } + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + { + starter_whack_del_ca(ca); + ca->state = STATE_TO_ADD; + } + } + } + _action_ &= ~FLAG_ACTION_RELOAD; } - if (!starter_cmp_pluto(cfg, new_cfg)) - { - plog("Pluto has changed"); - if (starter_pluto_pid()) - starter_stop_pluto(); - _action_ &= ~FLAG_ACTION_LISTEN; - _action_ |= FLAG_ACTION_START_PLUTO; - } - else + /* + * Update configuration + */ + if (_action_ & FLAG_ACTION_UPDATE) { - /* Only reload conn and ca sections if pluto is not killed */ + err = NULL; + DBG(DBG_CONTROL, + DBG_log("Reloading config...") + ) + new_cfg = confread_load(CONFIG_FILE); - /* Look for new connections that are already loaded */ - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_ADDED) + if (new_cfg) { - for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next) - { - if (conn2->state == STATE_TO_ADD - && starter_cmp_conn(conn, conn2)) + /* Switch to new config. New conn will be loaded below */ + if (!starter_cmp_defaultroute(&new_cfg->defaultroute + , &cfg->defaultroute)) { - conn->state = STATE_REPLACED; - conn2->state = STATE_ADDED; - conn2->id = conn->id; - break; + _action_ |= FLAG_ACTION_LISTEN; } - } - } - } - /* Remove conn sections that have become unused */ - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_ADDED) - starter_whack_del_conn(conn); + if (!starter_cmp_pluto(cfg, new_cfg)) + { + plog("Pluto has changed"); + if (starter_pluto_pid()) + starter_stop_pluto(); + _action_ &= ~FLAG_ACTION_LISTEN; + _action_ |= FLAG_ACTION_START_PLUTO; + } + else + { + /* Only reload conn and ca sections if pluto is not killed */ + + /* Look for new connections that are already loaded */ + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + { + for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next) + { + if (conn2->state == STATE_TO_ADD + && starter_cmp_conn(conn, conn2)) + { + conn->state = STATE_REPLACED; + conn2->state = STATE_ADDED; + conn2->id = conn->id; + break; + } + } + } + } + + /* Remove conn sections that have become unused */ + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + { #ifdef IKEV2 - starter_stroke_del_conn(conn); + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + starter_stroke_del_conn(conn); + } + else #endif /* IKEV2 */ - } + { + starter_whack_del_conn(conn); + } + } + } + + /* Look for new ca sections that are already loaded */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + { + for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next) + { + if (ca2->state == STATE_TO_ADD + && starter_cmp_ca(ca, ca2)) + { + ca->state = STATE_REPLACED; + ca2->state = STATE_ADDED; + break; + } + } + } + } + + /* Remove ca sections that have become unused */ + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + starter_whack_del_ca(ca); + } + } + confread_free(cfg); + cfg = new_cfg; + } + else + { + plog("can't reload config file: %s -- keeping old one"); + } + _action_ &= ~FLAG_ACTION_UPDATE; + last_reload = time(NULL); + } - /* Look for new ca sections that are already loaded */ - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_ADDED) + /* + * Start pluto + */ + if (_action_ & FLAG_ACTION_START_PLUTO) + { + if (starter_pluto_pid() == 0) { - for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next) - { - if (ca2->state == STATE_TO_ADD - && starter_cmp_ca(ca, ca2)) + DBG(DBG_CONTROL, + DBG_log("Attempting to start pluto...") + ) + + if (starter_start_pluto(cfg, no_fork) == 0) { - ca->state = STATE_REPLACED; - ca2->state = STATE_ADDED; - break; + starter_whack_listen(); + } + else + { + /* schedule next try */ + alarm(PLUTO_RESTART_DELAY); } - } } - } - - /* Remove ca sections that have become unused */ - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_ADDED) - starter_whack_del_ca(ca); - } - } - confread_free(cfg); - cfg = new_cfg; - } - else - { - plog("can't reload config file: %s -- keeping old one"); - } - _action_ &= ~FLAG_ACTION_UPDATE; - last_reload = time(NULL); - } + _action_ &= ~FLAG_ACTION_START_PLUTO; - /* - * Start pluto - */ - if (_action_ & FLAG_ACTION_START_PLUTO) - { - if (starter_pluto_pid() == 0) - { - DBG(DBG_CONTROL, - DBG_log("Attempting to start pluto...") - ) + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_ADDED) + ca->state = STATE_TO_ADD; + } - if (starter_start_pluto(cfg, no_fork) == 0) - { - starter_whack_listen(); - } - else - { - /* schedule next try */ - alarm(PLUTO_RESTART_DELAY); + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_ADDED) + conn->state = STATE_TO_ADD; + } } - } - _action_ &= ~FLAG_ACTION_START_PLUTO; - - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_ADDED) - ca->state = STATE_TO_ADD; - } - - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_ADDED) - conn->state = STATE_TO_ADD; - } - } #ifdef IKEV2 - /* - * Start charon - */ - if (_action_ & FLAG_ACTION_START_CHARON) - { - if (starter_charon_pid() == 0) + /* + * Start charon + */ + if (_action_ & FLAG_ACTION_START_CHARON) { - DBG(DBG_CONTROL, - DBG_log("Attempting to start charon...") - ) - if (starter_start_charon(cfg, no_fork) != 0) + if (starter_charon_pid() == 0) { - /* schedule next try */ - alarm(PLUTO_RESTART_DELAY); + DBG(DBG_CONTROL, + DBG_log("Attempting to start charon...") + ) + if (starter_start_charon(cfg, no_fork) != 0) + { + /* schedule next try */ + alarm(PLUTO_RESTART_DELAY); + } } + _action_ &= ~FLAG_ACTION_START_CHARON; } - _action_ &= ~FLAG_ACTION_START_CHARON; - } #endif /* IKEV2 */ - /* - * Tell pluto to reread its interfaces - */ - if (_action_ & FLAG_ACTION_LISTEN) - { - starter_whack_listen(); - _action_ &= ~FLAG_ACTION_LISTEN; - } - - /* - * Add stale conn and ca sections - */ - if (starter_pluto_pid() != 0) - { - for (ca = cfg->ca_first; ca; ca = ca->next) - { - if (ca->state == STATE_TO_ADD) + /* + * Tell pluto to reread its interfaces + */ + if (_action_ & FLAG_ACTION_LISTEN) { - starter_whack_add_ca(ca); - ca->state = STATE_ADDED; + starter_whack_listen(); + _action_ &= ~FLAG_ACTION_LISTEN; } - } - for (conn = cfg->conn_first; conn; conn = conn->next) - { - if (conn->state == STATE_TO_ADD) + /* + * Add stale conn and ca sections + */ + if (starter_pluto_pid() != 0) { - if (conn->id == 0) - { - /* affect new unique id */ - conn->id = id++; - } - starter_whack_add_conn(conn); + for (ca = cfg->ca_first; ca; ca = ca->next) + { + if (ca->state == STATE_TO_ADD) + { + starter_whack_add_ca(ca); + ca->state = STATE_ADDED; + } + } + + for (conn = cfg->conn_first; conn; conn = conn->next) + { + if (conn->state == STATE_TO_ADD) + { + if (conn->id == 0) + { + /* affect new unique id */ + conn->id = id++; + } #ifdef IKEV2 - starter_stroke_add_conn(conn); + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + starter_stroke_add_conn(conn); + } + else #endif /* IKEV2 */ - conn->state = STATE_ADDED; - if (conn->startup == STARTUP_START) - { + { + starter_whack_add_conn(conn); + } + conn->state = STATE_ADDED; + + if (conn->startup == STARTUP_START) + { #ifdef IKEV2 - if (conn->keyexchange == 2) - { - starter_stroke_initiate_conn(conn); - } - else + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + starter_stroke_initiate_conn(conn); + } + else #endif /* IKEV2 */ - { - starter_whack_initiate_conn(conn); - } - } - else if (conn->startup == STARTUP_ROUTE) - { + { + starter_whack_initiate_conn(conn); + } + } + else if (conn->startup == STARTUP_ROUTE) + { #ifdef IKEV2 - if (conn->keyexchange == 2) - { - starter_stroke_route_conn(conn); - } - else + if (conn->keyexchange == KEY_EXCHANGE_IKEV2) + { + starter_stroke_route_conn(conn); + } + else #endif /* IKEV2 */ - { - starter_whack_route_conn(conn); + { + starter_whack_route_conn(conn); + } + } + } } - } } - } - } - /* - * If auto_update activated, when to stop select - */ - if (auto_update) - { - time_t now = time(NULL); - tv.tv_sec = (now < last_reload + auto_update) - ? (last_reload + auto_update-now) : 0; - tv.tv_usec = 0; - } + /* + * If auto_update activated, when to stop select + */ + if (auto_update) + { + time_t now = time(NULL); - /* - * Wait for something to happen - */ - if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0) - { - /* timeout -> auto_update */ - _action_ |= FLAG_ACTION_UPDATE; + tv.tv_sec = (now < last_reload + auto_update) + ? (last_reload + auto_update-now) : 0; + tv.tv_usec = 0; + } + + /* + * Wait for something to happen + */ + if (select(0, NULL, NULL, NULL, auto_update ? &tv : NULL) == 0) + { + /* timeout -> auto_update */ + _action_ |= FLAG_ACTION_UPDATE; + } } - } - return 0; + return 0; } diff --git a/testing/do-tests b/testing/do-tests index ceddd72d8..c4c624ea9 100755 --- a/testing/do-tests +++ b/testing/do-tests @@ -374,6 +374,9 @@ do eval HOSTLOGIN=root@\$ip_${host} ssh $HOSTLOGIN grep pluto /var/log/auth.log \ > $TESTRESULTDIR/${host}.auth.log + echo >> $TESTRESULTDIR/${host}.auth.log + ssh $HOSTLOGIN grep charon /var/log/auth.log \ + >> $TESTRESULTDIR/${host}.auth.log done diff --git a/testing/scripts/build-umlrootfs b/testing/scripts/build-umlrootfs index ba103838f..c2726cfc9 100755 --- a/testing/scripts/build-umlrootfs +++ b/testing/scripts/build-umlrootfs @@ -128,6 +128,7 @@ echo "export USERCOMPILE=\'-DRANDOM_DEVICE=\\\"/dev/urandom\\\"\'" >> $INSTALLSH echo "cd /root/${STRONGSWANVERSION}" >> $INSTALLSHELL echo "make programs" >> $INSTALLSHELL echo "make install" >> $INSTALLSHELL +echo "ldconfig" >> $INSTALLSHELL cecho-n " * Compiling $STRONGSWANVERSION within the root file system as chroot.." chroot $LOOPDIR /bin/bash /install.sh >> $LOGFILE 2>&1 diff --git a/testing/tests/ikev2-net2net/description.txt b/testing/tests/ikev2-net2net/description.txt new file mode 100644 index 000000000..7eea9192f --- /dev/null +++ b/testing/tests/ikev2-net2net/description.txt @@ -0,0 +1,6 @@ +A connection between the subnets behind the gateways <b>moon</b> and <b>sun</b> is set up. +The authentication is based on <b>X.509 certificates</b>. Upon the successful +establishment of the IPsec tunnel, <b>leftfirewall=yes</b> automatically +inserts iptables-based firewall rules that let pass the tunneled traffic. +In order to test both tunnel and firewall, client <b>alice</b> behind gateway <b>moon</b> +pings client <b>bob</b> located behind gateway <b>sun</b>. diff --git a/testing/tests/ikev2-net2net/evaltest.dat b/testing/tests/ikev2-net2net/evaltest.dat new file mode 100644 index 000000000..bb4eac44e --- /dev/null +++ b/testing/tests/ikev2-net2net/evaltest.dat @@ -0,0 +1,5 @@ +moon::ipsec statusall::net-net.*IKE_SA_ESTABLISHED::YES +sun::ipsec statusall::net-net.*IKE_SA_ESTABLISHED::YES +alice::ping -c 1 PH_IP_BOB::64 bytes from PH_IP_BOB: icmp_seq=1::YES +sun::tcpdump::IP moon.strongswan.org > sun.strongswan.org: ESP::YES +sun::tcpdump::IP sun.strongswan.org > moon.strongswan.org: ESP::YES diff --git a/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.conf b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.conf new file mode 100644 index 000000000..9a95d4040 --- /dev/null +++ b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.conf @@ -0,0 +1,13 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +version 2.0 # conforms to second version of ipsec.conf specification + +conn net-net + left=192.168.0.1 + leftcert=moonCert.pem + leftsubnet=10.1.0.0/16 + right=192.168.0.2 + rightcert=sunCert.pem + rightsubnet=10.2.0.0/16 + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.d/certs/sunCert.pem b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.d/certs/sunCert.pem new file mode 100644 index 000000000..e7825e3db --- /dev/null +++ b/testing/tests/ikev2-net2net/hosts/moon/etc/ipsec.d/certs/sunCert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIECzCCAvOgAwIBAgIBAjANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ +MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS +b290IENBMB4XDTA0MDkxMDExMTU1M1oXDTA5MDkwOTExMTU1M1owRTELMAkGA1UE +BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN1bi5z +dHJvbmdzd2FuLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOQ8 +foB9h5BZ92gA5JkQTJNuoF6FAzoq91Gh7To27/g74p01+SUnsSaBfPmNfGp4avdS +Ewy2dWMA/7uj0Dbe8MEKssNztp0JQubp2s7n8mrrQLGsqB6YAS09l75XDjS3yqTC +AtH1kD4zAl/j/AyeQBuLR4CyJEmC/rqD3/a+pr42CaljuFBgBRpCTUpU4mlslZSe +zv9wu61PwTFxb8VDlBHUd/lwkXThKgU3uEhWRxLahpSldEGmiTTmx30k/XbOMF2n +HObEHt5EY9uWRGGbj81ZRWiNk0dNtbpneUHv/NvdWLc591M8cEGEQdWW2XTVbL2G +N67q8hdzGgIvb7QJPMcCAwEAAaOCAQQwggEAMAkGA1UdEwQCMAAwCwYDVR0PBAQD +AgOoMB0GA1UdDgQWBBQ9xLkyCBbyQmRet0vvV1Fg6z5q2DBtBgNVHSMEZjBkgBRd +p91wBlEyfue2bbO15eBg6i5N76FJpEcwRTELMAkGA1UEBhMCQ0gxGTAXBgNVBAoT +EExpbnV4IHN0cm9uZ1N3YW4xGzAZBgNVBAMTEnN0cm9uZ1N3YW4gUm9vdCBDQYIB +ADAdBgNVHREEFjAUghJzdW4uc3Ryb25nc3dhbi5vcmcwOQYDVR0fBDIwMDAuoCyg +KoYoaHR0cDovL2NybC5zdHJvbmdzd2FuLm9yZy9zdHJvbmdzd2FuLmNybDANBgkq +hkiG9w0BAQQFAAOCAQEAGQQroiAa0SwwhJprGd7OM+rfBJAGbsa3DPzFCfHX1R7i +ZyDs9aph1DK+IgUa377Ev1U7oB0EldpmOoJJugCjtNLfpW3t1RXBERL/QfpO2+VP +Wt3SfZ0Oq48jiqB1MVLMZRPCICZEQjT4sJ3HYs5ZuucuvoxeMx3rQ4HxUtHtMD3S +5JNMwFFiOXAjyIyrTlb7YuRJTT5hE+Rms8GUQ5Xnt7zKZ7yfoSLFzy0/cLFPdQvE +JA7w8crODCZpDgEKVHVyUWuyt1O46N3ydUfDcnKJoQ9HWHm3xCbDex5MHTnvm1lk +Stx71CGM7TE6VPy028UlrSw0JqEwCVwstei2cMzwgA== +-----END CERTIFICATE----- diff --git a/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.conf b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.conf new file mode 100644 index 000000000..b2c2b71ec --- /dev/null +++ b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.conf @@ -0,0 +1,13 @@ +# /etc/ipsec.conf - strongSwan IPsec configuration file + +version 2.0 # conforms to second version of ipsec.conf specification + +conn net-net + left=192.168.0.2 + leftcert=sunCert.pem + leftsubnet=10.2.0.0/16 + right=192.168.0.1 + rightcert=moonCert.pem + rightsubnet=10.1.0.0/16 + keyexchange=ikev2 + auto=add diff --git a/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.d/certs/moonCert.pem b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.d/certs/moonCert.pem new file mode 100644 index 000000000..d8fbfa1c9 --- /dev/null +++ b/testing/tests/ikev2-net2net/hosts/sun/etc/ipsec.d/certs/moonCert.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEDTCCAvWgAwIBAgIBAzANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJDSDEZ +MBcGA1UEChMQTGludXggc3Ryb25nU3dhbjEbMBkGA1UEAxMSc3Ryb25nU3dhbiBS +b290IENBMB4XDTA0MDkxMDExMTcyNVoXDTA5MDkwOTExMTcyNVowRjELMAkGA1UE +BhMCQ0gxGTAXBgNVBAoTEExpbnV4IHN0cm9uZ1N3YW4xHDAaBgNVBAMTE21vb24u +c3Ryb25nc3dhbi5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCv +ri4QmsCnG0N7bxqeUZTQhcmZ/iyN4RsmHwFsiOc06xpnZ7Fbx9gzi/OswU6KGL+F +f9PfvOY36bDTZU8V2QaL30RQUXz3JlG+jUyP9zjqlhsvVYS/cImvqgo3uUkQ0YCD +v2SafTlaQfBOaPFElNEP/H2YSiyB6X80IcHsOMYpskVqPY8785FehjF+pxuyRCK+ +9HXmd+iWdnC09u4qgKRa3L0IamU3q1/BK/afkHK2IAIN4YgM7GzepHVD0f7Exf9U +esJEeh4hDZwSjcMzdybrY9XBxzGqLGPOF128jr+5weUZiBW+RzeBw/gsK1nSPeuX +Od2lPJjTGj+6V3YK6qibAgMBAAGjggEFMIIBATAJBgNVHRMEAjAAMAsGA1UdDwQE +AwIDqDAdBgNVHQ4EFgQU5eQQh2wqxL6thUlCpt52WDA6n8EwbQYDVR0jBGYwZIAU +XafdcAZRMn7ntm2zteXgYOouTe+hSaRHMEUxCzAJBgNVBAYTAkNIMRkwFwYDVQQK +ExBMaW51eCBzdHJvbmdTd2FuMRswGQYDVQQDExJzdHJvbmdTd2FuIFJvb3QgQ0GC +AQAwHgYDVR0RBBcwFYITbW9vbi5zdHJvbmdzd2FuLm9yZzA5BgNVHR8EMjAwMC6g +LKAqhihodHRwOi8vY3JsLnN0cm9uZ3N3YW4ub3JnL3N0cm9uZ3N3YW4uY3JsMA0G +CSqGSIb3DQEBBAUAA4IBAQAvLykhZnqldrsMcbYB36WzWKk+hOihr5dU3fv8Z4ec +tsa3gzxXSefDCxGoezVJ4QXdpdNxxFn31A+r1gxKyGI5JL6EyWz6Y462zp9lE7nW +EIC4ldJwxAXqzDEMcJphO29hApyU9TWsWDa4kL5AKtLFLwH3/Uv/jAzAy+qXIO8h +wLtB+wcmhSo8OFY9kX/cyhht7eb7yD/r2e3wVBOCRk7jePe4yWhN8NJAKwfrEd1K +iGq15ymdmeomhplHRsLZwA2VsCspUNZ/eXjG21s3nEoxcCOcQUz3Q7q4ZgBTZoCW +kAc6FQ5zxoZrmzNWFqzb06jmUVlt7baGtdjT7rEt+dcp +-----END CERTIFICATE----- diff --git a/testing/tests/ikev2-net2net/posttest.dat b/testing/tests/ikev2-net2net/posttest.dat new file mode 100644 index 000000000..63c76ec65 --- /dev/null +++ b/testing/tests/ikev2-net2net/posttest.dat @@ -0,0 +1,4 @@ +moon::ipsec stop +sun::ipsec stop +moon::rm /etc/ipsec.d/certs/* +sun::rm /etc/ipsec.d/certs/* diff --git a/testing/tests/ikev2-net2net/pretest.dat b/testing/tests/ikev2-net2net/pretest.dat new file mode 100644 index 000000000..33f838851 --- /dev/null +++ b/testing/tests/ikev2-net2net/pretest.dat @@ -0,0 +1,7 @@ +moon::echo 1 > /proc/sys/net/ipv4/ip_forward +sun::echo 1 > /proc/sys/net/ipv4/ip_forward +moon::ipsec start +sun::ipsec start +moon::sleep 1 +moon::ipsec up net-net +moon::sleep 1 diff --git a/testing/tests/ikev2-net2net/test.conf b/testing/tests/ikev2-net2net/test.conf new file mode 100644 index 000000000..d9a61590f --- /dev/null +++ b/testing/tests/ikev2-net2net/test.conf @@ -0,0 +1,21 @@ +#!/bin/bash +# +# This configuration file provides information on the +# UML instances used for this test + +# All UML instances that are required for this test +# +UMLHOSTS="alice moon winnetou sun bob" + +# Corresponding block diagram +# +DIAGRAM="a-m-w-s-b.png" + +# UML instances on which tcpdump is to be started +# +TCPDUMPHOSTS="sun" + +# UML instances on which IPsec is started +# Used for IPsec logging purposes +# +IPSECHOSTS="moon sun" |