#include "tpmtok_int.h"
pthread_rwlock_t obj_list_rw_mutex = PTHREAD_RWLOCK_INITIALIZER;
static CK_RV
object_mgr_search_shm_for_obj(TOK_OBJ_ENTRY *,
CK_ULONG, CK_ULONG, OBJECT *, CK_ULONG *);
static CK_RV object_mgr_update_from_shm(TSS_HCONTEXT);
static CK_RV object_mgr_check_shm(TSS_HCONTEXT, OBJECT *);
static CK_RV
check_object_access(SESSION *sess, OBJECT *o)
{
CK_BBOOL sess_obj, priv_obj;
CK_RV rc = CKR_OK;
sess_obj = object_is_session_object(o);
priv_obj = object_is_private(o);
if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) {
if (priv_obj) {
rc = CKR_USER_NOT_LOGGED_IN;
goto done;
}
if (!sess_obj) {
rc = CKR_SESSION_READ_ONLY;
goto done;
}
}
if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) {
if (! sess_obj) {
rc = CKR_SESSION_READ_ONLY;
goto done;
}
}
if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
if (priv_obj) {
rc = CKR_USER_NOT_LOGGED_IN;
goto done;
}
}
if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
if (priv_obj) {
rc = CKR_USER_NOT_LOGGED_IN;
goto done;
}
}
done:
return (rc);
}
CK_RV
object_mgr_add(SESSION * sess,
CK_ATTRIBUTE * pTemplate,
CK_ULONG ulCount,
CK_OBJECT_HANDLE * handle)
{
OBJECT * o = NULL;
CK_BBOOL priv_obj, sess_obj;
CK_RV rc;
if (! sess || ! pTemplate || ! handle) {
return (CKR_FUNCTION_FAILED);
}
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
rc = object_create(pTemplate, ulCount, &o);
if (rc != CKR_OK) {
goto done;
}
rc = check_object_access(sess, o);
if (rc != CKR_OK)
goto done;
sess_obj = object_is_session_object(o);
priv_obj = object_is_private(o);
if (sess_obj) {
o->session = sess;
(void) memset(o->name, 0x00, sizeof (CK_BYTE) * 8);
sess_obj_list = dlist_add_as_first(sess_obj_list, o);
} else {
CK_BYTE current[8];
CK_BYTE next[8];
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto done;
} else {
if (priv_obj) {
if (global_shm->num_priv_tok_obj >=
MAX_TOK_OBJS) {
rc = CKR_HOST_MEMORY;
(void) XProcUnLock(xproclock);
goto done;
}
} else {
if (global_shm->num_publ_tok_obj >=
MAX_TOK_OBJS) {
rc = CKR_HOST_MEMORY;
(void) XProcUnLock(xproclock);
goto done;
}
}
(void) memcpy(current,
&nv_token_data->next_token_object_name, 8);
o->session = NULL;
(void) memcpy(&o->name, current, 8);
(void) compute_next_token_obj_name(current, next);
(void) memcpy(&nv_token_data->next_token_object_name,
next, 8);
rc = save_token_object(sess->hContext, o);
if (rc != CKR_OK) {
(void) XProcUnLock(xproclock);
goto done;
}
(void) object_mgr_add_to_shm(o);
(void) XProcUnLock(xproclock);
(void) save_token_data(nv_token_data);
}
if (priv_obj)
priv_token_obj_list =
dlist_add_as_last(priv_token_obj_list, o);
else
publ_token_obj_list =
dlist_add_as_last(publ_token_obj_list, o);
}
rc = object_mgr_add_to_map(sess, o, handle);
if (rc != CKR_OK) {
DL_NODE *node = NULL;
if (sess_obj) {
node = dlist_find(sess_obj_list, o);
if (node)
sess_obj_list =
dlist_remove_node(sess_obj_list, node);
} else {
(void) delete_token_object(o);
if (priv_obj) {
node = dlist_find(priv_token_obj_list, o);
if (node)
priv_token_obj_list =
dlist_remove_node(
priv_token_obj_list, node);
} else {
node = dlist_find(publ_token_obj_list, o);
if (node)
publ_token_obj_list =
dlist_remove_node(
publ_token_obj_list, node);
}
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto done;
}
(void) object_mgr_del_from_shm(o);
(void) XProcUnLock(xproclock);
}
}
done:
(void) pthread_mutex_unlock(&obj_list_mutex);
if ((rc != CKR_OK) && (o != NULL))
(void) object_free(o);
return (rc);
}
CK_RV
object_mgr_add_to_map(SESSION * sess,
OBJECT * obj,
CK_OBJECT_HANDLE * handle) {
OBJECT_MAP *map_node = NULL;
if (! sess || ! obj || ! handle) {
return (CKR_FUNCTION_FAILED);
}
map_node = (OBJECT_MAP *)malloc(sizeof (OBJECT_MAP));
if (! map_node) {
return (CKR_HOST_MEMORY);
}
map_node->handle = next_object_handle++;
map_node->session = sess;
map_node->ptr = obj;
if (obj->session != NULL)
map_node->is_session_obj = TRUE;
else
map_node->is_session_obj = FALSE;
if (pthread_rwlock_wrlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
object_map = dlist_add_as_first(object_map, map_node);
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
*handle = map_node->handle;
return (CKR_OK);
}
CK_RV
object_mgr_copy(SESSION * sess,
CK_ATTRIBUTE * pTemplate,
CK_ULONG ulCount,
CK_OBJECT_HANDLE old_handle,
CK_OBJECT_HANDLE * new_handle)
{
OBJECT *old_obj = NULL;
OBJECT *new_obj = NULL;
CK_BBOOL priv_obj;
CK_BBOOL sess_obj;
CK_RV rc;
if (! sess || ! pTemplate || ! new_handle) {
return (CKR_FUNCTION_FAILED);
}
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
rc = object_mgr_find_in_map1(sess->hContext, old_handle, &old_obj);
if (rc != CKR_OK) {
goto done;
}
rc = object_copy(pTemplate, ulCount, old_obj, &new_obj);
if (rc != CKR_OK) {
goto done;
}
rc = check_object_access(sess, new_obj);
if (rc != CKR_OK)
goto done;
sess_obj = object_is_session_object(new_obj);
priv_obj = object_is_private(new_obj);
if (sess_obj) {
new_obj->session = sess;
(void) memset(&new_obj->name, 0x00, sizeof (CK_BYTE) * 8);
sess_obj_list = dlist_add_as_first(sess_obj_list, new_obj);
} else {
CK_BYTE current[8];
CK_BYTE next[8];
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto done;
} else {
if (priv_obj) {
if (global_shm->num_priv_tok_obj >=
MAX_TOK_OBJS) {
(void) XProcUnLock(xproclock);
rc = CKR_HOST_MEMORY;
goto done;
}
} else {
if (global_shm->num_publ_tok_obj >=
MAX_TOK_OBJS) {
(void) XProcUnLock(xproclock);
rc = CKR_HOST_MEMORY;
goto done;
}
}
(void) memcpy(current,
&nv_token_data->next_token_object_name, 8);
new_obj->session = NULL;
(void) memcpy(&new_obj->name, current, 8);
(void) compute_next_token_obj_name(current, next);
(void) memcpy(&nv_token_data->next_token_object_name,
next, 8);
rc = save_token_object(sess->hContext, new_obj);
if (rc != CKR_OK) {
(void) XProcUnLock(xproclock);
goto done;
}
(void) object_mgr_add_to_shm(new_obj);
(void) XProcUnLock(xproclock);
(void) save_token_data(nv_token_data);
}
if (priv_obj)
priv_token_obj_list = dlist_add_as_last(
priv_token_obj_list, new_obj);
else
publ_token_obj_list = dlist_add_as_last(
publ_token_obj_list, new_obj);
}
rc = object_mgr_add_to_map(sess, new_obj, new_handle);
if (rc != CKR_OK) {
DL_NODE *node = NULL;
if (sess_obj) {
node = dlist_find(sess_obj_list, new_obj);
if (node)
sess_obj_list = dlist_remove_node(
sess_obj_list, node);
} else {
(void) delete_token_object(new_obj);
if (priv_obj) {
node = dlist_find(priv_token_obj_list, new_obj);
if (node)
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, node);
} else {
node = dlist_find(publ_token_obj_list, new_obj);
if (node)
publ_token_obj_list = dlist_remove_node(
publ_token_obj_list, node);
}
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto done;
}
(void) object_mgr_del_from_shm(new_obj);
(void) XProcUnLock(xproclock);
}
}
done:
(void) pthread_mutex_unlock(&obj_list_mutex);
if ((rc != CKR_OK) && (new_obj != NULL))
(void) object_free(new_obj);
return (rc);
}
CK_RV
object_mgr_create_skel(SESSION * sess,
CK_ATTRIBUTE * pTemplate,
CK_ULONG ulCount,
CK_ULONG mode,
CK_ULONG obj_type,
CK_ULONG sub_class,
OBJECT ** obj)
{
OBJECT *o = NULL;
CK_RV rc;
CK_BBOOL priv_obj;
CK_BBOOL sess_obj;
if (! sess || ! obj) {
return (CKR_FUNCTION_FAILED);
}
if (! pTemplate && (ulCount != 0)) {
return (CKR_FUNCTION_FAILED);
}
rc = object_create_skel(pTemplate, ulCount,
mode, obj_type, sub_class, &o);
if (rc != CKR_OK) {
return (rc);
}
sess_obj = object_is_session_object(o);
priv_obj = object_is_private(o);
if (sess->session_info.state == CKS_RO_PUBLIC_SESSION) {
if (priv_obj) {
(void) object_free(o);
return (CKR_USER_NOT_LOGGED_IN);
}
if (! sess_obj) {
(void) object_free(o);
return (CKR_SESSION_READ_ONLY);
}
}
if (sess->session_info.state == CKS_RO_USER_FUNCTIONS) {
if (! sess_obj) {
(void) object_free(o);
return (CKR_SESSION_READ_ONLY);
}
}
if (sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
if (priv_obj) {
(void) object_free(o);
return (CKR_USER_NOT_LOGGED_IN);
}
}
if (sess->session_info.state == CKS_RW_SO_FUNCTIONS) {
if (priv_obj) {
(void) object_free(o);
return (CKR_USER_NOT_LOGGED_IN);
}
}
*obj = o;
return (CKR_OK);
}
CK_RV
object_mgr_create_final(SESSION * sess,
OBJECT * obj,
CK_OBJECT_HANDLE * handle)
{
CK_BBOOL sess_obj;
CK_BBOOL priv_obj;
CK_RV rc;
if (!sess || !obj || !handle)
return (CKR_FUNCTION_FAILED);
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
sess_obj = object_is_session_object(obj);
priv_obj = object_is_private(obj);
if (sess_obj) {
obj->session = sess;
(void) memset(obj->name, 0x0, sizeof (CK_BYTE) * 8);
sess_obj_list = dlist_add_as_first(sess_obj_list, obj);
} else {
CK_BYTE current[8];
CK_BYTE next[8];
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto done;
} else {
if (priv_obj) {
if (global_shm->num_priv_tok_obj >=
MAX_TOK_OBJS) {
(void) XProcUnLock(xproclock);
rc = CKR_HOST_MEMORY;
goto done;
}
} else {
if (global_shm->num_publ_tok_obj >=
MAX_TOK_OBJS) {
(void) XProcUnLock(xproclock);
rc = CKR_HOST_MEMORY;
goto done;
}
}
(void) memcpy(current,
&nv_token_data->next_token_object_name, 8);
obj->session = NULL;
(void) memcpy(&obj->name, current, 8);
(void) compute_next_token_obj_name(current, next);
(void) memcpy(&nv_token_data->next_token_object_name,
next, 8);
rc = save_token_object(sess->hContext, obj);
if (rc != CKR_OK) {
(void) XProcUnLock(xproclock);
goto done;
}
(void) object_mgr_add_to_shm(obj);
(void) XProcUnLock(xproclock);
(void) save_token_data(nv_token_data);
}
if (priv_obj)
priv_token_obj_list = dlist_add_as_last(
priv_token_obj_list, obj);
else
publ_token_obj_list = dlist_add_as_last(
publ_token_obj_list, obj);
}
rc = object_mgr_add_to_map(sess, obj, handle);
if (rc != CKR_OK) {
DL_NODE *node = NULL;
if (sess_obj) {
node = dlist_find(sess_obj_list, obj);
if (node)
sess_obj_list = dlist_remove_node(
sess_obj_list, node);
} else {
(void) delete_token_object(obj);
if (priv_obj) {
node = dlist_find(priv_token_obj_list, obj);
if (node)
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, node);
} else {
node = dlist_find(publ_token_obj_list, obj);
if (node)
publ_token_obj_list = dlist_remove_node(
publ_token_obj_list, node);
}
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto done;
}
(void) object_mgr_del_from_shm(obj);
(void) XProcUnLock(xproclock);
}
}
done:
(void) pthread_mutex_unlock(&obj_list_mutex);
return (rc);
}
CK_RV
object_mgr_destroy_object(SESSION * sess,
CK_OBJECT_HANDLE handle)
{
OBJECT * obj = NULL;
CK_BBOOL sess_obj;
CK_BBOOL priv_obj;
CK_RV rc;
if (! sess)
return (CKR_FUNCTION_FAILED);
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
rc = object_mgr_find_in_map1(sess->hContext, handle, &obj);
if (rc != CKR_OK) {
goto done;
}
rc = check_object_access(sess, obj);
if (rc != CKR_OK)
goto done;
sess_obj = object_is_session_object(obj);
priv_obj = object_is_private(obj);
if (sess_obj) {
DL_NODE *node;
node = dlist_find(sess_obj_list, obj);
if (node) {
(void) object_mgr_remove_from_map(handle);
(void) object_free(obj);
sess_obj_list = dlist_remove_node(
sess_obj_list, node);
rc = CKR_OK;
goto done;
}
} else {
DL_NODE *node = NULL;
(void) delete_token_object(obj);
if (priv_obj)
node = dlist_find(priv_token_obj_list, obj);
else
node = dlist_find(publ_token_obj_list, obj);
if (node) {
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
goto done;
}
(void) object_mgr_del_from_shm(obj);
(void) XProcUnLock(xproclock);
(void) object_mgr_remove_from_map(handle);
(void) object_free(obj);
if (priv_obj)
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, node);
else
publ_token_obj_list = dlist_remove_node(
publ_token_obj_list, node);
rc = CKR_OK;
goto done;
}
}
rc = CKR_FUNCTION_FAILED;
done:
(void) pthread_mutex_unlock(&obj_list_mutex);
return (rc);
}
CK_RV
object_mgr_destroy_token_objects(TSS_HCONTEXT hContext)
{
CK_BBOOL locked2 = FALSE;
CK_RV rc;
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
while (publ_token_obj_list) {
OBJECT *obj = (OBJECT *)publ_token_obj_list->data;
CK_OBJECT_HANDLE handle;
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_remove_from_map(handle);
}
(void) delete_token_object(obj);
(void) object_free(obj);
publ_token_obj_list = dlist_remove_node(
publ_token_obj_list, publ_token_obj_list);
}
while (priv_token_obj_list) {
OBJECT *obj = (OBJECT *)priv_token_obj_list->data;
CK_OBJECT_HANDLE handle;
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_remove_from_map(handle);
}
(void) delete_token_object(obj);
(void) object_free(obj);
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, priv_token_obj_list);
}
rc = XProcLock(xproclock);
if (rc == CKR_OK) {
locked2 = TRUE;
global_shm->num_priv_tok_obj = 0;
global_shm->num_publ_tok_obj = 0;
(void) memset(&global_shm->publ_tok_objs, 0x0,
MAX_TOK_OBJS * sizeof (TOK_OBJ_ENTRY));
(void) memset(&global_shm->priv_tok_objs, 0x0,
MAX_TOK_OBJS * sizeof (TOK_OBJ_ENTRY));
}
(void) pthread_mutex_unlock(&obj_list_mutex);
if (locked2 == TRUE) (void) XProcUnLock(xproclock);
return (rc);
}
CK_RV
object_mgr_find_in_map_nocache(CK_OBJECT_HANDLE handle,
OBJECT ** ptr) {
DL_NODE * node = NULL;
OBJECT * obj = NULL;
if (! ptr) {
return (CKR_FUNCTION_FAILED);
}
if (pthread_rwlock_rdlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
node = object_map;
while (node) {
OBJECT_MAP *map = (OBJECT_MAP *)node->data;
if (map->handle == handle) {
obj = map->ptr;
break;
}
node = node->next;
}
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
if (obj == NULL || node == NULL) {
return (CKR_OBJECT_HANDLE_INVALID);
}
if (object_is_session_object(obj) == TRUE) {
*ptr = obj;
return (CKR_OK);
}
*ptr = obj;
return (CKR_OK);
}
CK_RV
object_mgr_find_in_map1(
TSS_HCONTEXT hContext,
CK_OBJECT_HANDLE handle,
OBJECT ** ptr)
{
DL_NODE * node = NULL;
OBJECT * obj = NULL;
if (! ptr) {
return (CKR_FUNCTION_FAILED);
}
if (pthread_rwlock_rdlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
node = object_map;
while (node) {
OBJECT_MAP *map = (OBJECT_MAP *)node->data;
if (map->handle == handle) {
obj = map->ptr;
break;
}
node = node->next;
}
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
if (obj == NULL || node == NULL) {
return (CKR_OBJECT_HANDLE_INVALID);
}
if (object_is_session_object(obj) == TRUE) {
*ptr = obj;
return (CKR_OK);
}
(void) object_mgr_check_shm(hContext, obj);
*ptr = obj;
return (CKR_OK);
}
CK_RV
object_mgr_find_in_map2(
TSS_HCONTEXT hContext,
OBJECT * obj,
CK_OBJECT_HANDLE * handle)
{
DL_NODE * node = NULL;
CK_OBJECT_HANDLE h = (CK_OBJECT_HANDLE)NULL;
if (! obj || ! handle) {
return (CKR_FUNCTION_FAILED);
}
if (pthread_rwlock_rdlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
node = object_map;
while (node) {
OBJECT_MAP *map = (OBJECT_MAP *)node->data;
if (map->ptr == obj) {
h = map->handle;
break;
}
node = node->next;
}
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
if (node == NULL) {
return (CKR_OBJECT_HANDLE_INVALID);
}
if (object_is_session_object(obj) == TRUE) {
*handle = h;
return (CKR_OK);
}
(void) object_mgr_check_shm(hContext, obj);
*handle = h;
return (CKR_OK);
}
CK_RV
object_mgr_find_init(SESSION * sess,
CK_ATTRIBUTE * pTemplate,
CK_ULONG ulCount)
{
if (! sess) {
return (CKR_FUNCTION_FAILED);
}
if (sess->find_active != FALSE) {
return (CKR_OPERATION_ACTIVE);
}
if (sess->find_list != NULL) {
(void) memset(sess->find_list, 0x0,
sess->find_len * sizeof (CK_OBJECT_HANDLE));
} else {
sess->find_list = (CK_OBJECT_HANDLE *)malloc(
10 * sizeof (CK_OBJECT_HANDLE));
if (! sess->find_list) {
return (CKR_HOST_MEMORY);
} else {
(void) memset(sess->find_list, 0x0,
10 * sizeof (CK_OBJECT_HANDLE));
sess->find_len = 10;
}
}
sess->find_count = 0;
sess->find_idx = 0;
if (pthread_mutex_lock(&obj_list_mutex))
return (CKR_FUNCTION_FAILED);
(void) object_mgr_update_from_shm(sess->hContext);
switch (sess->session_info.state) {
case CKS_RO_PUBLIC_SESSION:
case CKS_RW_PUBLIC_SESSION:
case CKS_RW_SO_FUNCTIONS:
(void) object_mgr_find_build_list(sess, pTemplate,
ulCount, publ_token_obj_list, TRUE);
(void) object_mgr_find_build_list(sess, pTemplate,
ulCount, sess_obj_list, TRUE);
break;
case CKS_RO_USER_FUNCTIONS:
case CKS_RW_USER_FUNCTIONS:
(void) object_mgr_find_build_list(sess, pTemplate,
ulCount, priv_token_obj_list, FALSE);
(void) object_mgr_find_build_list(sess, pTemplate,
ulCount, publ_token_obj_list, FALSE);
(void) object_mgr_find_build_list(sess, pTemplate,
ulCount, sess_obj_list, FALSE);
break;
}
(void) pthread_mutex_unlock(&obj_list_mutex);
sess->find_active = TRUE;
return (CKR_OK);
}
CK_RV
object_mgr_find_build_list(SESSION * sess,
CK_ATTRIBUTE * pTemplate,
CK_ULONG ulCount,
DL_NODE * obj_list,
CK_BBOOL public_only)
{
OBJECT * obj = NULL;
DL_NODE * node = NULL;
CK_OBJECT_HANDLE handle;
CK_BBOOL is_priv;
CK_BBOOL match;
CK_BBOOL hw_feature = FALSE;
CK_BBOOL hidden_object = FALSE;
CK_RV rc;
CK_ATTRIBUTE * attr;
unsigned int i;
if (! sess) {
return (CKR_FUNCTION_FAILED);
}
if (! obj_list)
return (CKR_OK);
for (i = 0; i < ulCount; i++) {
if (pTemplate[i].type == CKA_CLASS) {
if (*(CK_ULONG *)pTemplate[i].pValue ==
CKO_HW_FEATURE) {
hw_feature = TRUE;
break;
}
}
if (pTemplate[i].type == CKA_HIDDEN) {
if (*(CK_BBOOL *)pTemplate[i].pValue == TRUE) {
hidden_object = TRUE;
break;
}
}
}
node = obj_list;
while (node) {
match = FALSE;
obj = (OBJECT *)node->data;
is_priv = object_is_private(obj);
if ((is_priv == FALSE) || (public_only == FALSE)) {
if (pTemplate == NULL || ulCount == 0)
match = TRUE;
else
match = template_compare(pTemplate,
ulCount, obj->template);
}
if (match) {
rc = object_mgr_find_in_map2(sess->hContext, obj,
&handle);
if (rc != CKR_OK) {
rc = object_mgr_add_to_map(sess, obj, &handle);
if (rc != CKR_OK) {
return (CKR_FUNCTION_FAILED);
}
}
if (rc == CKR_OK) {
if ((hw_feature == FALSE) &&
(template_attribute_find(obj->template,
CKA_CLASS, &attr) == TRUE)) {
if (*(CK_OBJECT_CLASS *)attr->pValue ==
CKO_HW_FEATURE)
goto next_loop;
}
if ((hidden_object == FALSE) &&
(template_attribute_find(obj->template,
CKA_HIDDEN, &attr) == TRUE)) {
if (*(CK_BBOOL *)attr->pValue == TRUE)
goto next_loop;
}
sess->find_list[ sess->find_count ] = handle;
sess->find_count++;
if (sess->find_count >= sess->find_len) {
sess->find_len += 15;
sess->find_list =
(CK_OBJECT_HANDLE *)realloc(
sess->find_list, sess->find_len *
sizeof (CK_OBJECT_HANDLE));
if (! sess->find_list) {
return (CKR_HOST_MEMORY);
}
}
}
}
next_loop:
node = node->next;
}
return (CKR_OK);
}
CK_RV
object_mgr_find_final(SESSION *sess)
{
if (! sess) {
return (CKR_FUNCTION_FAILED);
}
if (sess->find_active == FALSE) {
return (CKR_OPERATION_NOT_INITIALIZED);
}
free(sess->find_list);
sess->find_list = NULL;
sess->find_count = 0;
sess->find_idx = 0;
sess->find_active = FALSE;
return (CKR_OK);
}
CK_RV
object_mgr_get_attribute_values(SESSION * sess,
CK_OBJECT_HANDLE handle,
CK_ATTRIBUTE * pTemplate,
CK_ULONG ulCount)
{
OBJECT * obj;
CK_BBOOL priv_obj;
CK_RV rc;
if (! pTemplate) {
return (CKR_FUNCTION_FAILED);
}
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
rc = object_mgr_find_in_map1(sess->hContext, handle, &obj);
if (rc != CKR_OK) {
goto done;
}
priv_obj = object_is_private(obj);
if (priv_obj == TRUE) {
if (sess->session_info.state == CKS_RO_PUBLIC_SESSION ||
sess->session_info.state == CKS_RW_PUBLIC_SESSION) {
rc = CKR_USER_NOT_LOGGED_IN;
goto done;
}
}
rc = object_get_attribute_values(obj, pTemplate, ulCount);
done:
(void) pthread_mutex_unlock(&obj_list_mutex);
return (rc);
}
CK_RV
object_mgr_get_object_size(
TSS_HCONTEXT hContext,
CK_OBJECT_HANDLE handle,
CK_ULONG * size)
{
OBJECT * obj;
CK_RV rc;
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
rc = object_mgr_find_in_map1(hContext, handle, &obj);
if (rc != CKR_OK) {
rc = CKR_OBJECT_HANDLE_INVALID;
goto done;
}
*size = object_get_size(obj);
done:
(void) pthread_mutex_unlock(&obj_list_mutex);
return (rc);
}
CK_BBOOL
object_mgr_invalidate_handle1(CK_OBJECT_HANDLE handle)
{
DL_NODE *node = NULL;
if (pthread_rwlock_wrlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
node = object_map;
while (node) {
OBJECT_MAP *map = (OBJECT_MAP *)node->data;
if (map->handle == handle) {
object_map = dlist_remove_node(object_map, node);
free(map);
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
return (TRUE);
}
node = node->next;
}
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
return (FALSE);
}
CK_BBOOL
object_mgr_invalidate_handle2(OBJECT *obj)
{
DL_NODE *node = NULL;
if (! obj)
return (FALSE);
if (pthread_rwlock_wrlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
node = object_map;
while (node) {
OBJECT_MAP *map = (OBJECT_MAP *)node->data;
if (map->ptr == obj) {
object_map = dlist_remove_node(object_map, node);
free(map);
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
return (TRUE);
}
node = node->next;
}
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
return (FALSE);
}
CK_BBOOL
object_mgr_purge_session_objects(SESSION * sess,
SESS_OBJ_TYPE type)
{
DL_NODE *node = NULL;
DL_NODE *next = NULL;
OBJECT *obj = NULL;
CK_BBOOL del;
CK_RV rc;
if (!sess)
return (FALSE);
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (FALSE);
node = sess_obj_list;
while (node) {
obj = (OBJECT *)node->data;
del = FALSE;
if (obj->session == sess) {
if (type == PRIVATE) {
if (object_is_private(obj))
del = TRUE;
} else if (type == PUBLIC) {
if (object_is_public(obj))
del = TRUE;
} else if (type == ALL)
del = TRUE;
}
if (del == TRUE) {
CK_OBJECT_HANDLE handle;
CK_RV rc;
rc = object_mgr_find_in_map2(sess->hContext, obj,
&handle);
if (rc == CKR_OK) {
(void) object_mgr_invalidate_handle1(handle);
(void) object_free(obj);
}
next = node->next;
sess_obj_list = dlist_remove_node(sess_obj_list, node);
node = next;
}
else
node = node->next;
}
(void) pthread_mutex_unlock(&obj_list_mutex);
return (TRUE);
}
CK_BBOOL
object_mgr_purge_token_objects(TSS_HCONTEXT hContext)
{
DL_NODE *node = NULL;
DL_NODE *next = NULL;
OBJECT *obj = NULL;
CK_RV rc;
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (FALSE);
node = publ_token_obj_list;
while (publ_token_obj_list) {
CK_OBJECT_HANDLE handle;
CK_RV rc;
obj = (OBJECT *)node->data;
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_invalidate_handle1(handle);
}
(void) object_free(obj);
next = node->next;
publ_token_obj_list = dlist_remove_node(
publ_token_obj_list, node);
node = next;
}
node = priv_token_obj_list;
while (priv_token_obj_list) {
CK_OBJECT_HANDLE handle;
CK_RV rc;
obj = (OBJECT *)node->data;
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK)
(void) object_mgr_invalidate_handle1(handle);
(void) object_free(obj);
next = node->next;
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, node);
node = next;
}
(void) pthread_mutex_unlock(&obj_list_mutex);
return (TRUE);
}
CK_BBOOL
object_mgr_purge_private_token_objects(TSS_HCONTEXT hContext) {
OBJECT * obj = NULL;
DL_NODE * node = NULL;
DL_NODE * next = NULL;
CK_RV rc;
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (FALSE);
node = priv_token_obj_list;
while (priv_token_obj_list) {
CK_OBJECT_HANDLE handle;
CK_RV rc;
obj = (OBJECT *)node->data;
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_invalidate_handle1(handle);
}
(void) object_free(obj);
next = node->next;
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, node);
node = next;
}
(void) pthread_mutex_unlock(&obj_list_mutex);
return (TRUE);
}
CK_RV
object_mgr_remove_from_map(CK_OBJECT_HANDLE handle)
{
DL_NODE *node = NULL;
if (pthread_rwlock_wrlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
node = object_map;
while (node) {
OBJECT_MAP *map = (OBJECT_MAP *)node->data;
if (map->handle == handle) {
object_map = dlist_remove_node(object_map, node);
free(map);
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
return (CKR_OK);
}
node = node->next;
}
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
return (CKR_FUNCTION_FAILED);
}
CK_RV
object_mgr_restore_obj(CK_BYTE *data, OBJECT *oldObj)
{
OBJECT * obj = NULL;
CK_BBOOL priv;
CK_RV rc;
if (! data) {
return (CKR_FUNCTION_FAILED);
}
if (oldObj != NULL) {
obj = oldObj;
rc = object_restore(data, &obj, TRUE);
} else {
rc = object_restore(data, &obj, FALSE);
if (rc == CKR_OK) {
priv = object_is_private(obj);
if (priv)
priv_token_obj_list = dlist_add_as_last(
priv_token_obj_list, obj);
else
publ_token_obj_list = dlist_add_as_last(
publ_token_obj_list, obj);
(void) XProcLock(xproclock);
if (priv) {
if (global_shm->priv_loaded == FALSE) {
if (global_shm->num_priv_tok_obj <
MAX_TOK_OBJS)
(void) object_mgr_add_to_shm(
obj);
else
rc = CKR_HOST_MEMORY;
}
} else {
if (global_shm->publ_loaded == FALSE) {
if (global_shm->num_publ_tok_obj <
MAX_TOK_OBJS)
(void) object_mgr_add_to_shm(
obj);
else
rc = CKR_HOST_MEMORY;
}
}
(void) XProcUnLock(xproclock);
}
}
return (rc);
}
CK_RV
object_mgr_set_attribute_values(SESSION * sess,
CK_OBJECT_HANDLE handle,
CK_ATTRIBUTE * pTemplate,
CK_ULONG ulCount)
{
OBJECT * obj;
CK_BBOOL sess_obj, priv_obj;
CK_BBOOL modifiable;
CK_RV rc;
if (! pTemplate) {
return (CKR_FUNCTION_FAILED);
}
rc = pthread_mutex_lock(&obj_list_mutex);
if (rc != CKR_OK)
return (CKR_FUNCTION_FAILED);
rc = object_mgr_find_in_map1(sess->hContext, handle, &obj);
if (rc != CKR_OK) {
(void) pthread_mutex_unlock(&obj_list_mutex);
return (CKR_OBJECT_HANDLE_INVALID);
}
(void) pthread_mutex_unlock(&obj_list_mutex);
modifiable = object_is_modifiable(obj);
sess_obj = object_is_session_object(obj);
priv_obj = object_is_private(obj);
if (! modifiable) {
return (CKR_ATTRIBUTE_READ_ONLY);
}
rc = check_object_access(sess, obj);
if (rc != CKR_OK)
return (rc);
rc = object_set_attribute_values(obj, pTemplate, ulCount);
if (rc != CKR_OK) {
return (rc);
}
if (! sess_obj) {
TOK_OBJ_ENTRY *entry = NULL;
CK_ULONG index;
obj->count_lo++;
if (obj->count_lo == 0)
obj->count_hi++;
rc = save_token_object(sess->hContext, obj);
if (rc != CKR_OK)
return (rc);
rc = XProcLock(xproclock);
if (rc != CKR_OK) {
return (rc);
}
if (priv_obj) {
rc = object_mgr_search_shm_for_obj(
global_shm->priv_tok_objs,
0, global_shm->num_priv_tok_obj - 1,
obj, &index);
if (rc != CKR_OK) {
(void) XProcUnLock(xproclock);
return (rc);
}
entry = &global_shm->priv_tok_objs[index];
} else {
rc = object_mgr_search_shm_for_obj(
global_shm->publ_tok_objs,
0, global_shm->num_publ_tok_obj - 1,
obj, &index);
if (rc != CKR_OK) {
(void) XProcUnLock(xproclock);
return (rc);
}
entry = &global_shm->publ_tok_objs[index];
}
entry->count_lo = obj->count_lo;
entry->count_hi = obj->count_hi;
(void) XProcUnLock(xproclock);
}
return (rc);
}
CK_RV
object_mgr_add_to_shm(OBJECT *obj)
{
TOK_OBJ_ENTRY * entry = NULL;
CK_BBOOL priv;
priv = object_is_private(obj);
if (priv)
entry = &global_shm->priv_tok_objs[
global_shm->num_priv_tok_obj];
else
entry = &global_shm->publ_tok_objs[
global_shm->num_publ_tok_obj];
entry->deleted = FALSE;
entry->count_lo = 0;
entry->count_hi = 0;
(void) memcpy(entry->name, obj->name, 8);
if (priv) {
global_shm->num_priv_tok_obj++;
} else {
global_shm->num_publ_tok_obj++;
}
return (CKR_OK);
}
CK_RV
object_mgr_del_from_shm(OBJECT *obj)
{
CK_ULONG index, count;
CK_BBOOL priv;
CK_RV rc;
priv = object_is_private(obj);
if (priv) {
rc = object_mgr_search_shm_for_obj(global_shm->priv_tok_objs,
0, global_shm->num_priv_tok_obj - 1, obj, &index);
if (rc != CKR_OK) {
return (CKR_FUNCTION_FAILED);
}
global_shm->num_priv_tok_obj--;
if (index > global_shm->num_priv_tok_obj) {
count = index - global_shm->num_priv_tok_obj;
} else {
count = global_shm->num_priv_tok_obj - index;
}
if (count > 0) {
(void) memcpy((char *)&global_shm->priv_tok_objs[index],
(char *)&global_shm->priv_tok_objs[index + 1],
sizeof (TOK_OBJ_ENTRY) * count);
(void) memset((char *)&global_shm->priv_tok_objs[
global_shm->num_priv_tok_obj + 1], 0,
sizeof (TOK_OBJ_ENTRY));
} else {
(void) memset((char *)&global_shm->priv_tok_objs[
global_shm->num_priv_tok_obj], 0,
sizeof (TOK_OBJ_ENTRY));
}
} else {
rc = object_mgr_search_shm_for_obj(global_shm->publ_tok_objs,
0, global_shm->num_publ_tok_obj - 1, obj, &index);
if (rc != CKR_OK) {
return (CKR_FUNCTION_FAILED);
}
global_shm->num_publ_tok_obj--;
if (index > global_shm->num_publ_tok_obj) {
count = index - global_shm->num_publ_tok_obj;
} else {
count = global_shm->num_publ_tok_obj - index;
}
if (count > 0) {
(void) memcpy((char *)&global_shm->publ_tok_objs[index],
(char *)&global_shm->publ_tok_objs[index + 1],
sizeof (TOK_OBJ_ENTRY) * count);
(void) memset((char *)&global_shm->publ_tok_objs[
global_shm->num_publ_tok_obj + 1], 0,
sizeof (TOK_OBJ_ENTRY));
} else {
(void) memset((char *)&global_shm->publ_tok_objs[
global_shm->num_publ_tok_obj], 0,
sizeof (TOK_OBJ_ENTRY));
}
}
return (CKR_OK);
}
static CK_RV
object_mgr_check_shm(TSS_HCONTEXT hContext, OBJECT *obj)
{
TOK_OBJ_ENTRY * entry = NULL;
CK_BBOOL priv;
CK_ULONG index;
CK_RV rc;
priv = object_is_private(obj);
if (priv) {
rc = object_mgr_search_shm_for_obj(
global_shm->priv_tok_objs,
0, global_shm->num_priv_tok_obj - 1, obj, &index);
if (rc != CKR_OK) {
return (CKR_FUNCTION_FAILED);
}
entry = &global_shm->priv_tok_objs[index];
} else {
rc = object_mgr_search_shm_for_obj(
global_shm->publ_tok_objs,
0, global_shm->num_publ_tok_obj - 1, obj, &index);
if (rc != CKR_OK) {
return (CKR_FUNCTION_FAILED);
}
entry = &global_shm->publ_tok_objs[index];
}
if ((obj->count_hi == entry->count_hi) &&
(obj->count_lo == entry->count_lo))
return (CKR_OK);
rc = reload_token_object(hContext, obj);
return (rc);
}
static CK_RV
object_mgr_search_shm_for_obj(
TOK_OBJ_ENTRY *obj_list,
CK_ULONG lo,
CK_ULONG hi,
OBJECT *obj,
CK_ULONG *index)
{
CK_ULONG idx;
if (obj->index == 0) {
for (idx = lo; idx <= hi; idx++) {
if (memcmp(obj->name, obj_list[idx].name, 8) == 0) {
*index = idx;
obj->index = idx;
return (CKR_OK);
}
}
} else {
if (memcmp(obj->name, obj_list[obj->index].name, 8) == 0) {
*index = obj->index;
return (CKR_OK);
} else {
for (idx = lo; idx <= hi; idx++) {
if (memcmp(obj->name,
obj_list[idx].name, 8) == 0) {
*index = idx;
obj->index = idx;
return (CKR_OK);
}
}
}
}
return (CKR_FUNCTION_FAILED);
}
static CK_RV
object_mgr_update_publ_tok_obj_from_shm(TSS_HCONTEXT hContext)
{
DL_NODE * node = NULL;
DL_NODE * next = NULL;
TOK_OBJ_ENTRY * te = NULL;
OBJECT * obj = NULL;
CK_OBJECT_HANDLE handle;
CK_ULONG index;
int val;
CK_RV rc;
node = publ_token_obj_list;
index = 0;
while ((node != NULL) && (index < global_shm->num_publ_tok_obj)) {
te = &global_shm->publ_tok_objs[index];
obj = (OBJECT *)node->data;
val = memcmp(obj->name, te->name, 8);
if (val < 0) {
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_remove_from_map(handle);
}
(void) object_free(obj);
next = node->next;
publ_token_obj_list = dlist_remove_node(
publ_token_obj_list, node);
} else if (val == 0) {
if ((te->count_hi != obj->count_hi) ||
(te->count_lo != obj->count_lo)) {
(void) reload_token_object(hContext, obj);
obj->count_hi = te->count_hi;
obj->count_lo = te->count_lo;
}
next = node->next;
index++;
} else {
DL_NODE *new_node = NULL;
OBJECT *new_obj = NULL;
new_obj = (OBJECT *)malloc(sizeof (OBJECT));
(void) memset(new_obj, 0x0, sizeof (OBJECT));
(void) memcpy(new_obj->name, te->name, 8);
(void) reload_token_object(hContext, new_obj);
new_node = (DL_NODE *)malloc(sizeof (DL_NODE));
new_node->data = new_obj;
new_node->next = node->next;
node->next = new_node;
new_node->prev = node;
next = new_node->next;
index++;
}
node = next;
}
if ((node == NULL) && (index < global_shm->num_publ_tok_obj)) {
OBJECT *new_obj = NULL;
unsigned int i;
for (i = index; i < global_shm->num_publ_tok_obj; i++) {
new_obj = (OBJECT *)malloc(sizeof (OBJECT));
(void) memset(new_obj, 0x0, sizeof (OBJECT));
te = &global_shm->publ_tok_objs[index];
(void) memcpy(new_obj->name, te->name, 8);
(void) reload_token_object(hContext, new_obj);
publ_token_obj_list = dlist_add_as_last(
publ_token_obj_list, new_obj);
}
} else if ((node != NULL) && (index >= global_shm->num_publ_tok_obj)) {
while (node) {
obj = (OBJECT *)node->data;
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_remove_from_map(handle);
}
(void) object_free(obj);
next = node->next;
publ_token_obj_list = dlist_remove_node(
publ_token_obj_list, node);
node = next;
}
}
return (CKR_OK);
}
static CK_RV
object_mgr_update_priv_tok_obj_from_shm(TSS_HCONTEXT hContext)
{
DL_NODE * node = NULL;
DL_NODE * next = NULL;
TOK_OBJ_ENTRY * te = NULL;
OBJECT * obj = NULL;
CK_OBJECT_HANDLE handle;
CK_ULONG index;
int val;
CK_RV rc;
node = priv_token_obj_list;
index = 0;
if (! (global_login_state == CKS_RW_USER_FUNCTIONS ||
global_login_state == CKS_RO_USER_FUNCTIONS)) {
return (CKR_OK);
}
while ((node != NULL) && (index < global_shm->num_priv_tok_obj)) {
te = &global_shm->priv_tok_objs[index];
obj = (OBJECT *)node->data;
val = memcmp(obj->name, te->name, 8);
if (val < 0) {
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_remove_from_map(handle);
}
(void) object_free(obj);
next = node->next;
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, node);
} else if (val == 0) {
if ((te->count_hi != obj->count_hi) ||
(te->count_lo != obj->count_lo)) {
(void) reload_token_object(hContext, obj);
obj->count_hi = te->count_hi;
obj->count_lo = te->count_lo;
}
next = node->next;
index++;
} else {
DL_NODE *new_node = NULL;
OBJECT *new_obj = NULL;
new_obj = (OBJECT *)malloc(sizeof (OBJECT));
(void) memset(new_obj, 0x0, sizeof (OBJECT));
(void) memcpy(new_obj->name, te->name, 8);
(void) reload_token_object(hContext, new_obj);
new_node = (DL_NODE *)malloc(sizeof (DL_NODE));
new_node->data = new_obj;
new_node->next = node->next;
node->next = new_node;
new_node->prev = node;
next = new_node->next;
index++;
}
node = next;
}
if ((node == NULL) && (index < global_shm->num_priv_tok_obj)) {
OBJECT *new_obj = NULL;
unsigned int i;
for (i = index; i < global_shm->num_priv_tok_obj; i++) {
new_obj = (OBJECT *)malloc(sizeof (OBJECT));
(void) memset(new_obj, 0x0, sizeof (OBJECT));
te = &global_shm->priv_tok_objs[index];
(void) memcpy(new_obj->name, te->name, 8);
(void) reload_token_object(hContext, new_obj);
priv_token_obj_list = dlist_add_as_last(
priv_token_obj_list, new_obj);
}
} else if ((node != NULL) && (index >= global_shm->num_priv_tok_obj)) {
while (node) {
obj = (OBJECT *)node->data;
rc = object_mgr_find_in_map2(hContext, obj, &handle);
if (rc == CKR_OK) {
(void) object_mgr_remove_from_map(handle);
}
(void) object_free(obj);
next = node->next;
priv_token_obj_list = dlist_remove_node(
priv_token_obj_list, node);
node = next;
}
}
return (CKR_OK);
}
static CK_RV
object_mgr_update_from_shm(TSS_HCONTEXT hContext)
{
(void) object_mgr_update_publ_tok_obj_from_shm(hContext);
(void) object_mgr_update_priv_tok_obj_from_shm(hContext);
return (CKR_OK);
}
CK_BBOOL
object_mgr_purge_map(
SESSION *sess,
SESS_OBJ_TYPE type)
{
DL_NODE *node = NULL;
DL_NODE *next = NULL;
if (pthread_rwlock_wrlock(&obj_list_rw_mutex)) {
return (CKR_FUNCTION_FAILED);
}
node = object_map;
while (node) {
OBJECT_MAP *map = (OBJECT_MAP *)node->data;
OBJECT *obj = (OBJECT *)map->ptr;
next = node->next;
if (type == PRIVATE) {
if (object_is_private(obj)) {
object_map = dlist_remove_node(
object_map, node);
free(map);
}
}
if (type == PUBLIC) {
if (object_is_public(obj)) {
object_map = dlist_remove_node(
object_map, node);
free(map);
}
}
node = next;
}
(void) pthread_rwlock_unlock(&obj_list_rw_mutex);
return (TRUE);
}