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