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