#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <security/cryptoki.h>
#include <sys/debug.h>
#include "softGlobal.h"
#include "softObject.h"
#include "softSession.h"
#include "softKeystore.h"
#include "softKeystoreUtil.h"
void
soft_add_object_to_session(soft_object_t *objp, soft_session_t *sp)
{
(void) pthread_mutex_lock(&sp->session_mutex);
if (sp->object_list == NULL) {
sp->object_list = objp;
objp->next = NULL;
objp->prev = NULL;
} else {
sp->object_list->prev = objp;
objp->next = sp->object_list;
objp->prev = NULL;
sp->object_list = objp;
}
(void) pthread_mutex_unlock(&sp->session_mutex);
}
void
soft_cleanup_object(soft_object_t *objp)
{
soft_cleanup_object_bigint_attrs(objp);
soft_cleanup_extra_attr(objp);
soft_cleanup_cert_object(objp);
}
CK_RV
soft_copy_object(soft_object_t *old_object, soft_object_t **new_object,
CK_ULONG object_func, soft_session_t *sp)
{
CK_RV rv = CKR_OK;
soft_object_t *new_objp = NULL;
CK_ATTRIBUTE_INFO_PTR attrp;
new_objp = calloc(1, sizeof (soft_object_t));
if (new_objp == NULL)
return (CKR_HOST_MEMORY);
new_objp->class = old_object->class;
new_objp->bool_attr_mask = old_object->bool_attr_mask;
new_objp->cert_type = old_object->cert_type;
new_objp->object_type = old_object->object_type;
attrp = old_object->extra_attrlistp;
while (attrp) {
rv = soft_copy_extra_attr(attrp, new_objp);
if (rv != CKR_OK) {
soft_cleanup_extra_attr(new_objp);
free(new_objp);
return (rv);
}
attrp = attrp->next;
}
*new_object = new_objp;
if (object_func == SOFT_SET_ATTR_VALUE) {
return (CKR_OK);
}
new_objp->key_type = old_object->key_type;
new_objp->magic_marker = old_object->magic_marker;
new_objp->mechanism = old_object->mechanism;
switch (object_func) {
case SOFT_COPY_OBJ_ORIG_SH:
new_objp->session_handle = old_object->session_handle;
break;
case SOFT_COPY_OBJECT:
new_objp->session_handle = sp->handle;
break;
}
(void) pthread_cond_init(&(new_objp->obj_free_cond), NULL);
(void) pthread_mutex_init(&(new_objp->object_mutex), NULL);
switch (new_objp->class) {
case CKO_PUBLIC_KEY:
rv = soft_copy_public_key_attr(OBJ_PUB(old_object),
&(OBJ_PUB(new_objp)), new_objp->key_type);
break;
case CKO_PRIVATE_KEY:
rv = soft_copy_private_key_attr(OBJ_PRI(old_object),
&(OBJ_PRI(new_objp)), new_objp->key_type);
break;
case CKO_SECRET_KEY:
rv = soft_copy_secret_key_attr(OBJ_SEC(old_object),
&(OBJ_SEC(new_objp)));
break;
case CKO_DOMAIN_PARAMETERS:
rv = soft_copy_domain_attr(OBJ_DOM(old_object),
&(OBJ_DOM(new_objp)), new_objp->key_type);
break;
case CKO_CERTIFICATE:
rv = soft_copy_certificate(OBJ_CERT(old_object),
&(OBJ_CERT(new_objp)), new_objp->cert_type);
break;
default:
break;
}
if (rv != CKR_OK) {
soft_cleanup_extra_attr(new_objp);
free(new_objp);
}
return (rv);
}
void
soft_merge_object(soft_object_t *old_object, soft_object_t *new_object)
{
old_object->bool_attr_mask = new_object->bool_attr_mask;
soft_cleanup_extra_attr(old_object);
old_object->extra_attrlistp = new_object->extra_attrlistp;
}
CK_RV
handle2object(CK_OBJECT_HANDLE hObject, soft_object_t **object_p,
boolean_t refhold)
{
soft_object_t *obj;
soft_object_t node;
(void) memset(&node, 0, sizeof (node));
node.handle = hObject;
VERIFY0(pthread_mutex_lock(&soft_object_mutex));
if ((obj = avl_find(&soft_object_tree, &node, NULL)) == NULL ||
obj->magic_marker != SOFTTOKEN_OBJECT_MAGIC) {
VERIFY0(pthread_mutex_unlock(&soft_object_mutex));
return (CKR_OBJECT_HANDLE_INVALID);
}
(void) pthread_mutex_lock(&obj->object_mutex);
VERIFY0(pthread_mutex_unlock(&soft_object_mutex));
if (obj->obj_delete_sync & OBJECT_IS_DELETING) {
(void) pthread_mutex_unlock(&obj->object_mutex);
return (CKR_OBJECT_HANDLE_INVALID);
}
if (refhold)
obj->obj_refcnt++;
(void) pthread_mutex_unlock(&obj->object_mutex);
*object_p = obj;
return (CKR_OK);
}
CK_ULONG
set_objecthandle(soft_object_t *obj)
{
avl_index_t where;
(void) pthread_mutex_lock(&soft_object_mutex);
do {
arc4random_buf(&obj->handle, sizeof (obj->handle));
if (obj->handle == CK_INVALID_HANDLE)
continue;
} while (avl_find(&soft_object_tree, obj, &where) != NULL);
avl_insert(&soft_object_tree, obj, where);
(void) pthread_mutex_unlock(&soft_object_mutex);
return (obj->handle);
}
CK_RV
soft_add_object(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
CK_OBJECT_HANDLE_PTR objecthandle_p, soft_session_t *sp)
{
CK_RV rv = CKR_OK;
soft_object_t *new_objp = NULL;
new_objp = calloc(1, sizeof (soft_object_t));
if (new_objp == NULL) {
return (CKR_HOST_MEMORY);
}
new_objp->extra_attrlistp = NULL;
rv = soft_build_object(pTemplate, ulCount, new_objp);
if (rv != CKR_OK) {
goto fail_cleanup1;
}
rv = soft_pin_expired_check(new_objp);
if (rv != CKR_OK) {
goto fail_cleanup2;
}
rv = soft_object_write_access_check(sp, new_objp);
if (rv != CKR_OK) {
goto fail_cleanup2;
}
(void) pthread_cond_init(&new_objp->obj_free_cond, NULL);
(void) pthread_mutex_init(&new_objp->object_mutex, NULL);
new_objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
new_objp->obj_refcnt = 0;
new_objp->obj_delete_sync = 0;
if (IS_TOKEN_OBJECT(new_objp)) {
if (!soft_keystore_status(KEYSTORE_INITIALIZED)) {
rv = CKR_DEVICE_REMOVED;
goto fail_cleanup2;
}
new_objp->version = 1;
rv = soft_put_object_to_keystore(new_objp);
if (rv != CKR_OK) {
(void) pthread_cond_destroy(&new_objp->obj_free_cond);
(void) pthread_mutex_destroy(&new_objp->object_mutex);
goto fail_cleanup2;
}
new_objp->session_handle = CK_INVALID_HANDLE;
soft_add_token_object_to_slot(new_objp);
*objecthandle_p = set_objecthandle(new_objp);
return (CKR_OK);
}
new_objp->session_handle = sp->handle;
soft_add_object_to_session(new_objp, sp);
*objecthandle_p = set_objecthandle(new_objp);
return (CKR_OK);
fail_cleanup2:
soft_cleanup_object(new_objp);
fail_cleanup1:
if (new_objp) {
free(new_objp);
}
return (rv);
}
CK_RV
soft_remove_object_from_session(soft_object_t *objp, soft_session_t *sp)
{
soft_object_t *tmp_objp;
boolean_t found = B_FALSE;
if ((sp == NULL) ||
(sp->magic_marker != SOFTTOKEN_SESSION_MAGIC)) {
return (CKR_SESSION_HANDLE_INVALID);
}
if ((sp->object_list == NULL) || (objp == NULL) ||
(objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC)) {
return (CKR_OBJECT_HANDLE_INVALID);
}
tmp_objp = sp->object_list;
while (tmp_objp) {
if (tmp_objp == objp) {
found = B_TRUE;
break;
}
tmp_objp = tmp_objp->next;
}
if (!found)
return (CKR_OBJECT_HANDLE_INVALID);
if (sp->object_list == objp) {
if (objp->next) {
sp->object_list = objp->next;
objp->next->prev = NULL;
} else {
sp->object_list = NULL;
}
} else {
if (objp->next) {
objp->prev->next = objp->next;
objp->next->prev = objp->prev;
} else {
objp->prev->next = NULL;
}
}
return (CKR_OK);
}
void
object_delay_free(soft_object_t *objp)
{
soft_object_t *tmp;
(void) pthread_mutex_lock(&obj_delay_freed.obj_to_be_free_mutex);
objp->next = NULL;
if (obj_delay_freed.first == NULL) {
obj_delay_freed.last = objp;
obj_delay_freed.first = objp;
} else {
obj_delay_freed.last->next = objp;
obj_delay_freed.last = objp;
}
if (++obj_delay_freed.count >= MAX_OBJ_TO_BE_FREED) {
obj_delay_freed.count--;
tmp = obj_delay_freed.first->next;
free(obj_delay_freed.first);
obj_delay_freed.first = tmp;
}
(void) pthread_mutex_unlock(&obj_delay_freed.obj_to_be_free_mutex);
}
static void
soft_delete_object_cleanup(soft_object_t *objp, boolean_t force)
{
(void) pthread_mutex_lock(&objp->object_mutex);
if (objp->magic_marker != SOFTTOKEN_OBJECT_MAGIC) {
(void) pthread_mutex_unlock(&objp->object_mutex);
return;
}
if (force)
objp->obj_refcnt = 0;
while (objp->obj_refcnt != 0) {
objp->obj_delete_sync |= OBJECT_REFCNT_WAITING;
(void) pthread_cond_wait(&objp->obj_free_cond,
&objp->object_mutex);
}
objp->obj_delete_sync &= ~OBJECT_REFCNT_WAITING;
objp->magic_marker = 0;
(void) pthread_cond_destroy(&objp->obj_free_cond);
soft_cleanup_object(objp);
(void) pthread_mutex_lock(&soft_object_mutex);
avl_remove(&soft_object_tree, objp);
(void) pthread_mutex_unlock(&soft_object_mutex);
objp->obj_delete_sync &= ~OBJECT_IS_DELETING;
(void) pthread_mutex_unlock(&objp->object_mutex);
(void) pthread_mutex_destroy(&objp->object_mutex);
if (IS_TOKEN_OBJECT(objp))
free(objp);
else
(void) object_delay_free(objp);
}
void
soft_delete_object(soft_session_t *sp, soft_object_t *objp,
boolean_t force, boolean_t lock_held)
{
if (!lock_held) {
(void) pthread_mutex_lock(&sp->session_mutex);
}
if (soft_remove_object_from_session(objp, sp) != CKR_OK) {
if (!lock_held) {
(void) pthread_mutex_unlock(&sp->session_mutex);
}
return;
}
if (!lock_held) {
(void) pthread_mutex_unlock(&sp->session_mutex);
}
soft_delete_object_cleanup(objp, force);
}
void
soft_delete_all_objects_in_session(soft_session_t *sp, boolean_t force)
{
soft_object_t *objp = sp->object_list;
soft_object_t *objp1;
while (objp) {
objp1 = objp->next;
soft_delete_object(sp, objp, force, B_TRUE);
objp = objp1;
}
}
static CK_RV
add_to_search_result(soft_object_t *obj, find_context_t *fcontext,
CK_ULONG *num_result_alloc)
{
if (*num_result_alloc <= fcontext->num_results) {
fcontext->objs_found = realloc(fcontext->objs_found,
sizeof (soft_object_t *) * (*num_result_alloc + BUFSIZ));
if (fcontext->objs_found == NULL) {
return (CKR_HOST_MEMORY);
}
*num_result_alloc += BUFSIZ;
}
(fcontext->objs_found)[(fcontext->num_results)++] = obj;
return (CKR_OK);
}
static CK_RV
search_for_objects(CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount,
find_context_t *fcontext)
{
soft_session_t *session_p;
soft_object_t *obj;
CK_OBJECT_CLASS pclasses[6];
CK_ULONG num_pclasses;
CK_ULONG num_result_alloc = 0;
CK_RV rv = CKR_OK;
boolean_t token_specified = B_FALSE;
boolean_t token_flag_val = B_FALSE;
CK_ULONG i;
if (ulCount > 0) {
soft_process_find_attr(pclasses, &num_pclasses,
pTemplate, ulCount);
}
for (i = 0; i < ulCount; i++) {
if (pTemplate[i].type == CKA_PRIVATE) {
(void) pthread_mutex_lock(&soft_giant_mutex);
if (soft_slot.userpin_change_needed) {
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_PIN_EXPIRED);
}
(void) pthread_mutex_unlock(&soft_giant_mutex);
}
}
for (i = 0; i < ulCount; i++) {
if (pTemplate[i].type == CKA_TOKEN) {
token_specified = B_TRUE;
token_flag_val = *((CK_BBOOL *)pTemplate[i].pValue);
break;
}
}
if (((token_flag_val) || (!token_specified)) &&
soft_keystore_status(KEYSTORE_INITIALIZED)) {
(void) pthread_mutex_lock(&soft_slot.slot_mutex);
rv = refresh_token_objects();
if (rv != CKR_OK) {
(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
return (rv);
}
obj = soft_slot.token_object_list;
while (obj) {
(void) pthread_mutex_lock(&obj->object_mutex);
if (((token_specified) && (ulCount > 1)) ||
((!token_specified) && (ulCount > 0))) {
if (soft_find_match_attrs(obj, pclasses,
num_pclasses, pTemplate, ulCount)) {
rv = add_to_search_result(
obj, fcontext, &num_result_alloc);
}
} else {
rv = add_to_search_result(obj, fcontext,
&num_result_alloc);
}
(void) pthread_mutex_unlock(&obj->object_mutex);
if (rv != CKR_OK) {
(void) pthread_mutex_unlock
(&soft_slot.slot_mutex);
return (rv);
}
obj = obj->next;
}
(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
}
if (token_flag_val) {
return (rv);
}
(void) pthread_mutex_lock(&soft_sessionlist_mutex);
session_p = soft_session_list;
while (session_p) {
(void) pthread_mutex_lock(&session_p->session_mutex);
obj = session_p->object_list;
while (obj) {
(void) pthread_mutex_lock(&obj->object_mutex);
if (ulCount > 0) {
if (soft_find_match_attrs(obj, pclasses,
num_pclasses, pTemplate, ulCount)) {
rv = add_to_search_result(
obj, fcontext, &num_result_alloc);
}
} else {
rv = add_to_search_result(obj, fcontext,
&num_result_alloc);
}
(void) pthread_mutex_unlock(&obj->object_mutex);
if (rv != CKR_OK) {
(void) pthread_mutex_unlock(
&session_p->session_mutex);
goto cleanup;
}
obj = obj->next;
}
(void) pthread_mutex_unlock(&session_p->session_mutex);
session_p = session_p->next;
}
cleanup:
(void) pthread_mutex_unlock(&soft_sessionlist_mutex);
return (rv);
}
CK_RV
soft_find_objects_init(soft_session_t *sp, CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulCount)
{
CK_RV rv = CKR_OK;
CK_OBJECT_CLASS class;
find_context_t *fcontext;
if (ulCount) {
rv = soft_validate_attr(pTemplate, ulCount, &class);
if (rv != CKR_OK) {
return (rv);
}
}
fcontext = calloc(1, sizeof (find_context_t));
if (fcontext == NULL) {
return (CKR_HOST_MEMORY);
}
rv = search_for_objects(pTemplate, ulCount, fcontext);
if (rv != CKR_OK) {
free(fcontext);
return (rv);
}
sp->find_objects.context = (CK_VOID_PTR)fcontext;
return (rv);
}
void
soft_find_objects_final(soft_session_t *sp)
{
find_context_t *fcontext;
fcontext = sp->find_objects.context;
sp->find_objects.context = NULL;
sp->find_objects.flags = 0;
if (fcontext->objs_found != NULL) {
free(fcontext->objs_found);
}
free(fcontext);
}
void
soft_find_objects(soft_session_t *sp, CK_OBJECT_HANDLE *obj_found,
CK_ULONG max_obj_requested, CK_ULONG *found_obj_count)
{
find_context_t *fcontext;
CK_ULONG num_obj_found = 0;
CK_ULONG i;
soft_object_t *obj;
fcontext = sp->find_objects.context;
for (i = fcontext->next_result_index;
((num_obj_found < max_obj_requested) &&
(i < fcontext->num_results));
i++) {
obj = fcontext->objs_found[i];
if (obj != NULL) {
(void) pthread_mutex_lock(&obj->object_mutex);
if (obj->magic_marker == SOFTTOKEN_OBJECT_MAGIC) {
obj_found[num_obj_found] = obj->handle;
num_obj_found++;
}
(void) pthread_mutex_unlock(&obj->object_mutex);
}
}
fcontext->next_result_index = i;
*found_obj_count = num_obj_found;
}
void
soft_add_token_object_to_slot(soft_object_t *objp)
{
(void) pthread_mutex_lock(&soft_slot.slot_mutex);
if (soft_slot.token_object_list == NULL) {
soft_slot.token_object_list = objp;
objp->next = NULL;
objp->prev = NULL;
} else {
soft_slot.token_object_list->prev = objp;
objp->next = soft_slot.token_object_list;
objp->prev = NULL;
soft_slot.token_object_list = objp;
}
(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
}
void
soft_remove_token_object_from_slot(soft_object_t *objp, boolean_t lock_held)
{
if (!lock_held)
(void) pthread_mutex_lock(&soft_slot.slot_mutex);
if (soft_slot.token_object_list == objp) {
if (objp->next) {
soft_slot.token_object_list = objp->next;
objp->next->prev = NULL;
} else {
soft_slot.token_object_list = NULL;
}
} else {
if (objp->next) {
objp->prev->next = objp->next;
objp->next->prev = objp->prev;
} else {
objp->prev->next = NULL;
}
}
if (!lock_held)
(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
}
void
soft_delete_token_object(soft_object_t *objp, boolean_t persistent,
boolean_t lock_held)
{
if (!lock_held)
(void) pthread_mutex_lock(&soft_slot.slot_mutex);
if (persistent)
(void) soft_keystore_del_obj(&objp->ks_handle, B_FALSE);
soft_remove_token_object_from_slot(objp, B_TRUE);
if (!lock_held)
(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
soft_delete_object_cleanup(objp, B_FALSE);
}
void
soft_delete_all_in_core_token_objects(token_obj_type_t type)
{
soft_object_t *objp;
soft_object_t *objp1;
(void) pthread_mutex_lock(&soft_slot.slot_mutex);
objp = soft_slot.token_object_list;
switch (type) {
case PRIVATE_TOKEN:
while (objp) {
objp1 = objp->next;
if (objp->object_type == TOKEN_PRIVATE) {
soft_delete_token_object(objp, B_FALSE, B_TRUE);
}
objp = objp1;
}
break;
case PUBLIC_TOKEN:
while (objp) {
objp1 = objp->next;
if (objp->object_type == TOKEN_PUBLIC) {
soft_delete_token_object(objp, B_FALSE, B_TRUE);
}
objp = objp1;
}
break;
case ALL_TOKEN:
while (objp) {
objp1 = objp->next;
soft_delete_token_object(objp, B_FALSE, B_TRUE);
objp = objp1;
}
break;
}
(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
}
void
soft_validate_token_objects(boolean_t validate)
{
soft_object_t *objp;
(void) pthread_mutex_lock(&soft_slot.slot_mutex);
objp = soft_slot.token_object_list;
while (objp) {
if (validate)
objp->magic_marker = SOFTTOKEN_OBJECT_MAGIC;
else
objp->magic_marker = 0;
objp = objp->next;
}
(void) pthread_mutex_unlock(&soft_slot.slot_mutex);
}
CK_RV
soft_object_write_access_check(soft_session_t *sp, soft_object_t *objp)
{
(void) pthread_mutex_lock(&soft_giant_mutex);
if (!soft_slot.authenticated) {
(void) pthread_mutex_unlock(&soft_giant_mutex);
if (sp->flags & CKF_RW_SESSION) {
if ((objp->object_type == TOKEN_PRIVATE) ||
(objp->object_type == SESSION_PRIVATE)) {
return (CKR_USER_NOT_LOGGED_IN);
}
} else {
if (objp->object_type != SESSION_PUBLIC)
return (CKR_SESSION_READ_ONLY);
}
} else {
(void) pthread_mutex_unlock(&soft_giant_mutex);
if (!(sp->flags & CKF_RW_SESSION)) {
if ((objp->object_type == TOKEN_PUBLIC) ||
(objp->object_type == TOKEN_PRIVATE)) {
return (CKR_SESSION_READ_ONLY);
}
}
}
return (CKR_OK);
}
CK_RV
soft_pin_expired_check(soft_object_t *objp)
{
(void) pthread_mutex_lock(&soft_giant_mutex);
if (soft_slot.userpin_change_needed) {
if ((objp->object_type == TOKEN_PRIVATE) ||
(objp->object_type == SESSION_PRIVATE)) {
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_PIN_EXPIRED);
}
}
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_OK);
}
CK_RV
soft_copy_to_old_object(soft_object_t *new, soft_object_t *old)
{
CK_RV rv = CKR_OK;
CK_ATTRIBUTE_INFO_PTR attrp;
old->class = new->class;
old->bool_attr_mask = new->bool_attr_mask;
soft_cleanup_extra_attr(old);
attrp = new->extra_attrlistp;
while (attrp) {
rv = soft_copy_extra_attr(attrp, old);
if (rv != CKR_OK) {
soft_cleanup_extra_attr(old);
return (rv);
}
attrp = attrp->next;
}
return (CKR_OK);
}
CK_RV
soft_update_object(ks_obj_t *ks_obj, soft_object_t *old_obj)
{
soft_object_t *new_object;
CK_RV rv;
new_object = calloc(1, sizeof (soft_object_t));
if (new_object == NULL)
return (CKR_HOST_MEMORY);
rv = soft_keystore_unpack_obj(new_object, ks_obj);
if (rv != CKR_OK) {
soft_cleanup_object(new_object);
free(new_object);
return (rv);
}
rv = soft_copy_to_old_object(new_object, old_obj);
soft_cleanup_object(new_object);
free(new_object);
return (CKR_OK);
}
CK_RV
soft_keystore_load_latest_object(soft_object_t *old_obj)
{
uint_t version;
ks_obj_t *ks_obj = NULL;
CK_RV rv = CKR_OK;
if (soft_keystore_get_object_version(&old_obj->ks_handle, &version,
B_FALSE) == 1)
return (CKR_FUNCTION_FAILED);
if (old_obj->version != version) {
rv = soft_keystore_get_single_obj(&old_obj->ks_handle,
&ks_obj, B_FALSE);
if (rv != CKR_OK)
return (rv);
old_obj->version = version;
rv = soft_update_object(ks_obj, old_obj);
free(ks_obj->buf);
free(ks_obj);
}
return (rv);
}
static void
insert_into_list(soft_object_t **list, soft_object_t **end_of_list,
soft_object_t *objp)
{
if (*list == NULL) {
*list = objp;
objp->next = NULL;
objp->prev = NULL;
*end_of_list = objp;
} else {
(*list)->prev = objp;
objp->next = *list;
objp->prev = NULL;
*list = objp;
}
}
static void
move_into_list(soft_object_t **existing_list, soft_object_t **new_list,
soft_object_t **end_of_list, soft_object_t *objp)
{
if (objp == *existing_list) {
if (objp->next) {
*existing_list = objp->next;
objp->next->prev = NULL;
} else {
*existing_list = NULL;
}
} else {
if (objp->next) {
objp->prev->next = objp->next;
objp->next->prev = objp->prev;
} else {
objp->prev->next = NULL;
}
}
insert_into_list(new_list, end_of_list, objp);
}
static void
insert_list_into_list(soft_object_t **existing_list,
soft_object_t *new_list, soft_object_t *end_new_list)
{
if (new_list == NULL) {
return;
}
if (*existing_list == NULL) {
*existing_list = new_list;
} else {
(*existing_list)->prev = end_new_list;
end_new_list->next = *existing_list;
*existing_list = new_list;
}
}
static void
delete_all_objs_in_list(soft_object_t *list)
{
soft_object_t *objp, *objp_next;
if (list == NULL) {
return;
}
objp = list;
while (objp) {
objp_next = objp->next;
soft_delete_object_cleanup(objp, B_FALSE);
objp = objp_next;
}
}
CK_RV
refresh_token_objects()
{
uint_t on_disk_ks_version;
ks_obj_t *on_disk_list = NULL, *tmp_on_disk, *next_on_disk;
soft_object_t *in_core_obj, *tmp_incore_obj, *new_objp = NULL;
CK_RV rv = CKR_OK;
soft_object_t *del_objs_list = NULL;
soft_object_t *end_del_objs_list = NULL;
soft_object_t *mod_objs_list = NULL;
soft_object_t *end_mod_objs_list = NULL;
soft_object_t *copy_of_mod_objs_list = NULL;
soft_object_t *end_copy_of_mod_objs_list = NULL;
soft_object_t *added_objs_list = NULL;
soft_object_t *end_added_objs_list = NULL;
if (soft_keystore_get_version(&on_disk_ks_version, B_FALSE) != 0) {
return (CKR_FUNCTION_FAILED);
}
(void) pthread_mutex_lock(&soft_giant_mutex);
if (on_disk_ks_version == soft_slot.ks_version) {
(void) pthread_mutex_unlock(&soft_giant_mutex);
return (CKR_OK);
}
if (soft_slot.authenticated) {
(void) pthread_mutex_unlock(&soft_giant_mutex);
rv = soft_keystore_get_objs(ALL_TOKENOBJS, &on_disk_list,
B_FALSE);
} else {
(void) pthread_mutex_unlock(&soft_giant_mutex);
rv = soft_keystore_get_objs(PUB_TOKENOBJS, &on_disk_list,
B_FALSE);
}
if (rv != CKR_OK) {
return (rv);
}
in_core_obj = soft_slot.token_object_list;
while (in_core_obj) {
ks_obj_t *ondisk_obj, *prev_ondisk_obj;
boolean_t found = B_FALSE;
soft_object_t *obj_copy;
ondisk_obj = on_disk_list;
prev_ondisk_obj = NULL;
if (in_core_obj->ks_handle.name[0] == '\0') {
in_core_obj = in_core_obj->next;
continue;
}
while ((!found) && (ondisk_obj != NULL)) {
if (strcmp((char *)((ondisk_obj->ks_handle).name),
(char *)((in_core_obj->ks_handle).name)) == 0) {
found = B_TRUE;
if (ondisk_obj->obj_version !=
in_core_obj->version) {
rv = soft_copy_object(in_core_obj,
&obj_copy, SOFT_COPY_OBJ_ORIG_SH,
NULL);
if (rv != CKR_OK) {
goto cleanup;
}
insert_into_list(
©_of_mod_objs_list,
&end_copy_of_mod_objs_list,
obj_copy);
rv = soft_update_object(ondisk_obj,
in_core_obj);
if (rv != CKR_OK) {
goto cleanup;
}
move_into_list(
&(soft_slot.token_object_list),
&mod_objs_list, &end_mod_objs_list,
in_core_obj);
}
if (ondisk_obj == on_disk_list) {
on_disk_list = ondisk_obj->next;
} else {
prev_ondisk_obj->next =
ondisk_obj->next;
}
free(ondisk_obj->buf);
free(ondisk_obj);
} else {
prev_ondisk_obj = ondisk_obj;
ondisk_obj = ondisk_obj->next;
}
}
if (!found) {
tmp_incore_obj = in_core_obj->next;
move_into_list(&(soft_slot.token_object_list),
&del_objs_list, &end_del_objs_list, in_core_obj);
in_core_obj = tmp_incore_obj;
} else {
in_core_obj = in_core_obj->next;
}
}
next_on_disk = on_disk_list;
while (next_on_disk) {
new_objp = calloc(1, sizeof (soft_object_t));
if (new_objp == NULL) {
rv = CKR_HOST_MEMORY;
goto cleanup;
}
rv = soft_keystore_unpack_obj(new_objp, next_on_disk);
if (rv != CKR_OK) {
soft_cleanup_object(new_objp);
free(new_objp);
goto cleanup;
}
insert_into_list(&added_objs_list, &end_added_objs_list,
new_objp);
tmp_on_disk = next_on_disk;
next_on_disk = tmp_on_disk->next;
free(tmp_on_disk->buf);
free(tmp_on_disk);
}
if (rv == CKR_OK) {
(void) pthread_mutex_lock(&soft_giant_mutex);
soft_slot.ks_version = on_disk_ks_version;
(void) pthread_mutex_unlock(&soft_giant_mutex);
insert_list_into_list(&(soft_slot.token_object_list),
added_objs_list, end_added_objs_list);
insert_list_into_list(&(soft_slot.token_object_list),
mod_objs_list, end_mod_objs_list);
delete_all_objs_in_list(copy_of_mod_objs_list);
delete_all_objs_in_list(del_objs_list);
}
return (rv);
cleanup:
next_on_disk = on_disk_list;
while (next_on_disk) {
tmp_on_disk = next_on_disk;
next_on_disk = tmp_on_disk->next;
free(tmp_on_disk->buf);
free(tmp_on_disk);
}
insert_list_into_list(&(soft_slot.token_object_list),
del_objs_list, end_del_objs_list);
insert_list_into_list(&(soft_slot.token_object_list),
copy_of_mod_objs_list, end_copy_of_mod_objs_list);
delete_all_objs_in_list(mod_objs_list);
delete_all_objs_in_list(added_objs_list);
return (rv);
}
CK_RV
dup_bigint_attr(biginteger_t *bi, CK_BYTE *buf, CK_ULONG buflen)
{
bi->big_value_len = buflen;
if ((bi->big_value = malloc(buflen)) == NULL) {
return (CKR_HOST_MEMORY);
}
(void) memcpy(bi->big_value, buf, buflen);
return (CKR_OK);
}