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