PageRenderTime 85ms CodeModel.GetById 2ms app.highlight 76ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/ckfw/dbm/db.c

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