1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#include <fcntl.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <strings.h>
30#include <unistd.h>
31#include <locale.h>
32#include <libgen.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <sys/crypto/ioctladmin.h>
36#include <signal.h>
37#include <sys/crypto/elfsign.h>
38#include "cryptoadm.h"
39
40static int check_hardware_provider(char *, char *, int *, int *);
41
42/*
43 * Display the mechanism list for a kernel software provider.
44 * This implements part of the "cryptoadm list -m" command.
45 *
46 * Parameters phardlist and psoftlist are supplied by
47 * get_soft_info().
48 * If NULL, this function obtains it by calling getent_kef() and
49 * then get_kcfconf_info() via get_soft_info() internally.
50 */
51int
52list_mechlist_for_soft(char *provname,
53    entrylist_t *phardlist, entrylist_t *psoftlist)
54{
55	mechlist_t	*pmechlist = NULL;
56	int		rc;
57
58	if (provname == NULL) {
59		return (FAILURE);
60	}
61
62	rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist);
63	if (rc == SUCCESS) {
64		(void) filter_mechlist(&pmechlist, RANDOM);
65		print_mechlist(provname, pmechlist);
66		free_mechlist(pmechlist);
67	} else {
68		cryptoerror(LOG_STDERR, gettext(
69		    "failed to retrieve the mechanism list for %s."),
70		    provname);
71	}
72
73	return (rc);
74}
75
76/*
77 * Display the mechanism list for a kernel hardware provider.
78 * This implements part of the "cryptoadm list -m" command.
79 */
80int
81list_mechlist_for_hard(char *provname)
82{
83	mechlist_t	*pmechlist = NULL;
84	char		devname[MAXNAMELEN];
85	int		inst_num;
86	int		count;
87	int		rc = SUCCESS;
88
89	if (provname == NULL) {
90		return (FAILURE);
91	}
92
93	/*
94	 * Check if the provider is valid. If it is valid, get the number of
95	 * mechanisms also.
96	 */
97	if (check_hardware_provider(provname, devname, &inst_num, &count) ==
98	    FAILURE) {
99		return (FAILURE);
100	}
101
102	/* Get the mechanism list for the kernel hardware provider */
103	if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
104	    SUCCESS) {
105		(void) filter_mechlist(&pmechlist, RANDOM);
106		print_mechlist(provname, pmechlist);
107		free_mechlist(pmechlist);
108	}
109
110	return (rc);
111}
112
113
114/*
115 * Display the policy information for a kernel software provider.
116 * This implements part of the "cryptoadm list -p" command.
117 *
118 * Parameters phardlist and psoftlist are supplied by
119 * getent_kef().
120 * If NULL, this function obtains it by calling get_kcfconf_info()
121 * via getent_kef() internally.
122 */
123int
124list_policy_for_soft(char *provname,
125    entrylist_t *phardlist, entrylist_t *psoftlist)
126{
127	int		rc;
128	entry_t		*pent = NULL;
129	mechlist_t	*pmechlist = NULL;
130	boolean_t	has_random = B_FALSE;
131	boolean_t	has_mechs = B_FALSE;
132	boolean_t	in_kernel = B_FALSE;
133
134	if (provname == NULL) {
135		return (FAILURE);
136	}
137
138	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
139		return (FAILURE);
140	} else if (in_kernel == B_FALSE) {
141		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
142		    provname);
143		return (FAILURE);
144	}
145	pent = getent_kef(provname, phardlist, psoftlist);
146
147	rc = get_soft_info(provname, &pmechlist, phardlist, psoftlist);
148	if (rc == SUCCESS) {
149		has_random = filter_mechlist(&pmechlist, RANDOM);
150		if (pmechlist != NULL) {
151			has_mechs = B_TRUE;
152			free_mechlist(pmechlist);
153		}
154	} else {
155		cryptoerror(LOG_STDERR, gettext(
156		    "failed to retrieve the mechanism list for %s."),
157		    provname);
158		return (rc);
159	}
160
161	print_kef_policy(provname, pent, has_random, has_mechs);
162	free_entry(pent);
163	return (SUCCESS);
164}
165
166
167
168/*
169 * Display the policy information for a kernel hardware provider.
170 * This implements part of the "cryptoadm list -p" command.
171 *
172 * Parameters phardlist and psoftlist are supplied by getent_kef().
173 * If NULL, this function obtains it by calling get_kcfconf_info() via
174 * getent_kef() internally.
175 * Parameter pdevlist is supplied by check_kernel_for_hard().
176 * If NULL, this function obtains it by calling get_dev_list() via
177 * check_kernel_for_hard() internally.
178 */
179int
180list_policy_for_hard(char *provname,
181	entrylist_t *phardlist, entrylist_t *psoftlist,
182	crypto_get_dev_list_t *pdevlist)
183{
184	entry_t		*pent = NULL;
185	boolean_t	in_kernel;
186	mechlist_t	*pmechlist = NULL;
187	char		devname[MAXNAMELEN];
188	int		inst_num;
189	int		count;
190	int		rc = SUCCESS;
191	boolean_t	has_random = B_FALSE;
192	boolean_t 	has_mechs = B_FALSE;
193
194	if (provname == NULL) {
195		return (FAILURE);
196	}
197
198	/*
199	 * Check if the provider is valid. If it is valid, get the number of
200	 * mechanisms also.
201	 */
202	if (check_hardware_provider(provname, devname, &inst_num, &count) ==
203	    FAILURE) {
204		return (FAILURE);
205	}
206
207	/* Get the mechanism list for the kernel hardware provider */
208	if ((rc = get_dev_info(devname, inst_num, count, &pmechlist)) ==
209	    SUCCESS) {
210		has_random = filter_mechlist(&pmechlist, RANDOM);
211
212		if (pmechlist != NULL) {
213			has_mechs = B_TRUE;
214			free_mechlist(pmechlist);
215		}
216	} else {
217		cryptoerror(LOG_STDERR, gettext(
218		    "failed to retrieve the mechanism list for %s."),
219		    devname);
220		return (rc);
221	}
222
223	/*
224	 * If the hardware provider has an entry in the kcf.conf file,
225	 * some of its mechanisms must have been disabled.  Print out
226	 * the disabled list from the config file entry.  Otherwise,
227	 * if it is active, then all the mechanisms for it are enabled.
228	 */
229	if ((pent = getent_kef(provname, phardlist, psoftlist)) != NULL) {
230		print_kef_policy(provname, pent, has_random, has_mechs);
231		free_entry(pent);
232		return (SUCCESS);
233	} else {
234		if (check_kernel_for_hard(provname, pdevlist,
235		    &in_kernel) == FAILURE) {
236			return (FAILURE);
237		} else if (in_kernel == B_TRUE) {
238			(void) printf(gettext(
239			    "%s: all mechanisms are enabled."), provname);
240			if (has_random)
241				/*
242				 * TRANSLATION_NOTE
243				 * "random" is a keyword and not to be
244				 * translated.
245				 */
246				(void) printf(gettext(" %s is enabled.\n"),
247				    "random");
248			else
249				(void) printf("\n");
250			return (SUCCESS);
251		} else {
252			cryptoerror(LOG_STDERR,
253			    gettext("%s does not exist."), provname);
254			return (FAILURE);
255		}
256	}
257}
258
259
260/*
261 * Disable a kernel hardware provider.
262 * This implements the "cryptoadm disable" command for
263 * kernel hardware providers.
264 */
265int
266disable_kef_hardware(char *provname, boolean_t rndflag, boolean_t allflag,
267    mechlist_t *dislist)
268{
269	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
270	mechlist_t			*infolist = NULL;
271	entry_t				*pent = NULL;
272	boolean_t			new_dev_entry = B_FALSE;
273	char				devname[MAXNAMELEN];
274	int				inst_num;
275	int				count;
276	int				fd = -1;
277	int				rc = SUCCESS;
278
279	if (provname == NULL) {
280		return (FAILURE);
281	}
282
283	/*
284	 * Check if the provider is valid. If it is valid, get the number of
285	 * mechanisms also.
286	 */
287	if (check_hardware_provider(provname, devname, &inst_num, &count)
288	    == FAILURE) {
289		return (FAILURE);
290	}
291
292	/* Get the mechanism list for the kernel hardware provider */
293	if (get_dev_info(devname, inst_num, count, &infolist) == FAILURE) {
294		return (FAILURE);
295	}
296
297	/*
298	 * Get the entry of this hardware provider from the config file.
299	 * If there is no entry yet, create one for it.
300	 */
301	if ((pent = getent_kef(provname, NULL, NULL)) == NULL) {
302		if ((pent = create_entry(provname)) == NULL) {
303			cryptoerror(LOG_STDERR, gettext("out of memory."));
304			free_mechlist(infolist);
305			return (FAILURE);
306		}
307		new_dev_entry = B_TRUE;
308	}
309
310	/*
311	 * kCF treats random as an internal mechanism. So, we need to
312	 * filter it from the mechanism list here, if we are NOT disabling
313	 * or enabling the random feature. Note that we map random feature at
314	 * cryptoadm(1M) level to the "random" mechanism in kCF.
315	 */
316	if (!rndflag) {
317		(void) filter_mechlist(&dislist, RANDOM);
318	}
319
320	/* Calculate the new disabled list */
321	if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
322		free_mechlist(infolist);
323		free_entry(pent);
324		return (FAILURE);
325	}
326	free_mechlist(infolist);
327
328	/* If no mechanisms are to be disabled, return */
329	if (pent->dis_count == 0) {
330		free_entry(pent);
331		return (SUCCESS);
332	}
333
334	/* Update the config file with the new entry or the updated entry */
335	if (new_dev_entry) {
336		rc = update_kcfconf(pent, ADD_MODE);
337	} else {
338		rc = update_kcfconf(pent, MODIFY_MODE);
339	}
340
341	if (rc == FAILURE) {
342		free_entry(pent);
343		return (FAILURE);
344	}
345
346	/* Inform kernel about the new disabled mechanism list */
347	if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
348		free_entry(pent);
349		return (FAILURE);
350	}
351	free_entry(pent);
352
353	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
354		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
355		    ADMIN_IOCTL_DEVICE, strerror(errno));
356		free(pload_dev_dis);
357		return (FAILURE);
358	}
359
360	if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
361		cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: %s",
362		    strerror(errno));
363		free(pload_dev_dis);
364		(void) close(fd);
365		return (FAILURE);
366	}
367
368	if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
369		cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl return_value = "
370		    "%d", pload_dev_dis->dd_return_value);
371		free(pload_dev_dis);
372		(void) close(fd);
373		return (FAILURE);
374	}
375
376	free(pload_dev_dis);
377	(void) close(fd);
378	return (SUCCESS);
379}
380
381
382/*
383 * Disable a kernel software provider.
384 * This implements the "cryptoadm disable" command for
385 * kernel software providers.
386 */
387int
388disable_kef_software(char *provname, boolean_t rndflag, boolean_t allflag,
389    mechlist_t *dislist)
390{
391	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
392	mechlist_t			*infolist = NULL;
393	entry_t				*pent = NULL;
394	entrylist_t			*phardlist = NULL;
395	entrylist_t			*psoftlist = NULL;
396	boolean_t			in_kernel = B_FALSE;
397	int				fd = -1;
398	int				rc = SUCCESS;
399
400	if (provname == NULL) {
401		return (FAILURE);
402	}
403
404	/*
405	 * Check if the kernel software provider is currently unloaded.
406	 * If it is unloaded, return FAILURE, because the disable subcommand
407	 * can not perform on inactive (unloaded) providers.
408	 */
409	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
410		return (FAILURE);
411	} else if (in_kernel == B_FALSE) {
412		cryptoerror(LOG_STDERR,
413		    gettext("%s is not loaded or does not exist."),
414		    provname);
415		return (FAILURE);
416	}
417
418	if (get_kcfconf_info(&phardlist, &psoftlist) == FAILURE) {
419		cryptoerror(LOG_ERR,
420		    "failed to retrieve the providers' "
421		    "information from the configuration file - %s.",
422		    _PATH_KCF_CONF);
423		return (FAILURE);
424	}
425
426	/*
427	 * Get the entry of this provider from the kcf.conf file, if any.
428	 * Otherwise, create a new kcf.conf entry for writing back to the file.
429	 */
430	pent = getent_kef(provname, phardlist, psoftlist);
431	if (pent == NULL) { /* create a new entry */
432		pent = create_entry(provname);
433		if (pent == NULL) {
434			cryptodebug("out of memory.");
435			rc = FAILURE;
436			goto out;
437		}
438	}
439
440	/* Get the mechanism list for the software provider from the kernel */
441	if (get_soft_info(provname, &infolist, phardlist, psoftlist) ==
442	    FAILURE) {
443		rc = FAILURE;
444		goto out;
445	}
446
447	if ((infolist != NULL) && (infolist->name[0] != '\0')) {
448		/*
449		 * Replace the supportedlist from kcf.conf with possibly
450		 * more-up-to-date list from the kernel.  This is the case
451		 * for default software providers that had more mechanisms
452		 * added in the current version of the kernel.
453		 */
454		free_mechlist(pent->suplist);
455		pent->suplist = infolist;
456	}
457
458	/*
459	 * kCF treats random as an internal mechanism. So, we need to
460	 * filter it from the mechanism list here, if we are NOT disabling
461	 * or enabling the random feature. Note that we map random feature at
462	 * cryptoadm(1M) level to the "random" mechanism in kCF.
463	 */
464	if (!rndflag) {
465		(void) filter_mechlist(&infolist, RANDOM);
466	}
467
468	/* Calculate the new disabled list */
469	if (disable_mechs(&pent, infolist, allflag, dislist) == FAILURE) {
470		rc = FAILURE;
471		goto out;
472	}
473
474	/* Update the kcf.conf file with the updated entry */
475	if (update_kcfconf(pent, MODIFY_MODE) == FAILURE) {
476		rc = FAILURE;
477		goto out;
478	}
479
480	/* Setup argument to inform kernel about the new disabled list. */
481	if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
482		rc = FAILURE;
483		goto out;
484	}
485
486	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
487		cryptoerror(LOG_STDERR,
488		    gettext("failed to open %s for RW: %s"),
489		    ADMIN_IOCTL_DEVICE, strerror(errno));
490		rc = FAILURE;
491		goto out;
492	}
493
494	/* Inform kernel about the new disabled list. */
495	if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
496		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
497		    strerror(errno));
498		rc = FAILURE;
499		goto out;
500	}
501
502	if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
503		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
504		    "%d", pload_soft_dis->sd_return_value);
505		rc = FAILURE;
506		goto out;
507	}
508
509out:
510	free_entrylist(phardlist);
511	free_entrylist(psoftlist);
512	free_mechlist(infolist);
513	free_entry(pent);
514	free(pload_soft_dis);
515	if (fd != -1)
516		(void) close(fd);
517	return (rc);
518}
519
520
521/*
522 * Enable a kernel software or hardware provider.
523 * This implements the "cryptoadm enable" command for kernel providers.
524 */
525int
526enable_kef(char *provname, boolean_t rndflag, boolean_t allflag,
527    mechlist_t *mlist)
528{
529	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
530	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
531	entry_t				*pent = NULL;
532	boolean_t			redo_flag = B_FALSE;
533	boolean_t			in_kernel = B_FALSE;
534	int				fd = -1;
535	int				rc = SUCCESS;
536
537
538	/* Get the entry of this provider from the kcf.conf file, if any. */
539	pent = getent_kef(provname, NULL, NULL);
540
541	if (is_device(provname)) {
542		if (pent == NULL) {
543			/*
544			 * This device doesn't have an entry in the config
545			 * file, therefore nothing is disabled.
546			 */
547			cryptoerror(LOG_STDERR, gettext(
548			    "all mechanisms are enabled already for %s."),
549			    provname);
550			free_entry(pent);
551			return (SUCCESS);
552		}
553	} else { /* a software module */
554		if (check_kernel_for_soft(provname, NULL, &in_kernel) ==
555		    FAILURE) {
556			free_entry(pent);
557			return (FAILURE);
558		} else if (in_kernel == B_FALSE) {
559			cryptoerror(LOG_STDERR, gettext("%s does not exist."),
560			    provname);
561			free_entry(pent);
562			return (FAILURE);
563		} else if ((pent == NULL) || (pent->dis_count == 0)) {
564			/* nothing to be enabled. */
565			cryptoerror(LOG_STDERR, gettext(
566			    "all mechanisms are enabled already for %s."),
567			    provname);
568			free_entry(pent);
569			return (SUCCESS);
570		}
571	}
572
573	/*
574	 * kCF treats random as an internal mechanism. So, we need to
575	 * filter it from the mechanism list here, if we are NOT disabling
576	 * or enabling the random feature. Note that we map random feature at
577	 * cryptoadm(1M) level to the "random" mechanism in kCF.
578	 */
579	if (!rndflag) {
580		redo_flag = filter_mechlist(&pent->dislist, RANDOM);
581		if (redo_flag)
582			pent->dis_count--;
583	}
584
585	/* Update the entry by enabling mechanisms for this provider */
586	if ((rc = enable_mechs(&pent, allflag, mlist)) != SUCCESS) {
587		free_entry(pent);
588		return (rc);
589	}
590
591	if (redo_flag) {
592		mechlist_t *tmp;
593
594		if ((tmp = create_mech(RANDOM)) == NULL) {
595			free_entry(pent);
596			return (FAILURE);
597		}
598		tmp->next = pent->dislist;
599		pent->dislist = tmp;
600		pent->dis_count++;
601	}
602
603	/*
604	 * Update the kcf.conf file with the updated entry.
605	 * For a hardware provider, if there is no more disabled mechanism,
606	 * remove the entire kcf.conf entry.
607	 */
608	if (is_device(pent->name) && (pent->dis_count == 0)) {
609		rc = update_kcfconf(pent, DELETE_MODE);
610	} else {
611		rc = update_kcfconf(pent, MODIFY_MODE);
612	}
613
614	if (rc == FAILURE) {
615		free_entry(pent);
616		return (FAILURE);
617	}
618
619
620	/* Inform Kernel about the policy change */
621
622	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
623		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
624		    ADMIN_IOCTL_DEVICE, strerror(errno));
625		free_entry(pent);
626		return (FAILURE);
627	}
628
629	if (is_device(provname)) {
630		/*  LOAD_DEV_DISABLED */
631		if ((pload_dev_dis = setup_dev_dis(pent)) == NULL) {
632			free_entry(pent);
633			return (FAILURE);
634		}
635
636		if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis) == -1) {
637			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl failed: "
638			    "%s", strerror(errno));
639			free_entry(pent);
640			free(pload_dev_dis);
641			(void) close(fd);
642			return (FAILURE);
643		}
644
645		if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
646			cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
647			    "return_value = %d",
648			    pload_dev_dis->dd_return_value);
649			free_entry(pent);
650			free(pload_dev_dis);
651			(void) close(fd);
652			return (FAILURE);
653		}
654
655	} else { /* a software module */
656		/* LOAD_SOFT_DISABLED */
657		if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
658			free_entry(pent);
659			return (FAILURE);
660		}
661
662		if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis)
663		    == -1) {
664			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: "
665			    "%s", strerror(errno));
666			free_entry(pent);
667			free(pload_soft_dis);
668			(void) close(fd);
669			return (FAILURE);
670		}
671
672		if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
673			cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
674			    "return_value = %d",
675			    pload_soft_dis->sd_return_value);
676			free_entry(pent);
677			free(pload_soft_dis);
678			(void) close(fd);
679			return (FAILURE);
680		}
681	}
682
683	free_entry(pent);
684	free(pload_soft_dis);
685	(void) close(fd);
686	return (SUCCESS);
687}
688
689
690/*
691 * Install a software module with the specified mechanism list into the system.
692 * This routine adds an entry into the config file for this software module
693 * first, then makes a CRYPTO_LOAD_SOFT_CONFIG ioctl call to inform kernel
694 * about the new addition.
695 */
696int
697install_kef(char *provname, mechlist_t *mlist)
698{
699	crypto_load_soft_config_t	*pload_soft_conf = NULL;
700	boolean_t			found;
701	entry_t				*pent = NULL;
702	FILE				*pfile = NULL;
703	FILE				*pfile_tmp = NULL;
704	char				tmpfile_name[MAXPATHLEN];
705	char				*ptr;
706	char				*str;
707	char				*name;
708	char				buffer[BUFSIZ];
709	char				buffer2[BUFSIZ];
710	int				found_count;
711	int				fd = -1;
712	int				rc = SUCCESS;
713	int				err;
714
715	if ((provname == NULL) || (mlist == NULL)) {
716		return (FAILURE);
717	}
718
719	/* Check if the provider already exists */
720	if ((pent = getent_kef(provname, NULL, NULL)) != NULL) {
721		cryptoerror(LOG_STDERR, gettext("%s exists already."),
722		    provname);
723		free_entry(pent);
724		return (FAILURE);
725	}
726
727	/* Create an entry with provname and mlist. */
728	if ((pent = create_entry(provname)) == NULL) {
729		cryptoerror(LOG_STDERR, gettext("out of memory."));
730		return (FAILURE);
731	}
732	pent->sup_count = get_mech_count(mlist);
733	pent->suplist = mlist;
734
735	/* Append an entry for this software module to the kcf.conf file. */
736	if ((str = ent2str(pent)) == NULL) {
737		free_entry(pent);
738		return (FAILURE);
739	}
740
741	if ((pfile = fopen(_PATH_KCF_CONF, "r+")) == NULL) {
742		err = errno;
743		cryptoerror(LOG_STDERR,
744		    gettext("failed to update the configuration - %s"),
745		    strerror(err));
746		cryptodebug("failed to open %s for write.", _PATH_KCF_CONF);
747		free_entry(pent);
748		return (FAILURE);
749	}
750
751	if (lockf(fileno(pfile), F_TLOCK, 0) == -1) {
752		err = errno;
753		cryptoerror(LOG_STDERR,
754		    gettext("failed to lock the configuration - %s"),
755		    strerror(err));
756		free_entry(pent);
757		(void) fclose(pfile);
758		return (FAILURE);
759	}
760
761	/*
762	 * Create a temporary file in the /etc/crypto directory.
763	 */
764	(void) strlcpy(tmpfile_name, TMPFILE_TEMPLATE, sizeof (tmpfile_name));
765	if (mkstemp(tmpfile_name) == -1) {
766		err = errno;
767		cryptoerror(LOG_STDERR,
768		    gettext("failed to create a temporary file - %s"),
769		    strerror(err));
770		free_entry(pent);
771		(void) fclose(pfile);
772		return (FAILURE);
773	}
774
775	if ((pfile_tmp = fopen(tmpfile_name, "w")) == NULL) {
776		err = errno;
777		cryptoerror(LOG_STDERR, gettext("failed to open %s - %s"),
778		    tmpfile_name, strerror(err));
779		free_entry(pent);
780		(void) fclose(pfile);
781		return (FAILURE);
782	}
783
784
785	/*
786	 * Loop thru the config file. If the provider was reserved within a
787	 * package bracket, just uncomment it.  Otherwise, append it at
788	 * the end.  The resulting file will be saved in the temp file first.
789	 */
790	found_count = 0;
791	rc = SUCCESS;
792	while (fgets(buffer, BUFSIZ, pfile) != NULL) {
793		found = B_FALSE;
794		if (buffer[0] == '#') {
795			(void) strlcpy(buffer2, buffer, BUFSIZ);
796			ptr = buffer2;
797			ptr++;
798			if ((name = strtok(ptr, SEP_COLON)) == NULL) {
799				rc = FAILURE;
800				break;
801			} else if (strcmp(provname, name) == 0) {
802				found = B_TRUE;
803				found_count++;
804			}
805		}
806
807		if (found == B_FALSE) {
808			if (fputs(buffer, pfile_tmp) == EOF) {
809				rc = FAILURE;
810			}
811		} else {
812			if (found_count == 1) {
813				if (fputs(str, pfile_tmp) == EOF) {
814					rc = FAILURE;
815				}
816			} else {
817				/*
818				 * Found a second entry with #libname.
819				 * Should not happen. The kcf.conf file
820				 * is corrupted. Give a warning and skip
821				 * this entry.
822				 */
823				cryptoerror(LOG_STDERR, gettext(
824				    "(Warning) Found an additional reserved "
825				    "entry for %s."), provname);
826			}
827		}
828
829		if (rc == FAILURE) {
830			break;
831		}
832	}
833	(void) fclose(pfile);
834
835	if (rc == FAILURE) {
836		cryptoerror(LOG_STDERR, gettext("write error."));
837		(void) fclose(pfile_tmp);
838		if (unlink(tmpfile_name) != 0) {
839			err = errno;
840			cryptoerror(LOG_STDERR, gettext(
841			    "(Warning) failed to remove %s: %s"), tmpfile_name,
842			    strerror(err));
843		}
844		free_entry(pent);
845		return (FAILURE);
846	}
847
848	if (found_count == 0) {
849		/*
850		 * This libname was not in package before, append it to the
851		 * end of the temp file.
852		 */
853		if (fputs(str, pfile_tmp) == EOF) {
854			cryptoerror(LOG_STDERR, gettext(
855			    "failed to write to %s: %s"), tmpfile_name,
856			    strerror(errno));
857			(void) fclose(pfile_tmp);
858			if (unlink(tmpfile_name) != 0) {
859				err = errno;
860				cryptoerror(LOG_STDERR, gettext(
861				    "(Warning) failed to remove %s: %s"),
862				    tmpfile_name, strerror(err));
863			}
864			free_entry(pent);
865			return (FAILURE);
866		}
867	}
868
869	if (fclose(pfile_tmp) != 0) {
870		err = errno;
871		cryptoerror(LOG_STDERR,
872		    gettext("failed to close %s: %s"), tmpfile_name,
873		    strerror(err));
874		free_entry(pent);
875		return (FAILURE);
876	}
877
878	if (rename(tmpfile_name, _PATH_KCF_CONF) == -1) {
879		err = errno;
880		cryptoerror(LOG_STDERR,
881		    gettext("failed to update the configuration - %s"),
882		    strerror(err));
883		cryptodebug("failed to rename %s to %s: %s", tmpfile_name,
884		    _PATH_KCF_CONF, strerror(err));
885		rc = FAILURE;
886	} else if (chmod(_PATH_KCF_CONF,
887	    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1) {
888		err = errno;
889		cryptoerror(LOG_STDERR,
890		    gettext("failed to update the configuration - %s"),
891		    strerror(err));
892		cryptodebug("failed to chmod to %s: %s", _PATH_KCF_CONF,
893		    strerror(err));
894		rc = FAILURE;
895	} else {
896		rc = SUCCESS;
897	}
898
899	if (rc == FAILURE) {
900		if (unlink(tmpfile_name) != 0) {
901			err = errno;
902			cryptoerror(LOG_STDERR, gettext(
903			    "(Warning) failed to remove %s: %s"),
904			    tmpfile_name, strerror(err));
905		}
906		free_entry(pent);
907		return (FAILURE);
908	}
909
910
911	/* Inform kernel of this new software module. */
912
913	if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
914		free_entry(pent);
915		return (FAILURE);
916	}
917
918	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
919		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
920		    ADMIN_IOCTL_DEVICE, strerror(errno));
921		free_entry(pent);
922		free(pload_soft_conf);
923		return (FAILURE);
924	}
925
926	if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf) == -1) {
927		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
928		    strerror(errno));
929		free_entry(pent);
930		free(pload_soft_conf);
931		(void) close(fd);
932		return (FAILURE);
933	}
934
935	if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
936		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed, "
937		    "return_value = %d", pload_soft_conf->sc_return_value);
938		free_entry(pent);
939		free(pload_soft_conf);
940		(void) close(fd);
941		return (FAILURE);
942	}
943
944	free_entry(pent);
945	free(pload_soft_conf);
946	(void) close(fd);
947	return (SUCCESS);
948}
949
950/*
951 * Uninstall the software module. This routine first unloads the software
952 * module with 3 ioctl calls, then deletes its entry from the config file.
953 * Removing an entry from the config file needs to be done last to ensure
954 * that there is still an entry if the earlier unload failed for any reason.
955 */
956int
957uninstall_kef(char *provname)
958{
959	entry_t		*pent = NULL;
960	int		rc = SUCCESS;
961	boolean_t	in_kernel = B_FALSE;
962	boolean_t	in_kcfconf = B_FALSE;
963	int		fd = -1;
964	crypto_load_soft_config_t *pload_soft_conf = NULL;
965
966	/* Check to see if the provider exists first. */
967	if (check_kernel_for_soft(provname, NULL, &in_kernel) == FAILURE) {
968		return (FAILURE);
969	} else if (in_kernel == B_FALSE) {
970		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
971		    provname);
972		return (FAILURE);
973	}
974
975	/*
976	 * If it is loaded, unload it first.  This does 2 ioctl calls:
977	 * CRYPTO_UNLOAD_SOFT_MODULE and CRYPTO_LOAD_SOFT_DISABLED.
978	 */
979	if (unload_kef_soft(provname) == FAILURE) {
980		cryptoerror(LOG_STDERR,
981		    gettext("failed to unload %s during uninstall.\n"),
982		    provname);
983		return (FAILURE);
984	}
985
986	/*
987	 * Inform kernel to remove the configuration of this software module.
988	 */
989
990	/* Setup ioctl() parameter */
991	pent = getent_kef(provname, NULL, NULL);
992	if (pent != NULL) { /* in kcf.conf */
993		in_kcfconf = B_TRUE;
994		free_mechlist(pent->suplist);
995		pent->suplist = NULL;
996		pent->sup_count = 0;
997	} else if ((pent = create_entry(provname)) == NULL) {
998		cryptoerror(LOG_STDERR, gettext("out of memory."));
999		return (FAILURE);
1000	}
1001	if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
1002		free_entry(pent);
1003		return (FAILURE);
1004	}
1005
1006	/* Open the /dev/cryptoadm device */
1007	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1008		int	err = errno;
1009		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1010		    ADMIN_IOCTL_DEVICE, strerror(err));
1011		free_entry(pent);
1012		free(pload_soft_conf);
1013		return (FAILURE);
1014	}
1015
1016	if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG,
1017	    pload_soft_conf) == -1) {
1018		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
1019		    strerror(errno));
1020		free_entry(pent);
1021		free(pload_soft_conf);
1022		(void) close(fd);
1023		return (FAILURE);
1024	}
1025
1026	if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
1027		cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl = return_value = %d",
1028		    pload_soft_conf->sc_return_value);
1029		free_entry(pent);
1030		free(pload_soft_conf);
1031		(void) close(fd);
1032		return (FAILURE);
1033	}
1034
1035	/* ioctl cleanup */
1036	free(pload_soft_conf);
1037	(void) close(fd);
1038
1039
1040	/* Finally, remove entry from kcf.conf, if present */
1041	if (in_kcfconf && (pent != NULL)) {
1042		rc = update_kcfconf(pent, DELETE_MODE);
1043	}
1044
1045	free_entry(pent);
1046	return (rc);
1047}
1048
1049
1050/*
1051 * Implement the "cryptoadm refresh" command for global zones.
1052 * That is, send the current contents of kcf.conf to the kernel via ioctl().
1053 */
1054int
1055refresh(void)
1056{
1057	crypto_load_soft_config_t	*pload_soft_conf = NULL;
1058	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
1059	crypto_load_dev_disabled_t	*pload_dev_dis = NULL;
1060	entrylist_t			*pdevlist = NULL;
1061	entrylist_t			*psoftlist = NULL;
1062	entrylist_t			*ptr;
1063	int				fd = -1;
1064	int				rc = SUCCESS;
1065	int				err;
1066
1067	if (get_kcfconf_info(&pdevlist, &psoftlist) == FAILURE) {
1068		cryptoerror(LOG_ERR, "failed to retrieve the providers' "
1069		    "information from the configuration file - %s.",
1070		    _PATH_KCF_CONF);
1071		return (FAILURE);
1072	}
1073
1074	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1075		err = errno;
1076		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1077		    ADMIN_IOCTL_DEVICE, strerror(err));
1078		free(psoftlist);
1079		free(pdevlist);
1080		return (FAILURE);
1081	}
1082
1083	/*
1084	 * For each software provider module, pass two sets of information to
1085	 * the kernel: the supported list and the disabled list.
1086	 */
1087	for (ptr = psoftlist; ptr != NULL; ptr = ptr->next) {
1088		entry_t		*pent = ptr->pent;
1089
1090		/* load the supported list */
1091		if ((pload_soft_conf = setup_soft_conf(pent)) == NULL) {
1092			cryptodebug("setup_soft_conf() failed");
1093			rc = FAILURE;
1094			break;
1095		}
1096
1097		if (!pent->load) { /* unloaded--mark as loaded */
1098			pent->load = B_TRUE;
1099			rc = update_kcfconf(pent, MODIFY_MODE);
1100			if (rc != SUCCESS) {
1101				free(pload_soft_conf);
1102				break;
1103			}
1104		}
1105
1106		if (ioctl(fd, CRYPTO_LOAD_SOFT_CONFIG, pload_soft_conf)
1107		    == -1) {
1108			cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl failed: %s",
1109			    strerror(errno));
1110			free(pload_soft_conf);
1111			rc = FAILURE;
1112			break;
1113		}
1114
1115		if (pload_soft_conf->sc_return_value != CRYPTO_SUCCESS) {
1116			cryptodebug("CRYPTO_LOAD_SOFT_CONFIG ioctl "
1117			    "return_value = %d",
1118			    pload_soft_conf->sc_return_value);
1119			free(pload_soft_conf);
1120			rc = FAILURE;
1121			break;
1122		}
1123
1124		free(pload_soft_conf);
1125
1126		/* load the disabled list */
1127		if (ptr->pent->dis_count != 0) {
1128			pload_soft_dis = setup_soft_dis(ptr->pent);
1129			if (pload_soft_dis == NULL) {
1130				cryptodebug("setup_soft_dis() failed");
1131				free(pload_soft_dis);
1132				rc = FAILURE;
1133				break;
1134			}
1135
1136			if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED,
1137			    pload_soft_dis) == -1) {
1138				cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
1139				    "failed: %s", strerror(errno));
1140				free(pload_soft_dis);
1141				rc = FAILURE;
1142				break;
1143			}
1144
1145			if (pload_soft_dis->sd_return_value !=
1146			    CRYPTO_SUCCESS) {
1147				cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl "
1148				    "return_value = %d",
1149				    pload_soft_dis->sd_return_value);
1150				free(pload_soft_dis);
1151				rc = FAILURE;
1152				break;
1153			}
1154			free(pload_soft_dis);
1155		}
1156	}
1157
1158	if (rc != SUCCESS) {
1159		(void) close(fd);
1160		return (rc);
1161	}
1162
1163
1164	/*
1165	 * For each hardware provider module, pass the disabled list
1166	 * information to the kernel.
1167	 */
1168	for (ptr = pdevlist; ptr != NULL; ptr = ptr->next) {
1169		/* load the disabled list */
1170		if (ptr->pent->dis_count != 0) {
1171			pload_dev_dis = setup_dev_dis(ptr->pent);
1172			if (pload_dev_dis == NULL) {
1173				rc = FAILURE;
1174				break;
1175			}
1176
1177			if (ioctl(fd, CRYPTO_LOAD_DEV_DISABLED, pload_dev_dis)
1178			    == -1) {
1179				cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
1180				    "failed: %s", strerror(errno));
1181				free(pload_dev_dis);
1182				rc = FAILURE;
1183				break;
1184			}
1185
1186			if (pload_dev_dis->dd_return_value != CRYPTO_SUCCESS) {
1187				cryptodebug("CRYPTO_LOAD_DEV_DISABLED ioctl "
1188				    "return_value = %d",
1189				    pload_dev_dis->dd_return_value);
1190				free(pload_dev_dis);
1191				rc = FAILURE;
1192				break;
1193			}
1194			free(pload_dev_dis);
1195		}
1196	}
1197
1198	/*
1199	 * handle fips_status=enabled|disabled
1200	 */
1201	{
1202		int	pkcs11_fips_mode = 0;
1203
1204		/* Get FIPS-140 status from pkcs11.conf */
1205		fips_status_pkcs11conf(&pkcs11_fips_mode);
1206		if (pkcs11_fips_mode == CRYPTO_FIPS_MODE_ENABLED) {
1207			rc = do_fips_actions(FIPS140_ENABLE, REFRESH);
1208		} else {
1209			rc = do_fips_actions(FIPS140_DISABLE, REFRESH);
1210		}
1211	}
1212
1213	(void) close(fd);
1214	return (rc);
1215}
1216
1217/*
1218 * Unload the kernel software provider. Before calling this function, the
1219 * caller should check to see if the provider is in the kernel.
1220 *
1221 * This routine makes 2 ioctl calls to remove it completely from the kernel:
1222 *	CRYPTO_UNLOAD_SOFT_MODULE - does a modunload of the KCF module
1223 *	CRYPTO_LOAD_SOFT_DISABLED - updates kernel disabled mechanism list
1224 *
1225 * This implements part of "cryptoadm unload" and "cryptoadm uninstall".
1226 */
1227int
1228unload_kef_soft(char *provname)
1229{
1230	crypto_unload_soft_module_t	*punload_soft = NULL;
1231	crypto_load_soft_disabled_t	*pload_soft_dis = NULL;
1232	entry_t				*pent = NULL;
1233	int				fd = -1;
1234	int				err;
1235
1236	if (provname == NULL) {
1237		cryptoerror(LOG_STDERR, gettext("internal error."));
1238		return (FAILURE);
1239	}
1240
1241	pent = getent_kef(provname, NULL, NULL);
1242	if (pent == NULL) { /* not in kcf.conf */
1243		/* Construct an entry using the provname */
1244		pent = create_entry(provname);
1245		if (pent == NULL) {
1246			cryptoerror(LOG_STDERR, gettext("out of memory."));
1247			return (FAILURE);
1248		}
1249	}
1250
1251	/* Open the admin_ioctl_device */
1252	if ((fd = open(ADMIN_IOCTL_DEVICE, O_RDWR)) == -1) {
1253		err = errno;
1254		cryptoerror(LOG_STDERR, gettext("failed to open %s: %s"),
1255		    ADMIN_IOCTL_DEVICE, strerror(err));
1256		free_entry(pent);
1257		return (FAILURE);
1258	}
1259
1260	/* Inform kernel to unload this software module */
1261	if ((punload_soft = setup_unload_soft(pent)) == NULL) {
1262		free_entry(pent);
1263		(void) close(fd);
1264		return (FAILURE);
1265	}
1266
1267	if (ioctl(fd, CRYPTO_UNLOAD_SOFT_MODULE, punload_soft) == -1) {
1268		cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl failed: %s",
1269		    strerror(errno));
1270		free_entry(pent);
1271		free(punload_soft);
1272		(void) close(fd);
1273		return (FAILURE);
1274	}
1275
1276	if (punload_soft->sm_return_value != CRYPTO_SUCCESS) {
1277		cryptodebug("CRYPTO_UNLOAD_SOFT_MODULE ioctl return_value = "
1278		    "%d", punload_soft->sm_return_value);
1279		/*
1280		 * If the return value is CRYPTO_UNKNOWN_PROVIDER, it means
1281		 * that the provider is not registered yet.  Should just
1282		 * continue.
1283		 */
1284		if (punload_soft->sm_return_value != CRYPTO_UNKNOWN_PROVIDER) {
1285			free_entry(pent);
1286			free(punload_soft);
1287			(void) close(fd);
1288			return (FAILURE);
1289		}
1290	}
1291
1292	free(punload_soft);
1293
1294	/* Inform kernel to remove the disabled entries if any */
1295	if (pent->dis_count == 0) {
1296		free_entry(pent);
1297		(void) close(fd);
1298		return (SUCCESS);
1299	} else {
1300		free_mechlist(pent->dislist);
1301		pent->dislist = NULL;
1302		pent->dis_count = 0;
1303	}
1304
1305	if ((pload_soft_dis = setup_soft_dis(pent)) == NULL) {
1306		free_entry(pent);
1307		(void) close(fd);
1308		return (FAILURE);
1309	}
1310
1311	/* pent is no longer needed; free it */
1312	free_entry(pent);
1313
1314	if (ioctl(fd, CRYPTO_LOAD_SOFT_DISABLED, pload_soft_dis) == -1) {
1315		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl failed: %s",
1316		    strerror(errno));
1317		free(pload_soft_dis);
1318		(void) close(fd);
1319		return (FAILURE);
1320	}
1321
1322	if (pload_soft_dis->sd_return_value != CRYPTO_SUCCESS) {
1323		cryptodebug("CRYPTO_LOAD_SOFT_DISABLED ioctl return_value = "
1324		    "%d", pload_soft_dis->sd_return_value);
1325		free(pload_soft_dis);
1326		(void) close(fd);
1327		return (FAILURE);
1328	}
1329
1330	free(pload_soft_dis);
1331	(void) close(fd);
1332	return (SUCCESS);
1333}
1334
1335
1336/*
1337 * Check if a hardware provider is valid.  If it is valid, returns its device
1338 * name,  instance number and the number of mechanisms it supports.
1339 */
1340static int
1341check_hardware_provider(char *provname, char *pname, int *pnum, int *pcount)
1342{
1343	crypto_get_dev_list_t *dev_list = NULL;
1344	int	i;
1345
1346	if (provname == NULL) {
1347		return (FAILURE);
1348	}
1349
1350	/* First, get the device name and the instance number from provname */
1351	if (split_hw_provname(provname, pname, pnum) == FAILURE) {
1352		return (FAILURE);
1353	}
1354
1355	/*
1356	 * Get the complete device list from kernel and check if this provider
1357	 * is in the list.
1358	 */
1359	if (get_dev_list(&dev_list) == FAILURE) {
1360		return (FAILURE);
1361	}
1362
1363	for (i = 0; i < dev_list->dl_dev_count; i++) {
1364		if ((strcmp(dev_list->dl_devs[i].le_dev_name, pname) == 0) &&
1365		    (dev_list->dl_devs[i].le_dev_instance == *pnum)) {
1366			break;
1367		}
1368	}
1369
1370	if (i == dev_list->dl_dev_count) {
1371		/* didn't find this provider in the kernel device list */
1372		cryptoerror(LOG_STDERR, gettext("%s does not exist."),
1373		    provname);
1374		free(dev_list);
1375		return (FAILURE);
1376	}
1377
1378	/* This provider is valid.  Get its mechanism count */
1379	*pcount = dev_list->dl_devs[i].le_mechanism_count;
1380
1381	free(dev_list);
1382	return (SUCCESS);
1383}
1384