source: trunk/src/crypt32/collectionstore.c@ 22012

Last change on this file since 22012 was 21967, checked in by dmik, 14 years ago

Don't access debug fields in CRITICAL_SECTION in release builds.

This fixes occasional crashes in CRYPT32.DLL (e.g. when playing back
some Flash contents).

File size: 17.9 KB
Line 
1/*
2 * Copyright 2004-2007 Juan Lang
3 *
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.
8 *
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.
13 *
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
17 */
18#include <stdarg.h>
19#include <string.h>
20#include "windef.h"
21#include "winbase.h"
22#include "winbase.h"
23#include "winerror.h"
24#include "wincrypt.h"
25#include "wine/debug.h"
26#include "wine/list.h"
27#include "crypt32_private.h"
28#include "winnt.h"
29
30ODINDEBUGCHANNEL(crypt);
31
32
33typedef struct _WINE_STORE_LIST_ENTRY
34{
35 PWINECRYPT_CERTSTORE store;
36 DWORD dwUpdateFlags;
37 DWORD dwPriority;
38 struct list entry;
39} WINE_STORE_LIST_ENTRY, *PWINE_STORE_LIST_ENTRY;
40
41typedef struct _WINE_COLLECTIONSTORE
42{
43 WINECRYPT_CERTSTORE hdr;
44 /*CRITICAL_SECTION*/RTL_CRITICAL_SECTION cs;
45 struct list stores;
46} WINE_COLLECTIONSTORE, *PWINE_COLLECTIONSTORE;
47
48static void WINAPI CRYPT_CollectionCloseStore(HCERTSTORE store, DWORD dwFlags)
49{
50 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
51 PWINE_STORE_LIST_ENTRY entry, next;
52
53 TRACE("(%p, %08x)\n", store, dwFlags);
54
55 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY,
56 entry)
57 {
58 TRACE("closing %p\n", entry);
59 CertCloseStore((HCERTSTORE)entry->store, dwFlags);
60 CryptMemFree(entry);
61 }
62#ifdef DEBUG
63 cs->cs.DebugInfo->Spare[0] = 0;
64#endif
65 DeleteCriticalSection((CRITICAL_SECTION*)&cs->cs);
66 CRYPT_FreeStore((PWINECRYPT_CERTSTORE)store);
67}
68
69static void *CRYPT_CollectionCreateContextFromChild(PWINE_COLLECTIONSTORE store,
70 PWINE_STORE_LIST_ENTRY storeEntry, void *child, size_t contextSize,
71 BOOL addRef)
72{
73 void *ret = Context_CreateLinkContext(contextSize, child,
74 sizeof(PWINE_STORE_LIST_ENTRY), addRef);
75
76 if (ret)
77 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(ret, contextSize)
78 = storeEntry;
79
80 return ret;
81}
82
83static BOOL CRYPT_CollectionAddContext(PWINE_COLLECTIONSTORE store,
84 unsigned int contextFuncsOffset, void *context, void *toReplace, unsigned int contextSize,
85 void **pChildContext)
86{
87 BOOL ret;
88 void *childContext = NULL;
89 PWINE_STORE_LIST_ENTRY storeEntry = NULL;
90
91 TRACE("(%p, %d, %p, %p, %d)\n", store, contextFuncsOffset, context,
92 toReplace, contextSize);
93
94 ret = FALSE;
95 if (toReplace)
96 {
97 void *existingLinked = Context_GetLinkedContext(toReplace, contextSize);
98 PCONTEXT_FUNCS contextFuncs;
99
100 storeEntry = *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(toReplace,
101 contextSize);
102 contextFuncs = (PCONTEXT_FUNCS)((LPBYTE)storeEntry->store +
103 contextFuncsOffset);
104 ret = contextFuncs->addContext(storeEntry->store, context,
105 existingLinked, childContext);
106 }
107 else
108 {
109 PWINE_STORE_LIST_ENTRY entry, next;
110
111 EnterCriticalSection((CRITICAL_SECTION*)&store->cs);
112 LIST_FOR_EACH_ENTRY_SAFE(entry, next, &store->stores,
113 WINE_STORE_LIST_ENTRY, entry)
114 {
115 if (entry->dwUpdateFlags & CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG)
116 {
117 PCONTEXT_FUNCS contextFuncs = (PCONTEXT_FUNCS)(
118 (LPBYTE)entry->store + contextFuncsOffset);
119
120 storeEntry = entry;
121 ret = contextFuncs->addContext(entry->store, context, NULL,
122 (const void **)&childContext);
123 break;
124 }
125 }
126 LeaveCriticalSection((CRITICAL_SECTION*)&store->cs);
127 if (!storeEntry)
128 SetLastError(E_ACCESSDENIED);
129 }
130 *pChildContext = childContext;
131 return ret;
132}
133
134/* Advances a collection enumeration by one context, if possible, where
135 * advancing means:
136 * - calling the current store's enumeration function once, and returning
137 * the enumerated context if one is returned
138 * - moving to the next store if the current store has no more items, and
139 * recursively calling itself to get the next item.
140 * Returns NULL if the collection contains no more items or on error.
141 * Assumes the collection store's lock is held.
142 */
143static void *CRYPT_CollectionAdvanceEnum(PWINE_COLLECTIONSTORE store,
144 PWINE_STORE_LIST_ENTRY storeEntry, PCONTEXT_FUNCS contextFuncs,
145 PCWINE_CONTEXT_INTERFACE contextInterface, void *pPrev, size_t contextSize)
146{
147 void *ret, *child;
148 struct list *storeNext = list_next(&store->stores, &storeEntry->entry);
149
150 TRACE("(%p, %p, %p)\n", store, storeEntry, pPrev);
151
152 if (pPrev)
153 {
154 /* Ref-counting funny business: "duplicate" (addref) the child, because
155 * the free(pPrev) below can cause the ref count to become negative.
156 */
157 child = Context_GetLinkedContext(pPrev, contextSize);
158 contextInterface->duplicate(child);
159 child = contextFuncs->enumContext(storeEntry->store, child);
160 contextInterface->confree(pPrev);
161 pPrev = NULL;
162 }
163 else
164 child = contextFuncs->enumContext(storeEntry->store, NULL);
165 if (child)
166 ret = CRYPT_CollectionCreateContextFromChild(store, storeEntry, child,
167 contextSize, FALSE);
168 else
169 {
170 if (storeNext)
171 {
172 /* We always want the same function pointers (from certs, crls)
173 * in the next store, so use the same offset into the next store.
174 */
175 size_t offset = (LPBYTE)contextFuncs - (LPBYTE)storeEntry->store;
176 PWINE_STORE_LIST_ENTRY storeNextEntry =
177 LIST_ENTRY(storeNext, WINE_STORE_LIST_ENTRY, entry);
178 PCONTEXT_FUNCS storeNextContexts =
179 (PCONTEXT_FUNCS)((LPBYTE)storeNextEntry->store + offset);
180
181 ret = CRYPT_CollectionAdvanceEnum(store, storeNextEntry,
182 storeNextContexts, contextInterface, NULL, contextSize);
183 }
184 else
185 {
186 SetLastError(CRYPT_E_NOT_FOUND);
187 ret = NULL;
188 }
189 }
190 TRACE("returning %p\n", ret);
191 return ret;
192}
193
194static BOOL CRYPT_CollectionAddCert(PWINECRYPT_CERTSTORE store, void *cert,
195 void *toReplace, const void **ppStoreContext)
196{
197 BOOL ret;
198 void *childContext = NULL;
199 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
200
201 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, certs),
202 cert, toReplace, sizeof(CERT_CONTEXT), &childContext);
203 if (ppStoreContext && childContext)
204 {
205 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
206 Context_GetExtra(childContext, sizeof(CERT_CONTEXT));
207 PCERT_CONTEXT context =
208 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
209 sizeof(CERT_CONTEXT), TRUE);
210
211 if (context)
212 context->hCertStore = store;
213 *ppStoreContext = context;
214 }
215 CertFreeCertificateContext((PCCERT_CONTEXT)childContext);
216 return ret;
217}
218
219static void *CRYPT_CollectionEnumCert(PWINECRYPT_CERTSTORE store, void *pPrev)
220{
221 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
222 void *ret;
223
224 TRACE("(%p, %p)\n", store, pPrev);
225
226 EnterCriticalSection((CRITICAL_SECTION*)&cs->cs);
227 if (pPrev)
228 {
229 PWINE_STORE_LIST_ENTRY storeEntry =
230 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
231 sizeof(CERT_CONTEXT));
232
233 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
234 &storeEntry->store->certs, pCertInterface, pPrev,
235 sizeof(CERT_CONTEXT));
236 }
237 else
238 {
239 if (!list_empty(&cs->stores))
240 {
241 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
242 WINE_STORE_LIST_ENTRY, entry);
243
244 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
245 &storeEntry->store->certs, pCertInterface, NULL,
246 sizeof(CERT_CONTEXT));
247 }
248 else
249 {
250 SetLastError(CRYPT_E_NOT_FOUND);
251 ret = NULL;
252 }
253 }
254 LeaveCriticalSection((CRITICAL_SECTION*)&cs->cs);
255 if (ret)
256 ((PCERT_CONTEXT)ret)->hCertStore = store;
257 TRACE("returning %p\n", ret);
258 return ret;
259}
260
261static BOOL CRYPT_CollectionDeleteCert(PWINECRYPT_CERTSTORE store,
262 void *pCertContext)
263{
264 BOOL ret;
265
266 TRACE("(%p, %p)\n", store, pCertContext);
267
268 ret = CertDeleteCertificateFromStore((PCCERT_CONTEXT)
269 Context_GetLinkedContext(pCertContext, sizeof(CERT_CONTEXT)));
270 return ret;
271}
272
273static BOOL CRYPT_CollectionAddCRL(PWINECRYPT_CERTSTORE store, void *crl,
274 void *toReplace, const void **ppStoreContext)
275{
276 BOOL ret;
277 void *childContext = NULL;
278 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
279
280 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, crls),
281 crl, toReplace, sizeof(CRL_CONTEXT), &childContext);
282 if (ppStoreContext && childContext)
283 {
284 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
285 Context_GetExtra(childContext, sizeof(CRL_CONTEXT));
286 PCRL_CONTEXT context =
287 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
288 sizeof(CRL_CONTEXT), TRUE);
289
290 if (context)
291 context->hCertStore = store;
292 *ppStoreContext = context;
293 }
294 CertFreeCRLContext((PCCRL_CONTEXT)childContext);
295 return ret;
296}
297
298static void *CRYPT_CollectionEnumCRL(PWINECRYPT_CERTSTORE store, void *pPrev)
299{
300 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
301 void *ret;
302
303 TRACE("(%p, %p)\n", store, pPrev);
304
305 EnterCriticalSection((CRITICAL_SECTION*)&cs->cs);
306 if (pPrev)
307 {
308 PWINE_STORE_LIST_ENTRY storeEntry =
309 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
310 sizeof(CRL_CONTEXT));
311
312 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
313 &storeEntry->store->crls, pCRLInterface, pPrev, sizeof(CRL_CONTEXT));
314 }
315 else
316 {
317 if (!list_empty(&cs->stores))
318 {
319 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
320 WINE_STORE_LIST_ENTRY, entry);
321
322 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
323 &storeEntry->store->crls, pCRLInterface, NULL,
324 sizeof(CRL_CONTEXT));
325 }
326 else
327 {
328 SetLastError(CRYPT_E_NOT_FOUND);
329 ret = NULL;
330 }
331 }
332 LeaveCriticalSection((CRITICAL_SECTION*)&cs->cs);
333 if (ret)
334 ((PCRL_CONTEXT)ret)->hCertStore = store;
335 TRACE("returning %p\n", ret);
336 return ret;
337}
338
339static BOOL CRYPT_CollectionDeleteCRL(PWINECRYPT_CERTSTORE store,
340 void *pCrlContext)
341{
342 BOOL ret;
343
344 TRACE("(%p, %p)\n", store, pCrlContext);
345
346 ret = CertDeleteCRLFromStore((PCCRL_CONTEXT)
347 Context_GetLinkedContext(pCrlContext, sizeof(CRL_CONTEXT)));
348 return ret;
349}
350
351static BOOL CRYPT_CollectionAddCTL(PWINECRYPT_CERTSTORE store, void *ctl,
352 void *toReplace, const void **ppStoreContext)
353{
354 BOOL ret;
355 void *childContext = NULL;
356 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
357
358 ret = CRYPT_CollectionAddContext(cs, offsetof(WINECRYPT_CERTSTORE, ctls),
359 ctl, toReplace, sizeof(CTL_CONTEXT), &childContext);
360 if (ppStoreContext && childContext)
361 {
362 PWINE_STORE_LIST_ENTRY storeEntry = *(PWINE_STORE_LIST_ENTRY *)
363 Context_GetExtra(childContext, sizeof(CTL_CONTEXT));
364 PCTL_CONTEXT context =
365 CRYPT_CollectionCreateContextFromChild(cs, storeEntry, childContext,
366 sizeof(CTL_CONTEXT), TRUE);
367
368 if (context)
369 context->hCertStore = store;
370 *ppStoreContext = context;
371 }
372 CertFreeCTLContext((PCCTL_CONTEXT)childContext);
373 return ret;
374}
375
376static void *CRYPT_CollectionEnumCTL(PWINECRYPT_CERTSTORE store, void *pPrev)
377{
378 PWINE_COLLECTIONSTORE cs = (PWINE_COLLECTIONSTORE)store;
379 void *ret;
380
381 TRACE("(%p, %p)\n", store, pPrev);
382
383 EnterCriticalSection((CRITICAL_SECTION*)&cs->cs);
384 if (pPrev)
385 {
386 PWINE_STORE_LIST_ENTRY storeEntry =
387 *(PWINE_STORE_LIST_ENTRY *)Context_GetExtra(pPrev,
388 sizeof(CTL_CONTEXT));
389
390 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
391 &storeEntry->store->ctls, pCTLInterface, pPrev, sizeof(CTL_CONTEXT));
392 }
393 else
394 {
395 if (!list_empty(&cs->stores))
396 {
397 PWINE_STORE_LIST_ENTRY storeEntry = LIST_ENTRY(cs->stores.next,
398 WINE_STORE_LIST_ENTRY, entry);
399
400 ret = CRYPT_CollectionAdvanceEnum(cs, storeEntry,
401 &storeEntry->store->ctls, pCTLInterface, NULL,
402 sizeof(CTL_CONTEXT));
403 }
404 else
405 {
406 SetLastError(CRYPT_E_NOT_FOUND);
407 ret = NULL;
408 }
409 }
410 LeaveCriticalSection((CRITICAL_SECTION*)&cs->cs);
411 if (ret)
412 ((PCTL_CONTEXT)ret)->hCertStore = store;
413 TRACE("returning %p\n", ret);
414 return ret;
415}
416
417static BOOL CRYPT_CollectionDeleteCTL(PWINECRYPT_CERTSTORE store,
418 void *pCtlContext)
419{
420 BOOL ret;
421
422 TRACE("(%p, %p)\n", store, pCtlContext);
423
424 ret = CertDeleteCTLFromStore((PCCTL_CONTEXT)
425 Context_GetLinkedContext(pCtlContext, sizeof(CTL_CONTEXT)));
426 return ret;
427}
428
429PWINECRYPT_CERTSTORE CRYPT_CollectionOpenStore(HCRYPTPROV hCryptProv,
430 DWORD dwFlags, const void *pvPara)
431{
432 PWINE_COLLECTIONSTORE store;
433
434 if (dwFlags & CERT_STORE_DELETE_FLAG)
435 {
436 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
437 store = NULL;
438 }
439 else
440 {
441 store = CryptMemAlloc(sizeof(WINE_COLLECTIONSTORE));
442 if (store)
443 {
444 memset(store, 0, sizeof(WINE_COLLECTIONSTORE));
445 CRYPT_InitStore(&store->hdr, dwFlags, StoreTypeCollection);
446 store->hdr.closeStore = CRYPT_CollectionCloseStore;
447 store->hdr.certs.addContext = CRYPT_CollectionAddCert;
448 store->hdr.certs.enumContext = CRYPT_CollectionEnumCert;
449 store->hdr.certs.deleteContext = CRYPT_CollectionDeleteCert;
450 store->hdr.crls.addContext = CRYPT_CollectionAddCRL;
451 store->hdr.crls.enumContext = CRYPT_CollectionEnumCRL;
452 store->hdr.crls.deleteContext = CRYPT_CollectionDeleteCRL;
453 store->hdr.ctls.addContext = CRYPT_CollectionAddCTL;
454 store->hdr.ctls.enumContext = CRYPT_CollectionEnumCTL;
455 store->hdr.ctls.deleteContext = CRYPT_CollectionDeleteCTL;
456 InitializeCriticalSection((CRITICAL_SECTION*)&store->cs);
457#ifdef DEBUG
458 store->cs.DebugInfo->Spare[0] = (DWORD)(DWORD_PTR)(__FILE__ ": PWINE_COLLECTIONSTORE->cs");
459#endif
460 list_init(&store->stores);
461 }
462 }
463 return (PWINECRYPT_CERTSTORE)store;
464}
465
466BOOL WINAPI CertAddStoreToCollection(HCERTSTORE hCollectionStore,
467 HCERTSTORE hSiblingStore, DWORD dwUpdateFlags, DWORD dwPriority)
468{
469 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
470 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
471 PWINE_STORE_LIST_ENTRY entry;
472 BOOL ret;
473
474 TRACE("(%p, %p, %08x, %d)\n", hCollectionStore, hSiblingStore,
475 dwUpdateFlags, dwPriority);
476
477 if (!collection || !sibling)
478 return TRUE;
479 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
480 {
481 SetLastError(E_INVALIDARG);
482 return FALSE;
483 }
484 if (collection->hdr.type != StoreTypeCollection)
485 {
486 SetLastError(E_INVALIDARG);
487 return FALSE;
488 }
489 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
490 {
491 SetLastError(E_INVALIDARG);
492 return FALSE;
493 }
494
495 entry = CryptMemAlloc(sizeof(WINE_STORE_LIST_ENTRY));
496 if (entry)
497 {
498 InterlockedIncrement(&sibling->ref);
499 TRACE("sibling %p's ref count is %d\n", sibling, sibling->ref);
500 entry->store = sibling;
501 entry->dwUpdateFlags = dwUpdateFlags;
502 entry->dwPriority = dwPriority;
503 list_init(&entry->entry);
504 TRACE("%p: adding %p, priority %d\n", collection, entry, dwPriority);
505 EnterCriticalSection((CRITICAL_SECTION*)&collection->cs);
506 if (dwPriority)
507 {
508 PWINE_STORE_LIST_ENTRY cursor;
509 BOOL added = FALSE;
510
511 LIST_FOR_EACH_ENTRY(cursor, &collection->stores,
512 WINE_STORE_LIST_ENTRY, entry)
513 {
514 if (cursor->dwPriority < dwPriority)
515 {
516 list_add_before(&cursor->entry, &entry->entry);
517 added = TRUE;
518 break;
519 }
520 }
521 if (!added)
522 list_add_tail(&collection->stores, &entry->entry);
523 }
524 else
525 list_add_tail(&collection->stores, &entry->entry);
526 LeaveCriticalSection((CRITICAL_SECTION*)&collection->cs);
527 ret = TRUE;
528 }
529 else
530 ret = FALSE;
531 return ret;
532}
533
534void WINAPI CertRemoveStoreFromCollection(HCERTSTORE hCollectionStore,
535 HCERTSTORE hSiblingStore)
536{
537 PWINE_COLLECTIONSTORE collection = (PWINE_COLLECTIONSTORE)hCollectionStore;
538 WINECRYPT_CERTSTORE *sibling = (WINECRYPT_CERTSTORE *)hSiblingStore;
539 PWINE_STORE_LIST_ENTRY store, next;
540
541 TRACE("(%p, %p)\n", hCollectionStore, hSiblingStore);
542
543 if (!collection || !sibling)
544 return;
545 if (collection->hdr.dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
546 {
547 SetLastError(E_INVALIDARG);
548 return;
549 }
550 if (collection->hdr.type != StoreTypeCollection)
551 return;
552 if (sibling->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
553 {
554 SetLastError(E_INVALIDARG);
555 return;
556 }
557 EnterCriticalSection((CRITICAL_SECTION*)&collection->cs);
558 LIST_FOR_EACH_ENTRY_SAFE(store, next, &collection->stores,
559 WINE_STORE_LIST_ENTRY, entry)
560 {
561 if (store->store == sibling)
562 {
563 list_remove(&store->entry);
564 CertCloseStore(store->store, 0);
565 CryptMemFree(store);
566 break;
567 }
568 }
569 LeaveCriticalSection((CRITICAL_SECTION*)&collection->cs);
570}
Note: See TracBrowser for help on using the repository browser.