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