/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*/
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <libintl.h>
#include <locale.h>
#include <ctype.h>
#include <time.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <netdb.h>
#include <errno.h>
#include <assert.h>
#include <door.h>
#include <setjmp.h>
#include <ipsec_util.h>
#include <ikedoor.h>
/*
* These are additional return values for the command line parsing
* function (parsecmd()). They are specific to this utility, but
* need to share the same space as the IKE_SVC_* defs, without conflicts.
* So they're defined relative to the end of that range.
*/
/*
* Disable default TAB completion for now (until some brave soul tackles it).
*/
/* ARGSUSED */
static
{
return (0);
}
static void
command_complete(int s)
{
if (interactive) {
} else {
exit(s);
}
}
static void
usage()
{
if (!interactive) {
"ikeadm [ -hnp ] cmd obj [cmd-specific options]\n"));
} else {
gettext("\nType help for usage info\n"));
}
command_complete(1);
}
static void
{
(void) printf(
"\tget debug|priv|stats|p1|rule|preshared|defaults [%s]\n",
gettext("identifier"));
(void) printf("\tset debug %s [%s]\n",
(void) printf("\tadd rule|preshared {%s}|%s\n",
(void) printf("\tdump p1|rule|preshared|certcache|groups|"
"encralgs|authalgs\n");
(void) printf("\tflush p1|certcache\n");
(void) printf("\ttoken <login|logout> %s\n",
gettext("<PKCS#11 Token Object>"));
(void) printf(
"\thelp [get|set|add|del|dump|flush|read|write|token|help]\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command gets information from in.iked.\n\n"));
(void) printf("\tdebug\t\t");
(void) printf("\tpriv\t\t");
(void) printf("\tstats\t\t");
(void) printf("\tp1\t\t");
(void) printf("\trule\t\t");
(void) printf("\tpreshared\t");
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf("\tdebug\t\t");
(void) printf("\tpriv\t\t");
(void) printf(
gettext("change the privilege level (may only be lowered)\n"));
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command adds items to in.iked's tables.\n\n"));
(void) printf("\trule\t\t");
(void) printf("\tpreshared\t");
(void) printf(
gettext("\nObjects may be entered on the command-line, as a\n"));
(void) printf(
gettext("series of keywords and tokens contained in curly\n"));
(void) printf(
gettext("braces ('{', '}'); or the name of a file containing\n"));
(void) printf(
gettext("For security purposes, preshared keys may only be\n"));
(void) printf(
gettext("entered on the command-line if ikeadm is running in\n"));
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command deletes an item from in.iked's tables.\n\n"));
(void) printf("\tp1\t\t");
(void) printf("\trule\t\t");
(void) printf("\tpreshared\t");
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command dumps one of in.iked's tables.\n\n"));
(void) printf("\tp1\t\t");
(void) printf("\trule\t\t");
(void) printf("\tpreshared\t");
(void) printf("\tcertcache\t");
(void) printf("\tgroups\t\t");
(void) printf("\tencralgs\t");
(void) printf("\tauthalgs\t");
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command clears one of in.iked's tables.\n\n"));
(void) printf("\tp1\t\t");
(void) printf("\tcertcache\t");
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command reads a new configuration file into\n"));
(void) printf(
gettext("in.iked, discarding the old configuration info.\n\n"));
(void) printf("\trule\t\t");
(void) printf("\tpreshared\t");
(void) printf(
gettext("A filename may be provided to specify a source file\n"));
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command writes in.iked's current configuration\n"));
(void) printf("\trule\t\t");
(void) printf("\tpreshared\t");
(void) printf(
gettext("A filename must be provided to specify the file to\n"));
(void) printf("\n");
command_complete(0);
}
static void
{
"This command logs IKE into and out of PKCS#11 tokens.\n\n"));
(void) printf("\tlogin <PKCS#11 Token Object>\t");
(void) printf("\tlogout <PKCS#11 Token Object>\t");
(void) printf(
gettext("The PKCS#11 Token Object name must be "
"enclosed in quotation marks.\n"));
(void) printf("\n");
command_complete(0);
}
static void
{
(void) printf(
gettext("This command provides information about commands.\n\n"));
(void) printf(
gettext("The 'help' command alone provides a list of valid\n"));
(void) printf(
gettext("commands, along with the valid objects for each.\n"));
(void) printf(
gettext("'help' followed by a valid command name provides\n"));
(void) printf("\n");
command_complete(0);
}
/*PRINTFLIKE1*/
static void
{
}
static int
open_door(void)
{
if (doorfd >= 0)
return (doorfd);
}
static ike_service_t *
{
int retries = 0;
(open_door() >= 0)))
goto retry;
gettext("Unable to communicate with in.iked\n"));
Bail("door_call failed");
}
/* callers assume passed fds will be closed no matter what */
}
/* LINTED E_BAD_PTR_CAST_ALIGN */
}
/*
* Parsing functions
*/
/* stolen from ipseckey.c, with a second tier added */
static int
{
struct objtbl {
char *obj;
int token;
};
static struct cmdtbl {
char *cmd;
int null_obj_token;
} table[] = {
{"get", IKE_SVC_ERROR, {
{"debug", IKE_SVC_GET_DBG},
{"priv", IKE_SVC_GET_PRIV},
{"stats", IKE_SVC_GET_STATS},
{"p1", IKE_SVC_GET_P1},
{"rule", IKE_SVC_GET_RULE},
{"preshared", IKE_SVC_GET_PS},
{"defaults", IKE_SVC_GET_DEFS},
}
},
{"set", IKE_SVC_ERROR, {
{"debug", IKE_SVC_SET_DBG},
{"priv", IKE_SVC_SET_PRIV},
}
},
{"token", IKE_SVC_ERROR, {
{"login", IKE_SVC_SET_PIN},
{"logout", IKE_SVC_DEL_PIN},
{NULL, IKE_SVC_ERROR},
}
},
{"add", IKE_SVC_ERROR, {
{"rule", IKE_SVC_NEW_RULE},
{"preshared", IKE_SVC_NEW_PS},
}
},
{"del", IKE_SVC_ERROR, {
{"p1", IKE_SVC_DEL_P1},
{"rule", IKE_SVC_DEL_RULE},
{"preshared", IKE_SVC_DEL_PS},
}
},
{"dump", IKE_SVC_ERROR, {
{"p1", IKE_SVC_DUMP_P1S},
{"rule", IKE_SVC_DUMP_RULES},
{"preshared", IKE_SVC_DUMP_PS},
{"certcache", IKE_SVC_DUMP_CERTCACHE},
{"groups", IKE_SVC_DUMP_GROUPS},
{"encralgs", IKE_SVC_DUMP_ENCRALGS},
{"authalgs", IKE_SVC_DUMP_AUTHALGS},
}
},
{"flush", IKE_SVC_ERROR, {
{"p1", IKE_SVC_FLUSH_P1S},
{"certcache", IKE_SVC_FLUSH_CERTCACHE},
}
},
{"read", IKE_SVC_ERROR, {
{"rule", IKE_SVC_READ_RULES},
{"preshared", IKE_SVC_READ_PS},
}
},
{"write", IKE_SVC_ERROR, {
{"rule", IKE_SVC_WRITE_RULES},
{"preshared", IKE_SVC_WRITE_PS},
}
},
{"help", IKEADM_HELP_GENERAL, {
{"get", IKEADM_HELP_GET},
{"set", IKEADM_HELP_SET},
{"add", IKEADM_HELP_ADD},
{"del", IKEADM_HELP_DEL},
{"dump", IKEADM_HELP_DUMP},
{"flush", IKEADM_HELP_FLUSH},
{"read", IKEADM_HELP_READ},
{"write", IKEADM_HELP_WRITE},
{"token", IKEADM_HELP_TOKEN},
{"help", IKEADM_HELP_HELP},
}
},
{"exit", IKEADM_EXIT, {
}
},
{"quit", IKEADM_EXIT, {
}
},
{"dbg", IKE_SVC_ERROR, {
{"rbdump", IKE_SVC_DBG_RBDUMP},
}
},
{NULL, IKE_SVC_ERROR, {
}
}
};
return (IKE_SVC_ERROR);
}
ct++;
}
return (ct->null_obj_token);
}
ot++;
}
/*
* Parsing functions:
* Parse command-line identification info. All return -1 on failure,
* or the number of cmd-line args "consumed" on success (though argc
* and argv params are not actually modified).
*/
static int
{
return (-1);
return (-1);
return (1);
}
/*
* Parse a PKCS#11 token get the label.
*/
static int
{
return (-1);
return (-1);
return (0);
}
/*
* Parse an address off the command line. In the hpp param, either
* return a hostent pointer (caller frees) or a pointer to a dummy_he_t
* (must also be freed by the caller; both cases are handled by the
* macro FREE_HE). The new getipnodebyname() call does the Right Thing
* (TM), even with raw addresses (colon-separated IPv6 or dotted decimal
* IPv4).
* (mostly stolen from ipseckey.c, though some tweaks were made
* to better serve our purposes here.)
*/
typedef struct {
} dummy_he_t;
static int
{
int hp_errno;
char *addr1;
return (-1);
if (!nflag) {
/*
* Try name->address first. Assume AF_INET6, and
* get IPV4s, plus IPv6s iff IPv6 is configured.
*/
&hp_errno);
} else {
/*
* Try a normal address conversion only. malloc a
* dummy_he_t to construct a fake hostent. Caller
* will know to free this one using free_he().
*/
} else {
}
}
return (-1);
}
return (1);
}
/*
* Free a dummy_he_t structure that was malloc'd in parse_addr().
* Unfortunately, callers of parse_addr don't want to know about
* dummy_he_t structs, so all they have is a pointer to the struct
* hostent; so that's what's passed in. To manage this, we make
* the assumption that the struct hostent is the first field in
* the dummy_he_t, and therefore a pointer to it is a pointer to
* the dummy_he_t.
*/
static void
{
if (p->addtl[0])
if (p->addtl[1])
free(p);
}
#define FREE_HE(x) \
if (nflag) \
free_he(x); \
else \
freehostent(x)
static void
{
/* LINTED E_BAD_PTR_CAST_ALIGN */
/* LINTED E_BAD_PTR_CAST_ALIGN */
} else {
sizeof (struct in6_addr));
}
} else {
}
}
/*
* The possible ident-type keywords that might be used on the command
* line. This is a superset of the ones supported by ipseckey, those
* in the ike config file, and those in ike.preshared.
*/
/* ip, ipv4, and ipv6 are valid for preshared keys... */
{SADB_IDENTTYPE_RESERVED, "ip"},
{SADB_IDENTTYPE_RESERVED, "ipv4"},
{SADB_IDENTTYPE_RESERVED, "ipv6"},
{SADB_IDENTTYPE_PREFIX, "prefix"},
{SADB_IDENTTYPE_PREFIX, "ipv4-prefix"},
{SADB_IDENTTYPE_PREFIX, "ipv6-prefix"},
{SADB_IDENTTYPE_PREFIX, "subnet"},
{SADB_IDENTTYPE_PREFIX, "subnetv4"},
{SADB_IDENTTYPE_PREFIX, "subnetv6"},
{SADB_IDENTTYPE_FQDN, "fqdn"},
{SADB_IDENTTYPE_FQDN, "dns"},
{SADB_IDENTTYPE_FQDN, "domain"},
{SADB_IDENTTYPE_FQDN, "domainname"},
{SADB_IDENTTYPE_USER_FQDN, "user_fqdn"},
{SADB_IDENTTYPE_USER_FQDN, "mbox"},
{SADB_IDENTTYPE_USER_FQDN, "mailbox"},
{SADB_X_IDENTTYPE_DN, "dn"},
{SADB_X_IDENTTYPE_DN, "asn1dn"},
{SADB_X_IDENTTYPE_GN, "gn"},
{SADB_X_IDENTTYPE_GN, "asn1gn"},
{SADB_X_IDENTTYPE_ADDR_RANGE, "ipv4-range"},
{SADB_X_IDENTTYPE_ADDR_RANGE, "ipv6-range"},
{SADB_X_IDENTTYPE_ADDR_RANGE, "rangev4"},
{SADB_X_IDENTTYPE_ADDR_RANGE, "rangev6"},
{SADB_X_IDENTTYPE_KEY_ID, "keyid"},
{NULL, 0}
};
static int
{
return (-1);
return (1);
}
}
return (-1);
}
/*
* The sadb_ident_t is malloc'd, since its length varies;
* so the caller must free() it when done with the data.
*/
static int
{
return (-1);
Bail("parsing identity");
return (-1);
}
idp->sadb_ident_reserved = 0;
idp->sadb_ident_id = 0;
/* now copy in identity param */
alloclen - (sizeof (sadb_ident_t)));
return (++consumed);
}
static int
{
return (-1);
errno = 0;
if (errno != 0) {
return (-1);
}
return (1);
}
static int
{
return (-1);
}
return (-1);
}
return (consumed);
}
/*
* The sadb_ident_ts are malloc'd, since their length varies;
* so the caller must free() them when done with the data.
*/
static int
{
return (-1);
}
return (-1);
}
return (consumed);
}
static int
{
return (-1);
}
return (-1);
}
return (consumed);
}
/*
* Preshared key field types...used for parsing preshared keys that
* have been entered on the command line. The code to parse preshared
* keys (parse_ps, parse_key, parse_psfldid, parse_ikmtype, ...) is
* mostly duplicated from in.iked's readps.c.
*/
{PSFLD_LOCID, "localid"},
{PSFLD_LOCIDTYPE, "localidtype"},
{PSFLD_REMID, "remoteid"},
{PSFLD_REMIDTYPE, "remoteidtype"},
{PSFLD_MODE, "ike_mode"},
{PSFLD_KEY, "key"},
{NULL, 0}
};
static int
{
return (-1);
return (1);
}
}
return (-1);
}
{IKE_XCHG_IDENTITY_PROTECT, "main"},
{IKE_XCHG_AGGRESSIVE, "aggressive"},
{IKE_XCHG_IP_AND_AGGR, "both"},
{NULL, 0}
};
static int
{
return (-1);
return (1);
}
}
return (-1);
}
static uint8_t *
{
hexlen++;
if (input[i] == '\0') {
bits = 0;
} else {
/* Have /nn. */
input[i] = '\0';
return (NULL);
/* hexlen is in nibbles */
return (NULL);
/*
* Adjust hexlen down if user gave us too small of a bit
* count.
*/
}
}
/*
* Allocate. Remember, hexlen is in nibbles.
*/
return (NULL);
if (bits == 0)
else
/*
* Read in nibbles. Read in odd-numbered as shifted high.
* (e.g. 123 becomes 0x1230).
*/
return (NULL);
}
if (second)
else
break; /* out of for loop. */
keyp++;
}
/* zero the remaining bits if we're a non-octet amount. */
if (bits & 0x7)
return (keybufp);
}
/*
* the ike_ps_t struct (plus trailing data) will be allocated here,
* so it will need to be freed by the caller.
*/
static int
{
int pfxlen = 0;
return (-1);
if (argv[c][1] != 0) {
/* no space between '{' and first token */
argv[c]++;
} else {
c++;
}
/*
* whack '}' without a space before it or parsers break.
* Remember this trailing character for later
*/
}
/* Default to type IP */
/* Default to base exchanges */
goto bail;
goto bail;
switch (fldid) {
case PSFLD_LOCID:
break;
case PSFLD_LOCIDTYPE:
goto bail;
break;
case PSFLD_REMID:
break;
case PSFLD_REMIDTYPE:
goto bail;
break;
case PSFLD_MODE:
goto bail;
break;
case PSFLD_KEY:
goto bail;
break;
}
}
/* Make sure the line was terminated with '}' */
if (!whacked)
goto bail;
} else if (argv[c][0] != '}') {
goto bail;
}
/*
* make sure we got all the required fields. If no idtype, assume
* ip addr; if that translation fails, we'll catch the error then.
*/
goto bail;
/* figure out the size buffer we need */
if (locidtype != SADB_IDENTTYPE_RESERVED) {
*len += a_locidtotal;
}
if (remidtype != SADB_IDENTTYPE_RESERVED) {
*len += a_remidtotal;
}
goto bail;
if (locidtype == SADB_IDENTTYPE_RESERVED) {
*locpfx = '\0';
locpfx++;
}
/*
* this is an ip address, store in the sockaddr field;
* we won't use an sadb_ident_t.
*/
psp->ps_localid_len = 0;
goto bail;
"match multiple IP addresses"));
goto bail;
}
} else {
}
if (remidtype == SADB_IDENTTYPE_RESERVED) {
*rempfx = '\0';
rempfx++;
}
/*
* this is an ip address, store in the sockaddr field;
* we won't use an sadb_ident_t.
*/
psp->ps_remoteid_len = 0;
goto bail;
"match multiple IP addresses"));
goto bail;
}
} else {
/* make sure we have at least 16-bit alignment */
if (remidlen & 0x1)
remidlen++;
}
*presharedpp = psp;
return (c);
bail:
*presharedpp = NULL;
return (-1);
}
/*
* Printing functions
*
* A potential point of confusion here is that the ikeadm-specific string-
* producing functions do not match the ipsec_util.c versions in style: the
* ikeadm-specific functions return a string (and are named foostr), while
* the ipsec_util.c functions actually print the string to the file named
* in the second arg to the function (and are named dump_foo).
*
* Localization for ikeadm seems more straightforward when complete
* phrases are translated rather than: a part of a phrase, a call to
* dump_foo(), and more of the phrase. It could also accommodate
* non-English grammar more easily.
*/
static char *
{
switch (err) {
case IKE_ERR_NO_OBJ:
return (gettext("No data returned"));
case IKE_ERR_NO_DESC:
return (gettext("No destination provided"));
case IKE_ERR_ID_INVALID:
return (gettext("Id info invalid"));
case IKE_ERR_LOC_INVALID:
return (gettext("Destination invalid"));
case IKE_ERR_CMD_INVALID:
return (gettext("Command invalid"));
case IKE_ERR_DATA_INVALID:
return (gettext("Supplied data invalid"));
case IKE_ERR_CMD_NOTSUP:
return (gettext("Unknown command"));
case IKE_ERR_REQ_INVALID:
return (gettext("Request invalid"));
case IKE_ERR_NO_PRIV:
return (gettext("Not allowed at current privilege level"));
case IKE_ERR_NO_AUTH:
return (gettext("User not authorized"));
case IKE_ERR_SYS_ERR:
return (gettext("System error"));
case IKE_ERR_DUP_IGNORED:
return (gettext("One or more duplicate entries ignored"));
case IKE_ERR_NO_TOKEN:
return (gettext(
"token login failed or no objects on device"));
case IKE_ERR_IN_PROGRESS:
return (gettext(
"Duplicate operation already in progress"));
case IKE_ERR_NO_MEM:
return (gettext(
"Insufficient memory"));
default:
return (rtn);
}
}
static char *
{
switch (bit) {
case D_CERT:
return (gettext("Certificate management"));
case D_KEY:
return (gettext("Key management"));
case D_OP:
return (gettext("Operational"));
case D_P1:
return (gettext("Phase 1 SA creation"));
case D_P2:
return (gettext("Phase 2 SA creation"));
case D_PFKEY:
return (gettext("PF_KEY interface"));
case D_POL:
return (gettext("Policy management"));
case D_PROP:
return (gettext("Proposal construction"));
case D_DOOR:
return (gettext("Door interface"));
case D_CONFIG:
return (gettext("Config file processing"));
case D_LABEL:
return (gettext("MAC label processing"));
default:
return (rtn);
}
}
static char *
{
switch (priv) {
case IKE_PRIV_MINIMUM:
return (gettext("base privileges"));
case IKE_PRIV_MODKEYS:
return (gettext("access to preshared key information"));
case IKE_PRIV_KEYMAT:
return (gettext("access to keying material"));
default:
return (rtn);
}
}
static char *
{
switch (xchg) {
case IKE_XCHG_NONE:
return (gettext("<unspecified>"));
case IKE_XCHG_BASE:
return (gettext("base"));
return (gettext("main mode (identity protect)"));
case IKE_XCHG_AUTH_ONLY:
return (gettext("authentication only"));
case IKE_XCHG_AGGRESSIVE:
return (gettext("aggressive mode"));
case IKE_XCHG_IP_AND_AGGR:
return (gettext("main and aggressive mode"));
case IKE_XCHG_ANY:
return (gettext("any mode"));
default:
return (rtn);
}
}
static char *
{
switch (state) {
case IKE_SA_STATE_INIT:
return (gettext("INITIALIZING"));
case IKE_SA_STATE_SENT_SA:
return (gettext("SENT FIRST MSG (SA)"));
case IKE_SA_STATE_SENT_KE:
return (gettext("SENT SECOND MSG (KE)"));
case IKE_SA_STATE_SENT_LAST:
return (gettext("SENT FINAL MSG"));
case IKE_SA_STATE_DONE:
return (gettext("ACTIVE"));
case IKE_SA_STATE_DELETED:
return (gettext("DELETED"));
case IKE_SA_STATE_INVALID:
return (gettext("<invalid>"));
default:
return (rtn);
}
}
static char *
{
switch (meth) {
return (gettext("pre-shared key"));
case IKE_AUTH_METH_DSS_SIG:
return (gettext("DSS signatures"));
case IKE_AUTH_METH_RSA_SIG:
return (gettext("RSA signatures"));
case IKE_AUTH_METH_RSA_ENCR:
return (gettext("RSA Encryption"));
return (gettext("Revised RSA Encryption"));
default:
return (rtn);
}
}
static char *
{
switch (prf) {
case IKE_PRF_NONE:
return (gettext("<none/unavailable>"));
case IKE_PRF_HMAC_MD5:
return ("HMAC MD5");
case IKE_PRF_HMAC_SHA1:
return ("HMAC SHA1");
case IKE_PRF_HMAC_SHA256:
return ("HMAC SHA256");
case IKE_PRF_HMAC_SHA384:
return ("HMAC SHA384");
case IKE_PRF_HMAC_SHA512:
return ("HMAC SHA512");
default:
return (rtn);
}
}
static char *
{
switch (grp) {
case 0:
return (gettext("<unavailable>"));
case IKE_GRP_DESC_MODP_768:
return (gettext("768-bit MODP (group 1)"));
case IKE_GRP_DESC_MODP_1024:
return (gettext("1024-bit MODP (group 2)"));
case IKE_GRP_DESC_EC2N_155:
return (gettext("EC2N group on GP[2^155]"));
case IKE_GRP_DESC_EC2N_185:
return (gettext("EC2N group on GP[2^185]"));
case IKE_GRP_DESC_MODP_1536:
return (gettext("1536-bit MODP (group 5)"));
case IKE_GRP_DESC_MODP_2048:
return (gettext("2048-bit MODP (group 14)"));
case IKE_GRP_DESC_MODP_3072:
return (gettext("3072-bit MODP (group 15)"));
case IKE_GRP_DESC_MODP_4096:
return (gettext("4096-bit MODP (group 16)"));
case IKE_GRP_DESC_MODP_6144:
return (gettext("6144-bit MODP (group 17)"));
case IKE_GRP_DESC_MODP_8192:
return (gettext("8192-bit MODP (group 18)"));
case IKE_GRP_DESC_ECP_256:
return (gettext("256-bit ECP (group 19)"));
case IKE_GRP_DESC_ECP_384:
return (gettext("384-bit ECP (group 20)"));
case IKE_GRP_DESC_ECP_521:
return (gettext("521-bit ECP (group 21)"));
return (
gettext("1024-bit MODP with 160-bit subprime (group 22)"));
return (
gettext("2048-bit MODP with 224-bit subprime (group 23)"));
return (
gettext("2048-bit MODP with 256-bit subprime (group 24)"));
case IKE_GRP_DESC_ECP_192:
return (gettext("192-bit ECP (group 25)"));
case IKE_GRP_DESC_ECP_224:
return (gettext("224-bit ECP (group 26)"));
default:
return (rtn);
}
}
static void
{
(void) printf(
gettext("%s Cookies: Initiator 0x%llx Responder 0x%llx\n"),
return;
}
" enabled"), prefix);
(void) printf("\n");
return;
}
}
switch (hdrp->p1hdr_dpd_state) {
case DPD_SUCCESSFUL:
break;
case DPD_FAILURE:
break;
case DPD_IN_PROGRESS:
break;
}
(void) printf("\n");
}
static void
{
}
static void
{
}
static void
{
if (xfp->p1xf_encr_low_bits != 0) {
} else if ((xfp->p1xf_encr_low_bits == 0) &&
(xfp->p1xf_encr_high_bits != 0)) {
/*
* High bits is a placeholder for
* negotiated algorithm strength
*/
}
} else {
"%s Phase 2 PFS is required (Oakley Group: %s)\n"),
}
if (print_lifetimes)
}
static void
int statlen)
{
/*
* make sure the stats struct we've been passed is as big
* as we expect it to be. The usage stats are at the end,
* so anything less than the size we expect won't work.
*/
if (statlen >= sizeof (ike_p1_stats_t)) {
} else {
return;
}
if (xfp->p1xf_max_kbytes != 0)
"protected.\n"),
SPC_END));
if (xfp->p1xf_max_keyuses != 0)
"%u more times.\n"), prefix,
if (xfp->p1xf_max_secs != 0) {
/*
* The SA may have expired but still exist because libike
* has not freed it yet.
*/
if (remain > 0) {
"%s SA expires in %lu seconds%s\n"),
} else {
}
}
}
/* used to verify structure lengths... */
static void
{
if (statlen < COUNTER_PAIR)
return;
statlen -= COUNTER_PAIR;
}
static void
{
/*
* Don't try to break this one up; it's either all or nothing!
*/
if (errlen < sizeof (ike_p1_errors_t))
return;
}
static void
{
return;
}
case AF_INET:
break;
case AF_INET6:
break;
default:
return;
}
if (range) {
(void) printf(" - ");
nflag);
}
(void) printf("\n");
}
/*
* used to tell printing function if info should be identified
* as belonging to initiator, responder, or neither
*/
static void
int mask)
{
if (init_instr != DONT_PRINT_INIT)
else
(void) printf(":\n");
nflag);
}
static void
{
switch (init_instr) {
case IS_INITIATOR:
break;
case IS_RESPONDER:
break;
case DONT_PRINT_INIT:
break;
default:
return;
}
if (canprint) {
} else {
(const unsigned char *)(idp + 1),
}
}
static void
{
int i;
for (i = 0; i < icnt; i++) {
if (i == 0)
}
for (i = 0; i < ecnt; i++) {
if (i == 0)
}
}
static void
{
ike_p1_key_t *p;
int ssize;
ssize = sizeof (ike_p1_key_t);
p = (ike_p1_key_t *)curp;
break;
}
switch (p->p1key_type) {
case IKE_KEY_PRESHARED:
break;
case IKE_KEY_SKEYID:
break;
case IKE_KEY_SKEYID_D:
break;
case IKE_KEY_SKEYID_A:
break;
case IKE_KEY_SKEYID_E:
break;
case IKE_KEY_ENCR:
break;
case IKE_KEY_IV:
(void) printf(
gettext("%s Initialization vector (%d bytes): "),
break;
default:
goto badkey;
}
(void) printf("\n");
}
}
static void
print_group_header(void)
{
"up IKE SAs"));
"assigned numbers published by IANA\n\n"));
(void) printf("%-6s%-9s%-50s\n",
}
static void
{
(void) printf("%-6u%-9u%-50s\n",
}
static void
print_encralg_header(void)
{
"assigned numbers published by IANA\n\n"));
}
static void
{
(void) printf("%-6u%-20s%-15s\n",
}
static void
print_authalg_header(void)
{
"assigned numbers published by IANA\n\n"));
}
static void
{
(void) printf("%-6u%-20s\n",
}
static void
{
(void) printf("\n");
} else {
}
/*
* the stat len might be 0; but still make the call
* to print_lifetime() to pick up the xform info
*/
if (p1->p1sa_stat_len > 0) {
}
if (p1->p1sa_error_len > 0) {
}
if (p1->p1sa_localid_len > 0) {
}
if (p1->p1sa_remoteid_len > 0) {
}
if (p1->p1sa_key_len > 0) {
}
}
static void
{
(void) printf("\n");
if ((int)c->certclass == -1)
switch (c->linkage) {
case CERT_OFF_WIRE:
"\t\t[Obtained via certificate payload]\n"));
break;
case CERT_NO_PRIVKEY:
break;
case CERT_PRIVKEY_LOCKED:
"\t\t[Private key linked but locked]\n"));
break;
case CERT_PRIVKEY_AVAIL:
break;
}
}
static void
{
(void) printf("\n");
if (ps->ps_key_len > 0) {
ps->ps_key_len);
(void) printf("\n");
}
/*
* We get *either* and address or an ident, never both. So if
* the ident is there, don't try printing an address.
*/
if (ps->ps_localid_len > 0) {
lidp = (sadb_ident_t *)
} else {
}
if (ps->ps_remoteid_len > 0) {
ridp = (sadb_ident_t *)
} else {
}
}
static void
{
int i;
(void) printf("\n");
"GLOBL: p1_nonce_len=%u, p2_nonce_len=%u, p2_pfs=%s (group %u)\n"),
rp->rule_p2_pfs);
(void) printf(
gettext("GLOBL: p2_lifetime=%u seconds%s\n"),
(void) printf(
gettext("GLOBL: p2_softlife=%u seconds%s\n"),
(void) printf(
gettext("GLOBL: p2_idletime=%u seconds%s\n"),
/*
* Perform explicit conversion before passing to bytecnt2out()
* to avoid integer overflow.
*/
(void) printf(
gettext("GLOBL: p2_lifetime_kb=%u kilobytes%s\n"),
(void) printf(
gettext("GLOBL: p2_softlife_kb=%u kilobytes%s\n"),
if (rp->rule_locip_cnt > 0) {
}
}
if (rp->rule_remip_cnt > 0) {
}
}
}
}
if (rp->rule_xform_cnt > 0) {
}
}
}
static void
{
/*
* before printing each line, make sure the structure we were
* given is big enough to include the fields needed.
*/
if (len < COUNTER_PAIR)
return;
len -= COUNTER_PAIR;
if (len < COUNTER_PAIR)
return;
len -= COUNTER_PAIR;
if (len < COUNTER_PAIR)
return;
len -= COUNTER_PAIR;
return;
(void) printf(
gettext(" initiator fails include %u time-out(s)\n"),
return;
}
/* Print one line of 'get defaults' output (i.e. single value). */
static void
{
}
/*
* Print out defaults used by in.iked, the argument is a buffer containing
* two ike_defaults_t's, the first contains the hard coded defaults, the second
* contains the actual values used. If these differ, then the defaults have been
* changed via a config file entry. Note that "-" indicates this default
* is not tunable via ike.config(4) or is system wide tunable.
*/
static void
{
" over-ridden on a per rule basis.\n"));
(void) printf("%-18s%-10s%-12s%-10s%-26s\n\n",
/* iked tunables */
/* system wide tunables */
/* minimum and maximum values */
/* other values */
}
static void
{
int mask;
if (level == 0) {
return;
}
}
(void) printf("\n");
}
/*PRINTFLIKE2*/
static void
{
} else {
}
}
/*PRINTFLIKE2*/
static void
{
gettext("<unknown error>") :
gettext("Duplicate entry") :
} else {
}
}
/*
* Command functions
*/
/*
* Exploit the fact that ike_dbg_t and ike_priv_t have identical
* formats in the following two functions.
*/
static void
{
char *varname;
switch (cmd) {
case IKE_SVC_GET_DBG:
break;
case IKE_SVC_GET_PRIV:
break;
default:
}
}
if (cmd == IKE_SVC_GET_DBG) {
(void) printf("\n");
} else {
}
}
/*
* Log into a token and unlock all objects
* referenced by PKCS#11 hint files.
*/
static void
{
char *token_pin;
if (argc < 1)
switch (cmd) {
case IKE_SVC_SET_PIN:
Bail("Invalid syntax for \"token login\"");
"Enter PIN for PKCS#11 token \'%s\': ", token_label);
break;
case IKE_SVC_DEL_PIN:
Bail("Invalid syntax for \"token logout\"");
break;
default:
}
if (cmd == IKE_SVC_SET_PIN)
gettext("PKCS#11 operation"));
}
}
static void
{
char *varname;
if (argc < 1)
Bail("unspecified level");
switch (cmd) {
case IKE_SVC_SET_DBG:
if (argc > 2)
Bail("Too many arguments to \"set debug\"");
if (reqlevel == 0) {
/* check for a string... */
}
break;
case IKE_SVC_SET_PRIV:
if (argc > 1)
Bail("Too many arguments to \"set priv\"");
if (reqlevel == 0) {
/* check for a string... */
}
if (reqlevel > IKE_PRIV_MAXIMUM)
break;
default:
}
if (fd < 0)
Bail("open debug file");
ndesc = 1;
}
}
(void) printf(
gettext("Successfully changed %s level from 0x%x to 0x%x\n"),
if (cmd == IKE_SVC_SET_DBG) {
} else {
}
}
static void
{
}
}
static void
{
gettext("error getting defaults"));
}
/*
* Before printing each line, make sure the structure we were
* given is big enough to include the fields needed.
* Silently bail out of there is a version mismatch.
*/
return;
}
}
static void
{
char *name;
switch (cmd) {
case IKE_SVC_DUMP_P1S:
break;
case IKE_SVC_DUMP_RULES:
break;
case IKE_SVC_DUMP_PS:
break;
case IKE_SVC_DUMP_CERTCACHE:
break;
case IKE_SVC_DUMP_GROUPS:
break;
case IKE_SVC_DUMP_ENCRALGS:
break;
case IKE_SVC_DUMP_AUTHALGS:
break;
default:
}
do {
NULL, 0);
/* no entries to print */
break;
}
}
switch (cmd) {
case IKE_SVC_DUMP_P1S:
break;
case IKE_SVC_DUMP_RULES:
break;
case IKE_SVC_DUMP_PS:
break;
case IKE_SVC_DUMP_CERTCACHE:
break;
case IKE_SVC_DUMP_GROUPS:
break;
case IKE_SVC_DUMP_ENCRALGS:
break;
case IKE_SVC_DUMP_AUTHALGS:
break;
}
}
static void
{
int totallen;
char *p;
(cmd == IKE_SVC_GET_PS));
/*
* WARNING: to avoid being redundant, this code takes advantage
* of the fact that the ike_get_t and ike_del_t structures are
* identical (only the field names differ, their function and
* size are the same). If for some reason those structures
* change, this code will need to be re-written to accomodate
* that difference.
*/
Bail("malloc(id)");
p = (char *)(getp + 1);
} else {
name);
}
return;
}
if (getcmd) {
switch (cmd) {
case IKE_SVC_GET_P1:
break;
case IKE_SVC_GET_PS:
break;
case IKE_SVC_GET_RULE:
break;
}
} else {
}
}
static void
{
Bail("not enough identification info");
}
switch (cmd) {
case IKE_SVC_GET_P1:
case IKE_SVC_DEL_P1:
/*
* The first token must either be an address (or hostname)
* or a cookie. We require cookies to be entered as hex
* numbers, beginning with 0x; so if our token starts with
* that, it's a cookie.
*/
idlen = sizeof (ike_cky_pr_t);
}
} else {
idlen = sizeof (ike_addr_pr_t);
}
}
break;
case IKE_SVC_GET_RULE:
case IKE_SVC_DEL_RULE:
}
break;
case IKE_SVC_GET_PS:
case IKE_SVC_DEL_PS:
/*
* The first token must either be an address or an ident
* type. Check for an ident type to determine which it is.
*/
}
} else {
idlen = sizeof (ike_addr_pr_t);
}
}
break;
default:
}
switch (idtype) {
case IKE_ID_ADDR_PAIR:
/*
* we might have exploding addrs here; do every possible
* combination.
*/
i = 0;
j = 0;
}
}
break;
case IKE_ID_IDENT_PAIR:
Bail("ident syntax error");
if (p == NULL)
Bail("malloc(id)");
p += bytelen1;
break;
case IKE_ID_CKY_PAIR:
case IKE_ID_LABEL:
break;
case 0:
default:
}
}
/*
* Copy source into target, inserting an escape character ('\') before
* any quotes that appear. Return true on success, false on failure.
*/
static boolean_t
{
return (B_FALSE);
if (source[s] == '\"')
target[t++] = '\\';
}
return (B_FALSE);
return (B_TRUE);
}
/*
* Return true if the arg following the given keyword should
* be in quotes (i.e. is a string), false if not.
*/
static boolean_t
{
return (B_TRUE);
return (B_FALSE);
}
static void
{
switch (cmd) {
case IKE_SVC_NEW_PS:
break;
case IKE_SVC_NEW_RULE:
break;
default:
}
if (argc == 1) {
/* We've been given a file to read from */
if (fd < 0)
Bail("open source file");
ndesc = 1;
/*
* This is an alternative to using the tmpfile method
* for preshared keys. It means we're duplicating the
* parsing effort that happens in readps.c; but it
* does avoid having the key sitting in a file.
*/
int pslen;
/*
* must be in interactive mode; don't want keys in
* the process args.
*/
if (!interactive)
Bail("Must be in interactive mode to add key info.");
errno = 0;
Bail("invalid preshared key definition");
}
Bail("alloc pskey");
/* parse_ps allocated the ike_ps_t buffer; free it now */
/*
* We've been given the item in argv. However, parsing
* rules can get more than a little messy, and in.iked
* already has a great parser for this stuff! So don't
* fool around with trying to do the parsing here. Just
* write it out to a tempfile, and send the fd to in.iked.
*
* We could conceivably do this for preshared keys,
* rather than duplicating the parsing effort; but that
* would mean the key would be written out to a file,
* which isn't such a good idea.
*/
int rtn;
if ((argv[0][0] != '{') ||
/* attempt to use a fairly unpredictable file name... */
if (fd < 0)
Bail("cannot open tmpfile");
/* and make it inaccessible asap */
if (unlink(tmpfilepath) < 0) {
Bail("tmpfile error");
}
Bail("cannot write to tmpfile");
}
for (i = 0; i < argc; i++) {
/*
* We have to do some gyrations with our string here,
* to properly handle quotes. There are two issues:
* - some of the fields of a rule may have embedded
* whitespace, and thus must be quoted on the cmd
* line. The shell removes the quotes, and gives
* us a single argv string; but we need to put the
* quotes back in when we write the string out to
* file. The doquotes boolean is set when we
* process a keyword which will be followed by a
* string value (so the NEXT argv element will be
* quoted).
* - there might be a quote character in a field,
* that was escaped on the cmdline. The shell
* removes the escape char, and leaves the quote
* in the string it gives us. We need to put the
* escape char back in before writing to file.
*/
Bail("write to tmpfile failed (arg too big)");
if (doquotes) {
} else {
}
if (rtn < 0)
Bail("write to tmpfile failed");
/*
* check if this is a keyword identifying
* a field that needs to be quoted.
*/
}
Bail("write to tmpfile failed");
/* rewind so that the daemon will get the beginning */
ndesc = 1;
} else {
/* not enough information! */
}
} else {
}
}
static void
{
}
}
if (cmd == IKE_SVC_FLUSH_P1S)
else
}
static void
{
switch (cmd) {
case IKE_SVC_READ_PS:
/* FALLTHRU */
case IKE_SVC_READ_RULES:
omode = 0;
break;
case IKE_SVC_WRITE_PS:
/* FALLTHRU */
case IKE_SVC_WRITE_RULES:
/* for write commands, dest location must be specified */
if (argc < 1) {
"to write %ss"), obj);
}
break;
default:
}
if (argc >= 1) {
if (fd < 0)
Bail("open user-specified file");
ndesc = 1;
} else {
}
/*
* Need to remove the target file in the
* case of a failed write command.
*/
if (writing) {
/*
* argv[0] must be valid if we're writing; we
* exit before setting this boolean if not.
*/
obj);
return;
}
}
}
}
static void
{
}
}
/*ARGSUSED*/
static void
{
if (interactive) {
if (argc == 0)
return;
}
if (argc < REQ_ARG_CNT) {
usage();
}
if (argc > REQ_ARG_CNT) {
cmd_obj_args++;
} else {
}
argc -= cmd_obj_args;
argv += cmd_obj_args;
switch (cmd) {
case IKE_SVC_GET_DEFS:
if (argc != 0) {
break;
}
break;
case IKE_SVC_GET_DBG:
case IKE_SVC_GET_PRIV:
if (argc != 0) {
break;
}
break;
case IKE_SVC_GET_STATS:
if (argc != 0) {
break;
}
break;
case IKE_SVC_SET_DBG:
case IKE_SVC_SET_PRIV:
break;
case IKE_SVC_SET_PIN:
case IKE_SVC_DEL_PIN:
break;
case IKE_SVC_DUMP_P1S:
case IKE_SVC_DUMP_RULES:
case IKE_SVC_DUMP_GROUPS:
case IKE_SVC_DUMP_ENCRALGS:
case IKE_SVC_DUMP_AUTHALGS:
case IKE_SVC_DUMP_PS:
case IKE_SVC_DUMP_CERTCACHE:
break;
}
break;
case IKE_SVC_GET_P1:
case IKE_SVC_GET_RULE:
case IKE_SVC_GET_PS:
case IKE_SVC_DEL_P1:
case IKE_SVC_DEL_RULE:
case IKE_SVC_DEL_PS:
break;
case IKE_SVC_NEW_RULE:
case IKE_SVC_NEW_PS:
break;
case IKE_SVC_FLUSH_P1S:
case IKE_SVC_FLUSH_CERTCACHE:
if (argc != 0) {
break;
}
break;
case IKE_SVC_READ_RULES:
case IKE_SVC_READ_PS:
case IKE_SVC_WRITE_RULES:
case IKE_SVC_WRITE_PS:
break;
case IKEADM_HELP_GENERAL:
print_help();
break;
case IKEADM_HELP_GET:
break;
case IKEADM_HELP_SET:
break;
case IKEADM_HELP_ADD:
break;
case IKEADM_HELP_DEL:
break;
case IKEADM_HELP_DUMP:
break;
case IKEADM_HELP_FLUSH:
break;
case IKEADM_HELP_READ:
break;
case IKEADM_HELP_WRITE:
break;
case IKEADM_HELP_TOKEN:
break;
case IKEADM_HELP_HELP:
break;
case IKEADM_EXIT:
if (interactive)
exit(0);
break;
case IKE_SVC_DBG_RBDUMP:
do_rbdump();
break;
case IKE_SVC_ERROR:
usage();
default:
exit(0);
}
}
int
{
char ch;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
switch (ch) {
case 'h':
print_help();
return (0);
case 'p':
break;
case 'n':
break;
default:
usage();
}
}
if (open_door() < 0) {
gettext("Unable to communicate with in.iked\n"));
Bail("open_door failed");
}
/* no cmd-line args, do interactive mode */
no_match);
}
return (0);
}