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 *
nss_dbm_db_open(NSSArena * arena,NSSCKFWInstance * fwInstance,char * filename,int flags,CK_RV * pError)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
nss_dbm_db_close(nss_dbm_db_t * db)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
nss_dbm_db_get_format_version(nss_dbm_db_t * db)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
nss_dbm_db_set_label(nss_dbm_db_t * db,NSSUTF8 * label)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 *
nss_dbm_db_get_label(nss_dbm_db_t * db,NSSArena * arena,CK_RV * pError)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
nss_dbm_db_delete_object(nss_dbm_dbt_t * dbt)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
nss_dbm_db_new_handle(nss_dbm_db_t * db,DBT * dbt,CK_RV * pError)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
nss_dbm_db_swap_type(CK_ATTRIBUTE_TYPE 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_NETSCAPE_URL:
396             return type_opaque;
397         case CKA_NETSCAPE_EMAIL:
398             return type_opaque;
399         case CKA_NETSCAPE_SMIME_INFO:
400             return type_opaque;
401         case CKA_NETSCAPE_SMIME_TIMESTAMP:
402             return type_opaque;
403         case CKA_NETSCAPE_PKCS8_SALT:
404             return type_opaque;
405         case CKA_NETSCAPE_PASSWORD_CHECK:
406             return type_opaque;
407         case CKA_NETSCAPE_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_NETSCAPE_DB:
440             return type_opaque;
441         case CKA_NETSCAPE_TRUST:
442             return type_opaque;
443         default:
444             return type_opaque;
445     }
446 }
447 
448 static void
nss_dbm_db_swap_copy(CK_ATTRIBUTE_TYPE type,void * dest,void * src,CK_ULONG len)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
nss_dbm_db_wrap_object(NSSArena * arena,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,DBT * object)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
nss_dbm_db_unwrap_object(NSSArena * arena,DBT * object,CK_ATTRIBUTE_PTR * ppTemplate,CK_ULONG * pulAttributeCount)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 *
nss_dbm_db_create_object(NSSArena * arena,nss_dbm_db_t * db,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_RV * pError,CK_ULONG * pdbrv)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
nss_dbm_db_find_objects(nss_dbm_find_t * find,nss_dbm_db_t * db,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_ULONG * pdbrv)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
nss_dbm_db_object_still_exists(nss_dbm_dbt_t * dbt)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
nss_dbm_db_get_object_attribute_count(nss_dbm_dbt_t * dbt,CK_RV * pError,CK_ULONG * pdbrv)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
nss_dbm_db_get_object_attribute_types(nss_dbm_dbt_t * dbt,CK_ATTRIBUTE_TYPE_PTR typeArray,CK_ULONG ulCount,CK_ULONG * pdbrv)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
nss_dbm_db_get_object_attribute_size(nss_dbm_dbt_t * dbt,CK_ATTRIBUTE_TYPE type,CK_RV * pError,CK_ULONG * pdbrv)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 *
nss_dbm_db_get_object_attribute(nss_dbm_dbt_t * dbt,NSSArena * arena,CK_ATTRIBUTE_TYPE type,CK_RV * pError,CK_ULONG * pdbrv)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
nss_dbm_db_set_object_attribute(nss_dbm_dbt_t * dbt,CK_ATTRIBUTE_TYPE type,NSSItem * value,CK_ULONG * pdbrv)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 }
1070