# # 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 2010 Nexenta Systems, Inc. All rights reserved. PROG = cryptoadm OBJS = cryptoadm.o \ adm_uef.o \ adm_kef.o \ adm_kef_ioctl.o \ adm_kef_util.o \ adm_util.o \ adm_metaslot.o SRCS = $(OBJS:.o=.c) include ../../Makefile.cmd POFILES = $(OBJS:%.o=%.po) POFILE = $(PROG)_all.po CFLAGS += $(CCVERBOSE) CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-parentheses # Hammerhead: -ldl for dlopen/dlsym of PKCS#11 provider modules LDLIBS += -lcryptoutil -ldl .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) $(OBJS) -o $@ $(LDLIBS) $(DYNFLAGS) $(POST_PROCESS) $(POFILE): $(POFILES) $(RM) $@; cat $(POFILES) > $@ install: all $(ROOTSBINPROG) $(RM) $(ROOTUSRSBINPROG) -$(SYMLINK) ../../sbin/$(PROG) $(ROOTUSRSBINPROG) clean: $(RM) -f $(OBJS) $(PROG) lint: lint_SRCS include ../../Makefile.targ /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" static int check_hardware_provider(char *, char *, int *, int *); /* * 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); } /* * 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 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); } } } /* * 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(8) 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); } /* * 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(8) 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); } /* * 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(8) 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); } /* * Install a software module with the specified mechanism list into the system. * This routine adds an entry into the config file for this software module * first, then makes a CRYPTO_LOAD_SOFT_CONFIG ioctl call to inform kernel * about the new addition. */ int install_kef(char *provname, mechlist_t *mlist) { crypto_load_soft_config_t *pload_soft_conf = NULL; boolean_t found; entry_t *pent = NULL; FILE *pfile = NULL; FILE *pfile_tmp = NULL; char tmpfile_name[MAXPATHLEN]; char *ptr; char *str; char *name; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; int found_count; int fd = -1; int rc = SUCCESS; int err; if ((provname == NULL) || (mlist == NULL)) { return (FAILURE); } /* Check if the provider already exists */ if ((pent = getent_kef(provname, NULL, NULL)) != NULL) { cryptoerror(LOG_STDERR, gettext("%s exists already."), provname); free_entry(pent); return (FAILURE); } /* Create an entry with provname and mlist. */ if ((pent = create_entry(provname)) == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (FAILURE); } pent->sup_count = get_mech_count(mlist); pent->suplist = mlist; /* Append an entry for this software module to the kcf.conf file. */ if ((str = ent2str(pent)) == NULL) { free_entry(pent); return (FAILURE); } if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to open %s for write.", _PATH_KCF_CONF); free_entry(pent); return (FAILURE); } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to lock the configuration - %s"), strerror(err)); free_entry(pent); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory. */ (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to create a temporary file - %s"), strerror(err)); free_entry(pent); (void) fclose(pfile); return (FAILURE); } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), tmpfile_name, strerror(err)); free_entry(pent); (void) fclose(pfile); return (FAILURE); } /* * Loop thru the config file. If the provider was reserved within a * package bracket, just uncomment it. Otherwise, append it at * the end. The resulting file will be saved in the temp file first. */ found_count = 0; rc = SUCCESS; while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (buffer[0] == '#') { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; ptr++; if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(provname, name) == 0) { found = B_TRUE; found_count++; } } if (found == B_FALSE) { if (fputs(buffer, pfile_tmp) == EOF) { rc = FAILURE; } } else { if (found_count == 1) { if (fputs(str, pfile_tmp) == EOF) { rc = FAILURE; } } else { /* * Found a second entry with #libname. * Should not happen. The kcf.conf file * is corrupted. Give a warning and skip * this entry. */ cryptoerror(LOG_STDERR, gettext( "(Warning) Found an additional reserved " "entry for %s."), provname); } } if (rc == FAILURE) { break; } } (void) fclose(pfile); if (rc == FAILURE) { cryptoerror(LOG_STDERR, gettext("write error.")); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } free_entry(pent); return (FAILURE); } if (found_count == 0) { /* * This libname was not in package before, append it to the * end of the temp file. */ if (fputs(str, pfile_tmp) == EOF) { cryptoerror(LOG_STDERR, gettext( "failed to write to %s: %s"), tmpfile_name, strerror(errno)); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } free_entry(pent); return (FAILURE); } } if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); free_entry(pent); return (FAILURE); } if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to rename %s to %s: %s", tmpfile_name, _PATH_KCF_CONF, strerror(err)); rc = FAILURE; } else if (chmod(_PATH_KCF_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if (rc == FAILURE) { if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } free_entry(pent); return (FAILURE); } /* Inform kernel of this new software module. */ if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { free_entry(pent); return (FAILURE); } 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); 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 failed, " "return_value = %d", pload_soft_conf->sc_return_value); free_entry(pent); free(pload_soft_conf); (void) close(fd); return (FAILURE); } free_entry(pent); free(pload_soft_conf); (void) close(fd); return (SUCCESS); } /* * 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); } /* * Implement the "cryptoadm refresh" command for global zones. * That is, send the current contents of kcf.conf to the kernel via ioctl(). */ int refresh(void) { crypto_load_soft_config_t *pload_soft_conf = NULL; crypto_load_soft_disabled_t *pload_soft_dis = NULL; crypto_load_dev_disabled_t *pload_dev_dis = NULL; entrylist_t *pdevlist = NULL; entrylist_t *psoftlist = NULL; entrylist_t *ptr; int fd = -1; int rc = SUCCESS; int err; if (get_kcfconf_info(&pdevlist, &psoftlist) == FAILURE) { cryptoerror(LOG_ERR, "failed to retrieve the providers' " "information from the configuration file - %s.", _PATH_KCF_CONF); return (FAILURE); } 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(psoftlist); free(pdevlist); return (FAILURE); } /* * For each software provider module, pass two sets of information to * the kernel: the supported list and the disabled list. */ for (ptr = psoftlist; ptr != NULL; ptr = ptr->next) { entry_t *pent = ptr->pent; /* load the supported list */ if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) { cryptodebug("setup_soft_conf() failed"); rc = FAILURE; break; } if (!pent->load) { /* unloaded--mark as loaded */ pent->load = B_TRUE; rc = update_kcfconf(pent, MODIFY_MODE); if (rc != SUCCESS) { free(pload_soft_conf); break; } } if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) { cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s", strerror(errno)); free(pload_soft_conf); rc = FAILURE; break; } 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(pload_soft_conf); rc = FAILURE; break; } free(pload_soft_conf); /* load the disabled list */ if (ptr->pent->dis_count != 0) { pload_soft_dis = setup_soft_dis(ptr->pent); if (pload_soft_dis == NULL) { cryptodebug("setup_soft_dis() failed"); free(pload_soft_dis); rc = FAILURE; break; } 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); rc = FAILURE; break; } 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); rc = FAILURE; break; } free(pload_soft_dis); } } if (rc != SUCCESS) { (void) close(fd); return (rc); } /* * For each hardware provider module, pass the disabled list * information to the kernel. */ for (ptr = pdevlist; ptr != NULL; ptr = ptr->next) { /* load the disabled list */ if (ptr->pent->dis_count != 0) { pload_dev_dis = setup_dev_dis(ptr->pent); if (pload_dev_dis == NULL) { rc = FAILURE; break; } 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); rc = FAILURE; break; } 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); rc = FAILURE; break; } free(pload_dev_dis); } } (void) close(fd); return (rc); } /* * 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); } /* * Check if a hardware provider is valid. If it is valid, returns its device * name, instance number and the number of mechanisms it supports. */ static int check_hardware_provider(char *provname, char *pname, int *pnum, int *pcount) { crypto_get_dev_list_t *dev_list = NULL; int i; if (provname == NULL) { return (FAILURE); } /* First, get the device name and the instance number from provname */ if (split_hw_provname(provname, pname, pnum) == FAILURE) { return (FAILURE); } /* * Get the complete device list from kernel and check if this provider * is in the list. */ if (get_dev_list(&dev_list) == FAILURE) { return (FAILURE); } for (i = 0; i < dev_list->dl_dev_count; i++) { if ((strcmp(dev_list->dl_devs[i].le_dev_name, pname) == 0) && (dev_list->dl_devs[i].le_dev_instance == *pnum)) { break; } } if (i == dev_list->dl_dev_count) { /* didn't find this provider in the kernel device list */ cryptoerror(LOG_STDERR, gettext("%s does not exist."), provname); free(dev_list); return (FAILURE); } /* This provider is valid. Get its mechanism count */ *pcount = dev_list->dl_devs[i].le_mechanism_count; free(dev_list); return (SUCCESS); } /* * 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 2010 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" #define DEFAULT_DEV_NUM 5 #define DEFAULT_SOFT_NUM 10 static crypto_get_soft_info_t *setup_get_soft_info(char *, int); /* * Prepare the argument for the LOAD_SOFT_CONFIG ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_load_soft_config_t * setup_soft_conf(entry_t *pent) { crypto_load_soft_config_t *pload_soft_conf; mechlist_t *plist; uint_t sup_count; size_t extra_mech_size = 0; int i; if (pent == NULL) { return (NULL); } sup_count = pent->sup_count; if (sup_count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (sup_count - 1); } pload_soft_conf = malloc(sizeof (crypto_load_soft_config_t) + extra_mech_size); if (pload_soft_conf == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(pload_soft_conf->sc_name, pent->name, MAXNAMELEN); pload_soft_conf->sc_count = sup_count; i = 0; plist = pent->suplist; while (i < sup_count) { (void) strlcpy(pload_soft_conf->sc_list[i++], plist->name, CRYPTO_MAX_MECH_NAME); plist = plist->next; } return (pload_soft_conf); } /* * Prepare the argument for the LOAD_SOFT_DISABLED ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_load_soft_disabled_t * setup_soft_dis(entry_t *pent) { crypto_load_soft_disabled_t *pload_soft_dis = NULL; mechlist_t *plist = NULL; size_t extra_mech_size = 0; uint_t dis_count; int i; if (pent == NULL) { return (NULL); } dis_count = pent->dis_count; if (dis_count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (dis_count - 1); } pload_soft_dis = malloc(sizeof (crypto_load_soft_disabled_t) + extra_mech_size); if (pload_soft_dis == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(pload_soft_dis->sd_name, pent->name, MAXNAMELEN); pload_soft_dis->sd_count = dis_count; i = 0; plist = pent->dislist; while (i < dis_count) { (void) strlcpy(pload_soft_dis->sd_list[i++], plist->name, CRYPTO_MAX_MECH_NAME); plist = plist->next; } return (pload_soft_dis); } /* * Prepare the argument for the LOAD_DEV_DISABLED ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_load_dev_disabled_t * setup_dev_dis(entry_t *pent) { crypto_load_dev_disabled_t *pload_dev_dis = NULL; mechlist_t *plist = NULL; size_t extra_mech_size = 0; uint_t dis_count; int i; char pname[MAXNAMELEN]; int inst_num; if (pent == NULL) { return (NULL); } /* get the device name and the instance number */ if (split_hw_provname(pent->name, pname, &inst_num) == FAILURE) { return (NULL); } /* allocate space for pload_dev_des */ dis_count = pent->dis_count; if (dis_count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (dis_count - 1); } pload_dev_dis = malloc(sizeof (crypto_load_dev_disabled_t) + extra_mech_size); if (pload_dev_dis == NULL) { cryptodebug("out of memory."); return (NULL); } /* set the values for pload_dev_dis */ (void) strlcpy(pload_dev_dis->dd_dev_name, pname, MAXNAMELEN); pload_dev_dis->dd_dev_instance = inst_num; pload_dev_dis->dd_count = dis_count; i = 0; plist = pent->dislist; while (i < dis_count) { (void) strlcpy(pload_dev_dis->dd_list[i++], plist->name, CRYPTO_MAX_MECH_NAME); plist = plist->next; } return (pload_dev_dis); } /* * Prepare the calling argument of the UNLOAD_SOFT_MODULE ioctl call for the * provider pointed by pent. Return NULL if out of memory. */ crypto_unload_soft_module_t * setup_unload_soft(entry_t *pent) { crypto_unload_soft_module_t *punload_soft; if (pent == NULL) { return (NULL); } punload_soft = malloc(sizeof (crypto_unload_soft_module_t)); if (punload_soft == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(punload_soft->sm_name, pent->name, MAXNAMELEN); return (punload_soft); } /* * Prepare the calling argument for the GET_SOFT_INFO call for the provider * with the number of mechanisms specified in the second argument. * * Called by get_soft_info(). */ static crypto_get_soft_info_t * setup_get_soft_info(char *provname, int count) { crypto_get_soft_info_t *psoft_info; size_t extra_mech_size = 0; if (provname == NULL) { return (NULL); } if (count > 1) { extra_mech_size = sizeof (crypto_mech_name_t) * (count - 1); } psoft_info = malloc(sizeof (crypto_get_soft_info_t) + extra_mech_size); if (psoft_info == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(psoft_info->si_name, provname, MAXNAMELEN); psoft_info->si_count = count; return (psoft_info); } /* * Get the device list from kernel. */ int get_dev_list(crypto_get_dev_list_t **ppdevlist) { crypto_get_dev_list_t *pdevlist; int fd = -1; int count = DEFAULT_DEV_NUM; pdevlist = malloc(sizeof (crypto_get_dev_list_t) + sizeof (crypto_dev_list_entry_t) * (count - 1)); if (pdevlist == NULL) { cryptodebug("out of memory."); 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(pdevlist); return (FAILURE); } pdevlist->dl_dev_count = count; if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", strerror(errno)); free(pdevlist); (void) close(fd); return (FAILURE); } /* BUFFER is too small, get the number of devices and retry it. */ if (pdevlist->dl_return_value == CRYPTO_BUFFER_TOO_SMALL) { count = pdevlist->dl_dev_count; free(pdevlist); pdevlist = malloc(sizeof (crypto_get_dev_list_t) + sizeof (crypto_dev_list_entry_t) * (count - 1)); if (pdevlist == NULL) { cryptodebug("out of memory."); (void) close(fd); return (FAILURE); } if (ioctl(fd, CRYPTO_GET_DEV_LIST, pdevlist) == -1) { cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed: %s", strerror(errno)); free(pdevlist); (void) close(fd); return (FAILURE); } } if (pdevlist->dl_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_DEV_LIST ioctl failed, " "return_value = %d", pdevlist->dl_return_value); free(pdevlist); (void) close(fd); return (FAILURE); } *ppdevlist = pdevlist; (void) close(fd); return (SUCCESS); } /* * 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 = -1; 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); } /* * Get the supported mechanism list of the software provider from kernel. * * Parameters phardlist and psoftlist are supplied by get_kcfconf_info(). * If NULL, this function calls get_kcfconf_info() internally. */ int get_soft_info(char *provname, mechlist_t **ppmechlist, entrylist_t *phardlist, entrylist_t *psoftlist) { boolean_t in_kernel = B_FALSE; crypto_get_soft_info_t *psoft_info; mechlist_t *phead; mechlist_t *pmech; mechlist_t *pcur; entry_t *pent = NULL; int count; int fd = -1; 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, phardlist, psoftlist)) == NULL) { /* No kcf.conf entry for this provider */ 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); } /* * Set mech count to 1. It will be reset to the * correct value later if the setup buffer is too small. */ count = 1; } else { 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); } /* Build the mechanism linked 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 the kernel software provider list from kernel. */ int get_soft_list(crypto_get_soft_list_t **ppsoftlist) { crypto_get_soft_list_t *psoftlist = NULL; int count = DEFAULT_SOFT_NUM; int len; int fd = -1; if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) { cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"), ADMIN_IOCTL_DEVICE, strerror(errno)); return (FAILURE); } len = MAXNAMELEN * count; psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); if (psoftlist == NULL) { cryptodebug("out of memory."); (void) close(fd); return (FAILURE); } psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); psoftlist->sl_soft_count = count; psoftlist->sl_soft_len = len; if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed: %s", strerror(errno)); free(psoftlist); (void) close(fd); return (FAILURE); } /* * if BUFFER is too small, get the number of software providers and * the minimum length needed for names and length and retry it. */ if (psoftlist->sl_return_value == CRYPTO_BUFFER_TOO_SMALL) { count = psoftlist->sl_soft_count; len = psoftlist->sl_soft_len; free(psoftlist); psoftlist = malloc(sizeof (crypto_get_soft_list_t) + len); if (psoftlist == NULL) { cryptodebug("out of memory."); (void) close(fd); return (FAILURE); } psoftlist->sl_soft_names = (caddr_t)(psoftlist + 1); psoftlist->sl_soft_count = count; psoftlist->sl_soft_len = len; if (ioctl(fd, CRYPTO_GET_SOFT_LIST, psoftlist) == -1) { cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed:" "%s", strerror(errno)); free(psoftlist); (void) close(fd); return (FAILURE); } } if (psoftlist->sl_return_value != CRYPTO_SUCCESS) { cryptodebug("CRYPTO_GET_SOFT_LIST ioctl failed, " "return_value = %d", psoftlist->sl_return_value); free(psoftlist); (void) close(fd); return (FAILURE); } *ppsoftlist = psoftlist; (void) close(fd); return (SUCCESS); } /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" static int err; /* To store errno which may be overwritten by gettext() */ static int build_entrylist(entry_t *pent, entrylist_t **pplist); static entry_t *dup_entry(entry_t *pent1); static mechlist_t *dup_mechlist(mechlist_t *plist); static entry_t *getent(char *provname, entrylist_t *entrylist); static int interpret(char *buf, entry_t **ppent); static int parse_sup_dis_list(const char *buf, entry_t *pent); /* * Duplicate the mechanism list. A null pointer is returned if the storage * space available is insufficient or the input argument is NULL. */ static mechlist_t * dup_mechlist(mechlist_t *plist) { mechlist_t *pres = NULL; mechlist_t *pcur; mechlist_t *ptmp; int rc = SUCCESS; while (plist != NULL) { if (!(ptmp = create_mech(plist->name))) { rc = FAILURE; break; } if (pres == NULL) { pres = pcur = ptmp; } else { pcur->next = ptmp; pcur = pcur->next; } plist = plist->next; } if (rc != SUCCESS) { free_mechlist(pres); return (NULL); } return (pres); } /* * Get the number of mechanisms in the mechanism list. */ int get_mech_count(mechlist_t *plist) { int count = 0; while (plist != NULL) { count++; plist = plist->next; } return (count); } /* * Create one item of type entry_t with the provider name. * Return NULL if there's not enough memory or provname is NULL. */ entry_t * create_entry(char *provname) { entry_t *pent = NULL; if (provname == NULL) { return (NULL); } pent = calloc(1, sizeof (entry_t)); if (pent == NULL) { cryptodebug("out of memory."); return (NULL); } (void) strlcpy(pent->name, provname, MAXNAMELEN); pent->suplist = NULL; pent->sup_count = 0; pent->dislist = NULL; pent->dis_count = 0; pent->load = B_TRUE; return (pent); } /* * Duplicate an entry for a provider from kcf.conf. * Return NULL if memory is insufficient or the input argument is NULL. * Called by getent(). */ static entry_t * dup_entry(entry_t *pent1) { entry_t *pent2 = NULL; if (pent1 == NULL) { return (NULL); } if ((pent2 = create_entry(pent1->name)) == NULL) { cryptodebug("out of memory."); return (NULL); } pent2->sup_count = pent1->sup_count; pent2->dis_count = pent1->dis_count; pent2->load = pent1->load; if (pent1->suplist != NULL) { pent2->suplist = dup_mechlist(pent1->suplist); if (pent2->suplist == NULL) { free_entry(pent2); return (NULL); } } if (pent1->dislist != NULL) { pent2->dislist = dup_mechlist(pent1->dislist); if (pent2->dislist == NULL) { free_entry(pent2); return (NULL); } } return (pent2); } /* * This routine parses the disabledlist or the supportedlist of an entry * in the kcf.conf configuration file. * * Arguments: * buf: an input argument which is a char string with the format of * "disabledlist=m1,m2,..." or "supportedlist=m1,m2,..." * pent: the entry for the disabledlist. This is an IN/OUT argument. * * Return value: SUCCESS or FAILURE. */ static int parse_sup_dis_list(const char *buf, entry_t *pent) { mechlist_t *pmech = NULL; mechlist_t *phead = NULL; char *next_token; char *value; int count; int supflag = B_FALSE; int disflag = B_FALSE; int rc = SUCCESS; if (strncmp(buf, EF_SUPPORTED, strlen(EF_SUPPORTED)) == 0) { supflag = B_TRUE; } else if (strncmp(buf, EF_DISABLED, strlen(EF_DISABLED)) == 0) { disflag = B_TRUE; } else { /* should not come here */ return (FAILURE); } if (value = strpbrk(buf, SEP_EQUAL)) { value++; /* get rid of = */ } else { cryptodebug("failed to parse the kcf.conf file."); return (FAILURE); } if ((next_token = strtok(value, SEP_COMMA)) == NULL) { cryptodebug("failed to parse the kcf.conf file."); return (FAILURE); } if ((pmech = create_mech(next_token)) == NULL) { return (FAILURE); } if (supflag) { if (pent->suplist != NULL) { cryptodebug("multiple supportedlist entries " "for a mechanism in file kcf.conf."); return (FAILURE); } else { pent->suplist = phead = pmech; } } else if (disflag) { if (pent->dislist != NULL) { cryptodebug("multiple disabledlist entries " "for a mechanism in file kcf.conf."); return (FAILURE); } else { pent->dislist = phead = pmech; } } count = 1; while (next_token) { if (next_token = strtok(NULL, SEP_COMMA)) { if ((pmech = create_mech(next_token)) == NULL) { rc = FAILURE; break; } count++; phead->next = pmech; phead = phead->next; } } if (rc == SUCCESS) { if (supflag) { pent->sup_count = count; } else if (disflag) { pent->dis_count = count; } } else { free_mechlist(phead); } return (rc); } /* * Convert a char string containing a line about a provider * from kcf.conf into an entry_t structure. * * Note: the input string, buf, may be modified by this function. * * See ent2str(), the reverse of this function, for the format of * kcf.conf lines. */ static int interpret(char *buf, entry_t **ppent) { entry_t *pent = NULL; char *token1; char *token2; char *token3; int rc; /* Get provider name */ if ((token1 = strtok(buf, SEP_COLON)) == NULL) { /* buf is NULL */ return (FAILURE); }; pent = create_entry(token1); if (pent == NULL) { cryptodebug("out of memory."); return (FAILURE); } if ((token2 = strtok(NULL, SEP_SEMICOLON)) == NULL) { /* The entry contains a provider name only */ free_entry(pent); return (FAILURE); } if (strncmp(token2, EF_UNLOAD, strlen(EF_UNLOAD)) == 0) { pent->load = B_FALSE; /* cryptoadm unload */ token2 = strtok(NULL, SEP_SEMICOLON); /* * If token2 is NULL, the entry contains a * provider name:unload only */ } if (token2 != NULL) { /* * Either supportedlist or disabledlist or both are present. * Need to call strtok() to get token3 first, as function * parse_sup_dis_list() makes strtok() calls on the * token2 substring. */ token3 = strtok(NULL, SEP_SEMICOLON); /* optional */ /* parse supportedlist (or disabledlist if no supportedlist) */ if ((rc = parse_sup_dis_list(token2, pent)) != SUCCESS) { free_entry(pent); return (rc); } /* parse disabledlist (if there's a supportedlist) */ if ((token3 != NULL) && ((rc = parse_sup_dis_list(token3, pent)) != SUCCESS)) { free_entry(pent); return (rc); } } *ppent = pent; return (SUCCESS); } /* * Add an entry about a provider from kcf.conf to the end of an entry list. * If the entry list pplist is NULL, create the linked list with pent as the * first element. */ static int build_entrylist(entry_t *pent, entrylist_t **pplist) { entrylist_t *pentlist; entrylist_t *pcur = NULL; pentlist = malloc(sizeof (entrylist_t)); if (pentlist == NULL) { cryptodebug("out of memory."); return (FAILURE); } pentlist->pent = pent; pentlist->next = NULL; if (*pplist) { pcur = *pplist; while (pcur->next != NULL) pcur = pcur->next; pcur->next = pentlist; } else { /* empty list */ *pplist = pentlist; } return (SUCCESS); } /* * Find the entry with the "provname" name from the entry list and duplicate * it. Called by getent_kef(). */ static entry_t * getent(char *provname, entrylist_t *entrylist) { boolean_t found = B_FALSE; entry_t *pent1 = NULL; if ((provname == NULL) || (entrylist == NULL)) { return (NULL); } while (!found && entrylist) { if (strcmp(entrylist->pent->name, provname) == 0) { found = B_TRUE; pent1 = entrylist->pent; } else { entrylist = entrylist->next; } } if (!found) { return (NULL); } /* duplicate the entry to be returned */ return (dup_entry(pent1)); } /* * Free memory in entry_t. * That is, the supported and disabled lists for a provider * from kcf.conf. */ void free_entry(entry_t *pent) { if (pent == NULL) { return; } else { free_mechlist(pent->suplist); free_mechlist(pent->dislist); free(pent); } } /* * Free elements in a entrylist_t linked list, * which lists providers in kcf.conf. */ void free_entrylist(entrylist_t *entrylist) { entrylist_t *pnext; while (entrylist != NULL) { pnext = entrylist->next; free_entry(entrylist->pent); entrylist = pnext; } } /* * Convert an entry_t to a kcf.conf line string. Build a string to insert * as a line in file kcf.conf. Based on the content of an entry_t, * the result string is one of these 8 forms: * - name:supportedlist=m1,m2,...,mj * - name:disabledlist=m1,m2,...,mj * - name:supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk * * - name:unload * - name:unload;supportedlist=m1,m2,...,mj * - name:unload;disabledlist=m1,m2,...,mj * - name:unload;supportedlist=m1,...,mj;disabledlist=m1,m2,...,mk * * - (NUL character or 0-length string) * * Return a 0-length empty string if no keyword is present (that is, * supportedlist, disabledlist, or unload). A kcf.conf line with just the * provider name with no keyword is invalid. * * Note that the caller is responsible for freeing the returned string * (with free_entry()). * See interpret() for the reverse of this function: converting a string * to an entry_t. */ char * ent2str(entry_t *pent) { char *buf; mechlist_t *pcur = NULL; boolean_t keyword_already_present = B_FALSE; if (pent == NULL) { return (NULL); } if ((buf = malloc(BUFSIZ)) == NULL) { return (NULL); } /* convert the provider name */ if (strlcpy(buf, pent->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (!pent->load) { /* add "unload" keyword */ if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_UNLOAD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } keyword_already_present = B_TRUE; } /* convert the supported list if any */ pcur = pent->suplist; if (pcur != NULL) { if (strlcat(buf, keyword_already_present ? SEP_SEMICOLON : SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_SUPPORTED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } while (pcur != NULL) { if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } pcur = pcur->next; if (pcur != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } keyword_already_present = B_TRUE; } /* convert the disabled list if any */ pcur = pent->dislist; if (pcur != NULL) { if (strlcat(buf, keyword_already_present ? SEP_SEMICOLON : SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } while (pcur != NULL) { if (strlcat(buf, pcur->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } pcur = pcur->next; if (pcur != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } keyword_already_present = B_TRUE; } if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (!keyword_already_present) { /* Only the provider name, without a keyword, is on the line */ buf[0] = '\0'; } return (buf); } /* * Enable the mechanisms for the provider pointed by *ppent. If allflag is * TRUE, enable all. Otherwise, enable the mechanisms specified in the 3rd * argument "mlist". The result will be stored in ppent also. */ int enable_mechs(entry_t **ppent, boolean_t allflag, mechlist_t *mlist) { entry_t *pent; mechlist_t *phead; /* the current and resulting disabled list */ mechlist_t *ptr = NULL; mechlist_t *pcur = NULL; boolean_t found; pent = *ppent; if (pent == NULL) { return (FAILURE); } if (allflag) { free_mechlist(pent->dislist); pent->dis_count = 0; pent->dislist = NULL; return (SUCCESS); } /* * for each mechanism in the to-be-enabled mechanism list, * - check if it is in the current disabled list * - if found, delete it from the disabled list * otherwise, give a warning. */ ptr = mlist; while (ptr != NULL) { found = B_FALSE; phead = pcur = pent->dislist; while (!found && pcur) { if (strcmp(pcur->name, ptr->name) == 0) { found = B_TRUE; } else { phead = pcur; pcur = pcur->next; } } if (found) { if (phead == pcur) { pent->dislist = pent->dislist->next; free(pcur); } else { phead->next = pcur->next; free(pcur); } pent->dis_count--; } else { cryptoerror(LOG_STDERR, gettext( "(Warning) %1$s is either enabled already or not " "a valid mechanism for %2$s"), ptr->name, pent->name); } ptr = ptr->next; } if (pent->dis_count == 0) { pent->dislist = NULL; } return (SUCCESS); } /* * Determine if the kernel provider name, path, is a device * (that is, it contains a slash character (e.g., "mca/0"). * If so, it is a hardware provider; otherwise it is a software provider. */ boolean_t is_device(char *path) { if (strchr(path, SEP_SLASH) != NULL) { return (B_TRUE); } else { return (B_FALSE); } } /* * Split a hardware provider name with the "name/inst_num" format into * a name and a number (e.g., split "mca/0" into "mca" instance 0). */ int split_hw_provname(char *provname, char *pname, int *inst_num) { char name[MAXNAMELEN]; char *inst_str; if (provname == NULL) { return (FAILURE); } (void) strlcpy(name, provname, MAXNAMELEN); if (strtok(name, "/") == NULL) { return (FAILURE); } if ((inst_str = strtok(NULL, "/")) == NULL) { return (FAILURE); } (void) strlcpy(pname, name, MAXNAMELEN); *inst_num = atoi(inst_str); return (SUCCESS); } /* * Retrieve information from kcf.conf and build a hardware device entry list * and a software entry list of kernel crypto providers. * * This list is usually incomplete, as kernel crypto providers only have to * be listed in kcf.conf if a mechanism is disabled (by cryptoadm) or * if the kernel provider module is not one of the default kernel providers. * * The kcf.conf file is available only in the global zone. */ int get_kcfconf_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist) { FILE *pfile = NULL; char buffer[BUFSIZ]; int len; entry_t *pent = NULL; int rc = SUCCESS; if ((pfile = fopen(_PATH_KCF_CONF, "r")) == NULL) { cryptodebug("failed to open the kcf.conf file for read only"); return (FAILURE); } *ppdevlist = NULL; *ppsoftlist = NULL; while (fgets(buffer, BUFSIZ, pfile) != NULL) { if (buffer[0] == '#' || buffer[0] == ' ' || buffer[0] == '\n'|| buffer[0] == '\t') { continue; /* ignore comment lines */ } len = strlen(buffer); if (buffer[len - 1] == '\n') { /* get rid of trailing '\n' */ len--; } buffer[len] = '\0'; if ((rc = interpret(buffer, &pent)) == SUCCESS) { if (is_device(pent->name)) { rc = build_entrylist(pent, ppdevlist); } else { rc = build_entrylist(pent, ppsoftlist); } } else { cryptoerror(LOG_STDERR, gettext( "failed to parse configuration.")); } if (rc != SUCCESS) { free_entrylist(*ppdevlist); free_entrylist(*ppsoftlist); free_entry(pent); break; } } (void) fclose(pfile); return (rc); } /* * Retrieve information from admin device and build a device entry list and * a software entry list. This is used where there is no kcf.conf, e.g., the * non-global zone. */ int get_admindev_info(entrylist_t **ppdevlist, entrylist_t **ppsoftlist) { crypto_get_dev_list_t *pdevlist_kernel = NULL; crypto_get_soft_list_t *psoftlist_kernel = NULL; char *devname; int inst_num; int mcount; mechlist_t *pmech = NULL; entry_t *pent_dev = NULL, *pent_soft = NULL; int i; char *psoftname; entrylist_t *tmp_pdev = NULL; entrylist_t *tmp_psoft = NULL; entrylist_t *phardlist = NULL, *psoftlist = NULL; /* * Get hardware providers */ if (get_dev_list(&pdevlist_kernel) != SUCCESS) { cryptodebug("failed to get hardware provider list from kernel"); return (FAILURE); } for (i = 0; i < pdevlist_kernel->dl_dev_count; i++) { devname = pdevlist_kernel->dl_devs[i].le_dev_name; inst_num = pdevlist_kernel->dl_devs[i].le_dev_instance; mcount = pdevlist_kernel->dl_devs[i].le_mechanism_count; pmech = NULL; if (get_dev_info(devname, inst_num, mcount, &pmech) != SUCCESS) { cryptodebug( "failed to retrieve the mechanism list for %s/%d.", devname, inst_num); goto fail_out; } if ((pent_dev = create_entry(devname)) == NULL) { cryptodebug("out of memory."); free_mechlist(pmech); goto fail_out; } pent_dev->suplist = pmech; pent_dev->sup_count = mcount; if (build_entrylist(pent_dev, &tmp_pdev) != SUCCESS) { goto fail_out; } } free(pdevlist_kernel); pdevlist_kernel = NULL; /* * Get software providers */ if (getzoneid() == GLOBAL_ZONEID) { if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) { goto fail_out; } } if (get_soft_list(&psoftlist_kernel) != SUCCESS) { cryptodebug("failed to get software provider list from kernel"); goto fail_out; } for (i = 0, psoftname = psoftlist_kernel->sl_soft_names; i < psoftlist_kernel->sl_soft_count; i++, psoftname = psoftname + strlen(psoftname) + 1) { pmech = NULL; if (get_soft_info(psoftname, &pmech, phardlist, psoftlist) != SUCCESS) { cryptodebug( "failed to retrieve the mechanism list for %s.", psoftname); goto fail_out; } if ((pent_soft = create_entry(psoftname)) == NULL) { cryptodebug("out of memory."); free_mechlist(pmech); goto fail_out; } pent_soft->suplist = pmech; pent_soft->sup_count = get_mech_count(pmech); if (build_entrylist(pent_soft, &tmp_psoft) != SUCCESS) { goto fail_out; } } free(psoftlist_kernel); psoftlist_kernel = NULL; *ppdevlist = tmp_pdev; *ppsoftlist = tmp_psoft; return (SUCCESS); fail_out: if (pent_dev != NULL) free_entry(pent_dev); if (pent_soft != NULL) free_entry(pent_soft); free_entrylist(tmp_pdev); free_entrylist(tmp_psoft); if (pdevlist_kernel != NULL) free(pdevlist_kernel); if (psoftlist_kernel != NULL) free(psoftlist_kernel); return (FAILURE); } /* * Return configuration information for a kernel provider from kcf.conf. * For kernel software providers return a enabled list and disabled list. * For kernel hardware providers return just a disabled list. * * Parameters phardlist and psoftlist are supplied by get_kcfconf_info(). * If NULL, this function calls get_kcfconf_info() internally. */ entry_t * getent_kef(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist) { entry_t *pent = NULL; boolean_t memory_allocated = B_FALSE; if ((phardlist == NULL) || (psoftlist == NULL)) { if (get_kcfconf_info(&phardlist, &psoftlist) != SUCCESS) { return (NULL); } memory_allocated = B_TRUE; } if (is_device(provname)) { pent = getent(provname, phardlist); } else { pent = getent(provname, psoftlist); } if (memory_allocated) { free_entrylist(phardlist); free_entrylist(psoftlist); } return (pent); } /* * Print out the provider name and the mechanism list. */ void print_mechlist(char *provname, mechlist_t *pmechlist) { mechlist_t *ptr = NULL; if (provname == NULL) { return; } (void) printf("%s: ", provname); if (pmechlist == NULL) { (void) printf(gettext("No mechanisms presented.\n")); return; } ptr = pmechlist; while (ptr != NULL) { (void) printf("%s", ptr->name); ptr = ptr->next; if (ptr == NULL) { (void) printf("\n"); } else { (void) printf(","); } } } /* * Update the kcf.conf file based on the update mode: * - If update_mode is MODIFY_MODE, modify the entry with the same name. * If not found, append a new entry to the kcf.conf file. * - If update_mode is DELETE_MODE, delete the entry with the same name. * - If update_mode is ADD_MODE, append a new entry to the kcf.conf file. */ int update_kcfconf(entry_t *pent, int update_mode) { boolean_t add_it = B_FALSE; boolean_t delete_it = B_FALSE; boolean_t this_entry_matches = B_FALSE; boolean_t found_entry = B_FALSE; FILE *pfile = NULL; FILE *pfile_tmp = NULL; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; char tmpfile_name[MAXPATHLEN]; char *name; char *new_str = NULL; int rc = SUCCESS; if (pent == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } /* Check the update_mode */ switch (update_mode) { case ADD_MODE: add_it = B_TRUE; /* FALLTHROUGH */ case MODIFY_MODE: /* Convert the entry a string to add to kcf.conf */ if ((new_str = ent2str(pent)) == NULL) { return (FAILURE); } if (strlen(new_str) == 0) { free(new_str); delete_it = B_TRUE; } break; case DELETE_MODE: delete_it = B_TRUE; break; default: cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } /* Open the kcf.conf file */ if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to open %s for write.", _PATH_KCF_CONF); return (FAILURE); } /* Lock the kcf.conf file */ if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory to save * updated configuration file first. */ (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to create a temporary file - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), tmpfile_name, strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Loop thru the entire kcf.conf file, insert, modify or delete * an entry. */ while (fgets(buffer, BUFSIZ, pfile) != NULL) { if (add_it) { if (fputs(buffer, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: %s."), strerror(err)); rc = FAILURE; break; } } else { /* modify or delete */ this_entry_matches = B_FALSE; if (!(buffer[0] == '#' || buffer[0] == ' ' || buffer[0] == '\n'|| buffer[0] == '\t')) { /* * Get the provider name from this line and * check if this is the entry to be updated * or deleted. Note: can not use "buffer" * directly because strtok will change its * value. */ (void) strlcpy(buffer2, buffer, BUFSIZ); if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rc = FAILURE; break; } if (strcmp(pent->name, name) == 0) { this_entry_matches = B_TRUE; found_entry = B_TRUE; } } if (!this_entry_matches || !delete_it) { /* write this entry */ if (this_entry_matches) { /* * Modify this entry: get the * updated string and place into buffer. */ (void) strlcpy(buffer, new_str, BUFSIZ); free(new_str); } /* write the (unchanged or modified) entry */ if (fputs(buffer, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: " "%s."), strerror(err)); rc = FAILURE; break; } } } } if ((!delete_it) && (rc != FAILURE)) { if (add_it || !found_entry) { /* append new entry to end of file */ if (fputs(new_str, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: %s."), strerror(err)); rc = FAILURE; } free(new_str); } } (void) fclose(pfile); if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); return (FAILURE); } /* Copy the temporary file to the kcf.conf file */ if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to rename %s to %s: %s", tmpfile, _PATH_KCF_CONF, strerror(err)); rc = FAILURE; } else if (chmod(_PATH_KCF_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (rc); } /* * Disable the mechanisms for the provider pointed by *ppent. If allflag is * TRUE, disable all. Otherwise, disable the mechanisms specified in the * dislist argument. The "infolist" argument contains the mechanism list * supported by this provider. */ int disable_mechs(entry_t **ppent, mechlist_t *infolist, boolean_t allflag, mechlist_t *dislist) { entry_t *pent; mechlist_t *plist = NULL; mechlist_t *phead = NULL; mechlist_t *pmech = NULL; int rc = SUCCESS; pent = *ppent; if (pent == NULL) { return (FAILURE); } if (allflag) { free_mechlist(pent->dislist); pent->dis_count = get_mech_count(infolist); if (!(pent->dislist = dup_mechlist(infolist))) { return (FAILURE); } else { return (SUCCESS); } } /* * Not disable all. Now loop thru the mechanisms specified in the * dislist. If the mechanism is not supported by the provider, * ignore it with a warning. If the mechanism is disabled already, * do nothing. Otherwise, prepend it to the beginning of the disabled * list of the provider. */ plist = dislist; while (plist != NULL) { if (!is_in_list(plist->name, infolist)) { cryptoerror(LOG_STDERR, gettext("(Warning) " "%1$s is not a valid mechanism for %2$s."), plist->name, pent->name); } else if (!is_in_list(plist->name, pent->dislist)) { /* Add this mechanism into the disabled list */ if ((pmech = create_mech(plist->name)) == NULL) { rc = FAILURE; break; } if (pent->dislist == NULL) { pent->dislist = pmech; } else { phead = pent->dislist; pent->dislist = pmech; pmech->next = phead; } pent->dis_count++; } plist = plist->next; } return (rc); } /* * Remove the mechanism passed, specified by mech, from the list of * mechanisms, if present in the list. Else, do nothing. * * Returns B_TRUE if mechanism is present in the list. */ boolean_t filter_mechlist(mechlist_t **pmechlist, const char *mech) { int cnt = 0; mechlist_t *ptr, *pptr; boolean_t mech_present = B_FALSE; ptr = pptr = *pmechlist; while (ptr != NULL) { if (strncmp(ptr->name, mech, sizeof (mech_name_t)) == 0) { mech_present = B_TRUE; if (ptr == *pmechlist) { pptr = *pmechlist = ptr->next; free(ptr); ptr = pptr; } else { pptr->next = ptr->next; free(ptr); ptr = pptr->next; } } else { pptr = ptr; ptr = ptr->next; cnt++; } } /* Only one entry is present */ if (cnt == 0) *pmechlist = NULL; return (mech_present); } /* * Print out the mechanism policy for a kernel provider that has an entry * in the kcf.conf file. * * The flag has_random is set to B_TRUE if the provider does random * numbers. The flag has_mechs is set by the caller to B_TRUE if the provider * has some mechanisms. * * If pent is NULL, the provider doesn't have a kcf.conf entry. */ void print_kef_policy(char *provname, entry_t *pent, boolean_t has_random, boolean_t has_mechs) { mechlist_t *ptr = NULL; boolean_t rnd_disabled = B_FALSE; if (pent != NULL) { rnd_disabled = filter_mechlist(&pent->dislist, RANDOM); ptr = pent->dislist; } (void) printf("%s:", provname); if (has_mechs == B_TRUE) { /* * TRANSLATION_NOTE * This code block may need to be modified a bit to avoid * constructing the text message on the fly. */ (void) printf(gettext(" all mechanisms are enabled")); if (ptr != NULL) (void) printf(gettext(", except ")); while (ptr != NULL) { (void) printf("%s", ptr->name); ptr = ptr->next; if (ptr != NULL) (void) printf(","); } if (ptr == NULL) (void) printf("."); } /* * TRANSLATION_NOTE * "random" is a keyword and not to be translated. */ if (rnd_disabled) (void) printf(gettext(" %s is disabled."), "random"); else if (has_random) (void) printf(gettext(" %s is enabled."), "random"); (void) printf("\n"); } /* * Check if a kernel software provider is in the kernel. * * Parameters: * provname Provider name * psoftlist_kernel Optional software provider list. If NULL, it will be * obtained from get_soft_list(). * in_kernel Set to B_TRUE if device is in the kernel, else B_FALSE */ int check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist_kernel, boolean_t *in_kernel) { char *ptr; int i; boolean_t psoftlist_allocated = B_FALSE; if (provname == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } if (psoftlist_kernel == NULL) { if (get_soft_list(&psoftlist_kernel) == FAILURE) { cryptodebug("failed to get the software provider list" " from kernel."); return (FAILURE); } psoftlist_allocated = B_TRUE; } *in_kernel = B_FALSE; ptr = psoftlist_kernel->sl_soft_names; for (i = 0; i < psoftlist_kernel->sl_soft_count; i++) { if (strcmp(provname, ptr) == 0) { *in_kernel = B_TRUE; break; } ptr = ptr + strlen(ptr) + 1; } if (psoftlist_allocated) free(psoftlist_kernel); return (SUCCESS); } /* * Check if a kernel hardware provider is in the kernel. * * Parameters: * provname Provider name * pdevlist Optional Hardware Crypto Device List. If NULL, it will be * obtained from get_dev_list(). * in_kernel Set to B_TRUE if device is in the kernel, otherwise B_FALSE */ int check_kernel_for_hard(char *provname, crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel) { char devname[MAXNAMELEN]; int inst_num; int i; boolean_t dev_list_allocated = B_FALSE; if (provname == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } if (split_hw_provname(provname, devname, &inst_num) == FAILURE) { return (FAILURE); } if (pdevlist == NULL) { if (get_dev_list(&pdevlist) == FAILURE) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } dev_list_allocated = B_TRUE; } *in_kernel = B_FALSE; for (i = 0; i < pdevlist->dl_dev_count; i++) { if ((strcmp(pdevlist->dl_devs[i].le_dev_name, devname) == 0) && (pdevlist->dl_devs[i].le_dev_instance == inst_num)) { *in_kernel = B_TRUE; break; } } if (dev_list_allocated) free(pdevlist); return (SUCCESS); } /* * 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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Administration for metaslot * * All the "list" operations will call functions in libpkcs11.so * Normally, it doesn't make sense to call functions in libpkcs11.so directly * because libpkcs11.so depends on the configuration file (pkcs11.conf) the * cryptoadm command is trying to administer. However, since metaslot * is part of the framework, it is not possible to get information about * it without actually calling functions in libpkcs11.so. * * So, for the listing operation, which won't modify the value of pkcs11.conf * it is safe to call libpkcs11.so. * * For other operations that modifies the pkcs11.conf file, libpkcs11.so * will not be called. * */ #include #include #include #include #include #include #include #include #include "cryptoadm.h" #define METASLOT_ID 0 int list_metaslot_info(boolean_t show_mechs, boolean_t verbose, mechlist_t *mechlist) { int rc = SUCCESS; CK_RV rv; CK_SLOT_INFO slot_info; CK_TOKEN_INFO token_info; CK_MECHANISM_TYPE_PTR pmech_list = NULL; CK_ULONG mech_count; int i; CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR); CK_FUNCTION_LIST_PTR funcs; void *dldesc = NULL; boolean_t lib_initialized = B_FALSE; uentry_t *puent; char buf[128]; /* * Display the system-wide metaslot settings as specified * in pkcs11.conf file. */ if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } (void) printf(gettext("System-wide Meta Slot Configuration:\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")); (void) printf(gettext("Status: %s\n"), puent->flag_metaslot_enabled ? gettext("enabled") : gettext("disabled")); (void) printf(gettext("Sensitive Token Object Automatic Migrate: %s\n"), puent->flag_metaslot_auto_key_migrate ? gettext("enabled") : gettext("disabled")); bzero(buf, sizeof (buf)); if (memcmp(puent->metaslot_ks_slot, buf, SLOT_DESCRIPTION_SIZE) != 0) { (void) printf(gettext("Persistent object store slot: %s\n"), puent->metaslot_ks_slot); } if (memcmp(puent->metaslot_ks_token, buf, TOKEN_LABEL_SIZE) != 0) { (void) printf(gettext("Persistent object store token: %s\n"), puent->metaslot_ks_token); } if ((!verbose) && (!show_mechs)) { return (SUCCESS); } if (verbose) { (void) printf(gettext("\nDetailed Meta Slot Information:\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")); } /* * Need to actually make calls to libpkcs11.so to get * information about metaslot. */ dldesc = dlopen(UEF_FRAME_LIB, RTLD_NOW); if (dldesc == NULL) { char *dl_error; dl_error = dlerror(); cryptodebug("Cannot load PKCS#11 framework library. " "dlerror:%s", dl_error); return (FAILURE); } /* Get the pointer to library's C_GetFunctionList() */ Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList"); if (Tmp_C_GetFunctionList == NULL) { cryptodebug("Cannot get the address of the C_GetFunctionList " "from framework"); rc = FAILURE; goto finish; } /* Get the provider's function list */ rv = Tmp_C_GetFunctionList(&funcs); if (rv != CKR_OK) { cryptodebug("failed to call C_GetFunctionList in " "framework library"); rc = FAILURE; goto finish; } /* Initialize this provider */ rv = funcs->C_Initialize(NULL_PTR); if (rv != CKR_OK) { cryptodebug("C_Initialize failed with error code 0x%x\n", rv); rc = FAILURE; goto finish; } else { lib_initialized = B_TRUE; } /* * We know for sure that metaslot is slot 0 in the framework, * so, we will do a C_GetSlotInfo() trying to see if it works. * If it fails with CKR_SLOT_ID_INVALID, we know that metaslot * is not really enabled. */ rv = funcs->C_GetSlotInfo(METASLOT_ID, &slot_info); if (rv == CKR_SLOT_ID_INVALID) { (void) printf(gettext("actual status: disabled.\n")); /* * Even if the -m and -v flag is supplied, there's nothing * interesting to display about metaslot since it is disabled, * so, just stop right here. */ goto finish; } if (rv != CKR_OK) { cryptodebug("C_GetSlotInfo failed with error " "code 0x%x\n", rv); rc = FAILURE; goto finish; } if (!verbose) { goto display_mechs; } (void) printf(gettext("actual status: enabled.\n")); (void) printf(gettext("Description: %.64s\n"), slot_info.slotDescription); (void) printf(gettext("Token Present: %s\n"), (slot_info.flags & CKF_TOKEN_PRESENT ? gettext("True") : gettext("False"))); rv = funcs->C_GetTokenInfo(METASLOT_ID, &token_info); if (rv != CKR_OK) { cryptodebug("C_GetTokenInfo failed with error " "code 0x%x\n", rv); rc = FAILURE; goto finish; } (void) printf(gettext("Token Label: %.32s\n" "Manufacturer ID: %.32s\n" "Model: %.16s\n" "Serial Number: %.16s\n" "Hardware Version: %d.%d\n" "Firmware Version: %d.%d\n" "UTC Time: %.16s\n" "PIN Min Length: %d\n" "PIN Max Length: %d\n"), token_info.label, token_info.manufacturerID, token_info.model, token_info.serialNumber, token_info.hardwareVersion.major, token_info.hardwareVersion.minor, token_info.firmwareVersion.major, token_info.firmwareVersion.minor, token_info.utcTime, token_info.ulMinPinLen, token_info.ulMaxPinLen); display_token_flags(token_info.flags); if (!show_mechs) { goto finish; } display_mechs: if (mechlist == NULL) { rv = funcs->C_GetMechanismList(METASLOT_ID, NULL_PTR, &mech_count); if (rv != CKR_OK) { cryptodebug("C_GetMechanismList failed with error " "code 0x%x\n", rv); rc = FAILURE; goto finish; } if (mech_count > 0) { pmech_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE)); if (pmech_list == NULL) { cryptodebug("out of memory"); rc = FAILURE; goto finish; } rv = funcs->C_GetMechanismList(METASLOT_ID, pmech_list, &mech_count); if (rv != CKR_OK) { cryptodebug("C_GetMechanismList failed with " "error code 0x%x\n", rv); rc = FAILURE; goto finish; } } } else { rc = convert_mechlist(&pmech_list, &mech_count, mechlist); if (rc != SUCCESS) { goto finish; } } (void) printf(gettext("Mechanisms:\n")); if (mech_count == 0) { /* should never be this case */ (void) printf(gettext("No mechanisms\n")); goto finish; } if (verbose) { display_verbose_mech_header(); } for (i = 0; i < mech_count; i++) { CK_MECHANISM_TYPE mech = pmech_list[i]; if (mech >= CKM_VENDOR_DEFINED) { (void) printf("%#lx", mech); } else { (void) printf("%-29s", pkcs11_mech2str(mech)); } if (verbose) { CK_MECHANISM_INFO mech_info; rv = funcs->C_GetMechanismInfo(METASLOT_ID, mech, &mech_info); if (rv != CKR_OK) { cryptodebug("C_GetMechanismInfo failed with " "error code 0x%x\n", rv); rc = FAILURE; goto finish; } display_mech_info(&mech_info); } (void) printf("\n"); } finish: if ((rc == FAILURE) && (show_mechs)) { (void) printf(gettext( "metaslot: failed to retrieve the mechanism list.\n")); } if (lib_initialized) { (void) funcs->C_Finalize(NULL_PTR); } if (dldesc != NULL) { (void) dlclose(dldesc); } if (pmech_list != NULL) { (void) free(pmech_list); } return (rc); } int list_metaslot_policy() { uentry_t *puent; int rc; if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } rc = display_policy(puent); (void) printf("\n"); free_uentry(puent); return (rc); } /* * disable metaslot and some of its configuration options * * If mechlist==NULL, and the other 2 flags are false, just disabled * the metaslot feature. * * mechlist: list of mechanisms to disable * allflag: if true, indicates all mechanisms should be disabled. * auto_key_migrate_flag: if true, indicates auto key migrate should be disabled */ int disable_metaslot(mechlist_t *mechlist, boolean_t allflag, boolean_t auto_key_migrate_flag) { uentry_t *puent; int rc = SUCCESS; if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } if ((mechlist == NULL) && (!auto_key_migrate_flag) && (!allflag)) { /* disable metaslot */ puent->flag_metaslot_enabled = B_FALSE; goto write_to_file; } if (auto_key_migrate_flag) { /* need to disable auto_key_migrate */ puent->flag_metaslot_auto_key_migrate = B_FALSE; } if ((mechlist == NULL) && (!allflag)) { goto write_to_file; } /* disable specified mechanisms */ if (allflag) { free_umechlist(puent->policylist); puent->policylist = NULL; puent->count = 0; puent->flag_enabledlist = B_TRUE; rc = SUCCESS; } else { if (puent->flag_enabledlist == B_TRUE) { /* * The current default policy mode * is "all are disabled, except ...", so if a * specified mechanism is in the exception list * (the policylist), delete it from the policylist. */ rc = update_policylist(puent, mechlist, DELETE_MODE); } else { /* * The current default policy mode of this library * is "all are enabled", so if a specified mechanism * is not in the exception list (policylist), add * it into the policylist. */ rc = update_policylist(puent, mechlist, ADD_MODE); } } if (rc != SUCCESS) { goto finish; } /* If all mechanisms are disabled, metaslot will be disabled as well */ if ((puent->flag_enabledlist) && (puent->count == 0)) { puent->flag_metaslot_enabled = B_FALSE; } write_to_file: rc = update_pkcs11conf(puent); finish: free_uentry(puent); return (rc); } /* * enable metaslot and some of its configuration options * * If mechlist==NULL, and the other flags are false, or not specified, * just enable the metaslot feature. * * token: if specified, indicate label of token to be used as keystore. * slot: if specified, indicate slot to be used as keystore. * use_default: if true, indicate to use the default keystore. It should * not be specified if either token or slot is specified. * mechlist: list of mechanisms to enable * allflag: if true, indicates all mechanisms should be enabled. * auto_key_migrate_flag: if true, indicates auto key migrate should be enabled */ int enable_metaslot(char *token, char *slot, boolean_t use_default, mechlist_t *mechlist, boolean_t allflag, boolean_t auto_key_migrate_flag) { uentry_t *puent; int rc = SUCCESS; if ((puent = getent_uef(METASLOT_KEYWORD)) == NULL) { cryptoerror(LOG_STDERR, gettext("metaslot entry doesn't exist.")); return (FAILURE); } puent->flag_metaslot_enabled = B_TRUE; if (auto_key_migrate_flag) { /* need to enable auto_key_migrate */ puent->flag_metaslot_auto_key_migrate = B_TRUE; } if (allflag) { /* * If enabling all, what needs to be done are cleaning up the * policylist and setting the "flag_enabledlist" flag to * B_FALSE. */ free_umechlist(puent->policylist); puent->policylist = NULL; puent->count = 0; puent->flag_enabledlist = B_FALSE; rc = SUCCESS; } else { if (mechlist) { if (puent->flag_enabledlist == B_TRUE) { /* * The current default policy mode of this * library is "all are disabled, except ...", * so if a specified mechanism is not in the * exception list (policylist), add it. */ rc = update_policylist(puent, mechlist, ADD_MODE); } else { /* * The current default policy mode of this * library is "all are enabled, except", so if * a specified mechanism is in the exception * list (policylist), delete it. */ rc = update_policylist(puent, mechlist, DELETE_MODE); } } } if (rc != SUCCESS) { goto finish; } if (!use_default && !token && !slot) { /* no need to change metaslot keystore */ goto write_to_file; } (void) bzero((char *)puent->metaslot_ks_token, TOKEN_LABEL_SIZE); (void) bzero((char *)puent->metaslot_ks_slot, SLOT_DESCRIPTION_SIZE); if (use_default) { (void) strlcpy((char *)puent->metaslot_ks_token, SOFT_TOKEN_LABEL, TOKEN_LABEL_SIZE); (void) strlcpy((char *)puent->metaslot_ks_slot, SOFT_SLOT_DESCRIPTION, SLOT_DESCRIPTION_SIZE); } else { if (token) { (void) strlcpy((char *)puent->metaslot_ks_token, token, TOKEN_LABEL_SIZE); } if (slot) { (void) strlcpy((char *)puent->metaslot_ks_slot, slot, SLOT_DESCRIPTION_SIZE); } } write_to_file: rc = update_pkcs11conf(puent); finish: free_uentry(puent); return (rc); } /* * 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 2010 Nexenta Systems, Inc. All rights resrved. * Copyright (c) 2018, Joyent, Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cryptoadm.h" #define HDR1 " P\n" #define HDR2 " S V K a U D\n" #define HDR3 " i e e i n e\n" #define HDR4 " S g V r y r W w r\n" #define HDR5 " E D D i n e i G G r r i\n" #define HDR6 " H n e i g + r + e e a a v E\n" #define HDR7 "min max W c c g n R i R n n p p e C\n" static int err; /* To store errno which may be overwritten by gettext() */ static boolean_t is_in_policylist(midstr_t, umechlist_t *); static char *uent2str(uentry_t *); static boolean_t check_random(CK_SLOT_ID, CK_FUNCTION_LIST_PTR); static void display_slot_flags(CK_FLAGS flags) { (void) printf(gettext("Slot Flags: ")); if (flags & CKF_TOKEN_PRESENT) (void) printf("CKF_TOKEN_PRESENT "); if (flags & CKF_REMOVABLE_DEVICE) (void) printf("CKF_REMOVABLE_DEVICE "); if (flags & CKF_HW_SLOT) (void) printf("CKF_HW_SLOT "); (void) printf("\n"); } void display_token_flags(CK_FLAGS flags) { (void) printf(gettext("Flags: ")); if (flags & CKF_RNG) (void) printf("CKF_RNG "); if (flags & CKF_WRITE_PROTECTED) (void) printf("CKF_WRITE_PROTECTED "); if (flags & CKF_LOGIN_REQUIRED) (void) printf("CKF_LOGIN_REQUIRED "); if (flags & CKF_USER_PIN_INITIALIZED) (void) printf("CKF_USER_PIN_INITIALIZED "); if (flags & CKF_RESTORE_KEY_NOT_NEEDED) (void) printf("CKF_RESTORE_KEY_NOT_NEEDED "); if (flags & CKF_CLOCK_ON_TOKEN) (void) printf("CKF_CLOCK_ON_TOKEN "); if (flags & CKF_PROTECTED_AUTHENTICATION_PATH) (void) printf("CKF_PROTECTED_AUTHENTICATION_PATH "); if (flags & CKF_DUAL_CRYPTO_OPERATIONS) (void) printf("CKF_DUAL_CRYPTO_OPERATIONS "); if (flags & CKF_TOKEN_INITIALIZED) (void) printf("CKF_TOKEN_INITIALIZED "); if (flags & CKF_SECONDARY_AUTHENTICATION) (void) printf("CKF_SECONDARY_AUTHENTICATION "); if (flags & CKF_USER_PIN_COUNT_LOW) (void) printf("CKF_USER_PIN_COUNT_LOW "); if (flags & CKF_USER_PIN_FINAL_TRY) (void) printf("CKF_USER_PIN_FINAL_TRY "); if (flags & CKF_USER_PIN_LOCKED) (void) printf("CKF_USER_PIN_LOCKED "); if (flags & CKF_USER_PIN_TO_BE_CHANGED) (void) printf("CKF_USER_PIN_TO_BE_CHANGED "); if (flags & CKF_SO_PIN_COUNT_LOW) (void) printf("CKF_SO_PIN_COUNT_LOW "); if (flags & CKF_SO_PIN_FINAL_TRY) (void) printf("CKF_SO_PIN_FINAL_TRY "); if (flags & CKF_SO_PIN_LOCKED) (void) printf("CKF_SO_PIN_LOCKED "); if (flags & CKF_SO_PIN_TO_BE_CHANGED) (void) printf("CKF_SO_PIN_TO_BE_CHANGED "); if (flags & CKF_SO_PIN_TO_BE_CHANGED) (void) printf("CKF_SO_PIN_TO_BE_CHANGED "); (void) printf("\n"); } void display_mech_info(CK_MECHANISM_INFO *mechInfo) { CK_FLAGS ec_flags = CKF_EC_F_P | CKF_EC_F_2M | CKF_EC_ECPARAMETERS | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS | CKF_EC_COMPRESS; (void) printf("%-4ld %-4ld ", mechInfo->ulMinKeySize, mechInfo->ulMaxKeySize); (void) printf("%s %s %s %s %s %s %s %s %s %s %s %s " "%s %s", (mechInfo->flags & CKF_HW) ? "X" : ".", (mechInfo->flags & CKF_ENCRYPT) ? "X" : ".", (mechInfo->flags & CKF_DECRYPT) ? "X" : ".", (mechInfo->flags & CKF_DIGEST) ? "X" : ".", (mechInfo->flags & CKF_SIGN) ? "X" : ".", (mechInfo->flags & CKF_SIGN_RECOVER) ? "X" : ".", (mechInfo->flags & CKF_VERIFY) ? "X" : ".", (mechInfo->flags & CKF_VERIFY_RECOVER) ? "X" : ".", (mechInfo->flags & CKF_GENERATE) ? "X" : ".", (mechInfo->flags & CKF_GENERATE_KEY_PAIR) ? "X" : ".", (mechInfo->flags & CKF_WRAP) ? "X" : ".", (mechInfo->flags & CKF_UNWRAP) ? "X" : ".", (mechInfo->flags & CKF_DERIVE) ? "X" : ".", (mechInfo->flags & ec_flags) ? "X" : "."); } /* * Converts the provided list of mechanism names in their string format to * their corresponding PKCS#11 mechanism IDs. * * The list of mechanism names to be converted is provided in the * "mlist" argument. The list of converted mechanism IDs is returned * in the "pmech_list" argument. * * This function is called by list_metaslot_info() and * list_mechlist_for_lib() functions. */ int convert_mechlist(CK_MECHANISM_TYPE **pmech_list, CK_ULONG *mech_count, mechlist_t *mlist) { int i, n = 0; mechlist_t *p = mlist; while (p != NULL) { p = p->next; n++; } *pmech_list = malloc(n * sizeof (CK_MECHANISM_TYPE)); if (*pmech_list == NULL) { cryptodebug("out of memory"); return (FAILURE); } p = mlist; for (i = 0; i < n; i++) { if (pkcs11_str2mech(p->name, &(*pmech_list[i])) != CKR_OK) { free(*pmech_list); return (FAILURE); } p = p->next; } *mech_count = n; return (SUCCESS); } /* * Display the mechanism list for a user-level library */ int list_mechlist_for_lib(char *libname, mechlist_t *mlist, flag_val_t *rng_flag, boolean_t no_warn, boolean_t verbose, boolean_t show_mechs) { CK_RV rv = CKR_OK; CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR); CK_FUNCTION_LIST_PTR prov_funcs; /* Provider's function list */ CK_SLOT_ID_PTR prov_slots = NULL; /* Provider's slot list */ CK_MECHANISM_TYPE_PTR pmech_list = NULL; /* mech list for a slot */ CK_SLOT_INFO slotinfo; CK_ULONG slot_count; CK_ULONG mech_count; uentry_t *puent = NULL; boolean_t lib_initialized = B_FALSE; void *dldesc = NULL; char *dl_error; const char *mech_name; char *isa; char libpath[MAXPATHLEN]; char buf[MAXPATHLEN]; int i, j; int rc = SUCCESS; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("list_mechlist_for_lib() - libname is NULL."); return (FAILURE); } /* Check if the library is in the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } free_uentry(puent); /* Remove $ISA from the library name */ if (strlcpy(buf, libname, sizeof (buf)) >= sizeof (buf)) { (void) printf(gettext("%s: the provider name is too long."), libname); return (FAILURE); } if ((isa = strstr(buf, PKCS11_ISA)) != NULL) { *isa = '\000'; isa += strlen(PKCS11_ISA); (void) snprintf(libpath, MAXPATHLEN, "%s%s%s", buf, "/", isa); } else { (void) strlcpy(libpath, libname, sizeof (libpath)); } /* * Open the provider. Use RTLD_NOW here, as a way to * catch any providers with incomplete symbols that * might otherwise cause problems during libpkcs11's * execution. */ dldesc = dlopen(libpath, RTLD_NOW); if (dldesc == NULL) { dl_error = dlerror(); cryptodebug("Cannot load PKCS#11 library %s. dlerror: %s", libname, dl_error != NULL ? dl_error : "Unknown"); rc = FAILURE; goto clean_exit; } /* Get the pointer to provider's C_GetFunctionList() */ Tmp_C_GetFunctionList = (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList"); if (Tmp_C_GetFunctionList == NULL) { cryptodebug("Cannot get the address of the C_GetFunctionList " "from %s", libname); rc = FAILURE; goto clean_exit; } /* Get the provider's function list */ rv = Tmp_C_GetFunctionList(&prov_funcs); if (rv != CKR_OK) { cryptodebug("failed to call C_GetFunctionList from %s", libname); rc = FAILURE; goto clean_exit; } /* Initialize this provider */ rv = prov_funcs->C_Initialize(NULL_PTR); if (rv != CKR_OK) { cryptodebug("failed to call C_Initialize from %s, " "return code = %d", libname, rv); rc = FAILURE; goto clean_exit; } else { lib_initialized = B_TRUE; } /* * Find out how many slots this provider has, call with tokenPresent * set to FALSE so all potential slots are returned. */ rv = prov_funcs->C_GetSlotList(FALSE, NULL_PTR, &slot_count); if (rv != CKR_OK) { cryptodebug("failed to get the slotlist from %s.", libname); rc = FAILURE; goto clean_exit; } else if (slot_count == 0) { if (!no_warn) (void) printf(gettext("%s: no slots presented.\n"), libname); rc = SUCCESS; goto clean_exit; } /* Allocate memory for the slot list */ prov_slots = malloc(slot_count * sizeof (CK_SLOT_ID)); if (prov_slots == NULL) { cryptodebug("out of memory."); rc = FAILURE; goto clean_exit; } /* Get the slot list from provider */ rv = prov_funcs->C_GetSlotList(FALSE, prov_slots, &slot_count); if (rv != CKR_OK) { cryptodebug("failed to call C_GetSlotList() from %s.", libname); rc = FAILURE; goto clean_exit; } if (verbose) { (void) printf(gettext("Number of slots: %d\n"), slot_count); } /* Get the mechanism list for each slot */ for (i = 0; i < slot_count; i++) { if (verbose) /* * TRANSLATION_NOTE * In some languages, the # symbol should be * converted to "no", an "n" followed by a * superscript "o".. */ (void) printf(gettext("\nSlot #%d\n"), i+1); if ((rng_flag != NULL) && (*rng_flag == NO_RNG)) { if (check_random(prov_slots[i], prov_funcs)) { *rng_flag = HAS_RNG; rc = SUCCESS; goto clean_exit; } else continue; } rv = prov_funcs->C_GetSlotInfo(prov_slots[i], &slotinfo); if (rv != CKR_OK) { cryptodebug("failed to get slotinfo from %s", libname); rc = FAILURE; break; } if (verbose) { CK_TOKEN_INFO tokeninfo; (void) printf(gettext("Description: %.64s\n" "Manufacturer: %.32s\n" "PKCS#11 Version: %d.%d\n"), slotinfo.slotDescription, slotinfo.manufacturerID, prov_funcs->version.major, prov_funcs->version.minor); (void) printf(gettext("Hardware Version: %d.%d\n" "Firmware Version: %d.%d\n"), slotinfo.hardwareVersion.major, slotinfo.hardwareVersion.minor, slotinfo.firmwareVersion.major, slotinfo.firmwareVersion.minor); (void) printf(gettext("Token Present: %s\n"), (slotinfo.flags & CKF_TOKEN_PRESENT ? gettext("True") : gettext("False"))); display_slot_flags(slotinfo.flags); rv = prov_funcs->C_GetTokenInfo(prov_slots[i], &tokeninfo); if (rv != CKR_OK) { cryptodebug("Failed to get " "token info from %s", libname); rc = FAILURE; break; } (void) printf(gettext("Token Label: %.32s\n" "Manufacturer ID: %.32s\n" "Model: %.16s\n" "Serial Number: %.16s\n" "Hardware Version: %d.%d\n" "Firmware Version: %d.%d\n" "UTC Time: %.16s\n" "PIN Min Length: %d\n" "PIN Max Length: %d\n"), tokeninfo.label, tokeninfo.manufacturerID, tokeninfo.model, tokeninfo.serialNumber, tokeninfo.hardwareVersion.major, tokeninfo.hardwareVersion.minor, tokeninfo.firmwareVersion.major, tokeninfo.firmwareVersion.minor, tokeninfo.utcTime, tokeninfo.ulMinPinLen, tokeninfo.ulMaxPinLen); display_token_flags(tokeninfo.flags); } if (mlist == NULL) { rv = prov_funcs->C_GetMechanismList(prov_slots[i], NULL_PTR, &mech_count); if (rv != CKR_OK) { cryptodebug( "failed to call C_GetMechanismList() " "from %s.", libname); rc = FAILURE; break; } if (mech_count == 0) { /* no mechanisms in this slot */ continue; } pmech_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE)); if (pmech_list == NULL) { cryptodebug("out of memory"); rc = FAILURE; break; } /* Get the actual mechanism list */ rv = prov_funcs->C_GetMechanismList(prov_slots[i], pmech_list, &mech_count); if (rv != CKR_OK) { cryptodebug( "failed to call C_GetMechanismList() " "from %s.", libname); free(pmech_list); rc = FAILURE; break; } } else { /* use the mechanism list passed in */ rc = convert_mechlist(&pmech_list, &mech_count, mlist); if (rc != SUCCESS) { goto clean_exit; } } if (show_mechs) (void) printf(gettext("Mechanisms:\n")); if (verbose && show_mechs) { display_verbose_mech_header(); } /* * Merge the current mechanism list into the returning * mechanism list. */ for (j = 0; show_mechs && j < mech_count; j++) { CK_MECHANISM_TYPE mech = pmech_list[j]; CK_MECHANISM_INFO mech_info; rv = prov_funcs->C_GetMechanismInfo( prov_slots[i], mech, &mech_info); if (rv != CKR_OK) { cryptodebug( "failed to call " "C_GetMechanismInfo() from %s.", libname); free(pmech_list); pmech_list = NULL; rc = FAILURE; break; } if (mech >= CKM_VENDOR_DEFINED) { (void) printf("%#lx", mech); } else { mech_name = pkcs11_mech2str(mech); (void) printf("%-29s", mech_name); } if (verbose) { display_mech_info(&mech_info); } (void) printf("\n"); } if (pmech_list) free(pmech_list); if (rc == FAILURE) { break; } } if (rng_flag != NULL || rc == FAILURE) { goto clean_exit; } clean_exit: if (rc == FAILURE) { (void) printf(gettext( "%s: failed to retrieve the mechanism list.\n"), libname); } if (lib_initialized) { (void) prov_funcs->C_Finalize(NULL_PTR); } if (dldesc != NULL) { (void) dlclose(dldesc); } if (prov_slots != NULL) { free(prov_slots); } return (rc); } /* * Display the mechanism policy for a user-level library */ int list_policy_for_lib(char *libname) { uentry_t *puent = NULL; int rc; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("list_policy_for_lib() - libname is NULL."); return (FAILURE); } /* Get the library entry from the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } /* Print the policy for this library */ rc = print_uef_policy(puent); free_uentry(puent); return (rc); } /* * Disable mechanisms for a user-level library */ int disable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag, mechlist_t *marglist) { uentry_t *puent; int rc; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("disable_uef_lib() - libname is NULL."); return (FAILURE); } /* Get the provider entry from the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } /* * Update the mechanism policy of this library entry, based on * the current policy mode of the library and the mechanisms specified * in CLI. */ if (allflag) { /* * If disabling all, just need to clean up the policylist and * set the flag_enabledlist flag to be B_TRUE. */ free_umechlist(puent->policylist); puent->policylist = NULL; puent->count = 0; puent->flag_enabledlist = B_TRUE; rc = SUCCESS; } else if (marglist != NULL) { if (puent->flag_enabledlist == B_TRUE) { /* * The current default policy mode of this library * is "all are disabled, except ...", so if a * specified mechanism is in the exception list * (the policylist), delete it from the policylist. */ rc = update_policylist(puent, marglist, DELETE_MODE); } else { /* * The current default policy mode of this library * is "all are enabled", so if a specified mechanism * is not in the exception list (policylist), add * it into the policylist. */ rc = update_policylist(puent, marglist, ADD_MODE); } } else if (!rndflag) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("disable_uef_lib() - wrong arguments."); return (FAILURE); } if (rndflag) puent->flag_norandom = B_TRUE; if (rc == FAILURE) { free_uentry(puent); return (FAILURE); } /* Update the pkcs11.conf file with the updated entry */ rc = update_pkcs11conf(puent); free_uentry(puent); return (rc); } /* * Enable disabled mechanisms for a user-level library. */ int enable_uef_lib(char *libname, boolean_t rndflag, boolean_t allflag, mechlist_t *marglist) { uentry_t *puent; int rc = SUCCESS; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("enable_uef_lib() - libname is NULL."); return (FAILURE); } /* Get the provider entry from the pkcs11.conf file */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } /* * Update the mechanism policy of this library entry, based on * the current policy mode of the library and the mechanisms * specified in CLI. */ if (allflag) { /* * If enabling all, what needs to be done are cleaning up the * policylist and setting the "flag_enabledlist" flag to * B_FALSE. */ free_umechlist(puent->policylist); puent->policylist = NULL; puent->count = 0; puent->flag_enabledlist = B_FALSE; rc = SUCCESS; } else if (marglist != NULL) { if (puent->flag_enabledlist == B_TRUE) { /* * The current default policy mode of this library * is "all are disabled, except ...", so if a * specified mechanism is not in the exception list * (policylist), add it. */ rc = update_policylist(puent, marglist, ADD_MODE); } else { /* * The current default policy mode of this library * is "all are enabled, except", so if a specified * mechanism is in the exception list (policylist), * delete it. */ rc = update_policylist(puent, marglist, DELETE_MODE); } } else if (!rndflag) { /* should not come here */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("enable_uef_lib() - wrong arguments."); return (FAILURE); } if (rndflag) puent->flag_norandom = B_FALSE; if (rc == FAILURE) { free_uentry(puent); return (FAILURE); } /* Update the pkcs11.conf file with the updated entry */ rc = update_pkcs11conf(puent); free_uentry(puent); return (rc); } /* * Install a user-level library. */ int install_uef_lib(char *libname) { uentry_t *puent; struct stat statbuf; char libpath[MAXPATHLEN]; char libbuf[MAXPATHLEN]; char *isa; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("install_uef_lib() - libname is NULL."); return (FAILURE); } /* Check if the provider already exists in the framework */ if ((puent = getent_uef(libname)) != NULL) { cryptoerror(LOG_STDERR, gettext("%s exists already."), libname); free_uentry(puent); return (FAILURE); } /* * Check if the library exists in the system. if $ISA is in the * path, only check the 32bit version. */ if (strlcpy(libbuf, libname, MAXPATHLEN) >= MAXPATHLEN) { cryptoerror(LOG_STDERR, gettext("the provider name is too long - %s"), libname); return (FAILURE); } if ((isa = strstr(libbuf, PKCS11_ISA)) != NULL) { *isa = '\000'; isa += strlen(PKCS11_ISA); (void) snprintf(libpath, sizeof (libpath), "%s%s%s", libbuf, "/", isa); } else { (void) strlcpy(libpath, libname, sizeof (libpath)); } /* Check if it is same as the framework library */ if (strcmp(libpath, UEF_FRAME_LIB) == 0) { cryptoerror(LOG_STDERR, gettext( "The framework library %s can not be installed."), libname); return (FAILURE); } if (stat(libpath, &statbuf) != 0) { cryptoerror(LOG_STDERR, gettext("%s not found"), libname); return (FAILURE); } /* Need to add "\n" to libname for adding into the config file */ if (strlcat(libname, "\n", MAXPATHLEN) >= MAXPATHLEN) { cryptoerror(LOG_STDERR, gettext( "can not install %s; the name is too long."), libname); return (FAILURE); } return (update_conf(_PATH_PKCS11_CONF, libname)); } /* * Uninstall a user-level library. */ int uninstall_uef_lib(char *libname) { uentry_t *puent; FILE *pfile; FILE *pfile_tmp; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; char tmpfile_name[MAXPATHLEN]; char *name; boolean_t found; boolean_t in_package; int len; int rc = SUCCESS; if (libname == NULL) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("uninstall_uef_lib() - libname is NULL."); return (FAILURE); } /* Check if the provider exists */ if ((puent = getent_uef(libname)) == NULL) { cryptoerror(LOG_STDERR, gettext("%s does not exist."), libname); return (FAILURE); } free_uentry(puent); /* Open the pkcs11.conf file and lock it */ if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF); return (FAILURE); } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to lock the configuration - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory to save * the new configuration file first. */ (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to create a temporary file - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), tmpfile_name, strerror(err)); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } (void) fclose(pfile); return (FAILURE); } /* * Loop thru the config file. If the library to be uninstalled * is in a package, just comment it off. */ in_package = B_FALSE; while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (!(buffer[0] == ' ' || buffer[0] == '\n' || buffer[0] == '\t')) { if (strstr(buffer, " Start ") != NULL) { in_package = B_TRUE; } else if (strstr(buffer, " End ") != NULL) { in_package = B_FALSE; } else if (buffer[0] != '#') { (void) strlcpy(buffer2, buffer, BUFSIZ); /* get rid of trailing '\n' */ len = strlen(buffer2); if (buffer2[len-1] == '\n') { len--; } buffer2[len] = '\0'; if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(libname, name) == 0) { found = B_TRUE; } } } if (found) { if (in_package) { (void) snprintf(buffer2, sizeof (buffer2), "%s%s%s", "#", libname, "\n"); if (fputs(buffer2, pfile_tmp) == EOF) { rc = FAILURE; } } } else { if (fputs(buffer, pfile_tmp) == EOF) { rc = FAILURE; } } if (rc == FAILURE) { break; } } if (rc == FAILURE) { cryptoerror(LOG_STDERR, gettext("write error.")); (void) fclose(pfile); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (FAILURE); } (void) fclose(pfile); if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close a temporary file - %s"), strerror(err)); return (FAILURE); } /* Now update the real config file */ if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to rename %s to %s: %s", tmpfile, _PATH_PKCS11_CONF, strerror(err)); rc = FAILURE; } else if (chmod(_PATH_PKCS11_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (rc); } int display_policy(uentry_t *puent) { CK_MECHANISM_TYPE mech_id; const char *mech_name; umechlist_t *ptr; if (puent == NULL) { return (SUCCESS); } if (puent->flag_enabledlist == B_FALSE) { (void) printf(gettext("%s: all mechanisms are enabled"), puent->name); ptr = puent->policylist; if (ptr == NULL) { (void) printf("."); } else { (void) printf(gettext(", except ")); while (ptr != NULL) { mech_id = strtoul(ptr->name, NULL, 0); if (mech_id & CKO_VENDOR_DEFINED) { /* vendor defined mechanism */ (void) printf("%s", ptr->name); } else { if (mech_id >= CKM_VENDOR_DEFINED) { (void) printf("%#lx", mech_id); } else { mech_name = pkcs11_mech2str( mech_id); if (mech_name == NULL) { return (FAILURE); } (void) printf("%s", mech_name); } } ptr = ptr->next; if (ptr == NULL) { (void) printf("."); } else { (void) printf(","); } } } } else { /* puent->flag_enabledlist == B_TRUE */ (void) printf(gettext("%s: all mechanisms are disabled"), puent->name); ptr = puent->policylist; if (ptr == NULL) { (void) printf("."); } else { (void) printf(gettext(", except ")); while (ptr != NULL) { mech_id = strtoul(ptr->name, NULL, 0); if (mech_id & CKO_VENDOR_DEFINED) { /* vendor defined mechanism */ (void) printf("%s", ptr->name); } else { mech_name = pkcs11_mech2str(mech_id); if (mech_name == NULL) { return (FAILURE); } (void) printf("%s", mech_name); } ptr = ptr->next; if (ptr == NULL) { (void) printf("."); } else { (void) printf(","); } } } } return (SUCCESS); } /* * Print out the mechanism policy for a user-level provider pointed by puent. */ int print_uef_policy(uentry_t *puent) { flag_val_t rng_flag; if (puent == NULL) { return (FAILURE); } rng_flag = NO_RNG; if (list_mechlist_for_lib(puent->name, NULL, &rng_flag, B_TRUE, B_FALSE, B_FALSE) != SUCCESS) { cryptoerror(LOG_STDERR, gettext("%s internal error."), puent->name); return (FAILURE); } if (display_policy(puent) != SUCCESS) { goto failed_exit; } if (puent->flag_norandom == B_TRUE) /* * TRANSLATION_NOTE * "random" is a keyword and not to be translated. */ (void) printf(gettext(" %s is disabled."), "random"); else { if (rng_flag == HAS_RNG) /* * TRANSLATION_NOTE * "random" is a keyword and not to be translated. */ (void) printf(gettext(" %s is enabled."), "random"); } (void) printf("\n"); return (SUCCESS); failed_exit: (void) printf(gettext("\nout of memory.\n")); return (FAILURE); } /* * Check if the mechanism is in the mechanism list. */ static boolean_t is_in_policylist(midstr_t mechname, umechlist_t *plist) { boolean_t found = B_FALSE; if (mechname == NULL) { return (B_FALSE); } while (plist != NULL) { if (strcmp(plist->name, mechname) == 0) { found = B_TRUE; break; } plist = plist->next; } return (found); } /* * Update the pkcs11.conf file with the updated entry. */ int update_pkcs11conf(uentry_t *puent) { FILE *pfile; FILE *pfile_tmp; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; char tmpfile_name[MAXPATHLEN]; char *name; char *str; int len; int rc = SUCCESS; boolean_t found; if (puent == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (FAILURE); } /* Open the pkcs11.conf file */ if ((pfile = fopen(_PATH_PKCS11_CONF, "r+")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to open %s for write.", _PATH_PKCS11_CONF); return (FAILURE); } /* Lock the pkcs11.conf file */ if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory to save * updated configuration file first. */ (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to create a temporary file - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), tmpfile_name, strerror(err)); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } (void) fclose(pfile); return (FAILURE); } /* * Loop thru entire pkcs11.conf file, update the entry to be * updated and save the updated file to the temporary file first. */ while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (!(buffer[0] == '#' || buffer[0] == ' ' || buffer[0] == '\n'|| buffer[0] == '\t')) { /* * Get the provider name from this line and check if * this is the entry to be updated. Note: can not use * "buffer" directly because strtok will change its * value. */ (void) strlcpy(buffer2, buffer, BUFSIZ); /* get rid of trailing '\n' */ len = strlen(buffer2); if (buffer2[len-1] == '\n') { len--; } buffer2[len] = '\0'; if ((name = strtok(buffer2, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(puent->name, name) == 0) { found = B_TRUE; } } if (found) { /* * This is the entry to be modified, get the updated * string. */ if ((str = uent2str(puent)) == NULL) { rc = FAILURE; break; } else { (void) strlcpy(buffer, str, BUFSIZ); free(str); } } if (fputs(buffer, pfile_tmp) == EOF) { err = errno; cryptoerror(LOG_STDERR, gettext( "failed to write to a temp file: %s."), strerror(err)); rc = FAILURE; break; } } if (rc == FAILURE) { (void) fclose(pfile); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (FAILURE); } (void) fclose(pfile); if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); return (FAILURE); } /* Copy the temporary file to the pkcs11.conf file */ if (rename(tmpfile_name, _PATH_PKCS11_CONF) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to rename %s to %s: %s", tmpfile_name, _PATH_PKCS11_CONF, strerror(err)); rc = FAILURE; } else if (chmod(_PATH_PKCS11_CONF, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to chmod to %s: %s", _PATH_PKCS11_CONF, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if ((rc == FAILURE) && (unlink(tmpfile_name) != 0)) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (rc); } /* * Convert an uentry to a character string */ static char * uent2str(uentry_t *puent) { umechlist_t *phead; boolean_t tok1_present = B_FALSE; char *buf; char blank_buf[128]; if (puent == NULL) { cryptoerror(LOG_STDERR, gettext("internal error.")); return (NULL); } buf = malloc(BUFSIZ); if (buf == NULL) { cryptoerror(LOG_STDERR, gettext("out of memory.")); return (NULL); } /* convert the library name */ if (strlcpy(buf, puent->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } /* convert the enabledlist or the disabledlist */ if (puent->flag_enabledlist == B_TRUE) { if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_ENABLED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = puent->policylist; while (phead != NULL) { if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = phead->next; if (phead != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } tok1_present = B_TRUE; } else if (puent->policylist != NULL) { if (strlcat(buf, SEP_COLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_DISABLED, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = puent->policylist; while (phead != NULL) { if (strlcat(buf, phead->name, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } phead = phead->next; if (phead != NULL) { if (strlcat(buf, SEP_COMMA, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } tok1_present = B_TRUE; } if (puent->flag_norandom == B_TRUE) { if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, EF_NORANDOM, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } if (strcmp(puent->name, METASLOT_KEYWORD) == 0) { /* write the metaslot_status= value */ if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_STATUS, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (puent->flag_metaslot_enabled) { if (strlcat(buf, ENABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } else { if (strlcat(buf, DISABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } if (!tok1_present) { tok1_present = B_TRUE; } if (strlcat(buf, SEP_SEMICOLON, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_AUTO_KEY_MIGRATE, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (puent->flag_metaslot_auto_key_migrate) { if (strlcat(buf, ENABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } else { if (strlcat(buf, DISABLED_KEYWORD, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } bzero(blank_buf, sizeof (blank_buf)); /* write metaslot_token= if specified */ if (memcmp(puent->metaslot_ks_token, blank_buf, TOKEN_LABEL_SIZE) != 0) { /* write the metaslot_status= value */ if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_TOKEN, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, (const char *)puent->metaslot_ks_token, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } /* write metaslot_slot= if specified */ if (memcmp(puent->metaslot_ks_slot, blank_buf, SLOT_DESCRIPTION_SIZE) != 0) { /* write the metaslot_status= value */ if (strlcat(buf, (tok1_present ? SEP_SEMICOLON : SEP_COLON), BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, METASLOT_SLOT, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } if (strlcat(buf, (const char *)puent->metaslot_ks_slot, BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } } } if (strlcat(buf, "\n", BUFSIZ) >= BUFSIZ) { free(buf); return (NULL); } return (buf); } /* * This function updates the default policy mode and the policy exception list * for a user-level provider based on the mechanism specified in the disable * or enable subcommand and the update mode. This function is called by the * enable_uef_lib() or disable_uef_lib(). */ int update_policylist(uentry_t *puent, mechlist_t *marglist, int update_mode) { CK_MECHANISM_TYPE mech_type; midstr_t midname; umechlist_t *phead; umechlist_t *pcur; umechlist_t *pumech; boolean_t found; int rc = SUCCESS; if ((puent == NULL) || (marglist == NULL)) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("update_policylist()- puent or marglist is NULL."); return (FAILURE); } if ((update_mode != ADD_MODE) && (update_mode != DELETE_MODE)) { /* should not happen */ cryptoerror(LOG_STDERR, gettext("internal error.")); cryptodebug("update_policylist() - update_mode is incorrect."); return (FAILURE); } /* * For each mechanism operand, get its mechanism type first. * If fails to get the mechanism type, the mechanism operand must be * invalid, gives an warning and ignore it. Otherwise, * - convert the mechanism type to the internal representation (hex) * in the pkcs11.conf file * - If update_mode == DELETE_MODE, * If the mechanism is in the policy list, delete it. * If the mechanism is not in the policy list, do nothing. * - If update_mode == ADD_MODE, * If the mechanism is not in the policy list, add it. * If the mechanism is in the policy list already, do nothing. */ while (marglist) { if (pkcs11_str2mech(marglist->name, &mech_type) != CKR_OK) { /* * This mechanism is not a valid PKCS11 mechanism, * give warning and ignore it. */ cryptoerror(LOG_STDERR, gettext( "(Warning) %s is not a valid PKCS#11 mechanism."), marglist->name); rc = FAILURE; } else { (void) snprintf(midname, sizeof (midname), "%#010x", (int)mech_type); if (update_mode == DELETE_MODE) { found = B_FALSE; phead = pcur = puent->policylist; while (!found && pcur) { if (strcmp(pcur->name, midname) == 0) { found = B_TRUE; } else { phead = pcur; pcur = pcur->next; } } if (found) { if (phead == pcur) { puent->policylist = puent->policylist->next; free(pcur); } else { phead->next = pcur->next; free(pcur); } puent->count--; if (puent->count == 0) { puent->policylist = NULL; } } } else if (update_mode == ADD_MODE) { if (!is_in_policylist(midname, puent->policylist)) { pumech = create_umech(midname); if (pumech == NULL) { rc = FAILURE; break; } phead = puent->policylist; puent->policylist = pumech; pumech->next = phead; puent->count++; } } } marglist = marglist->next; } return (rc); } /* * Open a session to the given slot and check if we can do * random numbers by asking for one byte. */ static boolean_t check_random(CK_SLOT_ID slot_id, CK_FUNCTION_LIST_PTR prov_funcs) { CK_RV rv; CK_SESSION_HANDLE hSession; CK_BYTE test_byte; CK_BYTE_PTR test_byte_ptr = &test_byte; rv = prov_funcs->C_OpenSession(slot_id, CKF_SERIAL_SESSION, NULL_PTR, NULL, &hSession); if (rv != CKR_OK) return (B_FALSE); /* We care only about the return value */ rv = prov_funcs->C_GenerateRandom(hSession, test_byte_ptr, sizeof (test_byte)); (void) prov_funcs->C_CloseSession(hSession); /* * These checks are purely to determine whether the slot can do * random numbers. So, we don't check whether the routine * succeeds. The reason we check for CKR_RANDOM_NO_RNG also is that * this error effectively means CKR_FUNCTION_NOT_SUPPORTED. */ if (rv != CKR_FUNCTION_NOT_SUPPORTED && rv != CKR_RANDOM_NO_RNG) return (B_TRUE); else return (B_FALSE); } void display_verbose_mech_header() { (void) printf("%28s %s", " ", HDR1); (void) printf("%28s %s", " ", HDR2); (void) printf("%28s %s", " ", HDR3); (void) printf("%28s %s", " ", HDR4); (void) printf("%28s %s", " ", HDR5); (void) printf("%28s %s", " ", HDR6); (void) printf("%-28.28s %s", gettext("mechanism name"), HDR7); /* * TRANSLATION_NOTE * Strictly for appearance's sake, the first header line should be * as long as the length of the translated text above. The format * lengths should all match too. */ (void) printf("%28s ---- ---- " "- - - - - - - - - - - - - -\n", gettext("----------------------------")); } /* * 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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include "cryptoadm.h" #include /* * Create one item of type mechlist_t with the mechanism name. A null is * returned to indicate that the storage space available is insufficient. */ mechlist_t * create_mech(char *name) { mechlist_t *pres = NULL; char *first, *last; if (name == NULL) { return (NULL); } pres = malloc(sizeof (mechlist_t)); if (pres == NULL) { cryptodebug("out of memory."); return (NULL); } first = name; while (isspace(*first)) /* nuke leading whitespace */ first++; (void) strlcpy(pres->name, first, sizeof (pres->name)); last = strrchr(pres->name, '\0'); last--; while (isspace(*last)) /* nuke trailing whitespace */ *last-- = '\0'; pres->next = NULL; return (pres); } void free_mechlist(mechlist_t *plist) { mechlist_t *pnext; while (plist != NULL) { pnext = plist->next; free(plist); plist = pnext; } } /* * Check if the mechanism is in the mechanism list. */ boolean_t is_in_list(char *mechname, mechlist_t *plist) { boolean_t found = B_FALSE; if (mechname == NULL) { return (B_FALSE); } while (plist != NULL) { if (strcmp(plist->name, mechname) == 0) { found = B_TRUE; break; } plist = plist->next; } return (found); } int update_conf(char *conf_file, char *entry) { boolean_t found; boolean_t fips_entry = B_FALSE; FILE *pfile; FILE *pfile_tmp; char tmpfile_name[MAXPATHLEN]; char *ptr; char *name; char buffer[BUFSIZ]; char buffer2[BUFSIZ]; int found_count; int rc = SUCCESS; int err; if ((pfile = fopen(conf_file, "r+")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to open %s for write.", conf_file); return (FAILURE); } if (lockf(fileno(pfile), F_TLOCK, 0) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to lock the configuration - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Create a temporary file in the /etc/crypto directory. */ (void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name)); if (mkstemp(tmpfile_name) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to create a temporary file - %s"), strerror(err)); (void) fclose(pfile); return (FAILURE); } if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"), tmpfile_name, strerror(err)); (void) fclose(pfile); return (FAILURE); } /* * Loop thru the config file. If the provider was reserved within a * package bracket, just uncomment it. Otherwise, append it at * the end. The resulting file will be saved in the temp file first. */ found_count = 0; rc = SUCCESS; while (fgets(buffer, BUFSIZ, pfile) != NULL) { found = B_FALSE; if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { if (buffer[0] == '#') { ptr = buffer; ptr++; if (strcmp(entry, ptr) == 0) { found = B_TRUE; found_count++; } } else { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } else if (strcmp(FIPS_KEYWORD, name) == 0) { found = B_TRUE; found_count++; fips_entry = B_TRUE; } } } else { /* _PATH_KCF_CONF */ if (buffer[0] == '#') { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; ptr++; /* skip # */ if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } } else { (void) strlcpy(buffer2, buffer, BUFSIZ); ptr = buffer2; if ((name = strtok(ptr, SEP_COLON)) == NULL) { rc = FAILURE; break; } } } if (found == B_FALSE) { if (fputs(buffer, pfile_tmp) == EOF) { rc = FAILURE; } } else { if (found_count == 1) { if (strcmp(conf_file, _PATH_PKCS11_CONF) == 0) { if (fips_entry == B_TRUE) { if (fputs(entry, pfile_tmp) == EOF) { rc = FAILURE; } fips_entry = B_FALSE; } else { if (fputs(ptr, pfile_tmp) == EOF) { rc = FAILURE; } } } else { if (fputs(entry, pfile_tmp) == EOF) { rc = FAILURE; } } } else { /* * Found a second entry with same tag name. * Should not happen. The config file * is corrupted. Give a warning and skip * this entry. */ cryptoerror(LOG_STDERR, gettext( "(Warning) Found an additional reserved " "entry for %s."), entry); } } if (rc == FAILURE) { break; } } (void) fclose(pfile); if (rc == FAILURE) { cryptoerror(LOG_STDERR, gettext("write error.")); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (FAILURE); } if (found_count == 0) { /* * The entry was not in config file before, append it to the * end of the temp file. */ if (fputs(entry, pfile_tmp) == EOF) { cryptoerror(LOG_STDERR, gettext( "failed to write to %s: %s"), tmpfile_name, strerror(errno)); (void) fclose(pfile_tmp); if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } return (FAILURE); } } if (fclose(pfile_tmp) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to close %s: %s"), tmpfile_name, strerror(err)); return (FAILURE); } if (rename(tmpfile_name, conf_file) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to rename %s to %s: %s", tmpfile_name, conf_file, strerror(err)); rc = FAILURE; } else if (chmod(conf_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) { err = errno; cryptoerror(LOG_STDERR, gettext("failed to update the configuration - %s"), strerror(err)); cryptodebug("failed to chmod to %s: %s", conf_file, strerror(err)); rc = FAILURE; } else { rc = SUCCESS; } if (rc == FAILURE) { if (unlink(tmpfile_name) != 0) { err = errno; cryptoerror(LOG_STDERR, gettext( "(Warning) failed to remove %s: %s"), tmpfile_name, strerror(err)); } } return (rc); } /* * 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); } /* * 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 2010 Nexenta Systems, Inc. All rights reserved. */ #ifndef _CRYPTOADM_H #define _CRYPTOADM_H #include #include #include #include #ifdef __cplusplus extern "C" { #endif #define TMPFILE_TEMPLATE "/etc/crypto/admXXXXXX" #define ERROR_USAGE 2 #define HW_PROVIDER_NCP 1 #define HW_PROVIDER_N2CP 2 #define HW_PROVIDER_N2RNG 3 /* * Common keywords and delimiters for pkcs11.conf and kcf.conf files are * defined in usr/lib/libcryptoutil/common/cryptoutil.h. The following is * the extra keywords and delimiters used in kcf.conf file. */ #define SEP_SLASH '/' #define EF_SUPPORTED "supportedlist=" #define EF_UNLOAD "unload" #define RANDOM "random" #define UEF_FRAME_LIB "/usr/lib/libpkcs11.so" #define ADD_MODE 1 #define DELETE_MODE 2 #define MODIFY_MODE 3 #define REFRESH 1 #define NOT_REFRESH 0 typedef char prov_name_t[MAXNAMELEN]; typedef char mech_name_t[CRYPTO_MAX_MECH_NAME]; typedef struct mechlist { mech_name_t name; struct mechlist *next; } mechlist_t; typedef struct entry { prov_name_t name; mechlist_t *suplist; /* supported list */ uint_t sup_count; mechlist_t *dislist; /* disabled list */ uint_t dis_count; boolean_t load; /* B_FALSE after cryptoadm unload */ } entry_t; typedef struct entrylist { entry_t *pent; struct entrylist *next; } entrylist_t; typedef enum { NO_RNG, HAS_RNG } flag_val_t; extern int errno; /* adm_util */ extern boolean_t is_in_list(char *, mechlist_t *); extern mechlist_t *create_mech(char *); extern void free_mechlist(mechlist_t *); /* adm_kef_util */ extern boolean_t is_device(char *); extern char *ent2str(entry_t *); extern entry_t *getent_kef(char *provname, entrylist_t *pdevlist, entrylist_t *psoftlist); extern int check_kernel_for_soft(char *provname, crypto_get_soft_list_t *psoftlist, boolean_t *in_kernel); extern int check_kernel_for_hard(char *provname, crypto_get_dev_list_t *pdevlist, boolean_t *in_kernel); extern int disable_mechs(entry_t **, mechlist_t *, boolean_t, mechlist_t *); extern int enable_mechs(entry_t **, boolean_t, mechlist_t *); extern int get_kcfconf_info(entrylist_t **, entrylist_t **); extern int get_admindev_info(entrylist_t **, entrylist_t **); extern int get_mech_count(mechlist_t *); extern entry_t *create_entry(char *provname); extern int insert_kcfconf(entry_t *); extern int split_hw_provname(char *, char *, int *); extern int update_kcfconf(entry_t *, int); extern void free_entry(entry_t *); extern void free_entrylist(entrylist_t *); extern void print_mechlist(char *, mechlist_t *); extern void print_kef_policy(char *provname, entry_t *pent, boolean_t has_random, boolean_t has_mechs); extern boolean_t filter_mechlist(mechlist_t **, const char *); extern uentry_t *getent_uef(char *); /* adm_uef */ extern int list_mechlist_for_lib(char *, mechlist_t *, flag_val_t *, boolean_t, boolean_t, boolean_t); extern int list_policy_for_lib(char *); extern int disable_uef_lib(char *, boolean_t, boolean_t, mechlist_t *); extern int enable_uef_lib(char *, boolean_t, boolean_t, mechlist_t *); extern int install_uef_lib(char *); extern int uninstall_uef_lib(char *); extern int print_uef_policy(uentry_t *); extern void display_token_flags(CK_FLAGS flags); extern int convert_mechlist(CK_MECHANISM_TYPE **, CK_ULONG *, mechlist_t *); extern void display_verbose_mech_header(); extern void display_mech_info(CK_MECHANISM_INFO *); extern int display_policy(uentry_t *); extern int update_pkcs11conf(uentry_t *); extern int update_policylist(uentry_t *, mechlist_t *, int); /* adm_kef */ extern int list_mechlist_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist); extern int list_mechlist_for_hard(char *); extern int list_policy_for_soft(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist); extern int list_policy_for_hard(char *provname, entrylist_t *phardlist, entrylist_t *psoftlist, crypto_get_dev_list_t *pdevlist); extern int disable_kef_software(char *, boolean_t, boolean_t, mechlist_t *); extern int disable_kef_hardware(char *, boolean_t, boolean_t, mechlist_t *); extern int enable_kef(char *, boolean_t, boolean_t, mechlist_t *); extern int install_kef(char *, mechlist_t *); extern int uninstall_kef(char *); extern int unload_kef_soft(char *provname); extern int refresh(void); /* adm_ioctl */ extern crypto_load_soft_config_t *setup_soft_conf(entry_t *); extern crypto_load_soft_disabled_t *setup_soft_dis(entry_t *); extern crypto_load_dev_disabled_t *setup_dev_dis(entry_t *); extern crypto_unload_soft_module_t *setup_unload_soft(entry_t *); extern int get_dev_info(char *, int, int, mechlist_t **); extern int get_dev_list(crypto_get_dev_list_t **); extern int get_soft_info(char *provname, mechlist_t **ppmechlist, entrylist_t *phardlist, entrylist_t *psoftlist); extern int get_soft_list(crypto_get_soft_list_t **); /* adm_metaslot */ extern int list_metaslot_info(boolean_t, boolean_t, mechlist_t *); extern int list_metaslot_policy(); extern int disable_metaslot(mechlist_t *, boolean_t, boolean_t); extern int enable_metaslot(char *, char *, boolean_t, mechlist_t *, boolean_t, boolean_t); #ifdef __cplusplus } #endif #endif /* _CRYPTOADM_H */