/* * Display the mechanism list for a kernel hardware provider. * This implements part of the "cryptoadm list -m" command. */ int list_mechlist_for_hard(char *provname) { mechlist_t *pmechlist = NULL; char devname[MAXNAMELEN]; int inst_num; int count; int rc = SUCCESS; if (provname == NULL) { return (FAILURE); } /* * Check if the provider is valid. If it is valid, get the number of * mechanisms also. */ if (check_hardware_provider(provname, devname, &inst_num, &count) == FAILURE) { return (FAILURE); } /* Get the mechanism list for the kernel hardware provider */ if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) == SUCCESS) { (void) filter_mechlist(&pmechlist, RANDOM); print_mechlist(provname, pmechlist); free_mechlist(pmechlist); } return (rc); }
/* * Display the policy information for a kernel software provider. * This implements part of the "cryptoadm list -p" command. * * Parameters phardlist and psoftlist are supplied by * getent_kef(). * If NULL, this function obtains it by calling get_kcfconf_info() * via getent_kef() internally. */ int list_policy_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist) { int rc; entry_t *pent = NULL; mechlist_t *pmechlist = NULL; boolean_t has_random = B_FALSE; boolean_t has_mechs = B_FALSE; boolean_t in_kernel = B_FALSE; if (provname == NULL) { return (FAILURE); } if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { return (FAILURE); } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); return (FAILURE); } pent = getent_kef(provname, phardlist, psoftlist); rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist); if (rc == SUCCESS) { has_random = filter_mechlist(&pmechlist, RANDOM); if (pmechlist != NULL) { has_mechs = B_TRUE; free_mechlist(pmechlist); } } else { cryptoerror(LOG_STDERR, gettext( "failed to retrieve the mechanism list for %s."), provname); return (rc); } print_kef_policy(provname, pent, has_random, has_mechs); free_entry(pent); return (SUCCESS); }
/* * Display the mechanism list for a kernel software provider. * This implements part of the "cryptoadm list -m" command. * * Parameters phardlist and psoftlist are supplied by * get_soft_info(). * If NULL, this function obtains it by calling getent_kef() and * then get_kcfconf_info() via get_soft_info() internally. */ int list_mechlist_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist) { mechlist_t *pmechlist = NULL; int rc; if (provname == NULL) { return (FAILURE); } rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist); if (rc == SUCCESS) { (void) filter_mechlist(&pmechlist, RANDOM); print_mechlist(provname, pmechlist); free_mechlist(pmechlist); } else { cryptoerror(LOG_STDERR, gettext( "failed to retrieve the mechanism list for %s."), provname); } return (rc); }
/* * Get the supported mechanism list of the software provider from kernel. */ int get_soft_info(char *provname, mechlist_t **ppmechlist) { crypto_get_soft_info_t *psoft_info; mechlist_t *phead; mechlist_t *pmech; mechlist_t *pcur; entry_t *pent; int count; int fd; int rc; int i; if (provname == NULL) { return (FAILURE); } if (getzoneid() == GLOBAL_ZONEID) { /* use kcf.conf for kernel software providers in global zone */ if ((pent = getent_kef(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); return (FAILURE); } count = pent->sup_count; free_entry(pent); } else { /* * kcf.conf not there in non-global zone, set mech count to 1; * it will be reset to the correct value later if the setup * buffer is too small */ count = 1; } if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) { return (FAILURE); } if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free(psoft_info); return (FAILURE); } /* make GET_SOFT_INFO ioctl call */ if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) { cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s", strerror(errno)); (void) close(fd); free(psoft_info); return (FAILURE); } /* BUFFER is too small, get the number of mechanisms and retry it. */ if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) { count = psoft_info->si_count; free(psoft_info); if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) { (void) close(fd); return (FAILURE); } else { rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info); if (rc == -1) { cryptodebug("CRYPTO_GET_SOFT_INFO ioctl " "failed: %s", strerror(errno)); (void) close(fd); free(psoft_info); return (FAILURE); } } } (void) close(fd); if (psoft_info->si_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, " "return_value = %d", psoft_info->si_return_value); free(psoft_info); return (FAILURE); } /* Get the mechanism list and return it */ rc = SUCCESS; phead = pcur = NULL; for (i = 0; i < psoft_info->si_count; i++) { pmech = create_mech(&psoft_info->si_list[i][0]); if (pmech == NULL) { rc = FAILURE; break; } else { if (phead == NULL) { phead = pcur = pmech; } else { pcur->next = pmech; pcur = pmech; } } } if (rc == FAILURE) { free_mechlist(phead); } else { *ppmechlist = phead; } free(psoft_info); return (rc); }
/* * Get all the mechanisms supported by the hardware provider. * The result will be stored in the second argument. */ int get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist) { crypto_get_dev_info_t *dev_info; mechlist_t *phead; mechlist_t *pcur; mechlist_t *pmech; int fd; int i; int rc; if (devname == NULL || count < 1) { cryptodebug("get_dev_info(): devname is NULL or bogus count"); return (FAILURE); } /* Set up the argument for the CRYPTO_GET_DEV_INFO ioctl call */ dev_info = malloc(sizeof (crypto_get_dev_info_t) + sizeof (crypto_mech_name_t) * (count - 1)); if (dev_info == NULL) { cryptodebug("out of memory."); return (FAILURE); } (void) strlcpy(dev_info->di_dev_name, devname, MAXNAMELEN); dev_info->di_dev_instance = inst_num; dev_info->di_count = count; /* Open the ioctl device */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free(dev_info); return (FAILURE); } if (ioctl(fd, CRYPTO_GET_DEV_INFO, dev_info) == -1) { cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed: %s", strerror(errno)); free(dev_info); (void) close(fd); return (FAILURE); } if (dev_info->di_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed, " "return_value = %d", dev_info->di_return_value); free(dev_info); (void) close(fd); return (FAILURE); } phead = pcur = NULL; rc = SUCCESS; for (i = 0; i < dev_info->di_count; i++) { pmech = create_mech(&dev_info->di_list[i][0]); if (pmech == NULL) { rc = FAILURE; break; } else { if (phead == NULL) { phead = pcur = pmech; } else { pcur->next = pmech; pcur = pmech; } } } if (rc == SUCCESS) { *ppmechlist = phead; } else { free_mechlist(phead); } free(dev_info); (void) close(fd); 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) && (strncmp(argv[2], FIPS_KEYWORD, strlen(FIPS_KEYWORD))) == 0) { /* * cryptoadm enable fips-140 */ rc = do_fips_actions(FIPS140_ENABLE, NOT_REFRESH); return (rc); } 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 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; if ((argc == 3) && (strncmp(argv[2], FIPS_KEYWORD, strlen(FIPS_KEYWORD))) == 0) { /* * cryptoadm list fips-140 */ rc = do_fips_actions(FIPS140_STATUS, NOT_REFRESH); return (rc); } 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); }
/* * 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); }
/* * 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); }
/* * Uninstall the software module. This routine first unloads the software * module with 3 ioctl calls, then deletes its entry from the config file. * Removing an entry from the config file needs to be done last to ensure * that there is still an entry if the earlier unload failed for any reason. */ int uninstall_kef(char *provname) { entry_t *pent = NULL; int rc = SUCCESS; boolean_t in_kernel = B_FALSE; boolean_t in_kcfconf = B_FALSE; int fd = -1; crypto_load_soft_config_t *pload_soft_conf = NULL; /* Check to see if the provider exists first. */ if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { return (FAILURE); } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); return (FAILURE); } /* * If it is loaded, unload it first. This does 2 ioctl calls: * CRYPTO_UNLOAD_SOFT_MODULE and CRYPTO_LOAD_SOFT_DISABLED. */ if (unload_kef_soft(provname) == FAILURE) { cryptoerror(LOG_STDERR, gettext("failed to unload %s during uninstall.\n"), provname); return (FAILURE); } /* * Inform kernel to remove the configuration of this software module. */ /* Setup ioctl() parameter */ pent = getent_kef(provname, NULL, NULL); if (pent != NULL) { /* in kcf.conf */ in_kcfconf = B_TRUE; free_mechlist(pent->suplist); pent->suplist = NULL; pent->sup_count = 0; } else if ((pent = create_entry(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (FAILURE); } if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { free_entry(pent); return (FAILURE); } /* Open the /dev/cryptoadm device */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { int err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(err)); free_entry(pent); free(pload_soft_conf); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", strerror(errno)); free_entry(pent); free(pload_soft_conf); (void) close(fd); return (FAILURE); } if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl = return_value = %d", pload_soft_conf->sc_return_value); free_entry(pent); free(pload_soft_conf); (void) close(fd); return (FAILURE); } /* ioctl cleanup */ free(pload_soft_conf); (void) close(fd); /* Finally, remove entry from kcf.conf, if present */ if (in_kcfconf && (pent != NULL)) { rc = update_kcfconf(pent, DELETE_MODE); } free_entry(pent); return (rc); }
/* * Disable a kernel software provider. * This implements the "cryptoadm disable" command for * kernel software providers. */ int disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag, mechlist_t *dislist) { crypto_load_soft_disabled_t *pload_soft_dis = NULL; mechlist_t *infolist = NULL; entry_t *pent = NULL; entrylist_t *phardlist = NULL; entrylist_t *psoftlist = NULL; boolean_t in_kernel = B_FALSE; int fd = -1; int rc = SUCCESS; if (provname == NULL) { return (FAILURE); } /* * Check if the kernel software provider is currently unloaded. * If it is unloaded, return FAILURE, because the disable subcommand * can not perform on inactive (unloaded) providers. */ if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { return (FAILURE); } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("%s is not loaded or does not exist."), provname); return (FAILURE); } if (get_kcfconf_info(&phardlist, &psoftlist) == FAILURE) { cryptoerror(LOG_ERR, "failed to retrieve the providers' " "information from the configuration file - %s.", _PATH_KCF_CONF); return (FAILURE); } /* * Get the entry of this provider from the kcf.conf file, if any. * Otherwise, create a new kcf.conf entry for writing back to the file. */ pent = getent_kef(provname, phardlist, psoftlist); if (pent == NULL) { /* create a new entry */ pent = create_entry(provname); if (pent == NULL) { cryptodebug("out of memory."); rc = FAILURE; goto out; } } /* Get the mechanism list for the software provider from the kernel */ if (get_soft_info(provname, &infolist, phardlist, psoftlist) == FAILURE) { rc = FAILURE; goto out; } if ((infolist != NULL) && (infolist->name[0] != '\0')) { /* * Replace the supportedlist from kcf.conf with possibly * more-up-to-date list from the kernel. This is the case * for default software providers that had more mechanisms * added in the current version of the kernel. */ free_mechlist(pent->suplist); pent->suplist = infolist; } /* * kCF treats random as an internal mechanism. So, we need to * filter it from the mechanism list here, if we are NOT disabling * or enabling the random feature. Note that we map random feature at * cryptoadm(1M) level to the "random" mechanism in kCF. */ if (!rndflag) { (void) filter_mechlist(&infolist, RANDOM); } /* Calculate the new disabled list */ if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) { rc = FAILURE; goto out; } /* Update the kcf.conf file with the updated entry */ if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) { rc = FAILURE; goto out; } /* Setup argument to inform kernel about the new disabled list. */ if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { rc = FAILURE; goto out; } if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s for RW: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); rc = FAILURE; goto out; } /* Inform kernel about the new disabled list. */ if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s", strerror(errno)); rc = FAILURE; goto out; } if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = " "%d", pload_soft_dis->sd_return_value); rc = FAILURE; goto out; } out: free_entrylist(phardlist); free_entrylist(psoftlist); free_mechlist(infolist); free_entry(pent); free(pload_soft_dis); if (fd != -1) (void) close(fd); return (rc); }
/* * Disable a kernel hardware provider. * This implements the "cryptoadm disable" command for * kernel hardware providers. */ int disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag, mechlist_t *dislist) { crypto_load_dev_disabled_t *pload_dev_dis = NULL; mechlist_t *infolist = NULL; entry_t *pent = NULL; boolean_t new_dev_entry = B_FALSE; char devname[MAXNAMELEN]; int inst_num; int count; int fd = -1; int rc = SUCCESS; if (provname == NULL) { return (FAILURE); } /* * Check if the provider is valid. If it is valid, get the number of * mechanisms also. */ if (check_hardware_provider(provname, devname, &inst_num, &count) == FAILURE) { return (FAILURE); } /* Get the mechanism list for the kernel hardware provider */ if (get_dev_info(devname, inst_num, count, &infolist) == FAILURE) { return (FAILURE); } /* * Get the entry of this hardware provider from the config file. * If there is no entry yet, create one for it. */ if ((pent = getent_kef(provname, NULL, NULL)) == NULL) { if ((pent = create_entry(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); free_mechlist(infolist); return (FAILURE); } new_dev_entry = B_TRUE; } /* * kCF treats random as an internal mechanism. So, we need to * filter it from the mechanism list here, if we are NOT disabling * or enabling the random feature. Note that we map random feature at * cryptoadm(1M) level to the "random" mechanism in kCF. */ if (!rndflag) { (void) filter_mechlist(&dislist, RANDOM); } /* Calculate the new disabled list */ if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) { free_mechlist(infolist); free_entry(pent); return (FAILURE); } free_mechlist(infolist); /* If no mechanisms are to be disabled, return */ if (pent->dis_count == 0) { free_entry(pent); return (SUCCESS); } /* Update the config file with the new entry or the updated entry */ if (new_dev_entry) { rc = update_kcfconf(pent, ADD_MODE); } else { rc = update_kcfconf(pent, MODIFY_MODE); } if (rc == FAILURE) { free_entry(pent); return (FAILURE); } /* Inform kernel about the new disabled mechanism list */ if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) { free_entry(pent); return (FAILURE); } free_entry(pent); if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free(pload_dev_dis); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: %s", strerror(errno)); free(pload_dev_dis); (void) close(fd); return (FAILURE); } if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl return_value = " "%d", pload_dev_dis->dd_return_value); free(pload_dev_dis); (void) close(fd); return (FAILURE); } free(pload_dev_dis); (void) close(fd); return (SUCCESS); }
/* * Display the policy information for a kernel hardware provider. * This implements part of the "cryptoadm list -p" command. * * Parameters phardlist and psoftlist are supplied by getent_kef(). * If NULL, this function obtains it by calling get_kcfconf_info() via * getent_kef() internally. * Parameter pdevlist is supplied by check_kernel_for_hard(). * If NULL, this function obtains it by calling get_dev_list() via * check_kernel_for_hard() internally. */ int list_policy_for_hard(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist, crypto_get_dev_list_t *pdevlist) { entry_t *pent = NULL; boolean_t in_kernel; mechlist_t *pmechlist = NULL; char devname[MAXNAMELEN]; int inst_num; int count; int rc = SUCCESS; boolean_t has_random = B_FALSE; boolean_t has_mechs = B_FALSE; if (provname == NULL) { return (FAILURE); } /* * Check if the provider is valid. If it is valid, get the number of * mechanisms also. */ if (check_hardware_provider(provname, devname, &inst_num, &count) == FAILURE) { return (FAILURE); } /* Get the mechanism list for the kernel hardware provider */ if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) == SUCCESS) { has_random = filter_mechlist(&pmechlist, RANDOM); if (pmechlist != NULL) { has_mechs = B_TRUE; free_mechlist(pmechlist); } } else { cryptoerror(LOG_STDERR, gettext( "failed to retrieve the mechanism list for %s."), devname); return (rc); } /* * If the hardware provider has an entry in the kcf.conf file, * some of its mechanisms must have been disabled. Print out * the disabled list from the config file entry. Otherwise, * if it is active, then all the mechanisms for it are enabled. */ if ((pent = getent_kef(provname, phardlist, psoftlist)) != NULL) { print_kef_policy(provname, pent, has_random, has_mechs); free_entry(pent); return (SUCCESS); } else { if (check_kernel_for_hard(provname, pdevlist, &in_kernel) == FAILURE) { return (FAILURE); } else if (in_kernel == B_TRUE) { (void) printf(gettext( "%s: all mechanisms are enabled."), provname); if (has_random) /* * TRANSLATION_NOTE * "random" is a keyword and not to be * translated. */ (void) printf(gettext(" %s is enabled.\n"), "random"); else (void) printf("\n"); return (SUCCESS); } else { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); return (FAILURE); } } }
/* * Unload the kernel software provider. Before calling this function, the * caller should check to see if the provider is in the kernel. * * This routine makes 2 ioctl calls to remove it completely from the kernel: * CRYPTO_UNLOAD_SOFT_MODULE - does a modunload of the KCF module * CRYPTO_LOAD_SOFT_DISABLED - updates kernel disabled mechanism list * * This implements part of "cryptoadm unload" and "cryptoadm uninstall". */ int unload_kef_soft(char *provname) { crypto_unload_soft_module_t *punload_soft = NULL; crypto_load_soft_disabled_t *pload_soft_dis = NULL; entry_t *pent = NULL; int fd = -1; int err; if (provname == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } pent = getent_kef(provname, NULL, NULL); if (pent == NULL) { /* not in kcf.conf */ /* Construct an entry using the provname */ pent = create_entry(provname); if (pent == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (FAILURE); } } /* Open the admin_ioctl_device */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(err)); free_entry(pent); return (FAILURE); } /* Inform kernel to unload this software module */ if ((punload_soft = setup_unload_soft(pent)) == NULL) { free_entry(pent); (void) close(fd); return (FAILURE); } if (ioctl(fd, CRYPTO_UNLOAD_SOFT_MODULE, punload_soft) == -1) { cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl failed: %s", strerror(errno)); free_entry(pent); free(punload_soft); (void) close(fd); return (FAILURE); } if (punload_soft->sm_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl return_value = " "%d", punload_soft->sm_return_value); /* * If the return value is CRYPTO_UNKNOWN_PROVIDER, it means * that the provider is not registered yet. Should just * continue. */ if (punload_soft->sm_return_value != CRYPTO_UNKNOWN_PROVIDER) { free_entry(pent); free(punload_soft); (void) close(fd); return (FAILURE); } } free(punload_soft); /* Inform kernel to remove the disabled entries if any */ if (pent->dis_count == 0) { free_entry(pent); (void) close(fd); return (SUCCESS); } else { free_mechlist(pent->dislist); pent->dislist = NULL; pent->dis_count = 0; } if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { free_entry(pent); (void) close(fd); return (FAILURE); } /* pent is no longer needed; free it */ free_entry(pent); if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s", strerror(errno)); free(pload_soft_dis); (void) close(fd); return (FAILURE); } if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = " "%d", pload_soft_dis->sd_return_value); free(pload_soft_dis); (void) close(fd); return (FAILURE); } free(pload_soft_dis); (void) close(fd); return (SUCCESS); }