/* * 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. */ /* * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #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; int 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); 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); }