From 9cf5f29027969d5477fe190a8bf85f1aef457179 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 10 May 2006 13:16:27 +0000 Subject: --- src/whack/whack.c | 1911 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/whack/whack.h | 316 +++++++++ 2 files changed, 2227 insertions(+) create mode 100644 src/whack/whack.c create mode 100644 src/whack/whack.h (limited to 'src/whack') diff --git a/src/whack/whack.c b/src/whack/whack.c new file mode 100644 index 000000000..a3b983771 --- /dev/null +++ b/src/whack/whack.c @@ -0,0 +1,1911 @@ +/* command interface to Pluto + * Copyright (C) 1997 Angelos D. Keromytis. + * Copyright (C) 1998-2001 D. Hugh Redelmeier. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * RCSID $Id: whack.c,v 1.21 2006/04/20 04:42:12 as Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "constants.h" +#include "defs.h" +#include "whack.h" + +static void +help(void) +{ + fprintf(stderr + , "Usage:\n\n" + "all forms:" + " [--optionsfrom ]" + " [--ctlbase ]" + " [--label ]" + "\n\n" + "help: whack" + " [--help]" + " [--version]" + "\n\n" + "connection: whack" + " --name " + " \\\n " + " [--ipv4 | --ipv6]" + " [--tunnelipv4 | --tunnelipv6]" + " \\\n " + " (--host | --id )" + " \\\n " + " [--cert ]" + " [--ca ]" + " [--sendcert ]" + " \\\n " + " [--groups ]" + " \\\n " + " [--ikeport ]" + " [--nexthop ]" + " [--srcip ]" + " \\\n " + " [--client | --clientwithin
]" + " [--clientprotoport /]" + " \\\n " + " [--dnskeyondemand]" + " [--updown ]" + " \\\n " + " --to" + " (--host | --id )" + " \\\n " + " [--cert ]" + " [--ca ]" + " [--sendcert ]" + " \\\n " + " [--ikeport ]" + " [--nexthop ]" + " [--srcip ]" + " \\\n " + " [--client | --clientwithin
]" + " [--clientprotoport /]" + " \\\n " + " [--dnskeyondemand]" + " [--updown ]" + " [--psk]" + " [--rsasig]" + " \\\n " + " [--encrypt]" + " [--authenticate]" + " [--compress]" + " [--tunnel]" + " [--pfs]" + " \\\n " + " [--ikelifetime ]" + " [--ipseclifetime ]" + " \\\n " + " [--reykeymargin ]" + " [--reykeyfuzz ]" + " \\\n " + " [--keyingtries ]" + " \\\n " + " [--esp ]" + " \\\n " + " [--dontrekey]" + + " [--dpdaction (none|clear|hold|restart)]" + " \\\n " + " [--dpddelay --dpdtimeout ]" + " \\\n " + " [--initiateontraffic|--pass|--drop|--reject]" + " \\\n " + " [--failnone|--failpass|--faildrop|--failreject]" + "\n\n" + "routing: whack" + " (--route | --unroute)" + " --name " + "\n\n" + "initiation:" + "\n " + " whack" + " (--initiate | --terminate)" + " --name " + " [--asynchronous]" + "\n\n" + "opportunistic initiation: whack" + " [--tunnelipv4 | --tunnelipv6]" + " \\\n " + " --oppohere " + " --oppothere " + "\n\n" + "delete: whack" + " --delete" + " (--name | --caname )" + "\n\n" + "deletestate: whack" + " --deletestate " + " --crash " + "\n\n" + "pubkey: whack" + " --keyid " + " [--addkey]" + " [--pubkeyrsa ]" + "\n\n" + "myid: whack" + " --myid " + "\n\n" + "ca: whack" + " --caname " + " --cacert " + " \\\n " + " [--ldaphost ]" + " [--ldapbase ]" + " \\\n " + " [--crluri ]" + " [--crluri2 ]" + " [--ocspuri ]" + " [--strictcrlpolicy]" + "\n\n" +#ifdef DEBUG + "debug: whack [--name ]" + " \\\n " + " [--debug-none]" + " [--debug-all]" + " \\\n " + " [--debug-raw]" + " [--debug-crypt]" + " [--debug-parsing]" + " [--debug-emitting]" + " \\\n " + " [--debug-control]" + " [--debug-lifecycle]" + " [--debug-klips]" + " [--debug-dns]" + " \\\n " + " [--debug-natt]" + " [--debug-oppo]" + " [--debug-controlmore]" + " [--debug-private]" + "\n\n" +#endif + "listen: whack" + " (--listen | --unlisten)" + "\n\n" + "list: whack [--utc]" + " [--listalgs]" + " [--listpubkeys]" + " [--listcerts]" + " [--listcacerts]" + " \\\n " + " [--listacerts]" + " [--listaacerts]" + " [--listocspcerts]" + " [--listgroups]" + " \\\n " + " [--listcainfos]" + " [--listcrls]" + " [--listocsp]" + " [--listcards]" + " [--listall]" + "\n\n" + "purge: whack" + " [--purgeocsp]" + "\n\n" + "reread: whack" + " [--rereadsecrets]" + " [--rereadcacerts]" + " [--rereadaacerts]" + " \\\n " + " [--rereadocspcerts]" + " [--rereadacerts]" + " [--rereadcrls]" + " [--rereadall]" + "\n\n" + "status: whack" + " [--name ] --status|--statusall" + "\n\n" + "scdecrypt: whack" + " --scencrypt|scdecrypt " + " [--inbase ]" + " [--outbase ]" + " [--keyid ]" + "\n\n" + "shutdown: whack" + " --shutdown" + "\n\n" + "strongSwan %s\n" + , ipsec_version_code()); +} + +static const char *label = NULL; /* --label operand, saved for diagnostics */ + +static const char *name = NULL; /* --name operand, saved for diagnostics */ + +/* print a string as a diagnostic, then exit whack unhappily */ +static void +diag(const char *mess) +{ + if (mess != NULL) + { + fprintf(stderr, "whack error: "); + if (label != NULL) + fprintf(stderr, "%s ", label); + if (name != NULL) + fprintf(stderr, "\"%s\" ", name); + fprintf(stderr, "%s\n", mess); + } + + exit(RC_WHACK_PROBLEM); +} + +/* conditially calls diag; prints second arg, if non-NULL, as quoted string */ +static void +diagq(err_t ugh, const char *this) +{ + if (ugh != NULL) + { + if (this == NULL) + { + diag(ugh); + } + else + { + char buf[120]; /* arbitrary limit */ + + snprintf(buf, sizeof(buf), "%s \"%s\"", ugh, this); + diag(buf); + } + } +} + +/* complex combined operands return one of these enumerated values + * Note: these become flags in an lset_t. Since there are more than + * 32, we partition them into: + * - OPT_* options (most random options) + * - LST_* options (list various internal data) + * - DBGOPT_* option (DEBUG options) + * - END_* options (End description options) + * - CD_* options (Connection Description options) + * - CA_* options (CA description options) + */ +enum { +# define OPT_FIRST OPT_CTLBASE + OPT_CTLBASE, + OPT_NAME, + + OPT_CD, + + OPT_KEYID, + OPT_ADDKEY, + OPT_PUBKEYRSA, + + OPT_MYID, + + OPT_ROUTE, + OPT_UNROUTE, + + OPT_INITIATE, + OPT_TERMINATE, + OPT_DELETE, + OPT_DELETESTATE, + OPT_LISTEN, + OPT_UNLISTEN, + + OPT_PURGEOCSP, + + OPT_REREADSECRETS, + OPT_REREADCACERTS, + OPT_REREADAACERTS, + OPT_REREADOCSPCERTS, + OPT_REREADACERTS, + OPT_REREADCRLS, + OPT_REREADALL, + + OPT_STATUS, + OPT_STATUSALL, + OPT_SHUTDOWN, + + OPT_OPPO_HERE, + OPT_OPPO_THERE, + + OPT_ASYNC, + OPT_DELETECRASH, + +# define OPT_LAST OPT_ASYNC /* last "normal" option */ + +/* Smartcard options */ + +# define SC_FIRST SC_ENCRYPT /* first smartcard option */ + + SC_ENCRYPT, + SC_DECRYPT, + SC_INBASE, + SC_OUTBASE, + +# define SC_LAST SC_OUTBASE /* last "smartcard" option */ + +/* List options */ + +# define LST_FIRST LST_UTC /* first list option */ + LST_UTC, + LST_ALGS, + LST_PUBKEYS, + LST_CERTS, + LST_CACERTS, + LST_ACERTS, + LST_AACERTS, + LST_OCSPCERTS, + LST_GROUPS, + LST_CAINFOS, + LST_CRLS, + LST_OCSP, + LST_CARDS, + LST_ALL, + +# define LST_LAST LST_ALL /* last list option */ + +/* Connection End Description options */ + +# define END_FIRST END_HOST /* first end description */ + END_HOST, + END_ID, + END_CERT, + END_CA, + END_SENDCERT, + END_GROUPS, + END_IKEPORT, + END_NEXTHOP, + END_CLIENT, + END_CLIENTWITHIN, + END_CLIENTPROTOPORT, + END_DNSKEYONDEMAND, + END_SRCIP, + END_HOSTACCESS, + END_UPDOWN, + +#define END_LAST END_UPDOWN /* last end description*/ + +/* Connection Description options -- segregated */ + +# define CD_FIRST CD_TO /* first connection description */ + CD_TO, + +# define CD_POLICY_FIRST CD_PSK + CD_PSK, /* same order as POLICY_* */ + CD_RSASIG, /* same order as POLICY_* */ + CD_ENCRYPT, /* same order as POLICY_* */ + CD_AUTHENTICATE, /* same order as POLICY_* */ + CD_COMPRESS, /* same order as POLICY_* */ + CD_TUNNEL, /* same order as POLICY_* */ + CD_PFS, /* same order as POLICY_* */ + CD_DISABLEARRIVALCHECK, /* same order as POLICY_* */ + CD_SHUNT0, /* same order as POLICY_* */ + CD_SHUNT1, /* same order as POLICY_* */ + CD_FAIL0, /* same order as POLICY_* */ + CD_FAIL1, /* same order as POLICY_* */ + CD_DONT_REKEY, /* same order as POLICY_* */ + + CD_TUNNELIPV4, + CD_TUNNELIPV6, + CD_CONNIPV4, + CD_CONNIPV6, + + CD_IKELIFETIME, + CD_IPSECLIFETIME, + CD_RKMARGIN, + CD_RKFUZZ, + CD_KTRIES, + CD_DPDACTION, + CD_DPDDELAY, + CD_DPDTIMEOUT, + CD_IKE, + CD_PFSGROUP, + CD_ESP, + +# define CD_LAST CD_ESP /* last connection description */ + +/* Certificate Authority (CA) description options */ + +# define CA_FIRST CA_NAME /* first ca description */ + + CA_NAME, + CA_CERT, + CA_LDAPHOST, + CA_LDAPBASE, + CA_CRLURI, + CA_CRLURI2, + CA_OCSPURI, + CA_STRICT + +# define CA_LAST CA_STRICT /* last ca description */ + +#ifdef DEBUG /* must be last so others are less than 32 to fit in lset_t */ +# define DBGOPT_FIRST DBGOPT_NONE + , + /* NOTE: these definitions must match DBG_* and IMPAIR_* in constants.h */ + DBGOPT_NONE, + DBGOPT_ALL, + + DBGOPT_RAW, /* same order as DBG_* */ + DBGOPT_CRYPT, /* same order as DBG_* */ + DBGOPT_PARSING, /* same order as DBG_* */ + DBGOPT_EMITTING, /* same order as DBG_* */ + DBGOPT_CONTROL, /* same order as DBG_* */ + DBGOPT_LIFECYCLE, /* same order as DBG_* */ + DBGOPT_KLIPS, /* same order as DBG_* */ + DBGOPT_DNS, /* same order as DBG_* */ + DBGOPT_NATT, /* same order as DBG_* */ + DBGOPT_OPPO, /* same order as DBG_* */ + DBGOPT_CONTROLMORE, /* same order as DBG_* */ + + DBGOPT_PRIVATE, /* same order as DBG_* */ + + DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER, /* same order as IMPAIR_* */ + DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER, /* same order as IMPAIR_* */ + DBGOPT_IMPAIR_BUST_MI2, /* same order as IMPAIR_* */ + DBGOPT_IMPAIR_BUST_MR2 /* same order as IMPAIR_* */ + +# define DBGOPT_LAST DBGOPT_IMPAIR_BUST_MR2 +#endif + +}; + +/* Carve up space for result from getop_long. + * Stupidly, the only result is an int. + * Numeric arg is bit immediately left of basic value. + * + */ +#define OPTION_OFFSET 256 /* to get out of the way of letter options */ +#define NUMERIC_ARG (1 << 9) /* expect a numeric argument */ +#define AUX_SHIFT 10 /* amount to shift for aux information */ + +static const struct option long_opts[] = { +# define OO OPTION_OFFSET + /* name, has_arg, flag, val */ + + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "optionsfrom", required_argument, NULL, '+' }, + { "label", required_argument, NULL, 'l' }, + + { "ctlbase", required_argument, NULL, OPT_CTLBASE + OO }, + { "name", required_argument, NULL, OPT_NAME + OO }, + + { "keyid", required_argument, NULL, OPT_KEYID + OO }, + { "addkey", no_argument, NULL, OPT_ADDKEY + OO }, + { "pubkeyrsa", required_argument, NULL, OPT_PUBKEYRSA + OO }, + + { "myid", required_argument, NULL, OPT_MYID + OO }, + + { "route", no_argument, NULL, OPT_ROUTE + OO }, + { "unroute", no_argument, NULL, OPT_UNROUTE + OO }, + + { "initiate", no_argument, NULL, OPT_INITIATE + OO }, + { "terminate", no_argument, NULL, OPT_TERMINATE + OO }, + { "delete", no_argument, NULL, OPT_DELETE + OO }, + { "deletestate", required_argument, NULL, OPT_DELETESTATE + OO + NUMERIC_ARG }, + { "crash", required_argument, NULL, OPT_DELETECRASH + OO }, + { "listen", no_argument, NULL, OPT_LISTEN + OO }, + { "unlisten", no_argument, NULL, OPT_UNLISTEN + OO }, + + { "purgeocsp", no_argument, NULL, OPT_PURGEOCSP + OO }, + + { "rereadsecrets", no_argument, NULL, OPT_REREADSECRETS + OO }, + { "rereadcacerts", no_argument, NULL, OPT_REREADCACERTS + OO }, + { "rereadaacerts", no_argument, NULL, OPT_REREADAACERTS + OO }, + { "rereadocspcerts", no_argument, NULL, OPT_REREADOCSPCERTS + OO }, + { "rereadacerts", no_argument, NULL, OPT_REREADACERTS + OO }, + { "rereadcrls", no_argument, NULL, OPT_REREADCRLS + OO }, + { "rereadall", no_argument, NULL, OPT_REREADALL + OO }, + { "status", no_argument, NULL, OPT_STATUS + OO }, + { "statusall", no_argument, NULL, OPT_STATUSALL + OO }, + { "shutdown", no_argument, NULL, OPT_SHUTDOWN + OO }, + + { "oppohere", required_argument, NULL, OPT_OPPO_HERE + OO }, + { "oppothere", required_argument, NULL, OPT_OPPO_THERE + OO }, + + { "asynchronous", no_argument, NULL, OPT_ASYNC + OO }, + + /* smartcard options */ + + { "scencrypt", required_argument, NULL, SC_ENCRYPT + OO }, + { "scdecrypt", required_argument, NULL, SC_DECRYPT + OO }, + { "inbase", required_argument, NULL, SC_INBASE + OO }, + { "outbase", required_argument, NULL, SC_OUTBASE + OO }, + + /* list options */ + + { "utc", no_argument, NULL, LST_UTC + OO }, + { "listalgs", no_argument, NULL, LST_ALGS + OO }, + { "listpubkeys", no_argument, NULL, LST_PUBKEYS + OO }, + { "listcerts", no_argument, NULL, LST_CERTS + OO }, + { "listcacerts", no_argument, NULL, LST_CACERTS + OO }, + { "listacerts", no_argument, NULL, LST_ACERTS + OO }, + { "listaacerts", no_argument, NULL, LST_AACERTS + OO }, + { "listocspcerts", no_argument, NULL, LST_OCSPCERTS + OO }, + { "listgroups", no_argument, NULL, LST_GROUPS + OO }, + { "listcainfos", no_argument, NULL, LST_CAINFOS + OO }, + { "listcrls", no_argument, NULL, LST_CRLS + OO }, + { "listocsp", no_argument, NULL, LST_OCSP + OO }, + { "listcards", no_argument, NULL, LST_CARDS + OO }, + { "listall", no_argument, NULL, LST_ALL + OO }, + + /* options for an end description */ + + { "host", required_argument, NULL, END_HOST + OO }, + { "id", required_argument, NULL, END_ID + OO }, + { "cert", required_argument, NULL, END_CERT + OO }, + { "ca", required_argument, NULL, END_CA + OO }, + { "sendcert", required_argument, NULL, END_SENDCERT + OO }, + { "groups", required_argument, NULL, END_GROUPS + OO }, + { "ikeport", required_argument, NULL, END_IKEPORT + OO + NUMERIC_ARG }, + { "nexthop", required_argument, NULL, END_NEXTHOP + OO }, + { "client", required_argument, NULL, END_CLIENT + OO }, + { "clientwithin", required_argument, NULL, END_CLIENTWITHIN + OO }, + { "clientprotoport", required_argument, NULL, END_CLIENTPROTOPORT + OO }, + { "dnskeyondemand", no_argument, NULL, END_DNSKEYONDEMAND + OO }, + { "srcip", required_argument, NULL, END_SRCIP + OO }, + { "hostaccess", no_argument, NULL, END_HOSTACCESS + OO }, + { "updown", required_argument, NULL, END_UPDOWN + OO }, + + /* options for a connection description */ + + { "to", no_argument, NULL, CD_TO + OO }, + + { "psk", no_argument, NULL, CD_PSK + OO }, + { "rsasig", no_argument, NULL, CD_RSASIG + OO }, + + { "encrypt", no_argument, NULL, CD_ENCRYPT + OO }, + { "authenticate", no_argument, NULL, CD_AUTHENTICATE + OO }, + { "compress", no_argument, NULL, CD_COMPRESS + OO }, + { "tunnel", no_argument, NULL, CD_TUNNEL + OO }, + { "tunnelipv4", no_argument, NULL, CD_TUNNELIPV4 + OO }, + { "tunnelipv6", no_argument, NULL, CD_TUNNELIPV6 + OO }, + { "pfs", no_argument, NULL, CD_PFS + OO }, + { "disablearrivalcheck", no_argument, NULL, CD_DISABLEARRIVALCHECK + OO }, + { "initiateontraffic", no_argument, NULL + , CD_SHUNT0 + (POLICY_SHUNT_TRAP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO }, + { "pass", no_argument, NULL + , CD_SHUNT0 + (POLICY_SHUNT_PASS >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO }, + { "drop", no_argument, NULL + , CD_SHUNT0 + (POLICY_SHUNT_DROP >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO }, + { "reject", no_argument, NULL + , CD_SHUNT0 + (POLICY_SHUNT_REJECT >> POLICY_SHUNT_SHIFT << AUX_SHIFT) + OO }, + { "failnone", no_argument, NULL + , CD_FAIL0 + (POLICY_FAIL_NONE >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO }, + { "failpass", no_argument, NULL + , CD_FAIL0 + (POLICY_FAIL_PASS >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO }, + { "faildrop", no_argument, NULL + , CD_FAIL0 + (POLICY_FAIL_DROP >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO }, + { "failreject", no_argument, NULL + , CD_FAIL0 + (POLICY_FAIL_REJECT >> POLICY_FAIL_SHIFT << AUX_SHIFT) + OO }, + { "dontrekey", no_argument, NULL, CD_DONT_REKEY + OO }, + { "ipv4", no_argument, NULL, CD_CONNIPV4 + OO }, + { "ipv6", no_argument, NULL, CD_CONNIPV6 + OO }, + + { "ikelifetime", required_argument, NULL, CD_IKELIFETIME + OO + NUMERIC_ARG }, + { "ipseclifetime", required_argument, NULL, CD_IPSECLIFETIME + OO + NUMERIC_ARG }, + { "rekeymargin", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG }, + { "rekeywindow", required_argument, NULL, CD_RKMARGIN + OO + NUMERIC_ARG }, /* OBSOLETE */ + { "rekeyfuzz", required_argument, NULL, CD_RKFUZZ + OO + NUMERIC_ARG }, + { "keyingtries", required_argument, NULL, CD_KTRIES + OO + NUMERIC_ARG }, + { "dpdaction", required_argument, NULL, CD_DPDACTION + OO }, + { "dpddelay", required_argument, NULL, CD_DPDDELAY + OO + NUMERIC_ARG }, + { "dpdtimeout", required_argument, NULL, CD_DPDTIMEOUT + OO + NUMERIC_ARG }, + { "ike", required_argument, NULL, CD_IKE + OO }, + { "pfsgroup", required_argument, NULL, CD_PFSGROUP + OO }, + { "esp", required_argument, NULL, CD_ESP + OO }, + + /* options for a ca description */ + + { "caname", required_argument, NULL, CA_NAME + OO }, + { "cacert", required_argument, NULL, CA_CERT + OO }, + { "ldaphost", required_argument, NULL, CA_LDAPHOST + OO }, + { "ldapbase", required_argument, NULL, CA_LDAPBASE + OO }, + { "crluri", required_argument, NULL, CA_CRLURI + OO }, + { "crluri2", required_argument, NULL, CA_CRLURI2 + OO }, + { "ocspuri", required_argument, NULL, CA_OCSPURI + OO }, + { "strictcrlpolicy", no_argument, NULL, CA_STRICT + OO }, + +#ifdef DEBUG + { "debug-none", no_argument, NULL, DBGOPT_NONE + OO }, + { "debug-all]", no_argument, NULL, DBGOPT_ALL + OO }, + { "debug-raw", no_argument, NULL, DBGOPT_RAW + OO }, + { "debug-crypt", no_argument, NULL, DBGOPT_CRYPT + OO }, + { "debug-parsing", no_argument, NULL, DBGOPT_PARSING + OO }, + { "debug-emitting", no_argument, NULL, DBGOPT_EMITTING + OO }, + { "debug-control", no_argument, NULL, DBGOPT_CONTROL + OO }, + { "debug-lifecycle", no_argument, NULL, DBGOPT_LIFECYCLE + OO }, + { "debug-klips", no_argument, NULL, DBGOPT_KLIPS + OO }, + { "debug-dns", no_argument, NULL, DBGOPT_DNS + OO }, + { "debug-natt", no_argument, NULL, DBGOPT_NATT + OO }, + { "debug-oppo", no_argument, NULL, DBGOPT_OPPO + OO }, + { "debug-controlmore", no_argument, NULL, DBGOPT_CONTROLMORE + OO }, + { "debug-private", no_argument, NULL, DBGOPT_PRIVATE + OO }, + + { "impair-delay-adns-key-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER + OO }, + { "impair-delay-adns-txt-answer", no_argument, NULL, DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER + OO }, + { "impair-bust-mi2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MI2 + OO }, + { "impair-bust-mr2", no_argument, NULL, DBGOPT_IMPAIR_BUST_MR2 + OO }, +#endif +# undef OO + { 0,0,0,0 } +}; + +struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX }; + +/* helper variables and function to encode strings from whack message */ + +static char + *next_str, + *str_roof; + +static bool +pack_str(char **p) +{ + const char *s = *p == NULL? "" : *p; /* note: NULL becomes ""! */ + size_t len = strlen(s) + 1; + + if (str_roof - next_str < (ptrdiff_t)len) + { + return FALSE; /* fishy: no end found */ + } + else + { + strcpy(next_str, s); + next_str += len; + *p = NULL; /* don't send pointers on the wire! */ + return TRUE; + } +} + +static void +check_life_time(time_t life, time_t limit, const char *which +, const whack_message_t *msg) +{ + time_t mint = msg->sa_rekey_margin * (100 + msg->sa_rekey_fuzz) / 100; + + if (life > limit) + { + char buf[200]; /* arbitrary limit */ + + snprintf(buf, sizeof(buf) + , "%s [%lu seconds] must be less than %lu seconds" + , which, (unsigned long)life, (unsigned long)limit); + diag(buf); + } + if ((msg->policy & POLICY_DONT_REKEY) == LEMPTY && life <= mint) + { + char buf[200]; /* arbitrary limit */ + + snprintf(buf, sizeof(buf) + , "%s [%lu] must be greater than" + " rekeymargin*(100+rekeyfuzz)/100 [%lu*(100+%lu)/100 = %lu]" + , which + , (unsigned long)life + , (unsigned long)msg->sa_rekey_margin + , (unsigned long)msg->sa_rekey_fuzz + , (unsigned long)mint); + diag(buf); + } +} + +static void +clear_end(whack_end_t *e) +{ + zero(e); + e->id = NULL; + e->cert = NULL; + e->ca = NULL; + e->updown = NULL; + e->host_port = IKE_UDP_PORT; +} + +static void +update_ports(whack_message_t *m) +{ + int port; + + if (m->left.port != 0) { + port = htons(m->left.port); + setportof(port, &m->left.host_addr); + setportof(port, &m->left.client.addr); + } + if (m->right.port != 0) { + port = htons(m->right.port); + setportof(port, &m->right.host_addr); + setportof(port, &m->right.client.addr); + } +} + +static void +check_end(whack_end_t *this, whack_end_t *that +, bool default_nexthop, sa_family_t caf, sa_family_t taf) +{ + if (caf != addrtypeof(&this->host_addr)) + diag("address family of host inconsistent"); + + if (default_nexthop) + { + if (isanyaddr(&that->host_addr)) + diag("our nexthop must be specified when other host is a %any or %opportunistic"); + this->host_nexthop = that->host_addr; + } + + if (caf != addrtypeof(&this->host_nexthop)) + diag("address family of nexthop inconsistent"); + + if (this->has_client) + { + if (taf != subnettypeof(&this->client)) + diag("address family of client subnet inconsistent"); + } + else + { + /* fill in anyaddr-anyaddr as (missing) client subnet */ + ip_address cn; + + diagq(anyaddr(caf, &cn), NULL); + diagq(rangetosubnet(&cn, &cn, &this->client), NULL); + } + + /* fill in anyaddr if source IP is not defined */ + if (!this->has_srcip) + diagq(anyaddr(caf, &this->host_srcip), optarg); + + /* check protocol */ + if (this->protocol != that->protocol) + diag("the protocol for leftprotoport and rightprotoport must be the same"); +} + +static void +get_secret(int sock) +{ + const char *buf, *secret; + int len; + + fflush(stdout); + usleep(20000); /* give fflush time for flushing */ + buf = getpass("Enter: "); + secret = (buf == NULL)? "" : buf; + + /* send the secret to pluto */ + len = strlen(secret) + 1; + if (write(sock, secret, len) != len) + { + int e = errno; + + fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e)); + exit(RC_WHACK_PROBLEM); + } +} + +/* This is a hack for initiating ISAKMP exchanges. */ + +int +main(int argc, char **argv) +{ + whack_message_t msg; + char esp_buf[256]; /* uses snprintf */ + lset_t + opts_seen = LEMPTY, + sc_seen = LEMPTY, + lst_seen = LEMPTY, + cd_seen = LEMPTY, + ca_seen = LEMPTY, + end_seen = LEMPTY, + end_seen_before_to = LEMPTY; + const char + *af_used_by = NULL, + *tunnel_af_used_by = NULL; + + /* check division of numbering space */ +#ifdef DEBUG + assert(OPTION_OFFSET + DBGOPT_LAST < NUMERIC_ARG); +#else + assert(OPTION_OFFSET + CA_LAST < NUMERIC_ARG); +#endif + assert(OPT_LAST - OPT_FIRST < (sizeof opts_seen * BITS_PER_BYTE)); + assert(SC_LAST - SC_FIRST < (sizeof sc_seen * BITS_PER_BYTE)); + assert(LST_LAST - LST_FIRST < (sizeof lst_seen * BITS_PER_BYTE)); + assert(END_LAST - END_FIRST < (sizeof end_seen * BITS_PER_BYTE)); + assert(CD_LAST - CD_FIRST < (sizeof cd_seen * BITS_PER_BYTE)); + assert(CA_LAST - CA_FIRST < (sizeof ca_seen * BITS_PER_BYTE)); +#ifdef DEBUG /* must be last so others are less than (sizeof cd_seen * BITS_PER_BYTE) to fit in lset_t */ + assert(DBGOPT_LAST - DBGOPT_FIRST < (sizeof cd_seen * BITS_PER_BYTE)); +#endif + /* check that POLICY bit assignment matches with CD_ */ + assert(LELEM(CD_DONT_REKEY - CD_POLICY_FIRST) == POLICY_DONT_REKEY); + + zero(&msg); + + clear_end(&msg.right); /* left set from this after --to */ + + msg.name = NULL; + msg.keyid = NULL; + msg.keyval.ptr = NULL; + msg.esp = NULL; + msg.ike = NULL; + msg.pfsgroup = NULL; + + msg.sa_ike_life_seconds = OAKLEY_ISAKMP_SA_LIFETIME_DEFAULT; + msg.sa_ipsec_life_seconds = PLUTO_SA_LIFE_DURATION_DEFAULT; + msg.sa_rekey_margin = SA_REPLACEMENT_MARGIN_DEFAULT; + msg.sa_rekey_fuzz = SA_REPLACEMENT_FUZZ_DEFAULT; + msg.sa_keying_tries = SA_REPLACEMENT_RETRIES_DEFAULT; + + msg.addr_family = AF_INET; + msg.tunnel_addr_family = AF_INET; + + msg.cacert = NULL; + msg.ldaphost = NULL; + msg.ldapbase = NULL; + msg.crluri = NULL; + msg.crluri2 = NULL; + msg.ocspuri = NULL; + + for (;;) + { + int long_index; + unsigned long opt_whole = 0; /* numeric argument for some flags */ + + /* Note: we don't like the way short options get parsed + * by getopt_long, so we simply pass an empty string as + * the list. It could be "hp:d:c:o:eatfs" "NARXPECK". + */ + int c = getopt_long(argc, argv, "", long_opts, &long_index) - OPTION_OFFSET; + int aux = 0; + + /* decode a numeric argument, if expected */ + if (0 <= c) + { + if (c & NUMERIC_ARG) + { + char *endptr; + + c -= NUMERIC_ARG; + opt_whole = strtoul(optarg, &endptr, 0); + + if (*endptr != '\0' || endptr == optarg) + diagq("badly formed numeric argument", optarg); + } + if (c >= (1 << AUX_SHIFT)) + { + aux = c >> AUX_SHIFT; + c -= aux << AUX_SHIFT; + } + } + + /* per-class option processing */ + if (0 <= c && c <= OPT_LAST) + { + /* OPT_* options get added to opts_seen. + * Reject repeated options (unless later code intervenes). + */ + lset_t f = LELEM(c); + + if (opts_seen & f) + diagq("duplicated flag", long_opts[long_index].name); + opts_seen |= f; + } + else if (SC_FIRST <= c && c <= SC_LAST) + { + /* SC_* options get added to sc_seen. + * Reject repeated options (unless later code intervenes). + */ + lset_t f = LELEM(c - SC_FIRST); + + if (sc_seen & f) + diagq("duplicated flag", long_opts[long_index].name); + sc_seen |= f; + } + else if (LST_FIRST <= c && c <= LST_LAST) + { + /* LST_* options get added to lst_seen. + * Reject repeated options (unless later code intervenes). + */ + lset_t f = LELEM(c - LST_FIRST); + + if (lst_seen & f) + diagq("duplicated flag", long_opts[long_index].name); + lst_seen |= f; + } +#ifdef DEBUG + else if (DBGOPT_FIRST <= c && c <= DBGOPT_LAST) + { + msg.whack_options = TRUE; + } +#endif + else if (END_FIRST <= c && c <= END_LAST) + { + /* END_* options are added to end_seen. + * Reject repeated options (unless later code intervenes). + */ + lset_t f = LELEM(c - END_FIRST); + + if (end_seen & f) + diagq("duplicated flag", long_opts[long_index].name); + end_seen |= f; + opts_seen |= LELEM(OPT_CD); + } + else if (CD_FIRST <= c && c <= CD_LAST) + { + /* CD_* options are added to cd_seen. + * Reject repeated options (unless later code intervenes). + */ + lset_t f = LELEM(c - CD_FIRST); + + if (cd_seen & f) + diagq("duplicated flag", long_opts[long_index].name); + cd_seen |= f; + opts_seen |= LELEM(OPT_CD); + } + else if (CA_FIRST <= c && c <= CA_LAST) + { + /* CA_* options are added to ca_seen. + * Reject repeated options (unless later code intervenes). + */ + lset_t f = LELEM(c - CA_FIRST); + + if (ca_seen & f) + diagq("duplicated flag", long_opts[long_index].name); + ca_seen |= f; + } + + /* Note: "break"ing from switch terminates loop. + * most cases should end with "continue". + */ + switch (c) + { + case EOF - OPTION_OFFSET: /* end of flags */ + break; + + case 0 - OPTION_OFFSET: /* long option already handled */ + continue; + + case ':' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */ + case '?' - OPTION_OFFSET: /* diagnostic already printed by getopt_long */ + diag(NULL); /* print no additional diagnostic, but exit sadly */ + break; /* not actually reached */ + + case 'h' - OPTION_OFFSET: /* --help */ + help(); + return 0; /* GNU coding standards say to stop here */ + + case 'v' - OPTION_OFFSET: /* --version */ + { + const char **sp = ipsec_copyright_notice(); + + printf("%s\n", ipsec_version_string()); + for (; *sp != NULL; sp++) + puts(*sp); + } + return 0; /* GNU coding standards say to stop here */ + + case 'l' - OPTION_OFFSET: /* --label */ + label = optarg; /* remember for diagnostics */ + continue; + + case '+' - OPTION_OFFSET: /* --optionsfrom */ + optionsfrom(optarg, &argc, &argv, optind, stderr); + /* does not return on error */ + continue; + + /* the rest of the options combine in complex ways */ + + case OPT_CTLBASE: /* --port */ + if (snprintf(ctl_addr.sun_path, sizeof(ctl_addr.sun_path) + , "%s%s", optarg, CTL_SUFFIX) == -1) + diag("" CTL_SUFFIX " must be fit in a sun_addr"); + continue; + + case OPT_NAME: /* --name */ + name = optarg; + msg.name = optarg; + continue; + + case OPT_KEYID: /* --keyid */ + msg.whack_key = !msg.whack_sc_op; + msg.keyid = optarg; /* decoded by Pluto */ + continue; + + case OPT_MYID: /* --myid */ + msg.whack_myid = TRUE; + msg.myid = optarg; /* decoded by Pluto */ + continue; + + case OPT_ADDKEY: /* --addkey */ + msg.whack_addkey = TRUE; + continue; + + case OPT_PUBKEYRSA: /* --pubkeyrsa */ + { + static char keyspace[RSA_MAX_ENCODING_BYTES]; /* room for 8K bit key */ + char diag_space[TTODATAV_BUF]; + const char *ugh = ttodatav(optarg, 0, 0 + , keyspace, sizeof(keyspace) + , &msg.keyval.len, diag_space, sizeof(diag_space) + , TTODATAV_SPACECOUNTS); + + if (ugh != NULL) + { + char ugh_space[80]; /* perhaps enough space */ + + snprintf(ugh_space, sizeof(ugh_space) + , "RSA public-key data malformed (%s)", ugh); + diagq(ugh_space, optarg); + } + msg.pubkey_alg = PUBKEY_ALG_RSA; + msg.keyval.ptr = keyspace; + } + continue; + + case OPT_ROUTE: /* --route */ + msg.whack_route = TRUE; + continue; + + case OPT_UNROUTE: /* --unroute */ + msg.whack_unroute = TRUE; + continue; + + case OPT_INITIATE: /* --initiate */ + msg.whack_initiate = TRUE; + continue; + + case OPT_TERMINATE: /* --terminate */ + msg.whack_terminate = TRUE; + continue; + + case OPT_DELETE: /* --delete */ + msg.whack_delete = TRUE; + continue; + + case OPT_DELETESTATE: /* --deletestate */ + msg.whack_deletestate = TRUE; + msg.whack_deletestateno = opt_whole; + continue; + + case OPT_DELETECRASH: /* --crash */ + msg.whack_crash = TRUE; + tunnel_af_used_by = long_opts[long_index].name; + diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.whack_crash_peer), optarg); + if (isanyaddr(&msg.whack_crash_peer)) + diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg); + continue; + + case OPT_LISTEN: /* --listen */ + msg.whack_listen = TRUE; + continue; + + case OPT_UNLISTEN: /* --unlisten */ + msg.whack_unlisten = TRUE; + continue; + + case OPT_PURGEOCSP: /* --purgeocsp */ + msg.whack_purgeocsp = TRUE; + continue; + + case OPT_REREADSECRETS: /* --rereadsecrets */ + case OPT_REREADCACERTS: /* --rereadcacerts */ + case OPT_REREADAACERTS: /* --rereadaacerts */ + case OPT_REREADOCSPCERTS: /* --rereadocspcerts */ + case OPT_REREADACERTS: /* --rereadacerts */ + case OPT_REREADCRLS: /* --rereadcrls */ + msg.whack_reread |= LELEM(c-OPT_REREADSECRETS); + continue; + + case OPT_REREADALL: /* --rereadall */ + msg.whack_reread = REREAD_ALL; + continue; + + case OPT_STATUSALL: /* --statusall */ + msg.whack_statusall = TRUE; + + case OPT_STATUS: /* --status */ + msg.whack_status = TRUE; + continue; + + case OPT_SHUTDOWN: /* --shutdown */ + msg.whack_shutdown = TRUE; + continue; + + case OPT_OPPO_HERE: /* --oppohere */ + tunnel_af_used_by = long_opts[long_index].name; + diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_my_client), optarg); + if (isanyaddr(&msg.oppo_my_client)) + diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg); + continue; + + case OPT_OPPO_THERE: /* --oppohere */ + tunnel_af_used_by = long_opts[long_index].name; + diagq(ttoaddr(optarg, 0, msg.tunnel_addr_family, &msg.oppo_peer_client), optarg); + if (isanyaddr(&msg.oppo_peer_client)) + diagq("0.0.0.0 or 0::0 isn't a valid client address", optarg); + continue; + + case OPT_ASYNC: + msg.whack_async = TRUE; + continue; + + /* Smartcard options */ + + case SC_ENCRYPT: /* --scencrypt */ + case SC_DECRYPT: /* --scdecrypt <encrypted data> */ + msg.whack_sc_op = 1 + c - SC_ENCRYPT; + msg.whack_key = FALSE; + msg.sc_data = optarg; + continue; + + case SC_INBASE: /* --inform <format> */ + case SC_OUTBASE: /* --outform <format> */ + { + int base = 0; + + if (streq(optarg, "16") || strcaseeq(optarg, "hex")) + base = 16; + else if (streq(optarg, "64") || strcaseeq(optarg, "base64")) + base = 64; + else if (streq(optarg, "256") || strcaseeq(optarg, "text") + || strcaseeq(optarg, "ascii")) + base = 256; + else + diagq("not a valid base", optarg); + + if (c == SC_INBASE) + msg.inbase = base; + else + msg.outbase = base; + } + continue; + + /* List options */ + + case LST_UTC: /* --utc */ + msg.whack_utc = TRUE; + continue; + + case LST_ALGS: /* --listalgs */ + case LST_PUBKEYS: /* --listpubkeys */ + case LST_CERTS: /* --listcerts */ + case LST_CACERTS: /* --listcacerts */ + case LST_ACERTS: /* --listacerts */ + case LST_AACERTS: /* --listaacerts */ + case LST_OCSPCERTS: /* --listocspcerts */ + case LST_GROUPS: /* --listgroups */ + case LST_CAINFOS: /* --listcainfos */ + case LST_CRLS: /* --listcrls */ + case LST_OCSP: /* --listocsp */ + case LST_CARDS: /* --listcards */ + msg.whack_list |= LELEM(c - LST_ALGS); + continue; + + case LST_ALL: /* --listall */ + msg.whack_list = LIST_ALL; + continue; + + /* Connection Description options */ + + case END_HOST: /* --host <ip-address> */ + { + lset_t new_policy = LEMPTY; + + af_used_by = long_opts[long_index].name; + diagq(anyaddr(msg.addr_family, &msg.right.host_addr), optarg); + if (streq(optarg, "%any")) + { + } + else if (streq(optarg, "%opportunistic")) + { + /* always use tunnel mode; mark as opportunistic */ + new_policy |= POLICY_TUNNEL | POLICY_OPPO; + } + else if (streq(optarg, "%group")) + { + /* always use tunnel mode; mark as group */ + new_policy |= POLICY_TUNNEL | POLICY_GROUP; + } + else if (streq(optarg, "%opportunisticgroup")) + { + /* always use tunnel mode; mark as opportunistic */ + new_policy |= POLICY_TUNNEL | POLICY_OPPO | POLICY_GROUP; + } + else + { + diagq(ttoaddr(optarg, 0, msg.addr_family + , &msg.right.host_addr), optarg); + } + + msg.policy |= new_policy; + + if (new_policy & (POLICY_OPPO | POLICY_GROUP)) + { + if (!LHAS(end_seen, END_CLIENT - END_FIRST)) + { + /* set host to 0.0.0 and --client to 0.0.0.0/0 + * or IPV6 equivalent + */ + ip_address any; + + tunnel_af_used_by = optarg; + diagq(anyaddr(msg.tunnel_addr_family, &any), optarg); + diagq(initsubnet(&any, 0, '0', &msg.right.client), optarg); + } + msg.right.has_client = TRUE; + } + if (new_policy & POLICY_GROUP) + { + /* client subnet must not be specified by user: + * it will come from the group's file. + */ + if (LHAS(end_seen, END_CLIENT - END_FIRST)) + diag("--host %group clashes with --client"); + + end_seen |= LELEM(END_CLIENT - END_FIRST); + } + if (new_policy & POLICY_OPPO) + msg.right.key_from_DNS_on_demand = TRUE; + continue; + } + case END_ID: /* --id <identity> */ + msg.right.id = optarg; /* decoded by Pluto */ + continue; + + case END_CERT: /* --cert <path> */ + msg.right.cert = optarg; /* decoded by Pluto */ + continue; + + case END_CA: /* --ca <distinguished name> */ + msg.right.ca = optarg; /* decoded by Pluto */ + continue; + + case END_SENDCERT: + if (streq(optarg, "yes") || streq(optarg, "always")) + { + msg.right.sendcert = CERT_ALWAYS_SEND; + } + else if (streq(optarg, "no") || streq(optarg, "never")) + { + msg.right.sendcert = CERT_NEVER_SEND; + } + else if (streq(optarg, "ifasked")) + { + msg.right.sendcert = CERT_SEND_IF_ASKED; + } + else + { + diagq("whack sendcert value is not legal", optarg); + } + continue; + + case END_GROUPS:/* --groups <access control groups> */ + msg.right.groups = optarg; /* decoded by Pluto */ + continue; + + case END_IKEPORT: /* --ikeport <port-number> */ + if (opt_whole<=0 || opt_whole >= 0x10000) + diagq("<port-number> must be a number between 1 and 65535", optarg); + msg.right.host_port = opt_whole; + continue; + + case END_NEXTHOP: /* --nexthop <ip-address> */ + af_used_by = long_opts[long_index].name; + if (streq(optarg, "%direct")) + diagq(anyaddr(msg.addr_family + , &msg.right.host_nexthop), optarg); + else + diagq(ttoaddr(optarg, 0, msg.addr_family + , &msg.right.host_nexthop), optarg); + continue; + + case END_SRCIP: /* --srcip <ip-address> */ + af_used_by = long_opts[long_index].name; + if (streq(optarg, "%modeconfig") || streq(optarg, "%modecfg")) + { + msg.right.modecfg = TRUE; + } + else + { + diagq(ttoaddr(optarg, 0, msg.addr_family + , &msg.right.host_srcip), optarg); + msg.right.has_srcip = TRUE; + } + msg.policy |= POLICY_TUNNEL; /* srcip => tunnel */ + continue; + + case END_CLIENT: /* --client <subnet> */ + if (end_seen & LELEM(END_CLIENTWITHIN - END_FIRST)) + diag("--client conflicts with --clientwithin"); + tunnel_af_used_by = long_opts[long_index].name; +#ifdef VIRTUAL_IP + if ((strlen(optarg) >= 6 && strncmp(optarg,"vhost:",6) == 0) + || (strlen(optarg) >= 5 && strncmp(optarg,"vnet:",5) == 0)) + { + msg.right.virt = optarg; + } + else + { + diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg); + msg.right.has_client = TRUE; + } +#else + diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg); + msg.right.has_client = TRUE; +#endif + msg.policy |= POLICY_TUNNEL; /* client => tunnel */ + continue; + + case END_CLIENTWITHIN: /* --clienwithin <address range> */ + if (end_seen & LELEM(END_CLIENT - END_FIRST)) + diag("--clientwithin conflicts with --client"); + tunnel_af_used_by = long_opts[long_index].name; + diagq(ttosubnet(optarg, 0, msg.tunnel_addr_family, &msg.right.client), optarg); + msg.right.has_client = TRUE; + msg.policy |= POLICY_TUNNEL; /* client => tunnel */ + msg.right.has_client_wildcard = TRUE; + continue; + + case END_CLIENTPROTOPORT: /* --clientprotoport <protocol>/<port> */ + diagq(ttoprotoport(optarg, 0, &msg.right.protocol, &msg.right.port + , &msg.right.has_port_wildcard), optarg); + continue; + + case END_DNSKEYONDEMAND: /* --dnskeyondemand */ + msg.right.key_from_DNS_on_demand = TRUE; + continue; + + case END_HOSTACCESS: /* --hostaccess */ + msg.right.hostaccess = TRUE; + continue; + + case END_UPDOWN: /* --updown <updown> */ + msg.right.updown = optarg; + continue; + + case CD_TO: /* --to */ + /* process right end, move it to left, reset it */ + if (!LHAS(end_seen, END_HOST - END_FIRST)) + diag("connection missing --host before --to"); + msg.left = msg.right; + clear_end(&msg.right); + end_seen_before_to = end_seen; + end_seen = LEMPTY; + continue; + + case CD_PSK: /* --psk */ + case CD_RSASIG: /* --rsasig */ + case CD_ENCRYPT: /* --encrypt */ + case CD_AUTHENTICATE: /* --authenticate */ + case CD_COMPRESS: /* --compress */ + case CD_TUNNEL: /* --tunnel */ + case CD_PFS: /* --pfs */ + case CD_DISABLEARRIVALCHECK: /* --disablearrivalcheck */ + case CD_DONT_REKEY: /* --donotrekey */ + msg.policy |= LELEM(c - CD_POLICY_FIRST); + continue; + + /* --initiateontraffic + * --pass + * --drop + * --reject + */ + case CD_SHUNT0: + msg.policy = (msg.policy & ~POLICY_SHUNT_MASK) + | ((lset_t)aux << POLICY_SHUNT_SHIFT); + continue; + + /* --failnone + * --failpass + * --faildrop + * --failreject + */ + case CD_FAIL0: + msg.policy = (msg.policy & ~POLICY_FAIL_MASK) + | ((lset_t)aux << POLICY_FAIL_SHIFT); + continue; + + case CD_IKELIFETIME: /* --ikelifetime <seconds> */ + msg.sa_ike_life_seconds = opt_whole; + continue; + + case CD_IPSECLIFETIME: /* --ipseclifetime <seconds> */ + msg.sa_ipsec_life_seconds = opt_whole; + continue; + + case CD_RKMARGIN: /* --rekeymargin <seconds> */ + msg.sa_rekey_margin = opt_whole; + continue; + + case CD_RKFUZZ: /* --rekeyfuzz <percentage> */ + msg.sa_rekey_fuzz = opt_whole; + continue; + + case CD_KTRIES: /* --keyingtries <count> */ + msg.sa_keying_tries = opt_whole; + continue; + + case CD_DPDACTION: + if (streq(optarg, "none")) + msg.dpd_action = DPD_ACTION_NONE; + else if (streq(optarg, "clear")) + msg.dpd_action = DPD_ACTION_CLEAR; + else if (streq(optarg, "hold")) + msg.dpd_action = DPD_ACTION_HOLD; + else if (streq(optarg, "restart")) + msg.dpd_action = DPD_ACTION_RESTART; + else + msg.dpd_action = DPD_ACTION_UNKNOWN; + continue; + + case CD_DPDDELAY: + msg.dpd_delay = opt_whole; + continue; + + case CD_DPDTIMEOUT: + msg.dpd_timeout = opt_whole; + continue; + + case CD_IKE: /* --ike <ike_alg1,ike_alg2,...> */ + msg.ike = optarg; + continue; + + case CD_PFSGROUP: /* --pfsgroup modpXXXX */ + msg.pfsgroup = optarg; + continue; + + case CD_ESP: /* --esp <esp_alg1,esp_alg2,...> */ + msg.esp = optarg; + continue; + + case CD_CONNIPV4: + if (LHAS(cd_seen, CD_CONNIPV6 - CD_FIRST)) + diag("--ipv4 conflicts with --ipv6"); + + /* Since this is the default, the flag is redundant. + * So we don't need to set msg.addr_family + * and we don't need to check af_used_by + * and we don't have to consider defaulting tunnel_addr_family. + */ + continue; + + case CD_CONNIPV6: + if (LHAS(cd_seen, CD_CONNIPV4 - CD_FIRST)) + diag("--ipv6 conflicts with --ipv4"); + + if (af_used_by != NULL) + diagq("--ipv6 must precede", af_used_by); + + af_used_by = long_opts[long_index].name; + msg.addr_family = AF_INET6; + + /* Consider defaulting tunnel_addr_family to AF_INET6. + * Do so only if it hasn't yet been specified or used. + */ + if (LDISJOINT(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST)) + && tunnel_af_used_by == NULL) + msg.tunnel_addr_family = AF_INET6; + continue; + + case CD_TUNNELIPV4: + if (LHAS(cd_seen, CD_TUNNELIPV6 - CD_FIRST)) + diag("--tunnelipv4 conflicts with --tunnelipv6"); + + if (tunnel_af_used_by != NULL) + diagq("--tunnelipv4 must precede", af_used_by); + + msg.tunnel_addr_family = AF_INET; + continue; + + case CD_TUNNELIPV6: + if (LHAS(cd_seen, CD_TUNNELIPV4 - CD_FIRST)) + diag("--tunnelipv6 conflicts with --tunnelipv4"); + + if (tunnel_af_used_by != NULL) + diagq("--tunnelipv6 must precede", af_used_by); + + msg.tunnel_addr_family = AF_INET6; + continue; + + case CA_NAME: /* --caname <name> */ + msg.name = optarg; + msg.whack_ca = TRUE; + continue; + case CA_CERT: /* --cacert <path> */ + msg.cacert = optarg; + continue; + case CA_LDAPHOST: /* --ldaphost <hostname> */ + msg.ldaphost = optarg; + continue; + case CA_LDAPBASE: /* --ldapbase <base> */ + msg.ldapbase = optarg; + continue; + case CA_CRLURI: /* --crluri <uri> */ + msg.crluri = optarg; + continue; + case CA_CRLURI2: /* --crluri2 <uri> */ + msg.crluri2 = optarg; + continue; + case CA_OCSPURI: /* --ocspuri <uri> */ + msg.ocspuri = optarg; + continue; + case CA_STRICT: /* --strictcrlpolicy */ + msg.whack_strict = TRUE; + continue; + +#ifdef DEBUG + case DBGOPT_NONE: /* --debug-none */ + msg.debugging = DBG_NONE; + continue; + + case DBGOPT_ALL: /* --debug-all */ + msg.debugging |= DBG_ALL; /* note: does not include PRIVATE */ + continue; + + case DBGOPT_RAW: /* --debug-raw */ + case DBGOPT_CRYPT: /* --debug-crypt */ + case DBGOPT_PARSING: /* --debug-parsing */ + case DBGOPT_EMITTING: /* --debug-emitting */ + case DBGOPT_CONTROL: /* --debug-control */ + case DBGOPT_LIFECYCLE: /* --debug-lifecycle */ + case DBGOPT_KLIPS: /* --debug-klips */ + case DBGOPT_DNS: /* --debug-dns */ + case DBGOPT_NATT: /* --debug-natt */ + case DBGOPT_OPPO: /* --debug-oppo */ + case DBGOPT_CONTROLMORE: /* --debug-controlmore */ + case DBGOPT_PRIVATE: /* --debug-private */ + case DBGOPT_IMPAIR_DELAY_ADNS_KEY_ANSWER: /* --impair-delay-adns-key-answer */ + case DBGOPT_IMPAIR_DELAY_ADNS_TXT_ANSWER: /* --impair-delay-adns-txt-answer */ + case DBGOPT_IMPAIR_BUST_MI2: /* --impair_bust_mi2 */ + case DBGOPT_IMPAIR_BUST_MR2: /* --impair_bust_mr2 */ + msg.debugging |= LELEM(c-DBGOPT_RAW); + continue; +#endif + default: + assert(FALSE); /* unknown return value */ + } + break; + } + + if (optind != argc) + { + /* If you see this message unexpectedly, perhaps the + * case for the previous option ended with "break" + * instead of "continue" + */ + diagq("unexpected argument", argv[optind]); + } + + /* For each possible form of the command, figure out if an argument + * suggests whether that form was intended, and if so, whether all + * required information was supplied. + */ + + /* check opportunistic initiation simulation request */ + switch (opts_seen & (LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE))) + { + case LELEM(OPT_OPPO_HERE): + case LELEM(OPT_OPPO_THERE): + diag("--oppohere and --oppothere must be used together"); + /*NOTREACHED*/ + case LELEM(OPT_OPPO_HERE) | LELEM(OPT_OPPO_THERE): + msg.whack_oppo_initiate = TRUE; + if (LIN(cd_seen, LELEM(CD_TUNNELIPV4 - CD_FIRST) | LELEM(CD_TUNNELIPV6 - CD_FIRST))) + opts_seen &= ~LELEM(OPT_CD); + break; + } + + /* check connection description */ + if (LHAS(opts_seen, OPT_CD)) + { + if (!LHAS(cd_seen, CD_TO-CD_FIRST)) + diag("connection description option, but no --to"); + + if (!LHAS(end_seen, END_HOST-END_FIRST)) + diag("connection missing --host after --to"); + + if (isanyaddr(&msg.left.host_addr) + && isanyaddr(&msg.right.host_addr)) + diag("hosts cannot both be 0.0.0.0 or 0::0"); + + if (msg.policy & POLICY_OPPO) + { + if ((msg.policy & (POLICY_PSK | POLICY_RSASIG)) != POLICY_RSASIG) + diag("only RSASIG is supported for opportunism"); + if ((msg.policy & POLICY_PFS) == 0) + diag("PFS required for opportunism"); + if ((msg.policy & POLICY_ENCRYPT) == 0) + diag("encryption required for opportunism"); + } + + check_end(&msg.left, &msg.right, !LHAS(end_seen_before_to, END_NEXTHOP-END_FIRST) + , msg.addr_family, msg.tunnel_addr_family); + + check_end(&msg.right, &msg.left, !LHAS(end_seen, END_NEXTHOP-END_FIRST) + , msg.addr_family, msg.tunnel_addr_family); + + if (subnettypeof(&msg.left.client) != subnettypeof(&msg.right.client)) + diag("endpoints clash: one is IPv4 and the other is IPv6"); + + if (NEVER_NEGOTIATE(msg.policy)) + { + /* we think this is just a shunt (because he didn't specify + * a host authentication method). If he didn't specify a + * shunt type, he's probably gotten it wrong. + */ + if ((msg.policy & POLICY_SHUNT_MASK) == POLICY_SHUNT_TRAP) + diag("non-shunt connection must have --psk or --rsasig or both"); + } + else + { + /* not just a shunt: a real ipsec connection */ + if ((msg.policy & POLICY_ID_AUTH_MASK) == LEMPTY) + diag("must specify --rsasig or --psk for a connection"); + + if (!HAS_IPSEC_POLICY(msg.policy) + && (msg.left.has_client || msg.right.has_client)) + diag("must not specify clients for ISAKMP-only connection"); + } + + msg.whack_connection = TRUE; + } + + /* decide whether --name is mandatory or forbidden */ + if (!LDISJOINT(opts_seen + , LELEM(OPT_ROUTE) | LELEM(OPT_UNROUTE) + | LELEM(OPT_INITIATE) | LELEM(OPT_TERMINATE) + | LELEM(OPT_DELETE) | LELEM(OPT_CD))) + { + if (!LHAS(opts_seen, OPT_NAME) && !msg.whack_ca) + diag("missing --name <connection_name>"); + } + else if (!msg.whack_options && !msg.whack_status) + { + if (LHAS(opts_seen, OPT_NAME)) + diag("no reason for --name"); + } + + if (!LDISJOINT(opts_seen, LELEM(OPT_PUBKEYRSA) | LELEM(OPT_ADDKEY))) + { + if (!LHAS(opts_seen, OPT_KEYID)) + diag("--addkey and --pubkeyrsa require --keyid"); + } + + if (!(msg.whack_connection || msg.whack_key || msg.whack_myid + || msg.whack_delete || msg.whack_deletestate + || msg.whack_initiate || msg.whack_oppo_initiate || msg.whack_terminate + || msg.whack_route || msg.whack_unroute || msg.whack_listen + || msg.whack_unlisten || msg.whack_list || msg.whack_purgeocsp || msg.whack_reread + || msg.whack_ca || msg.whack_status || msg.whack_options || msg.whack_shutdown + || msg.whack_sc_op)) + { + diag("no action specified; try --help for hints"); + } + + update_ports(&msg); + + /* tricky quick and dirty check for wild values */ + if (msg.sa_rekey_margin != 0 + && msg.sa_rekey_fuzz * msg.sa_rekey_margin * 4 / msg.sa_rekey_margin / 4 + != msg.sa_rekey_fuzz) + diag("rekeymargin or rekeyfuzz values are so large that they cause oveflow"); + + check_life_time (msg.sa_ike_life_seconds, OAKLEY_ISAKMP_SA_LIFETIME_MAXIMUM + , "ikelifetime", &msg); + + check_life_time(msg.sa_ipsec_life_seconds, SA_LIFE_DURATION_MAXIMUM + , "ipseclifetime", &msg); + + if (msg.dpd_action == DPD_ACTION_UNKNOWN) + diag("dpdaction must be \"none\", \"clear\", \"hold\" or \"restart\""); + + if (msg.dpd_action != DPD_ACTION_NONE) + { + if (msg.dpd_delay <= 0) + diag("dpddelay must be larger than zero"); + + if (msg.dpd_timeout <= 0) + diag("dpdtimeout must be larger than zero"); + + if (msg.dpd_timeout <= msg.dpd_delay) + diag("dpdtimeout must be larger than dpddelay"); + } + + /* pack strings for inclusion in message */ + next_str = msg.string; + str_roof = &msg.string[sizeof(msg.string)]; + + /* build esp message as esp="<esp>;<pfsgroup>" */ + if (msg.pfsgroup) { + snprintf(esp_buf, sizeof (esp_buf), "%s;%s", + msg.esp ? msg.esp : "", + msg.pfsgroup ? msg.pfsgroup : ""); + msg.esp=esp_buf; + } + if (!pack_str(&msg.name) /* string 1 */ + || !pack_str(&msg.left.id) /* string 2 */ + || !pack_str(&msg.left.cert) /* string 3 */ + || !pack_str(&msg.left.ca) /* string 4 */ + || !pack_str(&msg.left.groups) /* string 5 */ + || !pack_str(&msg.left.updown) /* string 6 */ +#ifdef VIRTUAL_IP + || !pack_str(&msg.left.virt) +#endif + || !pack_str(&msg.right.id) /* string 7 */ + || !pack_str(&msg.right.cert) /* string 8 */ + || !pack_str(&msg.right.ca) /* string 9 */ + || !pack_str(&msg.right.groups) /* string 10 */ + || !pack_str(&msg.right.updown) /* string 11 */ +#ifdef VIRTUAL_IP + || !pack_str(&msg.right.virt) +#endif + || !pack_str(&msg.keyid) /* string 12 */ + || !pack_str(&msg.myid) /* string 13 */ + || !pack_str(&msg.cacert) /* string 14 */ + || !pack_str(&msg.ldaphost) /* string 15 */ + || !pack_str(&msg.ldapbase) /* string 16 */ + || !pack_str(&msg.crluri) /* string 17 */ + || !pack_str(&msg.crluri2) /* string 18 */ + || !pack_str(&msg.ocspuri) /* string 19 */ + || !pack_str(&msg.ike) /* string 20 */ + || !pack_str(&msg.esp) /* string 21 */ + || !pack_str(&msg.sc_data) /* string 22 */ + || str_roof - next_str < (ptrdiff_t)msg.keyval.len) /* chunk (sort of string 5) */ + diag("too many bytes of strings to fit in message to pluto"); + + memcpy(next_str, msg.keyval.ptr, msg.keyval.len); + msg.keyval.ptr = NULL; + next_str += msg.keyval.len; + + msg.magic = ((opts_seen & ~LELEM(OPT_SHUTDOWN)) + | sc_seen | lst_seen | cd_seen | ca_seen) != LEMPTY + || msg.whack_options + ? WHACK_MAGIC : WHACK_BASIC_MAGIC; + + /* send message to Pluto */ + if (access(ctl_addr.sun_path, R_OK | W_OK) < 0) + { + int e = errno; + + switch (e) + { + case EACCES: + fprintf(stderr, "whack: no right to communicate with pluto (access(\"%s\"))\n" + , ctl_addr.sun_path); + break; + case ENOENT: + fprintf(stderr, "whack: Pluto is not running (no \"%s\")\n" + , ctl_addr.sun_path); + break; + default: + fprintf(stderr, "whack: access(\"%s\") failed with %d %s\n" + , ctl_addr.sun_path, errno, strerror(e)); + break; + } + exit(RC_WHACK_PROBLEM); + } + else + { + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + int exit_status = 0; + ssize_t len = next_str - (char *)&msg; + + if (sock == -1) + { + int e = errno; + + fprintf(stderr, "whack: socket() failed (%d %s)\n", e, strerror(e)); + exit(RC_WHACK_PROBLEM); + } + + if (connect(sock, (struct sockaddr *)&ctl_addr + , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) + { + int e = errno; + + fprintf(stderr, "whack:%s connect() for \"%s\" failed (%d %s)\n" + , e == ECONNREFUSED? " is Pluto running? " : "" + , ctl_addr.sun_path, e, strerror(e)); + exit(RC_WHACK_PROBLEM); + } + + if (write(sock, &msg, len) != len) + { + int e = errno; + + fprintf(stderr, "whack: write() failed (%d %s)\n", e, strerror(e)); + exit(RC_WHACK_PROBLEM); + } + + /* for now, just copy reply back to stdout */ + + { + char buf[4097]; /* arbitrary limit on log line length */ + char *be = buf; + + for (;;) + { + char *ls = buf; + ssize_t rl = read(sock, be, (buf + sizeof(buf)-1) - be); + + if (rl < 0) + { + int e = errno; + + fprintf(stderr, "whack: read() failed (%d %s)\n", e, strerror(e)); + exit(RC_WHACK_PROBLEM); + } + if (rl == 0) + { + if (be != buf) + fprintf(stderr, "whack: last line from pluto too long or unterminated\n"); + break; + } + + be += rl; + *be = '\0'; + + for (;;) + { + char *le = strchr(ls, '\n'); + + if (le == NULL) + { + /* move last, partial line to start of buffer */ + memmove(buf, ls, be-ls); + be -= ls - buf; + break; + } + + le++; /* include NL in line */ + write(1, ls, le - ls); + + /* figure out prefix number + * and how it should affect our exit status + */ + { + unsigned long s = strtoul(ls, NULL, 10); + + switch (s) + { + case RC_COMMENT: + case RC_LOG: + /* ignore */ + break; + case RC_SUCCESS: + /* be happy */ + exit_status = 0; + break; + case RC_ENTERSECRET: + get_secret(sock); + break; + /* case RC_LOG_SERIOUS: */ + default: + /* pass through */ + exit_status = s; + break; + } + } + ls = le; + } + } + } + return exit_status; + } +} diff --git a/src/whack/whack.h b/src/whack/whack.h new file mode 100644 index 000000000..a62853f61 --- /dev/null +++ b/src/whack/whack.h @@ -0,0 +1,316 @@ +/* Structure of messages from whack to Pluto proper. + * Copyright (C) 1998-2001 D. Hugh Redelmeier. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * RCSID $Id: whack.h,v 1.16 2006/04/17 10:39:14 as Exp $ + */ + +#ifndef _WHACK_H +#define _WHACK_H + +#include <freeswan.h> + +/* Since the message remains on one host, native representation is used. + * Think of this as horizontal microcode: all selected operations are + * to be done (in the order declared here). + * + * MAGIC is used to help detect version mismatches between whack and Pluto. + * Whenever the interface (i.e. this struct) changes in form or + * meaning, change this value (probably by changing the last number). + * + * If the command only requires basic actions (status or shutdown), + * it is likely that the relevant part of the message changes less frequently. + * Whack uses WHACK_BASIC_MAGIC in those cases. + * + * NOTE: no value of WHACK_BASIC_MAGIC may equal any value of WHACK_MAGIC. + * Otherwise certain version mismatches will not be detected. + */ + +#define WHACK_BASIC_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 24) +#define WHACK_MAGIC (((((('w' << 8) + 'h') << 8) + 'k') << 8) + 26) + +typedef struct whack_end whack_end_t; + +/* struct whack_end is a lot like connection.h's struct end + * It differs because it is going to be shipped down a socket + * and because whack is a separate program from pluto. + */ +struct whack_end { + char *id; /* id string (if any) -- decoded by pluto */ + char *cert; /* path string (if any) -- loaded by pluto */ + char *ca; /* distinguished name string (if any) -- parsed by pluto */ + char *groups; /* access control groups (if any) -- parsed by pluto */ + ip_address + host_addr, + host_nexthop, + host_srcip; + ip_subnet client; + + bool key_from_DNS_on_demand; + bool has_client; + bool has_client_wildcard; + bool has_port_wildcard; + bool has_srcip; + bool modecfg; + bool hostaccess; + certpolicy_t sendcert; + char *updown; /* string */ + u_int16_t host_port; /* host order */ + u_int16_t port; /* host order */ + u_int8_t protocol; +#ifdef VIRTUAL_IP + char *virt; +#endif + }; + +typedef struct whack_message whack_message_t; + +struct whack_message { + unsigned int magic; + + /* for WHACK_STATUS: */ + bool whack_status; + bool whack_statusall; + + + /* for WHACK_SHUTDOWN */ + bool whack_shutdown; + + /* END OF BASIC COMMANDS + * If you change anything earlier in this struct, update WHACK_BASIC_MAGIC. + */ + + /* name is used in connection, ca and initiate */ + size_t name_len; /* string 1 */ + char *name; + + /* for WHACK_OPTIONS: */ + + bool whack_options; + + lset_t debugging; /* only used #ifdef DEBUG, but don't want layout to change */ + + /* for WHACK_CONNECTION */ + + bool whack_connection; + bool whack_async; + + lset_t policy; + time_t sa_ike_life_seconds; + time_t sa_ipsec_life_seconds; + time_t sa_rekey_margin; + unsigned long sa_rekey_fuzz; + unsigned long sa_keying_tries; + + /* For DPD 3706 - Dead Peer Detection */ + time_t dpd_delay; + time_t dpd_timeout; + dpd_action_t dpd_action; + + /* note that each end contains string 2/5.id, string 3/6 cert, + * and string 4/7 updown + */ + whack_end_t left; + whack_end_t right; + + /* note: if the client is the gateway, the following must be equal */ + sa_family_t addr_family; /* between gateways */ + sa_family_t tunnel_addr_family; /* between clients */ + + char *ike; /* ike algo string (separated by commas) */ + char *pfsgroup; /* pfsgroup will be "encapsulated" in esp string for pluto */ + char *esp; /* esp algo string (separated by commas) */ + + /* for WHACK_KEY: */ + bool whack_key; + bool whack_addkey; + char *keyid; /* string 8 */ + enum pubkey_alg pubkey_alg; + chunk_t keyval; /* chunk */ + + /* for WHACK_MYID: */ + bool whack_myid; + char *myid; /* string 7 */ + + /* for WHACK_ROUTE: */ + bool whack_route; + + /* for WHACK_UNROUTE: */ + bool whack_unroute; + + /* for WHACK_INITIATE: */ + bool whack_initiate; + + /* for WHACK_OPINITIATE */ + bool whack_oppo_initiate; + ip_address oppo_my_client, oppo_peer_client; + + /* for WHACK_TERMINATE: */ + bool whack_terminate; + + /* for WHACK_DELETE: */ + bool whack_delete; + + /* for WHACK_DELETESTATE: */ + bool whack_deletestate; + so_serial_t whack_deletestateno; + + /* for WHACK_LISTEN: */ + bool whack_listen, whack_unlisten; + + /* for WHACK_CRASH - note if a remote peer is known to have rebooted */ + bool whack_crash; + ip_address whack_crash_peer; + + /* for WHACK_LIST */ + bool whack_utc; + lset_t whack_list; + + /* for WHACK_PURGEOCSP */ + bool whack_purgeocsp; + + /* for WHACK_REREAD */ + u_char whack_reread; + + /* for WHACK_CA */ + bool whack_ca; + bool whack_strict; + + char *cacert; + char *ldaphost; + char *ldapbase; + char *crluri; + char *crluri2; + char *ocspuri; + + /* for WHACK_SC_OP */ + sc_op_t whack_sc_op; + int inbase, outbase; + char *sc_data; + + /* space for strings (hope there is enough room): + * Note that pointers don't travel on wire. + * 1 connection name [name_len] + * 2 left's name [left.host.name.len] + * 3 left's cert + * 4 left's ca + * 5 left's groups + * 6 left's updown + * 7 right's name [left.host.name.len] + * 8 right's cert + * 9 right's ca + * 10 right's groups + * 11 right's updown + * 12 keyid + * 13 myid + * 14 cacert + * 15 ldaphost + * 16 ldapbase + * 17 crluri + * 18 crluri2 + * 19 ocspuri + * 20 ike + " 21 esp + * 22 rsa_data + * plus keyval (limit: 8K bits + overhead), a chunk. + */ + size_t str_size; + char string[2048]; +}; + +/* Codes for status messages returned to whack. + * These are 3 digit decimal numerals. The structure + * is inspired by section 4.2 of RFC959 (FTP). + * Since these will end up as the exit status of whack, they + * must be less than 256. + * NOTE: ipsec_auto(8) knows about some of these numbers -- change carefully. + */ +enum rc_type { + RC_COMMENT, /* non-commital utterance (does not affect exit status) */ + RC_WHACK_PROBLEM, /* whack-detected problem */ + RC_LOG, /* message aimed at log (does not affect exit status) */ + RC_LOG_SERIOUS, /* serious message aimed at log (does not affect exit status) */ + RC_SUCCESS, /* success (exit status 0) */ + + /* failure, but not definitive */ + + RC_RETRANSMISSION = 10, + + /* improper request */ + + RC_DUPNAME = 20, /* attempt to reuse a connection name */ + RC_UNKNOWN_NAME, /* connection name unknown or state number */ + RC_ORIENT, /* cannot orient connection: neither end is us */ + RC_CLASH, /* clash between two Road Warrior connections OVERLOADED */ + RC_DEAF, /* need --listen before --initiate */ + RC_ROUTE, /* cannot route */ + RC_RTBUSY, /* cannot unroute: route busy */ + RC_BADID, /* malformed --id */ + RC_NOKEY, /* no key found through DNS */ + RC_NOPEERIP, /* cannot initiate when peer IP is unknown */ + RC_INITSHUNT, /* cannot initiate a shunt-oly connection */ + RC_WILDCARD, /* cannot initiate when ID has wildcards */ + RC_NOVALIDPIN, /* cannot initiate without valid PIN */ + + /* permanent failure */ + + RC_BADWHACKMESSAGE = 30, + RC_NORETRANSMISSION, + RC_INTERNALERR, + RC_OPPOFAILURE, /* Opportunism failed */ + + /* entry of secrets */ + RC_ENTERSECRET = 40, + + /* progress: start of range for successful state transition. + * Actual value is RC_NEW_STATE plus the new state code. + */ + RC_NEW_STATE = 100, + + /* start of range for notification. + * Actual value is RC_NOTIFICATION plus code for notification + * that should be generated by this Pluto. + */ + RC_NOTIFICATION = 200 /* as per IKE notification messages */ +}; + +/* options of whack --list*** command */ + +#define LIST_NONE 0x0000 /* don't list anything */ +#define LIST_ALGS 0x0001 /* list all registered IKE algorithms */ +#define LIST_PUBKEYS 0x0002 /* list all public keys */ +#define LIST_CERTS 0x0004 /* list all host/user certs */ +#define LIST_CACERTS 0x0008 /* list all ca certs */ +#define LIST_ACERTS 0x0010 /* list all attribute certs */ +#define LIST_AACERTS 0x0020 /* list all aa certs */ +#define LIST_OCSPCERTS 0x0040 /* list all ocsp certs */ +#define LIST_GROUPS 0x0080 /* list all access control groups */ +#define LIST_CAINFOS 0x0100 /* list all ca information records */ +#define LIST_CRLS 0x0200 /* list all crls */ +#define LIST_OCSP 0x0400 /* list all ocsp cache entries */ +#define LIST_CARDS 0x0800 /* list all smartcard records */ + +#define LIST_ALL LRANGES(LIST_ALGS, LIST_CARDS) /* all list options */ + +/* options of whack --reread*** command */ + +#define REREAD_NONE 0x00 /* don't reread anything */ +#define REREAD_SECRETS 0x01 /* reread /etc/ipsec.secrets */ +#define REREAD_CACERTS 0x02 /* reread certs in /etc/ipsec.d/cacerts */ +#define REREAD_AACERTS 0x04 /* reread certs in /etc/ipsec.d/aacerts */ +#define REREAD_OCSPCERTS 0x08 /* reread certs in /etc/ipsec.d/ocspcerts */ +#define REREAD_ACERTS 0x10 /* reread certs in /etc/ipsec.d/acerts */ +#define REREAD_CRLS 0x20 /* reread crls in /etc/ipsec.d/crls */ + +#define REREAD_ALL LRANGES(REREAD_SECRETS, REREAD_CRLS) /* all reread options */ + +#endif /* _WHACK_H */ -- cgit v1.2.3