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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <md5.h>
27 #include <pthread.h>
28 #include <syslog.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <sys/sha1.h>
33 #include <security/cryptoki.h>
34 #include "softGlobal.h"
35 #include "softSession.h"
36 #include "softObject.h"
37 #include "softOps.h"
38 #include "softKeystore.h"
39 #include "softKeystoreUtil.h"
40
41
42 CK_ULONG soft_session_cnt = 0; /* the number of opened sessions */
43 CK_ULONG soft_session_rw_cnt = 0; /* the number of opened R/W sessions */
44
45 #define DIGEST_MECH_OK(_m_) ((_m_) == CKM_MD5 || (_m_) == CKM_SHA_1)
46
47 /*
48 * Delete all the sessions. First, obtain the global session
49 * list lock. Then start to delete one session at a time.
50 * Release the global session list lock before returning to
51 * caller.
52 */
53 CK_RV
soft_delete_all_sessions(boolean_t force)54 soft_delete_all_sessions(boolean_t force)
55 {
56
57 CK_RV rv = CKR_OK;
58 CK_RV rv1;
59 soft_session_t *session_p;
60 soft_session_t *session_p1;
61
62 /* Acquire the global session list lock */
63 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
64
65 session_p = soft_session_list;
66
67 /* Delete all the sessions in the session list */
68 while (session_p) {
69 session_p1 = session_p->next;
70
71 /*
72 * Delete a session by calling soft_delete_session()
73 * with a session pointer and a boolean arguments.
74 * Boolean value TRUE is used to indicate that the
75 * caller holds the lock on the global session list.
76 *
77 */
78 rv1 = soft_delete_session(session_p, force, B_TRUE);
79
80 /* Record the very first error code */
81 if (rv == CKR_OK) {
82 rv = rv1;
83 }
84
85 session_p = session_p1;
86 }
87
88 /* No session left */
89 soft_session_list = NULL;
90
91 /* Release the global session list lock */
92 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
93
94 return (rv);
95
96 }
97
98
99 /*
100 * Create a new session struct, and add it to the session linked list.
101 *
102 * This function will acquire the global session list lock, and release
103 * it after adding the session to the session linked list.
104 */
105 CK_RV
soft_add_session(CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY notify,CK_ULONG * sessionhandle_p)106 soft_add_session(CK_FLAGS flags, CK_VOID_PTR pApplication,
107 CK_NOTIFY notify, CK_ULONG *sessionhandle_p)
108 {
109
110 soft_session_t *new_sp = NULL;
111
112 /* Allocate a new session struct */
113 new_sp = calloc(1, sizeof (soft_session_t));
114 if (new_sp == NULL) {
115 return (CKR_HOST_MEMORY);
116 }
117
118 new_sp->magic_marker = SOFTTOKEN_SESSION_MAGIC;
119 new_sp->pApplication = pApplication;
120 new_sp->Notify = notify;
121 new_sp->flags = flags;
122 new_sp->state = CKS_RO_PUBLIC_SESSION;
123 new_sp->object_list = NULL;
124 new_sp->ses_refcnt = 0;
125 new_sp->ses_close_sync = 0;
126
127 (void) pthread_mutex_lock(&soft_giant_mutex);
128 if (soft_slot.authenticated) {
129 (void) pthread_mutex_unlock(&soft_giant_mutex);
130 if (flags & CKF_RW_SESSION) {
131 new_sp->state = CKS_RW_USER_FUNCTIONS;
132 } else {
133 new_sp->state = CKS_RO_USER_FUNCTIONS;
134 }
135 } else {
136 (void) pthread_mutex_unlock(&soft_giant_mutex);
137 if (flags & CKF_RW_SESSION) {
138 new_sp->state = CKS_RW_PUBLIC_SESSION;
139 } else {
140 new_sp->state = CKS_RO_PUBLIC_SESSION;
141 }
142 }
143
144 /* Initialize the lock for the newly created session */
145 if (pthread_mutex_init(&new_sp->session_mutex, NULL) != 0) {
146 free(new_sp);
147 return (CKR_CANT_LOCK);
148 }
149
150 (void) pthread_cond_init(&new_sp->ses_free_cond, NULL);
151
152 /* Acquire the global session list lock */
153 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
154
155 /* Insert the new session in front of session list */
156 if (soft_session_list == NULL) {
157 soft_session_list = new_sp;
158 new_sp->next = NULL;
159 new_sp->prev = NULL;
160 } else {
161 soft_session_list->prev = new_sp;
162 new_sp->next = soft_session_list;
163 new_sp->prev = NULL;
164 soft_session_list = new_sp;
165 }
166
167 /* Type casting the address of a session struct to a session handle */
168 *sessionhandle_p = (CK_ULONG)new_sp;
169 ++soft_session_cnt;
170 if (flags & CKF_RW_SESSION)
171 ++soft_session_rw_cnt;
172
173 if (soft_session_cnt == 1)
174 /*
175 * This is the first session to be opened, so we can set
176 * validate the public token objects in token list now.
177 */
178 soft_validate_token_objects(B_TRUE);
179
180 /* Release the global session list lock */
181 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
182
183 return (CKR_OK);
184
185 }
186
187 /*
188 * This function adds the to-be-freed session to a linked list.
189 * When the number of sessions queued in the linked list reaches the
190 * maximum threshold MAX_SES_TO_BE_FREED, it will free the first
191 * session (FIFO) in the list.
192 */
193 void
session_delay_free(soft_session_t * sp)194 session_delay_free(soft_session_t *sp)
195 {
196 soft_session_t *tmp;
197
198 (void) pthread_mutex_lock(&ses_delay_freed.ses_to_be_free_mutex);
199
200 /* Add the newly deleted session at the end of the list */
201 sp->next = NULL;
202 if (ses_delay_freed.first == NULL) {
203 ses_delay_freed.last = sp;
204 ses_delay_freed.first = sp;
205 } else {
206 ses_delay_freed.last->next = sp;
207 ses_delay_freed.last = sp;
208 }
209
210 if (++ses_delay_freed.count >= MAX_SES_TO_BE_FREED) {
211 /*
212 * Free the first session in the list only if
213 * the total count reaches maximum threshold.
214 */
215 ses_delay_freed.count--;
216 tmp = ses_delay_freed.first->next;
217 free(ses_delay_freed.first);
218 ses_delay_freed.first = tmp;
219 }
220 (void) pthread_mutex_unlock(&ses_delay_freed.ses_to_be_free_mutex);
221 }
222
223 /*
224 * Delete a session:
225 * - Remove the session from the session linked list.
226 * Holding the lock on the global session list is needed to do this.
227 * - Release all the objects created by the session.
228 *
229 * The boolean argument lock_held is used to indicate that whether
230 * the caller of this function holds the lock on the global session
231 * list or not.
232 * - When called by soft_delete_all_sessions(), which is called by
233 * C_Finalize() or C_CloseAllSessions() -- the lock_held = TRUE.
234 * - When called by C_CloseSession() -- the lock_held = FALSE.
235 *
236 * When the caller does not hold the lock on the global session
237 * list, this function will acquire that lock in order to proceed,
238 * and also release that lock before returning to caller.
239 */
240 CK_RV
soft_delete_session(soft_session_t * session_p,boolean_t force,boolean_t lock_held)241 soft_delete_session(soft_session_t *session_p,
242 boolean_t force, boolean_t lock_held)
243 {
244
245 /*
246 * Check to see if the caller holds the lock on the global
247 * session list. If not, we need to acquire that lock in
248 * order to proceed.
249 */
250 if (!lock_held) {
251 /* Acquire the global session list lock */
252 (void) pthread_mutex_lock(&soft_sessionlist_mutex);
253 }
254
255 /*
256 * Remove the session from the session linked list first.
257 */
258 if (soft_session_list == session_p) {
259 /* Session is the first one in the list */
260 if (session_p->next) {
261 soft_session_list = session_p->next;
262 session_p->next->prev = NULL;
263 } else {
264 /* Session is the only one in the list */
265 soft_session_list = NULL;
266 }
267 } else {
268 /* Session is not the first one in the list */
269 if (session_p->next) {
270 /* Session is in the middle of the list */
271 session_p->prev->next = session_p->next;
272 session_p->next->prev = session_p->prev;
273 } else {
274 /* Session is the last one in the list */
275 session_p->prev->next = NULL;
276 }
277 }
278
279 --soft_session_cnt;
280 if (session_p->flags & CKF_RW_SESSION)
281 --soft_session_rw_cnt;
282
283 if (!lock_held) {
284 /*
285 * If the global session list lock is obtained by
286 * this function, then release that lock after
287 * removing the session from session linked list.
288 * We want the releasing of the objects of the
289 * session, and freeing of the session itself to
290 * be done without holding the global session list
291 * lock.
292 */
293 (void) pthread_mutex_unlock(&soft_sessionlist_mutex);
294 }
295
296
297 /* Acquire the individual session lock */
298 (void) pthread_mutex_lock(&session_p->session_mutex);
299 /*
300 * Make sure another thread hasn't freed the session.
301 */
302 if (session_p->magic_marker != SOFTTOKEN_SESSION_MAGIC) {
303 (void) pthread_mutex_unlock(&session_p->session_mutex);
304 return (CKR_OK);
305 }
306
307 /*
308 * The deletion of a session must be blocked when the session
309 * reference count is not zero. This means if any session related
310 * operation starts prior to the session close operation gets in,
311 * the session closing thread must wait for the non-closing
312 * operation to be completed before it can proceed the close
313 * operation.
314 *
315 * Unless we are being forced to shut everything down, this only
316 * happens if the libraries _fini() is running not of someone
317 * explicitly called C_Finalize().
318 */
319 if (force)
320 session_p->ses_refcnt = 0;
321
322 while (session_p->ses_refcnt != 0) {
323 /*
324 * We set the SESSION_REFCNT_WAITING flag before we put
325 * this closing thread in a wait state, so other non-closing
326 * operation thread will signal to wake it up only when
327 * the session reference count becomes zero and this flag
328 * is set.
329 */
330 session_p->ses_close_sync |= SESSION_REFCNT_WAITING;
331 (void) pthread_cond_wait(&session_p->ses_free_cond,
332 &session_p->session_mutex);
333 }
334
335 session_p->ses_close_sync &= ~SESSION_REFCNT_WAITING;
336
337 /*
338 * Remove all the objects created in this session.
339 */
340 soft_delete_all_objects_in_session(session_p, force);
341
342 /*
343 * Mark session as no longer valid. This can only be done after all
344 * objects created by this session are free'd since the marker is
345 * still needed in the process of removing objects from the session.
346 */
347 session_p->magic_marker = 0;
348
349 (void) pthread_cond_destroy(&session_p->ses_free_cond);
350
351 /* In case application did not call Final */
352 if (session_p->digest.context != NULL)
353 free(session_p->digest.context);
354
355 if (session_p->encrypt.context != NULL)
356 /*
357 * 1st B_TRUE: encrypt
358 * 2nd B_TRUE: caller is holding session_mutex.
359 */
360 soft_crypt_cleanup(session_p, B_TRUE, B_TRUE);
361
362 if (session_p->decrypt.context != NULL)
363 /*
364 * 1st B_FALSE: decrypt
365 * 2nd B_TRUE: caller is holding session_mutex.
366 */
367 soft_crypt_cleanup(session_p, B_FALSE, B_TRUE);
368
369 if (session_p->sign.context != NULL)
370 free(session_p->sign.context);
371
372 if (session_p->verify.context != NULL)
373 free(session_p->verify.context);
374
375 if (session_p->find_objects.context != NULL) {
376 find_context_t *fcontext;
377 fcontext = (find_context_t *)session_p->find_objects.context;
378 free(fcontext->objs_found);
379 free(fcontext);
380 }
381
382 /* Reset SESSION_IS_CLOSIN flag. */
383 session_p->ses_close_sync &= ~SESSION_IS_CLOSING;
384
385 (void) pthread_mutex_unlock(&session_p->session_mutex);
386 /* Destroy the individual session lock */
387 (void) pthread_mutex_destroy(&session_p->session_mutex);
388
389 /* Delay freeing the session */
390 session_delay_free(session_p);
391
392 return (CKR_OK);
393 }
394
395
396 /*
397 * This function is used to type cast a session handle to a pointer to
398 * the session struct. Also, it does the following things:
399 * 1) Check to see if the session struct is tagged with a session
400 * magic number. This is to detect when an application passes
401 * a bogus session pointer.
402 * 2) Acquire the lock on the designated session.
403 * 3) Check to see if the session is in the closing state that another
404 * thread is performing.
405 * 4) Increment the session reference count by one. This is to prevent
406 * this session from being closed by other thread.
407 * 5) Release the lock held on the designated session.
408 */
409 CK_RV
handle2session(CK_SESSION_HANDLE hSession,soft_session_t ** session_p)410 handle2session(CK_SESSION_HANDLE hSession, soft_session_t **session_p)
411 {
412
413 soft_session_t *sp = (soft_session_t *)(hSession);
414
415 /*
416 * No need to hold soft_sessionlist_mutex as we are
417 * just reading the value and 32-bit reads are atomic.
418 */
419 if (all_sessions_closing) {
420 return (CKR_SESSION_CLOSED);
421 }
422
423 if ((sp == NULL) ||
424 (sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
425 return (CKR_SESSION_HANDLE_INVALID);
426 }
427 (void) pthread_mutex_lock(&sp->session_mutex);
428
429 if (sp->ses_close_sync & SESSION_IS_CLOSING) {
430 (void) pthread_mutex_unlock(&sp->session_mutex);
431 return (CKR_SESSION_CLOSED);
432 }
433
434 /* Increment session ref count. */
435 sp->ses_refcnt++;
436
437 (void) pthread_mutex_unlock(&sp->session_mutex);
438
439 *session_p = sp;
440
441 return (CKR_OK);
442 }
443
444 /*
445 * The format to be saved in the pOperationState will be:
446 * 1. internal_op_state_t
447 * 2. crypto_active_op_t
448 * 3. actual context of the active operation
449 */
450 CK_RV
soft_get_operationstate(soft_session_t * session_p,CK_BYTE_PTR pOperationState,CK_ULONG_PTR pulOperationStateLen)451 soft_get_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
452 CK_ULONG_PTR pulOperationStateLen)
453 {
454
455 internal_op_state_t *p_op_state;
456 CK_ULONG op_data_len = 0;
457 CK_RV rv = CKR_OK;
458
459 if (pulOperationStateLen == NULL)
460 return (CKR_ARGUMENTS_BAD);
461
462 (void) pthread_mutex_lock(&session_p->session_mutex);
463
464 /* Check to see if encrypt operation is active. */
465 if (session_p->encrypt.flags & CRYPTO_OPERATION_ACTIVE) {
466 rv = CKR_STATE_UNSAVEABLE;
467 goto unlock_session;
468 }
469
470 /* Check to see if decrypt operation is active. */
471 if (session_p->decrypt.flags & CRYPTO_OPERATION_ACTIVE) {
472 rv = CKR_STATE_UNSAVEABLE;
473 goto unlock_session;
474 }
475
476 /* Check to see if sign operation is active. */
477 if (session_p->sign.flags & CRYPTO_OPERATION_ACTIVE) {
478 rv = CKR_STATE_UNSAVEABLE;
479 goto unlock_session;
480 }
481
482 /* Check to see if verify operation is active. */
483 if (session_p->verify.flags & CRYPTO_OPERATION_ACTIVE) {
484 rv = CKR_STATE_UNSAVEABLE;
485 goto unlock_session;
486 }
487
488 /* Check to see if digest operation is active. */
489 if (session_p->digest.flags & CRYPTO_OPERATION_ACTIVE) {
490 op_data_len = sizeof (internal_op_state_t) +
491 sizeof (crypto_active_op_t);
492
493 switch (session_p->digest.mech.mechanism) {
494 case CKM_MD5:
495 op_data_len += sizeof (MD5_CTX);
496 break;
497 case CKM_SHA_1:
498 op_data_len += sizeof (SHA1_CTX);
499 break;
500 default:
501 rv = CKR_STATE_UNSAVEABLE;
502 goto unlock_session;
503 }
504
505 if (pOperationState == NULL_PTR) {
506 *pulOperationStateLen = op_data_len;
507 goto unlock_session;
508 } else {
509 if (*pulOperationStateLen < op_data_len) {
510 *pulOperationStateLen = op_data_len;
511 rv = CKR_BUFFER_TOO_SMALL;
512 goto unlock_session;
513 }
514 }
515
516 /* Save internal_op_state_t */
517 /* LINTED E_BAD_PTR_CAST_ALIGN */
518 p_op_state = (internal_op_state_t *)pOperationState;
519 p_op_state->op_len = op_data_len;
520 p_op_state->op_active = DIGEST_OP;
521 p_op_state->op_session_state = session_p->state;
522
523 /* Save crypto_active_op_t */
524 (void) memcpy((CK_BYTE *)pOperationState +
525 sizeof (internal_op_state_t),
526 &session_p->digest,
527 sizeof (crypto_active_op_t));
528
529 switch (session_p->digest.mech.mechanism) {
530 case CKM_MD5:
531 /* Save MD5_CTX for the active digest operation */
532 (void) memcpy((CK_BYTE *)pOperationState +
533 sizeof (internal_op_state_t) +
534 sizeof (crypto_active_op_t),
535 session_p->digest.context,
536 sizeof (MD5_CTX));
537 break;
538
539 case CKM_SHA_1:
540 /* Save SHA1_CTX for the active digest operation */
541 (void) memcpy((CK_BYTE *)pOperationState +
542 sizeof (internal_op_state_t) +
543 sizeof (crypto_active_op_t),
544 session_p->digest.context,
545 sizeof (SHA1_CTX));
546 break;
547
548 default:
549 rv = CKR_STATE_UNSAVEABLE;
550 }
551 } else {
552 rv = CKR_OPERATION_NOT_INITIALIZED;
553 goto unlock_session;
554 }
555
556 *pulOperationStateLen = op_data_len;
557
558 unlock_session:
559 (void) pthread_mutex_unlock(&session_p->session_mutex);
560
561 return (rv);
562
563 }
564
alloc_digest(CK_ULONG mech)565 static CK_BYTE_PTR alloc_digest(CK_ULONG mech)
566 {
567 CK_BYTE_PTR ret_val;
568
569 switch (mech) {
570 case CKM_MD5:
571 ret_val = (CK_BYTE_PTR) malloc(sizeof (MD5_CTX));
572 break;
573 case CKM_SHA_1:
574 ret_val = (CK_BYTE_PTR) malloc(sizeof (SHA1_CTX));
575 break;
576 default: ret_val = NULL;
577 }
578
579 return (ret_val);
580 }
581
582 /*
583 * The format to be restored from the pOperationState will be:
584 * 1. internal_op_state_t
585 * 2. crypto_active_op_t
586 * 3. actual context of the saved operation
587 */
588 CK_RV
soft_set_operationstate(soft_session_t * session_p,CK_BYTE_PTR pOperationState,CK_ULONG ulOperationStateLen,CK_OBJECT_HANDLE hEncryptionKey,CK_OBJECT_HANDLE hAuthenticationKey)589 soft_set_operationstate(soft_session_t *session_p, CK_BYTE_PTR pOperationState,
590 CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey,
591 CK_OBJECT_HANDLE hAuthenticationKey)
592 {
593
594 CK_RV rv = CKR_OK;
595 internal_op_state_t *p_op_state;
596 crypto_active_op_t *p_active_op;
597 CK_ULONG offset = 0;
598 CK_ULONG mech;
599 void *free_it = NULL;
600
601 /* LINTED E_BAD_PTR_CAST_ALIGN */
602 p_op_state = (internal_op_state_t *)pOperationState;
603
604 if (p_op_state->op_len != ulOperationStateLen) {
605 /*
606 * The supplied data length does not match with
607 * the saved data length.
608 */
609 return (CKR_SAVED_STATE_INVALID);
610 }
611
612 if (p_op_state->op_active != DIGEST_OP)
613 return (CKR_SAVED_STATE_INVALID);
614
615 if ((hAuthenticationKey != 0) || (hEncryptionKey != 0)) {
616 return (CKR_KEY_NOT_NEEDED);
617 }
618
619 offset = sizeof (internal_op_state_t);
620 /* LINTED E_BAD_PTR_CAST_ALIGN */
621 p_active_op = (crypto_active_op_t *)(pOperationState + offset);
622 offset += sizeof (crypto_active_op_t);
623 mech = p_active_op->mech.mechanism;
624
625 if (!DIGEST_MECH_OK(mech)) {
626 return (CKR_SAVED_STATE_INVALID);
627 }
628
629 /*
630 * We may reuse digest.context in case the digest mechanisms (the one,
631 * which belongs to session and the operation, which we are restoring)
632 * are the same. If digest mechanisms are different, we have to release
633 * the digest context, which belongs to session and allocate a new one.
634 */
635 (void) pthread_mutex_lock(&session_p->session_mutex);
636
637 if (session_p->state != p_op_state->op_session_state) {
638 /*
639 * The supplied session state does not match with
640 * the saved session state.
641 */
642 rv = CKR_SAVED_STATE_INVALID;
643 goto unlock_session;
644 }
645
646 if (session_p->digest.context &&
647 (session_p->digest.mech.mechanism != mech)) {
648 free_it = session_p->digest.context;
649 session_p->digest.context = NULL;
650 }
651
652 if (session_p->digest.context == NULL) {
653 session_p->digest.context = alloc_digest(mech);
654
655 if (session_p->digest.context == NULL) {
656 /*
657 * put back original context into session in case
658 * allocation of new context has failed.
659 */
660 session_p->digest.context = free_it;
661 free_it = NULL;
662 rv = CKR_HOST_MEMORY;
663 goto unlock_session;
664 }
665 }
666
667 /* Restore crypto_active_op_t */
668 session_p->digest.mech.mechanism = mech;
669 session_p->digest.flags = p_active_op->flags;
670
671 switch (mech) {
672 case CKM_MD5:
673 /* Restore MD5_CTX from the saved digest operation */
674 (void) memcpy((CK_BYTE *)session_p->digest.context,
675 (CK_BYTE *)pOperationState + offset,
676 sizeof (MD5_CTX));
677 break;
678 case CKM_SHA_1:
679 /* Restore SHA1_CTX from the saved digest operation */
680 (void) memcpy((CK_BYTE *)session_p->digest.context,
681 (CK_BYTE *)pOperationState + offset,
682 sizeof (SHA1_CTX));
683 break;
684 default:
685 /* never reached */
686 rv = CKR_SAVED_STATE_INVALID;
687 }
688
689 unlock_session:
690 (void) pthread_mutex_unlock(&session_p->session_mutex);
691
692 if (free_it != NULL)
693 free(free_it);
694
695 return (rv);
696 }
697
698
699 CK_RV
soft_login(CK_UTF8CHAR_PTR pPin,CK_ULONG ulPinLen)700 soft_login(CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen)
701 {
702
703 /*
704 * Authenticate the input PIN.
705 */
706 return (soft_verify_pin(pPin, ulPinLen));
707
708 }
709
710 void
soft_logout(void)711 soft_logout(void)
712 {
713
714 /*
715 * Delete all the private token objects from the "token_object_list".
716 */
717 soft_delete_all_in_core_token_objects(PRIVATE_TOKEN);
718 return;
719
720 }
721
722 void
soft_acquire_all_session_mutexes(soft_session_t * session_p)723 soft_acquire_all_session_mutexes(soft_session_t *session_p)
724 {
725 /* Iterate through sessions acquiring all mutexes */
726 while (session_p) {
727 soft_object_t *object_p;
728
729 (void) pthread_mutex_lock(&session_p->session_mutex);
730 object_p = session_p->object_list;
731
732 /* Lock also all objects related to session */
733 while (object_p) {
734 (void) pthread_mutex_lock(&object_p->object_mutex);
735 object_p = object_p->next;
736 }
737 session_p = session_p->next;
738 }
739 }
740
741 void
soft_release_all_session_mutexes(soft_session_t * session_p)742 soft_release_all_session_mutexes(soft_session_t *session_p)
743 {
744 /* Iterate through sessions releasing all mutexes */
745 while (session_p) {
746 /*
747 * N.B. Ideally, should go in opposite order to guarantee
748 * lock-order requirements but there is no tail pointer.
749 */
750 soft_object_t *object_p = session_p->object_list;
751
752 /* Unlock also all objects related to session */
753 while (object_p) {
754 (void) pthread_mutex_unlock(&object_p->object_mutex);
755 object_p = object_p->next;
756 }
757 (void) pthread_mutex_unlock(&session_p->session_mutex);
758 session_p = session_p->next;
759 }
760 }
761