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