예제 #1
0
/*
 * Get the supported mechanism list of the software provider from kernel.
 */
int
get_soft_info(char *provname, mechlist_t **ppmechlist)
{
	crypto_get_soft_info_t	*psoft_info;
	mechlist_t	*phead;
	mechlist_t	*pmech;
	mechlist_t	*pcur;
	entry_t	*pent;
	int	count;
	int	fd;
	int	rc;
	int	i;

	if (provname == NULL) {
		return (FAILURE);
	}

	if (getzoneid() == GLOBAL_ZONEID) {
		/* use kcf.conf for kernel software providers in global zone */
		if ((pent = getent_kef(provname)) == NULL) {
			cryptoerror(LOG_STDERR, gettext("%s does not exist."),
			    provname);
			return (FAILURE);
		}
		count = pent->sup_count;
		free_entry(pent);
	} else {
		/*
		 * kcf.conf not there in non-global zone, set mech count to 1;
		 * it will be reset to the correct value later if the setup
		 * buffer is too small
		 */
		count = 1;
	}

	if ((psoft_info = setup_get_soft_info(provname, count)) == NULL) {
		return (FAILURE);
	}

	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
		    ADMIN_IOCTL_DEVICE, strerror(errno));
		free(psoft_info);
		return (FAILURE);
	}

	/* make GET_SOFT_INFO ioctl call */
	if ((rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info)) == -1) {
		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed: %s",
		    strerror(errno));
		(void) close(fd);
		free(psoft_info);
		return (FAILURE);
	}

	/* BUFFER is too small, get the number of mechanisms and retry it. */
	if (psoft_info->si_return_value == CRYPTO_BUFFER_TOO_SMALL) {
		count = psoft_info->si_count;
		free(psoft_info);
		if ((psoft_info = setup_get_soft_info(provname, count))
		    == NULL) {
			(void) close(fd);
			return (FAILURE);
		} else {
			rc = ioctl(fd, CRYPTO_GET_SOFT_INFO, psoft_info);
			if (rc == -1) {
				cryptodebug("CRYPTO_GET_SOFT_INFO ioctl "
				    "failed: %s", strerror(errno));
				(void) close(fd);
				free(psoft_info);
				return (FAILURE);
			}
		}
	}

	(void) close(fd);
	if (psoft_info->si_return_value != CRYPTO_SUCCESS) {
		cryptodebug("CRYPTO_GET_SOFT_INFO ioctl failed, "
		    "return_value = %d", psoft_info->si_return_value);
		free(psoft_info);
		return (FAILURE);
	}


	/* Get the mechanism list and return it */
	rc = SUCCESS;
	phead = pcur = NULL;
	for (i = 0; i < psoft_info->si_count; i++) {
		pmech = create_mech(&psoft_info->si_list[i][0]);
		if (pmech == NULL) {
			rc = FAILURE;
			break;
		} else {
			if (phead == NULL) {
				phead = pcur = pmech;
			} else {
				pcur->next = pmech;
				pcur = pmech;
			}
		}
	}

	if (rc == FAILURE) {
		free_mechlist(phead);
	} else {
		*ppmechlist = phead;
	}

	free(psoft_info);
	return (rc);
}
예제 #2
0
/*
 * Get all the mechanisms supported by the hardware provider.
 * The result will be stored in the second argument.
 */
int
get_dev_info(char *devname, int inst_num, int count, mechlist_t **ppmechlist)
{
	crypto_get_dev_info_t *dev_info;
	mechlist_t *phead;
	mechlist_t *pcur;
	mechlist_t *pmech;
	int fd;
	int i;
	int rc;

	if (devname == NULL || count < 1) {
		cryptodebug("get_dev_info(): devname is NULL or bogus count");
		return (FAILURE);
	}

	/* Set up the argument for the CRYPTO_GET_DEV_INFO ioctl call */
	dev_info = malloc(sizeof (crypto_get_dev_info_t) +
	    sizeof (crypto_mech_name_t) * (count - 1));
	if (dev_info == NULL) {
		cryptodebug("out of memory.");
		return (FAILURE);
	}
	(void) strlcpy(dev_info->di_dev_name, devname, MAXNAMELEN);
	dev_info->di_dev_instance = inst_num;
	dev_info->di_count = count;

	/* Open the ioctl device */
	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDONLY)) == -1) {
		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
		    ADMIN_IOCTL_DEVICE, strerror(errno));
		free(dev_info);
		return (FAILURE);
	}

	if (ioctl(fd, CRYPTO_GET_DEV_INFO, dev_info) == -1) {
		cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed: %s",
		    strerror(errno));
		free(dev_info);
		(void) close(fd);
		return (FAILURE);
	}

	if (dev_info->di_return_value != CRYPTO_SUCCESS) {
		cryptodebug("CRYPTO_GET_DEV_INFO ioctl failed, "
		    "return_value = %d", dev_info->di_return_value);
		free(dev_info);
		(void) close(fd);
		return (FAILURE);
	}

	phead = pcur = NULL;
	rc = SUCCESS;
	for (i = 0; i < dev_info->di_count; i++) {
		pmech = create_mech(&dev_info->di_list[i][0]);
		if (pmech == NULL) {
			rc = FAILURE;
			break;
		} else {
			if (phead == NULL) {
				phead = pcur = pmech;
			} else {
				pcur->next = pmech;
				pcur = pmech;
			}
		}
	}

	if (rc == SUCCESS) {
		*ppmechlist = phead;
	} else {
		free_mechlist(phead);
	}

	free(dev_info);
	(void) close(fd);
	return (rc);
}
예제 #3
0
/*
 * 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);
}
예제 #4
0
/*
 * The top level function for the "cryptoadm enable" subcommand.
 */
static int
do_enable(int argc, char **argv)
{
	cryptoadm_provider_t	*prov = NULL;
	int			rc = SUCCESS;
	char 			*alt_token = NULL, *alt_slot = NULL;
	boolean_t		use_default = B_FALSE;
	boolean_t		auto_key_migrate_flag = B_FALSE;

	if ((argc == 3) && (strncmp(argv[2], FIPS_KEYWORD,
	    strlen(FIPS_KEYWORD))) == 0) {
		/*
		 * cryptoadm enable fips-140
		 */
		rc = do_fips_actions(FIPS140_ENABLE, NOT_REFRESH);
		return (rc);
	}

	if ((argc < 3) || (argc > 6)) {
		usage();
		return (ERROR_USAGE);
	}

	prov = get_provider(argc, argv);
	if (prov == NULL) {
		usage();
		return (ERROR_USAGE);
	}
	if ((prov->cp_type != METASLOT) && (argc != 4)) {
		usage();
		return (ERROR_USAGE);
	}
	if (prov->cp_type == PROV_BADNAME) {
		rc = FAILURE;
		goto out;
	}


	if (prov->cp_type == METASLOT) {
		if ((rc = process_metaslot_operands(argc, argv, &alt_token,
		    &alt_slot, &use_default, &auto_key_migrate_flag))
		    != SUCCESS) {
			usage();
			goto out;
		}
		if ((alt_slot || alt_token) && use_default) {
			usage();
			rc = FAILURE;
			goto out;
		}
	} else {
		if ((rc = process_feature_operands(argc, argv)) != SUCCESS) {
			goto out;
		}

		/*
		 * If allflag or rndflag has already been set there is
		 * no reason to process mech=
		 */
		if (!allflag && !rndflag &&
		    (rc = process_mech_operands(argc, argv, B_FALSE))
		    != SUCCESS) {
			goto out;
		}
	}

	switch (prov->cp_type) {
	case METASLOT:
		rc = enable_metaslot(alt_token, alt_slot, use_default,
		    mecharglist, allflag, auto_key_migrate_flag);
		break;
	case PROV_UEF_LIB:
		rc = enable_uef_lib(prov->cp_name, rndflag, allflag,
		    mecharglist);
		break;
	case PROV_KEF_SOFT:
	case PROV_KEF_HARD:
		if (rndflag && !allflag) {
			if ((mecharglist = create_mech(RANDOM)) == NULL) {
				rc = FAILURE;
				break;
			}
		}
		if (getzoneid() == GLOBAL_ZONEID) {
			rc = enable_kef(prov->cp_name, rndflag, allflag,
			    mecharglist);
		} else {
			/*
			 * TRANSLATION_NOTE
			 * "enable" could be either a literal keyword
			 * and hence not to be translated, or a verb and
			 * translatable.  A choice was made to view it as
			 * a literal keyword.  "global" is keyword and not
			 * to be translated.
			 */
			cryptoerror(LOG_STDERR, gettext("%1$s for kernel "
			    "providers is supported in the %2$s zone only"),
			    "enable", "global");
			rc = FAILURE;
		}
		break;
	default: /* should not come here */
		rc = FAILURE;
		break;
	}
out:
	free(prov);
	if (mecharglist != NULL) {
		free_mechlist(mecharglist);
	}
	if (alt_token != NULL) {
		free(alt_token);
	}
	if (alt_slot != NULL) {
		free(alt_slot);
	}
	return (rc);
}
예제 #5
0
/*
 * Enable a kernel software or hardware provider.
 * This implements the "cryptoadm enable" command for kernel providers.
 */
int
enable_kef(char *provname, boolean_t rndflag, boolean_t allflag,
    mechlist_t *mlist)
{
	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
	entry_t				*pent = NULL;
	boolean_t			redo_flag = B_FALSE;
	boolean_t			in_kernel = B_FALSE;
	int				fd = -1;
	int				rc = SUCCESS;


	/* Get the entry of this provider from the kcf.conf file, if any. */
	pent = getent_kef(provname, NULL, NULL);

	if (is_device(provname)) {
		if (pent == NULL) {
			/*
			 * This device doesn't have an entry in the config
			 * file, therefore nothing is disabled.
			 */
			cryptoerror(LOG_STDERR, gettext(
			    "all mechanisms are enabled already for %s."),
			    provname);
			free_entry(pent);
			return (SUCCESS);
		}
	} else { /* a software module */
		if (check_kernel_for_soft(provname, NULL, &in_kernel) ==
		    FAILURE) {
			free_entry(pent);
			return (FAILURE);
		} else if (in_kernel == B_FALSE) {
			cryptoerror(LOG_STDERR, gettext("%s does not exist."),
			    provname);
			free_entry(pent);
			return (FAILURE);
		} else if ((pent == NULL) || (pent->dis_count == 0)) {
			/* nothing to be enabled. */
			cryptoerror(LOG_STDERR, gettext(
			    "all mechanisms are enabled already for %s."),
			    provname);
			free_entry(pent);
			return (SUCCESS);
		}
	}

	/*
	 * kCF treats random as an internal mechanism. So, we need to
	 * filter it from the mechanism list here, if we are NOT disabling
	 * or enabling the random feature. Note that we map random feature at
	 * cryptoadm(1M) level to the "random" mechanism in kCF.
	 */
	if (!rndflag) {
		redo_flag = filter_mechlist(&pent->dislist, RANDOM);
		if (redo_flag)
			pent->dis_count--;
	}

	/* Update the entry by enabling mechanisms for this provider */
	if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) {
		free_entry(pent);
		return (rc);
	}

	if (redo_flag) {
		mechlist_t *tmp;

		if ((tmp = create_mech(RANDOM)) == NULL) {
			free_entry(pent);
			return (FAILURE);
		}
		tmp->next = pent->dislist;
		pent->dislist = tmp;
		pent->dis_count++;
	}

	/*
	 * Update the kcf.conf file with the updated entry.
	 * For a hardware provider, if there is no more disabled mechanism,
	 * remove the entire kcf.conf entry.
	 */
	if (is_device(pent->name) && (pent->dis_count == 0)) {
		rc = update_kcfconf(pent, DELETE_MODE);
	} else {
		rc = update_kcfconf(pent, MODIFY_MODE);
	}

	if (rc == FAILURE) {
		free_entry(pent);
		return (FAILURE);
	}


	/* Inform Kernel about the policy change */

	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
		    ADMIN_IOCTL_DEVICE, strerror(errno));
		free_entry(pent);
		return (FAILURE);
	}

	if (is_device(provname)) {
		/*  LOAD_DEV_DISABLED */
		if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
			free_entry(pent);
			return (FAILURE);
		}

		if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: "
			    "%s", strerror(errno));
			free_entry(pent);
			free(pload_dev_dis);
			(void) close(fd);
			return (FAILURE);
		}

		if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
			    "return_value = %d",
			    pload_dev_dis->dd_return_value);
			free_entry(pent);
			free(pload_dev_dis);
			(void) close(fd);
			return (FAILURE);
		}

	} else { /* a software module */
		/* LOAD_SOFT_DISABLED */
		if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
			free_entry(pent);
			return (FAILURE);
		}

		if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis)
		    == -1) {
			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: "
			    "%s", strerror(errno));
			free_entry(pent);
			free(pload_soft_dis);
			(void) close(fd);
			return (FAILURE);
		}

		if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
			    "return_value = %d",
			    pload_soft_dis->sd_return_value);
			free_entry(pent);
			free(pload_soft_dis);
			(void) close(fd);
			return (FAILURE);
		}
	}

	free_entry(pent);
	free(pload_soft_dis);
	(void) close(fd);
	return (SUCCESS);
}