wined3d: Only link and use GLSL program if at least one GLSL shader is available.
[wine] / dlls / crypt32 / store.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2004-2006 Juan Lang
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  *
19  * FIXME:
20  * - The concept of physical stores and locations isn't implemented.  (This
21  *   doesn't mean registry stores et al aren't implemented.  See the PSDK for
22  *   registering and enumerating physical stores and locations.)
23  * - Many flags, options and whatnot are unimplemented.
24  */
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winnls.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #include "wincrypt.h"
34 #include "wine/debug.h"
35 #include "wine/list.h"
36 #include "excpt.h"
37 #include "wine/exception.h"
38 #include "crypt32_private.h"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
41
42 #define WINE_CRYPTCERTSTORE_MAGIC 0x74726563
43
44 static const WINE_CONTEXT_INTERFACE gCertInterface = {
45     (CreateContextFunc)CertCreateCertificateContext,
46     (AddContextToStoreFunc)CertAddCertificateContextToStore,
47     (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
48     (DuplicateContextFunc)CertDuplicateCertificateContext,
49     (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
50     (EnumPropertiesFunc)CertEnumCertificateContextProperties,
51     (GetContextPropertyFunc)CertGetCertificateContextProperty,
52     (SetContextPropertyFunc)CertSetCertificateContextProperty,
53     (SerializeElementFunc)CertSerializeCertificateStoreElement,
54     (FreeContextFunc)CertFreeCertificateContext,
55     (DeleteContextFunc)CertDeleteCertificateFromStore,
56 };
57 PCWINE_CONTEXT_INTERFACE pCertInterface = &gCertInterface;
58
59 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
60     (CreateContextFunc)CertCreateCRLContext,
61     (AddContextToStoreFunc)CertAddCRLContextToStore,
62     (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
63     (DuplicateContextFunc)CertDuplicateCRLContext,
64     (EnumContextsInStoreFunc)CertEnumCRLsInStore,
65     (EnumPropertiesFunc)CertEnumCRLContextProperties,
66     (GetContextPropertyFunc)CertGetCRLContextProperty,
67     (SetContextPropertyFunc)CertSetCRLContextProperty,
68     (SerializeElementFunc)CertSerializeCRLStoreElement,
69     (FreeContextFunc)CertFreeCRLContext,
70     (DeleteContextFunc)CertDeleteCRLFromStore,
71 };
72 PCWINE_CONTEXT_INTERFACE pCRLInterface = &gCRLInterface;
73
74 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
75     (CreateContextFunc)CertCreateCTLContext,
76     (AddContextToStoreFunc)CertAddCTLContextToStore,
77     (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
78     (DuplicateContextFunc)CertDuplicateCTLContext,
79     (EnumContextsInStoreFunc)CertEnumCTLsInStore,
80     (EnumPropertiesFunc)CertEnumCTLContextProperties,
81     (GetContextPropertyFunc)CertGetCTLContextProperty,
82     (SetContextPropertyFunc)CertSetCTLContextProperty,
83     (SerializeElementFunc)CertSerializeCTLStoreElement,
84     (FreeContextFunc)CertFreeCTLContext,
85     (DeleteContextFunc)CertDeleteCTLFromStore,
86 };
87 PCWINE_CONTEXT_INTERFACE pCTLInterface = &gCTLInterface;
88
89 struct WINE_CRYPTCERTSTORE;
90
91 typedef struct WINE_CRYPTCERTSTORE * (*StoreOpenFunc)(HCRYPTPROV hCryptProv,
92  DWORD dwFlags, const void *pvPara);
93
94 /* Called to enumerate the next context in a store. */
95 typedef void * (*EnumFunc)(struct WINE_CRYPTCERTSTORE *store, void *pPrev);
96
97 /* Called to add a context to a store.  If toReplace is not NULL,
98  * context replaces toReplace in the store, and access checks should not be
99  * performed.  Otherwise context is a new context, and it should only be
100  * added if the store allows it.  If ppStoreContext is not NULL, the added
101  * context should be returned in *ppStoreContext.
102  */
103 typedef BOOL (*AddFunc)(struct WINE_CRYPTCERTSTORE *store, void *context,
104  void *toReplace, const void **ppStoreContext);
105
106 typedef BOOL (*DeleteFunc)(struct WINE_CRYPTCERTSTORE *store, void *context);
107
108 typedef struct _CONTEXT_STORE
109 {
110     AddFunc    addContext;
111     EnumFunc   enumContext;
112     DeleteFunc deleteContext;
113 } CONTEXT_STORE, *PCONTEXT_STORE;
114
115 typedef enum _CertStoreType {
116     StoreTypeMem,
117     StoreTypeCollection,
118     StoreTypeProvider,
119 } CertStoreType;
120
121 /* A cert store is polymorphic through the use of function pointers.  A type
122  * is still needed to distinguish collection stores from other types.
123  * On the function pointers:
124  * - closeStore is called when the store's ref count becomes 0
125  * - control is optional, but should be implemented by any store that supports
126  *   persistence
127  */
128 typedef struct WINE_CRYPTCERTSTORE
129 {
130     DWORD                       dwMagic;
131     LONG                        ref;
132     DWORD                       dwOpenFlags;
133     HCRYPTPROV                  cryptProv;
134     CertStoreType               type;
135     PFN_CERT_STORE_PROV_CLOSE   closeStore;
136     CONTEXT_STORE               certs;
137     CONTEXT_STORE               crls;
138     PFN_CERT_STORE_PROV_CONTROL control; /* optional */
139 } WINECRYPT_CERTSTORE, *PWINECRYPT_CERTSTORE;
140
141 typedef struct _WINE_MEMSTORE
142 {
143     WINECRYPT_CERTSTORE hdr;
144     struct ContextList *certs;
145     struct ContextList *crls;
146 } WINE_MEMSTORE, *PWINE_MEMSTORE;
147
148 typedef struct _WINE_HASH_TO_DELETE
149 {
150     BYTE        hash[20];
151     struct list entry;
152 } WINE_HASH_TO_DELETE, *PWINE_HASH_TO_DELETE;
153
154 typedef struct _WINE_REGSTOREINFO
155 {
156     DWORD                dwOpenFlags;
157     HCRYPTPROV           cryptProv;
158     PWINECRYPT_CERTSTORE memStore;
159     HKEY                 key;
160     BOOL                 dirty;
161     CRITICAL_SECTION     cs;
162     struct list          certsToDelete;
163     struct list          crlsToDelete;
164 } WINE_REGSTOREINFO, *PWINE_REGSTOREINFO;
165
166 typedef struct _WINE_STORE_LIST_ENTRY
167 {
168     PWINECRYPT_CERTSTORE store;
169     DWORD                dwUpdateFlags;
170     DWORD                dwPriority;
171     struct list          entry;
172 } WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
173
174 typedef struct _WINE_COLLECTIONSTORE
175 {
176     WINECRYPT_CERTSTORE hdr;
177     CRITICAL_SECTION    cs;
178     struct list         stores;
179 } WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
180
181 typedef struct _WINE_PROVIDERSTORE
182 {
183     WINECRYPT_CERTSTORE             hdr;
184     DWORD                           dwStoreProvFlags;
185     PWINECRYPT_CERTSTORE            memStore;
186     HCERTSTOREPROV                  hStoreProv;
187     PFN_CERT_STORE_PROV_CLOSE       provCloseStore;
188     PFN_CERT_STORE_PROV_WRITE_CERT  provWriteCert;
189     PFN_CERT_STORE_PROV_DELETE_CERT provDeleteCert;
190     PFN_CERT_STORE_PROV_WRITE_CRL   provWriteCrl;
191     PFN_CERT_STORE_PROV_DELETE_CRL  provDeleteCrl;
192     PFN_CERT_STORE_PROV_CONTROL     provControl;
193 } WINE_PROVIDERSTORE, *PWINE_PROVIDERSTORE;
194
195 static void CRYPT_InitStore(WINECRYPT_CERTSTORE *store, HCRYPTPROV hCryptProv,
196  DWORD dwFlags, CertStoreType type)
197 {
198     store->ref = 1;
199     store->dwMagic = WINE_CRYPTCERTSTORE_MAGIC;
200     store->type = type;
201     if (!hCryptProv)
202     {
203         hCryptProv = CRYPT_GetDefaultProvider();
204         dwFlags |= CERT_STORE_NO_CRYPT_RELEASE_FLAG;
205     }
206     store->cryptProv = hCryptProv;
207     store->dwOpenFlags = dwFlags;
208 }
209
210 static BOOL CRYPT_MemAddCert(PWINECRYPT_CERTSTORE store, void *cert,
211  void *toReplace, const void **ppStoreContext)
212 {
213     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
214     PCERT_CONTEXT context;
215
216     TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
217
218     context = (PCERT_CONTEXT)ContextList_Add(ms->certs, cert, toReplace);
219     if (context)
220     {
221         context->hCertStore = store;
222         if (ppStoreContext)
223             *ppStoreContext = CertDuplicateCertificateContext(context);
224     }
225     return context ? TRUE : FALSE;
226 }
227
228 static void *CRYPT_MemEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
229 {
230     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
231     void *ret;
232
233     TRACE("(%p, %p)\n", store, pPrev);
234
235     ret = ContextList_Enum(ms->certs, pPrev);
236     if (!ret)
237         SetLastError(CRYPT_E_NOT_FOUND);
238
239     TRACE("returning %p\n", ret);
240     return ret;
241 }
242
243 static BOOL CRYPT_MemDeleteCert(PWINECRYPT_CERTSTORE store, void *pCertContext)
244 {
245     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
246
247     ContextList_Delete(ms->certs, pCertContext);
248     return TRUE;
249 }
250
251 static BOOL CRYPT_MemAddCrl(PWINECRYPT_CERTSTORE store, void *crl,
252  void *toReplace, const void **ppStoreContext)
253 {
254     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
255     PCRL_CONTEXT context;
256
257     TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
258
259     context = (PCRL_CONTEXT)ContextList_Add(ms->crls, crl, toReplace);
260     if (context)
261     {
262         context->hCertStore = store;
263         if (ppStoreContext)
264             *ppStoreContext = CertDuplicateCRLContext(context);
265     }
266     return context ? TRUE : FALSE;
267 }
268
269 static void *CRYPT_MemEnumCrl(PWINECRYPT_CERTSTORE store, void *pPrev)
270 {
271     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
272     void *ret;
273
274     TRACE("(%p, %p)\n", store, pPrev);
275
276     ret = ContextList_Enum(ms->crls, pPrev);
277     if (!ret)
278         SetLastError(CRYPT_E_NOT_FOUND);
279
280     TRACE("returning %p\n", ret);
281     return ret;
282 }
283
284 static BOOL CRYPT_MemDeleteCrl(PWINECRYPT_CERTSTORE store, void *pCrlContext)
285 {
286     WINE_MEMSTORE *ms = (WINE_MEMSTORE *)store;
287
288     ContextList_Delete(ms->crls, pCrlContext);
289     return TRUE;
290 }
291
292 static void CRYPT_MemEmptyStore(PWINE_MEMSTORE store)
293 {
294     ContextList_Empty(store->certs);
295     ContextList_Empty(store->crls);
296 }
297
298 static void WINAPI CRYPT_MemCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
299 {
300     WINE_MEMSTORE *store = (WINE_MEMSTORE *)hCertStore;
301
302     TRACE("(%p, %08lx)\n", store, dwFlags);
303     if (dwFlags)
304         FIXME("Unimplemented flags: %08lx\n", dwFlags);
305
306     ContextList_Free(store->certs);
307     ContextList_Free(store->crls);
308     CryptMemFree(store);
309 }
310
311 static WINECRYPT_CERTSTORE *CRYPT_MemOpenStore(HCRYPTPROV hCryptProv,
312  DWORD dwFlags, const void *pvPara)
313 {
314     PWINE_MEMSTORE store;
315
316     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
317
318     if (dwFlags & CERT_STORE_DELETE_FLAG)
319     {
320         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
321         store = NULL;
322     }
323     else
324     {
325         store = CryptMemAlloc(sizeof(WINE_MEMSTORE));
326         if (store)
327         {
328             memset(store, 0, sizeof(WINE_MEMSTORE));
329             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags, StoreTypeMem);
330             store->hdr.closeStore          = CRYPT_MemCloseStore;
331             store->hdr.certs.addContext    = CRYPT_MemAddCert;
332             store->hdr.certs.enumContext   = CRYPT_MemEnumCert;
333             store->hdr.certs.deleteContext = CRYPT_MemDeleteCert;
334             store->hdr.crls.addContext     = CRYPT_MemAddCrl;
335             store->hdr.crls.enumContext    = CRYPT_MemEnumCrl;
336             store->hdr.crls.deleteContext  = CRYPT_MemDeleteCrl;
337             store->hdr.control             = NULL;
338             store->certs = ContextList_Create(pCertInterface,
339              sizeof(CERT_CONTEXT));
340             store->crls = ContextList_Create(pCRLInterface,
341              sizeof(CRL_CONTEXT));
342         }
343     }
344     return (PWINECRYPT_CERTSTORE)store;
345 }
346
347 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
348 {
349     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
350     PWINE_STORE_LIST_ENTRY entry, next;
351
352     TRACE("(%p, %08lx)\n", store, dwFlags);
353
354     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
355      entry)
356     {
357         TRACE("closing %p\n", entry);
358         CertCloseStore((HCERTSTORE)entry->store, dwFlags);
359         CryptMemFree(entry);
360     }
361     DeleteCriticalSection(&cs->cs);
362     CryptMemFree(cs);
363 }
364
365 static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store,
366  PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize,
367  BOOL addRef)
368 {
369     void *ret = Context_CreateLinkContext(contextSize, child,
370      sizeof(PWINE_STORE_LIST_ENTRY), addRef);
371
372     if (ret)
373         *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize)
374          = storeEntry;
375
376     return ret;
377 }
378
379 static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store,
380  unsigned int contextStoreOffset, void *context, void *toReplace, unsigned int contextSize,
381  void **pChildContext)
382 {
383     BOOL ret;
384     void *childContext = NULL;
385     PWINE_STORE_LIST_ENTRY storeEntry = NULL;
386
387     TRACE("(%p, %d, %p, %p, %d)\n", store, contextStoreOffset, context,
388      toReplace, contextSize);
389
390     ret = FALSE;
391     if (toReplace)
392     {
393         void *existingLinked = Context_GetLinkedContext(toReplace, contextSize);
394         PCONTEXT_STORE contextStore;
395
396         storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace,
397          contextSize);
398         contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store +
399          contextStoreOffset);
400         ret = contextStore->addContext(storeEntry->store, context,
401          existingLinked, (const void **)&childContext);
402     }
403     else
404     {
405         PWINE_STORE_LIST_ENTRY entry, next;
406
407         EnterCriticalSection(&store->cs);
408         LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores,
409          WINE_STORE_LIST_ENTRY, entry)
410         {
411             if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
412             {
413                 PCONTEXT_STORE contextStore = (PCONTEXT_STORE)(
414                  (LPBYTE)entry->store + contextStoreOffset);
415
416                 storeEntry = entry;
417                 ret = contextStore->addContext(entry->store, context, NULL,
418                  (const void **)&childContext);
419                 break;
420             }
421         }
422         LeaveCriticalSection(&store->cs);
423         if (!storeEntry)
424             SetLastError(E_ACCESSDENIED);
425     }
426     *pChildContext = childContext;
427     return ret;
428 }
429
430 /* Advances a collection enumeration by one context, if possible, where
431  * advancing means:
432  * - calling the current store's enumeration function once, and returning
433  *   the enumerated context if one is returned
434  * - moving to the next store if the current store has no more items, and
435  *   recursively calling itself to get the next item.
436  * Returns NULL if the collection contains no more items or on error.
437  * Assumes the collection store's lock is held.
438  */
439 static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store,
440  PWINE_STORE_LIST_ENTRY storeEntry, size_t contextStoreOffset,
441  PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize)
442 {
443     void *ret, *child;
444     struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
445     PCONTEXT_STORE contextStore = (PCONTEXT_STORE)((LPBYTE)storeEntry->store +
446      contextStoreOffset);
447
448     TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
449
450     if (pPrev)
451     {
452         /* Ref-counting funny business: "duplicate" (addref) the child, because
453          * the free(pPrev) below can cause the ref count to become negative.
454          */
455         child = Context_GetLinkedContext(pPrev, contextSize);
456         contextInterface->duplicate(child);
457         child = contextStore->enumContext(storeEntry->store, child);
458         contextInterface->free(pPrev);
459         pPrev = NULL;
460     }
461     else
462         child = storeEntry->store->certs.enumContext(storeEntry->store, NULL);
463     if (child)
464         ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child,
465          contextSize, FALSE);
466     else
467     {
468         if (storeNext)
469             ret = CRYPT_CollectionAdvanceEnum(store, LIST_ENTRY(storeNext,
470              WINE_STORE_LIST_ENTRY, entry), contextStoreOffset,
471              contextInterface, NULL, contextSize);
472         else
473         {
474             SetLastError(CRYPT_E_NOT_FOUND);
475             ret = NULL;
476         }
477     }
478     TRACE("returning %p\n", ret);
479     return ret;
480 }
481
482 static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert,
483  void *toReplace, const void **ppStoreContext)
484 {
485     BOOL ret;
486     void *childContext = NULL;
487     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
488
489     ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs),
490      cert, toReplace, sizeof(CERT_CONTEXT), &childContext);
491     if (ppStoreContext && childContext)
492     {
493         PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
494          Context_GetExtra(childContext, sizeof(CERT_CONTEXT));
495         PCERT_CONTEXT context =
496          CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
497          sizeof(CERT_CONTEXT), TRUE);
498
499         if (context)
500             context->hCertStore = store;
501         *ppStoreContext = context;
502     }
503     CertFreeCertificateContext((PCCERT_CONTEXT)childContext);
504     return ret;
505 }
506
507 static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
508 {
509     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
510     void *ret;
511
512     TRACE("(%p, %p)\n", store, pPrev);
513
514     EnterCriticalSection(&cs->cs);
515     if (pPrev)
516     {
517         PWINE_STORE_LIST_ENTRY storeEntry =
518          *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
519          sizeof(CERT_CONTEXT));
520
521         ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
522          offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, pPrev,
523          sizeof(CERT_CONTEXT));
524     }
525     else
526     {
527         if (!list_empty(&cs->stores))
528         {
529             PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
530              WINE_STORE_LIST_ENTRY, entry);
531
532             ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
533              offsetof(WINECRYPT_CERTSTORE, certs), pCertInterface, NULL,
534              sizeof(CERT_CONTEXT));
535         }
536         else
537         {
538             SetLastError(CRYPT_E_NOT_FOUND);
539             ret = NULL;
540         }
541     }
542     LeaveCriticalSection(&cs->cs);
543     if (ret)
544         ((PCERT_CONTEXT)ret)->hCertStore = store;
545     TRACE("returning %p\n", ret);
546     return ret;
547 }
548
549 static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store,
550  void *pCertContext)
551 {
552     BOOL ret;
553
554     TRACE("(%p, %p)\n", store, pCertContext);
555
556     ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)
557      Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)));
558     return ret;
559 }
560
561 static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
562  void *toReplace, const void **ppStoreContext)
563 {
564     BOOL ret;
565     void *childContext = NULL;
566     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
567
568     ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls),
569      crl, toReplace, sizeof(CRL_CONTEXT), &childContext);
570     if (ppStoreContext && childContext)
571     {
572         PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
573          Context_GetExtra(childContext, sizeof(CRL_CONTEXT));
574         PCRL_CONTEXT context =
575          CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
576          sizeof(CRL_CONTEXT), TRUE);
577
578         if (context)
579             context->hCertStore = store;
580         *ppStoreContext = context;
581     }
582     CertFreeCRLContext((PCCRL_CONTEXT)childContext);
583     return ret;
584 }
585
586 static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
587 {
588     PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
589     void *ret;
590
591     TRACE("(%p, %p)\n", store, pPrev);
592
593     EnterCriticalSection(&cs->cs);
594     if (pPrev)
595     {
596         PWINE_STORE_LIST_ENTRY storeEntry =
597          *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
598          sizeof(CRL_CONTEXT));
599
600         ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
601          offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, pPrev,
602          sizeof(CRL_CONTEXT));
603     }
604     else
605     {
606         if (!list_empty(&cs->stores))
607         {
608             PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
609              WINE_STORE_LIST_ENTRY, entry);
610
611             ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
612              offsetof(WINECRYPT_CERTSTORE, crls), pCRLInterface, NULL,
613              sizeof(CRL_CONTEXT));
614         }
615         else
616         {
617             SetLastError(CRYPT_E_NOT_FOUND);
618             ret = NULL;
619         }
620     }
621     LeaveCriticalSection(&cs->cs);
622     if (ret)
623         ((PCRL_CONTEXT)ret)->hCertStore = store;
624     TRACE("returning %p\n", ret);
625     return ret;
626 }
627
628 static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store,
629  void *pCrlContext)
630 {
631     BOOL ret;
632
633     TRACE("(%p, %p)\n", store, pCrlContext);
634
635     ret = CertDeleteCRLFromStore((PCCRL_CONTEXT)
636      Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)));
637     return ret;
638 }
639
640 static WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
641  DWORD dwFlags, const void *pvPara)
642 {
643     PWINE_COLLECTIONSTORE store;
644
645     if (dwFlags & CERT_STORE_DELETE_FLAG)
646     {
647         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
648         store = NULL;
649     }
650     else
651     {
652         store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
653         if (store)
654         {
655             memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
656             CRYPT_InitStore(&store->hdr, hCryptProv, dwFlags,
657              StoreTypeCollection);
658             store->hdr.closeStore          = CRYPT_CollectionCloseStore;
659             store->hdr.certs.addContext    = CRYPT_CollectionAddCert;
660             store->hdr.certs.enumContext   = CRYPT_CollectionEnumCert;
661             store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert;
662             store->hdr.crls.addContext     = CRYPT_CollectionAddCRL;
663             store->hdr.crls.enumContext    = CRYPT_CollectionEnumCRL;
664             store->hdr.crls.deleteContext  = CRYPT_CollectionDeleteCRL;
665             InitializeCriticalSection(&store->cs);
666             list_init(&store->stores);
667         }
668     }
669     return (PWINECRYPT_CERTSTORE)store;
670 }
671
672 static void WINAPI CRYPT_ProvCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
673 {
674     PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
675
676     TRACE("(%p, %08lx)\n", store, dwFlags);
677
678     if (store->provCloseStore)
679         store->provCloseStore(store->hStoreProv, dwFlags);
680     if (!(store->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG))
681         CertCloseStore(store->memStore, dwFlags);
682     CryptMemFree(store);
683 }
684
685 static BOOL CRYPT_ProvAddCert(PWINECRYPT_CERTSTORE store, void *cert,
686  void *toReplace, const void **ppStoreContext)
687 {
688     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
689     BOOL ret;
690
691     TRACE("(%p, %p, %p, %p)\n", store, cert, toReplace, ppStoreContext);
692
693     if (toReplace)
694         ret = ps->memStore->certs.addContext(ps->memStore, cert, toReplace,
695          (const void **)ppStoreContext);
696     else
697     {
698         if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
699         {
700             SetLastError(ERROR_ACCESS_DENIED);
701             ret = FALSE;
702         }
703         else
704         {
705             ret = TRUE;
706             if (ps->provWriteCert)
707                 ret = ps->provWriteCert(ps->hStoreProv, (PCCERT_CONTEXT)cert,
708                  CERT_STORE_PROV_WRITE_ADD_FLAG);
709             if (ret)
710                 ret = ps->memStore->certs.addContext(ps->memStore, cert, NULL,
711                  (const void **)ppStoreContext);
712         }
713     }
714     /* dirty trick: replace the returned context's hCertStore with
715      * store.
716      */
717     if (ppStoreContext)
718         (*(PCERT_CONTEXT *)ppStoreContext)->hCertStore = store;
719     return ret;
720 }
721
722 static void *CRYPT_ProvEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
723 {
724     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
725     void *ret;
726
727     ret = ps->memStore->certs.enumContext(ps->memStore, pPrev);
728     if (ret)
729     {
730         /* same dirty trick: replace the returned context's hCertStore with
731          * store.
732          */
733         ((PCERT_CONTEXT)ret)->hCertStore = store;
734     }
735     return ret;
736 }
737
738 static BOOL CRYPT_ProvDeleteCert(PWINECRYPT_CERTSTORE store, void *cert)
739 {
740     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
741     BOOL ret = TRUE;
742
743     TRACE("(%p, %p)\n", store, cert);
744
745     if (ps->provDeleteCert)
746         ret = ps->provDeleteCert(ps->hStoreProv, cert, 0);
747     if (ret)
748         ret = ps->memStore->certs.deleteContext(ps->memStore, cert);
749     return ret;
750 }
751
752 static BOOL CRYPT_ProvAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
753  void *toReplace, const void **ppStoreContext)
754 {
755     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
756     BOOL ret;
757
758     TRACE("(%p, %p, %p, %p)\n", store, crl, toReplace, ppStoreContext);
759
760     if (toReplace)
761         ret = ps->memStore->crls.addContext(ps->memStore, crl, toReplace,
762          (const void **)ppStoreContext);
763     else
764     {
765         if (ps->hdr.dwOpenFlags & CERT_STORE_READONLY_FLAG)
766         {
767             SetLastError(ERROR_ACCESS_DENIED);
768             ret = FALSE;
769         }
770         else
771         {
772             ret = TRUE;
773             if (ps->provWriteCrl)
774                 ret = ps->provWriteCrl(ps->hStoreProv, (PCCRL_CONTEXT)crl,
775                  CERT_STORE_PROV_WRITE_ADD_FLAG);
776             if (ret)
777                 ret = ps->memStore->crls.addContext(ps->memStore, crl, NULL,
778                  (const void **)ppStoreContext);
779         }
780     }
781     /* dirty trick: replace the returned context's hCertStore with
782      * store.
783      */
784     if (ppStoreContext)
785         (*(PCRL_CONTEXT *)ppStoreContext)->hCertStore = store;
786     return ret;
787 }
788
789 static void *CRYPT_ProvEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
790 {
791     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
792     void *ret;
793
794     ret = ps->memStore->crls.enumContext(ps->memStore, pPrev);
795     if (ret)
796     {
797         /* same dirty trick: replace the returned context's hCertStore with
798          * store.
799          */
800         ((PCERT_CONTEXT)ret)->hCertStore = store;
801     }
802     return ret;
803 }
804
805 static BOOL CRYPT_ProvDeleteCRL(PWINECRYPT_CERTSTORE store, void *crl)
806 {
807     PWINE_PROVIDERSTORE ps = (PWINE_PROVIDERSTORE)store;
808     BOOL ret = TRUE;
809
810     TRACE("(%p, %p)\n", store, crl);
811
812     if (ps->provDeleteCrl)
813         ret = ps->provDeleteCrl(ps->hStoreProv, crl, 0);
814     if (ret)
815         ret = ps->memStore->crls.deleteContext(ps->memStore, crl);
816     return ret;
817 }
818
819 static BOOL WINAPI CRYPT_ProvControl(HCERTSTORE hCertStore, DWORD dwFlags,
820  DWORD dwCtrlType, void const *pvCtrlPara)
821 {
822     PWINE_PROVIDERSTORE store = (PWINE_PROVIDERSTORE)hCertStore;
823     BOOL ret = TRUE;
824
825     TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
826      pvCtrlPara);
827
828     if (store->provControl)
829         ret = store->provControl(store->hStoreProv, dwFlags, dwCtrlType,
830          pvCtrlPara);
831     return ret;
832 }
833
834 static PWINECRYPT_CERTSTORE CRYPT_ProvCreateStore(HCRYPTPROV hCryptProv,
835  DWORD dwFlags, PWINECRYPT_CERTSTORE memStore, PCERT_STORE_PROV_INFO pProvInfo)
836 {
837     PWINE_PROVIDERSTORE ret = (PWINE_PROVIDERSTORE)CryptMemAlloc(
838      sizeof(WINE_PROVIDERSTORE));
839
840     if (ret)
841     {
842         CRYPT_InitStore(&ret->hdr, hCryptProv, dwFlags,
843          StoreTypeProvider);
844         ret->dwStoreProvFlags = pProvInfo->dwStoreProvFlags;
845         if (ret->dwStoreProvFlags & CERT_STORE_PROV_EXTERNAL_FLAG)
846         {
847             CertCloseStore(memStore, 0);
848             ret->memStore = NULL;
849         }
850         else
851             ret->memStore = memStore;
852         ret->hStoreProv = pProvInfo->hStoreProv;
853         ret->hdr.closeStore = CRYPT_ProvCloseStore;
854         ret->hdr.certs.addContext = CRYPT_ProvAddCert;
855         ret->hdr.certs.enumContext = CRYPT_ProvEnumCert;
856         ret->hdr.certs.deleteContext = CRYPT_ProvDeleteCert;
857         ret->hdr.crls.addContext = CRYPT_ProvAddCRL;
858         ret->hdr.crls.enumContext = CRYPT_ProvEnumCRL;
859         ret->hdr.crls.deleteContext = CRYPT_ProvDeleteCRL;
860         ret->hdr.control = CRYPT_ProvControl;
861         if (pProvInfo->cStoreProvFunc > CERT_STORE_PROV_CLOSE_FUNC)
862             ret->provCloseStore =
863              pProvInfo->rgpvStoreProvFunc[CERT_STORE_PROV_CLOSE_FUNC];
864         else
865             ret->provCloseStore = NULL;
866         if (pProvInfo->cStoreProvFunc >
867          CERT_STORE_PROV_WRITE_CERT_FUNC)
868             ret->provWriteCert = pProvInfo->rgpvStoreProvFunc[
869              CERT_STORE_PROV_WRITE_CERT_FUNC];
870         else
871             ret->provWriteCert = NULL;
872         if (pProvInfo->cStoreProvFunc >
873          CERT_STORE_PROV_DELETE_CERT_FUNC)
874             ret->provDeleteCert = pProvInfo->rgpvStoreProvFunc[
875              CERT_STORE_PROV_DELETE_CERT_FUNC];
876         else
877             ret->provDeleteCert = NULL;
878         if (pProvInfo->cStoreProvFunc >
879          CERT_STORE_PROV_WRITE_CRL_FUNC)
880             ret->provWriteCrl = pProvInfo->rgpvStoreProvFunc[
881              CERT_STORE_PROV_WRITE_CRL_FUNC];
882         else
883             ret->provWriteCert = NULL;
884         if (pProvInfo->cStoreProvFunc >
885          CERT_STORE_PROV_DELETE_CRL_FUNC)
886             ret->provDeleteCrl = pProvInfo->rgpvStoreProvFunc[
887              CERT_STORE_PROV_DELETE_CRL_FUNC];
888         else
889             ret->provDeleteCert = NULL;
890         if (pProvInfo->cStoreProvFunc >
891          CERT_STORE_PROV_CONTROL_FUNC)
892             ret->provControl = pProvInfo->rgpvStoreProvFunc[
893              CERT_STORE_PROV_CONTROL_FUNC];
894         else
895             ret->provControl = NULL;
896     }
897     return (PWINECRYPT_CERTSTORE)ret;
898 }
899
900 static PWINECRYPT_CERTSTORE CRYPT_ProvOpenStore(LPCSTR lpszStoreProvider,
901  DWORD dwEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags, const void *pvPara)
902 {
903     static HCRYPTOIDFUNCSET set = NULL;
904     PFN_CERT_DLL_OPEN_STORE_PROV_FUNC provOpenFunc;
905     HCRYPTOIDFUNCADDR hFunc;
906     PWINECRYPT_CERTSTORE ret = NULL;
907
908     if (!set)
909         set = CryptInitOIDFunctionSet(CRYPT_OID_OPEN_STORE_PROV_FUNC, 0);
910     CryptGetOIDFunctionAddress(set, dwEncodingType, lpszStoreProvider, 0,
911      (void **)&provOpenFunc, &hFunc);
912     if (provOpenFunc)
913     {
914         CERT_STORE_PROV_INFO provInfo = { 0 };
915
916         provInfo.cbSize = sizeof(provInfo);
917         if (dwFlags & CERT_STORE_DELETE_FLAG)
918             provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
919              dwFlags, pvPara, NULL, &provInfo);
920         else
921         {
922             HCERTSTORE memStore;
923
924             memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
925              CERT_STORE_CREATE_NEW_FLAG, NULL);
926             if (memStore)
927             {
928                 if (provOpenFunc(lpszStoreProvider, dwEncodingType, hCryptProv,
929                  dwFlags, pvPara, memStore, &provInfo))
930                     ret = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
931                      &provInfo);
932                 else
933                     CertCloseStore(memStore, 0);
934             }
935         }
936         CryptFreeOIDFunctionAddress(hFunc, 0);
937     }
938     else
939         SetLastError(ERROR_FILE_NOT_FOUND);
940     return ret;
941 }
942
943 static void CRYPT_HashToStr(LPBYTE hash, LPWSTR asciiHash)
944 {
945     static const WCHAR fmt[] = { '%','0','2','X',0 };
946     DWORD i;
947
948     assert(hash);
949     assert(asciiHash);
950
951     for (i = 0; i < 20; i++)
952         wsprintfW(asciiHash + i * 2, fmt, hash[i]);
953 }
954
955 static const WCHAR CertsW[] = { 'C','e','r','t','i','f','i','c','a','t','e','s',
956  0 };
957 static const WCHAR CRLsW[] = { 'C','R','L','s',0 };
958 static const WCHAR CTLsW[] = { 'C','T','L','s',0 };
959 static const WCHAR BlobW[] = { 'B','l','o','b',0 };
960
961 static void CRYPT_RegReadSerializedFromReg(PWINE_REGSTOREINFO store, HKEY key,
962  DWORD contextType)
963 {
964     LONG rc;
965     DWORD index = 0;
966     WCHAR subKeyName[MAX_PATH];
967
968     do {
969         DWORD size = sizeof(subKeyName) / sizeof(WCHAR);
970
971         rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
972          NULL);
973         if (!rc)
974         {
975             HKEY subKey;
976
977             rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
978             if (!rc)
979             {
980                 LPBYTE buf = NULL;
981
982                 size = 0;
983                 rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, NULL, &size);
984                 if (!rc)
985                     buf = CryptMemAlloc(size);
986                 if (buf)
987                 {
988                     rc = RegQueryValueExW(subKey, BlobW, NULL, NULL, buf,
989                      &size);
990                     if (!rc)
991                     {
992                         const void *context;
993                         DWORD addedType;
994
995                         TRACE("Adding cert with hash %s\n",
996                          debugstr_w(subKeyName));
997                         context = CRYPT_ReadSerializedElement(buf, size,
998                          contextType, &addedType);
999                         if (context)
1000                         {
1001                             const WINE_CONTEXT_INTERFACE *contextInterface;
1002                             BYTE hash[20];
1003
1004                             switch (addedType)
1005                             {
1006                             case CERT_STORE_CERTIFICATE_CONTEXT:
1007                                 contextInterface = &gCertInterface;
1008                                 break;
1009                             case CERT_STORE_CRL_CONTEXT:
1010                                 contextInterface = &gCRLInterface;
1011                                 break;
1012                             case CERT_STORE_CTL_CONTEXT:
1013                                 contextInterface = &gCTLInterface;
1014                                 break;
1015                             default:
1016                                 contextInterface = NULL;
1017                             }
1018                             if (contextInterface)
1019                             {
1020                                 size = sizeof(hash);
1021                                 if (contextInterface->getProp(context,
1022                                  CERT_HASH_PROP_ID, hash, &size))
1023                                 {
1024                                     WCHAR asciiHash[20 * 2 + 1];
1025
1026                                     CRYPT_HashToStr(hash, asciiHash);
1027                                     TRACE("comparing %s\n",
1028                                      debugstr_w(asciiHash));
1029                                     TRACE("with %s\n", debugstr_w(subKeyName));
1030                                     if (!lstrcmpW(asciiHash, subKeyName))
1031                                     {
1032                                         TRACE("hash matches, adding\n");
1033                                         contextInterface->addContextToStore(
1034                                          store->memStore, context,
1035                                          CERT_STORE_ADD_REPLACE_EXISTING, NULL);
1036                                     }
1037                                     else
1038                                         TRACE("hash doesn't match, ignoring\n");
1039                                 }
1040                                 contextInterface->free(context);
1041                             }
1042                         }
1043                     }
1044                     CryptMemFree(buf);
1045                 }
1046                 RegCloseKey(subKey);
1047             }
1048             /* Ignore intermediate errors, continue enumerating */
1049             rc = ERROR_SUCCESS;
1050         }
1051     } while (!rc);
1052 }
1053
1054 static void CRYPT_RegReadFromReg(PWINE_REGSTOREINFO store)
1055 {
1056     static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1057     static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
1058      CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
1059     DWORD i;
1060
1061     for (i = 0; i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1062     {
1063         HKEY key;
1064         LONG rc;
1065
1066         rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
1067          &key, NULL);
1068         if (!rc)
1069         {
1070             CRYPT_RegReadSerializedFromReg(store, key, contextFlags[i]);
1071             RegCloseKey(key);
1072         }
1073     }
1074 }
1075
1076 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
1077 static BOOL CRYPT_WriteSerializedToReg(HKEY key, LPBYTE hash, LPBYTE buf,
1078  DWORD len)
1079 {
1080     WCHAR asciiHash[20 * 2 + 1];
1081     LONG rc;
1082     HKEY subKey;
1083     BOOL ret;
1084
1085     CRYPT_HashToStr(hash, asciiHash);
1086     rc = RegCreateKeyExW(key, asciiHash, 0, NULL, 0, KEY_ALL_ACCESS, NULL,
1087      &subKey, NULL);
1088     if (!rc)
1089     {
1090         rc = RegSetValueExW(subKey, BlobW, 0, REG_BINARY, buf, len);
1091         RegCloseKey(subKey);
1092     }
1093     if (!rc)
1094         ret = TRUE;
1095     else
1096     {
1097         SetLastError(rc);
1098         ret = FALSE;
1099     }
1100     return ret;
1101 }
1102
1103 static BOOL CRYPT_SerializeContextsToReg(HKEY key,
1104  const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
1105 {
1106     const void *context = NULL;
1107     BOOL ret;
1108
1109     do {
1110         context = contextInterface->enumContextsInStore(memStore, context);
1111         if (context)
1112         {
1113             BYTE hash[20];
1114             DWORD hashSize = sizeof(hash);
1115
1116             ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
1117              &hashSize);
1118             if (ret)
1119             {
1120                 DWORD size = 0;
1121                 LPBYTE buf = NULL;
1122
1123                 ret = contextInterface->serialize(context, 0, NULL, &size);
1124                 if (size)
1125                     buf = CryptMemAlloc(size);
1126                 if (buf)
1127                 {
1128                     ret = contextInterface->serialize(context, 0, buf, &size);
1129                     if (ret)
1130                         ret = CRYPT_WriteSerializedToReg(key, hash, buf, size);
1131                 }
1132                 CryptMemFree(buf);
1133             }
1134         }
1135         else
1136             ret = TRUE;
1137     } while (ret && context != NULL);
1138     if (context)
1139         contextInterface->free(context);
1140     return ret;
1141 }
1142
1143 static BOOL CRYPT_RegWriteToReg(PWINE_REGSTOREINFO store)
1144 {
1145     static const WCHAR *subKeys[] = { CertsW, CRLsW, CTLsW };
1146     static const WINE_CONTEXT_INTERFACE *interfaces[] = { &gCertInterface,
1147      &gCRLInterface, &gCTLInterface };
1148     struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete,
1149      NULL };
1150     BOOL ret = TRUE;
1151     DWORD i;
1152
1153     for (i = 0; ret && i < sizeof(subKeys) / sizeof(subKeys[0]); i++)
1154     {
1155         HKEY key;
1156         LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
1157          KEY_ALL_ACCESS, NULL, &key, NULL);
1158
1159         if (!rc)
1160         {
1161             if (listToDelete[i])
1162             {
1163                 PWINE_HASH_TO_DELETE toDelete, next;
1164                 WCHAR asciiHash[20 * 2 + 1];
1165
1166                 EnterCriticalSection(&store->cs);
1167                 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
1168                  WINE_HASH_TO_DELETE, entry)
1169                 {
1170                     LONG rc;
1171
1172                     CRYPT_HashToStr(toDelete->hash, asciiHash);
1173                     TRACE("Removing %s\n", debugstr_w(asciiHash));
1174                     rc = RegDeleteKeyW(key, asciiHash);
1175                     if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
1176                     {
1177                         SetLastError(rc);
1178                         ret = FALSE;
1179                     }
1180                     list_remove(&toDelete->entry);
1181                     CryptMemFree(toDelete);
1182                 }
1183                 LeaveCriticalSection(&store->cs);
1184             }
1185             ret = CRYPT_SerializeContextsToReg(key, interfaces[i],
1186              store->memStore);
1187             RegCloseKey(key);
1188         }
1189         else
1190         {
1191             SetLastError(rc);
1192             ret = FALSE;
1193         }
1194     }
1195     return ret;
1196 }
1197
1198 /* If force is true or the registry store is dirty, writes the contents of the
1199  * store to the registry.
1200  */
1201 static BOOL CRYPT_RegFlushStore(PWINE_REGSTOREINFO store, BOOL force)
1202 {
1203     BOOL ret;
1204
1205     TRACE("(%p, %d)\n", store, force);
1206
1207     if (store->dirty || force)
1208         ret = CRYPT_RegWriteToReg(store);
1209     else
1210         ret = TRUE;
1211     return ret;
1212 }
1213
1214 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
1215 {
1216     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1217
1218     TRACE("(%p, %08lx)\n", store, dwFlags);
1219     if (dwFlags)
1220         FIXME("Unimplemented flags: %08lx\n", dwFlags);
1221
1222     CRYPT_RegFlushStore(store, FALSE);
1223     RegCloseKey(store->key);
1224     DeleteCriticalSection(&store->cs);
1225     CryptMemFree(store);
1226 }
1227
1228 static BOOL WINAPI CRYPT_RegWriteContext(PWINE_REGSTOREINFO store,
1229  const void *context, DWORD dwFlags)
1230 {
1231     BOOL ret;
1232
1233     if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG)
1234     {
1235         store->dirty = TRUE;
1236         ret = TRUE;
1237     }
1238     else
1239         ret = FALSE;
1240     return ret;
1241 }
1242
1243 static BOOL CRYPT_RegDeleteContext(PWINE_REGSTOREINFO store,
1244  struct list *deleteList, const void *context,
1245  PCWINE_CONTEXT_INTERFACE contextInterface)
1246 {
1247     BOOL ret;
1248
1249     if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG)
1250     {
1251         SetLastError(ERROR_ACCESS_DENIED);
1252         ret = FALSE;
1253     }
1254     else
1255     {
1256         PWINE_HASH_TO_DELETE toDelete =
1257          CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
1258
1259         if (toDelete)
1260         {
1261             DWORD size = sizeof(toDelete->hash);
1262
1263             ret = contextInterface->getProp(context, CERT_HASH_PROP_ID,
1264              toDelete->hash, &size);
1265             if (ret)
1266             {
1267                 EnterCriticalSection(&store->cs);
1268                 list_add_tail(deleteList, &toDelete->entry);
1269                 LeaveCriticalSection(&store->cs);
1270             }
1271             else
1272             {
1273                 CryptMemFree(toDelete);
1274                 ret = FALSE;
1275             }
1276         }
1277         else
1278             ret = FALSE;
1279         if (ret)
1280             store->dirty = TRUE;
1281     }
1282     return ret;
1283 }
1284
1285 static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore,
1286  PCCERT_CONTEXT cert, DWORD dwFlags)
1287 {
1288     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1289
1290     TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
1291
1292     return CRYPT_RegWriteContext(store, cert, dwFlags);
1293 }
1294
1295 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
1296  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
1297 {
1298     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1299
1300     TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
1301
1302     return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext,
1303      pCertInterface);
1304 }
1305
1306 static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore,
1307  PCCRL_CONTEXT crl, DWORD dwFlags)
1308 {
1309     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1310
1311     TRACE("(%p, %p, %ld)\n", hCertStore, crl, dwFlags);
1312
1313     return CRYPT_RegWriteContext(store, crl, dwFlags);
1314 }
1315
1316 static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore,
1317  PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
1318 {
1319     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1320
1321     TRACE("(%p, %p, %08lx)\n", store, pCrlContext, dwFlags);
1322
1323     return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext,
1324      pCRLInterface);
1325 }
1326
1327 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
1328  DWORD dwCtrlType, void const *pvCtrlPara)
1329 {
1330     PWINE_REGSTOREINFO store = (PWINE_REGSTOREINFO)hCertStore;
1331     BOOL ret;
1332
1333     TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
1334      pvCtrlPara);
1335
1336     switch (dwCtrlType)
1337     {
1338     case CERT_STORE_CTRL_RESYNC:
1339         CRYPT_RegFlushStore(store, FALSE);
1340         CRYPT_MemEmptyStore((PWINE_MEMSTORE)store->memStore);
1341         CRYPT_RegReadFromReg(store);
1342         ret = TRUE;
1343         break;
1344     case CERT_STORE_CTRL_COMMIT:
1345         ret = CRYPT_RegFlushStore(store,
1346          dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
1347         break;
1348     default:
1349         FIXME("%ld: stub\n", dwCtrlType);
1350         ret = FALSE;
1351     }
1352     return ret;
1353 }
1354
1355 /* Copied from shlwapi's SHDeleteKeyW, and reformatted to match this file. */
1356 static DWORD CRYPT_RecurseDeleteKey(HKEY hKey, LPCWSTR lpszSubKey)
1357 {
1358     DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
1359     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
1360     HKEY hSubKey = 0;
1361
1362     TRACE("(hkey=%p,%s)\n", hKey, debugstr_w(lpszSubKey));
1363
1364     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
1365     if (!dwRet)
1366     {
1367         /* Find how many subkeys there are */
1368         dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
1369          &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
1370         if (!dwRet)
1371         {
1372             dwMaxSubkeyLen++;
1373             if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
1374             {
1375                 /* Name too big: alloc a buffer for it */
1376                 lpszName = CryptMemAlloc(dwMaxSubkeyLen*sizeof(WCHAR));
1377             }
1378
1379             if (!lpszName)
1380                 dwRet = ERROR_NOT_ENOUGH_MEMORY;
1381             else
1382             {
1383                 /* Recursively delete all the subkeys */
1384                 for (i = 0; i < dwKeyCount && !dwRet; i++)
1385                 {
1386                     dwSize = dwMaxSubkeyLen;
1387                     dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL,
1388                      NULL, NULL, NULL);
1389                     if (!dwRet)
1390                         dwRet = CRYPT_RecurseDeleteKey(hSubKey, lpszName);
1391                 }
1392
1393                 if (lpszName != szNameBuf)
1394                 {
1395                     /* Free buffer if allocated */
1396                     CryptMemFree(lpszName);
1397                 }
1398             }
1399         }
1400
1401         RegCloseKey(hSubKey);
1402         if (!dwRet)
1403             dwRet = RegDeleteKeyW(hKey, lpszSubKey);
1404     }
1405     return dwRet;
1406 }
1407
1408 static void *regProvFuncs[] = {
1409     CRYPT_RegCloseStore,
1410     NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
1411     CRYPT_RegWriteCert,
1412     CRYPT_RegDeleteCert,
1413     NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
1414     NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
1415     CRYPT_RegWriteCRL,
1416     CRYPT_RegDeleteCRL,
1417     NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
1418     NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
1419     NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
1420     NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
1421     NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
1422     CRYPT_RegControl,
1423 };
1424
1425 static WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv,
1426  DWORD dwFlags, const void *pvPara)
1427 {
1428     PWINECRYPT_CERTSTORE store = NULL;
1429
1430     TRACE("(%ld, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
1431
1432     if (dwFlags & CERT_STORE_DELETE_FLAG)
1433     {
1434         DWORD rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CertsW);
1435
1436         if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1437             rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CRLsW);
1438         if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
1439             rc = CRYPT_RecurseDeleteKey((HKEY)pvPara, CTLsW);
1440         if (rc == ERROR_NO_MORE_ITEMS)
1441             rc = ERROR_SUCCESS;
1442         SetLastError(rc);
1443     }
1444     else
1445     {
1446         HKEY key;
1447
1448         if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
1449          GetCurrentProcess(), (LPHANDLE)&key,
1450          dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
1451          TRUE, 0))
1452         {
1453             PWINECRYPT_CERTSTORE memStore;
1454
1455             memStore = CRYPT_MemOpenStore(hCryptProv, dwFlags, NULL);
1456             if (memStore)
1457             {
1458                 PWINE_REGSTOREINFO regInfo = CryptMemAlloc(
1459                  sizeof(WINE_REGSTOREINFO));
1460
1461                 if (regInfo)
1462                 {
1463                     CERT_STORE_PROV_INFO provInfo = { 0 };
1464
1465                     regInfo->dwOpenFlags = dwFlags;
1466                     regInfo->cryptProv = hCryptProv;
1467                     regInfo->memStore = memStore;
1468                     regInfo->key = key;
1469                     InitializeCriticalSection(&regInfo->cs);
1470                     list_init(&regInfo->certsToDelete);
1471                     list_init(&regInfo->crlsToDelete);
1472                     CRYPT_RegReadFromReg(regInfo);
1473                     regInfo->dirty = FALSE;
1474                     provInfo.cbSize = sizeof(provInfo);
1475                     provInfo.cStoreProvFunc = sizeof(regProvFuncs) /
1476                      sizeof(regProvFuncs[0]);
1477                     provInfo.rgpvStoreProvFunc = regProvFuncs;
1478                     provInfo.hStoreProv = regInfo;
1479                     store = CRYPT_ProvCreateStore(hCryptProv, dwFlags, memStore,
1480                      &provInfo);
1481                 }
1482             }
1483         }
1484     }
1485     TRACE("returning %p\n", store);
1486     return store;
1487 }
1488
1489 /* FIXME: this isn't complete for the Root store, in which the top-level
1490  * self-signed CA certs reside.  Adding a cert to the Root store should present
1491  * the user with a dialog indicating the consequences of doing so, and asking
1492  * the user to confirm whether the cert should be added.
1493  */
1494 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreW(HCRYPTPROV hCryptProv,
1495  DWORD dwFlags, const void *pvPara)
1496 {
1497     static const WCHAR fmt[] = { '%','s','\\','%','s',0 };
1498     LPCWSTR storeName = (LPCWSTR)pvPara;
1499     LPWSTR storePath;
1500     PWINECRYPT_CERTSTORE store = NULL;
1501     HKEY root;
1502     LPCWSTR base;
1503     BOOL ret;
1504
1505     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1506      debugstr_w((LPCWSTR)pvPara));
1507
1508     if (!pvPara)
1509     {
1510         SetLastError(E_INVALIDARG);
1511         return NULL;
1512     }
1513
1514     ret = TRUE;
1515     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1516     {
1517     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1518         root = HKEY_LOCAL_MACHINE;
1519         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1520         break;
1521     case CERT_SYSTEM_STORE_CURRENT_USER:
1522         root = HKEY_CURRENT_USER;
1523         base = CERT_LOCAL_MACHINE_SYSTEM_STORE_REGPATH;
1524         break;
1525     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1526         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1527          * SystemCertificates
1528          */
1529         FIXME("CERT_SYSTEM_STORE_CURRENT_SERVICE, %s: stub\n",
1530          debugstr_w(storeName));
1531         return NULL;
1532     case CERT_SYSTEM_STORE_SERVICES:
1533         /* hklm\Software\Microsoft\Cryptography\Services\servicename\
1534          * SystemCertificates
1535          */
1536         FIXME("CERT_SYSTEM_STORE_SERVICES, %s: stub\n",
1537          debugstr_w(storeName));
1538         return NULL;
1539     case CERT_SYSTEM_STORE_USERS:
1540         /* hku\user sid\Software\Microsoft\SystemCertificates */
1541         FIXME("CERT_SYSTEM_STORE_USERS, %s: stub\n",
1542          debugstr_w(storeName));
1543         return NULL;
1544     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1545         root = HKEY_CURRENT_USER;
1546         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1547         break;
1548     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1549         root = HKEY_LOCAL_MACHINE;
1550         base = CERT_GROUP_POLICY_SYSTEM_STORE_REGPATH;
1551         break;
1552     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1553         /* hklm\Software\Microsoft\EnterpriseCertificates */
1554         FIXME("CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE, %s: stub\n",
1555          debugstr_w(storeName));
1556         return NULL;
1557     default:
1558         SetLastError(E_INVALIDARG);
1559         return NULL;
1560     }
1561
1562     storePath = CryptMemAlloc((lstrlenW(base) + lstrlenW(storeName) + 2) *
1563      sizeof(WCHAR));
1564     if (storePath)
1565     {
1566         LONG rc;
1567         HKEY key;
1568         REGSAM sam = dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ :
1569             KEY_ALL_ACCESS;
1570
1571         wsprintfW(storePath, fmt, base, storeName);
1572         if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
1573             rc = RegOpenKeyExW(root, storePath, 0, sam, &key);
1574         else
1575         {
1576             DWORD disp;
1577
1578             rc = RegCreateKeyExW(root, storePath, 0, NULL, 0, sam, NULL,
1579                                  &key, &disp);
1580             if (!rc && dwFlags & CERT_STORE_CREATE_NEW_FLAG &&
1581                 disp == REG_OPENED_EXISTING_KEY)
1582             {
1583                 RegCloseKey(key);
1584                 rc = ERROR_FILE_EXISTS;
1585             }
1586         }
1587         if (!rc)
1588         {
1589             store = CRYPT_RegOpenStore(hCryptProv, dwFlags, key);
1590             RegCloseKey(key);
1591         }
1592         else
1593             SetLastError(rc);
1594         CryptMemFree(storePath);
1595     }
1596     return store;
1597 }
1598
1599 static PWINECRYPT_CERTSTORE CRYPT_SysRegOpenStoreA(HCRYPTPROV hCryptProv,
1600  DWORD dwFlags, const void *pvPara)
1601 {
1602     int len;
1603     PWINECRYPT_CERTSTORE ret = NULL;
1604
1605     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1606      debugstr_a((LPCSTR)pvPara));
1607
1608     if (!pvPara)
1609     {
1610         SetLastError(ERROR_FILE_NOT_FOUND);
1611         return NULL;
1612     }
1613     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1614     if (len)
1615     {
1616         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1617
1618         if (storeName)
1619         {
1620             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1621             ret = CRYPT_SysRegOpenStoreW(hCryptProv, dwFlags, storeName);
1622             CryptMemFree(storeName);
1623         }
1624     }
1625     return ret;
1626 }
1627
1628 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreW(HCRYPTPROV hCryptProv,
1629  DWORD dwFlags, const void *pvPara)
1630 {
1631     HCERTSTORE store = 0;
1632     BOOL ret;
1633
1634     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1635      debugstr_w((LPCWSTR)pvPara));
1636
1637     if (!pvPara)
1638     {
1639         SetLastError(ERROR_FILE_NOT_FOUND);
1640         return NULL;
1641     }
1642     /* This returns a different error than system registry stores if the
1643      * location is invalid.
1644      */
1645     switch (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK)
1646     {
1647     case CERT_SYSTEM_STORE_LOCAL_MACHINE:
1648     case CERT_SYSTEM_STORE_CURRENT_USER:
1649     case CERT_SYSTEM_STORE_CURRENT_SERVICE:
1650     case CERT_SYSTEM_STORE_SERVICES:
1651     case CERT_SYSTEM_STORE_USERS:
1652     case CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY:
1653     case CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY:
1654     case CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE:
1655         ret = TRUE;
1656         break;
1657     default:
1658         SetLastError(ERROR_FILE_NOT_FOUND);
1659         ret = FALSE;
1660     }
1661     if (ret)
1662     {
1663         HCERTSTORE regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W,
1664          0, hCryptProv, dwFlags, pvPara);
1665
1666         if (regStore)
1667         {
1668             store = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
1669              CERT_STORE_CREATE_NEW_FLAG, NULL);
1670             CertAddStoreToCollection(store, regStore,
1671              dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1672              CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1673             CertCloseStore(regStore, 0);
1674             /* CERT_SYSTEM_STORE_CURRENT_USER returns both the HKCU and HKLM
1675              * stores.
1676              */
1677             if ((dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK) ==
1678              CERT_SYSTEM_STORE_CURRENT_USER)
1679             {
1680                 dwFlags &= ~CERT_SYSTEM_STORE_CURRENT_USER;
1681                 dwFlags |= CERT_SYSTEM_STORE_LOCAL_MACHINE;
1682                 regStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_REGISTRY_W, 0,
1683                  hCryptProv, dwFlags, pvPara);
1684                 if (regStore)
1685                 {
1686                     CertAddStoreToCollection(store, regStore,
1687                      dwFlags & CERT_STORE_READONLY_FLAG ? 0 :
1688                      CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 0);
1689                     CertCloseStore(regStore, 0);
1690                 }
1691             }
1692         }
1693     }
1694     return (PWINECRYPT_CERTSTORE)store;
1695 }
1696
1697 static PWINECRYPT_CERTSTORE CRYPT_SysOpenStoreA(HCRYPTPROV hCryptProv,
1698  DWORD dwFlags, const void *pvPara)
1699 {
1700     int len;
1701     PWINECRYPT_CERTSTORE ret = NULL;
1702
1703     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1704      debugstr_a((LPCSTR)pvPara));
1705
1706     if (!pvPara)
1707     {
1708         SetLastError(ERROR_FILE_NOT_FOUND);
1709         return NULL;
1710     }
1711     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1712     if (len)
1713     {
1714         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1715
1716         if (storeName)
1717         {
1718             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1719             ret = CRYPT_SysOpenStoreW(hCryptProv, dwFlags, storeName);
1720             CryptMemFree(storeName);
1721         }
1722     }
1723     return ret;
1724 }
1725
1726 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1727  DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1728  const void* pvPara)
1729 {
1730     WINECRYPT_CERTSTORE *hcs;
1731     StoreOpenFunc openFunc = NULL;
1732
1733     TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1734           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1735
1736     if (!HIWORD(lpszStoreProvider))
1737     {
1738         switch (LOWORD(lpszStoreProvider))
1739         {
1740         case (int)CERT_STORE_PROV_MEMORY:
1741             openFunc = CRYPT_MemOpenStore;
1742             break;
1743         case (int)CERT_STORE_PROV_REG:
1744             openFunc = CRYPT_RegOpenStore;
1745             break;
1746         case (int)CERT_STORE_PROV_COLLECTION:
1747             openFunc = CRYPT_CollectionOpenStore;
1748             break;
1749         case (int)CERT_STORE_PROV_SYSTEM_A:
1750             openFunc = CRYPT_SysOpenStoreA;
1751             break;
1752         case (int)CERT_STORE_PROV_SYSTEM_W:
1753             openFunc = CRYPT_SysOpenStoreW;
1754             break;
1755         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1756             openFunc = CRYPT_SysRegOpenStoreA;
1757             break;
1758         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1759             openFunc = CRYPT_SysRegOpenStoreW;
1760             break;
1761         default:
1762             if (LOWORD(lpszStoreProvider))
1763                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1764         }
1765     }
1766     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1767         openFunc = CRYPT_MemOpenStore;
1768     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1769         openFunc = CRYPT_SysOpenStoreW;
1770     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1771         openFunc = CRYPT_CollectionOpenStore;
1772     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1773         openFunc = CRYPT_SysRegOpenStoreW;
1774     else
1775     {
1776         FIXME("unimplemented type %s\n", lpszStoreProvider);
1777         openFunc = NULL;
1778     }
1779
1780     if (!openFunc)
1781         hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
1782          hCryptProv, dwFlags, pvPara);
1783     else
1784         hcs = openFunc(hCryptProv, dwFlags, pvPara);
1785     return (HCERTSTORE)hcs;
1786 }
1787
1788 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1789  LPCSTR szSubSystemProtocol)
1790 {
1791     if (!szSubSystemProtocol)
1792     {
1793         SetLastError(E_INVALIDARG);
1794         return 0;
1795     }
1796     return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
1797      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1798 }
1799
1800 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1801  LPCWSTR szSubSystemProtocol)
1802 {
1803     if (!szSubSystemProtocol)
1804     {
1805         SetLastError(E_INVALIDARG);
1806         return 0;
1807     }
1808     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
1809      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1810 }
1811
1812 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1813              DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1814 {
1815     FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore, 
1816           dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1817     return TRUE;
1818 }
1819
1820 DWORD CertStore_GetAccessState(HCERTSTORE hCertStore)
1821 {
1822     DWORD state = 0;
1823
1824     if (hCertStore)
1825     {
1826         PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1827
1828         if (store->type != StoreTypeMem &&
1829          !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1830             state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1831     }
1832     return state;
1833 }
1834
1835 #define CertContext_CopyProperties(to, from) \
1836  Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
1837
1838 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
1839  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
1840  PCCERT_CONTEXT *ppStoreContext)
1841 {
1842     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1843     BOOL ret = TRUE;
1844     PCCERT_CONTEXT toAdd = NULL, existing = NULL;
1845
1846     TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
1847      dwAddDisposition, ppStoreContext);
1848
1849     /* Weird case to pass a test */
1850     if (dwAddDisposition == 0)
1851     {
1852         SetLastError(STATUS_ACCESS_VIOLATION);
1853         return FALSE;
1854     }
1855     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
1856     {
1857         BYTE hashToAdd[20];
1858         DWORD size = sizeof(hashToAdd);
1859
1860         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
1861          hashToAdd, &size);
1862         if (ret)
1863         {
1864             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
1865
1866             existing = CertFindCertificateInStore(hCertStore,
1867              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
1868              NULL);
1869         }
1870     }
1871
1872     switch (dwAddDisposition)
1873     {
1874     case CERT_STORE_ADD_ALWAYS:
1875         toAdd = CertDuplicateCertificateContext(pCertContext);
1876         break;
1877     case CERT_STORE_ADD_NEW:
1878         if (existing)
1879         {
1880             TRACE("found matching certificate, not adding\n");
1881             SetLastError(CRYPT_E_EXISTS);
1882             ret = FALSE;
1883         }
1884         else
1885             toAdd = CertDuplicateCertificateContext(pCertContext);
1886         break;
1887     case CERT_STORE_ADD_REPLACE_EXISTING:
1888         toAdd = CertDuplicateCertificateContext(pCertContext);
1889         break;
1890     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
1891         toAdd = CertDuplicateCertificateContext(pCertContext);
1892         if (existing)
1893             CertContext_CopyProperties(toAdd, existing);
1894         break;
1895     case CERT_STORE_ADD_USE_EXISTING:
1896         if (existing)
1897             CertContext_CopyProperties(existing, pCertContext);
1898         break;
1899     default:
1900         FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
1901         ret = FALSE;
1902     }
1903
1904     if (toAdd)
1905     {
1906         if (store)
1907             ret = store->certs.addContext(store, (void *)toAdd,
1908              (void *)existing, (const void **)ppStoreContext);
1909         else if (ppStoreContext)
1910             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
1911         CertFreeCertificateContext(toAdd);
1912     }
1913     CertFreeCertificateContext(existing);
1914
1915     TRACE("returning %d\n", ret);
1916     return ret;
1917 }
1918
1919 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
1920  PCCERT_CONTEXT pPrev)
1921 {
1922     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1923     PCCERT_CONTEXT ret;
1924
1925     TRACE("(%p, %p)\n", hCertStore, pPrev);
1926     if (!hCertStore)
1927         ret = NULL;
1928     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1929         ret = NULL;
1930     else
1931         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
1932     return ret;
1933 }
1934
1935 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
1936 {
1937     BOOL ret;
1938
1939     TRACE("(%p)\n", pCertContext);
1940
1941     if (!pCertContext)
1942         ret = TRUE;
1943     else if (!pCertContext->hCertStore)
1944     {
1945         ret = TRUE;
1946         CertFreeCertificateContext(pCertContext);
1947     }
1948     else
1949     {
1950         PWINECRYPT_CERTSTORE hcs =
1951          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
1952
1953         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1954             ret = FALSE;
1955         else
1956             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
1957         CertFreeCertificateContext(pCertContext);
1958     }
1959     return ret;
1960 }
1961
1962 #define CrlContext_CopyProperties(to, from) \
1963  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
1964
1965 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
1966  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
1967  PCCRL_CONTEXT* ppStoreContext)
1968 {
1969     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1970     BOOL ret = TRUE;
1971     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
1972
1973     TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCrlContext,
1974      dwAddDisposition, ppStoreContext);
1975
1976     /* Weird case to pass a test */
1977     if (dwAddDisposition == 0)
1978     {
1979         SetLastError(STATUS_ACCESS_VIOLATION);
1980         return FALSE;
1981     }
1982     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
1983     {
1984         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
1985          pCrlContext, NULL);
1986     }
1987
1988     switch (dwAddDisposition)
1989     {
1990     case CERT_STORE_ADD_ALWAYS:
1991         toAdd = CertDuplicateCRLContext(pCrlContext);
1992         break;
1993     case CERT_STORE_ADD_NEW:
1994         if (existing)
1995         {
1996             TRACE("found matching CRL, not adding\n");
1997             SetLastError(CRYPT_E_EXISTS);
1998             ret = FALSE;
1999         }
2000         else
2001             toAdd = CertDuplicateCRLContext(pCrlContext);
2002         break;
2003     case CERT_STORE_ADD_NEWER:
2004         if (existing)
2005         {
2006             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
2007              &pCrlContext->pCrlInfo->ThisUpdate);
2008
2009             if (newer < 0)
2010                 toAdd = CertDuplicateCRLContext(pCrlContext);
2011             else
2012             {
2013                 TRACE("existing CRL is newer, not adding\n");
2014                 SetLastError(CRYPT_E_EXISTS);
2015                 ret = FALSE;
2016             }
2017         }
2018         else
2019             toAdd = CertDuplicateCRLContext(pCrlContext);
2020         break;
2021     case CERT_STORE_ADD_REPLACE_EXISTING:
2022         toAdd = CertDuplicateCRLContext(pCrlContext);
2023         break;
2024     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
2025         toAdd = CertDuplicateCRLContext(pCrlContext);
2026         if (existing)
2027             CrlContext_CopyProperties(toAdd, existing);
2028         break;
2029     case CERT_STORE_ADD_USE_EXISTING:
2030         if (existing)
2031             CrlContext_CopyProperties(existing, pCrlContext);
2032         break;
2033     default:
2034         FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
2035         ret = FALSE;
2036     }
2037
2038     if (toAdd)
2039     {
2040         if (store)
2041             ret = store->crls.addContext(store, (void *)toAdd,
2042              (void *)existing, (const void **)ppStoreContext);
2043         else if (ppStoreContext)
2044             *ppStoreContext = CertDuplicateCRLContext(toAdd);
2045         CertFreeCRLContext(toAdd);
2046     }
2047     CertFreeCRLContext(existing);
2048
2049     TRACE("returning %d\n", ret);
2050     return ret;
2051 }
2052
2053 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2054 {
2055     BOOL ret;
2056
2057     TRACE("(%p)\n", pCrlContext);
2058
2059     if (!pCrlContext)
2060         ret = TRUE;
2061     else if (!pCrlContext->hCertStore)
2062     {
2063         ret = TRUE;
2064         CertFreeCRLContext(pCrlContext);
2065     }
2066     else
2067     {
2068         PWINECRYPT_CERTSTORE hcs =
2069          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
2070
2071         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2072             ret = FALSE;
2073         else
2074             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
2075         CertFreeCRLContext(pCrlContext);
2076     }
2077     return ret;
2078 }
2079
2080 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2081  PCCRL_CONTEXT pPrev)
2082 {
2083     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2084     PCCRL_CONTEXT ret;
2085
2086     TRACE("(%p, %p)\n", hCertStore, pPrev);
2087     if (!hCertStore)
2088         ret = NULL;
2089     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2090         ret = NULL;
2091     else
2092         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
2093     return ret;
2094 }
2095
2096 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2097   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2098 {
2099     FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2100      cbCtlEncoded);
2101     return NULL;
2102 }
2103
2104 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2105  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2106  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2107 {
2108     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2109      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2110      ppCtlContext);
2111     return FALSE;
2112 }
2113
2114 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2115  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2116  PCCTL_CONTEXT* ppStoreContext)
2117 {
2118     FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2119      dwAddDisposition, ppStoreContext);
2120     return TRUE;
2121 }
2122
2123 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
2124 {
2125     FIXME("(%p): stub\n", pCtlContext );
2126     return pCtlContext;
2127 }
2128
2129 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2130 {
2131     FIXME("(%p): stub\n", pCtlContext );
2132     return TRUE;
2133 }
2134
2135 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2136 {
2137     FIXME("(%p): stub\n", pCtlContext);
2138     return TRUE;
2139 }
2140
2141 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2142  PCCTL_CONTEXT pPrev)
2143 {
2144     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2145     return NULL;
2146 }
2147
2148 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
2149 {
2150     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2151
2152     TRACE("(%p)\n", hCertStore);
2153
2154     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
2155         InterlockedIncrement(&hcs->ref);
2156     return hCertStore;
2157 }
2158
2159 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2160 {
2161     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2162
2163     TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2164
2165     if( ! hCertStore )
2166         return TRUE;
2167
2168     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2169         return FALSE;
2170
2171     if (InterlockedDecrement(&hcs->ref) == 0)
2172     {
2173         TRACE("%p's ref count is 0, freeing\n", hcs);
2174         hcs->dwMagic = 0;
2175         if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2176             CryptReleaseContext(hcs->cryptProv, 0);
2177         hcs->closeStore(hcs, dwFlags);
2178     }
2179     else
2180         TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2181     return TRUE;
2182 }
2183
2184 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2185  DWORD dwCtrlType, void const *pvCtrlPara)
2186 {
2187     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2188     BOOL ret;
2189
2190     TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2191      pvCtrlPara);
2192
2193     if (!hcs)
2194         ret = FALSE;
2195     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2196         ret = FALSE;
2197     else
2198     {
2199         if (hcs->control)
2200             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2201         else
2202             ret = TRUE;
2203     }
2204     return ret;
2205 }
2206
2207 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
2208  DWORD dwPropId)
2209 {
2210     FIXME("(%p, %ld): stub\n", pCTLContext, dwPropId);
2211     return 0;
2212 }
2213
2214 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2215  DWORD dwPropId, void *pvData, DWORD *pcbData)
2216 {
2217     FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2218     return FALSE;
2219 }
2220
2221 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2222  DWORD dwPropId, DWORD dwFlags, const void *pvData)
2223 {
2224     FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2225      pvData);
2226     return FALSE;
2227 }
2228
2229 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2230  HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2231 {
2232     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2233     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2234     PWINE_STORE_LIST_ENTRY entry;
2235     BOOL ret;
2236
2237     TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2238      dwUpdateFlags, dwPriority);
2239
2240     if (!collection || !sibling)
2241         return TRUE;
2242     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2243     {
2244         SetLastError(E_INVALIDARG);
2245         return FALSE;
2246     }
2247     if (collection->hdr.type != StoreTypeCollection)
2248     {
2249         SetLastError(E_INVALIDARG);
2250         return FALSE;
2251     }
2252     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2253     {
2254         SetLastError(E_INVALIDARG);
2255         return FALSE;
2256     }
2257
2258     entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2259     if (entry)
2260     {
2261         InterlockedIncrement(&sibling->ref);
2262         TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2263         entry->store = sibling;
2264         entry->dwUpdateFlags = dwUpdateFlags;
2265         entry->dwPriority = dwPriority;
2266         list_init(&entry->entry);
2267         TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2268         EnterCriticalSection(&collection->cs);
2269         if (dwPriority)
2270         {
2271             PWINE_STORE_LIST_ENTRY cursor;
2272             BOOL added = FALSE;
2273
2274             LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2275              WINE_STORE_LIST_ENTRY, entry)
2276             {
2277                 if (cursor->dwPriority < dwPriority)
2278                 {
2279                     list_add_before(&cursor->entry, &entry->entry);
2280                     added = TRUE;
2281                     break;
2282                 }
2283             }
2284             if (!added)
2285                 list_add_tail(&collection->stores, &entry->entry);
2286         }
2287         else
2288             list_add_tail(&collection->stores, &entry->entry);
2289         LeaveCriticalSection(&collection->cs);
2290         ret = TRUE;
2291     }
2292     else
2293         ret = FALSE;
2294     return ret;
2295 }
2296
2297 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2298  HCERTSTORE hSiblingStore)
2299 {
2300     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2301     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2302     PWINE_STORE_LIST_ENTRY store, next;
2303
2304     TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2305
2306     if (!collection || !sibling)
2307         return;
2308     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2309     {
2310         SetLastError(E_INVALIDARG);
2311         return;
2312     }
2313     if (collection->hdr.type != StoreTypeCollection)
2314         return;
2315     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2316     {
2317         SetLastError(E_INVALIDARG);
2318         return;
2319     }
2320     EnterCriticalSection(&collection->cs);
2321     LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2322      WINE_STORE_LIST_ENTRY, entry)
2323     {
2324         if (store->store == sibling)
2325         {
2326             list_remove(&store->entry);
2327             CertCloseStore(store->store, 0);
2328             CryptMemFree(store);
2329             break;
2330         }
2331     }
2332     LeaveCriticalSection(&collection->cs);
2333 }