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 
35 pkcs11_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  */
43 CK_RV
pkcs11_slottable_initialize()44 pkcs11_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  */
84 CK_RV
pkcs11_slottable_increase(ulong_t increment)85 pkcs11_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  */
122 CK_RV
pkcs11_slot_allocate(CK_SLOT_ID * pslot_id)123 pkcs11_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  */
162 CK_RV
pkcs11_slottable_delete()163 pkcs11_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  */
265 CK_RV
pkcs11_is_valid_slot(CK_SLOT_ID slot_id)266 pkcs11_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  */
291 CK_RV
pkcs11_validate_and_convert_slotid(CK_SLOT_ID slot_id,CK_SLOT_ID * real_slot_id)292 pkcs11_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