Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / lib / ckfw / dbm / db.c
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
38 static 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
47 static CK_VERSION nss_dbm_db_format_version = { 1, 0 };
48 struct handle {
49   char prefix[4];
50   CK_ULONG id;
51 };
52
53 NSS_IMPLEMENT nss_dbm_db_t *
54 nss_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
93 NSS_IMPLEMENT void
94 nss_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
110 NSS_IMPLEMENT CK_VERSION
111 nss_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
158 NSS_IMPLEMENT CK_RV
159 nss_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
196 NSS_IMPLEMENT NSSUTF8 *
197 nss_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
238 NSS_IMPLEMENT CK_RV
239 nss_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
273 static CK_ULONG
274 nss_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
349 enum swap_type { type_byte, type_short, type_long, type_opaque };
350
351 static enum swap_type
352 nss_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
429 static void
430 nss_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
462 static CK_RV
463 nss_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
505 static CK_RV
506 nss_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
553 NSS_IMPLEMENT nss_dbm_dbt_t *
554 nss_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
624 NSS_IMPLEMENT CK_RV
625 nss_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
731 NSS_IMPLEMENT CK_BBOOL
732 nss_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
759 NSS_IMPLEMENT CK_ULONG
760 nss_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
799 NSS_IMPLEMENT CK_RV
800 nss_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
850 NSS_IMPLEMENT CK_ULONG
851 nss_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
903 NSS_IMPLEMENT NSSItem *
904 nss_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
977 NSS_IMPLEMENT CK_RV
978 nss_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 }