Source code
Revision control
Copy as Markdown
Other Tools
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
#include "ckdbm.h"
#define PREFIX_METADATA "0000"
#define PREFIX_OBJECT "0001"
#define PREFIX_INDEX "0002"
static CK_VERSION nss_dbm_db_format_version = { 1, 0 };
struct handle {
char prefix[4];
CK_ULONG id;
};
NSS_IMPLEMENT nss_dbm_db_t *
nss_dbm_db_open(
NSSArena *arena,
NSSCKFWInstance *fwInstance,
char *filename,
int flags,
CK_RV *pError)
{
nss_dbm_db_t *rv;
CK_VERSION db_version;
rv = nss_ZNEW(arena, nss_dbm_db_t);
if ((nss_dbm_db_t *)NULL == rv) {
*pError = CKR_HOST_MEMORY;
return (nss_dbm_db_t *)NULL;
}
rv->db = dbopen(filename, flags, 0600, DB_HASH, (const void *)NULL);
if ((DB *)NULL == rv->db) {
*pError = CKR_TOKEN_NOT_PRESENT;
return (nss_dbm_db_t *)NULL;
}
rv->crustylock = NSSCKFWInstance_CreateMutex(fwInstance, arena, pError);
if ((NSSCKFWMutex *)NULL == rv->crustylock) {
return (nss_dbm_db_t *)NULL;
}
db_version = nss_dbm_db_get_format_version(rv);
if (db_version.major != nss_dbm_db_format_version.major) {
nss_dbm_db_close(rv);
*pError = CKR_TOKEN_NOT_RECOGNIZED;
return (nss_dbm_db_t *)NULL;
}
return rv;
}
NSS_IMPLEMENT void
nss_dbm_db_close(
nss_dbm_db_t *db)
{
if ((NSSCKFWMutex *)NULL != db->crustylock) {
(void)NSSCKFWMutex_Destroy(db->crustylock);
}
if ((DB *)NULL != db->db) {
(void)db->db->close(db->db);
}
nss_ZFreeIf(db);
}
NSS_IMPLEMENT CK_VERSION
nss_dbm_db_get_format_version(
nss_dbm_db_t *db)
{
CK_VERSION rv;
DBT k, v;
int dbrv;
char buffer[64];
rv.major = rv.minor = 0;
k.data = PREFIX_METADATA "FormatVersion";
k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
(void)memset(&v, 0, sizeof(v));
/* Locked region */
{
if (CKR_OK != NSSCKFWMutex_Lock(db->crustylock)) {
return rv;
}
dbrv = db->db->get(db->db, &k, &v, 0);
if (dbrv == 0) {
CK_ULONG major = 0, minor = 0;
(void)PR_sscanf(v.data, "%ld.%ld", &major, &minor);
rv.major = major;
rv.minor = minor;
} else if (dbrv > 0) {
(void)PR_snprintf(buffer, sizeof(buffer), "%ld.%ld", nss_dbm_db_format_version.major,
nss_dbm_db_format_version.minor);
v.data = buffer;
v.size = nssUTF8_Size((NSSUTF8 *)v.data, (PRStatus *)NULL);
dbrv = db->db->put(db->db, &k, &v, 0);
(void)db->db->sync(db->db, 0);
rv = nss_dbm_db_format_version;
} else {
/* No error return.. */
;
}
(void)NSSCKFWMutex_Unlock(db->crustylock);
}
return rv;
}
NSS_IMPLEMENT CK_RV
nss_dbm_db_set_label(
nss_dbm_db_t *db,
NSSUTF8 *label)
{
CK_RV rv;
DBT k, v;
int dbrv;
k.data = PREFIX_METADATA "Label";
k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
v.data = label;
v.size = nssUTF8_Size((NSSUTF8 *)v.data, (PRStatus *)NULL);
/* Locked region */
{
rv = NSSCKFWMutex_Lock(db->crustylock);
if (CKR_OK != rv) {
return rv;
}
dbrv = db->db->put(db->db, &k, &v, 0);
if (0 != dbrv) {
rv = CKR_DEVICE_ERROR;
}
dbrv = db->db->sync(db->db, 0);
if (0 != dbrv) {
rv = CKR_DEVICE_ERROR;
}
(void)NSSCKFWMutex_Unlock(db->crustylock);
}
return rv;
}
NSS_IMPLEMENT NSSUTF8 *
nss_dbm_db_get_label(
nss_dbm_db_t *db,
NSSArena *arena,
CK_RV *pError)
{
NSSUTF8 *rv = (NSSUTF8 *)NULL;
DBT k, v;
int dbrv;
k.data = PREFIX_METADATA "Label";
k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
/* Locked region */
{
if (CKR_OK != NSSCKFWMutex_Lock(db->crustylock)) {
return rv;
}
dbrv = db->db->get(db->db, &k, &v, 0);
if (0 == dbrv) {
rv = nssUTF8_Duplicate((NSSUTF8 *)v.data, arena);
if ((NSSUTF8 *)NULL == rv) {
*pError = CKR_HOST_MEMORY;
}
} else if (dbrv > 0) {
/* Just return null */
;
} else {
*pError = CKR_DEVICE_ERROR;
;
}
(void)NSSCKFWMutex_Unlock(db->crustylock);
}
return rv;
}
NSS_IMPLEMENT CK_RV
nss_dbm_db_delete_object(
nss_dbm_dbt_t *dbt)
{
CK_RV rv;
int dbrv;
/* Locked region */
{
rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
if (CKR_OK != rv) {
return rv;
}
dbrv = dbt->my_db->db->del(dbt->my_db->db, &dbt->dbt, 0);
if (0 != dbrv) {
rv = CKR_DEVICE_ERROR;
goto done;
}
dbrv = dbt->my_db->db->sync(dbt->my_db->db, 0);
if (0 != dbrv) {
rv = CKR_DEVICE_ERROR;
goto done;
}
done:
(void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
}
return rv;
}
static CK_ULONG
nss_dbm_db_new_handle(
nss_dbm_db_t *db,
DBT *dbt, /* pre-allocated */
CK_RV *pError)
{
CK_ULONG rv;
DBT k, v;
CK_ULONG align = 0, id, myid;
struct handle *hp;
if (sizeof(struct handle) != dbt->size) {
return EINVAL;
}
/* Locked region */
{
*pError = NSSCKFWMutex_Lock(db->crustylock);
if (CKR_OK != *pError) {
return EINVAL;
}
k.data = PREFIX_METADATA "LastID";
k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
(void)memset(&v, 0, sizeof(v));
rv = db->db->get(db->db, &k, &v, 0);
if (0 == rv) {
(void)memcpy(&align, v.data, sizeof(CK_ULONG));
id = ntohl(align);
} else if (rv > 0) {
id = 0;
} else {
goto done;
}
myid = id;
id++;
align = htonl(id);
v.data = &align;
v.size = sizeof(CK_ULONG);
rv = db->db->put(db->db, &k, &v, 0);
if (0 != rv) {
goto done;
}
rv = db->db->sync(db->db, 0);
if (0 != rv) {
goto done;
}
done:
(void)NSSCKFWMutex_Unlock(db->crustylock);
}
if (0 != rv) {
return rv;
}
hp = (struct handle *)dbt->data;
(void)memcpy(&hp->prefix[0], PREFIX_OBJECT, 4);
hp->id = myid;
return 0;
}
/*
* This attribute-type-dependent swapping should probably
* be in the Framework, because it'll be a concern of just
* about every Module. Of course any Framework implementation
* will have to be augmentable or overridable by a Module.
*/
enum swap_type { type_byte,
type_short,
type_long,
type_opaque };
static enum swap_type
nss_dbm_db_swap_type(
CK_ATTRIBUTE_TYPE type)
{
switch (type) {
case CKA_CLASS:
return type_long;
case CKA_TOKEN:
return type_byte;
case CKA_PRIVATE:
return type_byte;
case CKA_LABEL:
return type_opaque;
case CKA_APPLICATION:
return type_opaque;
case CKA_VALUE:
return type_opaque;
case CKA_CERTIFICATE_TYPE:
return type_long;
case CKA_ISSUER:
return type_opaque;
case CKA_SERIAL_NUMBER:
return type_opaque;
case CKA_KEY_TYPE:
return type_long;
case CKA_SUBJECT:
return type_opaque;
case CKA_ID:
return type_opaque;
case CKA_SENSITIVE:
return type_byte;
case CKA_ENCRYPT:
return type_byte;
case CKA_DECRYPT:
return type_byte;
case CKA_WRAP:
return type_byte;
case CKA_UNWRAP:
return type_byte;
case CKA_SIGN:
return type_byte;
case CKA_SIGN_RECOVER:
return type_byte;
case CKA_VERIFY:
return type_byte;
case CKA_VERIFY_RECOVER:
return type_byte;
case CKA_DERIVE:
return type_byte;
case CKA_START_DATE:
return type_opaque;
case CKA_END_DATE:
return type_opaque;
case CKA_MODULUS:
return type_opaque;
case CKA_MODULUS_BITS:
return type_long;
case CKA_PUBLIC_EXPONENT:
return type_opaque;
case CKA_PRIVATE_EXPONENT:
return type_opaque;
case CKA_PRIME_1:
return type_opaque;
case CKA_PRIME_2:
return type_opaque;
case CKA_EXPONENT_1:
return type_opaque;
case CKA_EXPONENT_2:
return type_opaque;
case CKA_COEFFICIENT:
return type_opaque;
case CKA_PRIME:
return type_opaque;
case CKA_SUBPRIME:
return type_opaque;
case CKA_BASE:
return type_opaque;
case CKA_VALUE_BITS:
return type_long;
case CKA_VALUE_LEN:
return type_long;
case CKA_EXTRACTABLE:
return type_byte;
case CKA_LOCAL:
return type_byte;
case CKA_NEVER_EXTRACTABLE:
return type_byte;
case CKA_ALWAYS_SENSITIVE:
return type_byte;
case CKA_MODIFIABLE:
return type_byte;
case CKA_NSS_URL:
return type_opaque;
case CKA_NSS_EMAIL:
return type_opaque;
case CKA_NSS_SMIME_INFO:
return type_opaque;
case CKA_NSS_SMIME_TIMESTAMP:
return type_opaque;
case CKA_NSS_PKCS8_SALT:
return type_opaque;
case CKA_NSS_PASSWORD_CHECK:
return type_opaque;
case CKA_NSS_EXPIRES:
return type_opaque;
case CKA_TRUST_DIGITAL_SIGNATURE:
return type_long;
case CKA_TRUST_NON_REPUDIATION:
return type_long;
case CKA_TRUST_KEY_ENCIPHERMENT:
return type_long;
case CKA_TRUST_DATA_ENCIPHERMENT:
return type_long;
case CKA_TRUST_KEY_AGREEMENT:
return type_long;
case CKA_TRUST_KEY_CERT_SIGN:
return type_long;
case CKA_TRUST_CRL_SIGN:
return type_long;
case CKA_TRUST_SERVER_AUTH:
return type_long;
case CKA_TRUST_CLIENT_AUTH:
return type_long;
case CKA_TRUST_CODE_SIGNING:
return type_long;
case CKA_TRUST_EMAIL_PROTECTION:
return type_long;
case CKA_TRUST_IPSEC_END_SYSTEM:
return type_long;
case CKA_TRUST_IPSEC_TUNNEL:
return type_long;
case CKA_TRUST_IPSEC_USER:
return type_long;
case CKA_TRUST_TIME_STAMPING:
return type_long;
case CKA_NSS_DB:
return type_opaque;
case CKA_NSS_TRUST:
return type_opaque;
default:
return type_opaque;
}
}
static void
nss_dbm_db_swap_copy(
CK_ATTRIBUTE_TYPE type,
void *dest,
void *src,
CK_ULONG len)
{
switch (nss_dbm_db_swap_type(type)) {
case type_byte:
case type_opaque:
(void)memcpy(dest, src, len);
break;
case type_short: {
CK_USHORT s, d;
(void)memcpy(&s, src, sizeof(CK_USHORT));
d = htons(s);
(void)memcpy(dest, &d, sizeof(CK_USHORT));
break;
}
case type_long: {
CK_ULONG s, d;
(void)memcpy(&s, src, sizeof(CK_ULONG));
d = htonl(s);
(void)memcpy(dest, &d, sizeof(CK_ULONG));
break;
}
}
}
static CK_RV
nss_dbm_db_wrap_object(
NSSArena *arena,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
DBT *object)
{
CK_ULONG object_size;
CK_ULONG i;
CK_ULONG *pulData;
char *pcData;
CK_ULONG offset;
object_size = (1 + ulAttributeCount * 3) * sizeof(CK_ULONG);
offset = object_size;
for (i = 0; i < ulAttributeCount; i++) {
object_size += pTemplate[i].ulValueLen;
}
object->size = object_size;
object->data = nss_ZAlloc(arena, object_size);
if ((void *)NULL == object->data) {
return CKR_HOST_MEMORY;
}
pulData = (CK_ULONG *)object->data;
pcData = (char *)object->data;
pulData[0] = htonl(ulAttributeCount);
for (i = 0; i < ulAttributeCount; i++) {
CK_ULONG len = pTemplate[i].ulValueLen;
pulData[1 + i * 3] = htonl(pTemplate[i].type);
pulData[2 + i * 3] = htonl(len);
pulData[3 + i * 3] = htonl(offset);
nss_dbm_db_swap_copy(pTemplate[i].type, &pcData[offset], pTemplate[i].pValue, len);
offset += len;
}
return CKR_OK;
}
static CK_RV
nss_dbm_db_unwrap_object(
NSSArena *arena,
DBT *object,
CK_ATTRIBUTE_PTR *ppTemplate,
CK_ULONG *pulAttributeCount)
{
CK_ULONG *pulData;
char *pcData;
CK_ULONG n, i;
CK_ATTRIBUTE_PTR pTemplate;
pulData = (CK_ULONG *)object->data;
pcData = (char *)object->data;
n = ntohl(pulData[0]);
*pulAttributeCount = n;
pTemplate = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, n);
if ((CK_ATTRIBUTE_PTR)NULL == pTemplate) {
return CKR_HOST_MEMORY;
}
for (i = 0; i < n; i++) {
CK_ULONG len;
CK_ULONG offset;
void *p;
pTemplate[i].type = ntohl(pulData[1 + i * 3]);
len = ntohl(pulData[2 + i * 3]);
offset = ntohl(pulData[3 + i * 3]);
p = nss_ZAlloc(arena, len);
if ((void *)NULL == p) {
return CKR_HOST_MEMORY;
}
nss_dbm_db_swap_copy(pTemplate[i].type, p, &pcData[offset], len);
pTemplate[i].ulValueLen = len;
pTemplate[i].pValue = p;
}
*ppTemplate = pTemplate;
return CKR_OK;
}
NSS_IMPLEMENT nss_dbm_dbt_t *
nss_dbm_db_create_object(
NSSArena *arena,
nss_dbm_db_t *db,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_RV *pError,
CK_ULONG *pdbrv)
{
NSSArena *tmparena = (NSSArena *)NULL;
nss_dbm_dbt_t *rv = (nss_dbm_dbt_t *)NULL;
DBT object;
rv = nss_ZNEW(arena, nss_dbm_dbt_t);
if ((nss_dbm_dbt_t *)NULL == rv) {
*pError = CKR_HOST_MEMORY;
return (nss_dbm_dbt_t *)NULL;
}
rv->my_db = db;
rv->dbt.size = sizeof(struct handle);
rv->dbt.data = nss_ZAlloc(arena, rv->dbt.size);
if ((void *)NULL == rv->dbt.data) {
*pError = CKR_HOST_MEMORY;
return (nss_dbm_dbt_t *)NULL;
}
*pdbrv = nss_dbm_db_new_handle(db, &rv->dbt, pError);
if (0 != *pdbrv) {
return (nss_dbm_dbt_t *)NULL;
}
tmparena = NSSArena_Create();
if ((NSSArena *)NULL == tmparena) {
*pError = CKR_HOST_MEMORY;
return (nss_dbm_dbt_t *)NULL;
}
*pError = nss_dbm_db_wrap_object(tmparena, pTemplate, ulAttributeCount, &object);
if (CKR_OK != *pError) {
return (nss_dbm_dbt_t *)NULL;
}
/* Locked region */
{
*pError = NSSCKFWMutex_Lock(db->crustylock);
if (CKR_OK != *pError) {
goto loser;
}
*pdbrv = db->db->put(db->db, &rv->dbt, &object, 0);
if (0 != *pdbrv) {
*pError = CKR_DEVICE_ERROR;
}
(void)db->db->sync(db->db, 0);
(void)NSSCKFWMutex_Unlock(db->crustylock);
}
loser:
if ((NSSArena *)NULL != tmparena) {
(void)NSSArena_Destroy(tmparena);
}
return rv;
}
NSS_IMPLEMENT CK_RV
nss_dbm_db_find_objects(
nss_dbm_find_t *find,
nss_dbm_db_t *db,
CK_ATTRIBUTE_PTR pTemplate,
CK_ULONG ulAttributeCount,
CK_ULONG *pdbrv)
{
CK_RV rv = CKR_OK;
if ((nss_dbm_db_t *)NULL != db) {
DBT k, v;
rv = NSSCKFWMutex_Lock(db->crustylock);
if (CKR_OK != rv) {
return rv;
}
*pdbrv = db->db->seq(db->db, &k, &v, R_FIRST);
while (0 == *pdbrv) {
CK_ULONG i, j;
NSSArena *tmparena = (NSSArena *)NULL;
CK_ULONG ulac;
CK_ATTRIBUTE_PTR pt;
if ((k.size < 4) || (0 != memcmp(k.data, PREFIX_OBJECT, 4))) {
goto nomatch;
}
tmparena = NSSArena_Create();
rv = nss_dbm_db_unwrap_object(tmparena, &v, &pt, &ulac);
if (CKR_OK != rv) {
goto loser;
}
for (i = 0; i < ulAttributeCount; i++) {
for (j = 0; j < ulac; j++) {
if (pTemplate[i].type ==
pt[j].type) {
if (pTemplate[i].ulValueLen !=
pt[j].ulValueLen) {
goto nomatch;
}
if (0 !=
memcmp(pTemplate[i].pValue, pt[j].pValue, pt[j].ulValueLen)) {
goto nomatch;
}
break;
}
}
if (j == ulac) {
goto nomatch;
}
}
/* entire template matches */
{
struct nss_dbm_dbt_node *node;
node = nss_ZNEW(find->arena, struct nss_dbm_dbt_node);
if ((struct nss_dbm_dbt_node *)NULL == node) {
rv =
CKR_HOST_MEMORY;
goto loser;
}
node->dbt = nss_ZNEW(find->arena, nss_dbm_dbt_t);
if ((nss_dbm_dbt_t *)NULL == node->dbt) {
rv =
CKR_HOST_MEMORY;
goto loser;
}
node->dbt->dbt.size = k.size;
node->dbt->dbt.data = nss_ZAlloc(find->arena, k.size);
if ((void *)NULL == node->dbt->dbt.data) {
rv =
CKR_HOST_MEMORY;
goto loser;
}
(void)memcpy(node->dbt->dbt.data, k.data, k.size);
node->dbt->my_db = db;
node->next = find->found;
find->found = node;
}
nomatch:
if ((NSSArena *)NULL != tmparena) {
(void)NSSArena_Destroy(tmparena);
}
*pdbrv = db->db->seq(db->db, &k, &v, R_NEXT);
}
if (*pdbrv < 0) {
rv = CKR_DEVICE_ERROR;
goto loser;
}
rv = CKR_OK;
loser:
(void)NSSCKFWMutex_Unlock(db->crustylock);
}
return rv;
}
NSS_IMPLEMENT CK_BBOOL
nss_dbm_db_object_still_exists(
nss_dbm_dbt_t *dbt)
{
CK_BBOOL rv;
CK_RV ckrv;
int dbrv;
DBT object;
ckrv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
if (CKR_OK != ckrv) {
return CK_FALSE;
}
dbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
if (0 == dbrv) {
rv = CK_TRUE;
} else {
rv = CK_FALSE;
}
(void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
return rv;
}
NSS_IMPLEMENT CK_ULONG
nss_dbm_db_get_object_attribute_count(
nss_dbm_dbt_t *dbt,
CK_RV *pError,
CK_ULONG *pdbrv)
{
CK_ULONG rv = 0;
DBT object;
CK_ULONG *pulData;
/* Locked region */
{
*pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
if (CKR_OK != *pError) {
return rv;
}
*pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
if (0 == *pdbrv) {
;
} else if (*pdbrv > 0) {
*pError = CKR_OBJECT_HANDLE_INVALID;
goto done;
} else {
*pError = CKR_DEVICE_ERROR;
goto done;
}
pulData = (CK_ULONG *)object.data;
rv = ntohl(pulData[0]);
done:
(void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
}
return rv;
}
NSS_IMPLEMENT CK_RV
nss_dbm_db_get_object_attribute_types(
nss_dbm_dbt_t *dbt,
CK_ATTRIBUTE_TYPE_PTR typeArray,
CK_ULONG ulCount,
CK_ULONG *pdbrv)
{
CK_RV rv = CKR_OK;
DBT object;
CK_ULONG *pulData;
CK_ULONG n, i;
/* Locked region */
{
rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
if (CKR_OK != rv) {
return rv;
}
*pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
if (0 == *pdbrv) {
;
} else if (*pdbrv > 0) {
rv = CKR_OBJECT_HANDLE_INVALID;
goto done;
} else {
rv = CKR_DEVICE_ERROR;
goto done;
}
pulData = (CK_ULONG *)object.data;
n = ntohl(pulData[0]);
if (ulCount < n) {
rv = CKR_BUFFER_TOO_SMALL;
goto done;
}
for (i = 0; i < n; i++) {
typeArray[i] = ntohl(pulData[1 + i * 3]);
}
done:
(void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
}
return rv;
}
NSS_IMPLEMENT CK_ULONG
nss_dbm_db_get_object_attribute_size(
nss_dbm_dbt_t *dbt,
CK_ATTRIBUTE_TYPE type,
CK_RV *pError,
CK_ULONG *pdbrv)
{
CK_ULONG rv = 0;
DBT object;
CK_ULONG *pulData;
CK_ULONG n, i;
/* Locked region */
{
*pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
if (CKR_OK != *pError) {
return rv;
}
*pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
if (0 == *pdbrv) {
;
} else if (*pdbrv > 0) {
*pError = CKR_OBJECT_HANDLE_INVALID;
goto done;
} else {
*pError = CKR_DEVICE_ERROR;
goto done;
}
pulData = (CK_ULONG *)object.data;
n = ntohl(pulData[0]);
for (i = 0; i < n; i++) {
if (type == ntohl(pulData[1 + i * 3])) {
rv = ntohl(pulData[2 + i * 3]);
}
}
if (i == n) {
*pError = CKR_ATTRIBUTE_TYPE_INVALID;
goto done;
}
done:
(void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
}
return rv;
}
NSS_IMPLEMENT NSSItem *
nss_dbm_db_get_object_attribute(
nss_dbm_dbt_t *dbt,
NSSArena *arena,
CK_ATTRIBUTE_TYPE type,
CK_RV *pError,
CK_ULONG *pdbrv)
{
NSSItem *rv = (NSSItem *)NULL;
DBT object;
CK_ULONG i;
NSSArena *tmp = NSSArena_Create();
CK_ATTRIBUTE_PTR pTemplate;
CK_ULONG ulAttributeCount;
/* Locked region */
{
*pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
if (CKR_OK != *pError) {
goto loser;
}
*pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
if (0 == *pdbrv) {
;
} else if (*pdbrv > 0) {
*pError = CKR_OBJECT_HANDLE_INVALID;
goto done;
} else {
*pError = CKR_DEVICE_ERROR;
goto done;
}
*pError = nss_dbm_db_unwrap_object(tmp, &object, &pTemplate, &ulAttributeCount);
if (CKR_OK != *pError) {
goto done;
}
for (i = 0; i < ulAttributeCount; i++) {
if (type == pTemplate[i].type) {
rv = nss_ZNEW(arena, NSSItem);
if ((NSSItem *)NULL == rv) {
*pError =
CKR_HOST_MEMORY;
goto done;
}
rv->size = pTemplate[i].ulValueLen;
rv->data = nss_ZAlloc(arena, rv->size);
if ((void *)NULL == rv->data) {
*pError =
CKR_HOST_MEMORY;
goto done;
}
(void)memcpy(rv->data, pTemplate[i].pValue, rv->size);
break;
}
}
if (ulAttributeCount == i) {
*pError = CKR_ATTRIBUTE_TYPE_INVALID;
goto done;
}
done:
(void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
}
loser:
if ((NSSArena *)NULL != tmp) {
NSSArena_Destroy(tmp);
}
return rv;
}
NSS_IMPLEMENT CK_RV
nss_dbm_db_set_object_attribute(
nss_dbm_dbt_t *dbt,
CK_ATTRIBUTE_TYPE type,
NSSItem *value,
CK_ULONG *pdbrv)
{
CK_RV rv = CKR_OK;
DBT object;
CK_ULONG i;
NSSArena *tmp = NSSArena_Create();
CK_ATTRIBUTE_PTR pTemplate;
CK_ULONG ulAttributeCount;
/* Locked region */
{
rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
if (CKR_OK != rv) {
goto loser;
}
*pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
if (0 == *pdbrv) {
;
} else if (*pdbrv > 0) {
rv = CKR_OBJECT_HANDLE_INVALID;
goto done;
} else {
rv = CKR_DEVICE_ERROR;
goto done;
}
rv = nss_dbm_db_unwrap_object(tmp, &object, &pTemplate, &ulAttributeCount);
if (CKR_OK != rv) {
goto done;
}
for (i = 0; i < ulAttributeCount; i++) {
if (type == pTemplate[i].type) {
/* Replacing an existing attribute */
pTemplate[i].ulValueLen = value->size;
pTemplate[i].pValue = value->data;
break;
}
}
if (i == ulAttributeCount) {
/* Adding a new attribute */
CK_ATTRIBUTE_PTR npt = nss_ZNEWARRAY(tmp, CK_ATTRIBUTE, ulAttributeCount + 1);
if ((CK_ATTRIBUTE_PTR)NULL == npt) {
rv = CKR_DEVICE_ERROR;
goto done;
}
for (i = 0; i < ulAttributeCount; i++) {
npt[i] = pTemplate[i];
}
npt[ulAttributeCount].type = type;
npt[ulAttributeCount].ulValueLen = value->size;
npt[ulAttributeCount].pValue = value->data;
pTemplate = npt;
ulAttributeCount++;
}
rv = nss_dbm_db_wrap_object(tmp, pTemplate, ulAttributeCount, &object);
if (CKR_OK != rv) {
goto done;
}
*pdbrv = dbt->my_db->db->put(dbt->my_db->db, &dbt->dbt, &object, 0);
if (0 != *pdbrv) {
rv = CKR_DEVICE_ERROR;
goto done;
}
(void)dbt->my_db->db->sync(dbt->my_db->db, 0);
done:
(void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
}
loser:
if ((NSSArena *)NULL != tmp) {
NSSArena_Destroy(tmp);
}
return rv;
}