dinput8: DirectInput8Create rewrite.
[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 static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
1727  DWORD dwFlags, const void *pvPara)
1728 {
1729     FIXME("(%ld, %08lx, %s): stub\n", hCryptProv, dwFlags,
1730      debugstr_w((LPCWSTR)pvPara));
1731     return NULL;
1732 }
1733
1734 static PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
1735  DWORD dwFlags, const void *pvPara)
1736 {
1737     int len;
1738     PWINECRYPT_CERTSTORE ret = NULL;
1739
1740     TRACE("(%ld, %08lx, %s)\n", hCryptProv, dwFlags,
1741      debugstr_a((LPCSTR)pvPara));
1742
1743     if (!pvPara)
1744     {
1745         SetLastError(ERROR_FILE_NOT_FOUND);
1746         return NULL;
1747     }
1748     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
1749     if (len)
1750     {
1751         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
1752
1753         if (storeName)
1754         {
1755             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
1756             ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName);
1757             CryptMemFree(storeName);
1758         }
1759     }
1760     return ret;
1761 }
1762
1763 static PWINECRYPT_CERTSTORE CRYPT_PhysOpenStoreW(HCRYPTPROV hCryptProv,
1764  DWORD dwFlags, const void *pvPara)
1765 {
1766     if (dwFlags & CERT_SYSTEM_STORE_RELOCATE_FLAG)
1767         FIXME("(%ld, %08lx, %p): stub\n", hCryptProv, dwFlags, pvPara);
1768     else
1769         FIXME("(%ld, %08lx, %s): stub\n", hCryptProv, dwFlags,
1770          debugstr_w((LPCWSTR)pvPara));
1771     return NULL;
1772 }
1773
1774 HCERTSTORE WINAPI CertOpenStore(LPCSTR lpszStoreProvider,
1775  DWORD dwMsgAndCertEncodingType, HCRYPTPROV hCryptProv, DWORD dwFlags,
1776  const void* pvPara)
1777 {
1778     WINECRYPT_CERTSTORE *hcs;
1779     StoreOpenFunc openFunc = NULL;
1780
1781     TRACE("(%s, %08lx, %08lx, %08lx, %p)\n", debugstr_a(lpszStoreProvider),
1782           dwMsgAndCertEncodingType, hCryptProv, dwFlags, pvPara);
1783
1784     if (!HIWORD(lpszStoreProvider))
1785     {
1786         switch (LOWORD(lpszStoreProvider))
1787         {
1788         case (int)CERT_STORE_PROV_MEMORY:
1789             openFunc = CRYPT_MemOpenStore;
1790             break;
1791         case (int)CERT_STORE_PROV_REG:
1792             openFunc = CRYPT_RegOpenStore;
1793             break;
1794         case (int)CERT_STORE_PROV_FILENAME_A:
1795             openFunc = CRYPT_FileNameOpenStoreA;
1796             break;
1797         case (int)CERT_STORE_PROV_FILENAME_W:
1798             openFunc = CRYPT_FileNameOpenStoreW;
1799             break;
1800         case (int)CERT_STORE_PROV_COLLECTION:
1801             openFunc = CRYPT_CollectionOpenStore;
1802             break;
1803         case (int)CERT_STORE_PROV_SYSTEM_A:
1804             openFunc = CRYPT_SysOpenStoreA;
1805             break;
1806         case (int)CERT_STORE_PROV_SYSTEM_W:
1807             openFunc = CRYPT_SysOpenStoreW;
1808             break;
1809         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_A:
1810             openFunc = CRYPT_SysRegOpenStoreA;
1811             break;
1812         case (int)CERT_STORE_PROV_SYSTEM_REGISTRY_W:
1813             openFunc = CRYPT_SysRegOpenStoreW;
1814             break;
1815         case (int)CERT_STORE_PROV_PHYSICAL_W:
1816             openFunc = CRYPT_PhysOpenStoreW;
1817             break;
1818         default:
1819             if (LOWORD(lpszStoreProvider))
1820                 FIXME("unimplemented type %d\n", LOWORD(lpszStoreProvider));
1821         }
1822     }
1823     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_MEMORY))
1824         openFunc = CRYPT_MemOpenStore;
1825     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM))
1826         openFunc = CRYPT_SysOpenStoreW;
1827     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_COLLECTION))
1828         openFunc = CRYPT_CollectionOpenStore;
1829     else if (!strcasecmp(lpszStoreProvider, sz_CERT_STORE_PROV_SYSTEM_REGISTRY))
1830         openFunc = CRYPT_SysRegOpenStoreW;
1831     else
1832     {
1833         FIXME("unimplemented type %s\n", lpszStoreProvider);
1834         openFunc = NULL;
1835     }
1836
1837     if (!openFunc)
1838         hcs = CRYPT_ProvOpenStore(lpszStoreProvider, dwMsgAndCertEncodingType,
1839          hCryptProv, dwFlags, pvPara);
1840     else
1841         hcs = openFunc(hCryptProv, dwFlags, pvPara);
1842     return (HCERTSTORE)hcs;
1843 }
1844
1845 HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV hProv,
1846  LPCSTR szSubSystemProtocol)
1847 {
1848     if (!szSubSystemProtocol)
1849     {
1850         SetLastError(E_INVALIDARG);
1851         return 0;
1852     }
1853     return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
1854      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1855 }
1856
1857 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV hProv,
1858  LPCWSTR szSubSystemProtocol)
1859 {
1860     if (!szSubSystemProtocol)
1861     {
1862         SetLastError(E_INVALIDARG);
1863         return 0;
1864     }
1865     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
1866      CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
1867 }
1868
1869 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1870              DWORD dwSaveAs, DWORD dwSaveTo, void* pvSaveToPara, DWORD dwFlags)
1871 {
1872     FIXME("(%p,%ld,%ld,%ld,%p,%08lx) stub!\n", hCertStore, 
1873           dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1874     return TRUE;
1875 }
1876
1877 DWORD CertStore_GetAccessState(HCERTSTORE hCertStore)
1878 {
1879     DWORD state = 0;
1880
1881     if (hCertStore)
1882     {
1883         PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1884
1885         if (store->type != StoreTypeMem &&
1886          !(store->dwOpenFlags & CERT_STORE_READONLY_FLAG))
1887             state |= CERT_ACCESS_STATE_WRITE_PERSIST_FLAG;
1888     }
1889     return state;
1890 }
1891
1892 #define CertContext_CopyProperties(to, from) \
1893  Context_CopyProperties((to), (from), sizeof(CERT_CONTEXT))
1894
1895 BOOL WINAPI CertAddCertificateContextToStore(HCERTSTORE hCertStore,
1896  PCCERT_CONTEXT pCertContext, DWORD dwAddDisposition,
1897  PCCERT_CONTEXT *ppStoreContext)
1898 {
1899     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
1900     BOOL ret = TRUE;
1901     PCCERT_CONTEXT toAdd = NULL, existing = NULL;
1902
1903     TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCertContext,
1904      dwAddDisposition, ppStoreContext);
1905
1906     /* Weird case to pass a test */
1907     if (dwAddDisposition == 0)
1908     {
1909         SetLastError(STATUS_ACCESS_VIOLATION);
1910         return FALSE;
1911     }
1912     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
1913     {
1914         BYTE hashToAdd[20];
1915         DWORD size = sizeof(hashToAdd);
1916
1917         ret = CertGetCertificateContextProperty(pCertContext, CERT_HASH_PROP_ID,
1918          hashToAdd, &size);
1919         if (ret)
1920         {
1921             CRYPT_HASH_BLOB blob = { sizeof(hashToAdd), hashToAdd };
1922
1923             existing = CertFindCertificateInStore(hCertStore,
1924              pCertContext->dwCertEncodingType, 0, CERT_FIND_SHA1_HASH, &blob,
1925              NULL);
1926         }
1927     }
1928
1929     switch (dwAddDisposition)
1930     {
1931     case CERT_STORE_ADD_ALWAYS:
1932         toAdd = CertDuplicateCertificateContext(pCertContext);
1933         break;
1934     case CERT_STORE_ADD_NEW:
1935         if (existing)
1936         {
1937             TRACE("found matching certificate, not adding\n");
1938             SetLastError(CRYPT_E_EXISTS);
1939             ret = FALSE;
1940         }
1941         else
1942             toAdd = CertDuplicateCertificateContext(pCertContext);
1943         break;
1944     case CERT_STORE_ADD_REPLACE_EXISTING:
1945         toAdd = CertDuplicateCertificateContext(pCertContext);
1946         break;
1947     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
1948         toAdd = CertDuplicateCertificateContext(pCertContext);
1949         if (existing)
1950             CertContext_CopyProperties(toAdd, existing);
1951         break;
1952     case CERT_STORE_ADD_USE_EXISTING:
1953         if (existing)
1954             CertContext_CopyProperties(existing, pCertContext);
1955         break;
1956     default:
1957         FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
1958         ret = FALSE;
1959     }
1960
1961     if (toAdd)
1962     {
1963         if (store)
1964             ret = store->certs.addContext(store, (void *)toAdd,
1965              (void *)existing, (const void **)ppStoreContext);
1966         else if (ppStoreContext)
1967             *ppStoreContext = CertDuplicateCertificateContext(toAdd);
1968         CertFreeCertificateContext(toAdd);
1969     }
1970     CertFreeCertificateContext(existing);
1971
1972     TRACE("returning %d\n", ret);
1973     return ret;
1974 }
1975
1976 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore,
1977  PCCERT_CONTEXT pPrev)
1978 {
1979     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
1980     PCCERT_CONTEXT ret;
1981
1982     TRACE("(%p, %p)\n", hCertStore, pPrev);
1983     if (!hCertStore)
1984         ret = NULL;
1985     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
1986         ret = NULL;
1987     else
1988         ret = (PCCERT_CONTEXT)hcs->certs.enumContext(hcs, (void *)pPrev);
1989     return ret;
1990 }
1991
1992 BOOL WINAPI CertDeleteCertificateFromStore(PCCERT_CONTEXT pCertContext)
1993 {
1994     BOOL ret;
1995
1996     TRACE("(%p)\n", pCertContext);
1997
1998     if (!pCertContext)
1999         ret = TRUE;
2000     else if (!pCertContext->hCertStore)
2001     {
2002         ret = TRUE;
2003         CertFreeCertificateContext(pCertContext);
2004     }
2005     else
2006     {
2007         PWINECRYPT_CERTSTORE hcs =
2008          (PWINECRYPT_CERTSTORE)pCertContext->hCertStore;
2009
2010         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2011             ret = FALSE;
2012         else
2013             ret = hcs->certs.deleteContext(hcs, (void *)pCertContext);
2014         CertFreeCertificateContext(pCertContext);
2015     }
2016     return ret;
2017 }
2018
2019 #define CrlContext_CopyProperties(to, from) \
2020  Context_CopyProperties((to), (from), sizeof(CRL_CONTEXT))
2021
2022 BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE hCertStore,
2023  PCCRL_CONTEXT pCrlContext, DWORD dwAddDisposition,
2024  PCCRL_CONTEXT* ppStoreContext)
2025 {
2026     PWINECRYPT_CERTSTORE store = (PWINECRYPT_CERTSTORE)hCertStore;
2027     BOOL ret = TRUE;
2028     PCCRL_CONTEXT toAdd = NULL, existing = NULL;
2029
2030     TRACE("(%p, %p, %08lx, %p)\n", hCertStore, pCrlContext,
2031      dwAddDisposition, ppStoreContext);
2032
2033     /* Weird case to pass a test */
2034     if (dwAddDisposition == 0)
2035     {
2036         SetLastError(STATUS_ACCESS_VIOLATION);
2037         return FALSE;
2038     }
2039     if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
2040     {
2041         existing = CertFindCRLInStore(hCertStore, 0, 0, CRL_FIND_EXISTING,
2042          pCrlContext, NULL);
2043     }
2044
2045     switch (dwAddDisposition)
2046     {
2047     case CERT_STORE_ADD_ALWAYS:
2048         toAdd = CertDuplicateCRLContext(pCrlContext);
2049         break;
2050     case CERT_STORE_ADD_NEW:
2051         if (existing)
2052         {
2053             TRACE("found matching CRL, not adding\n");
2054             SetLastError(CRYPT_E_EXISTS);
2055             ret = FALSE;
2056         }
2057         else
2058             toAdd = CertDuplicateCRLContext(pCrlContext);
2059         break;
2060     case CERT_STORE_ADD_NEWER:
2061         if (existing)
2062         {
2063             LONG newer = CompareFileTime(&existing->pCrlInfo->ThisUpdate,
2064              &pCrlContext->pCrlInfo->ThisUpdate);
2065
2066             if (newer < 0)
2067                 toAdd = CertDuplicateCRLContext(pCrlContext);
2068             else
2069             {
2070                 TRACE("existing CRL is newer, not adding\n");
2071                 SetLastError(CRYPT_E_EXISTS);
2072                 ret = FALSE;
2073             }
2074         }
2075         else
2076             toAdd = CertDuplicateCRLContext(pCrlContext);
2077         break;
2078     case CERT_STORE_ADD_REPLACE_EXISTING:
2079         toAdd = CertDuplicateCRLContext(pCrlContext);
2080         break;
2081     case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
2082         toAdd = CertDuplicateCRLContext(pCrlContext);
2083         if (existing)
2084             CrlContext_CopyProperties(toAdd, existing);
2085         break;
2086     case CERT_STORE_ADD_USE_EXISTING:
2087         if (existing)
2088             CrlContext_CopyProperties(existing, pCrlContext);
2089         break;
2090     default:
2091         FIXME("Unimplemented add disposition %ld\n", dwAddDisposition);
2092         ret = FALSE;
2093     }
2094
2095     if (toAdd)
2096     {
2097         if (store)
2098             ret = store->crls.addContext(store, (void *)toAdd,
2099              (void *)existing, (const void **)ppStoreContext);
2100         else if (ppStoreContext)
2101             *ppStoreContext = CertDuplicateCRLContext(toAdd);
2102         CertFreeCRLContext(toAdd);
2103     }
2104     CertFreeCRLContext(existing);
2105
2106     TRACE("returning %d\n", ret);
2107     return ret;
2108 }
2109
2110 BOOL WINAPI CertDeleteCRLFromStore(PCCRL_CONTEXT pCrlContext)
2111 {
2112     BOOL ret;
2113
2114     TRACE("(%p)\n", pCrlContext);
2115
2116     if (!pCrlContext)
2117         ret = TRUE;
2118     else if (!pCrlContext->hCertStore)
2119     {
2120         ret = TRUE;
2121         CertFreeCRLContext(pCrlContext);
2122     }
2123     else
2124     {
2125         PWINECRYPT_CERTSTORE hcs =
2126          (PWINECRYPT_CERTSTORE)pCrlContext->hCertStore;
2127
2128         if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2129             ret = FALSE;
2130         else
2131             ret = hcs->crls.deleteContext(hcs, (void *)pCrlContext);
2132         CertFreeCRLContext(pCrlContext);
2133     }
2134     return ret;
2135 }
2136
2137 PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE hCertStore,
2138  PCCRL_CONTEXT pPrev)
2139 {
2140     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2141     PCCRL_CONTEXT ret;
2142
2143     TRACE("(%p, %p)\n", hCertStore, pPrev);
2144     if (!hCertStore)
2145         ret = NULL;
2146     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2147         ret = NULL;
2148     else
2149         ret = (PCCRL_CONTEXT)hcs->crls.enumContext(hcs, (void *)pPrev);
2150     return ret;
2151 }
2152
2153 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwCertEncodingType,
2154   const BYTE* pbCtlEncoded, DWORD cbCtlEncoded)
2155 {
2156     FIXME("(%08lx, %p, %08lx): stub\n", dwCertEncodingType, pbCtlEncoded,
2157      cbCtlEncoded);
2158     return NULL;
2159 }
2160
2161 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
2162  DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
2163  DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
2164 {
2165     FIXME("(%p, %08lx, %p, %ld, %08lx, %p): stub\n", hCertStore,
2166      dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
2167      ppCtlContext);
2168     return FALSE;
2169 }
2170
2171 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
2172  PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
2173  PCCTL_CONTEXT* ppStoreContext)
2174 {
2175     FIXME("(%p, %p, %08lx, %p): stub\n", hCertStore, pCtlContext,
2176      dwAddDisposition, ppStoreContext);
2177     return TRUE;
2178 }
2179
2180 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
2181 {
2182     FIXME("(%p): stub\n", pCtlContext );
2183     return pCtlContext;
2184 }
2185
2186 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCtlContext)
2187 {
2188     FIXME("(%p): stub\n", pCtlContext );
2189     return TRUE;
2190 }
2191
2192 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
2193 {
2194     FIXME("(%p): stub\n", pCtlContext);
2195     return TRUE;
2196 }
2197
2198 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
2199  PCCTL_CONTEXT pPrev)
2200 {
2201     FIXME("(%p, %p): stub\n", hCertStore, pPrev);
2202     return NULL;
2203 }
2204
2205 HCERTSTORE WINAPI CertDuplicateStore(HCERTSTORE hCertStore)
2206 {
2207     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2208
2209     TRACE("(%p)\n", hCertStore);
2210
2211     if (hcs && hcs->dwMagic == WINE_CRYPTCERTSTORE_MAGIC)
2212         InterlockedIncrement(&hcs->ref);
2213     return hCertStore;
2214 }
2215
2216 BOOL WINAPI CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
2217 {
2218     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *) hCertStore;
2219
2220     TRACE("(%p, %08lx)\n", hCertStore, dwFlags);
2221
2222     if( ! hCertStore )
2223         return TRUE;
2224
2225     if ( hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC )
2226         return FALSE;
2227
2228     if (InterlockedDecrement(&hcs->ref) == 0)
2229     {
2230         TRACE("%p's ref count is 0, freeing\n", hcs);
2231         hcs->dwMagic = 0;
2232         if (!(hcs->dwOpenFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
2233             CryptReleaseContext(hcs->cryptProv, 0);
2234         hcs->closeStore(hcs, dwFlags);
2235     }
2236     else
2237         TRACE("%p's ref count is %ld\n", hcs, hcs->ref);
2238     return TRUE;
2239 }
2240
2241 BOOL WINAPI CertControlStore(HCERTSTORE hCertStore, DWORD dwFlags,
2242  DWORD dwCtrlType, void const *pvCtrlPara)
2243 {
2244     WINECRYPT_CERTSTORE *hcs = (WINECRYPT_CERTSTORE *)hCertStore;
2245     BOOL ret;
2246
2247     TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
2248      pvCtrlPara);
2249
2250     if (!hcs)
2251         ret = FALSE;
2252     else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2253         ret = FALSE;
2254     else
2255     {
2256         if (hcs->control)
2257             ret = hcs->control(hCertStore, dwFlags, dwCtrlType, pvCtrlPara);
2258         else
2259             ret = TRUE;
2260     }
2261     return ret;
2262 }
2263
2264 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
2265  DWORD dwPropId)
2266 {
2267     FIXME("(%p, %ld): stub\n", pCTLContext, dwPropId);
2268     return 0;
2269 }
2270
2271 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2272  DWORD dwPropId, void *pvData, DWORD *pcbData)
2273 {
2274     FIXME("(%p, %ld, %p, %p): stub\n", pCTLContext, dwPropId, pvData, pcbData);
2275     return FALSE;
2276 }
2277
2278 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
2279  DWORD dwPropId, DWORD dwFlags, const void *pvData)
2280 {
2281     FIXME("(%p, %ld, %08lx, %p): stub\n", pCTLContext, dwPropId, dwFlags,
2282      pvData);
2283     return FALSE;
2284 }
2285
2286 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
2287  HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
2288 {
2289     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2290     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2291     PWINE_STORE_LIST_ENTRY entry;
2292     BOOL ret;
2293
2294     TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
2295      dwUpdateFlags, dwPriority);
2296
2297     if (!collection || !sibling)
2298         return TRUE;
2299     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2300     {
2301         SetLastError(E_INVALIDARG);
2302         return FALSE;
2303     }
2304     if (collection->hdr.type != StoreTypeCollection)
2305     {
2306         SetLastError(E_INVALIDARG);
2307         return FALSE;
2308     }
2309     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2310     {
2311         SetLastError(E_INVALIDARG);
2312         return FALSE;
2313     }
2314
2315     entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
2316     if (entry)
2317     {
2318         InterlockedIncrement(&sibling->ref);
2319         TRACE("sibling %p's ref count is %ld\n", sibling, sibling->ref);
2320         entry->store = sibling;
2321         entry->dwUpdateFlags = dwUpdateFlags;
2322         entry->dwPriority = dwPriority;
2323         list_init(&entry->entry);
2324         TRACE("%p: adding %p, priority %ld\n", collection, entry, dwPriority);
2325         EnterCriticalSection(&collection->cs);
2326         if (dwPriority)
2327         {
2328             PWINE_STORE_LIST_ENTRY cursor;
2329             BOOL added = FALSE;
2330
2331             LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
2332              WINE_STORE_LIST_ENTRY, entry)
2333             {
2334                 if (cursor->dwPriority < dwPriority)
2335                 {
2336                     list_add_before(&cursor->entry, &entry->entry);
2337                     added = TRUE;
2338                     break;
2339                 }
2340             }
2341             if (!added)
2342                 list_add_tail(&collection->stores, &entry->entry);
2343         }
2344         else
2345             list_add_tail(&collection->stores, &entry->entry);
2346         LeaveCriticalSection(&collection->cs);
2347         ret = TRUE;
2348     }
2349     else
2350         ret = FALSE;
2351     return ret;
2352 }
2353
2354 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
2355  HCERTSTORE hSiblingStore)
2356 {
2357     PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
2358     WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
2359     PWINE_STORE_LIST_ENTRY store, next;
2360
2361     TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
2362
2363     if (!collection || !sibling)
2364         return;
2365     if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2366     {
2367         SetLastError(E_INVALIDARG);
2368         return;
2369     }
2370     if (collection->hdr.type != StoreTypeCollection)
2371         return;
2372     if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
2373     {
2374         SetLastError(E_INVALIDARG);
2375         return;
2376     }
2377     EnterCriticalSection(&collection->cs);
2378     LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
2379      WINE_STORE_LIST_ENTRY, entry)
2380     {
2381         if (store->store == sibling)
2382         {
2383             list_remove(&store->entry);
2384             CertCloseStore(store->store, 0);
2385             CryptMemFree(store);
2386             break;
2387         }
2388     }
2389     LeaveCriticalSection(&collection->cs);
2390 }