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

Last change on this file since 21329 was 21311, checked in by vladest, 16 years ago

Added CRYPT32 and MSCMS APIs support

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