/*
* 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
* or http://www.opensolaris.org/os/licensing.
* 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
*/
/*
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <locale.h>
#include <libgen.h>
#include <sys/types.h>
#include <zone.h>
#include <sys/crypto/ioctladmin.h>
#include <cryptoutil.h>
#include "cryptoadm.h"
#define REQ_ARG_CNT 2
/* subcommand index */
enum subcommand_index {
CRYPTO_LIST,
CRYPTO_DISABLE,
CRYPTO_ENABLE,
CRYPTO_INSTALL,
CRYPTO_UNINSTALL,
CRYPTO_UNLOAD,
CRYPTO_REFRESH,
CRYPTO_START,
CRYPTO_STOP,
CRYPTO_HELP };
/*
* TRANSLATION_NOTE
* Command keywords are not to be translated.
*/
static char *cmd_table[] = {
"list",
"disable",
"enable",
"install",
"uninstall",
"unload",
"refresh",
"start",
"stop",
"--help" };
/* provider type */
enum provider_type_index {
PROV_UEF_LIB,
PROV_KEF_SOFT,
PROV_KEF_HARD,
METASLOT,
PROV_BADNAME };
typedef struct {
char cp_name[MAXPATHLEN];
enum provider_type_index cp_type;
} cryptoadm_provider_t;
/*
* TRANSLATION_NOTE
* Operand keywords are not to be translated.
*/
static const char *KN_PROVIDER = "provider=";
static const char *KN_MECH = "mechanism=";
static const char *KN_ALL = "all";
static const char *KN_TOKEN = "token=";
static const char *KN_SLOT = "slot=";
static const char *KN_DEFAULT_KS = "default-keystore";
static const char *KN_AUTO_KEY_MIGRATE = "auto-key-migrate";
/* static variables */
static boolean_t allflag = B_FALSE;
static boolean_t rndflag = B_FALSE;
static mechlist_t *mecharglist = NULL;
/* static functions */
static void usage(void);
static int get_provider_type(char *);
static int process_mech_operands(int, char **, boolean_t);
static int do_list(int, char **);
static int do_disable(int, char **);
static int do_enable(int, char **);
static int do_install(int, char **);
static int do_uninstall(int, char **);
static int do_unload(int, char **);
static int do_refresh(int);
static int do_start(int);
static int do_stop(int);
static int list_simple_for_all(boolean_t);
static int list_mechlist_for_all(boolean_t);
static int list_policy_for_all(void);
int
main(int argc, char *argv[])
{
char *subcmd;
int cmdnum;
int cmd_index = 0;
int rc = SUCCESS;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
#endif
(void) textdomain(TEXT_DOMAIN);
cryptodebug_init(basename(argv[0]));
if (argc < REQ_ARG_CNT) {
usage();
return (ERROR_USAGE);
}
/* get the subcommand index */
cmd_index = 0;
subcmd = argv[1];
cmdnum = sizeof (cmd_table)/sizeof (cmd_table[0]);
while ((cmd_index < cmdnum) &&
(strcmp(subcmd, cmd_table[cmd_index]) != 0)) {
cmd_index++;
}
if (cmd_index >= cmdnum) {
usage();
return (ERROR_USAGE);
}
/* do the subcommand */
switch (cmd_index) {
case CRYPTO_LIST:
rc = do_list(argc, argv);
break;
case CRYPTO_DISABLE:
rc = do_disable(argc, argv);
break;
case CRYPTO_ENABLE:
rc = do_enable(argc, argv);
break;
case CRYPTO_INSTALL:
rc = do_install(argc, argv);
break;
case CRYPTO_UNINSTALL:
rc = do_uninstall(argc, argv);
break;
case CRYPTO_UNLOAD:
rc = do_unload(argc, argv);
break;
case CRYPTO_REFRESH:
rc = do_refresh(argc);
break;
case CRYPTO_START:
rc = do_start(argc);
break;
case CRYPTO_STOP:
rc = do_stop(argc);
break;
case CRYPTO_HELP:
usage();
rc = SUCCESS;
break;
default: /* should not come here */
usage();
rc = ERROR_USAGE;
break;
}
return (rc);
}
static void
usage(void)
{
/*
* TRANSLATION_NOTE
* Command usage is not to be translated. Only the word "Usage:"
* along with localized expressions indicating what kind of value
* is expected for arguments.
*/
(void) fprintf(stderr, gettext("Usage:\n"));
(void) fprintf(stderr,
" cryptoadm list [-mpv] [provider=<%s> | metaslot]"
" [mechanism=<%s>]\n",
gettext("provider-name"), gettext("mechanism-list"));
(void) fprintf(stderr,
" cryptoadm disable provider=<%s>"
" mechanism=<%s> | random | all\n",
gettext("provider-name"), gettext("mechanism-list"));
(void) fprintf(stderr,
" cryptoadm disable metaslot"
" [auto-key-migrate] [mechanism=<%s>]\n",
gettext("mechanism-list"));
(void) fprintf(stderr,
" cryptoadm enable provider=<%s>"
" mechanism=<%s> | random | all\n",
gettext("provider-name"), gettext("mechanism-list"));
(void) fprintf(stderr,
" cryptoadm enable metaslot [mechanism=<%s>]"
" [[token=<%s>] [slot=<%s>]"
" | [default-keystore]] | [auto-key-migrate]\n",
gettext("mechanism-list"), gettext("token-label"),
gettext("slot-description"));
(void) fprintf(stderr,
" cryptoadm install provider=<%s>\n",
gettext("provider-name"));
(void) fprintf(stderr,
" cryptoadm install provider=<%s> [mechanism=<%s>]\n",
gettext("provider-name"), gettext("mechanism-list"));
(void) fprintf(stderr,
" cryptoadm uninstall provider=<%s>\n",
gettext("provider-name"));
(void) fprintf(stderr,
" cryptoadm unload provider=<%s>\n",
gettext("provider-name"));
(void) fprintf(stderr,
" cryptoadm refresh\n"
" cryptoadm start\n"
" cryptoadm stop\n"
" cryptoadm --help\n");
}
/*
* Get the provider type. This function returns
* - PROV_UEF_LIB if provname contains an absolute path name
* - PROV_KEF_SOFT if provname is a base name only (e.g., "aes").
* - PROV_KEF_HARD if provname contains one slash only and the slash is not
* the 1st character (e.g., "mca/0").
* - PROV_BADNAME otherwise.
*/
static int
get_provider_type(char *provname)
{
char *pslash1;
char *pslash2;
if (provname == NULL) {
return (FAILURE);
}
if (provname[0] == '/') {
return (PROV_UEF_LIB);
} else if ((pslash1 = strchr(provname, SEP_SLASH)) == NULL) {
/* no slash */
return (PROV_KEF_SOFT);
} else {
pslash2 = strrchr(provname, SEP_SLASH);
if (pslash1 == pslash2) {
return (PROV_KEF_HARD);
} else {
return (PROV_BADNAME);
}
}
}
/*
* Get the provider structure. This function returns NULL if no valid
* provider= is found in argv[], otherwise a cryptoadm_provider_t is returned.
* If provider= is found but has no argument, then a cryptoadm_provider_t
* with cp_type = PROV_BADNAME is returned.
*/
static cryptoadm_provider_t *
get_provider(int argc, char **argv)
{
int c = 0;
boolean_t found = B_FALSE;
cryptoadm_provider_t *provider = NULL;
char *provstr = NULL, *savstr;
boolean_t is_metaslot = B_FALSE;
while (!found && ++c < argc) {
if (strncmp(argv[c], METASLOT_KEYWORD,
strlen(METASLOT_KEYWORD)) == 0) {
is_metaslot = B_TRUE;
found = B_TRUE;
} else if (strncmp(argv[c], KN_PROVIDER,
strlen(KN_PROVIDER)) == 0 &&
strlen(argv[c]) > strlen(KN_PROVIDER)) {
if ((provstr = strdup(argv[c])) == NULL) {
int err = errno;
/*
* TRANSLATION_NOTE
* "get_provider" is a function name and should
* not be translated.
*/
cryptoerror(LOG_STDERR, "get_provider: %s.",
strerror(err));
return (NULL);
}
found = B_TRUE;
}
}
if (!found)
return (NULL);
provider = malloc(sizeof (cryptoadm_provider_t));
if (provider == NULL) {
cryptoerror(LOG_STDERR, gettext("out of memory."));
if (provstr) {
free(provstr);
}
return (NULL);
}
if (is_metaslot) {
(void) strlcpy(provider->cp_name, METASLOT_KEYWORD,
strlen(METASLOT_KEYWORD));
provider->cp_type = METASLOT;
} else {
savstr = provstr;
(void) strtok(provstr, "=");
provstr = strtok(NULL, "=");
if (provstr == NULL) {
cryptoerror(LOG_STDERR, gettext("bad provider name."));
provider->cp_type = PROV_BADNAME;
free(savstr);
return (provider);
}
(void) strlcpy(provider->cp_name, provstr,
sizeof (provider->cp_name));
provider->cp_type = get_provider_type(provider->cp_name);
free(savstr);
}
return (provider);
}
/*
* Process the "feature" operands.
*
* "argc" and "argv" contain values specified on the command line.
* All other arguments are used for returning parsing results.
* If any of these arguments are NULL, that keyword is not expected,
* and FAILURE will be returned.
*/
static int
process_metaslot_operands(int argc, char **argv, char **meta_ks_token,
char **meta_ks_slot, boolean_t *use_default,
boolean_t *auto_key_migrate_flag)
{
int c = 2;
int rc = SUCCESS;
while (++c < argc) {
if ((strncmp(argv[c], KN_MECH, strlen(KN_MECH)) == 0) &&
strlen(argv[c]) > strlen(KN_MECH)) {
/* process mechanism operands */
if ((rc = process_mech_operands(argc, argv, B_TRUE))
!= SUCCESS) {
goto finish;
}
} else if ((strncmp(argv[c], KN_TOKEN,
strlen(KN_TOKEN)) == 0) &&
strlen(argv[c]) > strlen(KN_TOKEN)) {
if ((meta_ks_token) && (strtok(argv[c], "=") != NULL)) {
char *tmp;
if ((tmp = strtok(NULL, "=")) != NULL) {
*meta_ks_token = strdup(tmp);
} else {
return (FAILURE);
}
} else {
return (FAILURE);
}
} else if ((strncmp(argv[c], KN_SLOT,
strlen(KN_SLOT)) == 0) &&
strlen(argv[c]) > strlen(KN_SLOT)) {
if ((meta_ks_slot) && (strtok(argv[c], "=") != NULL)) {
char *tmp;
if ((tmp = strtok(NULL, "=")) != NULL) {
*meta_ks_slot = strdup(tmp);
} else {
return (FAILURE);
}
} else {
return (FAILURE);
}
} else if (strncmp(argv[c], KN_DEFAULT_KS,
strlen(KN_DEFAULT_KS)) == 0) {
if (use_default) {
*use_default = B_TRUE;
} else {
return (FAILURE);
}
} else if (strncmp(argv[c], KN_AUTO_KEY_MIGRATE,
strlen(KN_AUTO_KEY_MIGRATE)) == 0) {
if (auto_key_migrate_flag) {
*auto_key_migrate_flag = B_TRUE;
} else {
return (FAILURE);
}
} else {
return (FAILURE);
}
}
finish:
return (rc);
}
/*
* Process the "feature" operands.
*/
static int
process_feature_operands(int argc, char **argv)
{
int c = 2;
while (++c < argc) {
if (strcmp(argv[c], KN_ALL) == 0) {
allflag = B_TRUE;
rndflag = B_TRUE; /* all includes random also. */
} else if (strcmp(argv[c], RANDOM) == 0) {
rndflag = B_TRUE;
}
}
return (SUCCESS);
}
/*
* Process the mechanism operands for the disable, enable and install
* subcommands. This function sets the static variable allflag to be B_TRUE
* if the keyword "all" is specified, otherwise builds a link list of the
* mechanism operands and save it in the static variable mecharglist.
*
* This function returns
* ERROR_USAGE: mechanism operand is missing.
* FAILURE: out of memory.
* SUCCESS: otherwise.
*/
static int
process_mech_operands(int argc, char **argv, boolean_t quiet)
{
mechlist_t *pmech;
mechlist_t *pcur = NULL;
mechlist_t *phead = NULL;
boolean_t found = B_FALSE;
char *mechliststr = NULL;
char *curmech = NULL;
int c = -1;
int rc = SUCCESS;
while (!found && ++c < argc) {
if ((strncmp(argv[c], KN_MECH, strlen(KN_MECH)) == 0) &&
strlen(argv[c]) > strlen(KN_MECH)) {
found = B_TRUE;
}
}
if (!found) {
if (!quiet)
/*
* TRANSLATION_NOTE
* "mechanism" could be either a literal keyword
* and hence not to be translated, or a descriptive
* word and translatable. A choice was made to
* view it as a literal keyword.
*/
cryptoerror(LOG_STDERR,
gettext("the %s operand is missing.\n"),
"mechanism");
return (ERROR_USAGE);
}
(void) strtok(argv[c], "=");
mechliststr = strtok(NULL, "=");
if (strcmp(mechliststr, "all") == 0) {
allflag = B_TRUE;
mecharglist = NULL;
return (SUCCESS);
}
curmech = strtok(mechliststr, ",");
do {
if ((pmech = create_mech(curmech)) == NULL) {
rc = FAILURE;
break;
} else {
if (phead == NULL) {
phead = pcur = pmech;
} else {
pcur->next = pmech;
pcur = pmech;
}
}
} while ((curmech = strtok(NULL, ",")) != NULL);
if (rc == FAILURE) {
cryptoerror(LOG_STDERR, gettext("out of memory."));
free_mechlist(phead);
} else {
mecharglist = phead;
rc = SUCCESS;
}
return (rc);
}
/*
* The top level function for the "cryptoadm list" subcommand and options.
*/
static int
do_list(int argc, char **argv)
{
boolean_t mflag = B_FALSE;
boolean_t pflag = B_FALSE;
boolean_t vflag = B_FALSE;
char ch;
cryptoadm_provider_t *prov = NULL;
int rc = SUCCESS;
argc -= 1;
argv += 1;
if (argc == 1) {
rc = list_simple_for_all(B_FALSE);
goto out;
}
/*
* cryptoadm list [-v] [-m] [-p] [provider=<>] [mechanism=<>]
*/
if (argc > 5) {
usage();
return (rc);
}
while ((ch = getopt(argc, argv, "mpv")) != EOF) {
switch (ch) {
case 'm':
mflag = B_TRUE;
if (pflag) {
rc = ERROR_USAGE;
}
break;
case 'p':
pflag = B_TRUE;
if (mflag || vflag) {
rc = ERROR_USAGE;
}
break;
case 'v':
vflag = B_TRUE;
if (pflag)
rc = ERROR_USAGE;
break;
default:
rc = ERROR_USAGE;
break;
}
}
if (rc == ERROR_USAGE) {
usage();
return (rc);
}
if ((rc = process_feature_operands(argc, argv)) != SUCCESS) {
goto out;
}
prov = get_provider(argc, argv);
if (mflag || vflag) {
if (argc > 0) {
rc = process_mech_operands(argc, argv, B_TRUE);
if (rc == FAILURE)
goto out;
/* "-m" is implied when a mechanism list is given */
if (mecharglist != NULL || allflag)
mflag = B_TRUE;
}
}
if (prov == NULL) {
if (mflag) {
rc = list_mechlist_for_all(vflag);
} else if (pflag) {
rc = list_policy_for_all();
} else if (vflag) {
rc = list_simple_for_all(vflag);
}
} else if (prov->cp_type == METASLOT) {
if ((!mflag) && (!vflag) && (!pflag)) {
/* no flag is specified, just list metaslot status */
rc = list_metaslot_info(mflag, vflag, mecharglist);
} else if (mflag || vflag) {
rc = list_metaslot_info(mflag, vflag, mecharglist);
} else if (pflag) {
rc = list_metaslot_policy();
} else {
/* error message */
usage();
rc = ERROR_USAGE;
}
} else if (prov->cp_type == PROV_BADNAME) {
usage();
rc = ERROR_USAGE;
goto out;
} else { /* do the listing for a provider only */
char *provname = prov->cp_name;
if (mflag || vflag) {
if (vflag)
(void) printf(gettext("Provider: %s\n"),
provname);
switch (prov->cp_type) {
case PROV_UEF_LIB:
rc = list_mechlist_for_lib(provname,
mecharglist, NULL, B_FALSE, vflag, mflag);
break;
case PROV_KEF_SOFT:
rc = list_mechlist_for_soft(provname,
NULL, NULL);
break;
case PROV_KEF_HARD:
rc = list_mechlist_for_hard(provname);
break;
default: /* should not come here */
rc = FAILURE;
break;
}
} else if (pflag) {
switch (prov->cp_type) {
case PROV_UEF_LIB:
rc = list_policy_for_lib(provname);
break;
case PROV_KEF_SOFT:
if (getzoneid() == GLOBAL_ZONEID) {
rc = list_policy_for_soft(provname,
NULL, NULL);
} else {
/*
* TRANSLATION_NOTE
* "global" is keyword and not to
* be translated.
*/
cryptoerror(LOG_STDERR, gettext(
"policy information for kernel "
"providers is available "
"in the %s zone only"), "global");
rc = FAILURE;
}
break;
case PROV_KEF_HARD:
if (getzoneid() == GLOBAL_ZONEID) {
rc = list_policy_for_hard(
provname, NULL, NULL, NULL);
} else {
/*
* TRANSLATION_NOTE
* "global" is keyword and not to
* be translated.
*/
cryptoerror(LOG_STDERR, gettext(
"policy information for kernel "
"providers is available "
"in the %s zone only"), "global");
rc = FAILURE;
}
break;
default: /* should not come here */
rc = FAILURE;
break;
}
} else {
/* error message */
usage();
rc = ERROR_USAGE;
}
}
out:
if (prov != NULL)
free(prov);
if (mecharglist != NULL)
free_mechlist(mecharglist);
return (rc);
}
/*
* The top level function for the "cryptoadm disable" subcommand.
*/
static int
do_disable(int argc, char **argv)
{
cryptoadm_provider_t *prov = NULL;
int rc = SUCCESS;
boolean_t auto_key_migrate_flag = B_FALSE;
if ((argc < 3) || (argc > 5)) {
usage();
return (ERROR_USAGE);
}
prov = get_provider(argc, argv);
if (prov == NULL) {
usage();
return (ERROR_USAGE);
}
if (prov->cp_type == PROV_BADNAME) {
return (FAILURE);
}
if ((rc = process_feature_operands(argc, argv)) != SUCCESS) {
goto out;
}
/*
* If allflag or rndflag has already been set there is no reason to
* process mech=
*/
if (prov->cp_type == METASLOT) {
if ((argc > 3) &&
(rc = process_metaslot_operands(argc, argv,
NULL, NULL, NULL, &auto_key_migrate_flag)) != SUCCESS) {
usage();
return (rc);
}
} else if (!allflag && !rndflag &&
(rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) {
return (rc);
}
switch (prov->cp_type) {
case METASLOT:
rc = disable_metaslot(mecharglist, allflag,
auto_key_migrate_flag);
break;
case PROV_UEF_LIB:
rc = disable_uef_lib(prov->cp_name, rndflag, allflag,
mecharglist);
break;
case PROV_KEF_SOFT:
if (rndflag && !allflag) {
if ((mecharglist = create_mech(RANDOM)) == NULL) {
rc = FAILURE;
break;
}
}
if (getzoneid() == GLOBAL_ZONEID) {
rc = disable_kef_software(prov->cp_name, rndflag,
allflag, mecharglist);
} else {
/*
* TRANSLATION_NOTE
* "disable" could be either a literal keyword
* and hence not to be translated, or a verb and
* translatable. A choice was made to view it as
* a literal keyword. "global" is keyword and not
* to be translated.
*/
cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
"providers is supported in the %2$s zone only"),
"disable", "global");
rc = FAILURE;
}
break;
case PROV_KEF_HARD:
if (rndflag && !allflag) {
if ((mecharglist = create_mech(RANDOM)) == NULL) {
rc = FAILURE;
break;
}
}
if (getzoneid() == GLOBAL_ZONEID) {
rc = disable_kef_hardware(prov->cp_name, rndflag,
allflag, mecharglist);
} else {
/*
* TRANSLATION_NOTE
* "disable" could be either a literal keyword
* and hence not to be translated, or a verb and
* translatable. A choice was made to view it as
* a literal keyword. "global" is keyword and not
* to be translated.
*/
cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
"providers is supported in the %2$s zone only"),
"disable", "global");
rc = FAILURE;
}
break;
default: /* should not come here */
rc = FAILURE;
break;
}
out:
free(prov);
if (mecharglist != NULL) {
free_mechlist(mecharglist);
}
return (rc);
}
/*
* The top level function for the "cryptoadm enable" subcommand.
*/
static int
do_enable(int argc, char **argv)
{
cryptoadm_provider_t *prov = NULL;
int rc = SUCCESS;
char *alt_token = NULL, *alt_slot = NULL;
boolean_t use_default = B_FALSE;
boolean_t auto_key_migrate_flag = B_FALSE;
if ((argc < 3) || (argc > 6)) {
usage();
return (ERROR_USAGE);
}
prov = get_provider(argc, argv);
if (prov == NULL) {
usage();
return (ERROR_USAGE);
}
if ((prov->cp_type != METASLOT) && (argc != 4)) {
usage();
return (ERROR_USAGE);
}
if (prov->cp_type == PROV_BADNAME) {
rc = FAILURE;
goto out;
}
if (prov->cp_type == METASLOT) {
if ((rc = process_metaslot_operands(argc, argv, &alt_token,
&alt_slot, &use_default, &auto_key_migrate_flag))
!= SUCCESS) {
usage();
goto out;
}
if ((alt_slot || alt_token) && use_default) {
usage();
rc = FAILURE;
goto out;
}
} else {
if ((rc = process_feature_operands(argc, argv)) != SUCCESS) {
goto out;
}
/*
* If allflag or rndflag has already been set there is
* no reason to process mech=
*/
if (!allflag && !rndflag &&
(rc = process_mech_operands(argc, argv, B_FALSE))
!= SUCCESS) {
goto out;
}
}
switch (prov->cp_type) {
case METASLOT:
rc = enable_metaslot(alt_token, alt_slot, use_default,
mecharglist, allflag, auto_key_migrate_flag);
break;
case PROV_UEF_LIB:
rc = enable_uef_lib(prov->cp_name, rndflag, allflag,
mecharglist);
break;
case PROV_KEF_SOFT:
case PROV_KEF_HARD:
if (rndflag && !allflag) {
if ((mecharglist = create_mech(RANDOM)) == NULL) {
rc = FAILURE;
break;
}
}
if (getzoneid() == GLOBAL_ZONEID) {
rc = enable_kef(prov->cp_name, rndflag, allflag,
mecharglist);
} else {
/*
* TRANSLATION_NOTE
* "enable" could be either a literal keyword
* and hence not to be translated, or a verb and
* translatable. A choice was made to view it as
* a literal keyword. "global" is keyword and not
* to be translated.
*/
cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
"providers is supported in the %2$s zone only"),
"enable", "global");
rc = FAILURE;
}
break;
default: /* should not come here */
rc = FAILURE;
break;
}
out:
free(prov);
if (mecharglist != NULL) {
free_mechlist(mecharglist);
}
if (alt_token != NULL) {
free(alt_token);
}
if (alt_slot != NULL) {
free(alt_slot);
}
return (rc);
}
/*
* The top level function for the "cryptoadm install" subcommand.
*/
static int
do_install(int argc, char **argv)
{
cryptoadm_provider_t *prov = NULL;
int rc;
if (argc < 3) {
usage();
return (ERROR_USAGE);
}
prov = get_provider(argc, argv);
if (prov == NULL ||
prov->cp_type == PROV_BADNAME || prov->cp_type == PROV_KEF_HARD) {
/*
* TRANSLATION_NOTE
* "install" could be either a literal keyword and hence
* not to be translated, or a verb and translatable. A
* choice was made to view it as a literal keyword.
*/
cryptoerror(LOG_STDERR,
gettext("bad provider name for %s."), "install");
rc = FAILURE;
goto out;
}
if (prov->cp_type == PROV_UEF_LIB) {
rc = install_uef_lib(prov->cp_name);
goto out;
}
/* It is the PROV_KEF_SOFT type now */
/* check if there are mechanism operands */
if (argc < 4) {
/*
* TRANSLATION_NOTE
* "mechanism" could be either a literal keyword and hence
* not to be translated, or a descriptive word and
* translatable. A choice was made to view it as a literal
* keyword.
*/
cryptoerror(LOG_STDERR,
gettext("need %s operands for installing a"
" kernel software provider."), "mechanism");
rc = ERROR_USAGE;
goto out;
}
if ((rc = process_mech_operands(argc, argv, B_FALSE)) != SUCCESS) {
goto out;
}
if (allflag == B_TRUE) {
/*
* TRANSLATION_NOTE
* "all", "mechanism", and "install" are all keywords and
* not to be translated.
*/
cryptoerror(LOG_STDERR,
gettext("can not use the %1$s keyword for %2$s "
"in the %3$s subcommand."), "all", "mechanism", "install");
rc = ERROR_USAGE;
goto out;
}
if (getzoneid() == GLOBAL_ZONEID) {
rc = install_kef(prov->cp_name, mecharglist);
} else {
/*
* TRANSLATION_NOTE
* "install" could be either a literal keyword and hence
* not to be translated, or a verb and translatable. A
* choice was made to view it as a literal keyword.
* "global" is keyword and not to be translated.
*/
cryptoerror(LOG_STDERR, gettext("%1$s for kernel providers "
"is supported in the %2$s zone only"), "install", "global");
rc = FAILURE;
}
out:
free(prov);
return (rc);
}
/*
* The top level function for the "cryptoadm uninstall" subcommand.
*/
static int
do_uninstall(int argc, char **argv)
{
cryptoadm_provider_t *prov = NULL;
int rc = SUCCESS;
if (argc != 3) {
usage();
return (ERROR_USAGE);
}
prov = get_provider(argc, argv);
if (prov == NULL ||
prov->cp_type == PROV_BADNAME || prov->cp_type == PROV_KEF_HARD) {
/*
* TRANSLATION_NOTE
* "uninstall" could be either a literal keyword and hence
* not to be translated, or a verb and translatable. A
* choice was made to view it as a literal keyword.
*/
cryptoerror(LOG_STDERR,
gettext("bad provider name for %s."), "uninstall");
free(prov);
return (FAILURE);
}
if (prov->cp_type == PROV_UEF_LIB) {
rc = uninstall_uef_lib(prov->cp_name);
} else if (prov->cp_type == PROV_KEF_SOFT) {
if (getzoneid() == GLOBAL_ZONEID) {
/* unload and remove from kcf.conf */
rc = uninstall_kef(prov->cp_name);
} else {
/*
* TRANSLATION_NOTE
* "uninstall" could be either a literal keyword and
* hence not to be translated, or a verb and
* translatable. A choice was made to view it as a
* literal keyword. "global" is keyword and not to
* be translated.
*/
cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
"providers is supported in the %2$s zone only"),
"uninstall", "global");
rc = FAILURE;
}
}
free(prov);
return (rc);
}
/*
* The top level function for the "cryptoadm unload" subcommand.
*/
static int
do_unload(int argc, char **argv)
{
cryptoadm_provider_t *prov = NULL;
entry_t *pent = NULL;
boolean_t in_kernel = B_FALSE;
int rc = SUCCESS;
char *provname = NULL;
if (argc != 3) {
usage();
return (ERROR_USAGE);
}
/* check if it is a kernel software provider */
prov = get_provider(argc, argv);
if (prov == NULL) {
cryptoerror(LOG_STDERR,
gettext("unable to determine provider name."));
goto out;
}
provname = prov->cp_name;
if (prov->cp_type != PROV_KEF_SOFT) {
cryptoerror(LOG_STDERR,
gettext("%s is not a valid kernel software provider."),
provname);
rc = FAILURE;
goto out;
}
if (getzoneid() != GLOBAL_ZONEID) {
/*
* TRANSLATION_NOTE
* "unload" could be either a literal keyword and hence
* not to be translated, or a verb and translatable.
* A choice was made to view it as a literal keyword.
* "global" is keyword and not to be translated.
*/
cryptoerror(LOG_STDERR, gettext("%1$s for kernel providers "
"is supported in the %2$s zone only"), "unload", "global");
rc = FAILURE;
goto out;
}
if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
cryptodebug("internal error");
rc = FAILURE;
goto out;
} else if (in_kernel == B_FALSE) {
cryptoerror(LOG_STDERR,
gettext("provider %s is not loaded or does not exist."),
provname);
rc = FAILURE;
goto out;
}
/* Get kcf.conf entry. If none, build a new entry */
if ((pent = getent_kef(provname, NULL, NULL)) == NULL) {
if ((pent = create_entry(provname)) == NULL) {
cryptoerror(LOG_STDERR, gettext("out of memory."));
rc = FAILURE;
goto out;
}
}
/* If it is unloaded already, return */
if (!pent->load) { /* unloaded already */
cryptoerror(LOG_STDERR,
gettext("failed to unload %s."), provname);
rc = FAILURE;
goto out;
} else if (unload_kef_soft(provname) != FAILURE) {
/* Mark as unloaded in kcf.conf */
pent->load = B_FALSE;
rc = update_kcfconf(pent, MODIFY_MODE);
} else {
cryptoerror(LOG_STDERR,
gettext("failed to unload %s."), provname);
rc = FAILURE;
}
out:
free(prov);
free_entry(pent);
return (rc);
}
/*
* The top level function for the "cryptoadm refresh" subcommand.
*/
static int
do_refresh(int argc)
{
if (argc != 2) {
usage();
return (ERROR_USAGE);
}
if (getzoneid() == GLOBAL_ZONEID) {
return (refresh());
} else { /* non-global zone */
/*
* Note: in non-global zone, this must silently return SUCCESS
* due to integration with SMF, for "svcadm refresh cryptosvc"
*/
return (SUCCESS);
}
}
/*
* The top level function for the "cryptoadm start" subcommand.
* This used to start up kcfd, but now all it does is load up the
* initial providers.
*/
static int
do_start(int argc)
{
if (argc != 2) {
usage();
return (ERROR_USAGE);
}
return (do_refresh(argc));
}
/*
* The top level function for the "cryptoadm stop" subcommand.
* This no longer does anything useful, but we leave it here
* for compatibility.
*/
static int
do_stop(int argc)
{
if (argc != 2) {
usage();
return (ERROR_USAGE);
}
return (SUCCESS);
}
/*
* Print a list all the the providers.
* Called for "cryptoadm list" or "cryptoadm list -v" (no -m or -p).
*/
static int
list_simple_for_all(boolean_t verbose)
{
uentrylist_t *pliblist = NULL;
uentrylist_t *plibptr = NULL;
entry_t *pent = NULL;
crypto_get_dev_list_t *pdevlist_kernel = NULL;
int rc = SUCCESS;
int i;
/* get user-level providers */
(void) printf(gettext("\nUser-level providers:\n"));
if (get_pkcs11conf_info(&pliblist) != SUCCESS) {
cryptoerror(LOG_STDERR, gettext(
"failed to retrieve the list of user-level providers."));
rc = FAILURE;
}
for (plibptr = pliblist; plibptr != NULL; plibptr = plibptr->next) {
/* skip metaslot and fips-140 entry */
if ((strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) &&
(strcmp(plibptr->puent->name, FIPS_KEYWORD) != 0)) {
(void) printf(gettext("Provider: %s\n"),
plibptr->puent->name);
if (verbose) {
(void) list_mechlist_for_lib(
plibptr->puent->name, mecharglist, NULL,
B_FALSE, verbose, B_FALSE);
(void) printf("\n");
}
}
}
free_uentrylist(pliblist);
/* get kernel software providers */
(void) printf(gettext("\nKernel software providers:\n"));
if (getzoneid() == GLOBAL_ZONEID) {
/* get kernel software providers from kernel ioctl */
crypto_get_soft_list_t *psoftlist_kernel = NULL;
uint_t sl_soft_count;
char *psoftname;
entrylist_t *pdevlist_conf = NULL;
entrylist_t *psoftlist_conf = NULL;
if (get_soft_list(&psoftlist_kernel) == FAILURE) {
cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
"software provider list from kernel."));
rc = FAILURE;
} else {
sl_soft_count = psoftlist_kernel->sl_soft_count;
if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf)
== FAILURE) {
cryptoerror(LOG_ERR,
"failed to retrieve the providers' "
"information from file kcf.conf - %s.",
_PATH_KCF_CONF);
free(psoftlist_kernel);
rc = FAILURE;
} else {
for (i = 0,
psoftname = psoftlist_kernel->sl_soft_names;
i < sl_soft_count;
++i, psoftname += strlen(psoftname) + 1) {
pent = getent_kef(psoftname,
pdevlist_conf, psoftlist_conf);
(void) printf("\t%s%s\n", psoftname,
(pent == NULL) || (pent->load) ?
"" : gettext(" (inactive)"));
}
free_entrylist(pdevlist_conf);
free_entrylist(psoftlist_conf);
}
free(psoftlist_kernel);
}
} else {
/* kcf.conf not there in non-global zone, use /dev/cryptoadm */
entrylist_t *pdevlist_zone = NULL;
entrylist_t *psoftlist_zone = NULL;
entrylist_t *ptr;
if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) !=
SUCCESS) {
cryptoerror(LOG_STDERR,
gettext("failed to retrieve the "
"list of kernel software providers.\n"));
rc = FAILURE;
}
ptr = psoftlist_zone;
while (ptr != NULL) {
(void) printf("\t%s\n", ptr->pent->name);
ptr = ptr->next;
}
free_entrylist(pdevlist_zone);
free_entrylist(psoftlist_zone);
}
/* get kernel hardware providers */
(void) printf(gettext("\nKernel hardware providers:\n"));
if (get_dev_list(&pdevlist_kernel) == FAILURE) {
cryptoerror(LOG_STDERR, gettext("failed to retrieve "
"the list of kernel hardware providers.\n"));
rc = FAILURE;
} else {
for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
(void) printf("\t%s/%d\n",
pdevlist_kernel->dl_devs[i].le_dev_name,
pdevlist_kernel->dl_devs[i].le_dev_instance);
}
}
free(pdevlist_kernel);
return (rc);
}
/*
* List all the providers. And for each provider, list the mechanism list.
* Called for "cryptoadm list -m" or "cryptoadm list -mv" .
*/
static int
list_mechlist_for_all(boolean_t verbose)
{
crypto_get_dev_list_t *pdevlist_kernel = NULL;
uentrylist_t *pliblist = NULL;
uentrylist_t *plibptr = NULL;
entry_t *pent = NULL;
mechlist_t *pmechlist = NULL;
char provname[MAXNAMELEN];
char devname[MAXNAMELEN];
int inst_num;
int count;
int i;
int rv;
int rc = SUCCESS;
/* get user-level providers */
(void) printf(gettext("\nUser-level providers:\n"));
/*
* TRANSLATION_NOTE
* Strictly for appearance's sake, this line should be as long as
* the length of the translated text above.
*/
(void) printf(gettext("=====================\n"));
if (get_pkcs11conf_info(&pliblist) != SUCCESS) {
cryptoerror(LOG_STDERR, gettext("failed to retrieve "
"the list of user-level providers.\n"));
rc = FAILURE;
}
plibptr = pliblist;
while (plibptr != NULL) {
/* skip metaslot and fips-140 entry */
if ((strcmp(plibptr->puent->name, METASLOT_KEYWORD) != 0) &&
(strcmp(plibptr->puent->name, FIPS_KEYWORD) != 0)) {
(void) printf(gettext("\nProvider: %s\n"),
plibptr->puent->name);
rv = list_mechlist_for_lib(plibptr->puent->name,
mecharglist, NULL, B_FALSE, verbose, B_TRUE);
if (rv == FAILURE) {
rc = FAILURE;
}
}
plibptr = plibptr->next;
}
free_uentrylist(pliblist);
/* get kernel software providers */
(void) printf(gettext("\nKernel software providers:\n"));
/*
* TRANSLATION_NOTE
* Strictly for appearance's sake, this line should be as long as
* the length of the translated text above.
*/
(void) printf(gettext("==========================\n"));
if (getzoneid() == GLOBAL_ZONEID) {
/* get kernel software providers from kernel ioctl */
crypto_get_soft_list_t *psoftlist_kernel = NULL;
uint_t sl_soft_count;
char *psoftname;
int i;
entrylist_t *pdevlist_conf = NULL;
entrylist_t *psoftlist_conf = NULL;
if (get_soft_list(&psoftlist_kernel) == FAILURE) {
cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
"software provider list from kernel."));
return (FAILURE);
}
sl_soft_count = psoftlist_kernel->sl_soft_count;
if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf)
== FAILURE) {
cryptoerror(LOG_ERR,
"failed to retrieve the providers' "
"information from file kcf.conf - %s.",
_PATH_KCF_CONF);
free(psoftlist_kernel);
return (FAILURE);
}
for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
i < sl_soft_count;
++i, psoftname += strlen(psoftname) + 1) {
pent = getent_kef(psoftname, pdevlist_conf,
psoftlist_conf);
if ((pent == NULL) || (pent->load)) {
rv = list_mechlist_for_soft(psoftname,
NULL, NULL);
if (rv == FAILURE) {
rc = FAILURE;
}
} else {
(void) printf(gettext("%s: (inactive)\n"),
psoftname);
}
}
free(psoftlist_kernel);
free_entrylist(pdevlist_conf);
free_entrylist(psoftlist_conf);
} else {
/* kcf.conf not there in non-global zone, use /dev/cryptoadm */
entrylist_t *pdevlist_zone = NULL;
entrylist_t *psoftlist_zone = NULL;
entrylist_t *ptr;
if (get_admindev_info(&pdevlist_zone, &psoftlist_zone) !=
SUCCESS) {
cryptoerror(LOG_STDERR, gettext("failed to retrieve "
"the list of kernel software providers.\n"));
rc = FAILURE;
}
for (ptr = psoftlist_zone; ptr != NULL; ptr = ptr->next) {
rv = list_mechlist_for_soft(ptr->pent->name,
pdevlist_zone, psoftlist_zone);
if (rv == FAILURE) {
(void) printf(gettext(
"%s: failed to get the mechanism list.\n"),
ptr->pent->name);
rc = FAILURE;
}
}
free_entrylist(pdevlist_zone);
free_entrylist(psoftlist_zone);
}
/* Get kernel hardware providers and their mechanism lists */
(void) printf(gettext("\nKernel hardware providers:\n"));
/*
* TRANSLATION_NOTE
* Strictly for appearance's sake, this line should be as long as
* the length of the translated text above.
*/
(void) printf(gettext("==========================\n"));
if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
cryptoerror(LOG_STDERR, gettext("failed to retrieve "
"the list of hardware providers.\n"));
return (FAILURE);
}
for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
(void) strlcpy(devname,
pdevlist_kernel->dl_devs[i].le_dev_name, MAXNAMELEN);
inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance;
count = pdevlist_kernel->dl_devs[i].le_mechanism_count;
(void) snprintf(provname, sizeof (provname), "%s/%d", devname,
inst_num);
if (get_dev_info(devname, inst_num, count, &pmechlist) ==
SUCCESS) {
(void) filter_mechlist(&pmechlist, RANDOM);
print_mechlist(provname, pmechlist);
free_mechlist(pmechlist);
} else {
(void) printf(gettext("%s: failed to get the mechanism"
" list.\n"), provname);
rc = FAILURE;
}
}
free(pdevlist_kernel);
return (rc);
}
/*
* List all the providers. And for each provider, list the policy information.
* Called for "cryptoadm list -p".
*/
static int
list_policy_for_all(void)
{
crypto_get_dev_list_t *pdevlist_kernel = NULL;
uentrylist_t *pliblist = NULL;
entrylist_t *pdevlist_conf = NULL;
entrylist_t *psoftlist_conf = NULL;
entrylist_t *ptr = NULL;
entrylist_t *phead = NULL;
boolean_t found = B_FALSE;
char provname[MAXNAMELEN];
int i;
int rc = SUCCESS;
/* Get user-level providers */
(void) printf(gettext("\nUser-level providers:\n"));
/*
* TRANSLATION_NOTE
* Strictly for appearance's sake, this line should be as long as
* the length of the translated text above.
*/
(void) printf(gettext("=====================\n"));
if (get_pkcs11conf_info(&pliblist) == FAILURE) {
cryptoerror(LOG_STDERR, gettext("failed to retrieve "
"the list of user-level providers.\n"));
rc = FAILURE;
} else {
uentrylist_t *plibptr = pliblist;
while (plibptr != NULL) {
/* skip metaslot and fips-140 entry */
if ((strcmp(plibptr->puent->name,
METASLOT_KEYWORD) != 0) &&
(strcmp(plibptr->puent->name,
FIPS_KEYWORD) != 0)) {
if (print_uef_policy(plibptr->puent)
== FAILURE) {
rc = FAILURE;
}
}
plibptr = plibptr->next;
}
free_uentrylist(pliblist);
}
/* kernel software providers */
(void) printf(gettext("\nKernel software providers:\n"));
/*
* TRANSLATION_NOTE
* Strictly for appearance's sake, this line should be as long as
* the length of the translated text above.
*/
(void) printf(gettext("==========================\n"));
/* Get all entries from the kernel */
if (getzoneid() == GLOBAL_ZONEID) {
/* get kernel software providers from kernel ioctl */
crypto_get_soft_list_t *psoftlist_kernel = NULL;
uint_t sl_soft_count;
char *psoftname;
int i;
if (get_soft_list(&psoftlist_kernel) == FAILURE) {
cryptoerror(LOG_ERR, gettext("Failed to retrieve the "
"software provider list from kernel."));
rc = FAILURE;
} else {
sl_soft_count = psoftlist_kernel->sl_soft_count;
for (i = 0, psoftname = psoftlist_kernel->sl_soft_names;
i < sl_soft_count;
++i, psoftname += strlen(psoftname) + 1) {
(void) list_policy_for_soft(psoftname,
pdevlist_conf, psoftlist_conf);
}
free(psoftlist_kernel);
}
} else {
/* kcf.conf not there in non-global zone, no policy info */
/*
* TRANSLATION_NOTE
* "global" is keyword and not to be translated.
*/
cryptoerror(LOG_STDERR, gettext(
"policy information for kernel software providers is "
"available in the %s zone only"), "global");
}
/* Kernel hardware providers */
(void) printf(gettext("\nKernel hardware providers:\n"));
/*
* TRANSLATION_NOTE
* Strictly for appearance's sake, this line should be as long as
* the length of the translated text above.
*/
(void) printf(gettext("==========================\n"));
if (getzoneid() != GLOBAL_ZONEID) {
/*
* TRANSLATION_NOTE
* "global" is keyword and not to be translated.
*/
cryptoerror(LOG_STDERR, gettext(
"policy information for kernel hardware providers is "
"available in the %s zone only"), "global");
return (FAILURE);
}
/* Get the hardware provider list from kernel */
if (get_dev_list(&pdevlist_kernel) != SUCCESS) {
cryptoerror(LOG_STDERR, gettext(
"failed to retrieve the list of hardware providers.\n"));
return (FAILURE);
}
if (get_kcfconf_info(&pdevlist_conf, &psoftlist_conf) == FAILURE) {
cryptoerror(LOG_ERR, "failed to retrieve the providers' "
"information from file kcf.conf - %s.",
_PATH_KCF_CONF);
return (FAILURE);
}
/*
* For each hardware provider from kernel, check if it has an entry
* in the config file. If it has an entry, print out the policy from
* config file and remove the entry from the hardware provider list
* of the config file. If it does not have an entry in the config
* file, no mechanisms of it have been disabled. But, we still call
* list_policy_for_hard() to account for the "random" feature.
*/
for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) {
(void) snprintf(provname, sizeof (provname), "%s/%d",
pdevlist_kernel->dl_devs[i].le_dev_name,
pdevlist_kernel->dl_devs[i].le_dev_instance);
found = B_FALSE;
phead = ptr = pdevlist_conf;
while (!found && ptr) {
if (strcmp(ptr->pent->name, provname) == 0) {
found = B_TRUE;
} else {
phead = ptr;
ptr = ptr->next;
}
}
if (found) {
(void) list_policy_for_hard(ptr->pent->name,
pdevlist_conf, psoftlist_conf, pdevlist_kernel);
if (phead == ptr) {
pdevlist_conf = pdevlist_conf->next;
} else {
phead->next = ptr->next;
}
free_entry(ptr->pent);
free(ptr);
} else {
(void) list_policy_for_hard(provname, pdevlist_conf,
psoftlist_conf, pdevlist_kernel);
}
}
/*
* If there are still entries left in the pdevlist_conf list from
* the config file, these providers must have been detached.
* Should print out their policy information also.
*/
for (ptr = pdevlist_conf; ptr != NULL; ptr = ptr->next) {
print_kef_policy(ptr->pent->name, ptr->pent, B_FALSE, B_TRUE);
}
free_entrylist(pdevlist_conf);
free_entrylist(psoftlist_conf);
free(pdevlist_kernel);
return (rc);
}