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 context_t
*CRYPT_CollectionCreateContextFromChild(WINE_COLLECTIONSTORE
*store
,
75 WINE_STORE_LIST_ENTRY
*storeEntry
, context_t
*child
, size_t contextSize
)
79 ret
= child
->vtbl
->clone(child
, &store
->hdr
, TRUE
);
83 ret
->u
.ptr
= storeEntry
;
87 static BOOL
CRYPT_CollectionAddContext(WINE_COLLECTIONSTORE
*store
,
88 unsigned int contextFuncsOffset
, context_t
*context
, context_t
*toReplace
, unsigned int contextSize
,
89 context_t
**pChildContext
)
92 context_t
*childContext
= NULL
;
93 WINE_STORE_LIST_ENTRY
*storeEntry
= NULL
;
95 TRACE("(%p, %d, %p, %p, %d)\n", store
, contextFuncsOffset
, context
,
96 toReplace
, contextSize
);
101 context_t
*existingLinked
= toReplace
->linked
;
102 CONTEXT_FUNCS
*contextFuncs
;
104 storeEntry
= toReplace
->u
.ptr
;
105 contextFuncs
= (CONTEXT_FUNCS
*)((LPBYTE
)storeEntry
->store
->vtbl
+
107 ret
= contextFuncs
->addContext(storeEntry
->store
, context
,
108 existingLinked
, &childContext
, TRUE
);
112 WINE_STORE_LIST_ENTRY
*entry
, *next
;
114 EnterCriticalSection(&store
->cs
);
115 LIST_FOR_EACH_ENTRY_SAFE(entry
, next
, &store
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
117 if (entry
->dwUpdateFlags
& CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG
)
119 CONTEXT_FUNCS
*contextFuncs
= (CONTEXT_FUNCS
*)(
120 (LPBYTE
)entry
->store
->vtbl
+ contextFuncsOffset
);
123 ret
= contextFuncs
->addContext(entry
->store
, context
, NULL
, &childContext
, TRUE
);
127 LeaveCriticalSection(&store
->cs
);
129 SetLastError(E_ACCESSDENIED
);
131 *pChildContext
= childContext
;
135 /* Advances a collection enumeration by one context, if possible, where
137 * - calling the current store's enumeration function once, and returning
138 * the enumerated context if one is returned
139 * - moving to the next store if the current store has no more items, and
140 * recursively calling itself to get the next item.
141 * Returns NULL if the collection contains no more items or on error.
142 * Assumes the collection store's lock is held.
144 static context_t
*CRYPT_CollectionAdvanceEnum(WINE_COLLECTIONSTORE
*store
,
145 WINE_STORE_LIST_ENTRY
*storeEntry
, const CONTEXT_FUNCS
*contextFuncs
,
146 const WINE_CONTEXT_INTERFACE
*contextInterface
, context_t
*prev
, size_t contextSize
)
148 context_t
*child
, *ret
;
149 struct list
*storeNext
= list_next(&store
->stores
, &storeEntry
->entry
);
151 TRACE("(%p, %p, %p)\n", store
, storeEntry
, prev
);
155 /* Ref-counting funny business: "duplicate" (addref) the child, because
156 * the free(pPrev) below can cause the ref count to become negative.
158 child
= prev
->linked
;
159 Context_AddRef(child
);
160 child
= contextFuncs
->enumContext(storeEntry
->store
, child
);
161 Context_Release(prev
);
166 child
= contextFuncs
->enumContext(storeEntry
->store
, NULL
);
169 ret
= CRYPT_CollectionCreateContextFromChild(store
, storeEntry
, child
, contextSize
);
170 Context_Release(child
);
176 /* We always want the same function pointers (from certs, crls)
177 * in the next store, so use the same offset into the next store.
179 size_t offset
= (const BYTE
*)contextFuncs
- (LPBYTE
)storeEntry
->store
->vtbl
;
180 WINE_STORE_LIST_ENTRY
*storeNextEntry
=
181 LIST_ENTRY(storeNext
, WINE_STORE_LIST_ENTRY
, entry
);
182 CONTEXT_FUNCS
*storeNextContexts
=
183 (CONTEXT_FUNCS
*)((LPBYTE
)storeNextEntry
->store
->vtbl
+ offset
);
185 ret
= CRYPT_CollectionAdvanceEnum(store
, storeNextEntry
,
186 storeNextContexts
, contextInterface
, NULL
, contextSize
);
190 SetLastError(CRYPT_E_NOT_FOUND
);
194 TRACE("returning %p\n", ret
);
198 static BOOL
Collection_addCert(WINECRYPT_CERTSTORE
*store
, context_t
*cert
,
199 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
202 context_t
*childContext
= NULL
;
203 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
205 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, certs
),
206 cert
, toReplace
, sizeof(CERT_CONTEXT
), &childContext
);
207 if (ppStoreContext
&& childContext
)
209 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
210 cert_t
*context
= (cert_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
211 childContext
, sizeof(CERT_CONTEXT
));
213 *ppStoreContext
= &context
->base
;
216 Context_Release(childContext
);
220 static context_t
*Collection_enumCert(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
222 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
225 TRACE("(%p, %p)\n", store
, prev
);
227 EnterCriticalSection(&cs
->cs
);
230 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
232 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
233 &storeEntry
->store
->vtbl
->certs
, pCertInterface
, prev
,
234 sizeof(CERT_CONTEXT
));
238 if (!list_empty(&cs
->stores
))
240 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
241 WINE_STORE_LIST_ENTRY
, entry
);
243 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
244 &storeEntry
->store
->vtbl
->certs
, pCertInterface
, NULL
,
245 sizeof(CERT_CONTEXT
));
249 SetLastError(CRYPT_E_NOT_FOUND
);
253 LeaveCriticalSection(&cs
->cs
);
254 TRACE("returning %p\n", ret
);
258 static BOOL
Collection_deleteCert(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
260 cert_t
*cert
= (cert_t
*)context
;
264 TRACE("(%p, %p)\n", store
, cert
);
266 linked
= (cert_t
*)context
->linked
;
267 ret
= CertDeleteCertificateFromStore(&linked
->ctx
);
268 Context_Release(&cert
->base
);
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
, sizeof(CRL_CONTEXT
), &childContext
);
281 if (ppStoreContext
&& childContext
)
283 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
284 crl_t
*context
= (crl_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
285 childContext
, sizeof(CRL_CONTEXT
));
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
, pCRLInterface
, prev
, sizeof(CRL_CONTEXT
));
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
, pCRLInterface
, NULL
,
318 sizeof(CRL_CONTEXT
));
322 SetLastError(CRYPT_E_NOT_FOUND
);
326 LeaveCriticalSection(&cs
->cs
);
327 TRACE("returning %p\n", ret
);
331 static BOOL
Collection_deleteCRL(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
333 crl_t
*crl
= (crl_t
*)context
, *linked
;
336 TRACE("(%p, %p)\n", store
, crl
);
338 linked
= (crl_t
*)context
->linked
;
339 ret
= CertDeleteCRLFromStore(&linked
->ctx
);
340 Context_Release(&crl
->base
);
344 static BOOL
Collection_addCTL(WINECRYPT_CERTSTORE
*store
, context_t
*ctl
,
345 context_t
*toReplace
, context_t
**ppStoreContext
, BOOL use_link
)
348 context_t
*childContext
= NULL
;
349 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
351 ret
= CRYPT_CollectionAddContext(cs
, offsetof(store_vtbl_t
, ctls
),
352 ctl
, toReplace
, sizeof(CTL_CONTEXT
), &childContext
);
353 if (ppStoreContext
&& childContext
)
355 WINE_STORE_LIST_ENTRY
*storeEntry
= childContext
->u
.ptr
;
356 ctl_t
*context
= (ctl_t
*)CRYPT_CollectionCreateContextFromChild(cs
, storeEntry
,
357 childContext
, sizeof(CTL_CONTEXT
));
359 *ppStoreContext
= &context
->base
;
362 Context_Release(childContext
);
366 static context_t
*Collection_enumCTL(WINECRYPT_CERTSTORE
*store
, context_t
*prev
)
368 WINE_COLLECTIONSTORE
*cs
= (WINE_COLLECTIONSTORE
*)store
;
371 TRACE("(%p, %p)\n", store
, prev
);
373 EnterCriticalSection(&cs
->cs
);
376 WINE_STORE_LIST_ENTRY
*storeEntry
= prev
->u
.ptr
;
378 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
379 &storeEntry
->store
->vtbl
->ctls
, pCTLInterface
, prev
, sizeof(CTL_CONTEXT
));
383 if (!list_empty(&cs
->stores
))
385 WINE_STORE_LIST_ENTRY
*storeEntry
= LIST_ENTRY(cs
->stores
.next
,
386 WINE_STORE_LIST_ENTRY
, entry
);
388 ret
= CRYPT_CollectionAdvanceEnum(cs
, storeEntry
,
389 &storeEntry
->store
->vtbl
->ctls
, pCTLInterface
, NULL
,
390 sizeof(CTL_CONTEXT
));
394 SetLastError(CRYPT_E_NOT_FOUND
);
398 LeaveCriticalSection(&cs
->cs
);
399 TRACE("returning %p\n", ret
);
403 static BOOL
Collection_deleteCTL(WINECRYPT_CERTSTORE
*store
, context_t
*context
)
405 ctl_t
*ctl
= (ctl_t
*)context
, *linked
;
408 TRACE("(%p, %p)\n", store
, ctl
);
410 linked
= (ctl_t
*)context
->linked
;
411 ret
= CertDeleteCTLFromStore(&linked
->ctx
);
412 Context_Release(&ctl
->base
);
416 static BOOL
Collection_control(WINECRYPT_CERTSTORE
*cert_store
, DWORD dwFlags
,
417 DWORD dwCtrlType
, void const *pvCtrlPara
)
420 WINE_COLLECTIONSTORE
*store
= (WINE_COLLECTIONSTORE
*)cert_store
;
421 WINE_STORE_LIST_ENTRY
*entry
;
423 TRACE("(%p, %08x, %d, %p)\n", cert_store
, dwFlags
, dwCtrlType
, pvCtrlPara
);
427 if (store
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
429 SetLastError(E_INVALIDARG
);
432 if (store
->hdr
.type
!= StoreTypeCollection
)
434 SetLastError(E_INVALIDARG
);
439 EnterCriticalSection(&store
->cs
);
440 LIST_FOR_EACH_ENTRY(entry
, &store
->stores
, WINE_STORE_LIST_ENTRY
, entry
)
442 if (entry
->store
->vtbl
->control
)
444 ret
= entry
->store
->vtbl
->control(entry
->store
, dwFlags
, dwCtrlType
, pvCtrlPara
);
449 LeaveCriticalSection(&store
->cs
);
453 static const store_vtbl_t CollectionStoreVtbl
= {
460 Collection_deleteCert
472 WINECRYPT_CERTSTORE
*CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv
,
473 DWORD dwFlags
, const void *pvPara
)
475 WINE_COLLECTIONSTORE
*store
;
477 if (dwFlags
& CERT_STORE_DELETE_FLAG
)
479 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
484 store
= CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE
));
487 memset(store
, 0, sizeof(WINE_COLLECTIONSTORE
));
488 CRYPT_InitStore(&store
->hdr
, dwFlags
, StoreTypeCollection
, &CollectionStoreVtbl
);
489 InitializeCriticalSection(&store
->cs
);
490 store
->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": PWINE_COLLECTIONSTORE->cs");
491 list_init(&store
->stores
);
494 return (WINECRYPT_CERTSTORE
*)store
;
497 BOOL WINAPI
CertAddStoreToCollection(HCERTSTORE hCollectionStore
,
498 HCERTSTORE hSiblingStore
, DWORD dwUpdateFlags
, DWORD dwPriority
)
500 WINE_COLLECTIONSTORE
*collection
= hCollectionStore
;
501 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
502 WINE_STORE_LIST_ENTRY
*entry
;
505 TRACE("(%p, %p, %08x, %d)\n", hCollectionStore
, hSiblingStore
,
506 dwUpdateFlags
, dwPriority
);
508 if (!collection
|| !sibling
)
510 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
512 SetLastError(E_INVALIDARG
);
515 if (collection
->hdr
.type
!= StoreTypeCollection
)
517 SetLastError(E_INVALIDARG
);
520 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
522 SetLastError(E_INVALIDARG
);
526 entry
= CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY
));
529 InterlockedIncrement(&sibling
->ref
);
530 TRACE("sibling %p's ref count is %d\n", sibling
, sibling
->ref
);
531 entry
->store
= sibling
;
532 entry
->dwUpdateFlags
= dwUpdateFlags
;
533 entry
->dwPriority
= dwPriority
;
534 list_init(&entry
->entry
);
535 TRACE("%p: adding %p, priority %d\n", collection
, entry
, dwPriority
);
536 EnterCriticalSection(&collection
->cs
);
539 WINE_STORE_LIST_ENTRY
*cursor
;
542 LIST_FOR_EACH_ENTRY(cursor
, &collection
->stores
,
543 WINE_STORE_LIST_ENTRY
, entry
)
545 if (cursor
->dwPriority
< dwPriority
)
547 list_add_before(&cursor
->entry
, &entry
->entry
);
553 list_add_tail(&collection
->stores
, &entry
->entry
);
556 list_add_tail(&collection
->stores
, &entry
->entry
);
557 LeaveCriticalSection(&collection
->cs
);
565 void WINAPI
CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore
,
566 HCERTSTORE hSiblingStore
)
568 WINE_COLLECTIONSTORE
*collection
= hCollectionStore
;
569 WINECRYPT_CERTSTORE
*sibling
= hSiblingStore
;
570 WINE_STORE_LIST_ENTRY
*store
, *next
;
572 TRACE("(%p, %p)\n", hCollectionStore
, hSiblingStore
);
574 if (!collection
|| !sibling
)
576 if (collection
->hdr
.dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
578 SetLastError(E_INVALIDARG
);
581 if (collection
->hdr
.type
!= StoreTypeCollection
)
583 if (sibling
->dwMagic
!= WINE_CRYPTCERTSTORE_MAGIC
)
585 SetLastError(E_INVALIDARG
);
588 EnterCriticalSection(&collection
->cs
);
589 LIST_FOR_EACH_ENTRY_SAFE(store
, next
, &collection
->stores
,
590 WINE_STORE_LIST_ENTRY
, entry
)
592 if (store
->store
== sibling
)
594 list_remove(&store
->entry
);
595 CertCloseStore(store
->store
, 0);
600 LeaveCriticalSection(&collection
->cs
);