crypt32: Use context_t in addContext.
[wine.git] / dlls / crypt32 / collectionstore.c
blob8f15295676b11d44b6d8a320d368e7b53dc410af
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 "crypt32_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
27 typedef struct _WINE_STORE_LIST_ENTRY
29 WINECRYPT_CERTSTORE *store;
30 DWORD dwUpdateFlags;
31 DWORD dwPriority;
32 struct list entry;
33 } WINE_STORE_LIST_ENTRY;
35 typedef struct _WINE_COLLECTIONSTORE
37 WINECRYPT_CERTSTORE hdr;
38 CRITICAL_SECTION cs;
39 struct list stores;
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;
52 LONG ref;
54 if(flags)
55 FIXME("Unimplemented flags %x\n", flags);
57 ref = InterlockedDecrement(&cs->hdr.ref);
58 TRACE("(%p) ref=%d\n", store, ref);
59 if(ref)
60 return ERROR_SUCCESS;
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);
66 CryptMemFree(entry);
68 cs->cs.DebugInfo->Spare[0] = 0;
69 DeleteCriticalSection(&cs->cs);
70 CRYPT_FreeStore(store);
71 return ERROR_SUCCESS;
74 static context_t *CRYPT_CollectionCreateContextFromChild(WINE_COLLECTIONSTORE *store,
75 WINE_STORE_LIST_ENTRY *storeEntry, context_t *child, size_t contextSize)
77 context_t *ret;
79 ret = child->vtbl->clone(child, &store->hdr, TRUE);
80 if (!ret)
81 return NULL;
83 ret->u.ptr = storeEntry;
84 return ret;
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)
91 BOOL ret;
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);
98 ret = FALSE;
99 if (toReplace)
101 context_t *existingLinked = toReplace->linked;
102 CONTEXT_FUNCS *contextFuncs;
104 storeEntry = toReplace->u.ptr;
105 contextFuncs = (CONTEXT_FUNCS*)((LPBYTE)storeEntry->store->vtbl +
106 contextFuncsOffset);
107 ret = contextFuncs->addContext(storeEntry->store, context,
108 existingLinked, &childContext, TRUE);
110 else
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);
122 storeEntry = entry;
123 ret = contextFuncs->addContext(entry->store, context, NULL, &childContext, TRUE);
124 break;
127 LeaveCriticalSection(&store->cs);
128 if (!storeEntry)
129 SetLastError(E_ACCESSDENIED);
131 *pChildContext = childContext;
132 return ret;
135 /* Advances a collection enumeration by one context, if possible, where
136 * advancing means:
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);
153 if (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);
162 prev = NULL;
164 else
166 child = contextFuncs->enumContext(storeEntry->store, NULL);
168 if (child) {
169 ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child, contextSize);
170 Context_Release(child);
172 else
174 if (storeNext)
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);
188 else
190 SetLastError(CRYPT_E_NOT_FOUND);
191 ret = NULL;
194 TRACE("returning %p\n", ret);
195 return ret;
198 static BOOL Collection_addCert(WINECRYPT_CERTSTORE *store, context_t *cert,
199 context_t *toReplace, context_t **ppStoreContext, BOOL use_link)
201 BOOL ret;
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;
215 if (childContext)
216 Context_Release(childContext);
217 return ret;
220 static context_t *Collection_enumCert(WINECRYPT_CERTSTORE *store, context_t *prev)
222 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
223 context_t *ret;
225 TRACE("(%p, %p)\n", store, prev);
227 EnterCriticalSection(&cs->cs);
228 if (prev)
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));
236 else
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));
247 else
249 SetLastError(CRYPT_E_NOT_FOUND);
250 ret = NULL;
253 LeaveCriticalSection(&cs->cs);
254 TRACE("returning %p\n", ret);
255 return ret;
258 static BOOL Collection_deleteCert(WINECRYPT_CERTSTORE *store, context_t *context)
260 cert_t *cert = (cert_t*)context;
261 cert_t *linked;
262 BOOL ret;
264 TRACE("(%p, %p)\n", store, cert);
266 linked = (cert_t*)context->linked;
267 ret = CertDeleteCertificateFromStore(&linked->ctx);
268 Context_Release(&cert->base);
269 return ret;
272 static BOOL Collection_addCRL(WINECRYPT_CERTSTORE *store, context_t *crl,
273 context_t *toReplace, context_t **ppStoreContext, BOOL use_link)
275 BOOL ret;
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;
289 if (childContext)
290 Context_Release(childContext);
291 return ret;
294 static context_t *Collection_enumCRL(WINECRYPT_CERTSTORE *store, context_t *prev)
296 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
297 context_t *ret;
299 TRACE("(%p, %p)\n", store, prev);
301 EnterCriticalSection(&cs->cs);
302 if (prev)
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));
309 else
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));
320 else
322 SetLastError(CRYPT_E_NOT_FOUND);
323 ret = NULL;
326 LeaveCriticalSection(&cs->cs);
327 TRACE("returning %p\n", ret);
328 return ret;
331 static BOOL Collection_deleteCRL(WINECRYPT_CERTSTORE *store, context_t *context)
333 crl_t *crl = (crl_t*)context, *linked;
334 BOOL ret;
336 TRACE("(%p, %p)\n", store, crl);
338 linked = (crl_t*)context->linked;
339 ret = CertDeleteCRLFromStore(&linked->ctx);
340 Context_Release(&crl->base);
341 return ret;
344 static BOOL Collection_addCTL(WINECRYPT_CERTSTORE *store, context_t *ctl,
345 context_t *toReplace, context_t **ppStoreContext, BOOL use_link)
347 BOOL ret;
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;
361 if (childContext)
362 Context_Release(childContext);
363 return ret;
366 static context_t *Collection_enumCTL(WINECRYPT_CERTSTORE *store, context_t *prev)
368 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
369 void *ret;
371 TRACE("(%p, %p)\n", store, prev);
373 EnterCriticalSection(&cs->cs);
374 if (prev)
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));
381 else
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));
392 else
394 SetLastError(CRYPT_E_NOT_FOUND);
395 ret = NULL;
398 LeaveCriticalSection(&cs->cs);
399 TRACE("returning %p\n", ret);
400 return ret;
403 static BOOL Collection_deleteCTL(WINECRYPT_CERTSTORE *store, context_t *context)
405 ctl_t *ctl = (ctl_t*)context, *linked;
406 BOOL ret;
408 TRACE("(%p, %p)\n", store, ctl);
410 linked = (ctl_t*)context->linked;
411 ret = CertDeleteCTLFromStore(&linked->ctx);
412 Context_Release(&ctl->base);
413 return ret;
416 static BOOL Collection_control(WINECRYPT_CERTSTORE *cert_store, DWORD dwFlags,
417 DWORD dwCtrlType, void const *pvCtrlPara)
419 BOOL ret;
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);
425 if (!store)
426 return TRUE;
427 if (store->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
429 SetLastError(E_INVALIDARG);
430 return FALSE;
432 if (store->hdr.type != StoreTypeCollection)
434 SetLastError(E_INVALIDARG);
435 return FALSE;
438 ret = TRUE;
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);
445 if (!ret)
446 break;
449 LeaveCriticalSection(&store->cs);
450 return ret;
453 static const store_vtbl_t CollectionStoreVtbl = {
454 Collection_addref,
455 Collection_release,
456 Collection_control,
458 Collection_addCert,
459 Collection_enumCert,
460 Collection_deleteCert
461 }, {
462 Collection_addCRL,
463 Collection_enumCRL,
464 Collection_deleteCRL
465 }, {
466 Collection_addCTL,
467 Collection_enumCTL,
468 Collection_deleteCTL
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);
480 store = NULL;
482 else
484 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
485 if (store)
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;
503 BOOL ret;
505 TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore,
506 dwUpdateFlags, dwPriority);
508 if (!collection || !sibling)
509 return TRUE;
510 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
512 SetLastError(E_INVALIDARG);
513 return FALSE;
515 if (collection->hdr.type != StoreTypeCollection)
517 SetLastError(E_INVALIDARG);
518 return FALSE;
520 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
522 SetLastError(E_INVALIDARG);
523 return FALSE;
526 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
527 if (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);
537 if (dwPriority)
539 WINE_STORE_LIST_ENTRY *cursor;
540 BOOL added = FALSE;
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);
548 added = TRUE;
549 break;
552 if (!added)
553 list_add_tail(&collection->stores, &entry->entry);
555 else
556 list_add_tail(&collection->stores, &entry->entry);
557 LeaveCriticalSection(&collection->cs);
558 ret = TRUE;
560 else
561 ret = FALSE;
562 return ret;
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)
575 return;
576 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
578 SetLastError(E_INVALIDARG);
579 return;
581 if (collection->hdr.type != StoreTypeCollection)
582 return;
583 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
585 SetLastError(E_INVALIDARG);
586 return;
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);
596 CryptMemFree(store);
597 break;
600 LeaveCriticalSection(&collection->cs);