winhttp: Don't refill buffer after receiving server response.
[wine.git] / dlls / crypt32 / collectionstore.c
blobe8d6db78641d0296ef4fe70c17835ca55e006aff
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 = %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;
52 LONG ref;
54 if(flags)
55 FIXME("Unimplemented flags %lx\n", flags);
57 ref = InterlockedDecrement(&cs->hdr.ref);
58 TRACE("(%p) ref=%ld\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 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)
83 context_t *ret;
85 ret = child->vtbl->clone(child, &store->hdr, TRUE);
86 if (!ret)
87 return NULL;
89 ret->u.ptr = storeEntry;
90 return ret;
93 static BOOL CRYPT_CollectionAddContext(WINE_COLLECTIONSTORE *store,
94 unsigned int contextFuncsOffset, context_t *context, context_t *toReplace,
95 context_t **pChildContext)
97 BOOL ret;
98 context_t *childContext = NULL;
99 WINE_STORE_LIST_ENTRY *storeEntry = NULL;
101 TRACE("(%p, %d, %p, %p)\n", store, contextFuncsOffset, context, toReplace);
103 ret = FALSE;
104 if (toReplace)
106 context_t *existingLinked = toReplace->linked;
107 CONTEXT_FUNCS *contextFuncs;
109 storeEntry = toReplace->u.ptr;
110 contextFuncs = (CONTEXT_FUNCS*)((LPBYTE)storeEntry->store->vtbl +
111 contextFuncsOffset);
112 ret = contextFuncs->addContext(storeEntry->store, context,
113 existingLinked, &childContext, TRUE);
115 else
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);
127 storeEntry = entry;
128 ret = contextFuncs->addContext(entry->store, context, NULL, &childContext, TRUE);
129 break;
132 LeaveCriticalSection(&store->cs);
133 if (!storeEntry)
134 SetLastError(E_ACCESSDENIED);
136 *pChildContext = childContext;
137 return ret;
140 /* Advances a collection enumeration by one context, if possible, where
141 * advancing means:
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,
151 context_t *prev)
153 context_t *child, *ret;
154 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
156 TRACE("(%p, %p, %p)\n", store, storeEntry, prev);
158 if (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);
168 else
170 child = contextFuncs->enumContext(storeEntry->store, NULL);
172 if (child) {
173 ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child);
174 Context_Release(child);
176 else
178 if (storeNext)
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);
192 else
194 SetLastError(CRYPT_E_NOT_FOUND);
195 ret = NULL;
198 TRACE("returning %p\n", ret);
199 return ret;
202 static BOOL Collection_addCert(WINECRYPT_CERTSTORE *store, context_t *cert,
203 context_t *toReplace, context_t **ppStoreContext, BOOL use_link)
205 BOOL ret;
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,
215 childContext);
217 *ppStoreContext = &context->base;
219 if (childContext)
220 Context_Release(childContext);
221 return ret;
224 static context_t *Collection_enumCert(WINECRYPT_CERTSTORE *store, context_t *prev)
226 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
227 context_t *ret;
229 TRACE("(%p, %p)\n", store, prev);
231 EnterCriticalSection(&cs->cs);
232 if (prev)
234 WINE_STORE_LIST_ENTRY *storeEntry = prev->u.ptr;
236 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
237 &storeEntry->store->vtbl->certs, prev);
239 else
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);
249 else
251 SetLastError(CRYPT_E_NOT_FOUND);
252 ret = NULL;
255 LeaveCriticalSection(&cs->cs);
256 TRACE("returning %p\n", ret);
257 return ret;
260 static BOOL Collection_deleteCert(WINECRYPT_CERTSTORE *store, context_t *context)
262 cert_t *cert = (cert_t*)context;
263 cert_t *linked;
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)
274 BOOL ret;
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,
284 childContext);
286 *ppStoreContext = &context->base;
288 if (childContext)
289 Context_Release(childContext);
290 return ret;
293 static context_t *Collection_enumCRL(WINECRYPT_CERTSTORE *store, context_t *prev)
295 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
296 context_t *ret;
298 TRACE("(%p, %p)\n", store, prev);
300 EnterCriticalSection(&cs->cs);
301 if (prev)
303 WINE_STORE_LIST_ENTRY *storeEntry = prev->u.ptr;
305 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
306 &storeEntry->store->vtbl->crls, prev);
308 else
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);
318 else
320 SetLastError(CRYPT_E_NOT_FOUND);
321 ret = NULL;
324 LeaveCriticalSection(&cs->cs);
325 TRACE("returning %p\n", ret);
326 return 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)
342 BOOL ret;
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,
352 childContext);
354 *ppStoreContext = &context->base;
356 if (childContext)
357 Context_Release(childContext);
358 return ret;
361 static context_t *Collection_enumCTL(WINECRYPT_CERTSTORE *store, context_t *prev)
363 WINE_COLLECTIONSTORE *cs = (WINE_COLLECTIONSTORE*)store;
364 void *ret;
366 TRACE("(%p, %p)\n", store, prev);
368 EnterCriticalSection(&cs->cs);
369 if (prev)
371 WINE_STORE_LIST_ENTRY *storeEntry = prev->u.ptr;
373 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
374 &storeEntry->store->vtbl->ctls, prev);
376 else
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);
386 else
388 SetLastError(CRYPT_E_NOT_FOUND);
389 ret = NULL;
392 LeaveCriticalSection(&cs->cs);
393 TRACE("returning %p\n", ret);
394 return 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)
410 BOOL ret;
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);
416 if (!store)
417 return TRUE;
418 if (store->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
420 SetLastError(E_INVALIDARG);
421 return FALSE;
423 if (store->hdr.type != StoreTypeCollection)
425 SetLastError(E_INVALIDARG);
426 return FALSE;
429 ret = TRUE;
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);
436 if (!ret)
437 break;
440 LeaveCriticalSection(&store->cs);
441 return ret;
444 static const store_vtbl_t CollectionStoreVtbl = {
445 Collection_addref,
446 Collection_release,
447 Collection_releaseContext,
448 Collection_control,
450 Collection_addCert,
451 Collection_enumCert,
452 Collection_deleteCert
453 }, {
454 Collection_addCRL,
455 Collection_enumCRL,
456 Collection_deleteCRL
457 }, {
458 Collection_addCTL,
459 Collection_enumCTL,
460 Collection_deleteCTL
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);
472 store = NULL;
474 else
476 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
477 if (store)
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;
495 BOOL ret;
497 TRACE("(%p, %p, %08lx, %ld)\n", hCollectionStore, hSiblingStore,
498 dwUpdateFlags, dwPriority);
500 if (!collection || !sibling)
501 return TRUE;
502 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
504 SetLastError(E_INVALIDARG);
505 return FALSE;
507 if (collection->hdr.type != StoreTypeCollection)
509 SetLastError(E_INVALIDARG);
510 return FALSE;
512 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
514 SetLastError(E_INVALIDARG);
515 return FALSE;
518 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
519 if (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);
528 if (dwPriority)
530 WINE_STORE_LIST_ENTRY *cursor;
531 BOOL added = FALSE;
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);
539 added = TRUE;
540 break;
543 if (!added)
544 list_add_tail(&collection->stores, &entry->entry);
546 else
547 list_add_tail(&collection->stores, &entry->entry);
548 LeaveCriticalSection(&collection->cs);
549 ret = TRUE;
551 else
552 ret = FALSE;
553 return ret;
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)
566 return;
567 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
569 SetLastError(E_INVALIDARG);
570 return;
572 if (collection->hdr.type != StoreTypeCollection)
573 return;
574 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
576 SetLastError(E_INVALIDARG);
577 return;
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);
586 CryptMemFree(store);
587 break;
590 LeaveCriticalSection(&collection->cs);