2 * Copyright 2004-2007 Juan Lang
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "wine/debug.h"
23 #include "crypt32_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
27 typedef struct _WINE_STORE_LIST_ENTRY
29 WINECRYPT_CERTSTORE
*store
;
33 } WINE_STORE_LIST_ENTRY
;
35 typedef struct _WINE_COLLECTIONSTORE
37 WINECRYPT_CERTSTORE hdr
;
40 } WINE_COLLECTIONSTORE
;
42 static void Collection_addref(WINECRYPT_CERTSTORE
*store
)
44 LONG ref
= InterlockedIncrement(&store
->ref
);
45 TRACE("ref = %d\n", ref
);
48 static DWORD
Collection_release(WINECRYPT_CERTSTORE
*store
, DWORD flags
)
50 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
51 WINE_STORE_LIST_ENTRY
*entry
, *next
;
55 FIXME("Unimplemented flags %x\n", flags
);
57 ref
= InterlockedDecrement(&cs
->hdr
.ref
);
58 TRACE("(%p) ref=%d\n", store
, ref
);
62 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &cs
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
64 TRACE("closing %p\n", entry
);
65 entry
->store
->vtbl
->release(entry
->store
, flags
);
68 cs
->cs
.DebugInfo
->Spare
[0] = 0;
69 DeleteCriticalSection(&cs
->cs
);
70 CRYPT_FreeStore(store
);
74 static void Collection_releaseContext(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
76 /* We don't cache context links, so just free them. */
77 Context_Free(context
);
80 static context_t
*CRYPT_CollectionCreateContextFromChild(WINE_COLLECTIONSTORE
*store
,
81 WINE_STORE_LIST_ENTRY
*storeEntry
, context_t
*child
)
85 ret
= child
->vtbl
->clone(child
, &store
->hdr
, TRUE
);
89 ret
->u
.ptr
= storeEntry
;
93 static BOOL
CRYPT_CollectionAddContext(WINE_COLLECTIONSTORE
*store
,
94 unsigned int contextFuncsOffset
, context_t
*context
, context_t
*toReplace
,
95 context_t
**pChildContext
)
98 context_t
*childContext
= NULL
;
99 WINE_STORE_LIST_ENTRY
*storeEntry
= NULL
;
101 TRACE("(%p, %d, %p, %p)\n", store
, contextFuncsOffset
, context
, toReplace
);
106 context_t
*existingLinked
= toReplace
->linked
;
107 CONTEXT_FUNCS
*contextFuncs
;
109 storeEntry
= toReplace
->u
.ptr
;
110 contextFuncs
= (CONTEXT_FUNCS
*)((LPBYTE
)storeEntry
->store
->vtbl
+
112 ret
= contextFuncs
->addContext(storeEntry
->store
, context
,
113 existingLinked
, &childContext
, TRUE
);
117 WINE_STORE_LIST_ENTRY
*entry
, *next
;
119 EnterCriticalSection(&store
->cs
);
120 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &store
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
122 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
124 CONTEXT_FUNCS
*contextFuncs
= (CONTEXT_FUNCS
*)(
125 (LPBYTE
)entry
->store
->vtbl
+ contextFuncsOffset
);
128 ret
= contextFuncs
->addContext(entry
->store
, context
, NULL
, &childContext
, TRUE
);
132 LeaveCriticalSection(&store
->cs
);
134 SetLastError(E_ACCESSDENIED
);
136 *pChildContext
= childContext
;
140 /* Advances a collection enumeration by one context, if possible, where
142 * - calling the current store's enumeration function once, and returning
143 * the enumerated context if one is returned
144 * - moving to the next store if the current store has no more items, and
145 * recursively calling itself to get the next item.
146 * Returns NULL if the collection contains no more items or on error.
147 * Assumes the collection store's lock is held.
149 static context_t
*CRYPT_CollectionAdvanceEnum(WINE_COLLECTIONSTORE
*store
,
150 WINE_STORE_LIST_ENTRY
*storeEntry
, const CONTEXT_FUNCS
*contextFuncs
,
153 context_t
*child
, *ret
;
154 struct list
*storeNext
= list_next(&store
->stores
, &storeEntry
->entry
);
156 TRACE("(%p, %p, %p)\n", store
, storeEntry
, prev
);
160 /* Ref-counting funny business: "duplicate" (addref) the child, because
161 * the free(pPrev) below can cause the ref count to become negative.
163 child
= prev
->linked
;
164 Context_AddRef(child
);
165 child
= contextFuncs
->enumContext(storeEntry
->store
, child
);
166 Context_Release(prev
);
171 child
= contextFuncs
->enumContext(storeEntry
->store
, NULL
);
174 ret
= CRYPT_CollectionCreateContextFromChild(store
, storeEntry
, child
);
175 Context_Release(child
);
181 /* We always want the same function pointers (from certs, crls)
182 * in the next store, so use the same offset into the next store.
184 size_t offset
= (const BYTE
*)contextFuncs
- (LPBYTE
)storeEntry
->store
->vtbl
;
185 WINE_STORE_LIST_ENTRY
*storeNextEntry
=
186 LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
, entry
);
187 CONTEXT_FUNCS
*storeNextContexts
=
188 (CONTEXT_FUNCS
*)((LPBYTE
)storeNextEntry
->store
->vtbl
+ offset
);
190 ret
= CRYPT_CollectionAdvanceEnum(store
, storeNextEntry
,
191 storeNextContexts
, NULL
);
195 SetLastError(CRYPT_E_NOT_FOUND
);
199 TRACE("returning %p\n", ret
);
203 static BOOL
Collection_addCert(WINECRYPT_CERTSTORE
*store
, context_t
*cert
,
204 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
207 context_t
*childContext
= NULL
;
208 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
210 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, certs
),
211 cert
, toReplace
, &childContext
);
212 if (ppStoreContext
&& childContext
)
214 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
215 cert_t
*context
= (cert_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
218 *ppStoreContext
= &context
->base
;
221 Context_Release(childContext
);
225 static context_t
*Collection_enumCert(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
227 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
230 TRACE("(%p, %p)\n", store
, prev
);
232 EnterCriticalSection(&cs
->cs
);
235 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
237 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
238 &storeEntry
->store
->vtbl
->certs
, prev
);
242 if (!list_empty(&cs
->stores
))
244 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
245 WINE_STORE_LIST_ENTRY
, entry
);
247 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
248 &storeEntry
->store
->vtbl
->certs
, NULL
);
252 SetLastError(CRYPT_E_NOT_FOUND
);
256 LeaveCriticalSection(&cs
->cs
);
257 TRACE("returning %p\n", ret
);
261 static BOOL
Collection_deleteCert(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
263 cert_t
*cert
= (cert_t
*)context
;
266 TRACE("(%p, %p)\n", store
, cert
);
268 linked
= (cert_t
*)context
->linked
;
269 return CertDeleteCertificateFromStore(&linked
->ctx
);
272 static BOOL
Collection_addCRL(WINECRYPT_CERTSTORE
*store
, context_t
*crl
,
273 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
276 context_t
*childContext
= NULL
;
277 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
279 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, crls
),
280 crl
, toReplace
, &childContext
);
281 if (ppStoreContext
&& childContext
)
283 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
284 crl_t
*context
= (crl_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
287 *ppStoreContext
= &context
->base
;
290 Context_Release(childContext
);
294 static context_t
*Collection_enumCRL(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
296 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
299 TRACE("(%p, %p)\n", store
, prev
);
301 EnterCriticalSection(&cs
->cs
);
304 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
306 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
307 &storeEntry
->store
->vtbl
->crls
, prev
);
311 if (!list_empty(&cs
->stores
))
313 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
314 WINE_STORE_LIST_ENTRY
, entry
);
316 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
317 &storeEntry
->store
->vtbl
->crls
, NULL
);
321 SetLastError(CRYPT_E_NOT_FOUND
);
325 LeaveCriticalSection(&cs
->cs
);
326 TRACE("returning %p\n", ret
);
330 static BOOL
Collection_deleteCRL(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
332 crl_t
*crl
= (crl_t
*)context
, *linked
;
334 TRACE("(%p, %p)\n", store
, crl
);
336 linked
= (crl_t
*)context
->linked
;
337 return CertDeleteCRLFromStore(&linked
->ctx
);
340 static BOOL
Collection_addCTL(WINECRYPT_CERTSTORE
*store
, context_t
*ctl
,
341 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
344 context_t
*childContext
= NULL
;
345 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
347 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, ctls
),
348 ctl
, toReplace
, &childContext
);
349 if (ppStoreContext
&& childContext
)
351 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
352 ctl_t
*context
= (ctl_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
355 *ppStoreContext
= &context
->base
;
358 Context_Release(childContext
);
362 static context_t
*Collection_enumCTL(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
364 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
367 TRACE("(%p, %p)\n", store
, prev
);
369 EnterCriticalSection(&cs
->cs
);
372 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
374 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
375 &storeEntry
->store
->vtbl
->ctls
, prev
);
379 if (!list_empty(&cs
->stores
))
381 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
382 WINE_STORE_LIST_ENTRY
, entry
);
384 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
385 &storeEntry
->store
->vtbl
->ctls
, NULL
);
389 SetLastError(CRYPT_E_NOT_FOUND
);
393 LeaveCriticalSection(&cs
->cs
);
394 TRACE("returning %p\n", ret
);
398 static BOOL
Collection_deleteCTL(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
400 ctl_t
*ctl
= (ctl_t
*)context
, *linked
;
402 TRACE("(%p, %p)\n", store
, ctl
);
404 linked
= (ctl_t
*)context
->linked
;
405 return CertDeleteCTLFromStore(&linked
->ctx
);
408 static BOOL
Collection_control(WINECRYPT_CERTSTORE
*cert_store
, DWORD dwFlags
,
409 DWORD dwCtrlType
, void const *pvCtrlPara
)
412 WINE_COLLECTIONSTORE
*store
= (WINE_COLLECTIONSTORE
*)cert_store
;
413 WINE_STORE_LIST_ENTRY
*entry
;
415 TRACE("(%p, %08x, %d, %p)\n", cert_store
, dwFlags
, dwCtrlType
, pvCtrlPara
);
419 if (store
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
421 SetLastError(E_INVALIDARG
);
424 if (store
->hdr
.type
!= StoreTypeCollection
)
426 SetLastError(E_INVALIDARG
);
431 EnterCriticalSection(&store
->cs
);
432 LIST_FOR_EACH_ENTRY(entry
, &store
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
434 if (entry
->store
->vtbl
->control
)
436 ret
= entry
->store
->vtbl
->control(entry
->store
, dwFlags
, dwCtrlType
, pvCtrlPara
);
441 LeaveCriticalSection(&store
->cs
);
445 static const store_vtbl_t CollectionStoreVtbl
= {
448 Collection_releaseContext
,
453 Collection_deleteCert
465 WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
466 DWORD dwFlags
, const void *pvPara
)
468 WINE_COLLECTIONSTORE
*store
;
470 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
472 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
477 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
480 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
481 CRYPT_InitStore(&store
->hdr
, dwFlags
, StoreTypeCollection
, &CollectionStoreVtbl
);
482 InitializeCriticalSection(&store
->cs
);
483 store
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PWINE_COLLECTIONSTORE->cs");
484 list_init(&store
->stores
);
487 return (WINECRYPT_CERTSTORE
*)store
;
490 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
491 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
493 WINE_COLLECTIONSTORE
*collection
= hCollectionStore
;
494 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
495 WINE_STORE_LIST_ENTRY
*entry
;
498 TRACE("(%p, %p, %08x, %d)\n", hCollectionStore
, hSiblingStore
,
499 dwUpdateFlags
, dwPriority
);
501 if (!collection
|| !sibling
)
503 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
505 SetLastError(E_INVALIDARG
);
508 if (collection
->hdr
.type
!= StoreTypeCollection
)
510 SetLastError(E_INVALIDARG
);
513 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
515 SetLastError(E_INVALIDARG
);
519 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
522 InterlockedIncrement(&sibling
->ref
);
523 TRACE("sibling %p's ref count is %d\n", sibling
, sibling
->ref
);
524 entry
->store
= sibling
;
525 entry
->dwUpdateFlags
= dwUpdateFlags
;
526 entry
->dwPriority
= dwPriority
;
527 list_init(&entry
->entry
);
528 TRACE("%p: adding %p, priority %d\n", collection
, entry
, dwPriority
);
529 EnterCriticalSection(&collection
->cs
);
532 WINE_STORE_LIST_ENTRY
*cursor
;
535 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
536 WINE_STORE_LIST_ENTRY
, entry
)
538 if (cursor
->dwPriority
< dwPriority
)
540 list_add_before(&cursor
->entry
, &entry
->entry
);
546 list_add_tail(&collection
->stores
, &entry
->entry
);
549 list_add_tail(&collection
->stores
, &entry
->entry
);
550 LeaveCriticalSection(&collection
->cs
);
558 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
559 HCERTSTORE hSiblingStore
)
561 WINE_COLLECTIONSTORE
*collection
= hCollectionStore
;
562 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
563 WINE_STORE_LIST_ENTRY
*store
, *next
;
565 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
567 if (!collection
|| !sibling
)
569 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
571 SetLastError(E_INVALIDARG
);
574 if (collection
->hdr
.type
!= StoreTypeCollection
)
576 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
578 SetLastError(E_INVALIDARG
);
581 EnterCriticalSection(&collection
->cs
);
582 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
583 WINE_STORE_LIST_ENTRY
, entry
)
585 if (store
->store
== sibling
)
587 list_remove(&store
->entry
);
588 CertCloseStore(store
->store
, 0);
593 LeaveCriticalSection(&collection
->cs
);