/* * 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); }
/* * 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 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); }
/* * Enable a kernel software or hardware provider. * This implements the "cryptoadm enable" command for kernel providers. */ int enable_kef(char *provname, boolean_t rndflag, boolean_t allflag, mechlist_t *mlist) { crypto_load_soft_disabled_t *pload_soft_dis = NULL; crypto_load_dev_disabled_t *pload_dev_dis = NULL; entry_t *pent = NULL; boolean_t redo_flag = B_FALSE; boolean_t in_kernel = B_FALSE; int fd = -1; int rc = SUCCESS; /* Get the entry of this provider from the kcf.conf file, if any. */ pent = getent_kef(provname, NULL, NULL); if (is_device(provname)) { if (pent == NULL) { /* * This device doesn't have an entry in the config * file, therefore nothing is disabled. */ cryptoerror(LOG_STDERR, gettext( "all mechanisms are enabled already for %s."), provname); free_entry(pent); return (SUCCESS); } } else { /* a software module */ if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) { free_entry(pent); return (FAILURE); } else if (in_kernel == B_FALSE) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); free_entry(pent); return (FAILURE); } else if ((pent == NULL) || (pent->dis_count == 0)) { /* nothing to be enabled. */ cryptoerror(LOG_STDERR, gettext( "all mechanisms are enabled already for %s."), provname); free_entry(pent); return (SUCCESS); } } /* * 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) { redo_flag = filter_mechlist(&pent->dislist, RANDOM); if (redo_flag) pent->dis_count--; } /* Update the entry by enabling mechanisms for this provider */ if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) { free_entry(pent); return (rc); } if (redo_flag) { mechlist_t *tmp; if ((tmp = create_mech(RANDOM)) == NULL) { free_entry(pent); return (FAILURE); } tmp->next = pent->dislist; pent->dislist = tmp; pent->dis_count++; } /* * Update the kcf.conf file with the updated entry. * For a hardware provider, if there is no more disabled mechanism, * remove the entire kcf.conf entry. */ if (is_device(pent->name) && (pent->dis_count == 0)) { rc = update_kcfconf(pent, DELETE_MODE); } else { rc = update_kcfconf(pent, MODIFY_MODE); } if (rc == FAILURE) { free_entry(pent); return (FAILURE); } /* Inform Kernel about the policy change */ if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); free_entry(pent); return (FAILURE); } if (is_device(provname)) { /* LOAD_DEV_DISABLED */ if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) { free_entry(pent); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) { cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: " "%s", strerror(errno)); free_entry(pent); 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_entry(pent); free(pload_dev_dis); (void) close(fd); return (FAILURE); } } else { /* a software module */ /* LOAD_SOFT_DISABLED */ if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) { free_entry(pent); return (FAILURE); } if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: " "%s", strerror(errno)); free_entry(pent); 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_entry(pent); free(pload_soft_dis); (void) close(fd); return (FAILURE); } } free_entry(pent); free(pload_soft_dis); (void) close(fd); return (SUCCESS); }