Back to index

lightning-sunbird  0.9+nobinonly
db.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: db.c,v $ $Revision: 1.5.28.1 $ $Date: 2006/03/02 22:45:13 $";
00039 #endif /* DEBUG */
00040 
00041 #include "ckdbm.h"
00042 
00043 #define PREFIX_METADATA "0000"
00044 #define PREFIX_OBJECT   "0001"
00045 #define PREFIX_INDEX    "0002"
00046 
00047 static CK_VERSION nss_dbm_db_format_version = { 1, 0 };
00048 struct handle {
00049   char prefix[4];
00050   CK_ULONG id;
00051 };
00052 
00053 NSS_IMPLEMENT nss_dbm_db_t *
00054 nss_dbm_db_open
00055 (
00056   NSSArena *arena,
00057   NSSCKFWInstance *fwInstance,
00058   char *filename,
00059   int flags,
00060   CK_RV *pError
00061 )
00062 {
00063   nss_dbm_db_t *rv;
00064   CK_VERSION db_version;
00065 
00066   rv = nss_ZNEW(arena, nss_dbm_db_t);
00067   if( (nss_dbm_db_t *)NULL == rv ) {
00068     *pError = CKR_HOST_MEMORY;
00069     return (nss_dbm_db_t *)NULL;
00070   }
00071 
00072   rv->db = dbopen(filename, flags, 0600, DB_HASH, (const void *)NULL);
00073   if( (DB *)NULL == rv->db ) {
00074     *pError = CKR_TOKEN_NOT_PRESENT;
00075     return (nss_dbm_db_t *)NULL;
00076   }
00077 
00078   rv->crustylock = NSSCKFWInstance_CreateMutex(fwInstance, arena, pError);
00079   if( (NSSCKFWMutex *)NULL == rv->crustylock ) {
00080     return (nss_dbm_db_t *)NULL;
00081   }
00082 
00083   db_version = nss_dbm_db_get_format_version(rv);
00084   if( db_version.major != nss_dbm_db_format_version.major ) {
00085     nss_dbm_db_close(rv);
00086     *pError = CKR_TOKEN_NOT_RECOGNIZED;
00087     return (nss_dbm_db_t *)NULL;
00088   }
00089 
00090   return rv;
00091 }
00092 
00093 NSS_IMPLEMENT void
00094 nss_dbm_db_close
00095 (
00096   nss_dbm_db_t *db
00097 )
00098 {
00099   if( (NSSCKFWMutex *)NULL != db->crustylock ) {
00100     (void)NSSCKFWMutex_Destroy(db->crustylock);
00101   }
00102 
00103   if( (DB *)NULL != db->db ) {
00104     (void)db->db->close(db->db);
00105   }
00106 
00107   nss_ZFreeIf(db);
00108 }
00109 
00110 NSS_IMPLEMENT CK_VERSION
00111 nss_dbm_db_get_format_version
00112 (
00113   nss_dbm_db_t *db
00114 )
00115 {
00116   CK_VERSION rv;
00117   DBT k, v;
00118   int dbrv;
00119   char buffer[64];
00120 
00121   rv.major = rv.minor = 0;
00122 
00123   k.data = PREFIX_METADATA "FormatVersion";
00124   k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
00125   (void)memset(&v, 0, sizeof(v));
00126 
00127   /* Locked region */ 
00128   {
00129     if( CKR_OK != NSSCKFWMutex_Lock(db->crustylock) ) {
00130       return rv;
00131     }
00132 
00133     dbrv = db->db->get(db->db, &k, &v, 0);
00134     if( dbrv == 0 ) {
00135       CK_ULONG major = 0, minor = 0;
00136       (void)PR_sscanf(v.data, "%ld.%ld", &major, &minor);
00137       rv.major = major;
00138       rv.minor = minor;
00139     } else if( dbrv > 0 ) {
00140       (void)PR_snprintf(buffer, sizeof(buffer), "%ld.%ld", nss_dbm_db_format_version.major,
00141                         nss_dbm_db_format_version.minor);
00142       v.data = buffer;
00143       v.size = nssUTF8_Size((NSSUTF8 *)v.data, (PRStatus *)NULL);
00144       dbrv = db->db->put(db->db, &k, &v, 0);
00145       (void)db->db->sync(db->db, 0);
00146       rv = nss_dbm_db_format_version;
00147     } else {
00148       /* No error return.. */
00149       ;
00150     }
00151 
00152     (void)NSSCKFWMutex_Unlock(db->crustylock);
00153   }
00154 
00155   return rv;
00156 }
00157 
00158 NSS_IMPLEMENT CK_RV
00159 nss_dbm_db_set_label
00160 (
00161   nss_dbm_db_t *db,
00162   NSSUTF8 *label
00163 )
00164 {
00165   CK_RV rv;
00166   DBT k, v;
00167   int dbrv;
00168 
00169   k.data = PREFIX_METADATA "Label";
00170   k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
00171   v.data = label;
00172   v.size = nssUTF8_Size((NSSUTF8 *)v.data, (PRStatus *)NULL);
00173 
00174   /* Locked region */ 
00175   {
00176     if( CKR_OK != NSSCKFWMutex_Lock(db->crustylock) ) {
00177       return rv;
00178     }
00179 
00180     dbrv = db->db->put(db->db, &k, &v, 0);
00181     if( 0 != dbrv ) {
00182       rv = CKR_DEVICE_ERROR;
00183     }
00184 
00185     dbrv = db->db->sync(db->db, 0);
00186     if( 0 != dbrv ) {
00187       rv = CKR_DEVICE_ERROR;
00188     }
00189 
00190     (void)NSSCKFWMutex_Unlock(db->crustylock);
00191   }
00192 
00193   return rv;
00194 }
00195 
00196 NSS_IMPLEMENT NSSUTF8 *
00197 nss_dbm_db_get_label
00198 (
00199   nss_dbm_db_t *db,
00200   NSSArena *arena,
00201   CK_RV *pError
00202 )
00203 {
00204   NSSUTF8 *rv = (NSSUTF8 *)NULL;
00205   DBT k, v;
00206   int dbrv;
00207 
00208   k.data = PREFIX_METADATA "Label";
00209   k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
00210 
00211   /* Locked region */ 
00212   {
00213     if( CKR_OK != NSSCKFWMutex_Lock(db->crustylock) ) {
00214       return rv;
00215     }
00216 
00217     dbrv = db->db->get(db->db, &k, &v, 0);
00218     if( 0 == dbrv ) {
00219       rv = nssUTF8_Duplicate((NSSUTF8 *)v.data, arena);
00220       if( (NSSUTF8 *)NULL == rv ) {
00221         *pError = CKR_HOST_MEMORY;
00222       }
00223     } else if( dbrv > 0 ) {
00224       /* Just return null */
00225       ;
00226     } else {
00227       *pError = CKR_DEVICE_ERROR;
00228       ;
00229     }
00230 
00231 
00232     (void)NSSCKFWMutex_Unlock(db->crustylock);
00233   }
00234 
00235   return rv;
00236 }
00237 
00238 NSS_IMPLEMENT CK_RV
00239 nss_dbm_db_delete_object
00240 (
00241   nss_dbm_dbt_t *dbt
00242 )
00243 {
00244   CK_RV rv;
00245   int dbrv;
00246 
00247   /* Locked region */
00248   {
00249     rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
00250     if( CKR_OK != rv ) {
00251       return rv;
00252     }
00253 
00254     dbrv = dbt->my_db->db->del(dbt->my_db->db, &dbt->dbt, 0);
00255     if( 0 != dbrv ) {
00256       rv = CKR_DEVICE_ERROR;
00257       goto done;
00258     }
00259 
00260     dbrv = dbt->my_db->db->sync(dbt->my_db->db, 0);
00261     if( 0 != dbrv ) {
00262       rv = CKR_DEVICE_ERROR;
00263       goto done;
00264     }
00265 
00266   done:
00267     (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
00268   }
00269 
00270   return rv;
00271 }
00272 
00273 static CK_ULONG
00274 nss_dbm_db_new_handle
00275 (
00276   nss_dbm_db_t *db,
00277   DBT *dbt, /* pre-allocated */
00278   CK_RV *pError
00279 )
00280 {
00281   CK_ULONG rv;
00282   DBT k, v;
00283   CK_ULONG align = 0, id, myid;
00284   struct handle *hp;
00285 
00286   if( sizeof(struct handle) != dbt->size ) {
00287     return EINVAL;
00288   }
00289 
00290   /* Locked region */
00291   {
00292     *pError = NSSCKFWMutex_Lock(db->crustylock);
00293     if( CKR_OK != *pError ) {
00294       return EINVAL;
00295     }
00296 
00297     k.data = PREFIX_METADATA "LastID";
00298     k.size = nssUTF8_Size((NSSUTF8 *)k.data, (PRStatus *)NULL);
00299     (void)memset(&v, 0, sizeof(v));
00300 
00301     rv = db->db->get(db->db, &k, &v, 0);
00302     if( 0 == rv ) {
00303       (void)memcpy(&align, v.data, sizeof(CK_ULONG));
00304       id = ntohl(align);
00305     } else if( rv > 0 ) {
00306       id = 0;
00307     } else {
00308       goto done;
00309     }
00310 
00311     myid = id;
00312     id++;
00313     align = htonl(id);
00314     v.data = &align;
00315     v.size = sizeof(CK_ULONG);
00316 
00317     rv = db->db->put(db->db, &k, &v, 0);
00318     if( 0 != rv ) {
00319       goto done;
00320     }
00321 
00322     rv = db->db->sync(db->db, 0);
00323     if( 0 != rv ) {
00324       goto done;
00325     }
00326 
00327   done:
00328     (void)NSSCKFWMutex_Unlock(db->crustylock);
00329   }
00330 
00331   if( 0 != rv ) {
00332     return rv;
00333   }
00334 
00335   hp = (struct handle *)dbt->data;
00336   (void)memcpy(&hp->prefix[0], PREFIX_OBJECT, 4);
00337   hp->id = myid;
00338 
00339   return 0;
00340 }
00341 
00342 /*
00343  * This attribute-type-dependent swapping should probably
00344  * be in the Framework, because it'll be a concern of just
00345  * about every Module.  Of course any Framework implementation
00346  * will have to be augmentable or overridable by a Module.
00347  */
00348 
00349 enum swap_type { type_byte, type_short, type_long, type_opaque };
00350 
00351 static enum swap_type
00352 nss_dbm_db_swap_type
00353 (
00354   CK_ATTRIBUTE_TYPE type
00355 )
00356 {
00357   switch( type ) {
00358   case CKA_CLASS: return type_long;
00359   case CKA_TOKEN: return type_byte;
00360   case CKA_PRIVATE: return type_byte;
00361   case CKA_LABEL: return type_opaque;
00362   case CKA_APPLICATION: return type_opaque;
00363   case CKA_VALUE: return type_opaque;
00364   case CKA_CERTIFICATE_TYPE: return type_long;
00365   case CKA_ISSUER: return type_opaque;
00366   case CKA_SERIAL_NUMBER: return type_opaque;
00367   case CKA_KEY_TYPE: return type_long;
00368   case CKA_SUBJECT: return type_opaque;
00369   case CKA_ID: return type_opaque;
00370   case CKA_SENSITIVE: return type_byte;
00371   case CKA_ENCRYPT: return type_byte;
00372   case CKA_DECRYPT: return type_byte;
00373   case CKA_WRAP: return type_byte;
00374   case CKA_UNWRAP: return type_byte;
00375   case CKA_SIGN: return type_byte;
00376   case CKA_SIGN_RECOVER: return type_byte;
00377   case CKA_VERIFY: return type_byte;
00378   case CKA_VERIFY_RECOVER: return type_byte;
00379   case CKA_DERIVE: return type_byte;
00380   case CKA_START_DATE: return type_opaque;
00381   case CKA_END_DATE: return type_opaque;
00382   case CKA_MODULUS: return type_opaque;
00383   case CKA_MODULUS_BITS: return type_long;
00384   case CKA_PUBLIC_EXPONENT: return type_opaque;
00385   case CKA_PRIVATE_EXPONENT: return type_opaque;
00386   case CKA_PRIME_1: return type_opaque;
00387   case CKA_PRIME_2: return type_opaque;
00388   case CKA_EXPONENT_1: return type_opaque;
00389   case CKA_EXPONENT_2: return type_opaque;
00390   case CKA_COEFFICIENT: return type_opaque;
00391   case CKA_PRIME: return type_opaque;
00392   case CKA_SUBPRIME: return type_opaque;
00393   case CKA_BASE: return type_opaque;
00394   case CKA_VALUE_BITS: return type_long;
00395   case CKA_VALUE_LEN: return type_long;
00396   case CKA_EXTRACTABLE: return type_byte;
00397   case CKA_LOCAL: return type_byte;
00398   case CKA_NEVER_EXTRACTABLE: return type_byte;
00399   case CKA_ALWAYS_SENSITIVE: return type_byte;
00400   case CKA_MODIFIABLE: return type_byte;
00401   case CKA_NETSCAPE_URL: return type_opaque;
00402   case CKA_NETSCAPE_EMAIL: return type_opaque;
00403   case CKA_NETSCAPE_SMIME_INFO: return type_opaque;
00404   case CKA_NETSCAPE_SMIME_TIMESTAMP: return type_opaque;
00405   case CKA_NETSCAPE_PKCS8_SALT: return type_opaque;
00406   case CKA_NETSCAPE_PASSWORD_CHECK: return type_opaque;
00407   case CKA_NETSCAPE_EXPIRES: return type_opaque;
00408   case CKA_TRUST_DIGITAL_SIGNATURE: return type_long;
00409   case CKA_TRUST_NON_REPUDIATION: return type_long;
00410   case CKA_TRUST_KEY_ENCIPHERMENT: return type_long;
00411   case CKA_TRUST_DATA_ENCIPHERMENT: return type_long;
00412   case CKA_TRUST_KEY_AGREEMENT: return type_long;
00413   case CKA_TRUST_KEY_CERT_SIGN: return type_long;
00414   case CKA_TRUST_CRL_SIGN: return type_long;
00415   case CKA_TRUST_SERVER_AUTH: return type_long;
00416   case CKA_TRUST_CLIENT_AUTH: return type_long;
00417   case CKA_TRUST_CODE_SIGNING: return type_long;
00418   case CKA_TRUST_EMAIL_PROTECTION: return type_long;
00419   case CKA_TRUST_IPSEC_END_SYSTEM: return type_long;
00420   case CKA_TRUST_IPSEC_TUNNEL: return type_long;
00421   case CKA_TRUST_IPSEC_USER: return type_long;
00422   case CKA_TRUST_TIME_STAMPING: return type_long;
00423   case CKA_NETSCAPE_DB: return type_opaque;
00424   case CKA_NETSCAPE_TRUST: return type_opaque;
00425   default: return type_opaque;
00426   }
00427 }
00428 
00429 static void
00430 nss_dbm_db_swap_copy
00431 (
00432   CK_ATTRIBUTE_TYPE type,
00433   void *dest,
00434   void *src,
00435   CK_ULONG len
00436 )
00437 {
00438   switch( nss_dbm_db_swap_type(type) ) {
00439   case type_byte:
00440   case type_opaque:
00441     (void)memcpy(dest, src, len);
00442     break;
00443   case type_short:
00444     {
00445       CK_USHORT s, d;
00446       (void)memcpy(&s, src, sizeof(CK_USHORT));
00447       d = htons(s);
00448       (void)memcpy(dest, &d, sizeof(CK_USHORT));
00449       break;
00450     }
00451   case type_long:
00452     {
00453       CK_ULONG s, d;
00454       (void)memcpy(&s, src, sizeof(CK_ULONG));
00455       d = htonl(s);
00456       (void)memcpy(dest, &d, sizeof(CK_ULONG));
00457       break;
00458     }
00459   }
00460 }
00461 
00462 static CK_RV
00463 nss_dbm_db_wrap_object
00464 (
00465   NSSArena *arena,
00466   CK_ATTRIBUTE_PTR pTemplate,
00467   CK_ULONG ulAttributeCount,
00468   DBT *object
00469 )
00470 {
00471   CK_ULONG object_size;
00472   CK_ULONG i;
00473   CK_ULONG *pulData;
00474   char *pcData;
00475   CK_ULONG offset;
00476 
00477   object_size = (1 + ulAttributeCount*3) * sizeof(CK_ULONG);
00478   offset = object_size;
00479   for( i = 0; i < ulAttributeCount; i++ ) {
00480     object_size += pTemplate[i].ulValueLen;
00481   }
00482 
00483   object->size = object_size;
00484   object->data = nss_ZAlloc(arena, object_size);
00485   if( (void *)NULL == object->data ) {
00486     return CKR_HOST_MEMORY;
00487   }
00488 
00489   pulData = (CK_ULONG *)object->data;
00490   pcData = (char *)object->data;
00491 
00492   pulData[0] = htonl(ulAttributeCount);
00493   for( i = 0; i < ulAttributeCount; i++ ) {
00494     CK_ULONG len = pTemplate[i].ulValueLen;
00495     pulData[1 + i*3] = htonl(pTemplate[i].type);
00496     pulData[2 + i*3] = htonl(len);
00497     pulData[3 + i*3] = htonl(offset);
00498     nss_dbm_db_swap_copy(pTemplate[i].type, &pcData[offset], pTemplate[i].pValue, len);
00499     offset += len;
00500   }
00501 
00502   return CKR_OK;
00503 }
00504 
00505 static CK_RV
00506 nss_dbm_db_unwrap_object
00507 (
00508   NSSArena *arena,
00509   DBT *object,
00510   CK_ATTRIBUTE_PTR *ppTemplate,
00511   CK_ULONG *pulAttributeCount
00512 )
00513 {
00514   CK_ULONG *pulData;
00515   char *pcData;
00516   CK_ULONG n, i;
00517   CK_ATTRIBUTE_PTR pTemplate;
00518 
00519   pulData = (CK_ULONG *)object->data;
00520   pcData = (char *)object->data;
00521 
00522   n = ntohl(pulData[0]);
00523   *pulAttributeCount = n;
00524   pTemplate = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, n);
00525   if( (CK_ATTRIBUTE_PTR)NULL == pTemplate ) {
00526     return CKR_HOST_MEMORY;
00527   }
00528 
00529   for( i = 0; i < n; i++ ) {
00530     CK_ULONG len;
00531     CK_ULONG offset;
00532     void *p;
00533 
00534     pTemplate[i].type = ntohl(pulData[1 + i*3]);
00535     len = ntohl(pulData[2 + i*3]);
00536     offset = ntohl(pulData[3 +  i*3]);
00537     
00538     p = nss_ZAlloc(arena, len);
00539     if( (void *)NULL == p ) {
00540       return CKR_HOST_MEMORY;
00541     }
00542     
00543     nss_dbm_db_swap_copy(pTemplate[i].type, p, &pcData[offset], len);
00544     pTemplate[i].ulValueLen = len;
00545     pTemplate[i].pValue = p;
00546   }
00547 
00548   *ppTemplate = pTemplate;
00549   return CKR_OK;
00550 }
00551 
00552 
00553 NSS_IMPLEMENT nss_dbm_dbt_t *
00554 nss_dbm_db_create_object
00555 (
00556   NSSArena *arena,
00557   nss_dbm_db_t *db,
00558   CK_ATTRIBUTE_PTR pTemplate,
00559   CK_ULONG ulAttributeCount,
00560   CK_RV *pError,
00561   CK_ULONG *pdbrv
00562 )
00563 {
00564   NSSArena *tmparena = (NSSArena *)NULL;
00565   nss_dbm_dbt_t *rv = (nss_dbm_dbt_t *)NULL;
00566   DBT object;
00567 
00568   rv = nss_ZNEW(arena, nss_dbm_dbt_t);
00569   if( (nss_dbm_dbt_t *)NULL == rv ) {
00570     *pError = CKR_HOST_MEMORY;
00571     return (nss_dbm_dbt_t *)NULL;
00572   }
00573 
00574   rv->my_db = db;
00575   rv->dbt.size = sizeof(struct handle);
00576   rv->dbt.data = nss_ZAlloc(arena, rv->dbt.size);
00577   if( (void *)NULL == rv->dbt.data ) {
00578     *pError = CKR_HOST_MEMORY;
00579     return (nss_dbm_dbt_t *)NULL;
00580   }
00581 
00582   *pdbrv = nss_dbm_db_new_handle(db, &rv->dbt, pError);
00583   if( 0 != *pdbrv ) {
00584     return (nss_dbm_dbt_t *)NULL;
00585   }
00586 
00587   tmparena = NSSArena_Create();
00588   if( (NSSArena *)NULL == tmparena ) {
00589     *pError = CKR_HOST_MEMORY;
00590     return (nss_dbm_dbt_t *)NULL;
00591   }
00592 
00593   *pError = nss_dbm_db_wrap_object(tmparena, pTemplate, ulAttributeCount, &object);
00594   if( CKR_OK != *pError ) {
00595     return (nss_dbm_dbt_t *)NULL;
00596   }
00597   
00598   /* Locked region */
00599   {
00600     *pError = NSSCKFWMutex_Lock(db->crustylock);
00601     if( CKR_OK != *pError ) {
00602       goto loser;
00603     }
00604 
00605     *pdbrv = db->db->put(db->db, &rv->dbt, &object, 0);
00606     if( 0 != *pdbrv ) {
00607       *pError = CKR_DEVICE_ERROR;
00608     }
00609 
00610     (void)db->db->sync(db->db, 0);
00611 
00612     (void)NSSCKFWMutex_Unlock(db->crustylock);
00613   }
00614 
00615  loser:  
00616   if( (NSSArena *)NULL != tmparena ) {
00617     (void)NSSArena_Destroy(tmparena);
00618   }
00619 
00620   return rv;
00621 }
00622 
00623 
00624 NSS_IMPLEMENT CK_RV
00625 nss_dbm_db_find_objects
00626 (
00627   nss_dbm_find_t *find,
00628   nss_dbm_db_t *db,
00629   CK_ATTRIBUTE_PTR pTemplate,
00630   CK_ULONG ulAttributeCount,
00631   CK_ULONG *pdbrv
00632 )
00633 {
00634   CK_RV rv = CKR_OK;
00635 
00636   if( (nss_dbm_db_t *)NULL != db ) {
00637     DBT k, v;
00638 
00639     rv = NSSCKFWMutex_Lock(db->crustylock);
00640     if( CKR_OK != rv ) {
00641       return rv;
00642     }
00643 
00644     *pdbrv = db->db->seq(db->db, &k, &v, R_FIRST);
00645     while( 0 == *pdbrv ) {
00646       CK_ULONG i, j;
00647       NSSArena *tmparena = (NSSArena *)NULL;
00648       CK_ULONG ulac;
00649       CK_ATTRIBUTE_PTR pt;
00650 
00651       if( (k.size < 4) || (0 != memcmp(k.data, PREFIX_OBJECT, 4)) ) {
00652         goto nomatch;
00653       }
00654 
00655       tmparena = NSSArena_Create();
00656 
00657       rv = nss_dbm_db_unwrap_object(tmparena, &v, &pt, &ulac);
00658       if( CKR_OK != rv ) {
00659         goto loser;
00660       }
00661 
00662       for( i = 0; i < ulAttributeCount; i++ ) {
00663         for( j = 0; j < ulac; j++ ) {
00664           if( pTemplate[i].type == pt[j].type ) {
00665             if( pTemplate[i].ulValueLen != pt[j].ulValueLen ) {
00666               goto nomatch;
00667             }
00668             if( 0 != memcmp(pTemplate[i].pValue, pt[j].pValue, pt[j].ulValueLen) ) {
00669               goto nomatch;
00670             }
00671             break;
00672           }
00673         }
00674         if( j == ulac ) {
00675           goto nomatch;
00676         }
00677       }
00678 
00679       /* entire template matches */
00680       {
00681         struct nss_dbm_dbt_node *node;
00682 
00683         node = nss_ZNEW(find->arena, struct nss_dbm_dbt_node);
00684         if( (struct nss_dbm_dbt_node *)NULL == node ) {
00685           rv = CKR_HOST_MEMORY;
00686           goto loser;
00687         }
00688 
00689         node->dbt = nss_ZNEW(find->arena, nss_dbm_dbt_t);
00690         if( (nss_dbm_dbt_t *)NULL == node->dbt ) {
00691           rv = CKR_HOST_MEMORY;
00692           goto loser;
00693         }
00694         
00695         node->dbt->dbt.size = k.size;
00696         node->dbt->dbt.data = nss_ZAlloc(find->arena, k.size);
00697         if( (void *)NULL == node->dbt->dbt.data ) {
00698           rv = CKR_HOST_MEMORY;
00699           goto loser;
00700         }
00701 
00702         (void)memcpy(node->dbt->dbt.data, k.data, k.size);
00703 
00704         node->dbt->my_db = db;
00705 
00706         node->next = find->found;
00707         find->found = node;
00708       }
00709 
00710     nomatch:
00711       if( (NSSArena *)NULL != tmparena ) {
00712         (void)NSSArena_Destroy(tmparena);
00713       }
00714       *pdbrv = db->db->seq(db->db, &k, &v, R_NEXT);
00715     }
00716 
00717     if( *pdbrv < 0 ) {
00718       rv = CKR_DEVICE_ERROR;
00719       goto loser;
00720     }
00721 
00722     rv = CKR_OK;
00723 
00724   loser:
00725     (void)NSSCKFWMutex_Unlock(db->crustylock);
00726   }
00727 
00728   return rv;
00729 }
00730 
00731 NSS_IMPLEMENT CK_BBOOL
00732 nss_dbm_db_object_still_exists
00733 (
00734   nss_dbm_dbt_t *dbt
00735 )
00736 {
00737   CK_BBOOL rv;
00738   CK_RV ckrv;
00739   int dbrv;
00740   DBT object;
00741 
00742   ckrv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
00743   if( CKR_OK != ckrv ) {
00744     return CK_FALSE;
00745   }
00746 
00747   dbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
00748   if( 0 == dbrv ) {
00749     rv = CK_TRUE;
00750   } else {
00751     rv = CK_FALSE;
00752   }
00753 
00754   (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
00755 
00756   return rv;
00757 }
00758 
00759 NSS_IMPLEMENT CK_ULONG
00760 nss_dbm_db_get_object_attribute_count
00761 (
00762   nss_dbm_dbt_t *dbt,
00763   CK_RV *pError,
00764   CK_ULONG *pdbrv
00765 )
00766 {
00767   CK_ULONG rv = 0;
00768   DBT object;
00769   CK_ULONG *pulData;
00770 
00771   /* Locked region */
00772   {
00773     *pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
00774     if( CKR_OK != *pError ) {
00775       return rv;
00776     }
00777 
00778     *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
00779     if( 0 == *pdbrv ) {
00780       ;
00781     } else if( *pdbrv > 0 ) {
00782       *pError = CKR_OBJECT_HANDLE_INVALID;
00783       goto done;
00784     } else {
00785       *pError = CKR_DEVICE_ERROR;
00786       goto done;
00787     }
00788 
00789     pulData = (CK_ULONG *)object.data;
00790     rv = ntohl(pulData[0]);
00791 
00792   done:
00793     (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
00794   }
00795 
00796   return rv;
00797 }
00798 
00799 NSS_IMPLEMENT CK_RV
00800 nss_dbm_db_get_object_attribute_types
00801 (
00802   nss_dbm_dbt_t *dbt,
00803   CK_ATTRIBUTE_TYPE_PTR typeArray,
00804   CK_ULONG ulCount,
00805   CK_ULONG *pdbrv
00806 )
00807 {
00808   CK_RV rv = CKR_OK;
00809   DBT object;
00810   CK_ULONG *pulData;
00811   CK_ULONG n, i;
00812 
00813   /* Locked region */
00814   {
00815     rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
00816     if( CKR_OK != rv ) {
00817       return rv;
00818     }
00819 
00820     *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
00821     if( 0 == *pdbrv ) {
00822       ;
00823     } else if( *pdbrv > 0 ) {
00824       rv = CKR_OBJECT_HANDLE_INVALID;
00825       goto done;
00826     } else {
00827       rv = CKR_DEVICE_ERROR;
00828       goto done;
00829     }
00830 
00831     pulData = (CK_ULONG *)object.data;
00832     n = ntohl(pulData[0]);
00833 
00834     if( ulCount < n ) {
00835       rv = CKR_BUFFER_TOO_SMALL;
00836       goto done;
00837     }
00838 
00839     for( i = 0; i < n; i++ ) {
00840       typeArray[i] = ntohl(pulData[1 + i*3]);
00841     }
00842 
00843   done:
00844     (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
00845   }
00846 
00847   return rv;
00848 }
00849 
00850 NSS_IMPLEMENT CK_ULONG
00851 nss_dbm_db_get_object_attribute_size
00852 (
00853   nss_dbm_dbt_t *dbt,
00854   CK_ATTRIBUTE_TYPE type,
00855   CK_RV *pError,
00856   CK_ULONG *pdbrv
00857 )
00858 {
00859   CK_ULONG rv = 0;
00860   DBT object;
00861   CK_ULONG *pulData;
00862   CK_ULONG n, i;
00863 
00864   /* Locked region */
00865   {
00866     *pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
00867     if( CKR_OK != *pError ) {
00868       return rv;
00869     }
00870 
00871     *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
00872     if( 0 == *pdbrv ) {
00873       ;
00874     } else if( *pdbrv > 0 ) {
00875       *pError = CKR_OBJECT_HANDLE_INVALID;
00876       goto done;
00877     } else {
00878       *pError = CKR_DEVICE_ERROR;
00879       goto done;
00880     }
00881 
00882     pulData = (CK_ULONG *)object.data;
00883     n = ntohl(pulData[0]);
00884 
00885     for( i = 0; i < n; i++ ) {
00886       if( type == ntohl(pulData[1 + i*3]) ) {
00887         rv = ntohl(pulData[2 + i*3]);
00888       }
00889     }
00890 
00891     if( i == n ) {
00892       *pError = CKR_ATTRIBUTE_TYPE_INVALID;
00893       goto done;
00894     }
00895 
00896   done:
00897     (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
00898   }
00899 
00900   return rv;
00901 }
00902 
00903 NSS_IMPLEMENT NSSItem *
00904 nss_dbm_db_get_object_attribute
00905 (
00906   nss_dbm_dbt_t *dbt,
00907   NSSArena *arena,
00908   CK_ATTRIBUTE_TYPE type,
00909   CK_RV *pError,
00910   CK_ULONG *pdbrv
00911 )
00912 {
00913   NSSItem *rv = (NSSItem *)NULL;
00914   DBT object;
00915   CK_ULONG i;
00916   NSSArena *tmp = NSSArena_Create();
00917   CK_ATTRIBUTE_PTR pTemplate;
00918   CK_ULONG ulAttributeCount;
00919 
00920   /* Locked region */
00921   {
00922     *pError = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
00923     if( CKR_OK != *pError ) {
00924       goto loser;
00925     }
00926 
00927     *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
00928     if( 0 == *pdbrv ) {
00929       ;
00930     } else if( *pdbrv > 0 ) {
00931       *pError = CKR_OBJECT_HANDLE_INVALID;
00932       goto done;
00933     } else {
00934       *pError = CKR_DEVICE_ERROR;
00935       goto done;
00936     }
00937 
00938     *pError = nss_dbm_db_unwrap_object(tmp, &object, &pTemplate, &ulAttributeCount);
00939     if( CKR_OK != *pError ) {
00940       goto done;
00941     }
00942 
00943     for( i = 0; i < ulAttributeCount; i++ ) {
00944       if( type == pTemplate[i].type ) {
00945         rv = nss_ZNEW(arena, NSSItem);
00946         if( (NSSItem *)NULL == rv ) {
00947           *pError = CKR_HOST_MEMORY;
00948           goto done;
00949         }
00950         rv->size = pTemplate[i].ulValueLen;
00951         rv->data = nss_ZAlloc(arena, rv->size);
00952         if( (void *)NULL == rv->data ) {
00953           *pError = CKR_HOST_MEMORY;
00954           goto done;
00955         }
00956         (void)memcpy(rv->data, pTemplate[i].pValue, rv->size);
00957         break;
00958       }
00959     }
00960     if( ulAttributeCount == i ) {
00961       *pError = CKR_ATTRIBUTE_TYPE_INVALID;
00962       goto done;
00963     }
00964 
00965   done:
00966     (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
00967   }
00968 
00969  loser:
00970   if( (NSSArena *)NULL != tmp ) {
00971     NSSArena_Destroy(tmp);
00972   }
00973 
00974   return rv;
00975 }
00976 
00977 NSS_IMPLEMENT CK_RV
00978 nss_dbm_db_set_object_attribute
00979 (
00980   nss_dbm_dbt_t *dbt,
00981   CK_ATTRIBUTE_TYPE type,
00982   NSSItem *value,
00983   CK_ULONG *pdbrv
00984 )
00985 {
00986   CK_RV rv = CKR_OK;
00987   DBT object;
00988   CK_ULONG i;
00989   NSSArena *tmp = NSSArena_Create();
00990   CK_ATTRIBUTE_PTR pTemplate;
00991   CK_ULONG ulAttributeCount;
00992 
00993   /* Locked region */
00994   {
00995     rv = NSSCKFWMutex_Lock(dbt->my_db->crustylock);
00996     if( CKR_OK != rv ) {
00997       goto loser;
00998     }
00999 
01000     *pdbrv = dbt->my_db->db->get(dbt->my_db->db, &dbt->dbt, &object, 0);
01001     if( 0 == *pdbrv ) {
01002       ;
01003     } else if( *pdbrv > 0 ) {
01004       rv = CKR_OBJECT_HANDLE_INVALID;
01005       goto done;
01006     } else {
01007       rv = CKR_DEVICE_ERROR;
01008       goto done;
01009     }
01010 
01011     rv = nss_dbm_db_unwrap_object(tmp, &object, &pTemplate, &ulAttributeCount);
01012     if( CKR_OK != rv ) {
01013       goto done;
01014     }
01015 
01016     for( i = 0; i < ulAttributeCount; i++ ) {
01017       if( type == pTemplate[i].type ) {
01018         /* Replacing an existing attribute */
01019         pTemplate[i].ulValueLen = value->size;
01020         pTemplate[i].pValue = value->data;
01021         break;
01022       }
01023     }
01024 
01025     if( i == ulAttributeCount ) {
01026       /* Adding a new attribute */
01027       CK_ATTRIBUTE_PTR npt = nss_ZNEWARRAY(tmp, CK_ATTRIBUTE, ulAttributeCount+1);
01028       if( (CK_ATTRIBUTE_PTR)NULL == npt ) {
01029         rv = CKR_DEVICE_ERROR;
01030         goto done;
01031       }
01032 
01033       for( i = 0; i < ulAttributeCount; i++ ) {
01034         npt[i] = pTemplate[i];
01035       }
01036 
01037       npt[ulAttributeCount].type = type;
01038       npt[ulAttributeCount].ulValueLen = value->size;
01039       npt[ulAttributeCount].pValue = value->data;
01040 
01041       pTemplate = npt;
01042       ulAttributeCount++;
01043     }
01044 
01045     rv = nss_dbm_db_wrap_object(tmp, pTemplate, ulAttributeCount, &object);
01046     if( CKR_OK != rv ) {
01047       goto done;
01048     }
01049 
01050     *pdbrv = dbt->my_db->db->put(dbt->my_db->db, &dbt->dbt, &object, 0);
01051     if( 0 != *pdbrv ) {
01052       rv = CKR_DEVICE_ERROR;
01053       goto done;
01054     }
01055 
01056     (void)dbt->my_db->db->sync(dbt->my_db->db, 0);
01057 
01058   done:
01059     (void)NSSCKFWMutex_Unlock(dbt->my_db->crustylock);
01060   }
01061 
01062  loser:
01063   if( (NSSArena *)NULL != tmp ) {
01064     NSSArena_Destroy(tmp);
01065   }
01066 
01067   return rv;
01068 }