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/*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <dlfcn.h>
27#include <stdlib.h>
28#include <pthread.h>
29#include <strings.h>
30#include <security/cryptoki.h>
31#include "pkcs11Global.h"
32#include "pkcs11Slot.h"
33#include "metaGlobal.h"
34
35pkcs11_slottable_t *slottable = NULL;
36
37/*
38 * pkcs11_slottable_initialize initizializes the global slottable.
39 * This slottable will contain information about the plugged in
40 * slots, including their mapped slotID.  This function should only
41 * be called by C_Intialize.
42 */
43CK_RV
44pkcs11_slottable_initialize() {
45
46
47	pkcs11_slottable_t *stmp = malloc(sizeof (pkcs11_slottable_t));
48
49	if (stmp == NULL)
50		return (CKR_HOST_MEMORY);
51
52	stmp->st_first = 1;
53	stmp->st_cur_size = 0;
54	stmp->st_last = 0;
55	stmp->st_slots = NULL;
56
57	if (pthread_mutex_init(&stmp->st_mutex, NULL) != 0) {
58		free(stmp);
59		return (CKR_FUNCTION_FAILED);
60	}
61	/* Set up for possible threads later */
62	stmp->st_event_slot = 0;
63	stmp->st_thr_count = 0;
64	stmp->st_wfse_active = B_FALSE;
65	stmp->st_blocking = B_FALSE;
66	stmp->st_list_signaled = B_FALSE;
67
68	(void) pthread_cond_init(&stmp->st_wait_cond, NULL);
69	(void) pthread_mutex_init(&stmp->st_start_mutex, NULL);
70	(void) pthread_cond_init(&stmp->st_start_cond, NULL);
71
72	slottable = stmp;
73
74	return (CKR_OK);
75
76}
77
78/*
79 * pkcs11_slottable_increase should only be called from C_Initialize().
80 * It is called after the first call to C_GetSlotList() and is used to
81 * increase the size of the slottable, as needed, to contain the next
82 * set of slots that C_Initialize() is currently mapping into the framework.
83 */
84CK_RV
85pkcs11_slottable_increase(ulong_t increment) {
86
87	pkcs11_slot_t **tmpslots;
88	ulong_t newsize;
89
90	(void) pthread_mutex_lock(&slottable->st_mutex);
91
92	/* Add 1 to cover space for the metaslot */
93	newsize = slottable->st_last + increment + 1;
94
95	/* Check to see if we already have enough space */
96	if (slottable->st_cur_size >= newsize) {
97		(void) pthread_mutex_unlock(&slottable->st_mutex);
98		return (CKR_OK);
99	}
100
101	tmpslots = realloc
102	    (slottable->st_slots, newsize * sizeof (pkcs11_slot_t *));
103
104	if (tmpslots == NULL) {
105		(void) pthread_mutex_unlock(&slottable->st_mutex);
106		return (CKR_HOST_MEMORY);
107	}
108
109	slottable->st_slots = tmpslots;
110	slottable->st_cur_size = newsize;
111
112	(void) pthread_mutex_unlock(&slottable->st_mutex);
113
114	return (CKR_OK);
115}
116
117/*
118 * pkcs11_slot_allocate should only be called from C_Initialize().
119 * We won't know if the metaslot will be used until after all of
120 * the other slots have been allocated.
121 */
122CK_RV
123pkcs11_slot_allocate(CK_SLOT_ID *pslot_id) {
124
125	pkcs11_slot_t *tmpslot;
126
127	tmpslot = malloc(sizeof (pkcs11_slot_t));
128
129	if (tmpslot == NULL)
130		return (CKR_HOST_MEMORY);
131
132	bzero(tmpslot, sizeof (pkcs11_slot_t));
133
134	tmpslot->sl_wfse_state = WFSE_CLEAR;
135	tmpslot->sl_enabledpol = B_FALSE;
136	tmpslot->sl_no_wfse = B_FALSE;
137
138	/* Initialize this slot's mutex */
139	if (pthread_mutex_init(&tmpslot->sl_mutex, NULL) != 0) {
140		free(tmpslot);
141		return (CKR_FUNCTION_FAILED);
142	}
143
144	(void) pthread_mutex_lock(&slottable->st_mutex);
145
146	slottable->st_last++;
147
148	*pslot_id = slottable->st_last;
149
150	slottable->st_slots[*pslot_id] = tmpslot;
151
152	(void) pthread_mutex_unlock(&slottable->st_mutex);
153
154	return (CKR_OK);
155
156}
157
158/*
159 * pkcs11_slottable_delete should only be called by C_Finalize(),
160 * or by C_Initialize() in error conditions.
161 */
162CK_RV
163pkcs11_slottable_delete() {
164
165	ulong_t i;
166	uint32_t prov_id;
167	int32_t last_prov_id = -1;
168	pkcs11_slot_t *cur_slot;
169
170	(void) pthread_mutex_lock(&slottable->st_mutex);
171
172	for (i = slottable->st_first; i <= slottable->st_last; i++) {
173
174		if (slottable->st_slots[i] != NULL) {
175
176			cur_slot = slottable->st_slots[i];
177			prov_id = cur_slot->sl_prov_id;
178
179			(void) pthread_mutex_lock(&cur_slot->sl_mutex);
180
181			/*
182			 * For the first slot from this provider, do
183			 * extra cleanup.
184			 */
185			if (prov_id != last_prov_id) {
186
187				if (cur_slot->sl_wfse_state == WFSE_ACTIVE) {
188					(void) pthread_cancel
189					    (cur_slot->sl_tid);
190				}
191
192				/*
193				 * Only call C_Finalize of plug-in if we
194				 * get here from an explicit C_Finalize
195				 * call from an application.  Otherwise,
196				 * there is a risk that the application may
197				 * have directly dlopened this provider and
198				 * we could interrupt their work.  Plug-ins
199				 * should have their own _fini function to
200				 * clean up when they are no longer referenced.
201				 */
202				if ((cur_slot->sl_func_list != NULL) &&
203				    (!fini_called)) {
204					(void) cur_slot->
205					    sl_func_list->C_Finalize(NULL);
206				}
207
208				/* metaslot won't have a sl_dldesc! */
209				if (cur_slot->sl_dldesc != NULL) {
210					(void) dlclose(cur_slot->sl_dldesc);
211				}
212
213				/*
214				 * Each provider maintains one disabled
215				 * mechanism list for each of its slots to use.
216				 */
217				if (cur_slot->sl_pol_mechs != NULL)
218					free(cur_slot->sl_pol_mechs);
219			}
220
221			if (cur_slot->sl_wfse_args != NULL) {
222				free(cur_slot->sl_wfse_args);
223			}
224
225			(void) pthread_mutex_unlock(&cur_slot->sl_mutex);
226
227			/*
228			 * Cleanup the session list.  This must
229			 * happen after the mutext is unlocked
230			 * because session_delete tries to lock it
231			 * again.
232			 */
233			pkcs11_sessionlist_delete(cur_slot);
234
235			(void) pthread_mutex_destroy(&cur_slot->sl_mutex);
236
237			free(cur_slot);
238			cur_slot = NULL;
239			last_prov_id = prov_id;
240		}
241	}
242
243	(void) pthread_cond_destroy(&slottable->st_wait_cond);
244	(void) pthread_mutex_destroy(&slottable->st_start_mutex);
245	(void) pthread_cond_destroy(&slottable->st_start_cond);
246
247	free(slottable->st_slots);
248
249	(void) pthread_mutex_unlock(&slottable->st_mutex);
250
251	(void) pthread_mutex_destroy(&slottable->st_mutex);
252
253	free(slottable);
254
255	slottable = NULL;
256
257	return (CKR_OK);
258
259}
260
261/*
262 * pkcs11_is_valid_slot verifies that the slot ID passed to the
263 * framework is valid.
264 */
265CK_RV
266pkcs11_is_valid_slot(CK_SLOT_ID slot_id) {
267
268	if ((slot_id < slottable->st_first) ||
269	    (slot_id > slottable->st_last)) {
270		return (CKR_SLOT_ID_INVALID);
271	} else if (slottable->st_slots[slot_id] != NULL) {
272		return (CKR_OK);
273	} else {
274		return (CKR_SLOT_ID_INVALID);
275	}
276}
277
278
279/*
280 * pkcs11_validate_and_convert_slotid verifies whether the slot ID
281 * passed to the framework is valid, and convert it to the
282 * true slot ID maintained in the framework data structures
283 * accordingly.
284 *
285 * This is necessary because when metaslot is enabled, the slot
286 * providing persistent object storage is "hidden".
287 *
288 * The real ID is returned in the "real_slot_id" argument regardless conversion
289 * is done or not.
290 */
291CK_RV
292pkcs11_validate_and_convert_slotid(CK_SLOT_ID slot_id,
293    CK_SLOT_ID *real_slot_id) {
294
295	if (!metaslot_enabled) {
296		*real_slot_id = slot_id;
297	} else {
298		/* need to do conversion */
299		if (slot_id >= metaslot_keystore_slotid) {
300			*real_slot_id = slot_id + 1;
301		} else {
302			*real_slot_id = slot_id;
303		}
304	}
305	return (pkcs11_is_valid_slot(*real_slot_id));
306}
307