crypt32: Get rid of no longer used contextSize argument in Context_GetLinkedContext.
[wine.git] / dlls / crypt32 / collectionstore.c
blob6ab2d2b058081d02136e11b3ee8cd9b9fec4235b
1 /*
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
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "wine/debug.h"
23 #include "wine/list.h"
24 #include "crypt32_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28 typedef struct _WINE_STORE_LIST_ENTRY
30 WINECRYPT_CERTSTORE *store;
31 DWORD dwUpdateFlags;
32 DWORD dwPriority;
33 struct list entry;
34 } WINE_STORE_LIST_ENTRY;
36 typedef struct _WINE_COLLECTIONSTORE
38 WINECRYPT_CERTSTORE hdr;
39 CRITICAL_SECTION cs;
40 struct list stores;
41 } WINE_COLLECTIONSTORE;
43 static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
45 WINE_COLLECTIONSTORE *cs = store;
46 WINE_STORE_LIST_ENTRY *entry, *next;
48 TRACE("(%p, %08x)\n", store, dwFlags);
50 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
51 entry)
53 TRACE("closing %p\n", entry);
54 CertCloseStore(entry->store, dwFlags);
55 CryptMemFree(entry);
57 cs->cs.DebugInfo->Spare[0] = 0;
58 DeleteCriticalSection(&cs->cs);
59 CRYPT_FreeStore(store);
62 static void *CRYPT_CollectionCreateContextFromChild(WINE_COLLECTIONSTORE *store,
63 WINE_STORE_LIST_ENTRY *storeEntry, void *child, size_t contextSize,
64 BOOL addRef)
66 void *ret = Context_CreateLinkContext(contextSize, child,
67 sizeof(WINE_STORE_LIST_ENTRY*), addRef);
69 if (ret)
70 *(WINE_STORE_LIST_ENTRY **)Context_GetExtra(ret, contextSize)
71 = storeEntry;
73 return ret;
76 static BOOL CRYPT_CollectionAddContext(WINE_COLLECTIONSTORE *store,
77 unsigned int contextFuncsOffset, void *context, void *toReplace, unsigned int contextSize,
78 void **pChildContext)
80 BOOL ret;
81 void *childContext = NULL;
82 WINE_STORE_LIST_ENTRY *storeEntry = NULL;
84 TRACE("(%p, %d, %p, %p, %d)\n", store, contextFuncsOffset, context,
85 toReplace, contextSize);
87 ret = FALSE;
88 if (toReplace)
90 void *existingLinked = Context_GetLinkedContext(toReplace);
91 CONTEXT_FUNCS *contextFuncs;
93 storeEntry = *(WINE_STORE_LIST_ENTRY **)Context_GetExtra(toReplace,
94 contextSize);
95 contextFuncs = (CONTEXT_FUNCS*)((LPBYTE)storeEntry->store +
96 contextFuncsOffset);
97 ret = contextFuncs->addContext(storeEntry->store, context,
98 existingLinked, (const void **)&childContext);
100 else
102 WINE_STORE_LIST_ENTRY *entry, *next;
104 EnterCriticalSection(&store->cs);
105 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores,
106 WINE_STORE_LIST_ENTRY, entry)
108 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
110 CONTEXT_FUNCS *contextFuncs = (CONTEXT_FUNCS*)(
111 (LPBYTE)entry->store + contextFuncsOffset);
113 storeEntry = entry;
114 ret = contextFuncs->addContext(entry->store, context, NULL,
115 (const void **)&childContext);
116 break;
119 LeaveCriticalSection(&store->cs);
120 if (!storeEntry)
121 SetLastError(E_ACCESSDENIED);
123 *pChildContext = childContext;
124 return ret;
127 /* Advances a collection enumeration by one context, if possible, where
128 * advancing means:
129 * - calling the current store's enumeration function once, and returning
130 * the enumerated context if one is returned
131 * - moving to the next store if the current store has no more items, and
132 * recursively calling itself to get the next item.
133 * Returns NULL if the collection contains no more items or on error.
134 * Assumes the collection store's lock is held.
136 static void *CRYPT_CollectionAdvanceEnum(WINE_COLLECTIONSTORE *store,
137 WINE_STORE_LIST_ENTRY *storeEntry, const CONTEXT_FUNCS *contextFuncs,
138 const WINE_CONTEXT_INTERFACE *contextInterface, void *pPrev, size_t contextSize)
140 void *ret, *child;
141 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
143 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
145 if (pPrev)
147 /* Ref-counting funny business: "duplicate" (addref) the child, because
148 * the free(pPrev) below can cause the ref count to become negative.
150 child = Context_GetLinkedContext(pPrev);
151 contextInterface->duplicate(child);
152 child = contextFuncs->enumContext(storeEntry->store, child);
153 contextInterface->free(pPrev);
154 pPrev = NULL;
156 else
157 child = contextFuncs->enumContext(storeEntry->store, NULL);
158 if (child)
159 ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child,
160 contextSize, FALSE);
161 else
163 if (storeNext)
165 /* We always want the same function pointers (from certs, crls)
166 * in the next store, so use the same offset into the next store.
168 size_t offset = (const BYTE *)contextFuncs - (LPBYTE)storeEntry->store;
169 WINE_STORE_LIST_ENTRY *storeNextEntry =
170 LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
171 CONTEXT_FUNCS *storeNextContexts =
172 (CONTEXT_FUNCS*)((LPBYTE)storeNextEntry->store + offset);
174 ret = CRYPT_CollectionAdvanceEnum(store, storeNextEntry,
175 storeNextContexts, contextInterface, NULL, contextSize);
177 else
179 SetLastError(CRYPT_E_NOT_FOUND);
180 ret = NULL;
183 TRACE("returning %p\n", ret);
184 return ret;
187 static BOOL CRYPT_CollectionAddCert(WINECRYPT_CERTSTORE *store, void *cert,
188 void *toReplace, const void **ppStoreContext)
190 BOOL ret;
191 void *childContext = NULL;
192 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
194 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs),
195 cert, toReplace, sizeof(CERT_CONTEXT), &childContext);
196 if (ppStoreContext && childContext)
198 WINE_STORE_LIST_ENTRY *storeEntry = *(WINE_STORE_LIST_ENTRY **)
199 Context_GetExtra(childContext, sizeof(CERT_CONTEXT));
200 PCERT_CONTEXT context =
201 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
202 sizeof(CERT_CONTEXT), TRUE);
204 if (context)
205 context->hCertStore = store;
206 *ppStoreContext = context;
208 CertFreeCertificateContext(childContext);
209 return ret;
212 static void *CRYPT_CollectionEnumCert(WINECRYPT_CERTSTORE *store, void *pPrev)
214 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
215 void *ret;
217 TRACE("(%p, %p)\n", store, pPrev);
219 EnterCriticalSection(&cs->cs);
220 if (pPrev)
222 WINE_STORE_LIST_ENTRY *storeEntry =
223 *(WINE_STORE_LIST_ENTRY **)Context_GetExtra(pPrev,
224 sizeof(CERT_CONTEXT));
226 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
227 &storeEntry->store->certs, pCertInterface, pPrev,
228 sizeof(CERT_CONTEXT));
230 else
232 if (!list_empty(&cs->stores))
234 WINE_STORE_LIST_ENTRY *storeEntry = LIST_ENTRY(cs->stores.next,
235 WINE_STORE_LIST_ENTRY, entry);
237 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
238 &storeEntry->store->certs, pCertInterface, NULL,
239 sizeof(CERT_CONTEXT));
241 else
243 SetLastError(CRYPT_E_NOT_FOUND);
244 ret = NULL;
247 LeaveCriticalSection(&cs->cs);
248 if (ret)
249 ((PCERT_CONTEXT)ret)->hCertStore = store;
250 TRACE("returning %p\n", ret);
251 return ret;
254 static BOOL CRYPT_CollectionDeleteCert(WINECRYPT_CERTSTORE *store,
255 void *pCertContext)
257 BOOL ret;
258 PCCERT_CONTEXT linked;
260 TRACE("(%p, %p)\n", store, pCertContext);
262 /* Deleting the linked context results in its ref count getting
263 * decreased, but the caller of this (CertDeleteCertificateFromStore) also
264 * decreases pCertContext's ref count, by calling
265 * CertFreeCertificateContext. Increase ref count of linked context to
266 * compensate.
268 linked = Context_GetLinkedContext(pCertContext);
269 CertDuplicateCertificateContext(linked);
270 ret = CertDeleteCertificateFromStore(linked);
271 return ret;
274 static BOOL CRYPT_CollectionAddCRL(WINECRYPT_CERTSTORE *store, void *crl,
275 void *toReplace, const void **ppStoreContext)
277 BOOL ret;
278 void *childContext = NULL;
279 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
281 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls),
282 crl, toReplace, sizeof(CRL_CONTEXT), &childContext);
283 if (ppStoreContext && childContext)
285 WINE_STORE_LIST_ENTRY *storeEntry = *(WINE_STORE_LIST_ENTRY **)
286 Context_GetExtra(childContext, sizeof(CRL_CONTEXT));
287 PCRL_CONTEXT context =
288 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
289 sizeof(CRL_CONTEXT), TRUE);
291 if (context)
292 context->hCertStore = store;
293 *ppStoreContext = context;
295 CertFreeCRLContext(childContext);
296 return ret;
299 static void *CRYPT_CollectionEnumCRL(WINECRYPT_CERTSTORE *store, void *pPrev)
301 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
302 void *ret;
304 TRACE("(%p, %p)\n", store, pPrev);
306 EnterCriticalSection(&cs->cs);
307 if (pPrev)
309 WINE_STORE_LIST_ENTRY *storeEntry =
310 *(WINE_STORE_LIST_ENTRY **)Context_GetExtra(pPrev,
311 sizeof(CRL_CONTEXT));
313 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
314 &storeEntry->store->crls, pCRLInterface, pPrev, sizeof(CRL_CONTEXT));
316 else
318 if (!list_empty(&cs->stores))
320 WINE_STORE_LIST_ENTRY *storeEntry = LIST_ENTRY(cs->stores.next,
321 WINE_STORE_LIST_ENTRY, entry);
323 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
324 &storeEntry->store->crls, pCRLInterface, NULL,
325 sizeof(CRL_CONTEXT));
327 else
329 SetLastError(CRYPT_E_NOT_FOUND);
330 ret = NULL;
333 LeaveCriticalSection(&cs->cs);
334 if (ret)
335 ((PCRL_CONTEXT)ret)->hCertStore = store;
336 TRACE("returning %p\n", ret);
337 return ret;
340 static BOOL CRYPT_CollectionDeleteCRL(WINECRYPT_CERTSTORE *store, void *pCrlContext)
342 BOOL ret;
343 PCCRL_CONTEXT linked;
345 TRACE("(%p, %p)\n", store, pCrlContext);
347 /* Deleting the linked context results in its ref count getting
348 * decreased, but the caller of this (CertDeleteCRLFromStore) also
349 * decreases pCrlContext's ref count, by calling CertFreeCRLContext.
350 * Increase ref count of linked context to compensate.
352 linked = Context_GetLinkedContext(pCrlContext);
353 CertDuplicateCRLContext(linked);
354 ret = CertDeleteCRLFromStore(linked);
355 return ret;
358 static BOOL CRYPT_CollectionAddCTL(WINECRYPT_CERTSTORE *store, void *ctl,
359 void *toReplace, const void **ppStoreContext)
361 BOOL ret;
362 void *childContext = NULL;
363 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
365 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, ctls),
366 ctl, toReplace, sizeof(CTL_CONTEXT), &childContext);
367 if (ppStoreContext && childContext)
369 WINE_STORE_LIST_ENTRY *storeEntry = *(WINE_STORE_LIST_ENTRY **)
370 Context_GetExtra(childContext, sizeof(CTL_CONTEXT));
371 PCTL_CONTEXT context =
372 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
373 sizeof(CTL_CONTEXT), TRUE);
375 if (context)
376 context->hCertStore = store;
377 *ppStoreContext = context;
379 CertFreeCTLContext(childContext);
380 return ret;
383 static void *CRYPT_CollectionEnumCTL(WINECRYPT_CERTSTORE *store, void *pPrev)
385 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
386 void *ret;
388 TRACE("(%p, %p)\n", store, pPrev);
390 EnterCriticalSection(&cs->cs);
391 if (pPrev)
393 WINE_STORE_LIST_ENTRY *storeEntry =
394 *(WINE_STORE_LIST_ENTRY **)Context_GetExtra(pPrev, sizeof(CTL_CONTEXT));
396 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
397 &storeEntry->store->ctls, pCTLInterface, pPrev, sizeof(CTL_CONTEXT));
399 else
401 if (!list_empty(&cs->stores))
403 WINE_STORE_LIST_ENTRY *storeEntry = LIST_ENTRY(cs->stores.next,
404 WINE_STORE_LIST_ENTRY, entry);
406 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
407 &storeEntry->store->ctls, pCTLInterface, NULL,
408 sizeof(CTL_CONTEXT));
410 else
412 SetLastError(CRYPT_E_NOT_FOUND);
413 ret = NULL;
416 LeaveCriticalSection(&cs->cs);
417 if (ret)
418 ((PCTL_CONTEXT)ret)->hCertStore = store;
419 TRACE("returning %p\n", ret);
420 return ret;
423 static BOOL CRYPT_CollectionDeleteCTL(WINECRYPT_CERTSTORE *store,
424 void *pCtlContext)
426 BOOL ret;
427 PCCTL_CONTEXT linked;
429 TRACE("(%p, %p)\n", store, pCtlContext);
431 /* Deleting the linked context results in its ref count getting
432 * decreased, but the caller of this (CertDeleteCTLFromStore) also
433 * decreases pCtlContext's ref count, by calling CertFreeCTLContext.
434 * Increase ref count of linked context to compensate.
436 linked = Context_GetLinkedContext(pCtlContext);
437 CertDuplicateCTLContext(linked);
438 ret = CertDeleteCTLFromStore(linked);
439 return ret;
442 static BOOL WINAPI CRYPT_CollectionControl(HCERTSTORE hCertStore, DWORD dwFlags,
443 DWORD dwCtrlType, void const *pvCtrlPara)
445 BOOL ret;
446 WINE_COLLECTIONSTORE *store = hCertStore;
447 WINE_STORE_LIST_ENTRY *entry;
449 TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
450 pvCtrlPara);
452 if (!store)
453 return TRUE;
454 if (store->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
456 SetLastError(E_INVALIDARG);
457 return FALSE;
459 if (store->hdr.type != StoreTypeCollection)
461 SetLastError(E_INVALIDARG);
462 return FALSE;
465 ret = TRUE;
466 EnterCriticalSection(&store->cs);
467 LIST_FOR_EACH_ENTRY(entry, &store->stores, WINE_STORE_LIST_ENTRY, entry)
469 if (entry->store->control)
471 ret = entry->store->control(entry->store, dwFlags, dwCtrlType,
472 pvCtrlPara);
473 if (!ret)
474 break;
477 LeaveCriticalSection(&store->cs);
478 return ret;
481 WINECRYPT_CERTSTORE *CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
482 DWORD dwFlags, const void *pvPara)
484 WINE_COLLECTIONSTORE *store;
486 if (dwFlags & CERT_STORE_DELETE_FLAG)
488 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
489 store = NULL;
491 else
493 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
494 if (store)
496 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
497 CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeCollection);
498 store->hdr.closeStore = CRYPT_CollectionCloseStore;
499 store->hdr.certs.addContext = CRYPT_CollectionAddCert;
500 store->hdr.certs.enumContext = CRYPT_CollectionEnumCert;
501 store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert;
502 store->hdr.crls.addContext = CRYPT_CollectionAddCRL;
503 store->hdr.crls.enumContext = CRYPT_CollectionEnumCRL;
504 store->hdr.crls.deleteContext = CRYPT_CollectionDeleteCRL;
505 store->hdr.ctls.addContext = CRYPT_CollectionAddCTL;
506 store->hdr.ctls.enumContext = CRYPT_CollectionEnumCTL;
507 store->hdr.ctls.deleteContext = CRYPT_CollectionDeleteCTL;
508 store->hdr.control = CRYPT_CollectionControl;
509 InitializeCriticalSection(&store->cs);
510 store->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs");
511 list_init(&store->stores);
514 return (WINECRYPT_CERTSTORE*)store;
517 BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
518 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
520 WINE_COLLECTIONSTORE *collection = hCollectionStore;
521 WINECRYPT_CERTSTORE *sibling = hSiblingStore;
522 WINE_STORE_LIST_ENTRY *entry;
523 BOOL ret;
525 TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore,
526 dwUpdateFlags, dwPriority);
528 if (!collection || !sibling)
529 return TRUE;
530 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
532 SetLastError(E_INVALIDARG);
533 return FALSE;
535 if (collection->hdr.type != StoreTypeCollection)
537 SetLastError(E_INVALIDARG);
538 return FALSE;
540 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
542 SetLastError(E_INVALIDARG);
543 return FALSE;
546 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
547 if (entry)
549 InterlockedIncrement(&sibling->ref);
550 TRACE("sibling %p's ref count is %d\n", sibling, sibling->ref);
551 entry->store = sibling;
552 entry->dwUpdateFlags = dwUpdateFlags;
553 entry->dwPriority = dwPriority;
554 list_init(&entry->entry);
555 TRACE("%p: adding %p, priority %d\n", collection, entry, dwPriority);
556 EnterCriticalSection(&collection->cs);
557 if (dwPriority)
559 WINE_STORE_LIST_ENTRY *cursor;
560 BOOL added = FALSE;
562 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
563 WINE_STORE_LIST_ENTRY, entry)
565 if (cursor->dwPriority < dwPriority)
567 list_add_before(&cursor->entry, &entry->entry);
568 added = TRUE;
569 break;
572 if (!added)
573 list_add_tail(&collection->stores, &entry->entry);
575 else
576 list_add_tail(&collection->stores, &entry->entry);
577 LeaveCriticalSection(&collection->cs);
578 ret = TRUE;
580 else
581 ret = FALSE;
582 return ret;
585 void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
586 HCERTSTORE hSiblingStore)
588 WINE_COLLECTIONSTORE *collection = hCollectionStore;
589 WINECRYPT_CERTSTORE *sibling = hSiblingStore;
590 WINE_STORE_LIST_ENTRY *store, *next;
592 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
594 if (!collection || !sibling)
595 return;
596 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
598 SetLastError(E_INVALIDARG);
599 return;
601 if (collection->hdr.type != StoreTypeCollection)
602 return;
603 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
605 SetLastError(E_INVALIDARG);
606 return;
608 EnterCriticalSection(&collection->cs);
609 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
610 WINE_STORE_LIST_ENTRY, entry)
612 if (store->store == sibling)
614 list_remove(&store->entry);
615 CertCloseStore(store->store, 0);
616 CryptMemFree(store);
617 break;
620 LeaveCriticalSection(&collection->cs);