/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable * instead of those above. If you wish to allow use of your * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL. If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. */ #ifdef DEBUG static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; #endif /* DEBUG */ #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 */ { if( CKR_OK != NSSCKFWMutex_Lock(db->crustylock) ) { 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_NETSCAPE_URL: return type_opaque; case CKA_NETSCAPE_EMAIL: return type_opaque; case CKA_NETSCAPE_SMIME_INFO: return type_opaque; case CKA_NETSCAPE_SMIME_TIMESTAMP: return type_opaque; case CKA_NETSCAPE_PKCS8_SALT: return type_opaque; case CKA_NETSCAPE_PASSWORD_CHECK: return type_opaque; case CKA_NETSCAPE_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_NETSCAPE_DB: return type_opaque; case CKA_NETSCAPE_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; }