Imported Upstream version 3.13.6
[platform/upstream/nss.git] / mozilla / security / nss / lib / ckfw / sessobj.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: sessobj.c,v $ $Revision: 1.15 $ $Date: 2009/06/05 00:22:04 $";
39 #endif /* DEBUG */
40
41 /*
42  * sessobj.c
43  *
44  * This file contains an NSSCKMDObject implementation for session 
45  * objects.  The framework uses this implementation to manage
46  * session objects when a Module doesn't wish to be bothered.
47  */
48
49 #ifndef CK_T
50 #include "ck.h"
51 #endif /* CK_T */
52
53 /*
54  * nssCKMDSessionObject
55  *
56  *  -- create --
57  *  nssCKMDSessionObject_Create
58  *
59  *  -- EPV calls --
60  *  nss_ckmdSessionObject_Finalize
61  *  nss_ckmdSessionObject_IsTokenObject
62  *  nss_ckmdSessionObject_GetAttributeCount
63  *  nss_ckmdSessionObject_GetAttributeTypes
64  *  nss_ckmdSessionObject_GetAttributeSize
65  *  nss_ckmdSessionObject_GetAttribute
66  *  nss_ckmdSessionObject_SetAttribute
67  *  nss_ckmdSessionObject_GetObjectSize
68  */
69
70 struct nssCKMDSessionObjectStr {
71   CK_ULONG n;
72   NSSArena *arena;
73   NSSItem *attributes;
74   CK_ATTRIBUTE_TYPE_PTR types;
75   nssCKFWHash *hash;
76 };
77 typedef struct nssCKMDSessionObjectStr nssCKMDSessionObject;
78
79 #ifdef DEBUG
80 /*
81  * But first, the pointer-tracking stuff.
82  *
83  * NOTE: the pointer-tracking support in NSS/base currently relies
84  * upon NSPR's CallOnce support.  That, however, relies upon NSPR's
85  * locking, which is tied into the runtime.  We need a pointer-tracker
86  * implementation that uses the locks supplied through C_Initialize.
87  * That support, however, can be filled in later.  So for now, I'll
88  * just do this routines as no-ops.
89  */
90
91 static CK_RV
92 nss_ckmdSessionObject_add_pointer
93 (
94   const NSSCKMDObject *mdObject
95 )
96 {
97   return CKR_OK;
98 }
99
100 static CK_RV
101 nss_ckmdSessionObject_remove_pointer
102 (
103   const NSSCKMDObject *mdObject
104 )
105 {
106   return CKR_OK;
107 }
108
109 #ifdef NSS_DEBUG
110 static CK_RV
111 nss_ckmdSessionObject_verifyPointer
112 (
113   const NSSCKMDObject *mdObject
114 )
115 {
116   return CKR_OK;
117 }
118 #endif
119
120 #endif /* DEBUG */
121
122 /*
123  * We must forward-declare these routines
124  */
125 static void
126 nss_ckmdSessionObject_Finalize
127 (
128   NSSCKMDObject *mdObject,
129   NSSCKFWObject *fwObject,
130   NSSCKMDSession *mdSession,
131   NSSCKFWSession *fwSession,
132   NSSCKMDToken *mdToken,
133   NSSCKFWToken *fwToken,
134   NSSCKMDInstance *mdInstance,
135   NSSCKFWInstance *fwInstance
136 );
137
138 static CK_RV
139 nss_ckmdSessionObject_Destroy
140 (
141   NSSCKMDObject *mdObject,
142   NSSCKFWObject *fwObject,
143   NSSCKMDSession *mdSession,
144   NSSCKFWSession *fwSession,
145   NSSCKMDToken *mdToken,
146   NSSCKFWToken *fwToken,
147   NSSCKMDInstance *mdInstance,
148   NSSCKFWInstance *fwInstance
149 );
150
151 static CK_BBOOL
152 nss_ckmdSessionObject_IsTokenObject
153 (
154   NSSCKMDObject *mdObject,
155   NSSCKFWObject *fwObject,
156   NSSCKMDSession *mdSession,
157   NSSCKFWSession *fwSession,
158   NSSCKMDToken *mdToken,
159   NSSCKFWToken *fwToken,
160   NSSCKMDInstance *mdInstance,
161   NSSCKFWInstance *fwInstance
162 );
163
164 static CK_ULONG
165 nss_ckmdSessionObject_GetAttributeCount
166 (
167   NSSCKMDObject *mdObject,
168   NSSCKFWObject *fwObject,
169   NSSCKMDSession *mdSession,
170   NSSCKFWSession *fwSession,
171   NSSCKMDToken *mdToken,
172   NSSCKFWToken *fwToken,
173   NSSCKMDInstance *mdInstance,
174   NSSCKFWInstance *fwInstance,
175   CK_RV *pError
176 );
177
178 static CK_RV
179 nss_ckmdSessionObject_GetAttributeTypes
180 (
181   NSSCKMDObject *mdObject,
182   NSSCKFWObject *fwObject,
183   NSSCKMDSession *mdSession,
184   NSSCKFWSession *fwSession,
185   NSSCKMDToken *mdToken,
186   NSSCKFWToken *fwToken,
187   NSSCKMDInstance *mdInstance,
188   NSSCKFWInstance *fwInstance,
189   CK_ATTRIBUTE_TYPE_PTR typeArray,
190   CK_ULONG ulCount
191 );
192
193 static CK_ULONG
194 nss_ckmdSessionObject_GetAttributeSize
195 (
196   NSSCKMDObject *mdObject,
197   NSSCKFWObject *fwObject,
198   NSSCKMDSession *mdSession,
199   NSSCKFWSession *fwSession,
200   NSSCKMDToken *mdToken,
201   NSSCKFWToken *fwToken,
202   NSSCKMDInstance *mdInstance,
203   NSSCKFWInstance *fwInstance,
204   CK_ATTRIBUTE_TYPE attribute,
205   CK_RV *pError
206 );
207
208 static NSSCKFWItem
209 nss_ckmdSessionObject_GetAttribute
210 (
211   NSSCKMDObject *mdObject,
212   NSSCKFWObject *fwObject,
213   NSSCKMDSession *mdSession,
214   NSSCKFWSession *fwSession,
215   NSSCKMDToken *mdToken,
216   NSSCKFWToken *fwToken,
217   NSSCKMDInstance *mdInstance,
218   NSSCKFWInstance *fwInstance,
219   CK_ATTRIBUTE_TYPE attribute,
220   CK_RV *pError
221 );
222
223 static CK_RV
224 nss_ckmdSessionObject_SetAttribute
225 (
226   NSSCKMDObject *mdObject,
227   NSSCKFWObject *fwObject,
228   NSSCKMDSession *mdSession,
229   NSSCKFWSession *fwSession,
230   NSSCKMDToken *mdToken,
231   NSSCKFWToken *fwToken,
232   NSSCKMDInstance *mdInstance,
233   NSSCKFWInstance *fwInstance,
234   CK_ATTRIBUTE_TYPE attribute,
235   NSSItem *value
236 );
237
238 static CK_ULONG
239 nss_ckmdSessionObject_GetObjectSize
240 (
241   NSSCKMDObject *mdObject,
242   NSSCKFWObject *fwObject,
243   NSSCKMDSession *mdSession,
244   NSSCKFWSession *fwSession,
245   NSSCKMDToken *mdToken,
246   NSSCKFWToken *fwToken,
247   NSSCKMDInstance *mdInstance,
248   NSSCKFWInstance *fwInstance,
249   CK_RV *pError
250 );
251
252 /*
253  * nssCKMDSessionObject_Create
254  *
255  */
256 NSS_IMPLEMENT NSSCKMDObject *
257 nssCKMDSessionObject_Create
258 (
259   NSSCKFWToken *fwToken,
260   NSSArena *arena,
261   CK_ATTRIBUTE_PTR attributes,
262   CK_ULONG ulCount,
263   CK_RV *pError
264 )
265 {
266   NSSCKMDObject *mdObject = (NSSCKMDObject *)NULL;
267   nssCKMDSessionObject *mdso = (nssCKMDSessionObject *)NULL;
268   CK_ULONG i;
269   nssCKFWHash *hash;
270
271   *pError = CKR_OK;
272
273   mdso = nss_ZNEW(arena, nssCKMDSessionObject);
274   if (!mdso) {
275     goto loser;
276   }
277
278   mdso->arena = arena;
279   mdso->n = ulCount;
280   mdso->attributes = nss_ZNEWARRAY(arena, NSSItem, ulCount);
281   if (!mdso->attributes) {
282     goto loser;
283   }
284
285   mdso->types = nss_ZNEWARRAY(arena, CK_ATTRIBUTE_TYPE, ulCount);
286   if (!mdso->types) {
287     goto loser;
288   }
289   for( i = 0; i < ulCount; i++ ) {
290     mdso->types[i] = attributes[i].type;
291     mdso->attributes[i].size = attributes[i].ulValueLen;
292     mdso->attributes[i].data = nss_ZAlloc(arena, attributes[i].ulValueLen);
293     if (!mdso->attributes[i].data) {
294       goto loser;
295     }
296     (void)nsslibc_memcpy(mdso->attributes[i].data, attributes[i].pValue,
297       attributes[i].ulValueLen);
298   }
299
300   mdObject = nss_ZNEW(arena, NSSCKMDObject);
301   if (!mdObject) {
302     goto loser;
303   }
304
305   mdObject->etc = (void *)mdso;
306   mdObject->Finalize = nss_ckmdSessionObject_Finalize;
307   mdObject->Destroy = nss_ckmdSessionObject_Destroy;
308   mdObject->IsTokenObject = nss_ckmdSessionObject_IsTokenObject;
309   mdObject->GetAttributeCount = nss_ckmdSessionObject_GetAttributeCount;
310   mdObject->GetAttributeTypes = nss_ckmdSessionObject_GetAttributeTypes;
311   mdObject->GetAttributeSize = nss_ckmdSessionObject_GetAttributeSize;
312   mdObject->GetAttribute = nss_ckmdSessionObject_GetAttribute;
313   mdObject->SetAttribute = nss_ckmdSessionObject_SetAttribute;
314   mdObject->GetObjectSize = nss_ckmdSessionObject_GetObjectSize;
315
316   hash = nssCKFWToken_GetSessionObjectHash(fwToken);
317   if (!hash) {
318     *pError = CKR_GENERAL_ERROR;
319     goto loser;
320   }
321
322   mdso->hash = hash;
323
324   *pError = nssCKFWHash_Add(hash, mdObject, mdObject);
325   if( CKR_OK != *pError ) {
326     goto loser;
327   }
328
329 #ifdef DEBUG
330   if(( *pError = nss_ckmdSessionObject_add_pointer(mdObject)) != CKR_OK ) {
331     goto loser;
332   }
333 #endif /* DEBUG */
334
335   return mdObject;
336
337  loser:
338   if (mdso) {
339     if (mdso->attributes) {
340       for( i = 0; i < ulCount; i++ ) {
341         nss_ZFreeIf(mdso->attributes[i].data);
342       }
343       nss_ZFreeIf(mdso->attributes);
344     }
345     nss_ZFreeIf(mdso->types);
346     nss_ZFreeIf(mdso);
347   }
348
349   nss_ZFreeIf(mdObject);
350   if (*pError == CKR_OK) {
351       *pError = CKR_HOST_MEMORY;
352   }
353   return (NSSCKMDObject *)NULL;
354 }
355
356 /*
357  * nss_ckmdSessionObject_Finalize
358  *
359  */
360 static void
361 nss_ckmdSessionObject_Finalize
362 (
363   NSSCKMDObject *mdObject,
364   NSSCKFWObject *fwObject,
365   NSSCKMDSession *mdSession,
366   NSSCKFWSession *fwSession,
367   NSSCKMDToken *mdToken,
368   NSSCKFWToken *fwToken,
369   NSSCKMDInstance *mdInstance,
370   NSSCKFWInstance *fwInstance
371 )
372 {
373   /* This shouldn't ever be called */
374   return;
375 }
376
377 /*
378  * nss_ckmdSessionObject_Destroy
379  *
380  */
381
382 static CK_RV
383 nss_ckmdSessionObject_Destroy
384 (
385   NSSCKMDObject *mdObject,
386   NSSCKFWObject *fwObject,
387   NSSCKMDSession *mdSession,
388   NSSCKFWSession *fwSession,
389   NSSCKMDToken *mdToken,
390   NSSCKFWToken *fwToken,
391   NSSCKMDInstance *mdInstance,
392   NSSCKFWInstance *fwInstance
393 )
394 {
395 #ifdef NSSDEBUG
396   CK_RV error = CKR_OK;
397 #endif /* NSSDEBUG */
398   nssCKMDSessionObject *mdso;
399   CK_ULONG i;
400
401 #ifdef NSSDEBUG
402   error = nss_ckmdSessionObject_verifyPointer(mdObject);
403   if( CKR_OK != error ) {
404     return error;
405   }
406 #endif /* NSSDEBUG */
407
408   mdso = (nssCKMDSessionObject *)mdObject->etc;
409
410   nssCKFWHash_Remove(mdso->hash, mdObject);
411
412   for( i = 0; i < mdso->n; i++ ) {
413     nss_ZFreeIf(mdso->attributes[i].data);
414   }
415   nss_ZFreeIf(mdso->attributes);
416   nss_ZFreeIf(mdso->types);
417   nss_ZFreeIf(mdso);
418   nss_ZFreeIf(mdObject);
419
420 #ifdef DEBUG
421   (void)nss_ckmdSessionObject_remove_pointer(mdObject);
422 #endif /* DEBUG */
423
424   return CKR_OK;
425 }
426
427 /*
428  * nss_ckmdSessionObject_IsTokenObject
429  *
430  */
431
432 static CK_BBOOL
433 nss_ckmdSessionObject_IsTokenObject
434 (
435   NSSCKMDObject *mdObject,
436   NSSCKFWObject *fwObject,
437   NSSCKMDSession *mdSession,
438   NSSCKFWSession *fwSession,
439   NSSCKMDToken *mdToken,
440   NSSCKFWToken *fwToken,
441   NSSCKMDInstance *mdInstance,
442   NSSCKFWInstance *fwInstance
443 )
444 {
445 #ifdef NSSDEBUG
446   if( CKR_OK != nss_ckmdSessionObject_verifyPointer(mdObject) ) {
447     return CK_FALSE;
448   }
449 #endif /* NSSDEBUG */
450
451   /*
452    * This implementation is only ever used for session objects.
453    */
454   return CK_FALSE;
455 }
456
457 /*
458  * nss_ckmdSessionObject_GetAttributeCount
459  *
460  */
461 static CK_ULONG
462 nss_ckmdSessionObject_GetAttributeCount
463 (
464   NSSCKMDObject *mdObject,
465   NSSCKFWObject *fwObject,
466   NSSCKMDSession *mdSession,
467   NSSCKFWSession *fwSession,
468   NSSCKMDToken *mdToken,
469   NSSCKFWToken *fwToken,
470   NSSCKMDInstance *mdInstance,
471   NSSCKFWInstance *fwInstance,
472   CK_RV *pError
473 )
474 {
475   nssCKMDSessionObject *obj;
476
477 #ifdef NSSDEBUG
478   if (!pError) {
479     return 0;
480   }
481
482   *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
483   if( CKR_OK != *pError ) {
484     return 0;
485   }
486
487   /* We could even check all the other arguments, for sanity. */
488 #endif /* NSSDEBUG */
489
490   obj = (nssCKMDSessionObject *)mdObject->etc;
491
492   return obj->n;
493 }
494
495 /*
496  * nss_ckmdSessionObject_GetAttributeTypes
497  *
498  */
499 static CK_RV
500 nss_ckmdSessionObject_GetAttributeTypes
501 (
502   NSSCKMDObject *mdObject,
503   NSSCKFWObject *fwObject,
504   NSSCKMDSession *mdSession,
505   NSSCKFWSession *fwSession,
506   NSSCKMDToken *mdToken,
507   NSSCKFWToken *fwToken,
508   NSSCKMDInstance *mdInstance,
509   NSSCKFWInstance *fwInstance,
510   CK_ATTRIBUTE_TYPE_PTR typeArray,
511   CK_ULONG ulCount
512 )
513 {
514 #ifdef NSSDEBUG
515   CK_RV error = CKR_OK;
516 #endif /* NSSDEBUG */
517   nssCKMDSessionObject *obj;
518
519 #ifdef NSSDEBUG
520   error = nss_ckmdSessionObject_verifyPointer(mdObject);
521   if( CKR_OK != error ) {
522     return error;
523   }
524
525   /* We could even check all the other arguments, for sanity. */
526 #endif /* NSSDEBUG */
527
528   obj = (nssCKMDSessionObject *)mdObject->etc;
529
530   if( ulCount < obj->n ) {
531     return CKR_BUFFER_TOO_SMALL;
532   }
533
534   (void)nsslibc_memcpy(typeArray, obj->types, 
535     sizeof(CK_ATTRIBUTE_TYPE) * obj->n);
536
537   return CKR_OK;
538 }
539
540 /*
541  * nss_ckmdSessionObject_GetAttributeSize
542  *
543  */
544 static CK_ULONG
545 nss_ckmdSessionObject_GetAttributeSize
546 (
547   NSSCKMDObject *mdObject,
548   NSSCKFWObject *fwObject,
549   NSSCKMDSession *mdSession,
550   NSSCKFWSession *fwSession,
551   NSSCKMDToken *mdToken,
552   NSSCKFWToken *fwToken,
553   NSSCKMDInstance *mdInstance,
554   NSSCKFWInstance *fwInstance,
555   CK_ATTRIBUTE_TYPE attribute,
556   CK_RV *pError
557 )
558 {
559   nssCKMDSessionObject *obj;
560   CK_ULONG i;
561
562 #ifdef NSSDEBUG
563   if (!pError) {
564     return 0;
565   }
566
567   *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
568   if( CKR_OK != *pError ) {
569     return 0;
570   }
571
572   /* We could even check all the other arguments, for sanity. */
573 #endif /* NSSDEBUG */
574
575   obj = (nssCKMDSessionObject *)mdObject->etc;
576
577   for( i = 0; i < obj->n; i++ ) {
578     if( attribute == obj->types[i] ) {
579       return (CK_ULONG)(obj->attributes[i].size);
580     }
581   }
582
583   *pError = CKR_ATTRIBUTE_TYPE_INVALID;
584   return 0;
585 }
586
587 /*
588  * nss_ckmdSessionObject_GetAttribute
589  *
590  */
591 static NSSCKFWItem
592 nss_ckmdSessionObject_GetAttribute
593 (
594   NSSCKMDObject *mdObject,
595   NSSCKFWObject *fwObject,
596   NSSCKMDSession *mdSession,
597   NSSCKFWSession *fwSession,
598   NSSCKMDToken *mdToken,
599   NSSCKFWToken *fwToken,
600   NSSCKMDInstance *mdInstance,
601   NSSCKFWInstance *fwInstance,
602   CK_ATTRIBUTE_TYPE attribute,
603   CK_RV *pError
604 )
605 {
606   NSSCKFWItem item;
607   nssCKMDSessionObject *obj;
608   CK_ULONG i;
609
610   item.needsFreeing = PR_FALSE;
611   item.item = NULL;
612 #ifdef NSSDEBUG
613   if (!pError) {
614     return item;
615   }
616
617   *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
618   if( CKR_OK != *pError ) {
619     return item;
620   }
621
622   /* We could even check all the other arguments, for sanity. */
623 #endif /* NSSDEBUG */
624
625   obj = (nssCKMDSessionObject *)mdObject->etc;
626
627   for( i = 0; i < obj->n; i++ ) {
628     if( attribute == obj->types[i] ) {
629       item.item = &obj->attributes[i];
630       return item;
631     }
632   }
633
634   *pError = CKR_ATTRIBUTE_TYPE_INVALID;
635   return item;
636 }
637
638 /*
639  * nss_ckmdSessionObject_SetAttribute
640  *
641  */
642
643 /*
644  * Okay, so this implementation sucks.  It doesn't support removing
645  * an attribute (if value == NULL), and could be more graceful about
646  * memory.  It should allow "blank" slots in the arrays, with some
647  * invalid attribute type, and then it could support removal much
648  * more easily.  Do this later.
649  */
650 static CK_RV
651 nss_ckmdSessionObject_SetAttribute
652 (
653   NSSCKMDObject *mdObject,
654   NSSCKFWObject *fwObject,
655   NSSCKMDSession *mdSession,
656   NSSCKFWSession *fwSession,
657   NSSCKMDToken *mdToken,
658   NSSCKFWToken *fwToken,
659   NSSCKMDInstance *mdInstance,
660   NSSCKFWInstance *fwInstance,
661   CK_ATTRIBUTE_TYPE attribute,
662   NSSItem *value
663 )
664 {
665   nssCKMDSessionObject *obj;
666   CK_ULONG i;
667   NSSItem n;
668   NSSItem *ra;
669   CK_ATTRIBUTE_TYPE_PTR rt;
670 #ifdef NSSDEBUG
671   CK_RV error;
672 #endif /* NSSDEBUG */
673
674 #ifdef NSSDEBUG
675   error = nss_ckmdSessionObject_verifyPointer(mdObject);
676   if( CKR_OK != error ) {
677     return 0;
678   }
679
680   /* We could even check all the other arguments, for sanity. */
681 #endif /* NSSDEBUG */
682
683   obj = (nssCKMDSessionObject *)mdObject->etc;
684
685   n.size = value->size;
686   n.data = nss_ZAlloc(obj->arena, n.size);
687   if (!n.data) {
688     return CKR_HOST_MEMORY;
689   }
690   (void)nsslibc_memcpy(n.data, value->data, n.size);
691
692   for( i = 0; i < obj->n; i++ ) {
693     if( attribute == obj->types[i] ) {
694       nss_ZFreeIf(obj->attributes[i].data);
695       obj->attributes[i] = n;
696       return CKR_OK;
697     }
698   }
699
700   /*
701    * It's new.
702    */
703
704   ra = (NSSItem *)nss_ZRealloc(obj->attributes, sizeof(NSSItem) * (obj->n + 1));
705   if (!ra) {
706     nss_ZFreeIf(n.data);
707     return CKR_HOST_MEMORY;
708   }
709   obj->attributes = ra;
710
711   rt = (CK_ATTRIBUTE_TYPE_PTR)nss_ZRealloc(obj->types, 
712                                       sizeof(CK_ATTRIBUTE_TYPE) * (obj->n + 1));
713   if (!rt) {
714     nss_ZFreeIf(n.data);
715     return CKR_HOST_MEMORY;
716   }
717
718   obj->types = rt;
719   obj->attributes[obj->n] = n;
720   obj->types[obj->n] = attribute;
721   obj->n++;
722
723   return CKR_OK;
724 }
725
726 /*
727  * nss_ckmdSessionObject_GetObjectSize
728  *
729  */
730 static CK_ULONG
731 nss_ckmdSessionObject_GetObjectSize
732 (
733   NSSCKMDObject *mdObject,
734   NSSCKFWObject *fwObject,
735   NSSCKMDSession *mdSession,
736   NSSCKFWSession *fwSession,
737   NSSCKMDToken *mdToken,
738   NSSCKFWToken *fwToken,
739   NSSCKMDInstance *mdInstance,
740   NSSCKFWInstance *fwInstance,
741   CK_RV *pError
742 )
743 {
744   nssCKMDSessionObject *obj;
745   CK_ULONG i;
746   CK_ULONG rv = (CK_ULONG)0;
747
748 #ifdef NSSDEBUG
749   if (!pError) {
750     return 0;
751   }
752
753   *pError = nss_ckmdSessionObject_verifyPointer(mdObject);
754   if( CKR_OK != *pError ) {
755     return 0;
756   }
757
758   /* We could even check all the other arguments, for sanity. */
759 #endif /* NSSDEBUG */
760
761   obj = (nssCKMDSessionObject *)mdObject->etc;
762
763   for( i = 0; i < obj->n; i++ ) {
764     rv += obj->attributes[i].size;
765   }
766
767   rv += sizeof(NSSItem) * obj->n;
768   rv += sizeof(CK_ATTRIBUTE_TYPE) * obj->n;
769   rv += sizeof(nssCKMDSessionObject);
770
771   return rv;
772 }
773
774 /*
775  * nssCKMDFindSessionObjects
776  *
777  *  -- create --
778  *  nssCKMDFindSessionObjects_Create
779  *
780  *  -- EPV calls --
781  *  nss_ckmdFindSessionObjects_Final
782  *  nss_ckmdFindSessionObjects_Next
783  */
784
785 struct nodeStr {
786   struct nodeStr *next;
787   NSSCKMDObject *mdObject;
788 };
789
790 struct nssCKMDFindSessionObjectsStr {
791   NSSArena *arena;
792   CK_RV error;
793   CK_ATTRIBUTE_PTR pTemplate;
794   CK_ULONG ulCount;
795   struct nodeStr *list;
796   nssCKFWHash *hash;
797
798 };
799 typedef struct nssCKMDFindSessionObjectsStr nssCKMDFindSessionObjects;
800
801 #ifdef DEBUG
802 /*
803  * But first, the pointer-tracking stuff.
804  *
805  * NOTE: the pointer-tracking support in NSS/base currently relies
806  * upon NSPR's CallOnce support.  That, however, relies upon NSPR's
807  * locking, which is tied into the runtime.  We need a pointer-tracker
808  * implementation that uses the locks supplied through C_Initialize.
809  * That support, however, can be filled in later.  So for now, I'll
810  * just do this routines as no-ops.
811  */
812
813 static CK_RV
814 nss_ckmdFindSessionObjects_add_pointer
815 (
816   const NSSCKMDFindObjects *mdFindObjects
817 )
818 {
819   return CKR_OK;
820 }
821
822 static CK_RV
823 nss_ckmdFindSessionObjects_remove_pointer
824 (
825   const NSSCKMDFindObjects *mdFindObjects
826 )
827 {
828   return CKR_OK;
829 }
830
831 #ifdef NSS_DEBUG
832 static CK_RV
833 nss_ckmdFindSessionObjects_verifyPointer
834 (
835   const NSSCKMDFindObjects *mdFindObjects
836 )
837 {
838   return CKR_OK;
839 }
840 #endif
841
842 #endif /* DEBUG */
843
844 /*
845  * We must forward-declare these routines.
846  */
847 static void
848 nss_ckmdFindSessionObjects_Final
849 (
850   NSSCKMDFindObjects *mdFindObjects,
851   NSSCKFWFindObjects *fwFindObjects,
852   NSSCKMDSession *mdSession,
853   NSSCKFWSession *fwSession,
854   NSSCKMDToken *mdToken,
855   NSSCKFWToken *fwToken,
856   NSSCKMDInstance *mdInstance,
857   NSSCKFWInstance *fwInstance
858 );
859
860 static NSSCKMDObject *
861 nss_ckmdFindSessionObjects_Next
862 (
863   NSSCKMDFindObjects *mdFindObjects,
864   NSSCKFWFindObjects *fwFindObjects,
865   NSSCKMDSession *mdSession,
866   NSSCKFWSession *fwSession,
867   NSSCKMDToken *mdToken,
868   NSSCKFWToken *fwToken,
869   NSSCKMDInstance *mdInstance,
870   NSSCKFWInstance *fwInstance,
871   NSSArena *arena,
872   CK_RV *pError
873 );
874
875 static CK_BBOOL
876 items_match
877 (
878   NSSItem *a,
879   CK_VOID_PTR pValue,
880   CK_ULONG ulValueLen
881 )
882 {
883   if( a->size != ulValueLen ) {
884     return CK_FALSE;
885   }
886
887   if( PR_TRUE == nsslibc_memequal(a->data, pValue, ulValueLen, (PRStatus *)NULL) ) {
888     return CK_TRUE;
889   } else {
890     return CK_FALSE;
891   }
892 }
893
894 /*
895  * Our hashtable iterator
896  */
897 static void
898 findfcn
899 (
900   const void *key,
901   void *value,
902   void *closure
903 )
904 {
905   NSSCKMDObject *mdObject = (NSSCKMDObject *)value;
906   nssCKMDSessionObject *mdso = (nssCKMDSessionObject *)mdObject->etc;
907   nssCKMDFindSessionObjects *mdfso = (nssCKMDFindSessionObjects *)closure;
908   CK_ULONG i, j;
909   struct nodeStr *node;
910
911   if( CKR_OK != mdfso->error ) {
912     return;
913   }
914
915   for( i = 0; i < mdfso->ulCount; i++ ) {
916     CK_ATTRIBUTE_PTR p = &mdfso->pTemplate[i];
917
918     for( j = 0; j < mdso->n; j++ ) {
919       if( mdso->types[j] == p->type ) {
920         if( !items_match(&mdso->attributes[j], p->pValue, p->ulValueLen) ) {
921           return;
922         } else {
923           break;
924         }
925       }
926     }
927
928     if( j == mdso->n ) {
929       /* Attribute not found */
930       return;
931     }
932   }
933
934   /* Matches */
935   node = nss_ZNEW(mdfso->arena, struct nodeStr);
936   if( (struct nodeStr *)NULL == node ) {
937     mdfso->error = CKR_HOST_MEMORY;
938     return;
939   }
940
941   node->mdObject = mdObject;
942   node->next = mdfso->list;
943   mdfso->list = node;
944
945   return;
946 }
947
948 /*
949  * nssCKMDFindSessionObjects_Create
950  *
951  */
952 NSS_IMPLEMENT NSSCKMDFindObjects *
953 nssCKMDFindSessionObjects_Create
954 (
955   NSSCKFWToken *fwToken,
956   CK_ATTRIBUTE_PTR pTemplate,
957   CK_ULONG ulCount,
958   CK_RV *pError
959 )
960 {
961   NSSArena *arena;
962   nssCKMDFindSessionObjects *mdfso;
963   nssCKFWHash *hash;
964   NSSCKMDFindObjects *rv;
965
966 #ifdef NSSDEBUG
967   if (!pError) {
968     return (NSSCKMDFindObjects *)NULL;
969   }
970
971   *pError = nssCKFWToken_verifyPointer(fwToken);
972   if( CKR_OK != *pError ) {
973     return (NSSCKMDFindObjects *)NULL;
974   }
975
976   if( (CK_ATTRIBUTE_PTR)NULL == pTemplate ) {
977     *pError = CKR_ARGUMENTS_BAD;
978     return (NSSCKMDFindObjects *)NULL;
979   }
980 #endif /* NSSDEBUG */
981
982   *pError = CKR_OK;
983
984   hash = nssCKFWToken_GetSessionObjectHash(fwToken);
985   if (!hash) {
986     *pError= CKR_GENERAL_ERROR;
987     return (NSSCKMDFindObjects *)NULL;
988   }
989
990   arena = NSSArena_Create();
991   if (!arena) {
992     *pError = CKR_HOST_MEMORY;
993     return (NSSCKMDFindObjects *)NULL;
994   }
995
996   mdfso = nss_ZNEW(arena, nssCKMDFindSessionObjects);
997   if (!mdfso) {
998     goto loser;
999   }
1000
1001   rv = nss_ZNEW(arena, NSSCKMDFindObjects);
1002   if(rv == NULL) {
1003     goto loser;
1004   }
1005
1006   mdfso->error = CKR_OK;
1007   mdfso->pTemplate = pTemplate;
1008   mdfso->ulCount = ulCount;
1009   mdfso->hash = hash;
1010
1011   nssCKFWHash_Iterate(hash, findfcn, mdfso);
1012
1013   if( CKR_OK != mdfso->error ) {
1014     goto loser;
1015   }
1016
1017   rv->etc = (void *)mdfso;
1018   rv->Final = nss_ckmdFindSessionObjects_Final;
1019   rv->Next = nss_ckmdFindSessionObjects_Next;
1020
1021 #ifdef DEBUG
1022   if( (*pError = nss_ckmdFindSessionObjects_add_pointer(rv)) != CKR_OK ) {
1023     goto loser;
1024   }
1025 #endif /* DEBUG */    
1026   mdfso->arena = arena;
1027
1028   return rv;
1029
1030 loser:
1031   if (arena) {
1032     NSSArena_Destroy(arena);
1033   }
1034   if (*pError == CKR_OK) {
1035       *pError = CKR_HOST_MEMORY;
1036   }
1037   return NULL;
1038 }
1039
1040 static void
1041 nss_ckmdFindSessionObjects_Final
1042 (
1043   NSSCKMDFindObjects *mdFindObjects,
1044   NSSCKFWFindObjects *fwFindObjects,
1045   NSSCKMDSession *mdSession,
1046   NSSCKFWSession *fwSession,
1047   NSSCKMDToken *mdToken,
1048   NSSCKFWToken *fwToken,
1049   NSSCKMDInstance *mdInstance,
1050   NSSCKFWInstance *fwInstance
1051 )
1052 {
1053   nssCKMDFindSessionObjects *mdfso;
1054
1055 #ifdef NSSDEBUG
1056   if( CKR_OK != nss_ckmdFindSessionObjects_verifyPointer(mdFindObjects) ) {
1057     return;
1058   }
1059 #endif /* NSSDEBUG */
1060
1061   mdfso = (nssCKMDFindSessionObjects *)mdFindObjects->etc;
1062   if (mdfso->arena) NSSArena_Destroy(mdfso->arena);
1063
1064 #ifdef DEBUG
1065   (void)nss_ckmdFindSessionObjects_remove_pointer(mdFindObjects);
1066 #endif /* DEBUG */
1067
1068   return;
1069 }
1070
1071 static NSSCKMDObject *
1072 nss_ckmdFindSessionObjects_Next
1073 (
1074   NSSCKMDFindObjects *mdFindObjects,
1075   NSSCKFWFindObjects *fwFindObjects,
1076   NSSCKMDSession *mdSession,
1077   NSSCKFWSession *fwSession,
1078   NSSCKMDToken *mdToken,
1079   NSSCKFWToken *fwToken,
1080   NSSCKMDInstance *mdInstance,
1081   NSSCKFWInstance *fwInstance,
1082   NSSArena *arena,
1083   CK_RV *pError
1084 )
1085 {
1086   nssCKMDFindSessionObjects *mdfso;
1087   NSSCKMDObject *rv = (NSSCKMDObject *)NULL;
1088
1089 #ifdef NSSDEBUG
1090   if( CKR_OK != nss_ckmdFindSessionObjects_verifyPointer(mdFindObjects) ) {
1091     return (NSSCKMDObject *)NULL;
1092   }
1093 #endif /* NSSDEBUG */
1094
1095   mdfso = (nssCKMDFindSessionObjects *)mdFindObjects->etc;
1096
1097   while (!rv) {
1098     if( (struct nodeStr *)NULL == mdfso->list ) {
1099       *pError = CKR_OK;
1100       return (NSSCKMDObject *)NULL;
1101     }
1102
1103     if( nssCKFWHash_Exists(mdfso->hash, mdfso->list->mdObject) ) {
1104       rv = mdfso->list->mdObject;
1105     }
1106
1107     mdfso->list = mdfso->list->next;
1108   }
1109
1110   return rv;
1111 }