From 1fed10beb2b49b034ad733e48d8222093954fcb3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 11:26:22 +0100 Subject: charon-cmd: add a stub for charon-cmd, a simple command line IKE client --- configure.in | 101 +++++++------ src/Makefile.am | 4 + src/charon-cmd/.gitignore | 1 + src/charon-cmd/Makefile.am | 22 +++ src/charon-cmd/charon-cmd.c | 358 ++++++++++++++++++++++++++++++++++++++++++++ src/checksum/Makefile.am | 4 + 6 files changed, 442 insertions(+), 48 deletions(-) create mode 100644 src/charon-cmd/.gitignore create mode 100644 src/charon-cmd/Makefile.am create mode 100644 src/charon-cmd/charon-cmd.c diff --git a/configure.in b/configure.in index 311b15c6b..a244f632e 100644 --- a/configure.in +++ b/configure.in @@ -241,6 +241,7 @@ ARG_ENABL_SET([bfd-backtraces], [use binutils libbfd to resolve backtraces for m ARG_ENABL_SET([unwind-backtraces],[use libunwind to create backtraces for memory leaks and segfaults.]) ARG_ENABL_SET([unit-tests], [enable unit tests using the check test framework.]) ARG_ENABL_SET([tkm], [enable Trusted Key Manager support.]) +ARG_ENABL_SET([cmd], [enable the command line IKE client charon-cmd.]) # =================================== # option to disable default options @@ -931,6 +932,7 @@ scripts_plugins= manager_plugins= medsrv_plugins= nm_plugins= +cmd_plugins= # location specific lists for checksumming, # for src/libcharon, src/libhydra and src/libstrongswan @@ -939,63 +941,63 @@ h_plugins= s_plugins= ADD_PLUGIN([test-vectors], [s charon openac scepclient pki]) -ADD_PLUGIN([curl], [s charon scepclient scripts nm]) -ADD_PLUGIN([soup], [s charon scripts nm]) +ADD_PLUGIN([curl], [s charon scepclient scripts nm cmd]) +ADD_PLUGIN([soup], [s charon scripts nm cmd]) ADD_PLUGIN([unbound], [s charon scripts]) -ADD_PLUGIN([ldap], [s charon scepclient scripts nm]) +ADD_PLUGIN([ldap], [s charon scepclient scripts nm cmd]) ADD_PLUGIN([mysql], [s charon pool manager medsrv attest]) ADD_PLUGIN([sqlite], [s charon pool manager medsrv attest]) -ADD_PLUGIN([pkcs11], [s charon pki nm]) -ADD_PLUGIN([aes], [s charon openac scepclient pki scripts nm]) -ADD_PLUGIN([des], [s charon openac scepclient pki scripts nm]) -ADD_PLUGIN([blowfish], [s charon openac scepclient pki scripts nm]) -ADD_PLUGIN([sha1], [s charon openac scepclient pki scripts medsrv attest nm]) -ADD_PLUGIN([sha2], [s charon openac scepclient pki scripts medsrv attest nm]) -ADD_PLUGIN([md4], [s charon openac manager scepclient pki nm]) -ADD_PLUGIN([md5], [s charon openac scepclient pki scripts attest nm]) -ADD_PLUGIN([rdrand], [s charon openac scepclient pki scripts medsrv attest nm]) -ADD_PLUGIN([random], [s charon openac scepclient pki scripts medsrv attest nm]) -ADD_PLUGIN([nonce], [s charon nm]) -ADD_PLUGIN([x509], [s charon openac scepclient pki scripts attest nm]) -ADD_PLUGIN([revocation], [s charon nm]) -ADD_PLUGIN([constraints], [s charon nm]) +ADD_PLUGIN([pkcs11], [s charon pki nm cmd]) +ADD_PLUGIN([aes], [s charon openac scepclient pki scripts nm cmd]) +ADD_PLUGIN([des], [s charon openac scepclient pki scripts nm cmd]) +ADD_PLUGIN([blowfish], [s charon openac scepclient pki scripts nm cmd]) +ADD_PLUGIN([sha1], [s charon openac scepclient pki scripts medsrv attest nm cmd]) +ADD_PLUGIN([sha2], [s charon openac scepclient pki scripts medsrv attest nm cmd]) +ADD_PLUGIN([md4], [s charon openac manager scepclient pki nm cmd]) +ADD_PLUGIN([md5], [s charon openac scepclient pki scripts attest nm cmd]) +ADD_PLUGIN([rdrand], [s charon openac scepclient pki scripts medsrv attest nm cmd]) +ADD_PLUGIN([random], [s charon openac scepclient pki scripts medsrv attest nm cmd]) +ADD_PLUGIN([nonce], [s charon nm cmd]) +ADD_PLUGIN([x509], [s charon openac scepclient pki scripts attest nm cmd]) +ADD_PLUGIN([revocation], [s charon nm cmd]) +ADD_PLUGIN([constraints], [s charon nm cmd]) ADD_PLUGIN([pubkey], [s charon]) -ADD_PLUGIN([pkcs1], [s charon openac scepclient pki scripts manager medsrv attest nm]) +ADD_PLUGIN([pkcs1], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([pkcs7], [s scepclient pki]) -ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm]) +ADD_PLUGIN([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([pgp], [s charon]) ADD_PLUGIN([dnskey], [s charon]) ADD_PLUGIN([ipseckey], [c charon]) -ADD_PLUGIN([pem], [s charon openac scepclient pki scripts manager medsrv attest nm]) +ADD_PLUGIN([pem], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) ADD_PLUGIN([padlock], [s charon]) -ADD_PLUGIN([openssl], [s charon openac scepclient pki scripts manager medsrv attest nm]) -ADD_PLUGIN([gcrypt], [s charon openac scepclient pki scripts manager medsrv attest nm]) -ADD_PLUGIN([af-alg], [s charon openac scepclient pki scripts medsrv attest nm]) -ADD_PLUGIN([fips-prf], [s charon nm]) -ADD_PLUGIN([gmp], [s charon openac scepclient pki scripts manager medsrv attest nm]) -ADD_PLUGIN([agent], [s charon nm]) -ADD_PLUGIN([xcbc], [s charon nm]) -ADD_PLUGIN([cmac], [s charon nm]) -ADD_PLUGIN([hmac], [s charon scripts nm]) -ADD_PLUGIN([ctr], [s charon scripts nm]) -ADD_PLUGIN([ccm], [s charon scripts nm]) -ADD_PLUGIN([gcm], [s charon scripts nm]) +ADD_PLUGIN([openssl], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) +ADD_PLUGIN([gcrypt], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) +ADD_PLUGIN([af-alg], [s charon openac scepclient pki scripts medsrv attest nm cmd]) +ADD_PLUGIN([fips-prf], [s charon nm cmd]) +ADD_PLUGIN([gmp], [s charon openac scepclient pki scripts manager medsrv attest nm cmd]) +ADD_PLUGIN([agent], [s charon nm cmd]) +ADD_PLUGIN([xcbc], [s charon nm cmd]) +ADD_PLUGIN([cmac], [s charon nm cmd]) +ADD_PLUGIN([hmac], [s charon scripts nm cmd]) +ADD_PLUGIN([ctr], [s charon scripts nm cmd]) +ADD_PLUGIN([ccm], [s charon scripts nm cmd]) +ADD_PLUGIN([gcm], [s charon scripts nm cmd]) ADD_PLUGIN([attr], [h charon]) ADD_PLUGIN([attr-sql], [h charon]) ADD_PLUGIN([load-tester], [c charon]) -ADD_PLUGIN([kernel-pfkey], [h charon starter nm]) -ADD_PLUGIN([kernel-pfroute], [h charon starter nm]) +ADD_PLUGIN([kernel-pfkey], [h charon starter nm cmd]) +ADD_PLUGIN([kernel-pfroute], [h charon starter nm cmd]) ADD_PLUGIN([kernel-klips], [h charon starter]) -ADD_PLUGIN([kernel-netlink], [h charon starter nm]) -ADD_PLUGIN([resolve], [h charon]) -ADD_PLUGIN([socket-default], [c charon nm]) +ADD_PLUGIN([kernel-netlink], [h charon starter nm cmd]) +ADD_PLUGIN([resolve], [h charon cmd]) +ADD_PLUGIN([socket-default], [c charon nm cmd]) ADD_PLUGIN([socket-dynamic], [c charon]) ADD_PLUGIN([farp], [c charon]) ADD_PLUGIN([stroke], [c charon]) ADD_PLUGIN([smp], [c charon]) ADD_PLUGIN([sql], [c charon]) ADD_PLUGIN([updown], [c charon]) -ADD_PLUGIN([eap-identity], [c charon nm]) +ADD_PLUGIN([eap-identity], [c charon nm cmd]) ADD_PLUGIN([eap-sim], [c charon]) ADD_PLUGIN([eap-sim-file], [c charon]) ADD_PLUGIN([eap-sim-pcsc], [c charon]) @@ -1004,16 +1006,16 @@ ADD_PLUGIN([eap-aka-3gpp2], [c charon]) ADD_PLUGIN([eap-simaka-sql], [c charon]) ADD_PLUGIN([eap-simaka-pseudonym], [c charon]) ADD_PLUGIN([eap-simaka-reauth], [c charon]) -ADD_PLUGIN([eap-md5], [c charon nm]) -ADD_PLUGIN([eap-gtc], [c charon nm]) -ADD_PLUGIN([eap-mschapv2], [c charon nm]) +ADD_PLUGIN([eap-md5], [c charon nm cmd]) +ADD_PLUGIN([eap-gtc], [c charon nm cmd]) +ADD_PLUGIN([eap-mschapv2], [c charon nm cmd]) ADD_PLUGIN([eap-dynamic], [c charon]) ADD_PLUGIN([eap-radius], [c charon]) -ADD_PLUGIN([eap-tls], [c charon nm]) -ADD_PLUGIN([eap-ttls], [c charon nm]) -ADD_PLUGIN([eap-peap], [c charon nm]) +ADD_PLUGIN([eap-tls], [c charon nm cmd]) +ADD_PLUGIN([eap-ttls], [c charon nm cmd]) +ADD_PLUGIN([eap-peap], [c charon nm cmd]) ADD_PLUGIN([eap-tnc], [c charon]) -ADD_PLUGIN([xauth-generic], [c charon]) +ADD_PLUGIN([xauth-generic], [c charon cmd]) ADD_PLUGIN([xauth-eap], [c charon]) ADD_PLUGIN([xauth-pam], [c charon]) ADD_PLUGIN([xauth-noauth], [c charon]) @@ -1057,6 +1059,7 @@ AC_SUBST(scripts_plugins) AC_SUBST(manager_plugins) AC_SUBST(medsrv_plugins) AC_SUBST(nm_plugins) +AC_SUBST(cmd_plugins) AC_SUBST(c_plugins) AC_SUBST(h_plugins) @@ -1209,9 +1212,9 @@ AM_CONDITIONAL(USE_NM, test x$nm = xtrue) AM_CONDITIONAL(USE_TOOLS, test x$tools = xtrue) AM_CONDITIONAL(USE_SCRIPTS, test x$scripts = xtrue) AM_CONDITIONAL(USE_CONFTEST, test x$conftest = xtrue) -AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue) -AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue) -AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue) +AM_CONDITIONAL(USE_LIBSTRONGSWAN, test x$charon = xtrue -o x$tools = xtrue -o x$conftest = xtrue -o x$fast = xtrue -o x$imcv = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue) +AM_CONDITIONAL(USE_LIBHYDRA, test x$charon = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue) +AM_CONDITIONAL(USE_LIBCHARON, test x$charon = xtrue -o x$conftest = xtrue -o x$nm = xtrue -o x$tkm = xtrue -o x$cmd = xtrue) AM_CONDITIONAL(USE_LIBIPSEC, test x$libipsec = xtrue) AM_CONDITIONAL(USE_LIBTNCIF, test x$tnc_tnccs = xtrue -o x$imcv = xtrue) AM_CONDITIONAL(USE_LIBTNCCS, test x$tnc_tnccs = xtrue) @@ -1230,6 +1233,7 @@ AM_CONDITIONAL(MONOLITHIC, test x$monolithic = xtrue) AM_CONDITIONAL(USE_SILENT_RULES, test x$enable_silent_rules = xyes) AM_CONDITIONAL(UNITTESTS, test x$unit_tests = xtrue) AM_CONDITIONAL(USE_TKM, test x$tkm = xtrue) +AM_CONDITIONAL(USE_CMD, test x$cmd = xtrue) # ======================== # set global definitions @@ -1332,6 +1336,7 @@ AC_CONFIG_FILES([ src/charon/Makefile src/charon-nm/Makefile src/charon-tkm/Makefile + src/charon-cmd/Makefile src/libcharon/Makefile src/libcharon/plugins/eap_aka/Makefile src/libcharon/plugins/eap_aka_3gpp2/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index 07953b0b0..47299b03c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -104,6 +104,10 @@ if USE_TKM SUBDIRS += charon-tkm endif +if USE_CMD + SUBDIRS += charon-cmd +endif + EXTRA_DIST = strongswan.conf install-exec-local : diff --git a/src/charon-cmd/.gitignore b/src/charon-cmd/.gitignore new file mode 100644 index 000000000..c02dfbacc --- /dev/null +++ b/src/charon-cmd/.gitignore @@ -0,0 +1 @@ +charon-cmd diff --git a/src/charon-cmd/Makefile.am b/src/charon-cmd/Makefile.am new file mode 100644 index 000000000..de1580e3b --- /dev/null +++ b/src/charon-cmd/Makefile.am @@ -0,0 +1,22 @@ +sbin_PROGRAMS = charon-cmd + +charon_cmd_SOURCES = \ +charon-cmd.c + +charon-cmd.o : $(top_builddir)/config.status + +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = \ + -DIPSEC_DIR=\"${ipsecdir}\" \ + -DIPSEC_PIDDIR=\"${piddir}\" \ + -DPLUGINS=\""${cmd_plugins}\"" + +charon_cmd_LDADD = \ + $(top_builddir)/src/libstrongswan/libstrongswan.la \ + $(top_builddir)/src/libhydra/libhydra.la \ + $(top_builddir)/src/libcharon/libcharon.la \ + -lm $(PTHREADLIB) $(DLLIB) diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c new file mode 100644 index 000000000..b2cb6e810 --- /dev/null +++ b/src/charon-cmd/charon-cmd.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2006-2012 Tobias Brunner + * Copyright (C) 2005-2013 Martin Willi + * Copyright (C) 2006 Daniel Roethlisberger + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 . + * + * 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 +#define _POSIX_PTHREAD_SEMANTICS /* for two param sigwait on OpenSolaris */ +#include +#undef _POSIX_PTHREAD_SEMANTICS +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/** + * Loglevel configuration + */ +static level_t levels[DBG_MAX]; + +/** + * hook in library for debugging messages + */ +extern void (*dbg) (debug_t group, level_t level, char *fmt, ...); + +/** + * Logging hook for library logs, using stderr output + */ +static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) +{ + va_list args; + + if (level <= 1) + { + va_start(args, fmt); + fprintf(stderr, "00[%N] ", debug_names, group); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + } +} + +/** + * Run the daemon and handle unix signals + */ +static void run() +{ + sigset_t set; + + /* handle SIGINT, SIGHUP ans SIGTERM in this handler */ + sigemptyset(&set); + sigaddset(&set, SIGINT); + sigaddset(&set, SIGHUP); + sigaddset(&set, SIGTERM); + sigprocmask(SIG_BLOCK, &set, NULL); + + while (TRUE) + { + int sig; + int error; + + error = sigwait(&set, &sig); + if (error) + { + DBG1(DBG_DMN, "error %d while waiting for a signal", error); + return; + } + switch (sig) + { + case SIGHUP: + { + DBG1(DBG_DMN, "signal of type SIGHUP received. Reloading " + "configuration"); + if (lib->settings->load_files(lib->settings, NULL, FALSE)) + { + charon->load_loggers(charon, levels, TRUE); + lib->plugins->reload(lib->plugins, NULL); + } + else + { + DBG1(DBG_DMN, "reloading config failed, keeping old"); + } + break; + } + case SIGINT: + { + DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return; + } + case SIGTERM: + { + DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return; + } + default: + { + DBG1(DBG_DMN, "unknown signal %d received. Ignored", sig); + break; + } + } + } +} + +/** + * lookup UID and GID + */ +static bool lookup_uid_gid() +{ +#ifdef IPSEC_USER + if (!charon->caps->resolve_uid(charon->caps, IPSEC_USER)) + { + return FALSE; + } +#endif +#ifdef IPSEC_GROUP + if (!charon->caps->resolve_gid(charon->caps, IPSEC_GROUP)) + { + return FALSE; + } +#endif + return TRUE; +} + +/** + * Handle SIGSEGV/SIGILL signals raised by threads + */ +static void segv_handler(int signal) +{ + backtrace_t *backtrace; + + DBG1(DBG_DMN, "thread %u received %d", thread_current_id(), signal); + backtrace = backtrace_create(2); + backtrace->log(backtrace, stderr, TRUE); + backtrace->destroy(backtrace); + + DBG1(DBG_DMN, "killing ourself, received critical signal"); + abort(); +} + +/** + * Command line arguments, similar to "struct option", but with descriptions + */ +static struct { + /** long option name */ + const char *lng; + /** short option name */ + const char shrt; + /** takes argument */ + int has_arg; + /** decription of argument */ + const char *arg; + /** description to option */ + const char *desc; +} options[] = { + { "help", 'h', no_argument, "", + "print this usage information and exit" }, + { "version", 'v', no_argument, "", + "show version information and exit" }, +}; + +/** + * Print command line usage and exit + */ +static void usage(FILE *out, char *msg, char *binary) +{ + int i, pre, post, padto = 0, spacing = 2; + + for (i = 0; i < countof(options); i++) + { + padto = max(padto, strlen(options[i].lng) + strlen(options[i].arg)); + } + padto += spacing; + + if (msg) + { + fprintf(out, "%s\n", msg); + } + fprintf(out, "Usage: %s\n", binary); + for (i = 0; i < countof(options); i++) + { + switch (options[i].has_arg) + { + case required_argument: + pre = '<'; + post = '>'; + break; + case optional_argument: + pre = '['; + post = ']'; + break; + case no_argument: + default: + pre = post = ' '; + break; + } + fprintf(out, " --%s (-%-c) %c%s%c %-*s%s\n", + options[i].lng, options[i].shrt, + pre, options[i].arg, post, + padto - strlen(options[i].lng) - strlen(options[i].arg), "", + options[i].desc); + } +} + +/** + * Handle command line options + */ +static void handle_arguments(int argc, char *argv[]) +{ + while (TRUE) + { + struct option long_opts[countof(options) + 1] = {}; + char optstring[countof(options) * 3 + 1] = {}; + int i, pos = 0; + + for (i = 0; i < countof(options); i++) + { + long_opts[i].name = options[i].lng; + long_opts[i].val = options[i].shrt; + long_opts[i].has_arg = options[i].has_arg; + optstring[pos++] = options[i].shrt; + switch (options[i].has_arg) + { + case optional_argument: + optstring[pos++] = ':'; + /* FALL */ + case required_argument: + optstring[pos++] = ':'; + /* FALL */ + case no_argument: + default: + break; + } + } + + switch (getopt_long(argc, argv, optstring, long_opts, NULL)) + { + case EOF: + break; + case 'h': + usage(stdout, NULL, argv[0]); + exit(0); + case 'v': + printf("%s, strongSwan %s\n", "charon-cmd", VERSION); + exit(0); + default: + usage(stderr, NULL, argv[0]); + exit(1); + } + break; + } +} + +/** + * Main function, starts the daemon. + */ +int main(int argc, char *argv[]) +{ + struct sigaction action; + struct utsname utsname; + int group; + + dbg = dbg_stderr; + atexit(library_deinit); + if (!library_init(NULL)) + { + exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); + } + if (lib->integrity) + { + if (!lib->integrity->check_file(lib->integrity, "charon-cmd", argv[0])) + { + exit(SS_RC_DAEMON_INTEGRITY); + } + } + atexit(libhydra_deinit); + if (!libhydra_init("charon-cmd")) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + atexit(libcharon_deinit); + if (!libcharon_init("charon-cmd")) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + for (group = 0; group < DBG_MAX; group++) + { + levels[group] = LEVEL_CTRL; + } + + handle_arguments(argc, argv); + + if (!lookup_uid_gid()) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + charon->load_loggers(charon, levels, TRUE); + + if (uname(&utsname) != 0) + { + memset(&utsname, 0, sizeof(utsname)); + } + DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)", + VERSION, utsname.sysname, utsname.release, utsname.machine); + + if (!charon->initialize(charon, + lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS))) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + if (!charon->caps->drop(charon->caps)) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + + /* add handler for SEGV and ILL, + * INT, TERM and HUP are handled by sigwait() in run() */ + action.sa_handler = segv_handler; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGINT); + sigaddset(&action.sa_mask, SIGTERM); + sigaddset(&action.sa_mask, SIGHUP); + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGILL, &action, NULL); + sigaction(SIGBUS, &action, NULL); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + + pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL); + + /* start daemon with thread-pool */ + charon->start(charon); + /* wait for signal */ + run(); + + return 0; +} diff --git a/src/checksum/Makefile.am b/src/checksum/Makefile.am index 9f6945087..aabd96e77 100644 --- a/src/checksum/Makefile.am +++ b/src/checksum/Makefile.am @@ -84,6 +84,10 @@ if !MONOLITHIC endif endif +if USE_CMD + exes += $(top_builddir)/src/charon-cmd/.libs/charon-cmd +endif + if USE_TOOLS exes += $(top_builddir)/src/openac/.libs/openac exes += $(top_builddir)/src/pki/.libs/pki -- cgit v1.2.3 From be44723de05bc0cfd6e12a8126e07e211b2d16bb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 14:10:00 +0100 Subject: charon-cmd: move command line options to separate file, obsolete short options --- src/charon-cmd/Makefile.am | 3 +- src/charon-cmd/charon-cmd.c | 74 ++++++++++++---------------------------- src/charon-cmd/cmd/cmd_options.c | 28 +++++++++++++++ src/charon-cmd/cmd/cmd_options.h | 58 +++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 54 deletions(-) create mode 100644 src/charon-cmd/cmd/cmd_options.c create mode 100644 src/charon-cmd/cmd/cmd_options.h diff --git a/src/charon-cmd/Makefile.am b/src/charon-cmd/Makefile.am index de1580e3b..cd949e08f 100644 --- a/src/charon-cmd/Makefile.am +++ b/src/charon-cmd/Makefile.am @@ -1,7 +1,8 @@ sbin_PROGRAMS = charon-cmd charon_cmd_SOURCES = \ -charon-cmd.c + cmd/cmd_options.h cmd/cmd_options.c \ + charon-cmd.c charon-cmd.o : $(top_builddir)/config.status diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index b2cb6e810..f93b619db 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -32,6 +32,8 @@ #include #include +#include "cmd/cmd_options.h" + /** * Loglevel configuration */ @@ -158,27 +160,6 @@ static void segv_handler(int signal) abort(); } -/** - * Command line arguments, similar to "struct option", but with descriptions - */ -static struct { - /** long option name */ - const char *lng; - /** short option name */ - const char shrt; - /** takes argument */ - int has_arg; - /** decription of argument */ - const char *arg; - /** description to option */ - const char *desc; -} options[] = { - { "help", 'h', no_argument, "", - "print this usage information and exit" }, - { "version", 'v', no_argument, "", - "show version information and exit" }, -}; - /** * Print command line usage and exit */ @@ -186,9 +167,10 @@ static void usage(FILE *out, char *msg, char *binary) { int i, pre, post, padto = 0, spacing = 2; - for (i = 0; i < countof(options); i++) + for (i = 0; i < CMD_OPT_COUNT; i++) { - padto = max(padto, strlen(options[i].lng) + strlen(options[i].arg)); + padto = max(padto, strlen(cmd_options[i].name) + + strlen(cmd_options[i].arg)); } padto += spacing; @@ -197,9 +179,9 @@ static void usage(FILE *out, char *msg, char *binary) fprintf(out, "%s\n", msg); } fprintf(out, "Usage: %s\n", binary); - for (i = 0; i < countof(options); i++) + for (i = 0; i < CMD_OPT_COUNT; i++) { - switch (options[i].has_arg) + switch (cmd_options[i].has_arg) { case required_argument: pre = '<'; @@ -214,11 +196,11 @@ static void usage(FILE *out, char *msg, char *binary) pre = post = ' '; break; } - fprintf(out, " --%s (-%-c) %c%s%c %-*s%s\n", - options[i].lng, options[i].shrt, - pre, options[i].arg, post, - padto - strlen(options[i].lng) - strlen(options[i].arg), "", - options[i].desc); + fprintf(out, " --%s %c%s%c %-*s%s\n", + cmd_options[i].name, + pre, cmd_options[i].arg, post, + padto - strlen(cmd_options[i].name) - strlen(cmd_options[i].arg), "", + cmd_options[i].desc); } } @@ -229,38 +211,24 @@ static void handle_arguments(int argc, char *argv[]) { while (TRUE) { - struct option long_opts[countof(options) + 1] = {}; - char optstring[countof(options) * 3 + 1] = {}; - int i, pos = 0; + struct option long_opts[CMD_OPT_COUNT + 1] = {}; + int i; - for (i = 0; i < countof(options); i++) + for (i = 0; i < CMD_OPT_COUNT; i++) { - long_opts[i].name = options[i].lng; - long_opts[i].val = options[i].shrt; - long_opts[i].has_arg = options[i].has_arg; - optstring[pos++] = options[i].shrt; - switch (options[i].has_arg) - { - case optional_argument: - optstring[pos++] = ':'; - /* FALL */ - case required_argument: - optstring[pos++] = ':'; - /* FALL */ - case no_argument: - default: - break; - } + long_opts[i].name = cmd_options[i].name; + long_opts[i].val = cmd_options[i].id; + long_opts[i].has_arg = cmd_options[i].has_arg; } - switch (getopt_long(argc, argv, optstring, long_opts, NULL)) + switch (getopt_long(argc, argv, "", long_opts, NULL)) { case EOF: break; - case 'h': + case CMD_OPT_HELP: usage(stdout, NULL, argv[0]); exit(0); - case 'v': + case CMD_OPT_VERSION: printf("%s, strongSwan %s\n", "charon-cmd", VERSION); exit(0); default: diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c new file mode 100644 index 000000000..997cd3431 --- /dev/null +++ b/src/charon-cmd/cmd/cmd_options.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "cmd_options.h" + +#include + +/** + * See header. + */ +cmd_option_t cmd_options[CMD_OPT_COUNT] = { + { CMD_OPT_HELP, "help", no_argument, "", + "print this usage information and exit" }, + { CMD_OPT_VERSION, "version", no_argument, "", + "show version information and exit" }, +}; diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h new file mode 100644 index 000000000..d453a53eb --- /dev/null +++ b/src/charon-cmd/cmd/cmd_options.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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. + */ + +/** + * @defgroup cmd_option cmd_option + * @{ @ingroup cmd + */ + +#ifndef CMD_OPTION_H_ +#define CMD_OPTION_H_ + +typedef struct cmd_option_t cmd_option_t; +typedef enum cmd_option_type_t cmd_option_type_t; + +/** + * Command line options + */ +enum cmd_option_type_t { + CMD_OPT_HELP, + CMD_OPT_VERSION, + + CMD_OPT_COUNT +}; + +/** + * Command line arguments, similar to "struct option", but with descriptions + */ +struct cmd_option_t { + /** option identifier */ + cmd_option_type_t id; + /** long option name */ + const char *name; + /** takes argument */ + int has_arg; + /** decription of argument */ + const char *arg; + /** description to option */ + const char *desc; +}; + +/** + * Registered CMD options. + */ +extern cmd_option_t cmd_options[CMD_OPT_COUNT]; + +#endif /** CMD_OPTION_H_ @}*/ -- cgit v1.2.3 From 78d7a0f7e29af35902250cfd4f52bceee9a1608d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 15:07:15 +0100 Subject: charon-cmd: add a connection object and its initiation to charon-cmd --- src/charon-cmd/Makefile.am | 1 + src/charon-cmd/charon-cmd.c | 45 ++++++-- src/charon-cmd/cmd/cmd_connection.c | 216 ++++++++++++++++++++++++++++++++++++ src/charon-cmd/cmd/cmd_connection.h | 55 +++++++++ src/charon-cmd/cmd/cmd_options.c | 4 + src/charon-cmd/cmd/cmd_options.h | 2 + 6 files changed, 313 insertions(+), 10 deletions(-) create mode 100644 src/charon-cmd/cmd/cmd_connection.c create mode 100644 src/charon-cmd/cmd/cmd_connection.h diff --git a/src/charon-cmd/Makefile.am b/src/charon-cmd/Makefile.am index cd949e08f..ff360c18c 100644 --- a/src/charon-cmd/Makefile.am +++ b/src/charon-cmd/Makefile.am @@ -2,6 +2,7 @@ sbin_PROGRAMS = charon-cmd charon_cmd_SOURCES = \ cmd/cmd_options.h cmd/cmd_options.c \ + cmd/cmd_connection.h cmd/cmd_connection.c \ charon-cmd.c charon-cmd.o : $(top_builddir)/config.status diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index f93b619db..90cc8b6fa 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -33,12 +33,18 @@ #include #include "cmd/cmd_options.h" +#include "cmd/cmd_connection.h" /** * Loglevel configuration */ static level_t levels[DBG_MAX]; +/** + * Connection to initiate + */ +static cmd_connection_t *conn; + /** * hook in library for debugging messages */ @@ -61,18 +67,27 @@ static void dbg_stderr(debug_t group, level_t level, char *fmt, ...) } } +/** + * Clean up connection definition atexit() + */ +static void cleanup_conn() +{ + DESTROY_IF(conn); +} + /** * Run the daemon and handle unix signals */ -static void run() +static int run() { sigset_t set; - /* handle SIGINT, SIGHUP ans SIGTERM in this handler */ + /* handle SIGINT, SIGHUP and SIGTERM in this handler */ sigemptyset(&set); sigaddset(&set, SIGINT); sigaddset(&set, SIGHUP); sigaddset(&set, SIGTERM); + sigaddset(&set, SIGUSR1); sigprocmask(SIG_BLOCK, &set, NULL); while (TRUE) @@ -84,7 +99,7 @@ static void run() if (error) { DBG1(DBG_DMN, "error %d while waiting for a signal", error); - return; + return 1; } switch (sig) { @@ -107,13 +122,18 @@ static void run() { DBG1(DBG_DMN, "signal of type SIGINT received. Shutting down"); charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); - return; + return 0; } case SIGTERM: { DBG1(DBG_DMN, "signal of type SIGTERM received. Shutting down"); charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); - return; + return 0; + } + case SIGUSR1: + { /* an error occured */ + charon->bus->alert(charon->bus, ALERT_SHUTDOWN_SIGNAL, sig); + return 1; } default: { @@ -212,7 +232,7 @@ static void handle_arguments(int argc, char *argv[]) while (TRUE) { struct option long_opts[CMD_OPT_COUNT + 1] = {}; - int i; + int i, opt; for (i = 0; i < CMD_OPT_COUNT; i++) { @@ -221,7 +241,8 @@ static void handle_arguments(int argc, char *argv[]) long_opts[i].has_arg = cmd_options[i].has_arg; } - switch (getopt_long(argc, argv, "", long_opts, NULL)) + opt = getopt_long(argc, argv, "", long_opts, NULL); + switch (opt) { case EOF: break; @@ -232,6 +253,10 @@ static void handle_arguments(int argc, char *argv[]) printf("%s, strongSwan %s\n", "charon-cmd", VERSION); exit(0); default: + if (conn->handle(conn, opt, optarg)) + { + continue; + } usage(stderr, NULL, argv[0]); exit(1); } @@ -275,6 +300,8 @@ int main(int argc, char *argv[]) { levels[group] = LEVEL_CTRL; } + conn = cmd_connection_create(); + atexit(cleanup_conn); handle_arguments(argc, argv); @@ -320,7 +347,5 @@ int main(int argc, char *argv[]) /* start daemon with thread-pool */ charon->start(charon); /* wait for signal */ - run(); - - return 0; + return run(); } diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c new file mode 100644 index 000000000..566b2544b --- /dev/null +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "cmd_connection.h" + +#include +#include + +#include +#include +#include + +typedef struct private_cmd_connection_t private_cmd_connection_t; + +/** + * Private data of an cmd_connection_t object. + */ +struct private_cmd_connection_t { + + /** + * Public cmd_connection_t interface. + */ + cmd_connection_t public; + + /** + * Process ID to terminate on failure + */ + pid_t pid; + + /** + * Hostname to connect to + */ + char *host; + + /** + * Local identity + */ + char *identity; +}; + +/** + * Shut down application + */ +static void terminate(private_cmd_connection_t *this) +{ + kill(this->pid, SIGUSR1); +} + +/** + * Create peer config with associated ike config + */ +static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) +{ + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + + ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, + charon->socket->get_port(charon->socket, FALSE), + this->host, FALSE, IKEV2_UDP_PORT, + FRAGMENTATION_NO, 0); + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + peer_cfg = peer_cfg_create("cmd", ike_cfg, + CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ + 36000, 0, /* rekey 10h, reauth none */ + 600, 600, /* jitter, over 10min */ + TRUE, FALSE, /* mobike, aggressive */ + 30, 0, /* DPD delay, timeout */ + FALSE, NULL, NULL); /* mediation */ + peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0)); + + return peer_cfg; +} + +/** + * Attach authentication configs to peer config + */ +static void add_auth_cfgs(private_cmd_connection_t *this, peer_cfg_t *peer_cfg) +{ + auth_cfg_t *auth; + + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_string(this->identity)); + peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); + + auth = auth_cfg_create(); + + auth->add(auth, AUTH_RULE_IDENTITY, + identification_create_from_string(this->host)); + peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); +} + +/** + * Attach child config to peer config + */ +static child_cfg_t* create_child_cfg(private_cmd_connection_t *this) +{ + child_cfg_t *child_cfg; + traffic_selector_t *ts; + lifetime_cfg_t lifetime = { + .time = { + .life = 10800 /* 3h */, + .rekey = 10200 /* 2h50min */, + .jitter = 300 /* 5min */ + } + }; + + child_cfg = child_cfg_create("cmd", &lifetime, + NULL, FALSE, MODE_TUNNEL, /* updown, hostaccess */ + ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, + 0, 0, NULL, NULL, 0); + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + ts = traffic_selector_create_dynamic(0, 0, 65535); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts); + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, + "0.0.0.0", 0, "255.255.255.255", 65535); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts); + + return child_cfg; +} + +/** + * Initiate the configured connection + */ +static job_requeue_t initiate(private_cmd_connection_t *this) +{ + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + + if (!this->host) + { + DBG1(DBG_CFG, "unable to initiate, missing --host option"); + terminate(this); + return JOB_REQUEUE_NONE; + } + if (!this->identity) + { + DBG1(DBG_CFG, "unable to initiate, missing --identity option"); + terminate(this); + return JOB_REQUEUE_NONE; + } + + peer_cfg = create_peer_cfg(this); + + add_auth_cfgs(this, peer_cfg); + + child_cfg = create_child_cfg(this); + peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg)); + + if (charon->controller->initiate(charon->controller, peer_cfg, child_cfg, + controller_cb_empty, NULL, 0) != SUCCESS) + { + terminate(this); + } + return JOB_REQUEUE_NONE; +} + +METHOD(cmd_connection_t, handle, bool, + private_cmd_connection_t *this, cmd_option_type_t opt, char *arg) +{ + switch (opt) + { + case CMD_OPT_HOST: + this->host = arg; + break; + case CMD_OPT_IDENTITY: + this->identity = arg; + break; + default: + return FALSE; + } + return TRUE; +} + +METHOD(cmd_connection_t, destroy, void, + private_cmd_connection_t *this) +{ + free(this); +} + +/** + * See header + */ +cmd_connection_t *cmd_connection_create() +{ + private_cmd_connection_t *this; + + INIT(this, + .public = { + .handle = _handle, + .destroy = _destroy, + }, + .pid = getpid(), + ); + + /* queue job, gets initiated as soon as we are up and running */ + lib->processor->queue_job(lib->processor, + (job_t*)callback_job_create_with_prio( + (callback_job_cb_t)initiate, this, NULL, + (callback_job_cancel_t)return_false, JOB_PRIO_CRITICAL)); + + return &this->public; +} diff --git a/src/charon-cmd/cmd/cmd_connection.h b/src/charon-cmd/cmd/cmd_connection.h new file mode 100644 index 000000000..0f167bfdc --- /dev/null +++ b/src/charon-cmd/cmd/cmd_connection.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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. + */ + +/** + * @defgroup cmd_connection cmd_connection + * @{ @ingroup cmd + */ + +#ifndef CMD_CONNECTION_H_ +#define CMD_CONNECTION_H_ + +#include + +#include "cmd_options.h" + +typedef struct cmd_connection_t cmd_connection_t; + +/** + * Connection definition to construct and initiate. + */ +struct cmd_connection_t { + + /** + * Handle a command line option. + * + * @param opt option to handle + * @param arg option argument + * @return TRUE if option handled + */ + bool (*handle)(cmd_connection_t *this, cmd_option_type_t opt, char *arg); + + /** + * Destroy a cmd_connection_t. + */ + void (*destroy)(cmd_connection_t *this); +}; + +/** + * Create a cmd_connection instance. + */ +cmd_connection_t *cmd_connection_create(); + +#endif /** CMD_CONNECTION_H_ @}*/ diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c index 997cd3431..899cdd119 100644 --- a/src/charon-cmd/cmd/cmd_options.c +++ b/src/charon-cmd/cmd/cmd_options.c @@ -25,4 +25,8 @@ cmd_option_t cmd_options[CMD_OPT_COUNT] = { "print this usage information and exit" }, { CMD_OPT_VERSION, "version", no_argument, "", "show version information and exit" }, + { CMD_OPT_HOST, "host", required_argument, "hostname", + "DNS name or address to connect to" }, + { CMD_OPT_IDENTITY, "identity", required_argument, "identity", + "identity the client uses for the IKE exchange" }, }; diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h index d453a53eb..81fb54fe1 100644 --- a/src/charon-cmd/cmd/cmd_options.h +++ b/src/charon-cmd/cmd/cmd_options.h @@ -30,6 +30,8 @@ typedef enum cmd_option_type_t cmd_option_type_t; enum cmd_option_type_t { CMD_OPT_HELP, CMD_OPT_VERSION, + CMD_OPT_HOST, + CMD_OPT_IDENTITY, CMD_OPT_COUNT }; -- cgit v1.2.3 From 2baa7bbedb7d1ffd149fc326dfe28ed81dbcd09f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 15:42:06 +0100 Subject: charon-cmd: load certificates and RSA private keys --- src/charon-cmd/Makefile.am | 1 + src/charon-cmd/charon-cmd.c | 45 ++++++++++----- src/charon-cmd/cmd/cmd_creds.c | 117 +++++++++++++++++++++++++++++++++++++++ src/charon-cmd/cmd/cmd_creds.h | 55 ++++++++++++++++++ src/charon-cmd/cmd/cmd_options.c | 4 ++ src/charon-cmd/cmd/cmd_options.h | 2 + 6 files changed, 210 insertions(+), 14 deletions(-) create mode 100644 src/charon-cmd/cmd/cmd_creds.c create mode 100644 src/charon-cmd/cmd/cmd_creds.h diff --git a/src/charon-cmd/Makefile.am b/src/charon-cmd/Makefile.am index ff360c18c..2c9f1ba1f 100644 --- a/src/charon-cmd/Makefile.am +++ b/src/charon-cmd/Makefile.am @@ -3,6 +3,7 @@ sbin_PROGRAMS = charon-cmd charon_cmd_SOURCES = \ cmd/cmd_options.h cmd/cmd_options.c \ cmd/cmd_connection.h cmd/cmd_connection.c \ + cmd/cmd_creds.h cmd/cmd_creds.c \ charon-cmd.c charon-cmd.o : $(top_builddir)/config.status diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index 90cc8b6fa..4969c9645 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -34,6 +34,7 @@ #include "cmd/cmd_options.h" #include "cmd/cmd_connection.h" +#include "cmd/cmd_creds.h" /** * Loglevel configuration @@ -45,6 +46,11 @@ static level_t levels[DBG_MAX]; */ static cmd_connection_t *conn; +/** + * Credential backend + */ +static cmd_creds_t *creds; + /** * hook in library for debugging messages */ @@ -75,6 +81,14 @@ static void cleanup_conn() DESTROY_IF(conn); } +/** + * Clean up credentials atexit() + */ +static void cleanup_creds() +{ + DESTROY_IF(creds); +} + /** * Run the daemon and handle unix signals */ @@ -253,7 +267,8 @@ static void handle_arguments(int argc, char *argv[]) printf("%s, strongSwan %s\n", "charon-cmd", VERSION); exit(0); default: - if (conn->handle(conn, opt, optarg)) + if (conn->handle(conn, opt, optarg) || + creds->handle(creds, opt, optarg)) { continue; } @@ -300,24 +315,12 @@ int main(int argc, char *argv[]) { levels[group] = LEVEL_CTRL; } - conn = cmd_connection_create(); - atexit(cleanup_conn); - - handle_arguments(argc, argv); + charon->load_loggers(charon, levels, TRUE); if (!lookup_uid_gid()) { exit(SS_RC_INITIALIZATION_FAILED); } - charon->load_loggers(charon, levels, TRUE); - - if (uname(&utsname) != 0) - { - memset(&utsname, 0, sizeof(utsname)); - } - DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)", - VERSION, utsname.sysname, utsname.release, utsname.machine); - if (!charon->initialize(charon, lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS))) { @@ -328,6 +331,20 @@ int main(int argc, char *argv[]) exit(SS_RC_INITIALIZATION_FAILED); } + conn = cmd_connection_create(); + atexit(cleanup_conn); + creds = cmd_creds_create(); + atexit(cleanup_creds); + + handle_arguments(argc, argv); + + if (uname(&utsname) != 0) + { + memset(&utsname, 0, sizeof(utsname)); + } + DBG1(DBG_DMN, "Starting charon-cmd IKE client (strongSwan %s, %s %s, %s)", + VERSION, utsname.sysname, utsname.release, utsname.machine); + /* add handler for SEGV and ILL, * INT, TERM and HUP are handled by sigwait() in run() */ action.sa_handler = segv_handler; diff --git a/src/charon-cmd/cmd/cmd_creds.c b/src/charon-cmd/cmd/cmd_creds.c new file mode 100644 index 000000000..45f16522b --- /dev/null +++ b/src/charon-cmd/cmd/cmd_creds.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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 "cmd_creds.h" + +#include +#include + +typedef struct private_cmd_creds_t private_cmd_creds_t; + +/** + * Private data of an cmd_creds_t object. + */ +struct private_cmd_creds_t { + + /** + * Public cmd_creds_t interface. + */ + cmd_creds_t public; + + /** + * Reused in-memory credential set + */ + mem_cred_t *creds; +}; + +/** + * Load a trusted certificate from path + */ +static void load_cert(private_cmd_creds_t *this, char *path) +{ + certificate_t *cert; + + cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_FROM_FILE, path, BUILD_END); + if (!cert) + { + DBG1(DBG_CFG, "loading certificate from '%s' failed", path); + exit(1); + } + this->creds->add_cert(this->creds, TRUE, cert); +} + +/** + * Load a private key of given kind from path + */ +static void load_key(private_cmd_creds_t *this, key_type_t type, char *path) +{ + private_key_t *privkey; + + privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, + BUILD_FROM_FILE, path, BUILD_END); + if (!privkey) + { + DBG1(DBG_CFG, "loading %N private key from '%s' failed", + key_type_names, type, path); + exit(1); + } + this->creds->add_key(this->creds, privkey); +} + +METHOD(cmd_creds_t, handle, bool, + private_cmd_creds_t *this, cmd_option_type_t opt, char *arg) +{ + switch (opt) + { + case CMD_OPT_CERT: + load_cert(this, arg); + break; + case CMD_OPT_RSA: + load_key(this, KEY_RSA, arg); + break; + default: + return FALSE; + } + return TRUE; +} + +METHOD(cmd_creds_t, destroy, void, + private_cmd_creds_t *this) +{ + lib->credmgr->remove_set(lib->credmgr, &this->creds->set); + this->creds->destroy(this->creds); + free(this); +} + +/** + * See header + */ +cmd_creds_t *cmd_creds_create() +{ + private_cmd_creds_t *this; + + INIT(this, + .public = { + .handle = _handle, + .destroy = _destroy, + }, + .creds = mem_cred_create(), + ); + + lib->credmgr->add_set(lib->credmgr, &this->creds->set); + + return &this->public; +} diff --git a/src/charon-cmd/cmd/cmd_creds.h b/src/charon-cmd/cmd/cmd_creds.h new file mode 100644 index 000000000..053e596a5 --- /dev/null +++ b/src/charon-cmd/cmd/cmd_creds.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * 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 . + * + * 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. + */ + +/** + * @defgroup cmd_creds cmd_creds + * @{ @ingroup cmd + */ + +#ifndef CMD_CREDS_H_ +#define CMD_CREDS_H_ + +#include + +#include "cmd_options.h" + +typedef struct cmd_creds_t cmd_creds_t; + +/** + * Credential backend providing certificates, private keys and shared secrets. + */ +struct cmd_creds_t { + + /** + * Handle a command line options related to credentials. + * + * @param opt option to handle + * @param arg option argument + * @return TRUE if option handled + */ + bool (*handle)(cmd_creds_t *this, cmd_option_type_t opt, char *arg); + + /** + * Destroy a cmd_creds_t. + */ + void (*destroy)(cmd_creds_t *this); +}; + +/** + * Create a cmd_creds instance. + */ +cmd_creds_t *cmd_creds_create(); + +#endif /** CMD_CREDS_H_ @}*/ diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c index 899cdd119..4344bf237 100644 --- a/src/charon-cmd/cmd/cmd_options.c +++ b/src/charon-cmd/cmd/cmd_options.c @@ -29,4 +29,8 @@ cmd_option_t cmd_options[CMD_OPT_COUNT] = { "DNS name or address to connect to" }, { CMD_OPT_IDENTITY, "identity", required_argument, "identity", "identity the client uses for the IKE exchange" }, + { CMD_OPT_CERT, "cert", required_argument, "path", + "trusted certificate, for authentication or trust chain validation" }, + { CMD_OPT_RSA, "rsa", required_argument, "path", + "RSA private key to use for authentication" }, }; diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h index 81fb54fe1..358108d0b 100644 --- a/src/charon-cmd/cmd/cmd_options.h +++ b/src/charon-cmd/cmd/cmd_options.h @@ -32,6 +32,8 @@ enum cmd_option_type_t { CMD_OPT_VERSION, CMD_OPT_HOST, CMD_OPT_IDENTITY, + CMD_OPT_CERT, + CMD_OPT_RSA, CMD_OPT_COUNT }; -- cgit v1.2.3 From 5e9144a21ff15e38f1a6b89fad4b6b02f443051a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 16:19:00 +0100 Subject: controller: clean up job data if a thread gets cancelled waiting in a function Controller functions are thread cancellation points, so register a cancellation handler cleaning up job data. --- src/libcharon/control/controller.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c index 0ee99c4b7..c546da544 100644 --- a/src/libcharon/control/controller.c +++ b/src/libcharon/control/controller.c @@ -412,6 +412,7 @@ METHOD(controller_t, initiate, status_t, .refcount = 1, ); job->listener.logger.listener = &job->listener; + thread_cleanup_push((void*)destroy_job, job); if (callback == NULL) { @@ -425,7 +426,7 @@ METHOD(controller_t, initiate, status_t, } } status = job->listener.status; - destroy_job(job); + thread_cleanup_pop(TRUE); return status; } @@ -500,6 +501,7 @@ METHOD(controller_t, terminate_ike, status_t, .refcount = 1, ); job->listener.logger.listener = &job->listener; + thread_cleanup_push((void*)destroy_job, job); if (callback == NULL) { @@ -513,7 +515,7 @@ METHOD(controller_t, terminate_ike, status_t, } } status = job->listener.status; - destroy_job(job); + thread_cleanup_pop(TRUE); return status; } @@ -615,6 +617,7 @@ METHOD(controller_t, terminate_child, status_t, .refcount = 1, ); job->listener.logger.listener = &job->listener; + thread_cleanup_push((void*)destroy_job, job); if (callback == NULL) { @@ -628,7 +631,7 @@ METHOD(controller_t, terminate_child, status_t, } } status = job->listener.status; - destroy_job(job); + thread_cleanup_pop(TRUE); return status; } -- cgit v1.2.3 From d3874008e8a722be522a110afb7249317072f0d9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 17:23:38 +0100 Subject: socket-dynamic: when sending from port zero, allocate a free port dynamically --- .../plugins/socket_dynamic/socket_dynamic_socket.c | 127 ++++++++++++++++----- 1 file changed, 101 insertions(+), 26 deletions(-) diff --git a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c index a5e919348..b7c73945d 100644 --- a/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c +++ b/src/libcharon/plugins/socket_dynamic/socket_dynamic_socket.c @@ -325,14 +325,61 @@ METHOD(socket_t, receiver, status_t, return FAILED; } +/** + * Get the port allocated dynamically using bind() + */ +static bool get_dynamic_port(int fd, int family, u_int16_t *port) +{ + union { + struct sockaddr_storage ss; + struct sockaddr s; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; + socklen_t addrlen; + + addrlen = sizeof(addr); + if (getsockname(fd, &addr.s, &addrlen) != 0) + { + DBG1(DBG_NET, "unable to getsockname: %s", strerror(errno)); + return FALSE; + } + switch (family) + { + case AF_INET: + if (addrlen != sizeof(addr.sin) || addr.sin.sin_family != family) + { + break; + } + *port = ntohs(addr.sin.sin_port); + return TRUE; + case AF_INET6: + if (addrlen != sizeof(addr.sin6) || addr.sin6.sin6_family != family) + { + break; + } + *port = ntohs(addr.sin6.sin6_port); + return TRUE; + default: + return FALSE; + } + DBG1(DBG_NET, "received invalid getsockname() result"); + return FALSE; +} + /** * open a socket to send and receive packets */ static int open_socket(private_socket_dynamic_socket_t *this, - int family, u_int16_t port) + int family, u_int16_t *port) { + union { + struct sockaddr_storage ss; + struct sockaddr s; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; int on = TRUE; - struct sockaddr_storage addr; socklen_t addrlen; u_int sol, pktinfo = 0; int fd; @@ -342,27 +389,21 @@ static int open_socket(private_socket_dynamic_socket_t *this, switch (family) { case AF_INET: - { - struct sockaddr_in *sin = (struct sockaddr_in *)&addr; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_port = htons(port); - addrlen = sizeof(struct sockaddr_in); + addr.sin.sin_family = AF_INET; + addr.sin.sin_addr.s_addr = INADDR_ANY; + addr.sin.sin_port = htons(*port); + addrlen = sizeof(addr.sin); sol = SOL_IP; pktinfo = IP_PKTINFO; break; - } case AF_INET6: - { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; - sin6->sin6_family = AF_INET6; - memset(&sin6->sin6_addr, 0, sizeof(sin6->sin6_addr)); - sin6->sin6_port = htons(port); - addrlen = sizeof(struct sockaddr_in6); + addr.sin6.sin6_family = AF_INET6; + memset(&addr.sin6.sin6_addr, 0, sizeof(addr.sin6)); + addr.sin6.sin6_port = htons(*port); + addrlen = sizeof(addr.sin6); sol = SOL_IPV6; pktinfo = IPV6_RECVPKTINFO; break; - } default: return 0; } @@ -380,13 +421,17 @@ static int open_socket(private_socket_dynamic_socket_t *this, return 0; } - /* bind the socket */ - if (bind(fd, (struct sockaddr *)&addr, addrlen) < 0) + if (bind(fd, &addr.s, addrlen) < 0) { DBG1(DBG_NET, "unable to bind socket: %s", strerror(errno)); close(fd); return 0; } + if (*port == 0 && !get_dynamic_port(fd, family, port)) + { + close(fd); + return 0; + } /* get additional packet info on receive */ if (setsockopt(fd, sol, pktinfo, &on, sizeof(on)) < 0) @@ -404,15 +449,40 @@ static int open_socket(private_socket_dynamic_socket_t *this, /* enable UDP decapsulation on each socket */ if (!hydra->kernel_interface->enable_udp_decap(hydra->kernel_interface, - fd, family, port)) + fd, family, *port)) { DBG1(DBG_NET, "enabling UDP decapsulation for %s on port %d failed", - family == AF_INET ? "IPv4" : "IPv6", port); + family == AF_INET ? "IPv4" : "IPv6", *port); } return fd; } +/** + * Get the first usable socket for an address family + */ +static dynsock_t *get_any_socket(private_socket_dynamic_socket_t *this, + int family) +{ + dynsock_t *key, *value, *found = NULL; + enumerator_t *enumerator; + + this->lock->read_lock(this->lock); + enumerator = this->sockets->create_enumerator(this->sockets); + while (enumerator->enumerate(enumerator, &key, &value)) + { + if (value->family == family) + { + found = value; + break; + } + } + enumerator->destroy(enumerator); + this->lock->unlock(this->lock); + + return found; +} + /** * Find/Create a socket to send from host */ @@ -433,7 +503,15 @@ static dynsock_t *find_socket(private_socket_dynamic_socket_t *this, { return skt; } - fd = open_socket(this, family, port); + if (!port) + { + skt = get_any_socket(this, family); + if (skt) + { + return skt; + } + } + fd = open_socket(this, family, &port); if (!fd) { return NULL; @@ -457,7 +535,7 @@ METHOD(socket_t, sender, status_t, { dynsock_t *skt; host_t *src, *dst; - int port, family; + int family; ssize_t len; chunk_t data; struct msghdr msg; @@ -467,9 +545,7 @@ METHOD(socket_t, sender, status_t, src = packet->get_source(packet); dst = packet->get_destination(packet); family = src->get_family(src); - port = src->get_port(src); - port = port ?: CHARON_UDP_PORT; - skt = find_socket(this, family, port); + skt = find_socket(this, family, src->get_port(src)); if (!skt) { return FAILED; @@ -597,4 +673,3 @@ socket_dynamic_socket_t *socket_dynamic_socket_create() return &this->public; } - -- cgit v1.2.3 From f0749552a6f971504d5ce6a58b0b3898c57cd3d5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 17:28:40 +0100 Subject: charon-cmd: add support for using dynamic ports in charon-cmd --- configure.in | 2 +- src/charon-cmd/cmd/cmd_connection.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/configure.in b/configure.in index a244f632e..06829755f 100644 --- a/configure.in +++ b/configure.in @@ -991,7 +991,7 @@ ADD_PLUGIN([kernel-klips], [h charon starter]) ADD_PLUGIN([kernel-netlink], [h charon starter nm cmd]) ADD_PLUGIN([resolve], [h charon cmd]) ADD_PLUGIN([socket-default], [c charon nm cmd]) -ADD_PLUGIN([socket-dynamic], [c charon]) +ADD_PLUGIN([socket-dynamic], [c charon cmd]) ADD_PLUGIN([farp], [c charon]) ADD_PLUGIN([stroke], [c charon]) ADD_PLUGIN([smp], [c charon]) diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index 566b2544b..f58df5cec 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -65,11 +65,15 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) { ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; + u_int16_t local_port, remote_port = IKEV2_UDP_PORT; - ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, - charon->socket->get_port(charon->socket, FALSE), - this->host, FALSE, IKEV2_UDP_PORT, - FRAGMENTATION_NO, 0); + local_port = charon->socket->get_port(charon->socket, FALSE); + if (local_port != IKEV2_UDP_PORT) + { + remote_port = IKEV2_NATT_PORT; + } + ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, local_port, + this->host, FALSE, remote_port, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("cmd", ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ -- cgit v1.2.3 From 9dfd9275f029e9ccd7e25ded8f281e9987b9d982 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 17:36:31 +0100 Subject: charon-cmd: build long_opts only once when reading arguments in charon-cmd --- src/charon-cmd/charon-cmd.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index 4969c9645..acfdcbae8 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -243,18 +243,17 @@ static void usage(FILE *out, char *msg, char *binary) */ static void handle_arguments(int argc, char *argv[]) { + struct option long_opts[CMD_OPT_COUNT + 1] = {}; + int i, opt; + + for (i = 0; i < CMD_OPT_COUNT; i++) + { + long_opts[i].name = cmd_options[i].name; + long_opts[i].val = cmd_options[i].id; + long_opts[i].has_arg = cmd_options[i].has_arg; + } while (TRUE) { - struct option long_opts[CMD_OPT_COUNT + 1] = {}; - int i, opt; - - for (i = 0; i < CMD_OPT_COUNT; i++) - { - long_opts[i].name = cmd_options[i].name; - long_opts[i].val = cmd_options[i].id; - long_opts[i].has_arg = cmd_options[i].has_arg; - } - opt = getopt_long(argc, argv, "", long_opts, NULL); switch (opt) { -- cgit v1.2.3 From 7bcd96e43dcde713e7298b45cfbedb13290a278f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 17:38:02 +0100 Subject: charon-cmd: pass arguments to all handlers, even if already handled --- src/charon-cmd/charon-cmd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index acfdcbae8..d0fc4da07 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -254,6 +254,8 @@ static void handle_arguments(int argc, char *argv[]) } while (TRUE) { + bool handled = FALSE; + opt = getopt_long(argc, argv, "", long_opts, NULL); switch (opt) { @@ -266,8 +268,9 @@ static void handle_arguments(int argc, char *argv[]) printf("%s, strongSwan %s\n", "charon-cmd", VERSION); exit(0); default: - if (conn->handle(conn, opt, optarg) || - creds->handle(creds, opt, optarg)) + handled |= conn->handle(conn, opt, optarg); + handled |= creds->handle(creds, opt, optarg); + if (handled) { continue; } -- cgit v1.2.3 From b48941ae165171d4ed41927f1952d515872bb998 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 17:47:28 +0100 Subject: charon-cmd: authenticate with EAP if no private key is given --- src/charon-cmd/cmd/cmd_connection.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index f58df5cec..b3aad00ca 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -48,6 +48,11 @@ struct private_cmd_connection_t { * Local identity */ char *identity; + + /** + * Is a private key configured + */ + bool key_seen; }; /** @@ -93,9 +98,18 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) static void add_auth_cfgs(private_cmd_connection_t *this, peer_cfg_t *peer_cfg) { auth_cfg_t *auth; + auth_class_t class; + if (this->key_seen) + { + class = AUTH_CLASS_PUBKEY; + } + else + { + class = AUTH_CLASS_EAP; + } auth = auth_cfg_create(); - auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + auth->add(auth, AUTH_RULE_AUTH_CLASS, class); auth->add(auth, AUTH_RULE_IDENTITY, identification_create_from_string(this->identity)); peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); @@ -183,6 +197,9 @@ METHOD(cmd_connection_t, handle, bool, case CMD_OPT_IDENTITY: this->identity = arg; break; + case CMD_OPT_RSA: + this->key_seen = TRUE; + break; default: return FALSE; } -- cgit v1.2.3 From 3ca58c32beb8d05b010f59bf0e6fb9934c790255 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 26 Mar 2013 18:04:27 +0100 Subject: charon-cmd: prompt for EAP passwords on-demand using a callback credential set --- src/charon-cmd/cmd/cmd_creds.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/charon-cmd/cmd/cmd_creds.c b/src/charon-cmd/cmd/cmd_creds.c index 45f16522b..6112e96df 100644 --- a/src/charon-cmd/cmd/cmd_creds.c +++ b/src/charon-cmd/cmd/cmd_creds.c @@ -15,8 +15,11 @@ #include "cmd_creds.h" +#include + #include #include +#include typedef struct private_cmd_creds_t private_cmd_creds_t; @@ -34,8 +37,50 @@ struct private_cmd_creds_t { * Reused in-memory credential set */ mem_cred_t *creds; + + /** + * Callback credential set to get secrets + */ + callback_cred_t *cb; + + /** + * Already prompted for password? + */ + bool prompted; }; +/** + * Callback function to prompt for secret + */ +static shared_key_t* callback_shared(private_cmd_creds_t *this, + shared_key_type_t type, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) +{ + char *label, *pwd; + + if (this->prompted) + { + return NULL; + } + switch (type) + { + case SHARED_EAP: + label = "EAP password: "; + break; + default: + return NULL; + } + pwd = getpass(label); + if (!pwd || strlen(pwd) == 0) + { + return NULL; + } + this->prompted = TRUE; + *match_me = *match_other = ID_MATCH_PERFECT; + return shared_key_create(type, chunk_clone(chunk_from_str(pwd))); +} + /** * Load a trusted certificate from path */ @@ -92,7 +137,9 @@ METHOD(cmd_creds_t, destroy, void, private_cmd_creds_t *this) { lib->credmgr->remove_set(lib->credmgr, &this->creds->set); + lib->credmgr->remove_set(lib->credmgr, &this->cb->set); this->creds->destroy(this->creds); + this->cb->destroy(this->cb); free(this); } @@ -110,8 +157,10 @@ cmd_creds_t *cmd_creds_create() }, .creds = mem_cred_create(), ); + this->cb = callback_cred_create_shared((void*)callback_shared, this); lib->credmgr->add_set(lib->credmgr, &this->creds->set); + lib->credmgr->add_set(lib->credmgr, &this->cb->set); return &this->public; } -- cgit v1.2.3 From 69333acee088a80795467f785a3a82bfc9159984 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 11 Apr 2013 19:23:29 +0200 Subject: settings: Add a set_default_str() to set a different default for a key The value is set only if it is not configured in strongswan.conf or has not been set() otherwise. --- src/libstrongswan/utils/settings.c | 21 +++++++++++++++++++++ src/libstrongswan/utils/settings.h | 10 ++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/libstrongswan/utils/settings.c b/src/libstrongswan/utils/settings.c index 712ea6ee2..809ca10ab 100644 --- a/src/libstrongswan/utils/settings.c +++ b/src/libstrongswan/utils/settings.c @@ -644,6 +644,26 @@ METHOD(settings_t, set_time, void, va_end(args); } +METHOD(settings_t, set_default_str, bool, + private_settings_t *this, char *key, char *value, ...) +{ + char *old; + va_list args; + + va_start(args, value); + old = find_value(this, this->top, key, args); + va_end(args); + + if (!old) + { + va_start(args, value); + set_value(this, this->top, key, args, value); + va_end(args); + return TRUE; + } + return FALSE; +} + /** * Enumerate section names, not sections */ @@ -1209,6 +1229,7 @@ settings_t *settings_create(char *file) .set_double = _set_double, .set_time = _set_time, .set_bool = _set_bool, + .set_default_str = _set_default_str, .create_section_enumerator = _create_section_enumerator, .create_key_value_enumerator = _create_key_value_enumerator, .load_files = _load_files, diff --git a/src/libstrongswan/utils/settings.h b/src/libstrongswan/utils/settings.h index a861325f5..df0c534e9 100644 --- a/src/libstrongswan/utils/settings.h +++ b/src/libstrongswan/utils/settings.h @@ -238,6 +238,16 @@ struct settings_t { */ void (*set_time)(settings_t *this, char *key, u_int32_t value, ...); + /** + * Set a default for string value. + * + * @param key key including sections, printf style format + * @param def value to set if unconfigured + * @param ... argument list for key + * @return TRUE if a new default value for key has been set + */ + bool (*set_default_str)(settings_t *this, char *key, char *value, ...); + /** * Create an enumerator over subsection names of a section. * -- cgit v1.2.3 From 7a86bccd50a85dfb34652db8a376e84538a88d00 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 11 Apr 2013 19:27:27 +0200 Subject: charon-cmd: Use dynamic ports with the socket-default plugin --- src/charon-cmd/charon-cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index d0fc4da07..a493b17c7 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -323,6 +323,8 @@ int main(int argc, char *argv[]) { exit(SS_RC_INITIALIZATION_FAILED); } + lib->settings->set_default_str(lib->settings, "charon-cmd.port", "0"); + lib->settings->set_default_str(lib->settings, "charon-cmd.port_nat_t", "0"); if (!charon->initialize(charon, lib->settings->get_str(lib->settings, "charon-cmd.load", PLUGINS))) { -- cgit v1.2.3 From 8e53682cd9def392e219845eccd6f44de5fb2303 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 22 Apr 2013 10:52:17 +0200 Subject: charon-cmd: add --local/remote-ts options to set traffic selectors --- src/charon-cmd/cmd/cmd_connection.c | 62 ++++++++++++++++++++++++++++++++++--- src/charon-cmd/cmd/cmd_options.c | 4 +++ src/charon-cmd/cmd/cmd_options.h | 2 ++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index b3aad00ca..33c01298b 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -39,6 +39,16 @@ struct private_cmd_connection_t { */ pid_t pid; + /** + * List of local traffic selectors + */ + linked_list_t *local_ts; + + /** + * List of remote traffic selectors + */ + linked_list_t *remote_ts; + /** * Hostname to connect to */ @@ -141,11 +151,22 @@ static child_cfg_t* create_child_cfg(private_cmd_connection_t *this) ACTION_NONE, ACTION_NONE, ACTION_NONE, FALSE, 0, 0, NULL, NULL, 0); child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); - ts = traffic_selector_create_dynamic(0, 0, 65535); - child_cfg->add_traffic_selector(child_cfg, TRUE, ts); - ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, + while (this->local_ts->remove_first(this->local_ts, (void**)&ts) == SUCCESS) + { + child_cfg->add_traffic_selector(child_cfg, TRUE, ts); + } + if (this->remote_ts->get_count(this->remote_ts) == 0) + { + /* add a 0.0.0.0/0 TS for remote side if none given */ + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, "0.0.0.0", 0, "255.255.255.255", 65535); - child_cfg->add_traffic_selector(child_cfg, FALSE, ts); + this->remote_ts->insert_last(this->remote_ts, ts); + } + while (this->remote_ts->remove_first(this->remote_ts, + (void**)&ts) == SUCCESS) + { + child_cfg->add_traffic_selector(child_cfg, FALSE, ts); + } return child_cfg; } @@ -186,6 +207,23 @@ static job_requeue_t initiate(private_cmd_connection_t *this) return JOB_REQUEUE_NONE; } +/** + * Create a traffic selector from string, add to list + */ +static void add_ts(private_cmd_connection_t *this, + linked_list_t *list, char *string) +{ + traffic_selector_t *ts; + + ts = traffic_selector_create_from_cidr(string, 0, 0, 65535); + if (!ts) + { + DBG1(DBG_CFG, "invalid traffic selector: %s", string); + exit(1); + } + list->insert_last(list, ts); +} + METHOD(cmd_connection_t, handle, bool, private_cmd_connection_t *this, cmd_option_type_t opt, char *arg) { @@ -200,6 +238,12 @@ METHOD(cmd_connection_t, handle, bool, case CMD_OPT_RSA: this->key_seen = TRUE; break; + case CMD_OPT_LOCAL_TS: + add_ts(this, this->local_ts, arg); + break; + case CMD_OPT_REMOTE_TS: + add_ts(this, this->remote_ts, arg); + break; default: return FALSE; } @@ -209,6 +253,10 @@ METHOD(cmd_connection_t, handle, bool, METHOD(cmd_connection_t, destroy, void, private_cmd_connection_t *this) { + this->local_ts->destroy_offset(this->local_ts, + offsetof(traffic_selector_t, destroy)); + this->remote_ts->destroy_offset(this->remote_ts, + offsetof(traffic_selector_t, destroy)); free(this); } @@ -225,8 +273,14 @@ cmd_connection_t *cmd_connection_create() .destroy = _destroy, }, .pid = getpid(), + .local_ts = linked_list_create(), + .remote_ts = linked_list_create(), ); + /* always include the virtual IP in traffic selector list */ + this->local_ts->insert_last(this->local_ts, + traffic_selector_create_dynamic(0, 0, 65535)); + /* queue job, gets initiated as soon as we are up and running */ lib->processor->queue_job(lib->processor, (job_t*)callback_job_create_with_prio( diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c index 4344bf237..f41819810 100644 --- a/src/charon-cmd/cmd/cmd_options.c +++ b/src/charon-cmd/cmd/cmd_options.c @@ -33,4 +33,8 @@ cmd_option_t cmd_options[CMD_OPT_COUNT] = { "trusted certificate, for authentication or trust chain validation" }, { CMD_OPT_RSA, "rsa", required_argument, "path", "RSA private key to use for authentication" }, + { CMD_OPT_LOCAL_TS, "local-ts", required_argument, "subnet", + "additional traffic selector to propose for our side" }, + { CMD_OPT_REMOTE_TS, "remote-ts", required_argument, "subnet", + "remote traffic selector to propose for remote side" }, }; diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h index 358108d0b..3756225bf 100644 --- a/src/charon-cmd/cmd/cmd_options.h +++ b/src/charon-cmd/cmd/cmd_options.h @@ -34,6 +34,8 @@ enum cmd_option_type_t { CMD_OPT_IDENTITY, CMD_OPT_CERT, CMD_OPT_RSA, + CMD_OPT_LOCAL_TS, + CMD_OPT_REMOTE_TS, CMD_OPT_COUNT }; -- cgit v1.2.3 From d6b0c28b252a1312aea692f89a1ff0300c7ec9c9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 22 Apr 2013 11:20:58 +0200 Subject: charon-cmd: support multi-line help text for each option in usage --- src/charon-cmd/charon-cmd.c | 10 +++++++++- src/charon-cmd/cmd/cmd_options.h | 4 +++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/charon-cmd/charon-cmd.c b/src/charon-cmd/charon-cmd.c index a493b17c7..5f27255a9 100644 --- a/src/charon-cmd/charon-cmd.c +++ b/src/charon-cmd/charon-cmd.c @@ -199,7 +199,7 @@ static void segv_handler(int signal) */ static void usage(FILE *out, char *msg, char *binary) { - int i, pre, post, padto = 0, spacing = 2; + int i, line, pre, post, padto = 0, spacing = 2; for (i = 0; i < CMD_OPT_COUNT; i++) { @@ -235,6 +235,14 @@ static void usage(FILE *out, char *msg, char *binary) pre, cmd_options[i].arg, post, padto - strlen(cmd_options[i].name) - strlen(cmd_options[i].arg), "", cmd_options[i].desc); + for (line = 0; line < countof(cmd_options[i].lines); line++) + { + if (cmd_options[i].lines[line]) + { + fprintf(out, "%-*s %s\n", + padto, "", cmd_options[i].lines[line]); + } + } } } diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h index 3756225bf..6fa3fade4 100644 --- a/src/charon-cmd/cmd/cmd_options.h +++ b/src/charon-cmd/cmd/cmd_options.h @@ -52,8 +52,10 @@ struct cmd_option_t { int has_arg; /** decription of argument */ const char *arg; - /** description to option */ + /** short description to option */ const char *desc; + /** additional description lines */ + const char *lines[8]; }; /** -- cgit v1.2.3 From d2e2b9a2da96bfbde1ab430b57ed1ac6719bc9c9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 22 Apr 2013 12:33:10 +0200 Subject: charon-cmd: add support for different IKEv1/IKEv2 authentication profiles --- src/charon-cmd/cmd/cmd_connection.c | 173 ++++++++++++++++++++++++++++++++---- src/charon-cmd/cmd/cmd_creds.c | 3 + src/charon-cmd/cmd/cmd_options.c | 10 +++ src/charon-cmd/cmd/cmd_options.h | 1 + 4 files changed, 170 insertions(+), 17 deletions(-) diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index 33c01298b..db5499b7c 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -20,10 +20,36 @@ #include #include +#include #include +typedef enum profile_t profile_t; typedef struct private_cmd_connection_t private_cmd_connection_t; +/** + * Connection profiles we support + */ +enum profile_t { + PROF_UNDEF, + PROF_V2_PUB, + PROF_V2_EAP, + PROF_V2_PUB_EAP, + PROF_V1_PUB, + PROF_V1_XAUTH, + PROF_V1_XAUTH_PSK, + PROF_V1_HYBRID, +}; + +ENUM(profile_names, PROF_V2_PUB, PROF_V1_HYBRID, + "ikev2-pub", + "ikev2-eap", + "ikev2-pub-eap", + "ikev1-pub", + "ikev1-xauth", + "ikev1-xauth-psk", + "ikev1-hybrid", +); + /** * Private data of an cmd_connection_t object. */ @@ -63,6 +89,11 @@ struct private_cmd_connection_t { * Is a private key configured */ bool key_seen; + + /** + * Selected connection profile + */ + profile_t profile; }; /** @@ -81,13 +112,30 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) ike_cfg_t *ike_cfg; peer_cfg_t *peer_cfg; u_int16_t local_port, remote_port = IKEV2_UDP_PORT; + ike_version_t version = IKE_ANY; + + switch (this->profile) + { + case PROF_UNDEF: + case PROF_V2_PUB: + case PROF_V2_EAP: + case PROF_V2_PUB_EAP: + version = IKEV2; + break; + case PROF_V1_PUB: + case PROF_V1_XAUTH: + case PROF_V1_XAUTH_PSK: + case PROF_V1_HYBRID: + version = IKEV1; + break; + } local_port = charon->socket->get_port(charon->socket, FALSE); if (local_port != IKEV2_UDP_PORT) { remote_port = IKEV2_NATT_PORT; } - ike_cfg = ike_cfg_create(IKEV2, TRUE, FALSE, "0.0.0.0", FALSE, local_port, + ike_cfg = ike_cfg_create(version, TRUE, FALSE, "0.0.0.0", FALSE, local_port, this->host, FALSE, remote_port, FRAGMENTATION_NO, 0); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("cmd", ike_cfg, @@ -103,32 +151,98 @@ static peer_cfg_t* create_peer_cfg(private_cmd_connection_t *this) } /** - * Attach authentication configs to peer config + * Add a single auth cfg of given class to peer cfg */ -static void add_auth_cfgs(private_cmd_connection_t *this, peer_cfg_t *peer_cfg) +static void add_auth_cfg(private_cmd_connection_t *this, peer_cfg_t *peer_cfg, + bool local, auth_class_t class) { + identification_t *id; auth_cfg_t *auth; - auth_class_t class; - if (this->key_seen) + auth = auth_cfg_create(); + auth->add(auth, AUTH_RULE_AUTH_CLASS, class); + if (local) { - class = AUTH_CLASS_PUBKEY; + id = identification_create_from_string(this->identity); } else { - class = AUTH_CLASS_EAP; + id = identification_create_from_string(this->host); } - auth = auth_cfg_create(); - auth->add(auth, AUTH_RULE_AUTH_CLASS, class); - auth->add(auth, AUTH_RULE_IDENTITY, - identification_create_from_string(this->identity)); - peer_cfg->add_auth_cfg(peer_cfg, auth, TRUE); + auth->add(auth, AUTH_RULE_IDENTITY, id); + peer_cfg->add_auth_cfg(peer_cfg, auth, local); +} - auth = auth_cfg_create(); +/** + * Attach authentication configs to peer config + */ +static bool add_auth_cfgs(private_cmd_connection_t *this, peer_cfg_t *peer_cfg) +{ + if (this->profile == PROF_UNDEF) + { + if (this->key_seen) + { + this->profile = PROF_V2_PUB; + } + else + { + this->profile = PROF_V2_EAP; + } + } + switch (this->profile) + { + case PROF_V2_PUB: + case PROF_V2_PUB_EAP: + case PROF_V1_PUB: + case PROF_V1_XAUTH: + if (!this->key_seen) + { + DBG1(DBG_CFG, "missing private key for profile %N", + profile_names, this->profile); + return FALSE; + } + break; + default: + break; + } - auth->add(auth, AUTH_RULE_IDENTITY, - identification_create_from_string(this->host)); - peer_cfg->add_auth_cfg(peer_cfg, auth, FALSE); + switch (this->profile) + { + case PROF_V2_PUB: + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY); + add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY); + break; + case PROF_V2_EAP: + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_EAP); + add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY); + break; + case PROF_V2_PUB_EAP: + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY); + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_EAP); + add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_ANY); + break; + case PROF_V1_PUB: + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY); + add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY); + break; + case PROF_V1_XAUTH: + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PUBKEY); + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH); + add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY); + break; + case PROF_V1_XAUTH_PSK: + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_PSK); + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH); + add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PSK); + break; + case PROF_V1_HYBRID: + add_auth_cfg(this, peer_cfg, TRUE, AUTH_CLASS_XAUTH); + add_auth_cfg(this, peer_cfg, FALSE, AUTH_CLASS_PUBKEY); + break; + default: + return FALSE; + } + return TRUE; } /** @@ -194,7 +308,12 @@ static job_requeue_t initiate(private_cmd_connection_t *this) peer_cfg = create_peer_cfg(this); - add_auth_cfgs(this, peer_cfg); + if (!add_auth_cfgs(this, peer_cfg)) + { + peer_cfg->destroy(peer_cfg); + terminate(this); + return JOB_REQUEUE_NONE; + } child_cfg = create_child_cfg(this); peer_cfg->add_child_cfg(peer_cfg, child_cfg->get_ref(child_cfg)); @@ -224,6 +343,22 @@ static void add_ts(private_cmd_connection_t *this, list->insert_last(list, ts); } +/** + * Parse profile name identifier + */ +static void set_profile(private_cmd_connection_t *this, char *name) +{ + int profile; + + profile = enum_from_name(profile_names, name); + if (profile == -1) + { + DBG1(DBG_CFG, "unknown connection profile: %s", name); + exit(1); + } + this->profile = profile; +} + METHOD(cmd_connection_t, handle, bool, private_cmd_connection_t *this, cmd_option_type_t opt, char *arg) { @@ -244,6 +379,9 @@ METHOD(cmd_connection_t, handle, bool, case CMD_OPT_REMOTE_TS: add_ts(this, this->remote_ts, arg); break; + case CMD_OPT_PROFILE: + set_profile(this, arg); + break; default: return FALSE; } @@ -275,6 +413,7 @@ cmd_connection_t *cmd_connection_create() .pid = getpid(), .local_ts = linked_list_create(), .remote_ts = linked_list_create(), + .profile = PROF_UNDEF, ); /* always include the virtual IP in traffic selector list */ diff --git a/src/charon-cmd/cmd/cmd_creds.c b/src/charon-cmd/cmd/cmd_creds.c index 6112e96df..b70490915 100644 --- a/src/charon-cmd/cmd/cmd_creds.c +++ b/src/charon-cmd/cmd/cmd_creds.c @@ -68,6 +68,9 @@ static shared_key_t* callback_shared(private_cmd_creds_t *this, case SHARED_EAP: label = "EAP password: "; break; + case SHARED_IKE: + label = "Preshared Key: "; + break; default: return NULL; } diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c index f41819810..58877a043 100644 --- a/src/charon-cmd/cmd/cmd_options.c +++ b/src/charon-cmd/cmd/cmd_options.c @@ -37,4 +37,14 @@ cmd_option_t cmd_options[CMD_OPT_COUNT] = { "additional traffic selector to propose for our side" }, { CMD_OPT_REMOTE_TS, "remote-ts", required_argument, "subnet", "remote traffic selector to propose for remote side" }, + { CMD_OPT_PROFILE, "profile", required_argument, "name", + "authentication profile to use, where name is one of:", { + "ikev2-pub: IKEv2 with public key client authentication", + "ikev2-eap: IKEv2 with client EAP", + "ikev2-pub-eap: IKEv2 with public key client authentication + client EAP", + "ikev1-pub: IKEv1 public key authentication", + "ikev1-xauth: IKEv1 public key authentication + initiator XAuth", + "ikev1-xauth-psk: IKEv1 PSK authentication + initiator XAuth (INSECURE!)", + "ikev1-hybrid: IKEv1 public key responder only + initiator XAuth", + }}, }; diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h index 6fa3fade4..165e86212 100644 --- a/src/charon-cmd/cmd/cmd_options.h +++ b/src/charon-cmd/cmd/cmd_options.h @@ -36,6 +36,7 @@ enum cmd_option_type_t { CMD_OPT_RSA, CMD_OPT_LOCAL_TS, CMD_OPT_REMOTE_TS, + CMD_OPT_PROFILE, CMD_OPT_COUNT }; -- cgit v1.2.3 From a0f6f3934323410b18fd0562abda6cb54c4ecf00 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 22 Apr 2013 12:33:52 +0200 Subject: proposals: try next if IKEv2 algorithm could not be mapped to IKEv1 --- src/libcharon/encoding/payloads/proposal_substructure.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index ae0fce991..3cf22aefd 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -1224,7 +1224,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, number, IKEV1_TRANSID_KEY_IKE); enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); - if (enumerator->enumerate(enumerator, &alg, &key_size)) + while (enumerator->enumerate(enumerator, &alg, &key_size)) { alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg); if (alg) @@ -1238,13 +1238,14 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_KEY_LENGTH, key_size)); } + break; } } enumerator->destroy(enumerator); /* encode the integrity algorithm as hash and assume use the same PRF */ enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); - if (enumerator->enumerate(enumerator, &alg, &key_size)) + while (enumerator->enumerate(enumerator, &alg, &key_size)) { alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); if (alg) @@ -1252,6 +1253,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_HASH_ALGORITHM, alg)); + break; } } enumerator->destroy(enumerator); -- cgit v1.2.3 From 68fc0fe32eb3d7d89c9639b44903b98a1e073a05 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 22 Apr 2013 12:42:01 +0200 Subject: charon-cmd: add an option to set a different server identity --- src/charon-cmd/cmd/cmd_connection.c | 17 ++++++++++++++++- src/charon-cmd/cmd/cmd_options.c | 2 ++ src/charon-cmd/cmd/cmd_options.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/charon-cmd/cmd/cmd_connection.c b/src/charon-cmd/cmd/cmd_connection.c index db5499b7c..965b72bc0 100644 --- a/src/charon-cmd/cmd/cmd_connection.c +++ b/src/charon-cmd/cmd/cmd_connection.c @@ -80,6 +80,11 @@ struct private_cmd_connection_t { */ char *host; + /** + * Server identity, or NULL to use host + */ + char *server; + /** * Local identity */ @@ -167,7 +172,14 @@ static void add_auth_cfg(private_cmd_connection_t *this, peer_cfg_t *peer_cfg, } else { - id = identification_create_from_string(this->host); + if (this->server) + { + id = identification_create_from_string(this->server); + } + else + { + id = identification_create_from_string(this->host); + } } auth->add(auth, AUTH_RULE_IDENTITY, id); peer_cfg->add_auth_cfg(peer_cfg, auth, local); @@ -367,6 +379,9 @@ METHOD(cmd_connection_t, handle, bool, case CMD_OPT_HOST: this->host = arg; break; + case CMD_OPT_REMOTE_IDENTITY: + this->server = arg; + break; case CMD_OPT_IDENTITY: this->identity = arg; break; diff --git a/src/charon-cmd/cmd/cmd_options.c b/src/charon-cmd/cmd/cmd_options.c index 58877a043..312d12964 100644 --- a/src/charon-cmd/cmd/cmd_options.c +++ b/src/charon-cmd/cmd/cmd_options.c @@ -29,6 +29,8 @@ cmd_option_t cmd_options[CMD_OPT_COUNT] = { "DNS name or address to connect to" }, { CMD_OPT_IDENTITY, "identity", required_argument, "identity", "identity the client uses for the IKE exchange" }, + { CMD_OPT_REMOTE_IDENTITY, "remote-identity", required_argument, "identity", + "server identity to expect, defaults to host" }, { CMD_OPT_CERT, "cert", required_argument, "path", "trusted certificate, for authentication or trust chain validation" }, { CMD_OPT_RSA, "rsa", required_argument, "path", diff --git a/src/charon-cmd/cmd/cmd_options.h b/src/charon-cmd/cmd/cmd_options.h index 165e86212..addbb50d8 100644 --- a/src/charon-cmd/cmd/cmd_options.h +++ b/src/charon-cmd/cmd/cmd_options.h @@ -32,6 +32,7 @@ enum cmd_option_type_t { CMD_OPT_VERSION, CMD_OPT_HOST, CMD_OPT_IDENTITY, + CMD_OPT_REMOTE_IDENTITY, CMD_OPT_CERT, CMD_OPT_RSA, CMD_OPT_LOCAL_TS, -- cgit v1.2.3