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