tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

db.c (26773B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "ckdbm.h"
      6 
      7 #define PREFIX_METADATA "0000"
      8 #define PREFIX_OBJECT "0001"
      9 #define PREFIX_INDEX "0002"
     10 
     11 static CK_VERSION nss_dbm_db_format_version = { 1, 0 };
     12 struct handle {
     13    char prefix[4];
     14    CK_ULONG id;
     15 };
     16 
     17 NSS_IMPLEMENT nss_dbm_db_t *
     18 nss_dbm_db_open(
     19    NSSArena *arena,
     20    NSSCKFWInstance *fwInstance,
     21    char *filename,
     22    int flags,
     23    CK_RV *pError)
     24 {
     25    nss_dbm_db_t *rv;
     26    CK_VERSION db_version;
     27 
     28    rv = nss_ZNEW(arena, nss_dbm_db_t);
     29    if ((nss_dbm_db_t *)NULL == rv) {
     30        *pError = CKR_HOST_MEMORY;
     31        return (nss_dbm_db_t *)NULL;
     32    }
     33 
     34    rv->db = dbopen(filename, flags, 0600, DB_HASH, (const void *)NULL);
     35    if ((DB *)NULL == rv->db) {
     36        *pError = CKR_TOKEN_NOT_PRESENT;
     37        return (nss_dbm_db_t *)NULL;
     38    }
     39 
     40    rv->crustylock = NSSCKFWInstance_CreateMutex(fwInstance, arena, pError);
     41    if ((NSSCKFWMutex *)NULL == rv->crustylock) {
     42        return (nss_dbm_db_t *)NULL;
     43    }
     44 
     45    db_version = nss_dbm_db_get_format_version(rv);
     46    if (db_version.major != nss_dbm_db_format_version.major) {
     47        nss_dbm_db_close(rv);
     48        *pError = CKR_TOKEN_NOT_RECOGNIZED;
     49        return (nss_dbm_db_t *)NULL;
     50    }
     51 
     52    return rv;
     53 }
     54 
     55 NSS_IMPLEMENT void
     56 nss_dbm_db_close(
     57    nss_dbm_db_t *db)
     58 {
     59    if ((NSSCKFWMutex *)NULL != db->crustylock) {
     60        (void)NSSCKFWMutex_Destroy(db->crustylock);
     61    }
     62 
     63    if ((DB *)NULL != db->db) {
     64        (void)db->db->close(db->db);
     65    }
     66 
     67    nss_ZFreeIf(db);
     68 }
     69 
     70 NSS_IMPLEMENT CK_VERSION
     71 nss_dbm_db_get_format_version(
     72    nss_dbm_db_t *db)
     73 {
     74    CK_VERSION rv;
     75    DBT k, v;
     76    int dbrv;
     77    char buffer[64];
     78 
     79    rv.major = rv.minor = 0;
     80 
     81    k.data = PREFIX_METADATA "FormatVersion";
     82    k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
     83    (void)memset(&v, 0, sizeof(v));
     84 
     85    /* Locked region */
     86    {
     87        if (CKR_OK != NSSCKFWMutex_Lock(db->crustylock)) {
     88            return rv;
     89        }
     90 
     91        dbrv = db->db->get(db->db, &k, &v, 0);
     92        if (dbrv == 0) {
     93            CK_ULONG major = 0, minor = 0;
     94            (void)PR_sscanf(v.data, "%ld.%ld", &major, &minor);
     95            rv.major = major;
     96            rv.minor = minor;
     97        } else if (dbrv > 0) {
     98            (void)PR_snprintf(buffer, sizeof(buffer), "%ld.%ld", nss_dbm_db_format_version.major,
     99                              nss_dbm_db_format_version.minor);
    100            v.data = buffer;
    101            v.size = nssUTF8_Size((NSSUTF8 *)v.data, (PRStatus *)NULL);
    102            dbrv = db->db->put(db->db, &k, &v, 0);
    103            (void)db->db->sync(db->db, 0);
    104            rv = nss_dbm_db_format_version;
    105        } else {
    106            /* No error return.. */
    107            ;
    108        }
    109 
    110        (void)NSSCKFWMutex_Unlock(db->crustylock);
    111    }
    112 
    113    return rv;
    114 }
    115 
    116 NSS_IMPLEMENT CK_RV
    117 nss_dbm_db_set_label(
    118    nss_dbm_db_t *db,
    119    NSSUTF8 *label)
    120 {
    121    CK_RV rv;
    122    DBT k, v;
    123    int dbrv;
    124 
    125    k.data = PREFIX_METADATA "Label";
    126    k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
    127    v.data = label;
    128    v.size = nssUTF8_Size((NSSUTF8 *)v.data, (PRStatus *)NULL);
    129 
    130    /* Locked region */
    131    {
    132        rv = NSSCKFWMutex_Lock(db->crustylock);
    133        if (CKR_OK != rv) {
    134            return rv;
    135        }
    136 
    137        dbrv = db->db->put(db->db, &k, &v, 0);
    138        if (0 != dbrv) {
    139            rv = CKR_DEVICE_ERROR;
    140        }
    141 
    142        dbrv = db->db->sync(db->db, 0);
    143        if (0 != dbrv) {
    144            rv = CKR_DEVICE_ERROR;
    145        }
    146 
    147        (void)NSSCKFWMutex_Unlock(db->crustylock);
    148    }
    149 
    150    return rv;
    151 }
    152 
    153 NSS_IMPLEMENT NSSUTF8 *
    154 nss_dbm_db_get_label(
    155    nss_dbm_db_t *db,
    156    NSSArena *arena,
    157    CK_RV *pError)
    158 {
    159    NSSUTF8 *rv = (NSSUTF8 *)NULL;
    160    DBT k, v;
    161    int dbrv;
    162 
    163    k.data = PREFIX_METADATA "Label";
    164    k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
    165 
    166    /* Locked region */
    167    {
    168        if (CKR_OK != NSSCKFWMutex_Lock(db->crustylock)) {
    169            return rv;
    170        }
    171 
    172        dbrv = db->db->get(db->db, &k, &v, 0);
    173        if (0 == dbrv) {
    174            rv = nssUTF8_Duplicate((NSSUTF8 *)v.data, arena);
    175            if ((NSSUTF8 *)NULL == rv) {
    176                *pError = CKR_HOST_MEMORY;
    177            }
    178        } else if (dbrv > 0) {
    179            /* Just return null */
    180            ;
    181        } else {
    182            *pError = CKR_DEVICE_ERROR;
    183            ;
    184        }
    185 
    186        (void)NSSCKFWMutex_Unlock(db->crustylock);
    187    }
    188 
    189    return rv;
    190 }
    191 
    192 NSS_IMPLEMENT CK_RV
    193 nss_dbm_db_delete_object(
    194    nss_dbm_dbt_t *dbt)
    195 {
    196    CK_RV rv;
    197    int dbrv;
    198 
    199    /* Locked region */
    200    {
    201        rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
    202        if (CKR_OK != rv) {
    203            return rv;
    204        }
    205 
    206        dbrv = dbt->my_db->db->del(dbt->my_db->db, &dbt->dbt, 0);
    207        if (0 != dbrv) {
    208            rv = CKR_DEVICE_ERROR;
    209            goto done;
    210        }
    211 
    212        dbrv = dbt->my_db->db->sync(dbt->my_db->db, 0);
    213        if (0 != dbrv) {
    214            rv = CKR_DEVICE_ERROR;
    215            goto done;
    216        }
    217 
    218    done:
    219        (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
    220    }
    221 
    222    return rv;
    223 }
    224 
    225 static CK_ULONG
    226 nss_dbm_db_new_handle(
    227    nss_dbm_db_t *db,
    228    DBT *dbt, /* pre-allocated */
    229    CK_RV *pError)
    230 {
    231    CK_ULONG rv;
    232    DBT k, v;
    233    CK_ULONG align = 0, id, myid;
    234    struct handle *hp;
    235 
    236    if (sizeof(struct handle) != dbt->size) {
    237        return EINVAL;
    238    }
    239 
    240    /* Locked region */
    241    {
    242        *pError = NSSCKFWMutex_Lock(db->crustylock);
    243        if (CKR_OK != *pError) {
    244            return EINVAL;
    245        }
    246 
    247        k.data = PREFIX_METADATA "LastID";
    248        k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
    249        (void)memset(&v, 0, sizeof(v));
    250 
    251        rv = db->db->get(db->db, &k, &v, 0);
    252        if (0 == rv) {
    253            (void)memcpy(&align, v.data, sizeof(CK_ULONG));
    254            id = ntohl(align);
    255        } else if (rv > 0) {
    256            id = 0;
    257        } else {
    258            goto done;
    259        }
    260 
    261        myid = id;
    262        id++;
    263        align = htonl(id);
    264        v.data = &align;
    265        v.size = sizeof(CK_ULONG);
    266 
    267        rv = db->db->put(db->db, &k, &v, 0);
    268        if (0 != rv) {
    269            goto done;
    270        }
    271 
    272        rv = db->db->sync(db->db, 0);
    273        if (0 != rv) {
    274            goto done;
    275        }
    276 
    277    done:
    278        (void)NSSCKFWMutex_Unlock(db->crustylock);
    279    }
    280 
    281    if (0 != rv) {
    282        return rv;
    283    }
    284 
    285    hp = (struct handle *)dbt->data;
    286    (void)memcpy(&hp->prefix[0], PREFIX_OBJECT, 4);
    287    hp->id = myid;
    288 
    289    return 0;
    290 }
    291 
    292 /*
    293 * This attribute-type-dependent swapping should probably
    294 * be in the Framework, because it'll be a concern of just
    295 * about every Module.  Of course any Framework implementation
    296 * will have to be augmentable or overridable by a Module.
    297 */
    298 
    299 enum swap_type { type_byte,
    300                 type_short,
    301                 type_long,
    302                 type_opaque };
    303 
    304 static enum swap_type
    305 nss_dbm_db_swap_type(
    306    CK_ATTRIBUTE_TYPE type)
    307 {
    308    switch (type) {
    309        case CKA_CLASS:
    310            return type_long;
    311        case CKA_TOKEN:
    312            return type_byte;
    313        case CKA_PRIVATE:
    314            return type_byte;
    315        case CKA_LABEL:
    316            return type_opaque;
    317        case CKA_APPLICATION:
    318            return type_opaque;
    319        case CKA_VALUE:
    320            return type_opaque;
    321        case CKA_CERTIFICATE_TYPE:
    322            return type_long;
    323        case CKA_ISSUER:
    324            return type_opaque;
    325        case CKA_SERIAL_NUMBER:
    326            return type_opaque;
    327        case CKA_KEY_TYPE:
    328            return type_long;
    329        case CKA_SUBJECT:
    330            return type_opaque;
    331        case CKA_ID:
    332            return type_opaque;
    333        case CKA_SENSITIVE:
    334            return type_byte;
    335        case CKA_ENCRYPT:
    336            return type_byte;
    337        case CKA_DECRYPT:
    338            return type_byte;
    339        case CKA_WRAP:
    340            return type_byte;
    341        case CKA_UNWRAP:
    342            return type_byte;
    343        case CKA_SIGN:
    344            return type_byte;
    345        case CKA_SIGN_RECOVER:
    346            return type_byte;
    347        case CKA_VERIFY:
    348            return type_byte;
    349        case CKA_VERIFY_RECOVER:
    350            return type_byte;
    351        case CKA_DERIVE:
    352            return type_byte;
    353        case CKA_START_DATE:
    354            return type_opaque;
    355        case CKA_END_DATE:
    356            return type_opaque;
    357        case CKA_MODULUS:
    358            return type_opaque;
    359        case CKA_MODULUS_BITS:
    360            return type_long;
    361        case CKA_PUBLIC_EXPONENT:
    362            return type_opaque;
    363        case CKA_PRIVATE_EXPONENT:
    364            return type_opaque;
    365        case CKA_PRIME_1:
    366            return type_opaque;
    367        case CKA_PRIME_2:
    368            return type_opaque;
    369        case CKA_EXPONENT_1:
    370            return type_opaque;
    371        case CKA_EXPONENT_2:
    372            return type_opaque;
    373        case CKA_COEFFICIENT:
    374            return type_opaque;
    375        case CKA_PRIME:
    376            return type_opaque;
    377        case CKA_SUBPRIME:
    378            return type_opaque;
    379        case CKA_BASE:
    380            return type_opaque;
    381        case CKA_VALUE_BITS:
    382            return type_long;
    383        case CKA_VALUE_LEN:
    384            return type_long;
    385        case CKA_EXTRACTABLE:
    386            return type_byte;
    387        case CKA_LOCAL:
    388            return type_byte;
    389        case CKA_NEVER_EXTRACTABLE:
    390            return type_byte;
    391        case CKA_ALWAYS_SENSITIVE:
    392            return type_byte;
    393        case CKA_MODIFIABLE:
    394            return type_byte;
    395        case CKA_NSS_URL:
    396            return type_opaque;
    397        case CKA_NSS_EMAIL:
    398            return type_opaque;
    399        case CKA_NSS_SMIME_INFO:
    400            return type_opaque;
    401        case CKA_NSS_SMIME_TIMESTAMP:
    402            return type_opaque;
    403        case CKA_NSS_PKCS8_SALT:
    404            return type_opaque;
    405        case CKA_NSS_PASSWORD_CHECK:
    406            return type_opaque;
    407        case CKA_NSS_EXPIRES:
    408            return type_opaque;
    409        case CKA_TRUST_DIGITAL_SIGNATURE:
    410            return type_long;
    411        case CKA_TRUST_NON_REPUDIATION:
    412            return type_long;
    413        case CKA_TRUST_KEY_ENCIPHERMENT:
    414            return type_long;
    415        case CKA_TRUST_DATA_ENCIPHERMENT:
    416            return type_long;
    417        case CKA_TRUST_KEY_AGREEMENT:
    418            return type_long;
    419        case CKA_TRUST_KEY_CERT_SIGN:
    420            return type_long;
    421        case CKA_TRUST_CRL_SIGN:
    422            return type_long;
    423        case CKA_TRUST_SERVER_AUTH:
    424            return type_long;
    425        case CKA_TRUST_CLIENT_AUTH:
    426            return type_long;
    427        case CKA_TRUST_CODE_SIGNING:
    428            return type_long;
    429        case CKA_TRUST_EMAIL_PROTECTION:
    430            return type_long;
    431        case CKA_TRUST_IPSEC_END_SYSTEM:
    432            return type_long;
    433        case CKA_TRUST_IPSEC_TUNNEL:
    434            return type_long;
    435        case CKA_TRUST_IPSEC_USER:
    436            return type_long;
    437        case CKA_TRUST_TIME_STAMPING:
    438            return type_long;
    439        case CKA_NSS_DB:
    440            return type_opaque;
    441        case CKA_NSS_TRUST:
    442            return type_opaque;
    443        default:
    444            return type_opaque;
    445    }
    446 }
    447 
    448 static void
    449 nss_dbm_db_swap_copy(
    450    CK_ATTRIBUTE_TYPE type,
    451    void *dest,
    452    void *src,
    453    CK_ULONG len)
    454 {
    455    switch (nss_dbm_db_swap_type(type)) {
    456        case type_byte:
    457        case type_opaque:
    458            (void)memcpy(dest, src, len);
    459            break;
    460        case type_short: {
    461            CK_USHORT s, d;
    462            (void)memcpy(&s, src, sizeof(CK_USHORT));
    463            d = htons(s);
    464            (void)memcpy(dest, &d, sizeof(CK_USHORT));
    465            break;
    466        }
    467        case type_long: {
    468            CK_ULONG s, d;
    469            (void)memcpy(&s, src, sizeof(CK_ULONG));
    470            d = htonl(s);
    471            (void)memcpy(dest, &d, sizeof(CK_ULONG));
    472            break;
    473        }
    474    }
    475 }
    476 
    477 static CK_RV
    478 nss_dbm_db_wrap_object(
    479    NSSArena *arena,
    480    CK_ATTRIBUTE_PTR pTemplate,
    481    CK_ULONG ulAttributeCount,
    482    DBT *object)
    483 {
    484    CK_ULONG object_size;
    485    CK_ULONG i;
    486    CK_ULONG *pulData;
    487    char *pcData;
    488    CK_ULONG offset;
    489 
    490    object_size = (1 + ulAttributeCount * 3) * sizeof(CK_ULONG);
    491    offset = object_size;
    492    for (i = 0; i < ulAttributeCount; i++) {
    493        object_size += pTemplate[i].ulValueLen;
    494    }
    495 
    496    object->size = object_size;
    497    object->data = nss_ZAlloc(arena, object_size);
    498    if ((void *)NULL == object->data) {
    499        return CKR_HOST_MEMORY;
    500    }
    501 
    502    pulData = (CK_ULONG *)object->data;
    503    pcData = (char *)object->data;
    504 
    505    pulData[0] = htonl(ulAttributeCount);
    506    for (i = 0; i < ulAttributeCount; i++) {
    507        CK_ULONG len = pTemplate[i].ulValueLen;
    508        pulData[1 + i * 3] = htonl(pTemplate[i].type);
    509        pulData[2 + i * 3] = htonl(len);
    510        pulData[3 + i * 3] = htonl(offset);
    511        nss_dbm_db_swap_copy(pTemplate[i].type, &pcData[offset], pTemplate[i].pValue, len);
    512        offset += len;
    513    }
    514 
    515    return CKR_OK;
    516 }
    517 
    518 static CK_RV
    519 nss_dbm_db_unwrap_object(
    520    NSSArena *arena,
    521    DBT *object,
    522    CK_ATTRIBUTE_PTR *ppTemplate,
    523    CK_ULONG *pulAttributeCount)
    524 {
    525    CK_ULONG *pulData;
    526    char *pcData;
    527    CK_ULONG n, i;
    528    CK_ATTRIBUTE_PTR pTemplate;
    529 
    530    pulData = (CK_ULONG *)object->data;
    531    pcData = (char *)object->data;
    532 
    533    n = ntohl(pulData[0]);
    534    *pulAttributeCount = n;
    535    pTemplate = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, n);
    536    if ((CK_ATTRIBUTE_PTR)NULL == pTemplate) {
    537        return CKR_HOST_MEMORY;
    538    }
    539 
    540    for (i = 0; i < n; i++) {
    541        CK_ULONG len;
    542        CK_ULONG offset;
    543        void *p;
    544 
    545        pTemplate[i].type = ntohl(pulData[1 + i * 3]);
    546        len = ntohl(pulData[2 + i * 3]);
    547        offset = ntohl(pulData[3 + i * 3]);
    548 
    549        p = nss_ZAlloc(arena, len);
    550        if ((void *)NULL == p) {
    551            return CKR_HOST_MEMORY;
    552        }
    553 
    554        nss_dbm_db_swap_copy(pTemplate[i].type, p, &pcData[offset], len);
    555        pTemplate[i].ulValueLen = len;
    556        pTemplate[i].pValue = p;
    557    }
    558 
    559    *ppTemplate = pTemplate;
    560    return CKR_OK;
    561 }
    562 
    563 NSS_IMPLEMENT nss_dbm_dbt_t *
    564 nss_dbm_db_create_object(
    565    NSSArena *arena,
    566    nss_dbm_db_t *db,
    567    CK_ATTRIBUTE_PTR pTemplate,
    568    CK_ULONG ulAttributeCount,
    569    CK_RV *pError,
    570    CK_ULONG *pdbrv)
    571 {
    572    NSSArena *tmparena = (NSSArena *)NULL;
    573    nss_dbm_dbt_t *rv = (nss_dbm_dbt_t *)NULL;
    574    DBT object;
    575 
    576    rv = nss_ZNEW(arena, nss_dbm_dbt_t);
    577    if ((nss_dbm_dbt_t *)NULL == rv) {
    578        *pError = CKR_HOST_MEMORY;
    579        return (nss_dbm_dbt_t *)NULL;
    580    }
    581 
    582    rv->my_db = db;
    583    rv->dbt.size = sizeof(struct handle);
    584    rv->dbt.data = nss_ZAlloc(arena, rv->dbt.size);
    585    if ((void *)NULL == rv->dbt.data) {
    586        *pError = CKR_HOST_MEMORY;
    587        return (nss_dbm_dbt_t *)NULL;
    588    }
    589 
    590    *pdbrv = nss_dbm_db_new_handle(db, &rv->dbt, pError);
    591    if (0 != *pdbrv) {
    592        return (nss_dbm_dbt_t *)NULL;
    593    }
    594 
    595    tmparena = NSSArena_Create();
    596    if ((NSSArena *)NULL == tmparena) {
    597        *pError = CKR_HOST_MEMORY;
    598        return (nss_dbm_dbt_t *)NULL;
    599    }
    600 
    601    *pError = nss_dbm_db_wrap_object(tmparena, pTemplate, ulAttributeCount, &object);
    602    if (CKR_OK != *pError) {
    603        return (nss_dbm_dbt_t *)NULL;
    604    }
    605 
    606    /* Locked region */
    607    {
    608        *pError = NSSCKFWMutex_Lock(db->crustylock);
    609        if (CKR_OK != *pError) {
    610            goto loser;
    611        }
    612 
    613        *pdbrv = db->db->put(db->db, &rv->dbt, &object, 0);
    614        if (0 != *pdbrv) {
    615            *pError = CKR_DEVICE_ERROR;
    616        }
    617 
    618        (void)db->db->sync(db->db, 0);
    619 
    620        (void)NSSCKFWMutex_Unlock(db->crustylock);
    621    }
    622 
    623 loser:
    624    if ((NSSArena *)NULL != tmparena) {
    625        (void)NSSArena_Destroy(tmparena);
    626    }
    627 
    628    return rv;
    629 }
    630 
    631 NSS_IMPLEMENT CK_RV
    632 nss_dbm_db_find_objects(
    633    nss_dbm_find_t *find,
    634    nss_dbm_db_t *db,
    635    CK_ATTRIBUTE_PTR pTemplate,
    636    CK_ULONG ulAttributeCount,
    637    CK_ULONG *pdbrv)
    638 {
    639    CK_RV rv = CKR_OK;
    640 
    641    if ((nss_dbm_db_t *)NULL != db) {
    642        DBT k, v;
    643 
    644        rv = NSSCKFWMutex_Lock(db->crustylock);
    645        if (CKR_OK != rv) {
    646            return rv;
    647        }
    648 
    649        *pdbrv = db->db->seq(db->db, &k, &v, R_FIRST);
    650        while (0 == *pdbrv) {
    651            CK_ULONG i, j;
    652            NSSArena *tmparena = (NSSArena *)NULL;
    653            CK_ULONG ulac;
    654            CK_ATTRIBUTE_PTR pt;
    655 
    656            if ((k.size < 4) || (0 != memcmp(k.data, PREFIX_OBJECT, 4))) {
    657                goto nomatch;
    658            }
    659 
    660            tmparena = NSSArena_Create();
    661 
    662            rv = nss_dbm_db_unwrap_object(tmparena, &v, &pt, &ulac);
    663            if (CKR_OK != rv) {
    664                goto loser;
    665            }
    666 
    667            for (i = 0; i < ulAttributeCount; i++) {
    668                for (j = 0; j < ulac; j++) {
    669                    if (pTemplate[i].type ==
    670                        pt[j].type) {
    671                        if (pTemplate[i].ulValueLen !=
    672                            pt[j].ulValueLen) {
    673                            goto nomatch;
    674                        }
    675                        if (0 !=
    676                            memcmp(pTemplate[i].pValue, pt[j].pValue, pt[j].ulValueLen)) {
    677                            goto nomatch;
    678                        }
    679                        break;
    680                    }
    681                }
    682                if (j == ulac) {
    683                    goto nomatch;
    684                }
    685            }
    686 
    687            /* entire template matches */
    688            {
    689                struct nss_dbm_dbt_node *node;
    690 
    691                node = nss_ZNEW(find->arena, struct nss_dbm_dbt_node);
    692                if ((struct nss_dbm_dbt_node *)NULL == node) {
    693                    rv =
    694                        CKR_HOST_MEMORY;
    695                    goto loser;
    696                }
    697 
    698                node->dbt = nss_ZNEW(find->arena, nss_dbm_dbt_t);
    699                if ((nss_dbm_dbt_t *)NULL == node->dbt) {
    700                    rv =
    701                        CKR_HOST_MEMORY;
    702                    goto loser;
    703                }
    704 
    705                node->dbt->dbt.size = k.size;
    706                node->dbt->dbt.data = nss_ZAlloc(find->arena, k.size);
    707                if ((void *)NULL == node->dbt->dbt.data) {
    708                    rv =
    709                        CKR_HOST_MEMORY;
    710                    goto loser;
    711                }
    712 
    713                (void)memcpy(node->dbt->dbt.data, k.data, k.size);
    714 
    715                node->dbt->my_db = db;
    716 
    717                node->next = find->found;
    718                find->found = node;
    719            }
    720 
    721        nomatch:
    722            if ((NSSArena *)NULL != tmparena) {
    723                (void)NSSArena_Destroy(tmparena);
    724            }
    725            *pdbrv = db->db->seq(db->db, &k, &v, R_NEXT);
    726        }
    727 
    728        if (*pdbrv < 0) {
    729            rv = CKR_DEVICE_ERROR;
    730            goto loser;
    731        }
    732 
    733        rv = CKR_OK;
    734 
    735    loser:
    736        (void)NSSCKFWMutex_Unlock(db->crustylock);
    737    }
    738 
    739    return rv;
    740 }
    741 
    742 NSS_IMPLEMENT CK_BBOOL
    743 nss_dbm_db_object_still_exists(
    744    nss_dbm_dbt_t *dbt)
    745 {
    746    CK_BBOOL rv;
    747    CK_RV ckrv;
    748    int dbrv;
    749    DBT object;
    750 
    751    ckrv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
    752    if (CKR_OK != ckrv) {
    753        return CK_FALSE;
    754    }
    755 
    756    dbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
    757    if (0 == dbrv) {
    758        rv = CK_TRUE;
    759    } else {
    760        rv = CK_FALSE;
    761    }
    762 
    763    (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
    764 
    765    return rv;
    766 }
    767 
    768 NSS_IMPLEMENT CK_ULONG
    769 nss_dbm_db_get_object_attribute_count(
    770    nss_dbm_dbt_t *dbt,
    771    CK_RV *pError,
    772    CK_ULONG *pdbrv)
    773 {
    774    CK_ULONG rv = 0;
    775    DBT object;
    776    CK_ULONG *pulData;
    777 
    778    /* Locked region */
    779    {
    780        *pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
    781        if (CKR_OK != *pError) {
    782            return rv;
    783        }
    784 
    785        *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
    786        if (0 == *pdbrv) {
    787            ;
    788        } else if (*pdbrv > 0) {
    789            *pError = CKR_OBJECT_HANDLE_INVALID;
    790            goto done;
    791        } else {
    792            *pError = CKR_DEVICE_ERROR;
    793            goto done;
    794        }
    795 
    796        pulData = (CK_ULONG *)object.data;
    797        rv = ntohl(pulData[0]);
    798 
    799    done:
    800        (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
    801    }
    802 
    803    return rv;
    804 }
    805 
    806 NSS_IMPLEMENT CK_RV
    807 nss_dbm_db_get_object_attribute_types(
    808    nss_dbm_dbt_t *dbt,
    809    CK_ATTRIBUTE_TYPE_PTR typeArray,
    810    CK_ULONG ulCount,
    811    CK_ULONG *pdbrv)
    812 {
    813    CK_RV rv = CKR_OK;
    814    DBT object;
    815    CK_ULONG *pulData;
    816    CK_ULONG n, i;
    817 
    818    /* Locked region */
    819    {
    820        rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
    821        if (CKR_OK != rv) {
    822            return rv;
    823        }
    824 
    825        *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
    826        if (0 == *pdbrv) {
    827            ;
    828        } else if (*pdbrv > 0) {
    829            rv = CKR_OBJECT_HANDLE_INVALID;
    830            goto done;
    831        } else {
    832            rv = CKR_DEVICE_ERROR;
    833            goto done;
    834        }
    835 
    836        pulData = (CK_ULONG *)object.data;
    837        n = ntohl(pulData[0]);
    838 
    839        if (ulCount < n) {
    840            rv = CKR_BUFFER_TOO_SMALL;
    841            goto done;
    842        }
    843 
    844        for (i = 0; i < n; i++) {
    845            typeArray[i] = ntohl(pulData[1 + i * 3]);
    846        }
    847 
    848    done:
    849        (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
    850    }
    851 
    852    return rv;
    853 }
    854 
    855 NSS_IMPLEMENT CK_ULONG
    856 nss_dbm_db_get_object_attribute_size(
    857    nss_dbm_dbt_t *dbt,
    858    CK_ATTRIBUTE_TYPE type,
    859    CK_RV *pError,
    860    CK_ULONG *pdbrv)
    861 {
    862    CK_ULONG rv = 0;
    863    DBT object;
    864    CK_ULONG *pulData;
    865    CK_ULONG n, i;
    866 
    867    /* Locked region */
    868    {
    869        *pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
    870        if (CKR_OK != *pError) {
    871            return rv;
    872        }
    873 
    874        *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
    875        if (0 == *pdbrv) {
    876            ;
    877        } else if (*pdbrv > 0) {
    878            *pError = CKR_OBJECT_HANDLE_INVALID;
    879            goto done;
    880        } else {
    881            *pError = CKR_DEVICE_ERROR;
    882            goto done;
    883        }
    884 
    885        pulData = (CK_ULONG *)object.data;
    886        n = ntohl(pulData[0]);
    887 
    888        for (i = 0; i < n; i++) {
    889            if (type == ntohl(pulData[1 + i * 3])) {
    890                rv = ntohl(pulData[2 + i * 3]);
    891            }
    892        }
    893 
    894        if (i == n) {
    895            *pError = CKR_ATTRIBUTE_TYPE_INVALID;
    896            goto done;
    897        }
    898 
    899    done:
    900        (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
    901    }
    902 
    903    return rv;
    904 }
    905 
    906 NSS_IMPLEMENT NSSItem *
    907 nss_dbm_db_get_object_attribute(
    908    nss_dbm_dbt_t *dbt,
    909    NSSArena *arena,
    910    CK_ATTRIBUTE_TYPE type,
    911    CK_RV *pError,
    912    CK_ULONG *pdbrv)
    913 {
    914    NSSItem *rv = (NSSItem *)NULL;
    915    DBT object;
    916    CK_ULONG i;
    917    NSSArena *tmp = NSSArena_Create();
    918    CK_ATTRIBUTE_PTR pTemplate;
    919    CK_ULONG ulAttributeCount;
    920 
    921    /* Locked region */
    922    {
    923        *pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
    924        if (CKR_OK != *pError) {
    925            goto loser;
    926        }
    927 
    928        *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
    929        if (0 == *pdbrv) {
    930            ;
    931        } else if (*pdbrv > 0) {
    932            *pError = CKR_OBJECT_HANDLE_INVALID;
    933            goto done;
    934        } else {
    935            *pError = CKR_DEVICE_ERROR;
    936            goto done;
    937        }
    938 
    939        *pError = nss_dbm_db_unwrap_object(tmp, &object, &pTemplate, &ulAttributeCount);
    940        if (CKR_OK != *pError) {
    941            goto done;
    942        }
    943 
    944        for (i = 0; i < ulAttributeCount; i++) {
    945            if (type == pTemplate[i].type) {
    946                rv = nss_ZNEW(arena, NSSItem);
    947                if ((NSSItem *)NULL == rv) {
    948                    *pError =
    949                        CKR_HOST_MEMORY;
    950                    goto done;
    951                }
    952                rv->size = pTemplate[i].ulValueLen;
    953                rv->data = nss_ZAlloc(arena, rv->size);
    954                if ((void *)NULL == rv->data) {
    955                    *pError =
    956                        CKR_HOST_MEMORY;
    957                    goto done;
    958                }
    959                (void)memcpy(rv->data, pTemplate[i].pValue, rv->size);
    960                break;
    961            }
    962        }
    963        if (ulAttributeCount == i) {
    964            *pError = CKR_ATTRIBUTE_TYPE_INVALID;
    965            goto done;
    966        }
    967 
    968    done:
    969        (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
    970    }
    971 
    972 loser:
    973    if ((NSSArena *)NULL != tmp) {
    974        NSSArena_Destroy(tmp);
    975    }
    976 
    977    return rv;
    978 }
    979 
    980 NSS_IMPLEMENT CK_RV
    981 nss_dbm_db_set_object_attribute(
    982    nss_dbm_dbt_t *dbt,
    983    CK_ATTRIBUTE_TYPE type,
    984    NSSItem *value,
    985    CK_ULONG *pdbrv)
    986 {
    987    CK_RV rv = CKR_OK;
    988    DBT object;
    989    CK_ULONG i;
    990    NSSArena *tmp = NSSArena_Create();
    991    CK_ATTRIBUTE_PTR pTemplate;
    992    CK_ULONG ulAttributeCount;
    993 
    994    /* Locked region */
    995    {
    996        rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
    997        if (CKR_OK != rv) {
    998            goto loser;
    999        }
   1000 
   1001        *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
   1002        if (0 == *pdbrv) {
   1003            ;
   1004        } else if (*pdbrv > 0) {
   1005            rv = CKR_OBJECT_HANDLE_INVALID;
   1006            goto done;
   1007        } else {
   1008            rv = CKR_DEVICE_ERROR;
   1009            goto done;
   1010        }
   1011 
   1012        rv = nss_dbm_db_unwrap_object(tmp, &object, &pTemplate, &ulAttributeCount);
   1013        if (CKR_OK != rv) {
   1014            goto done;
   1015        }
   1016 
   1017        for (i = 0; i < ulAttributeCount; i++) {
   1018            if (type == pTemplate[i].type) {
   1019                /* Replacing an existing attribute */
   1020                pTemplate[i].ulValueLen = value->size;
   1021                pTemplate[i].pValue = value->data;
   1022                break;
   1023            }
   1024        }
   1025 
   1026        if (i == ulAttributeCount) {
   1027            /* Adding a new attribute */
   1028            CK_ATTRIBUTE_PTR npt = nss_ZNEWARRAY(tmp, CK_ATTRIBUTE, ulAttributeCount + 1);
   1029            if ((CK_ATTRIBUTE_PTR)NULL == npt) {
   1030                rv = CKR_DEVICE_ERROR;
   1031                goto done;
   1032            }
   1033 
   1034            for (i = 0; i < ulAttributeCount; i++) {
   1035                npt[i] = pTemplate[i];
   1036            }
   1037 
   1038            npt[ulAttributeCount].type = type;
   1039            npt[ulAttributeCount].ulValueLen = value->size;
   1040            npt[ulAttributeCount].pValue = value->data;
   1041 
   1042            pTemplate = npt;
   1043            ulAttributeCount++;
   1044        }
   1045 
   1046        rv = nss_dbm_db_wrap_object(tmp, pTemplate, ulAttributeCount, &object);
   1047        if (CKR_OK != rv) {
   1048            goto done;
   1049        }
   1050 
   1051        *pdbrv = dbt->my_db->db->put(dbt->my_db->db, &dbt->dbt, &object, 0);
   1052        if (0 != *pdbrv) {
   1053            rv = CKR_DEVICE_ERROR;
   1054            goto done;
   1055        }
   1056 
   1057        (void)dbt->my_db->db->sync(dbt->my_db->db, 0);
   1058 
   1059    done:
   1060        (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
   1061    }
   1062 
   1063 loser:
   1064    if ((NSSArena *)NULL != tmp) {
   1065        NSSArena_Destroy(tmp);
   1066    }
   1067 
   1068    return rv;
   1069 }