xref: /titanic_41/usr/src/lib/pkcs11/pkcs11_kernel/common/kernelSession.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <pthread.h>
30 #include <errno.h>
31 #include <security/cryptoki.h>
32 #include <sys/crypto/ioctl.h>
33 #include "kernelGlobal.h"
34 #include "kernelSession.h"
35 #include "kernelSlot.h"
36 
37 CK_RV
38 C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication,
39     CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession)
40 {
41 	CK_RV rv = CKR_OK;
42 	kernel_slot_t	*pslot;
43 
44 	if (!kernel_initialized)
45 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
46 
47 	/*
48 	 * For legacy reasons, the CKF_SERIAL_SESSION bit must always
49 	 * be set.
50 	 */
51 	if (!(flags & CKF_SERIAL_SESSION))
52 		return (CKR_SESSION_PARALLEL_NOT_SUPPORTED);
53 
54 	if (phSession == NULL)
55 		return (CKR_ARGUMENTS_BAD);
56 
57 	if (slotID >= slot_count) {
58 		return (CKR_SLOT_ID_INVALID);
59 	}
60 
61 	/*
62 	 * Acquire the slot lock to protect sl_state and sl_sess_list.
63 	 * These two fields need to be protected atomically, even though
64 	 * "sl_sess_list" is updated in kernel_add_session().
65 	 */
66 	pslot = slot_table[slotID];
67 	(void) pthread_mutex_lock(&pslot->sl_mutex);
68 
69 	/* If SO is logged in the slot, only the RW session is allowed. */
70 	if ((pslot->sl_state == CKU_SO) && !(flags & CKF_RW_SESSION)) {
71 		(void) pthread_mutex_unlock(&pslot->sl_mutex);
72 		return (CKR_SESSION_READ_WRITE_SO_EXISTS);
73 	}
74 
75 	/* Create a new session */
76 	rv = kernel_add_session(slotID, flags, pApplication, Notify,
77 	    phSession);
78 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
79 	return (rv);
80 }
81 
82 CK_RV
83 C_CloseSession(CK_SESSION_HANDLE hSession)
84 {
85 	CK_RV rv;
86 
87 	kernel_session_t *session_p;
88 	boolean_t ses_lock_held = B_FALSE;
89 
90 	if (!kernel_initialized)
91 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
92 
93 	/*
94 	 * Obtain the session pointer. Also, increment the session
95 	 * reference count.
96 	 */
97 	rv = handle2session(hSession, &session_p);
98 	if (rv != CKR_OK)
99 		return (rv);
100 
101 	(void) pthread_mutex_lock(&session_p->session_mutex);
102 	ses_lock_held = B_TRUE;
103 
104 	/*
105 	 * Set SESSION_IS_CLOSING flag so any access to this
106 	 * session will be rejected.
107 	 */
108 	session_p->ses_close_sync |= SESSION_IS_CLOSING;
109 
110 	/*
111 	 * Decrement the session reference count.
112 	 * We hold the session lock, and REFRELE()
113 	 * will release the session lock for us.
114 	 */
115 	REFRELE(session_p, ses_lock_held);
116 
117 	/*
118 	 * Delete a session by calling kernel_delete_session() with
119 	 * a session pointer and two boolean arguments. The 3rd argument
120 	 * boolean value FALSE indicates that the caller does not
121 	 * hold the slot lock.  The 4th argument boolean value B_FALSE
122 	 * indicates that we want to delete all the objects completely.
123 	 *
124 	 * kernel_delete_session() will reset SESSION_IS_CLOSING
125 	 * flag after it is done.
126 	 */
127 	rv = kernel_delete_session(session_p->ses_slotid, session_p, B_FALSE,
128 	    B_FALSE);
129 	return (rv);
130 }
131 
132 
133 CK_RV
134 C_CloseAllSessions(CK_SLOT_ID slotID)
135 {
136 	CK_RV rv = CKR_OK;
137 
138 	if (!kernel_initialized)
139 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
140 
141 	/* Delete all the sessions and release the allocated resources */
142 	rv = kernel_delete_all_sessions(slotID, B_FALSE);
143 
144 	return (rv);
145 }
146 
147 CK_RV
148 C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo)
149 {
150 	kernel_session_t *session_p;
151 	CK_RV rv;
152 	boolean_t ses_lock_held = B_FALSE;
153 	kernel_slot_t	*pslot;
154 
155 	if (!kernel_initialized)
156 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
157 
158 	if (pInfo == NULL)
159 		return (CKR_ARGUMENTS_BAD);
160 
161 	/*
162 	 * Obtain the session pointer. Also, increment the session
163 	 * reference count.
164 	 */
165 	rv = handle2session(hSession, &session_p);
166 	if (rv != CKR_OK)
167 		return (rv);
168 
169 	/* Provide information for the specified session */
170 	pInfo->slotID = session_p->ses_slotid;
171 	pInfo->flags = session_p->flags;
172 	pInfo->ulDeviceError = 0;
173 
174 	pslot = slot_table[session_p->ses_slotid];
175 	(void) pthread_mutex_lock(&pslot->sl_mutex);
176 
177 	if (pslot->sl_state == CKU_PUBLIC) {
178 		pInfo->state = (session_p->ses_RO) ?
179 		    CKS_RO_PUBLIC_SESSION : CKS_RW_PUBLIC_SESSION;
180 	} else if (pslot->sl_state == CKU_USER) {
181 		pInfo->state = (session_p->ses_RO) ?
182 		    CKS_RO_USER_FUNCTIONS : CKS_RW_USER_FUNCTIONS;
183 	} else if (pslot->sl_state == CKU_SO) {
184 		pInfo->state = CKS_RW_SO_FUNCTIONS;
185 	}
186 
187 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
188 
189 	/*
190 	 * Decrement the session reference count.
191 	 */
192 	REFRELE(session_p, ses_lock_held);
193 
194 	return (CKR_OK);
195 }
196 
197 
198 /*ARGSUSED*/
199 CK_RV
200 C_GetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
201     CK_ULONG_PTR pulOperationStateLen)
202 {
203 	if (!kernel_initialized)
204 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
205 
206 	return (CKR_FUNCTION_NOT_SUPPORTED);
207 }
208 
209 
210 /*ARGSUSED*/
211 CK_RV
212 C_SetOperationState(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState,
213     CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
214     CK_OBJECT_HANDLE hAuthenticationKey)
215 {
216 	if (!kernel_initialized)
217 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
218 
219 	return (CKR_FUNCTION_NOT_SUPPORTED);
220 }
221 
222 
223 CK_RV
224 C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType,
225     CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
226 {
227 	CK_RV	rv = CKR_OK;
228 	kernel_session_t *session_p;
229 	kernel_slot_t	*pslot;
230 	boolean_t ses_lock_held = B_FALSE;
231 	crypto_login_t  c_login;
232 	int r;
233 
234 	if (!kernel_initialized)
235 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
236 
237 	if ((userType != CKU_SO) && (userType != CKU_USER)) {
238 		return (CKR_USER_TYPE_INVALID);
239 	}
240 
241 	/*
242 	 * Obtain the session pointer. Also, increment the session
243 	 * reference count.
244 	 */
245 	rv = handle2session(hSession, &session_p);
246 	if (rv != CKR_OK)
247 		return (rv);
248 
249 	/* Acquire the slot lock */
250 	pslot = slot_table[session_p->ses_slotid];
251 	(void) pthread_mutex_lock(&pslot->sl_mutex);
252 
253 	/* Check if the slot is logged in already */
254 	if ((pslot->sl_state == CKU_USER) || (pslot->sl_state == CKU_SO)) {
255 		rv = CKR_USER_ALREADY_LOGGED_IN;
256 		goto clean_exit;
257 	}
258 
259 	/* To login as SO, every session in this slot needs to be R/W */
260 	if (userType == CKU_SO) {
261 		kernel_session_t  *sp;
262 		boolean_t	found;
263 
264 		found = B_FALSE;
265 		sp = pslot->sl_sess_list;
266 		while (sp) {
267 			/*
268 			 * Need not to lock individual sessions before
269 			 * accessing their "ses_RO" and "next" fields,
270 			 * because they are always accessed under the
271 			 * slot's mutex protection.
272 			 */
273 			if (sp->ses_RO) {
274 				found = B_TRUE;
275 				break;
276 			}
277 			sp = sp->next;
278 		}
279 
280 		if (found) {
281 			rv = CKR_SESSION_READ_ONLY_EXISTS;
282 			goto clean_exit;
283 		}
284 	}
285 
286 	/* Now make the ioctl call; no need to acquire the session lock. */
287 	c_login.co_session = session_p->k_session;
288 	c_login.co_user_type = userType;
289 	c_login.co_pin_len = ulPinLen;
290 	c_login.co_pin = (char *)pPin;
291 
292 	while ((r = ioctl(kernel_fd, CRYPTO_LOGIN, &c_login)) < 0) {
293 		if (errno != EINTR)
294 			break;
295 	}
296 	if (r < 0) {
297 		rv = CKR_FUNCTION_FAILED;
298 	} else {
299 		rv = crypto2pkcs11_error_number(c_login.co_return_value);
300 	}
301 
302 	if (rv == CKR_OK) {
303 		/* Set the slot's session state. */
304 		pslot->sl_state = userType;
305 	}
306 
307 clean_exit:
308 
309 	REFRELE(session_p, ses_lock_held);
310 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
311 	return (rv);
312 }
313 
314 
315 CK_RV
316 C_Logout(CK_SESSION_HANDLE hSession)
317 {
318 	CK_RV	rv = CKR_OK;
319 	kernel_session_t *session_p;
320 	kernel_slot_t	*pslot;
321 	boolean_t ses_lock_held = B_FALSE;
322 	crypto_logout_t  c_logout;
323 	int r;
324 
325 	if (!kernel_initialized)
326 		return (CKR_CRYPTOKI_NOT_INITIALIZED);
327 
328 	/*
329 	 * Obtain the session pointer. Also, increment the session
330 	 * reference count.
331 	 */
332 	rv = handle2session(hSession, &session_p);
333 	if (rv != CKR_OK)
334 		return (rv);
335 
336 	/* Acquire the slot lock. */
337 	pslot = slot_table[session_p->ses_slotid];
338 	(void) pthread_mutex_lock(&pslot->sl_mutex);
339 
340 	/* Check if the user or SO was logged in  */
341 	if (pslot->sl_state == CKU_PUBLIC) {
342 		rv = CKR_USER_NOT_LOGGED_IN;
343 		goto clean_exit;
344 	}
345 
346 	/* Now make the ioctl call. No need to acquire the session lock. */
347 	c_logout.cl_session = session_p->k_session;
348 	while ((r = ioctl(kernel_fd, CRYPTO_LOGOUT, &c_logout)) < 0) {
349 		if (errno != EINTR)
350 			break;
351 	}
352 	if (r < 0) {
353 		rv = CKR_FUNCTION_FAILED;
354 	} else {
355 		rv = crypto2pkcs11_error_number(c_logout.cl_return_value);
356 	}
357 
358 	if (rv != CKR_OK) {
359 		goto clean_exit;
360 	}
361 
362 	/*
363 	 * If this slot was logged in as USER previously, we need to clean up
364 	 * all private object wrappers in library for this slot.
365 	 */
366 	kernel_cleanup_pri_objects_in_slot(pslot, session_p);
367 
368 	if (rv == CKR_OK) {
369 		/* Reset the slot's session state. */
370 		pslot->sl_state = CKU_PUBLIC;
371 	}
372 
373 clean_exit:
374 	REFRELE(session_p, ses_lock_held);
375 	(void) pthread_mutex_unlock(&pslot->sl_mutex);
376 	return (rv);
377 }
378