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