summaryrefslogtreecommitdiff
path: root/usr/src/lib/pkcs11/libpkcs11/common/pkcs11Conf.c
blob: d33f8808a8a8b6ed566778961f96b03cb3a657d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
 */
/*
 * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <pthread.h>
#include <sys/mman.h>

#include <sys/crypto/elfsign.h>
#include <cryptoutil.h>

#include <security/cryptoki.h>
#include "pkcs11Global.h"
#include "pkcs11Conf.h"
#include "pkcs11Slot.h"
#include "metaGlobal.h"

/*
 * Fastpath is used when there is only one slot available from a single provider
 * plugged into the framework this is the common case.
 * These globals are used to track the function pointers and policy when
 * the fast-path is activated.
 * This will need to be revisted if per-slot policy is ever
 * implemented.
 */
boolean_t purefastpath = B_FALSE;
boolean_t policyfastpath = B_FALSE;
CK_FUNCTION_LIST_PTR fast_funcs = NULL;
CK_SLOT_ID fast_slot = 0;
boolean_t metaslot_enabled = B_FALSE;
boolean_t metaslot_auto_key_migrate = B_FALSE;
metaslot_config_t metaslot_config;
void (*Tmp_GetThreshold)(void *) = NULL;
cipher_mechs_threshold_t meta_mechs_threshold[MAX_NUM_THRESHOLD];

static const char *conf_err = "See cryptoadm(8). Skipping this plug-in.";

/*
 * Set up metaslot for the framework using either user configuration
 * or system wide configuration options
 *
 * Also sets up the global "slottable" to have the first slot be metaslot.
 */
static CK_RV
setup_metaslot(uentry_t *metaslot_entry) {
	CK_RV rv;
	CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL;
	pkcs11_slot_t *cur_slot;

	/* process policies for mechanisms */
	if ((metaslot_entry) && (metaslot_entry->count > 0)) {
		rv = pkcs11_mech_parse(metaslot_entry->policylist,
		    &prov_pol_mechs, metaslot_entry->count);

		if (rv == CKR_HOST_MEMORY) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: Could not parse configuration,"
			    "out of memory. Cannot continue parsing "
			    "%s.\n", _PATH_PKCS11_CONF);
			return (rv);
		} else if (rv == CKR_MECHANISM_INVALID) {
			/*
			 * Configuration file is corrupted for metaslot
			 */
			cryptoerror(LOG_ERR,
			    "libpkcs11: Policy invalid or corrupted "
			    "for metaslot. Use cryptoadm(8) to fix "
			    "this. Disabling metaslot functionality.\n");
			metaslot_enabled = B_FALSE;
			return (rv);
		}
	}

	/*
	 * Check for metaslot policy.  If all mechanisms are
	 * disabled, disable metaslot since there is nothing
	 * interesting for it to do
	 */
	if ((metaslot_entry) && (metaslot_entry->flag_enabledlist) &&
	    (prov_pol_mechs == NULL)) {
		metaslot_enabled = B_FALSE;
		return (rv);
	}

	/*
	 * save system wide value for metaslot's keystore.
	 * If either slot description or token label is specified by
	 * the user, the system wide value for both is ignored.
	 */
	if ((metaslot_entry) &&
	    (!metaslot_config.keystore_token_specified) &&
	    (!metaslot_config.keystore_slot_specified)) {
		/*
		 * blank_str is used for comparing with token label,
		 * and slot description, make sure it is better than
		 * the larger of both
		 */
		char blank_str[TOKEN_LABEL_SIZE + SLOT_DESCRIPTION_SIZE];

		bzero(blank_str, sizeof (blank_str));

		if (memcmp(metaslot_entry->metaslot_ks_token,
		    blank_str, TOKEN_LABEL_SIZE) != 0) {
			metaslot_config.keystore_token_specified = B_TRUE;
			(void) strlcpy(
			    (char *)metaslot_config.keystore_token,
			    (const char *)metaslot_entry->metaslot_ks_token,
			    TOKEN_LABEL_SIZE);
		}

		if (memcmp(metaslot_entry->metaslot_ks_slot,
		    blank_str, SLOT_DESCRIPTION_SIZE) != 0) {
			metaslot_config.keystore_slot_specified = B_TRUE;
			(void) strlcpy(
			    (char *)metaslot_config.keystore_slot,
			    (const char *)metaslot_entry->metaslot_ks_slot,
			    SLOT_DESCRIPTION_SIZE);
		}
	}

	/* check system-wide value for auto_key_migrate */
	if (metaslot_config.auto_key_migrate_specified) {
		/* take user's specified value */
		metaslot_auto_key_migrate = metaslot_config.auto_key_migrate;
	} else {
		if (metaslot_entry) {
			/* use system-wide default */
			metaslot_auto_key_migrate =
			    metaslot_entry->flag_metaslot_auto_key_migrate;
		} else {
			/*
			 * there's no system wide metaslot entry,
			 * default auto_key_migrate to true
			 */
			metaslot_auto_key_migrate = B_TRUE;
		}
	}


	/* Make first slotID be 0, for metaslot. */
	slottable->st_first = 0;

	/* Set up the slottable entry for metaslot */
	slottable->st_slots[0] = NULL;
	cur_slot = calloc(1, sizeof (pkcs11_slot_t));
	if (cur_slot == NULL) {
		rv = CKR_HOST_MEMORY;
		return (rv);
	}
	cur_slot->sl_wfse_state = WFSE_CLEAR;
	cur_slot->sl_enabledpol = B_FALSE;
	cur_slot->sl_no_wfse = B_FALSE;
	(void) pthread_mutex_init(&cur_slot->sl_mutex, NULL);

	/*
	 * The metaslot entry was prealloc'd by
	 * pkcs11_slottable_increase()
	 */
	(void) pthread_mutex_lock(&slottable->st_mutex);
	slottable->st_slots[0] = cur_slot;
	(void) pthread_mutex_unlock(&slottable->st_mutex);

	(void) pthread_mutex_lock(&cur_slot->sl_mutex);
	cur_slot->sl_id = METASLOT_SLOTID;
	cur_slot->sl_func_list = &metaslot_functionList;
	if (metaslot_entry) {
		cur_slot->sl_enabledpol = metaslot_entry->flag_enabledlist;
		cur_slot->sl_pol_count = metaslot_entry->count;
	} else {
		/* if no metaslot entry, assume all mechs are enabled */
		cur_slot->sl_enabledpol = B_FALSE;
		cur_slot->sl_pol_count = 0;
	}
	cur_slot->sl_pol_mechs = prov_pol_mechs;
	cur_slot->sl_dldesc = NULL; /* not applicable */
	cur_slot->sl_prov_id = 0;
	(void) pthread_mutex_unlock(&cur_slot->sl_mutex);

	/* Call the meta_Initialize() to initialize metaslot */
	rv = meta_Initialize(NULL);
	if (rv != CKR_OK) {
		cryptoerror(LOG_ERR,
		    "libpkcs11: Can't initialize metaslot (%s)",
		    pkcs11_strerror(rv));
		goto cleanup;
	}

	return (CKR_OK);

cleanup:
	metaslot_enabled = B_FALSE;
	slottable->st_slots[0] = NULL;

	if (cur_slot) {
		(void) pthread_mutex_destroy(&cur_slot->sl_mutex);
		free(cur_slot);
	}
	return (rv);
}

/*
 * For each provider found in pkcs11.conf: expand $ISA if necessary,
 * verify the module is signed, load the provider, find all of its
 * slots, and store the function list and disabled policy.
 *
 * This function requires that the uentrylist_t and pkcs11_slottable_t
 * already have memory allocated, and that the uentrylist_t is already
 * populated with provider and policy information.
 *
 * pInitArgs can be set to NULL, but is normally the same value
 * the framework's C_Initialize() was called with.
 *
 * Unless metaslot is explicitly disabled, it is setup when all other
 * providers are loaded.
 */
CK_RV
pkcs11_slot_mapping(uentrylist_t *pplist, CK_VOID_PTR pInitArgs)
{
	CK_RV rv = CKR_OK;
	CK_RV prov_rv;			/* Provider's return code */
	CK_INFO prov_info;
	CK_RV (*Tmp_C_GetFunctionList)(CK_FUNCTION_LIST_PTR_PTR);
	CK_FUNCTION_LIST_PTR prov_funcs = NULL; /* Provider's function list */
	CK_ULONG prov_slot_count; 		/* Number of slots */
	CK_SLOT_ID slot_id; 		/* slotID assigned for framework */
	CK_SLOT_ID_PTR prov_slots = NULL; 	/* Provider's slot list */
					/* Enabled or Disabled policy */
	CK_MECHANISM_TYPE_PTR prov_pol_mechs = NULL;

	void *dldesc = NULL;
	char *isa, *fullpath = NULL, *dl_error;
	uentrylist_t *phead;
	uint_t prov_count = 0;
	pkcs11_slot_t *cur_slot;
	CK_ULONG i;
	size_t len;
	uentry_t *metaslot_entry = NULL;
	/* number of slots in the framework, not including metaslot */
	uint_t slot_count = 0;

	phead = pplist;

	/* Loop through all of the provider listed in pkcs11.conf */
	while (phead != NULL) {
		if (!strcasecmp(phead->puent->name, "metaslot")) {
			/*
			 * Skip standard processing for metaslot
			 * entry since it is not an actual library
			 * that can be dlopened.
			 * It will be initialized later.
			 */
			if (metaslot_entry != NULL) {
				cryptoerror(LOG_ERR,
				    "libpkcs11: multiple entries for metaslot "
				    "detected.  All but the first entry will "
				    "be ignored");
			} else {
				metaslot_entry = phead->puent;
			}
			goto contparse;
		}

		if (!strcasecmp(phead->puent->name, FIPS_KEYWORD)) {
			/*
			 * Skip standard processing for fips-140
			 * entry since it is not an actual library
			 * that can be dlopened.
			 */
			goto contparse;
		}

		/* Check for Instruction Set Architecture indicator */
		if ((isa = strstr(phead->puent->name, PKCS11_ISA)) != NULL) {
			/* Substitute the architecture dependent path */
			len = strlen(phead->puent->name) -
			    strlen(PKCS11_ISA) +
			    strlen(PKCS11_ISA_DIR) + 1;
			if ((fullpath = (char *)malloc(len)) == NULL) {
				cryptoerror(LOG_ERR,
				    "libpksc11: parsing %s, out of memory. "
				    "Cannot continue parsing.",
				    _PATH_PKCS11_CONF);
				rv = CKR_HOST_MEMORY;
				goto conferror;
			}
			*isa = '\000';
			isa += strlen(PKCS11_ISA);
			(void) snprintf(fullpath, len, "%s%s%s",
			    phead->puent->name, PKCS11_ISA_DIR, isa);
		} else if ((fullpath = strdup(phead->puent->name)) == 0) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: parsing %s, out of memory. "
			    "Cannot continue parsing.",
			    _PATH_PKCS11_CONF);
			rv = CKR_HOST_MEMORY;
			goto conferror;
		}

		/*
		 * Open the provider. We assume all of our plugins have
		 * their symbols properly defined, so the use of RTLD_NOW
		 * to flush out errors immediately is not necessary.
		 *
		 * Note that for proper operation, all plugins must be
		 * built with direct bindings enabled.
		 */
		dldesc = dlopen(fullpath, RTLD_LAZY);

		/*
		 * If we failed to load it, we will just skip this
		 * provider and move on to the next one.
		 */
		if (dldesc == NULL) {
			dl_error = dlerror();
			cryptoerror(LOG_ERR,
			    "libpkcs11: Cannot load PKCS#11 library %s.  "
			    "dlerror: %s. %s",
			    fullpath, dl_error != NULL ? dl_error : "Unknown",
			    conf_err);
			goto contparse;
		}

		/* Get the pointer to provider's C_GetFunctionList() */
		Tmp_C_GetFunctionList =
		    (CK_RV(*)())dlsym(dldesc, "C_GetFunctionList");

		/*
		 * If we failed to get the pointer to C_GetFunctionList(),
		 * skip this provider and continue to the next one.
		 */
		if (Tmp_C_GetFunctionList == NULL) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: Could not dlsym() C_GetFunctionList() "
			    "for %s. May not be a PKCS#11 library. %s",
			    fullpath, conf_err);
			(void) dlclose(dldesc);
			goto contparse;
		}


		/* Get the provider's function list */
		prov_rv = Tmp_C_GetFunctionList(&prov_funcs);

		/*
		 * If we failed to get the provider's function list,
		 * skip this provider and continue to the next one.
		 */
		if (prov_rv != CKR_OK) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: Could not get function list for %s. "
			    "%s Error: %s.",
			    fullpath, conf_err, pkcs11_strerror(prov_rv));
			(void) dlclose(dldesc);
			goto contparse;
		}

		/* Initialize this provider */
		prov_rv = prov_funcs->C_Initialize(pInitArgs);

		/*
		 * If we failed to initialize this provider,
		 * skip this provider and continue to the next one.
		 */
		if ((prov_rv != CKR_OK) &&
		    (prov_rv != CKR_CRYPTOKI_ALREADY_INITIALIZED)) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: Could not initialize %s. "
			    "%s Error: %s.",
			    fullpath, conf_err, pkcs11_strerror(prov_rv));
			(void) dlclose(dldesc);
			goto contparse;
		}

		/*
		 * Make sure this provider is implementing the same
		 * major version, and at least the same minor version
		 * that we are.
		 */
		prov_rv = prov_funcs->C_GetInfo(&prov_info);

		/*
		 * If we can't verify that we are implementing the
		 * same major version, or if it is definitely not the same
		 * version, we need to skip this provider.
		 */
		if ((prov_rv != CKR_OK) ||
		    (prov_info.cryptokiVersion.major !=
		    CRYPTOKI_VERSION_MAJOR))  {
			if (prov_rv != CKR_OK) {
				cryptoerror(LOG_ERR,
				    "libpkcs11: Could not verify version of "
				    "%s. %s Error: %s.", fullpath,
				    conf_err, pkcs11_strerror(prov_rv));
			} else {
				cryptoerror(LOG_ERR,
				    "libpkcs11: Only CRYPTOKI major version "
				    "%d is supported.  %s is major "
				    "version %d. %s",
				    CRYPTOKI_VERSION_MAJOR, fullpath,
				    prov_info.cryptokiVersion.major, conf_err);
			}
			(void) prov_funcs->C_Finalize(NULL);
			(void) dlclose(dldesc);
			goto contparse;
		}

		/*
		 * Warn the administrator (at debug) that a provider with
		 * a significantly older or newer version of
		 * CRYPTOKI is being used.  It should not cause
		 * problems, but logging a warning makes it easier
		 * to debug later.
		 */
		if ((prov_info.cryptokiVersion.minor <
		    CRYPTOKI_VERSION_WARN_MINOR) ||
		    (prov_info.cryptokiVersion.minor >
		    CRYPTOKI_VERSION_MINOR)) {
			cryptoerror(LOG_DEBUG,
			    "libpkcs11: %s CRYPTOKI minor version, %d, may "
			    "not be compatible with minor version %d.",
			    fullpath, prov_info.cryptokiVersion.minor,
			    CRYPTOKI_VERSION_MINOR);
		}

		/*
		 * Find out how many slots this provider has,
		 * call with tokenPresent set to FALSE so all
		 * potential slots are returned.
		 */
		prov_rv = prov_funcs->C_GetSlotList(FALSE,
		    NULL, &prov_slot_count);

		/*
		 * If the call failed, or if no slots are returned,
		 * then skip this provider and continue to next one.
		 */
		if (prov_rv != CKR_OK) {
			cryptoerror(LOG_ERR,
			    "libpksc11: Could not get slot list from %s. "
			    "%s Error: %s.",
			    fullpath, conf_err, pkcs11_strerror(prov_rv));
			(void) prov_funcs->C_Finalize(NULL);
			(void) dlclose(dldesc);
			goto contparse;
		}

		if (prov_slot_count == 0) {
			cryptodebug("libpkcs11: No slots presented from %s. "
			    "Skipping this plug-in at this time.\n",
			    fullpath);
			(void) prov_funcs->C_Finalize(NULL);
			(void) dlclose(dldesc);
			goto contparse;
		}

		/* Allocate memory for the slot list */
		prov_slots = calloc(prov_slot_count, sizeof (CK_SLOT_ID));

		if (prov_slots == NULL) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: Could not allocate memory for "
			    "plug-in slots. Cannot continue parsing %s\n",
			    _PATH_PKCS11_CONF);
			rv = CKR_HOST_MEMORY;
			goto conferror;
		}

		/* Get slot list from provider */
		prov_rv = prov_funcs->C_GetSlotList(FALSE,
		    prov_slots, &prov_slot_count);

		/* if second call fails, drop this provider */
		if (prov_rv != CKR_OK) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: Second call to C_GetSlotList() for %s "
			    "failed. %s Error: %s.",
			    fullpath, conf_err, pkcs11_strerror(prov_rv));
			(void) prov_funcs->C_Finalize(NULL);
			(void) dlclose(dldesc);
			goto contparse;
		}

		/*
		 * Parse the list of disabled or enabled mechanisms, will
		 * apply to each of the provider's slots.
		 */
		if (phead->puent->count > 0) {
			rv = pkcs11_mech_parse(phead->puent->policylist,
			    &prov_pol_mechs, phead->puent->count);

			if (rv == CKR_HOST_MEMORY) {
				cryptoerror(LOG_ERR,
				    "libpkcs11: Could not parse configuration,"
				    "out of memory. Cannot continue parsing "
				    "%s.", _PATH_PKCS11_CONF);
				goto conferror;
			} else if (rv == CKR_MECHANISM_INVALID) {
				/*
				 * Configuration file is corrupted for this
				 * provider.
				 */
				cryptoerror(LOG_ERR,
				    "libpkcs11: Policy invalid or corrupted "
				    "for %s. Use cryptoadm(8) to fix "
				    "this. Skipping this plug-in.",
				    fullpath);
				(void) prov_funcs->C_Finalize(NULL);
				(void) dlclose(dldesc);
				goto contparse;
			}
		}

		/* Allocate memory in our slottable for these slots */
		rv = pkcs11_slottable_increase(prov_slot_count);

		/*
		 * If any error is returned, it will be memory related,
		 * so we need to abort the attempt at filling the
		 * slottable.
		 */
		if (rv != CKR_OK) {
			cryptoerror(LOG_ERR,
			    "libpkcs11: slottable could not increase. "
			    "Cannot continue parsing %s.",
			    _PATH_PKCS11_CONF);
			goto conferror;
		}

		/* Configure information for each new slot */
		for (i = 0; i < prov_slot_count; i++) {
			/* allocate slot in framework */
			rv = pkcs11_slot_allocate(&slot_id);
			if (rv != CKR_OK) {
				cryptoerror(LOG_ERR,
				    "libpkcs11: Could not allocate "
				    "new slot.  Cannot continue parsing %s.",
				    _PATH_PKCS11_CONF);
				goto conferror;
			}
			slot_count++;
			cur_slot = slottable->st_slots[slot_id];
			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
			cur_slot->sl_id = prov_slots[i];
			cur_slot->sl_func_list = prov_funcs;
			cur_slot->sl_enabledpol =
			    phead->puent->flag_enabledlist;
			cur_slot->sl_pol_mechs = prov_pol_mechs;
			cur_slot->sl_pol_count = phead->puent->count;
			cur_slot->sl_norandom = phead->puent->flag_norandom;
			cur_slot->sl_dldesc = dldesc;
			cur_slot->sl_prov_id = prov_count + 1;
			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
		}

		/*
		 * Get the pointer to private interface _SUNW_GetThreshold()
		 * in pkcs11_kernel.
		 */

		if (Tmp_GetThreshold == NULL) {
			Tmp_GetThreshold =
			    (void(*)())dlsym(dldesc, "_SUNW_GetThreshold");

			/* Get the threshold values for the supported mechs */
			if (Tmp_GetThreshold != NULL) {
				(void) memset(meta_mechs_threshold, 0,
				    sizeof (meta_mechs_threshold));
				Tmp_GetThreshold(meta_mechs_threshold);
			}
		}

		/* Set and reset values to process next provider */
		prov_count++;
contparse:
		prov_slot_count = 0;
		Tmp_C_GetFunctionList = NULL;
		prov_funcs = NULL;
		dldesc = NULL;
		if (fullpath != NULL) {
			free(fullpath);
			fullpath = NULL;
		}
		if (prov_slots != NULL) {
			free(prov_slots);
			prov_slots = NULL;
		}
		phead = phead->next;
	}

	if (slot_count == 0) {
		/*
		 * there's no other slot in the framework,
		 * there is nothing to do
		 */
		goto config_complete;
	}

	/* determine if metaslot should be enabled */

	/*
	 * Check to see if any environment variable is defined
	 * by the user for configuring metaslot.  Users'
	 * setting always take precedence over the system wide
	 * setting.  So, we will first check for any user's
	 * defined env variables before looking at the system-wide
	 * configuration.
	 */
	get_user_metaslot_config();

	/* no metaslot entry in /etc/crypto/pkcs11.conf */
	if (!metaslot_entry) {
		/*
		 * If user env variable indicates metaslot should be enabled,
		 * but there's no entry in /etc/crypto/pkcs11.conf for
		 * metaslot at all, will respect the user's defined value
		 */
		if ((metaslot_config.enabled_specified) &&
		    (metaslot_config.enabled)) {
			metaslot_enabled = B_TRUE;
		}
	} else {
		if (!metaslot_config.enabled_specified) {
			/*
			 * take system wide value if
			 * it is not specified by user
			 */
			metaslot_enabled
			    = metaslot_entry->flag_metaslot_enabled;
		} else {
			metaslot_enabled = metaslot_config.enabled;
		}
	}

	/*
	 *
	 * As long as the user or system configuration file does not
	 * disable metaslot, it will be enabled regardless of the
	 * number of slots plugged into the framework.  Therefore,
	 * metaslot is enabled even when there's only one slot
	 * plugged into the framework.  This is necessary for
	 * presenting a consistent token label view to applications.
	 *
	 * However, for the case where there is only 1 slot plugged into
	 * the framework, we can use "fastpath".
	 *
	 * "fastpath" will pass all of the application's requests
	 * directly to the underlying provider.  Only when policy is in
	 * effect will we need to keep slotID around.
	 *
	 * When metaslot is enabled, and fastpath is enabled,
	 * all the metaslot processing will be skipped.
	 * When there is only 1 slot, there's
	 * really not much metaslot can do in terms of combining functionality
	 * of different slots, and object migration.
	 *
	 */

	/* check to see if fastpath can be used */
	if (slottable->st_last == slottable->st_first) {

		cur_slot = slottable->st_slots[slottable->st_first];

		(void) pthread_mutex_lock(&cur_slot->sl_mutex);

		if ((cur_slot->sl_pol_count == 0) &&
		    (!cur_slot->sl_enabledpol) && (!cur_slot->sl_norandom)) {
			/* No policy is in effect, don't need slotid */
			fast_funcs = cur_slot->sl_func_list;
			purefastpath = B_TRUE;
		} else {
			fast_funcs = cur_slot->sl_func_list;
			fast_slot = slottable->st_first;
			policyfastpath = B_TRUE;
		}

		(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
	}

	if ((purefastpath || policyfastpath) && (!metaslot_enabled)) {
		goto config_complete;
	}

	/*
	 * If we get here, there are more than 2 slots in the framework,
	 * we need to set up metaslot if it is enabled
	 */
	if (metaslot_enabled) {
		rv = setup_metaslot(metaslot_entry);
		if (rv != CKR_OK) {
			goto conferror;
		}
	}


config_complete:

	return (CKR_OK);

conferror:
	/*
	 * This cleanup code is only exercised when a major,
	 * unrecoverable error like "out of memory".
	 */
	if (prov_funcs != NULL) {
		(void) prov_funcs->C_Finalize(NULL);
	}
	if (dldesc != NULL) {
		(void) dlclose(dldesc);
	}
	if (fullpath != NULL) {
		free(fullpath);
		fullpath = NULL;
	}
	if (prov_slots != NULL) {
		free(prov_slots);
		prov_slots = NULL;
	}

	return (rv);
}

/*
 * pkcs11_mech_parse will take hex mechanism ids, as a list of
 * strings, and convert them to CK_MECHANISM_TYPE_PTR.
 */
CK_RV
pkcs11_mech_parse(umechlist_t *str_list, CK_MECHANISM_TYPE_PTR *mech_list,
    int mech_count)
{
	CK_MECHANISM_TYPE_PTR tmp_list;
	umechlist_t *shead = str_list;

	tmp_list = malloc(mech_count * sizeof (CK_MECHANISM_TYPE));

	if (tmp_list == NULL) {
		cryptoerror(LOG_ERR, "libpkcs11: parsing %s, out of memory. "
		    "Cannot continue.",
		    _PATH_PKCS11_CONF);
		return (CKR_HOST_MEMORY);
	}

	*mech_list = tmp_list;

	/*
	 * The following will loop mech_count times, as there are
	 * exactly mech_count items in the str_list.
	 */
	while (shead != NULL) {
		CK_MECHANISM_TYPE cur_mech;

		errno = 0;

		/*
		 * "name" is a hexadecimal number, preceded by 0x.
		 */
		cur_mech = strtoul(shead->name, NULL, 16);

		if ((cur_mech == 0) &&
		    ((errno == EINVAL) || (errno == ERANGE))) {
			free(mech_list);
			return (CKR_MECHANISM_INVALID);
		}
		*tmp_list = (CK_MECHANISM_TYPE)cur_mech;
		tmp_list++;
		shead = shead->next;
	}

	return (CKR_OK);
}

/*
 * pkcs11_is_dismech is provided a slotid and a mechanism.
 * If mech is not disabled, then return B_FALSE.
 */
boolean_t
pkcs11_is_dismech(CK_SLOT_ID slotid, CK_MECHANISM_TYPE mech)
{
	ulong_t i;
	boolean_t enabled_pol;
	CK_MECHANISM_TYPE_PTR pol_mechs;
	ulong_t pol_count;

	/* Find the associated slot and get the mech policy info */
	(void) pthread_mutex_lock(&slottable->st_slots[slotid]->sl_mutex);
	enabled_pol = slottable->st_slots[slotid]->sl_enabledpol;
	pol_mechs = slottable->st_slots[slotid]->sl_pol_mechs;
	pol_count = slottable->st_slots[slotid]->sl_pol_count;
	(void) pthread_mutex_unlock(&slottable->st_slots[slotid]->sl_mutex);

	/* Check for policy */
	if ((!enabled_pol) && (pol_mechs == NULL)) {
		/* no policy */
		return (B_FALSE);
	} else if (pol_mechs == NULL) {
		/*
		 * We have an empty enabled list, which means no
		 * mechanisms are exempted from this policy: all
		 * are disabled.
		 */
		return (B_TRUE);
	}

	for (i = 0; i < pol_count; i++) {
		/*
		 * If it matches, return status based on this
		 * being and enabled or a disabled list of mechs.
		 */
		if (pol_mechs[i] == mech) {
			return (enabled_pol ? B_FALSE : B_TRUE);
		}
	}

	/* mech was not found in list */
	return (enabled_pol ? B_TRUE : B_FALSE);
}