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 = %ld\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 %lx\n", flags
);
57 ref
= InterlockedDecrement(&cs
->hdr
.ref
);
58 TRACE("(%p) ref=%ld\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
;
119 EnterCriticalSection(&store
->cs
);
120 LIST_FOR_EACH_ENTRY(entry
, &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
);
170 child
= contextFuncs
->enumContext(storeEntry
->store
, NULL
);
173 ret
= CRYPT_CollectionCreateContextFromChild(store
, storeEntry
, child
);
174 Context_Release(child
);
180 /* We always want the same function pointers (from certs, crls)
181 * in the next store, so use the same offset into the next store.
183 size_t offset
= (const BYTE
*)contextFuncs
- (LPBYTE
)storeEntry
->store
->vtbl
;
184 WINE_STORE_LIST_ENTRY
*storeNextEntry
=
185 LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
, entry
);
186 CONTEXT_FUNCS
*storeNextContexts
=
187 (CONTEXT_FUNCS
*)((LPBYTE
)storeNextEntry
->store
->vtbl
+ offset
);
189 ret
= CRYPT_CollectionAdvanceEnum(store
, storeNextEntry
,
190 storeNextContexts
, NULL
);
194 SetLastError(CRYPT_E_NOT_FOUND
);
198 TRACE("returning %p\n", ret
);
202 static BOOL
Collection_addCert(WINECRYPT_CERTSTORE
*store
, context_t
*cert
,
203 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
206 context_t
*childContext
= NULL
;
207 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
209 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, certs
),
210 cert
, toReplace
, &childContext
);
211 if (ppStoreContext
&& childContext
)
213 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
214 cert_t
*context
= (cert_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
217 *ppStoreContext
= &context
->base
;
220 Context_Release(childContext
);
224 static context_t
*Collection_enumCert(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
226 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
229 TRACE("(%p, %p)\n", store
, prev
);
231 EnterCriticalSection(&cs
->cs
);
234 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
236 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
237 &storeEntry
->store
->vtbl
->certs
, prev
);
241 if (!list_empty(&cs
->stores
))
243 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
244 WINE_STORE_LIST_ENTRY
, entry
);
246 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
247 &storeEntry
->store
->vtbl
->certs
, NULL
);
251 SetLastError(CRYPT_E_NOT_FOUND
);
255 LeaveCriticalSection(&cs
->cs
);
256 TRACE("returning %p\n", ret
);
260 static BOOL
Collection_deleteCert(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
262 cert_t
*cert
= (cert_t
*)context
;
265 TRACE("(%p, %p)\n", store
, cert
);
267 linked
= (cert_t
*)context
->linked
;
268 return CertDeleteCertificateFromStore(&linked
->ctx
);
271 static BOOL
Collection_addCRL(WINECRYPT_CERTSTORE
*store
, context_t
*crl
,
272 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
275 context_t
*childContext
= NULL
;
276 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
278 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, crls
),
279 crl
, toReplace
, &childContext
);
280 if (ppStoreContext
&& childContext
)
282 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
283 crl_t
*context
= (crl_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
286 *ppStoreContext
= &context
->base
;
289 Context_Release(childContext
);
293 static context_t
*Collection_enumCRL(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
295 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
298 TRACE("(%p, %p)\n", store
, prev
);
300 EnterCriticalSection(&cs
->cs
);
303 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
305 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
306 &storeEntry
->store
->vtbl
->crls
, prev
);
310 if (!list_empty(&cs
->stores
))
312 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
313 WINE_STORE_LIST_ENTRY
, entry
);
315 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
316 &storeEntry
->store
->vtbl
->crls
, NULL
);
320 SetLastError(CRYPT_E_NOT_FOUND
);
324 LeaveCriticalSection(&cs
->cs
);
325 TRACE("returning %p\n", ret
);
329 static BOOL
Collection_deleteCRL(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
331 crl_t
*crl
= (crl_t
*)context
, *linked
;
333 TRACE("(%p, %p)\n", store
, crl
);
335 linked
= (crl_t
*)context
->linked
;
336 return CertDeleteCRLFromStore(&linked
->ctx
);
339 static BOOL
Collection_addCTL(WINECRYPT_CERTSTORE
*store
, context_t
*ctl
,
340 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
343 context_t
*childContext
= NULL
;
344 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
346 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, ctls
),
347 ctl
, toReplace
, &childContext
);
348 if (ppStoreContext
&& childContext
)
350 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
351 ctl_t
*context
= (ctl_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
354 *ppStoreContext
= &context
->base
;
357 Context_Release(childContext
);
361 static context_t
*Collection_enumCTL(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
363 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
366 TRACE("(%p, %p)\n", store
, prev
);
368 EnterCriticalSection(&cs
->cs
);
371 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
373 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
374 &storeEntry
->store
->vtbl
->ctls
, prev
);
378 if (!list_empty(&cs
->stores
))
380 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
381 WINE_STORE_LIST_ENTRY
, entry
);
383 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
384 &storeEntry
->store
->vtbl
->ctls
, NULL
);
388 SetLastError(CRYPT_E_NOT_FOUND
);
392 LeaveCriticalSection(&cs
->cs
);
393 TRACE("returning %p\n", ret
);
397 static BOOL
Collection_deleteCTL(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
399 ctl_t
*ctl
= (ctl_t
*)context
, *linked
;
401 TRACE("(%p, %p)\n", store
, ctl
);
403 linked
= (ctl_t
*)context
->linked
;
404 return CertDeleteCTLFromStore(&linked
->ctx
);
407 static BOOL
Collection_control(WINECRYPT_CERTSTORE
*cert_store
, DWORD dwFlags
,
408 DWORD dwCtrlType
, void const *pvCtrlPara
)
411 WINE_COLLECTIONSTORE
*store
= (WINE_COLLECTIONSTORE
*)cert_store
;
412 WINE_STORE_LIST_ENTRY
*entry
;
414 TRACE("(%p, %08lx, %ld, %p)\n", cert_store
, dwFlags
, dwCtrlType
, pvCtrlPara
);
418 if (store
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
420 SetLastError(E_INVALIDARG
);
423 if (store
->hdr
.type
!= StoreTypeCollection
)
425 SetLastError(E_INVALIDARG
);
430 EnterCriticalSection(&store
->cs
);
431 LIST_FOR_EACH_ENTRY(entry
, &store
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
433 if (entry
->store
->vtbl
->control
)
435 ret
= entry
->store
->vtbl
->control(entry
->store
, dwFlags
, dwCtrlType
, pvCtrlPara
);
440 LeaveCriticalSection(&store
->cs
);
444 static const store_vtbl_t CollectionStoreVtbl
= {
447 Collection_releaseContext
,
452 Collection_deleteCert
464 WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
465 DWORD dwFlags
, const void *pvPara
)
467 WINE_COLLECTIONSTORE
*store
;
469 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
471 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
476 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
479 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
480 CRYPT_InitStore(&store
->hdr
, dwFlags
, StoreTypeCollection
, &CollectionStoreVtbl
);
481 InitializeCriticalSection(&store
->cs
);
482 store
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PWINE_COLLECTIONSTORE->cs");
483 list_init(&store
->stores
);
486 return (WINECRYPT_CERTSTORE
*)store
;
489 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
490 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
492 WINE_COLLECTIONSTORE
*collection
= hCollectionStore
;
493 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
494 WINE_STORE_LIST_ENTRY
*entry
;
497 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore
, hSiblingStore
,
498 dwUpdateFlags
, dwPriority
);
500 if (!collection
|| !sibling
)
502 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
504 SetLastError(E_INVALIDARG
);
507 if (collection
->hdr
.type
!= StoreTypeCollection
)
509 SetLastError(E_INVALIDARG
);
512 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
514 SetLastError(E_INVALIDARG
);
518 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
521 InterlockedIncrement(&sibling
->ref
);
522 TRACE("sibling %p's ref count is %ld\n", sibling
, sibling
->ref
);
523 entry
->store
= sibling
;
524 entry
->dwUpdateFlags
= dwUpdateFlags
;
525 entry
->dwPriority
= dwPriority
;
526 TRACE("%p: adding %p, priority %ld\n", collection
, entry
, dwPriority
);
527 EnterCriticalSection(&collection
->cs
);
530 WINE_STORE_LIST_ENTRY
*cursor
;
533 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
534 WINE_STORE_LIST_ENTRY
, entry
)
536 if (cursor
->dwPriority
< dwPriority
)
538 list_add_before(&cursor
->entry
, &entry
->entry
);
544 list_add_tail(&collection
->stores
, &entry
->entry
);
547 list_add_tail(&collection
->stores
, &entry
->entry
);
548 LeaveCriticalSection(&collection
->cs
);
556 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
557 HCERTSTORE hSiblingStore
)
559 WINE_COLLECTIONSTORE
*collection
= hCollectionStore
;
560 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
561 WINE_STORE_LIST_ENTRY
*store
;
563 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
565 if (!collection
|| !sibling
)
567 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
569 SetLastError(E_INVALIDARG
);
572 if (collection
->hdr
.type
!= StoreTypeCollection
)
574 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
576 SetLastError(E_INVALIDARG
);
579 EnterCriticalSection(&collection
->cs
);
580 LIST_FOR_EACH_ENTRY(store
, &collection
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
582 if (store
->store
== sibling
)
584 list_remove(&store
->entry
);
585 CertCloseStore(store
->store
, 0);
590 LeaveCriticalSection(&collection
->cs
);