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