xref: /illumos-gate/usr/src/uts/common/crypto/core/kcf_cryptoadm.c (revision 4aac33d31b41cc7e3ac6fb66747ff2cae63d08cf)
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 2007 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 /*
29  * Core KCF (Kernel Cryptographic Framework). This file implements
30  * the cryptoadm entry points.
31  */
32 
33 #include <sys/systm.h>
34 #include <sys/errno.h>
35 #include <sys/cmn_err.h>
36 #include <sys/rwlock.h>
37 #include <sys/kmem.h>
38 #include <sys/modctl.h>
39 #include <sys/sunddi.h>
40 #include <sys/door.h>
41 #include <sys/crypto/common.h>
42 #include <sys/crypto/api.h>
43 #include <sys/crypto/spi.h>
44 #include <sys/crypto/impl.h>
45 #include <sys/crypto/sched_impl.h>
46 
47 /* protects the the soft_config_list. */
48 kmutex_t soft_config_mutex;
49 
50 /*
51  * This linked list contains software configuration entries that
52  * are loaded into the kernel by the CRYPTO_LOAD_SOFT_CONFIG ioctl.
53  * It is protected by the soft_config_mutex.
54  */
55 kcf_soft_conf_entry_t *soft_config_list;
56 
57 static int add_soft_config(char *, uint_t, crypto_mech_name_t *);
58 static int dup_mech_names(kcf_provider_desc_t *, crypto_mech_name_t **,
59     uint_t *, int);
60 static void free_soft_config_entry(kcf_soft_conf_entry_t *);
61 
62 #define	KCF_MAX_CONFIG_ENTRIES 512 /* maximum entries in soft_config_list */
63 
64 void
65 kcf_soft_config_init(void)
66 {
67 	mutex_init(&soft_config_mutex, NULL, MUTEX_DRIVER, NULL);
68 }
69 
70 
71 /*
72  * Utility routine to identify the providers to filter out and
73  * present only one provider. This happens when a hardware provider
74  * registers multiple units of the same device instance.
75  */
76 static void
77 filter_providers(uint_t count, kcf_provider_desc_t **provider_array,
78 	char *skip_providers, int *mech_counts, int *new_count)
79 {
80 	int i, j;
81 	kcf_provider_desc_t *prov1, *prov2;
82 	int n = 0;
83 
84 	for (i = 0; i < count; i++) {
85 		if (skip_providers[i] == 1)
86 			continue;
87 
88 		prov1 = provider_array[i];
89 		mech_counts[i] = prov1->pd_mech_list_count;
90 		for (j = i + 1; j < count; j++) {
91 			prov2 = provider_array[j];
92 			if (strncmp(prov1->pd_name, prov2->pd_name,
93 			    MAXNAMELEN) == 0 &&
94 			    prov1->pd_instance == prov2->pd_instance) {
95 				skip_providers[j] = 1;
96 				mech_counts[i] += prov2->pd_mech_list_count;
97 			}
98 		}
99 		n++;
100 	}
101 
102 	*new_count = n;
103 }
104 
105 
106 /* called from the CRYPTO_GET_DEV_LIST ioctl */
107 int
108 crypto_get_dev_list(uint_t *count, crypto_dev_list_entry_t **array)
109 {
110 	kcf_provider_desc_t **provider_array;
111 	kcf_provider_desc_t *pd;
112 	crypto_dev_list_entry_t *p;
113 	size_t skip_providers_size, mech_counts_size;
114 	char *skip_providers;
115 	uint_t provider_count;
116 	int rval, i, j, new_count, *mech_counts;
117 
118 	/*
119 	 * Take snapshot of provider table returning only hardware providers
120 	 * that are in a usable state. Logical providers not included.
121 	 */
122 	rval =  kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
123 	    NULL, 0, B_FALSE);
124 	if (rval != CRYPTO_SUCCESS)
125 		return (rval);
126 
127 	if (provider_count == 0) {
128 		*array = NULL;
129 		*count = 0;
130 		return (CRYPTO_SUCCESS);
131 	}
132 
133 	skip_providers_size = provider_count * sizeof (char);
134 	mech_counts_size = provider_count * sizeof (int);
135 
136 	skip_providers = kmem_zalloc(skip_providers_size, KM_SLEEP);
137 	mech_counts = kmem_zalloc(mech_counts_size, KM_SLEEP);
138 	filter_providers(provider_count, provider_array, skip_providers,
139 	    mech_counts, &new_count);
140 
141 	p = kmem_alloc(new_count * sizeof (crypto_dev_list_entry_t), KM_SLEEP);
142 	for (i = 0, j = 0; i < provider_count; i++) {
143 		if (skip_providers[i] == 1) {
144 			ASSERT(mech_counts[i] == 0);
145 			continue;
146 		}
147 		pd = provider_array[i];
148 		p[j].le_mechanism_count = mech_counts[i];
149 		p[j].le_dev_instance = pd->pd_instance;
150 		(void) strncpy(p[j].le_dev_name, pd->pd_name, MAXNAMELEN);
151 		j++;
152 	}
153 
154 	kcf_free_provider_tab(provider_count, provider_array);
155 	kmem_free(skip_providers, skip_providers_size);
156 	kmem_free(mech_counts, mech_counts_size);
157 
158 	*array = p;
159 	*count = new_count;
160 	return (CRYPTO_SUCCESS);
161 }
162 
163 /*
164  * Called from the CRYPTO_GET_SOFT_LIST ioctl, this routine returns
165  * a buffer containing the null terminated names of software providers
166  * loaded by CRYPTO_LOAD_SOFT_CONFIG.
167  */
168 int
169 crypto_get_soft_list(uint_t *count, char **array, size_t *len)
170 {
171 	char *names = NULL, *namep, *end;
172 	kcf_soft_conf_entry_t *p;
173 	uint_t n = 0, cnt = 0, final_count = 0;
174 	size_t name_len, final_size = 0;
175 
176 	/* first estimate */
177 	mutex_enter(&soft_config_mutex);
178 	for (p = soft_config_list; p != NULL; p = p->ce_next) {
179 		n += strlen(p->ce_name) + 1;
180 		cnt++;
181 	}
182 	mutex_exit(&soft_config_mutex);
183 
184 	if (cnt == 0)
185 		goto out;
186 
187 again:
188 	namep = names = kmem_alloc(n, KM_SLEEP);
189 	end = names + n;
190 	final_size = 0;
191 	final_count = 0;
192 
193 	mutex_enter(&soft_config_mutex);
194 	for (p = soft_config_list; p != NULL; p = p->ce_next) {
195 		name_len = strlen(p->ce_name) + 1;
196 		/* check for enough space */
197 		if ((namep + name_len) > end) {
198 			mutex_exit(&soft_config_mutex);
199 			kmem_free(names, n);
200 			n = n << 1;
201 			goto again;
202 		}
203 		(void) strcpy(namep, p->ce_name);
204 		namep += name_len;
205 		final_size += name_len;
206 		final_count++;
207 	}
208 	mutex_exit(&soft_config_mutex);
209 
210 	ASSERT(final_size <= n);
211 
212 	/* check if buffer we allocated is too large */
213 	if (final_size < n) {
214 		char *final_buffer;
215 
216 		final_buffer = kmem_alloc(final_size, KM_SLEEP);
217 		bcopy(names, final_buffer, final_size);
218 		kmem_free(names, n);
219 		names = final_buffer;
220 	}
221 out:
222 	*array = names;
223 	*count = final_count;
224 	*len = final_size;
225 	return (CRYPTO_SUCCESS);
226 }
227 
228 /* called from the CRYPTO_GET_DEV_INFO ioctl */
229 int
230 crypto_get_dev_info(char *name, uint_t instance, uint_t *count,
231     crypto_mech_name_t **array)
232 {
233 	int rv;
234 	crypto_mech_name_t *mech_names;
235 	int i, j, k, all_count;
236 	uint_t provider_count;
237 	kcf_provider_desc_t **provider_array;
238 	kcf_provider_desc_t *pd;
239 
240 	/*
241 	 * Get provider table entries matching name and instance
242 	 * for hardware providers that are in a usable state.
243 	 * Logical providers not included. NULL name matches
244 	 * all hardware providers.
245 	 */
246 	rv =  kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
247 	    name, instance, B_FALSE);
248 	if (rv != CRYPTO_SUCCESS)
249 		return (rv);
250 
251 	if (provider_count == 0)
252 		return (CRYPTO_ARGUMENTS_BAD);
253 
254 	/* Get count */
255 	all_count = 0;
256 	for (i = 0; i < provider_count; i++)
257 		all_count += provider_array[i]->pd_mech_list_count;
258 
259 	if (all_count == 0) {
260 		mech_names = NULL;
261 		goto out;
262 	}
263 
264 	/* Allocate space and copy mech names */
265 	mech_names = kmem_alloc(all_count * sizeof (crypto_mech_name_t),
266 	    KM_SLEEP);
267 
268 	k = 0;
269 	for (i = 0; i < provider_count; i++) {
270 		pd = provider_array[i];
271 		for (j = 0; j < pd->pd_mech_list_count; j++, k++)
272 			bcopy(&pd->pd_mechanisms[j].cm_mech_name[0],
273 			    &mech_names[k][0], sizeof (crypto_mech_name_t));
274 	}
275 
276 out:
277 	kcf_free_provider_tab(provider_count, provider_array);
278 	*count = all_count;
279 	*array = mech_names;
280 
281 	return (CRYPTO_SUCCESS);
282 }
283 
284 /* called from the CRYPTO_GET_SOFT_INFO ioctl */
285 int
286 crypto_get_soft_info(caddr_t name, uint_t *count, crypto_mech_name_t **array)
287 {
288 	ddi_modhandle_t modh = NULL;
289 	kcf_provider_desc_t *provider;
290 	int rv;
291 
292 	provider = kcf_prov_tab_lookup_by_name(name);
293 	if (provider == NULL) {
294 		if (in_soft_config_list(name)) {
295 			char *tmp;
296 			int name_len;
297 
298 			/* strlen("crypto/") + NULL terminator == 8 */
299 			name_len = strlen(name);
300 			tmp = kmem_alloc(name_len + 8, KM_SLEEP);
301 			bcopy("crypto/", tmp, 7);
302 			bcopy(name, &tmp[7], name_len);
303 			tmp[name_len + 7] = '\0';
304 
305 			modh = ddi_modopen(tmp, KRTLD_MODE_FIRST, NULL);
306 			kmem_free(tmp, name_len + 8);
307 
308 			if (modh == NULL) {
309 				return (CRYPTO_ARGUMENTS_BAD);
310 			}
311 
312 			provider = kcf_prov_tab_lookup_by_name(name);
313 			if (provider == NULL) {
314 				return (CRYPTO_ARGUMENTS_BAD);
315 			}
316 		} else {
317 			return (CRYPTO_ARGUMENTS_BAD);
318 		}
319 	}
320 
321 	rv = dup_mech_names(provider, array, count, KM_SLEEP);
322 	KCF_PROV_REFRELE(provider);
323 	if (modh != NULL)
324 		(void) ddi_modclose(modh);
325 	return (rv);
326 }
327 
328 static void
329 kcf_change_mechs(kcf_provider_desc_t *provider, uint_t count,
330     crypto_mech_name_t *array, crypto_event_change_t direction)
331 {
332 	crypto_notify_event_change_t ec;
333 	crypto_mech_info_t *mi;
334 	kcf_prov_mech_desc_t *pmd;
335 	char *mech;
336 	int i, j, n;
337 
338 	ASSERT(direction == CRYPTO_MECH_ADDED ||
339 	    direction == CRYPTO_MECH_REMOVED);
340 
341 	if (provider == NULL) {
342 		/*
343 		 * Nothing to add or remove from the tables since
344 		 * the provider isn't registered.
345 		 */
346 		return;
347 	}
348 
349 	for (i = 0; i < count; i++) {
350 		if (array[i][0] == '\0')
351 			continue;
352 
353 		mech = &array[i][0];
354 
355 		n = provider->pd_mech_list_count;
356 		for (j = 0; j < n; j++) {
357 			mi = &provider->pd_mechanisms[j];
358 			if (strncmp(mi->cm_mech_name, mech,
359 			    CRYPTO_MAX_MECH_NAME) == 0)
360 				break;
361 		}
362 		if (j == n)
363 			continue;
364 
365 		switch (direction) {
366 		case CRYPTO_MECH_ADDED:
367 			(void) kcf_add_mech_provider(j, provider, &pmd);
368 			break;
369 
370 		case CRYPTO_MECH_REMOVED:
371 			kcf_remove_mech_provider(mech, provider);
372 			break;
373 		}
374 
375 		/* Inform interested clients of the event */
376 		ec.ec_provider_type = provider->pd_prov_type;
377 		ec.ec_change = direction;
378 
379 		(void) strncpy(ec.ec_mech_name, mech, CRYPTO_MAX_MECH_NAME);
380 		kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
381 	}
382 }
383 
384 /*
385  * If a mech name in the second array (prev_array) is also in the
386  * first array, then a NULL character is written into the first byte
387  * of the mech name in the second array.  This effectively removes
388  * the mech name from the second array.
389  */
390 static void
391 kcf_compare_mechs(uint_t count, crypto_mech_name_t *array, uint_t prev_count,
392     crypto_mech_name_t *prev_array)
393 {
394 	int i, j;
395 
396 	for (i = 0; i < prev_count; i++) {
397 		for (j = 0; j < count; j++) {
398 			if (strncmp(&prev_array[i][0], &array[j][0],
399 			    CRYPTO_MAX_MECH_NAME) == 0) {
400 				prev_array[i][0] = '\0';
401 			}
402 		}
403 	}
404 }
405 
406 /*
407  * Called from CRYPTO_LOAD_DEV_DISABLED ioctl.
408  * If new_count is 0, then completely remove the entry.
409  */
410 int
411 crypto_load_dev_disabled(char *name, uint_t instance, uint_t new_count,
412     crypto_mech_name_t *new_array)
413 {
414 	kcf_provider_desc_t *provider = NULL;
415 	kcf_provider_desc_t **provider_array;
416 	crypto_mech_name_t *prev_array;
417 	uint_t provider_count, prev_count;
418 	int i, rv = CRYPTO_SUCCESS;
419 
420 	/*
421 	 * Remove the policy entry if new_count is 0, otherwise put disabled
422 	 * mechanisms into policy table.
423 	 */
424 	if (new_count == 0) {
425 		kcf_policy_remove_by_dev(name, instance, &prev_count,
426 		    &prev_array);
427 	} else if ((rv = kcf_policy_load_dev_disabled(name, instance, new_count,
428 	    new_array, &prev_count, &prev_array)) != CRYPTO_SUCCESS) {
429 		return (rv);
430 	}
431 
432 	/*
433 	 * Get provider table entries matching name and instance
434 	 * for providers that are are in a usable or unverified state.
435 	 */
436 	rv =  kcf_get_hw_prov_tab(&provider_count, &provider_array, KM_SLEEP,
437 	    name, instance, B_TRUE);
438 	if (rv != CRYPTO_SUCCESS)
439 		return (rv);
440 
441 	for (i = 0; i < provider_count; i++) {
442 		provider = provider_array[i];
443 
444 		/* previously disabled mechanisms may become enabled */
445 		if (prev_array != NULL) {
446 			kcf_compare_mechs(new_count, new_array,
447 			    prev_count, prev_array);
448 			kcf_change_mechs(provider, prev_count, prev_array,
449 			    CRYPTO_MECH_ADDED);
450 		}
451 
452 		kcf_change_mechs(provider, new_count, new_array,
453 		    CRYPTO_MECH_REMOVED);
454 	}
455 
456 	kcf_free_provider_tab(provider_count, provider_array);
457 	crypto_free_mech_list(prev_array, prev_count);
458 	return (rv);
459 }
460 
461 /*
462  * Called from CRYPTO_LOAD_SOFT_DISABLED ioctl.
463  * If new_count is 0, then completely remove the entry.
464  */
465 int
466 crypto_load_soft_disabled(char *name, uint_t new_count,
467     crypto_mech_name_t *new_array)
468 {
469 	kcf_provider_desc_t *provider = NULL;
470 	crypto_mech_name_t *prev_array;
471 	uint_t prev_count = 0;
472 	int rv;
473 
474 	provider = kcf_prov_tab_lookup_by_name(name);
475 	if (provider != NULL) {
476 		mutex_enter(&provider->pd_lock);
477 		/*
478 		 * Check if any other thread is disabling or removing
479 		 * this provider. We return if this is the case.
480 		 */
481 		if (provider->pd_state >= KCF_PROV_DISABLED) {
482 			mutex_exit(&provider->pd_lock);
483 			KCF_PROV_REFRELE(provider);
484 			return (CRYPTO_BUSY);
485 		}
486 		provider->pd_state = KCF_PROV_DISABLED;
487 		mutex_exit(&provider->pd_lock);
488 
489 		undo_register_provider(provider, B_TRUE);
490 		KCF_PROV_REFRELE(provider);
491 		if (provider->pd_kstat != NULL)
492 			KCF_PROV_REFRELE(provider);
493 
494 		mutex_enter(&provider->pd_lock);
495 		/* Wait till the existing requests complete. */
496 		while (provider->pd_state != KCF_PROV_FREED) {
497 			cv_wait(&provider->pd_remove_cv, &provider->pd_lock);
498 		}
499 		mutex_exit(&provider->pd_lock);
500 	}
501 
502 	if (new_count == 0) {
503 		kcf_policy_remove_by_name(name, &prev_count, &prev_array);
504 		crypto_free_mech_list(prev_array, prev_count);
505 		rv = CRYPTO_SUCCESS;
506 		goto out;
507 	}
508 
509 	/* put disabled mechanisms into policy table */
510 	if ((rv = kcf_policy_load_soft_disabled(name, new_count, new_array,
511 	    &prev_count, &prev_array)) == CRYPTO_SUCCESS) {
512 		crypto_free_mech_list(prev_array, prev_count);
513 	}
514 
515 out:
516 	if (provider != NULL) {
517 		redo_register_provider(provider);
518 		if (provider->pd_kstat != NULL)
519 			KCF_PROV_REFHOLD(provider);
520 		mutex_enter(&provider->pd_lock);
521 		provider->pd_state = KCF_PROV_READY;
522 		mutex_exit(&provider->pd_lock);
523 	} else if (rv == CRYPTO_SUCCESS) {
524 		/*
525 		 * There are some cases where it is useful to kCF clients
526 		 * to have a provider whose mechanism is enabled now to be
527 		 * available. So, we attempt to load it here.
528 		 *
529 		 * The check, new_count < prev_count, ensures that we do this
530 		 * only in the case where a mechanism(s) is now enabled.
531 		 * This check assumes that enable and disable are separate
532 		 * administrative actions and are not done in a single action.
533 		 */
534 		if (new_count < prev_count && (in_soft_config_list(name)) &&
535 		    (modload("crypto", name) != -1)) {
536 			struct modctl *mcp;
537 			boolean_t load_again = B_FALSE;
538 
539 			if ((mcp = mod_hold_by_name(name)) != NULL) {
540 				mcp->mod_loadflags |= MOD_NOAUTOUNLOAD;
541 
542 				/* memory pressure may have unloaded module */
543 				if (!mcp->mod_installed)
544 					load_again = B_TRUE;
545 				mod_release_mod(mcp);
546 
547 				if (load_again)
548 					(void) modload("crypto", name);
549 			}
550 		}
551 	}
552 
553 	return (rv);
554 }
555 
556 /* called from the CRYPTO_LOAD_SOFT_CONFIG ioctl */
557 int
558 crypto_load_soft_config(caddr_t name, uint_t count, crypto_mech_name_t *array)
559 {
560 	return (add_soft_config(name, count, array));
561 }
562 
563 /* called from the CRYPTO_UNLOAD_SOFT_MODULE ioctl */
564 int
565 crypto_unload_soft_module(caddr_t name)
566 {
567 	int error;
568 	modid_t id;
569 	kcf_provider_desc_t *provider;
570 	struct modctl *mcp;
571 
572 	/* verify that 'name' refers to a registered crypto provider */
573 	if ((provider = kcf_prov_tab_lookup_by_name(name)) == NULL)
574 		return (CRYPTO_UNKNOWN_PROVIDER);
575 
576 	/*
577 	 * We save the module id and release the reference. We need to
578 	 * do this as modunload() calls unregister which waits for the
579 	 * refcnt to drop to zero.
580 	 */
581 	id = provider->pd_module_id;
582 	KCF_PROV_REFRELE(provider);
583 
584 	if ((mcp = mod_hold_by_name(name)) != NULL) {
585 		mcp->mod_loadflags &= ~(MOD_NOAUTOUNLOAD);
586 		mod_release_mod(mcp);
587 	}
588 
589 	if ((error = modunload(id)) != 0) {
590 		return (error == EBUSY ? CRYPTO_BUSY : CRYPTO_FAILED);
591 	}
592 
593 	return (CRYPTO_SUCCESS);
594 }
595 
596 /* called from CRYPTO_GET_DEV_LIST ioctl */
597 void
598 crypto_free_dev_list(crypto_dev_list_entry_t *array, uint_t count)
599 {
600 	if (count ==  0 || array == NULL)
601 		return;
602 
603 	kmem_free(array, count * sizeof (crypto_dev_list_entry_t));
604 }
605 
606 /*
607  * Returns duplicate array of mechanisms.  The array is allocated and
608  * must be freed by the caller.
609  */
610 static int
611 dup_mech_names(kcf_provider_desc_t *provider, crypto_mech_name_t **array,
612     uint_t *count, int kmflag)
613 {
614 	crypto_mech_name_t *mech_names;
615 	uint_t n;
616 	uint_t i;
617 
618 	if ((n = provider->pd_mech_list_count) == 0) {
619 		*count = 0;
620 		*array = NULL;
621 		return (CRYPTO_SUCCESS);
622 	}
623 
624 	mech_names = kmem_alloc(n * sizeof (crypto_mech_name_t), kmflag);
625 	if (mech_names == NULL)
626 		return (CRYPTO_HOST_MEMORY);
627 
628 	for (i = 0; i < n; i++) {
629 		bcopy(&provider->pd_mechanisms[i].cm_mech_name[0],
630 		    &mech_names[i][0], sizeof (crypto_mech_name_t));
631 	}
632 
633 	*count = n;
634 	*array = mech_names;
635 	return (CRYPTO_SUCCESS);
636 }
637 
638 /*
639  * Returns B_TRUE if the specified mechanism is disabled, B_FALSE otherwise.
640  */
641 boolean_t
642 is_mech_disabled_byname(crypto_provider_type_t prov_type, char *pd_name,
643     uint_t pd_instance, crypto_mech_name_t mech_name)
644 {
645 	kcf_policy_desc_t *policy;
646 	uint_t i;
647 
648 	ASSERT(prov_type == CRYPTO_SW_PROVIDER ||
649 	    prov_type == CRYPTO_HW_PROVIDER);
650 
651 	switch (prov_type) {
652 	case CRYPTO_SW_PROVIDER:
653 		policy = kcf_policy_lookup_by_name(pd_name);
654 		/* no policy for provider - so mechanism can't be disabled */
655 		if (policy == NULL)
656 			return (B_FALSE);
657 		break;
658 
659 	case CRYPTO_HW_PROVIDER:
660 		policy = kcf_policy_lookup_by_dev(pd_name, pd_instance);
661 		/* no policy for provider - so mechanism can't be disabled */
662 		if (policy == NULL)
663 			return (B_FALSE);
664 		break;
665 	}
666 
667 	mutex_enter(&policy->pd_mutex);
668 	for (i = 0; i < policy->pd_disabled_count; i ++) {
669 		if (strncmp(mech_name, &policy->pd_disabled_mechs[i][0],
670 		    CRYPTO_MAX_MECH_NAME) == 0) {
671 			mutex_exit(&policy->pd_mutex);
672 			KCF_POLICY_REFRELE(policy);
673 			return (B_TRUE);
674 		}
675 	}
676 	mutex_exit(&policy->pd_mutex);
677 	KCF_POLICY_REFRELE(policy);
678 	return (B_FALSE);
679 }
680 
681 /*
682  * Returns B_TRUE if the specified mechanism is disabled, B_FALSE otherwise.
683  *
684  * This is a wrapper routine around is_mech_disabled_byname() above and
685  * takes a pointer kcf_provider_desc structure as argument.
686  */
687 boolean_t
688 is_mech_disabled(kcf_provider_desc_t *provider, crypto_mech_name_t name)
689 {
690 	kcf_provider_list_t *e;
691 	kcf_provider_desc_t *pd;
692 	boolean_t found = B_FALSE;
693 	uint_t count, i;
694 
695 	if (provider->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
696 		return (is_mech_disabled_byname(provider->pd_prov_type,
697 		    provider->pd_name, provider->pd_instance, name));
698 	}
699 
700 	/*
701 	 * Lock the logical provider just in case one of its hardware
702 	 * provider members unregisters.
703 	 */
704 	mutex_enter(&provider->pd_lock);
705 	for (e = provider->pd_provider_list; e != NULL; e = e->pl_next) {
706 
707 		pd = e->pl_provider;
708 		ASSERT(pd->pd_prov_type == CRYPTO_HW_PROVIDER);
709 
710 		/* find out if mechanism is offered by hw provider */
711 		count = pd->pd_mech_list_count;
712 		for (i = 0; i < count; i++) {
713 			if (strncmp(&pd->pd_mechanisms[i].cm_mech_name[0],
714 			    name, MAXNAMELEN) == 0) {
715 				break;
716 			}
717 		}
718 		if (i == count)
719 			continue;
720 
721 		found = !is_mech_disabled_byname(pd->pd_prov_type,
722 		    pd->pd_name, pd->pd_instance, name);
723 
724 		if (found)
725 			break;
726 	}
727 	mutex_exit(&provider->pd_lock);
728 	/*
729 	 * If we found the mechanism, then it means it is still enabled for
730 	 * at least one hardware provider, so the mech can't be disabled
731 	 * for the logical provider.
732 	 */
733 	return (!found);
734 }
735 
736 /*
737  * Builds array of permitted mechanisms.  The array is allocated and
738  * must be freed by the caller.
739  */
740 int
741 crypto_build_permitted_mech_names(kcf_provider_desc_t *provider,
742     crypto_mech_name_t **array, uint_t *count, int kmflag)
743 {
744 	crypto_mech_name_t *mech_names, *p;
745 	uint_t i;
746 	uint_t scnt = provider->pd_mech_list_count;
747 	uint_t dcnt = 0;
748 
749 	/*
750 	 * Compute number of 'permitted mechanisms', which is
751 	 * 'supported mechanisms' - 'disabled mechanisms'.
752 	 */
753 	for (i = 0; i < scnt; i++) {
754 		if (is_mech_disabled(provider,
755 		    &provider->pd_mechanisms[i].cm_mech_name[0])) {
756 			dcnt++;
757 		}
758 	}
759 
760 	/* all supported mechanisms have been disabled */
761 	if (scnt == dcnt) {
762 		*count = 0;
763 		*array = NULL;
764 		return (CRYPTO_SUCCESS);
765 	}
766 
767 	mech_names = kmem_alloc((scnt - dcnt) * sizeof (crypto_mech_name_t),
768 	    kmflag);
769 	if (mech_names == NULL)
770 		return (CRYPTO_HOST_MEMORY);
771 
772 	/* build array of permitted mechanisms */
773 	for (i = 0, p = mech_names; i < scnt; i++) {
774 		if (!is_mech_disabled(provider,
775 		    &provider->pd_mechanisms[i].cm_mech_name[0])) {
776 			bcopy(&provider->pd_mechanisms[i].cm_mech_name[0],
777 			    p++, sizeof (crypto_mech_name_t));
778 		}
779 	}
780 
781 	*count = scnt - dcnt;
782 	*array = mech_names;
783 	return (CRYPTO_SUCCESS);
784 }
785 
786 static void
787 free_soft_config_entry(kcf_soft_conf_entry_t *p)
788 {
789 	kmem_free(p->ce_name, strlen(p->ce_name) + 1);
790 	crypto_free_mech_list(p->ce_mechs, p->ce_count);
791 	kmem_free(p, sizeof (kcf_soft_conf_entry_t));
792 }
793 
794 /*
795  * Called from the CRYPTO_LOAD_SOFT_CONFIG ioctl, this routine stores
796  * configuration information for software providers in a linked list.
797  * If the list already contains an entry for the specified provider
798  * and the specified mechanism list has at least one mechanism, then
799  * the mechanism list for the provider is updated. If the mechanism list
800  * is empty, the entry for the provider is removed.
801  *
802  * Important note: the array argument is consumed.
803  */
804 static int
805 add_soft_config(char *name, uint_t count, crypto_mech_name_t *array)
806 {
807 	static uint_t soft_config_count = 0;
808 	kcf_soft_conf_entry_t *prev = NULL, *entry = NULL, *new_entry, *p;
809 	size_t name_len;
810 
811 	/*
812 	 * Allocate storage for a new entry.
813 	 * Free later if an entry already exists.
814 	 */
815 	name_len = strlen(name) + 1;
816 	new_entry = kmem_zalloc(sizeof (kcf_soft_conf_entry_t), KM_SLEEP);
817 	new_entry->ce_name = kmem_alloc(name_len, KM_SLEEP);
818 	(void) strcpy(new_entry->ce_name, name);
819 
820 	mutex_enter(&soft_config_mutex);
821 	p = soft_config_list;
822 	if (p != NULL) {
823 		do {
824 			if (strncmp(name, p->ce_name, MAXNAMELEN) == 0) {
825 				entry = p;
826 				break;
827 			}
828 			prev = p;
829 
830 		} while ((p = p->ce_next) != NULL);
831 	}
832 
833 	if (entry == NULL) {
834 		if (count == 0) {
835 			mutex_exit(&soft_config_mutex);
836 			kmem_free(new_entry->ce_name, name_len);
837 			kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t));
838 			return (CRYPTO_SUCCESS);
839 		}
840 
841 		if (soft_config_count > KCF_MAX_CONFIG_ENTRIES) {
842 			mutex_exit(&soft_config_mutex);
843 			kmem_free(new_entry->ce_name, name_len);
844 			kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t));
845 			cmn_err(CE_WARN, "out of soft_config_list entries");
846 			return (CRYPTO_FAILED);
847 		}
848 
849 		/* add to head of list */
850 		new_entry->ce_next = soft_config_list;
851 		soft_config_list = new_entry;
852 		soft_config_count++;
853 		entry = new_entry;
854 	} else {
855 		kmem_free(new_entry->ce_name, name_len);
856 		kmem_free(new_entry, sizeof (kcf_soft_conf_entry_t));
857 	}
858 
859 	/* mechanism count == 0 means remove entry from list */
860 	if (count == 0) {
861 		if (prev == NULL) {
862 			/* remove first in list */
863 			soft_config_list = entry->ce_next;
864 		} else {
865 			prev->ce_next = entry->ce_next;
866 		}
867 		soft_config_count--;
868 		mutex_exit(&soft_config_mutex);
869 
870 		/* free entry */
871 		free_soft_config_entry(entry);
872 
873 		return (CRYPTO_SUCCESS);
874 	}
875 
876 
877 	/* replace mechanisms */
878 	if (entry->ce_mechs != NULL)
879 		crypto_free_mech_list(entry->ce_mechs, entry->ce_count);
880 
881 	entry->ce_mechs = array;
882 	entry->ce_count = count;
883 	mutex_exit(&soft_config_mutex);
884 
885 	return (CRYPTO_SUCCESS);
886 }
887 
888 /*
889  * This routine searches the soft_config_list for the first entry that
890  * has the specified mechanism in its mechanism list.  If found,
891  * a buffer containing the name of the software module that implements
892  * the mechanism is allocated and stored in 'name'.
893  */
894 int
895 get_sw_provider_for_mech(crypto_mech_name_t mech, char **name)
896 {
897 	kcf_soft_conf_entry_t *p, *next;
898 	char tmp_name[MAXNAMELEN];
899 	size_t name_len = 0;
900 	int i;
901 
902 	mutex_enter(&soft_config_mutex);
903 	p = soft_config_list;
904 	while (p != NULL) {
905 		next = p->ce_next;
906 		for (i = 0; i < p->ce_count; i++) {
907 			if (strcmp(mech, &p->ce_mechs[i][0]) == 0) {
908 				name_len = strlen(p->ce_name) + 1;
909 				bcopy(p->ce_name, tmp_name, name_len);
910 				break;
911 			}
912 		}
913 		p = next;
914 	}
915 	mutex_exit(&soft_config_mutex);
916 
917 	if (name_len == 0)
918 		return (CRYPTO_FAILED);
919 
920 	*name = kmem_alloc(name_len, KM_SLEEP);
921 	bcopy(tmp_name, *name, name_len);
922 	return (CRYPTO_SUCCESS);
923 }
924 
925 /*
926  * This routine searches the soft_config_list for the specified
927  * software provider, returning B_TRUE if it is in the list.
928  */
929 boolean_t
930 in_soft_config_list(char *provider_name)
931 {
932 	kcf_soft_conf_entry_t *p;
933 	boolean_t rv = B_FALSE;
934 
935 	mutex_enter(&soft_config_mutex);
936 	for (p = soft_config_list; p != NULL; p = p->ce_next) {
937 		if (strcmp(provider_name, p->ce_name) == 0) {
938 			rv = B_TRUE;
939 			break;
940 		}
941 	}
942 	mutex_exit(&soft_config_mutex);
943 	return (rv);
944 }
945