diff options
Diffstat (limited to 'nss/lib/ckfw/dbm/db.c')
-rw-r--r-- | nss/lib/ckfw/dbm/db.c | 1033 |
1 files changed, 1033 insertions, 0 deletions
diff --git a/nss/lib/ckfw/dbm/db.c b/nss/lib/ckfw/dbm/db.c new file mode 100644 index 0000000..8d0a6cb --- /dev/null +++ b/nss/lib/ckfw/dbm/db.c @@ -0,0 +1,1033 @@ +/* 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 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#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_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; +} |