cmd: DIR command outputs free space for the path.
[wine.git] / dlls / crypt32 / regstore.c
blob4f8914798f6d1c30ae52c4d5b546fb22d5dfcf36
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 <assert.h>
19 #include <stdarg.h>
20 #include "windef.h"
21 #include "winbase.h"
22 #include "wincrypt.h"
23 #include "winreg.h"
24 #include "winuser.h"
25 #include "wine/debug.h"
26 #include "crypt32_private.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30 typedef struct _WINE_HASH_TO_DELETE
32 BYTE hash[20];
33 struct list entry;
34 } WINE_HASH_TO_DELETE;
36 typedef struct _WINE_REGSTOREINFO
38 DWORD dwOpenFlags;
39 HCERTSTORE memStore;
40 HKEY key;
41 BOOL dirty;
42 CRITICAL_SECTION cs;
43 struct list certsToDelete;
44 struct list crlsToDelete;
45 struct list ctlsToDelete;
46 } WINE_REGSTOREINFO;
48 static void CRYPT_HashToStr(const BYTE *hash, LPWSTR asciiHash)
50 DWORD i;
52 assert(hash);
53 assert(asciiHash);
55 for (i = 0; i < 20; i++)
56 wsprintfW(asciiHash + i * 2, L"%02X", hash[i]);
59 void CRYPT_RegReadSerializedFromReg(HKEY key, DWORD contextType, HCERTSTORE store, DWORD disposition)
61 LONG rc;
62 DWORD index = 0;
63 WCHAR subKeyName[MAX_PATH];
65 do {
66 DWORD size = ARRAY_SIZE(subKeyName);
68 rc = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, NULL,
69 NULL);
70 if (!rc)
72 HKEY subKey;
74 rc = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey);
75 if (!rc)
77 LPBYTE buf = NULL;
79 size = 0;
80 rc = RegQueryValueExW(subKey, L"Blob", NULL, NULL, NULL, &size);
81 if (!rc)
82 buf = CryptMemAlloc(size);
83 if (buf)
85 rc = RegQueryValueExW(subKey, L"Blob", NULL, NULL, buf,
86 &size);
87 if (!rc)
89 const void *context;
90 DWORD addedType;
92 TRACE("Adding cert with hash %s\n",
93 debugstr_w(subKeyName));
94 context = CRYPT_ReadSerializedElement(buf, size,
95 contextType, &addedType);
96 if (context)
98 const WINE_CONTEXT_INTERFACE *contextInterface;
99 BYTE hash[20];
101 switch (addedType)
103 case CERT_STORE_CERTIFICATE_CONTEXT:
104 contextInterface = pCertInterface;
105 break;
106 case CERT_STORE_CRL_CONTEXT:
107 contextInterface = pCRLInterface;
108 break;
109 case CERT_STORE_CTL_CONTEXT:
110 contextInterface = pCTLInterface;
111 break;
112 default:
113 contextInterface = NULL;
115 if (contextInterface)
117 size = sizeof(hash);
118 if (contextInterface->getProp(context,
119 CERT_HASH_PROP_ID, hash, &size))
121 WCHAR asciiHash[20 * 2 + 1];
123 CRYPT_HashToStr(hash, asciiHash);
124 TRACE("comparing %s\n",
125 debugstr_w(asciiHash));
126 TRACE("with %s\n", debugstr_w(subKeyName));
127 if (!wcscmp(asciiHash, subKeyName))
129 TRACE("hash matches, adding\n");
130 contextInterface->addContextToStore(
131 store, context,
132 disposition, NULL);
134 else
135 TRACE("hash doesn't match, ignoring\n");
137 Context_Release(context_from_ptr(context));
141 CryptMemFree(buf);
143 RegCloseKey(subKey);
145 /* Ignore intermediate errors, continue enumerating */
146 rc = ERROR_SUCCESS;
148 } while (!rc);
151 static void CRYPT_RegReadFromReg(HKEY key, HCERTSTORE store, DWORD disposition)
153 static const WCHAR * const subKeys[] = { L"Certificates", L"CRLs", L"CTLs" };
154 static const DWORD contextFlags[] = { CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
155 CERT_STORE_CRL_CONTEXT_FLAG, CERT_STORE_CTL_CONTEXT_FLAG };
156 DWORD i;
158 for (i = 0; i < ARRAY_SIZE(subKeys); i++)
160 HKEY hKey;
161 LONG rc;
163 rc = RegCreateKeyExW(key, subKeys[i], 0, NULL, 0, KEY_READ, NULL,
164 &hKey, NULL);
165 if (!rc)
167 CRYPT_RegReadSerializedFromReg(hKey, contextFlags[i], store, disposition);
168 RegCloseKey(hKey);
173 /* Hash is assumed to be 20 bytes in length (a SHA-1 hash) */
174 static BOOL CRYPT_WriteSerializedToReg(HKEY key, DWORD flags, const BYTE *hash, const BYTE *buf,
175 DWORD len)
177 WCHAR asciiHash[20 * 2 + 1];
178 LONG rc;
179 HKEY subKey;
180 BOOL ret;
182 CRYPT_HashToStr(hash, asciiHash);
183 rc = RegCreateKeyExW(key, asciiHash, 0, NULL, flags, KEY_ALL_ACCESS, NULL,
184 &subKey, NULL);
185 if (!rc)
187 rc = RegSetValueExW(subKey, L"Blob", 0, REG_BINARY, buf, len);
188 RegCloseKey(subKey);
190 if (!rc)
191 ret = TRUE;
192 else
194 SetLastError(rc);
195 ret = FALSE;
197 return ret;
200 BOOL CRYPT_SerializeContextsToReg(HKEY key, DWORD flags,
201 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE memStore)
203 const void *context = NULL;
204 BOOL ret;
206 do {
207 context = contextInterface->enumContextsInStore(memStore, context);
208 if (context)
210 BYTE hash[20];
211 DWORD hashSize = sizeof(hash);
213 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID, hash,
214 &hashSize);
215 if (ret)
217 DWORD size = 0;
218 LPBYTE buf = NULL;
220 ret = contextInterface->serialize(context, 0, NULL, &size);
221 if (size)
222 buf = CryptMemAlloc(size);
223 if (buf)
225 ret = contextInterface->serialize(context, 0, buf, &size);
226 if (ret)
227 ret = CRYPT_WriteSerializedToReg(key, flags, hash, buf, size);
229 CryptMemFree(buf);
232 else
233 ret = TRUE;
234 } while (ret && context != NULL);
235 if (context)
236 Context_Release(context_from_ptr(context));
237 return ret;
240 static BOOL CRYPT_RegWriteToReg(WINE_REGSTOREINFO *store)
242 static const WCHAR * const subKeys[] = { L"Certificates", L"CRLs", L"CTLs" };
243 const WINE_CONTEXT_INTERFACE * const interfaces[] = { pCertInterface,
244 pCRLInterface, pCTLInterface };
245 struct list *listToDelete[] = { &store->certsToDelete, &store->crlsToDelete,
246 &store->ctlsToDelete };
247 BOOL ret = TRUE;
248 DWORD i;
250 for (i = 0; ret && i < ARRAY_SIZE(subKeys); i++)
252 HKEY key;
253 LONG rc = RegCreateKeyExW(store->key, subKeys[i], 0, NULL, 0,
254 KEY_ALL_ACCESS, NULL, &key, NULL);
256 if (!rc)
258 if (listToDelete[i])
260 WINE_HASH_TO_DELETE *toDelete, *next;
261 WCHAR asciiHash[20 * 2 + 1];
263 EnterCriticalSection(&store->cs);
264 LIST_FOR_EACH_ENTRY_SAFE(toDelete, next, listToDelete[i],
265 WINE_HASH_TO_DELETE, entry)
267 LONG rc;
269 CRYPT_HashToStr(toDelete->hash, asciiHash);
270 TRACE("Removing %s\n", debugstr_w(asciiHash));
271 rc = RegDeleteKeyW(key, asciiHash);
272 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
274 SetLastError(rc);
275 ret = FALSE;
277 list_remove(&toDelete->entry);
278 CryptMemFree(toDelete);
280 LeaveCriticalSection(&store->cs);
282 ret = CRYPT_SerializeContextsToReg(key, 0, interfaces[i], store->memStore);
283 RegCloseKey(key);
285 else
287 SetLastError(rc);
288 ret = FALSE;
291 return ret;
294 /* If force is true or the registry store is dirty, writes the contents of the
295 * store to the registry.
297 static BOOL CRYPT_RegFlushStore(WINE_REGSTOREINFO *store, BOOL force)
299 BOOL ret;
301 TRACE("(%p, %d)\n", store, force);
303 if (store->dirty || force)
305 ret = CRYPT_RegWriteToReg(store);
306 if (ret)
307 store->dirty = FALSE;
309 else
310 ret = TRUE;
311 return ret;
314 static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
316 WINE_REGSTOREINFO *store = hCertStore;
318 TRACE("(%p, %08lx)\n", store, dwFlags);
319 if (dwFlags)
320 FIXME("Unimplemented flags: %08lx\n", dwFlags);
322 CRYPT_RegFlushStore(store, FALSE);
323 RegCloseKey(store->key);
324 store->cs.DebugInfo->Spare[0] = 0;
325 DeleteCriticalSection(&store->cs);
326 CryptMemFree(store);
329 static BOOL CRYPT_RegWriteContext(WINE_REGSTOREINFO *store,
330 const void *context, DWORD dwFlags)
332 BOOL ret;
334 if (dwFlags & CERT_STORE_PROV_WRITE_ADD_FLAG)
336 store->dirty = TRUE;
337 ret = TRUE;
339 else
340 ret = FALSE;
341 return ret;
344 static BOOL CRYPT_RegDeleteContext(WINE_REGSTOREINFO *store,
345 struct list *deleteList, const void *context,
346 const WINE_CONTEXT_INTERFACE *contextInterface)
348 BOOL ret;
350 if (store->dwOpenFlags & CERT_STORE_READONLY_FLAG)
352 SetLastError(ERROR_ACCESS_DENIED);
353 ret = FALSE;
355 else
357 WINE_HASH_TO_DELETE *toDelete = CryptMemAlloc(sizeof(WINE_HASH_TO_DELETE));
359 if (toDelete)
361 DWORD size = sizeof(toDelete->hash);
363 ret = contextInterface->getProp(context, CERT_HASH_PROP_ID,
364 toDelete->hash, &size);
365 if (ret)
367 EnterCriticalSection(&store->cs);
368 list_add_tail(deleteList, &toDelete->entry);
369 LeaveCriticalSection(&store->cs);
371 else
373 CryptMemFree(toDelete);
374 ret = FALSE;
377 else
378 ret = FALSE;
379 if (ret)
380 store->dirty = TRUE;
382 return ret;
385 static BOOL WINAPI CRYPT_RegWriteCert(HCERTSTORE hCertStore,
386 PCCERT_CONTEXT cert, DWORD dwFlags)
388 WINE_REGSTOREINFO *store = hCertStore;
390 TRACE("(%p, %p, %ld)\n", hCertStore, cert, dwFlags);
392 return CRYPT_RegWriteContext(store, cert, dwFlags);
395 static BOOL WINAPI CRYPT_RegDeleteCert(HCERTSTORE hCertStore,
396 PCCERT_CONTEXT pCertContext, DWORD dwFlags)
398 WINE_REGSTOREINFO *store = hCertStore;
400 TRACE("(%p, %p, %08lx)\n", store, pCertContext, dwFlags);
402 return CRYPT_RegDeleteContext(store, &store->certsToDelete, pCertContext,
403 pCertInterface);
406 static BOOL WINAPI CRYPT_RegWriteCRL(HCERTSTORE hCertStore,
407 PCCRL_CONTEXT crl, DWORD dwFlags)
409 WINE_REGSTOREINFO *store = hCertStore;
411 TRACE("(%p, %p, %ld)\n", hCertStore, crl, dwFlags);
413 return CRYPT_RegWriteContext(store, crl, dwFlags);
416 static BOOL WINAPI CRYPT_RegDeleteCRL(HCERTSTORE hCertStore,
417 PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
419 WINE_REGSTOREINFO *store = hCertStore;
421 TRACE("(%p, %p, %08lx)\n", store, pCrlContext, dwFlags);
423 return CRYPT_RegDeleteContext(store, &store->crlsToDelete, pCrlContext,
424 pCRLInterface);
427 static BOOL WINAPI CRYPT_RegWriteCTL(HCERTSTORE hCertStore,
428 PCCTL_CONTEXT ctl, DWORD dwFlags)
430 WINE_REGSTOREINFO *store = hCertStore;
432 TRACE("(%p, %p, %ld)\n", hCertStore, ctl, dwFlags);
434 return CRYPT_RegWriteContext(store, ctl, dwFlags);
437 static BOOL WINAPI CRYPT_RegDeleteCTL(HCERTSTORE hCertStore,
438 PCCTL_CONTEXT pCtlContext, DWORD dwFlags)
440 WINE_REGSTOREINFO *store = hCertStore;
442 TRACE("(%p, %p, %08lx)\n", store, pCtlContext, dwFlags);
444 return CRYPT_RegDeleteContext(store, &store->ctlsToDelete, pCtlContext,
445 pCTLInterface);
448 static BOOL WINAPI CRYPT_RegControl(HCERTSTORE hCertStore, DWORD dwFlags,
449 DWORD dwCtrlType, void const *pvCtrlPara)
451 WINE_REGSTOREINFO *store = hCertStore;
452 BOOL ret = TRUE;
454 TRACE("(%p, %08lx, %ld, %p)\n", hCertStore, dwFlags, dwCtrlType,
455 pvCtrlPara);
457 switch (dwCtrlType)
459 case CERT_STORE_CTRL_RESYNC:
461 HCERTSTORE memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
462 CERT_STORE_CREATE_NEW_FLAG, NULL);
464 CRYPT_RegFlushStore(store, FALSE);
465 CRYPT_RegReadFromReg(store->key, memStore, CERT_STORE_ADD_REPLACE_EXISTING);
466 I_CertUpdateStore(store->memStore, memStore, 0, 0);
467 CertCloseStore(memStore, 0);
468 break;
470 case CERT_STORE_CTRL_COMMIT:
471 ret = CRYPT_RegFlushStore(store,
472 dwFlags & CERT_STORE_CTRL_COMMIT_FORCE_FLAG);
473 break;
474 case CERT_STORE_CTRL_AUTO_RESYNC:
475 FIXME("CERT_STORE_CTRL_AUTO_RESYNC: stub\n");
476 break;
477 case CERT_STORE_CTRL_NOTIFY_CHANGE:
478 FIXME("CERT_STORE_CTRL_NOTIFY_CHANGE: stub\n");
479 break;
480 default:
481 FIXME("%lu: stub\n", dwCtrlType);
482 ret = FALSE;
484 return ret;
487 static void *regProvFuncs[] = {
488 CRYPT_RegCloseStore,
489 NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
490 CRYPT_RegWriteCert,
491 CRYPT_RegDeleteCert,
492 NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
493 NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
494 CRYPT_RegWriteCRL,
495 CRYPT_RegDeleteCRL,
496 NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
497 NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
498 CRYPT_RegWriteCTL,
499 CRYPT_RegDeleteCTL,
500 NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
501 CRYPT_RegControl,
504 WINECRYPT_CERTSTORE *CRYPT_RegOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags,
505 const void *pvPara)
507 WINECRYPT_CERTSTORE *store = NULL;
509 TRACE("(%Id, %08lx, %p)\n", hCryptProv, dwFlags, pvPara);
511 if (dwFlags & CERT_STORE_DELETE_FLAG)
513 DWORD rc = RegDeleteTreeW((HKEY)pvPara, L"Certificates");
515 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
516 rc = RegDeleteTreeW((HKEY)pvPara, L"CRLs");
517 if (rc == ERROR_SUCCESS || rc == ERROR_NO_MORE_ITEMS)
518 rc = RegDeleteTreeW((HKEY)pvPara, L"CTLs");
519 if (rc == ERROR_NO_MORE_ITEMS)
520 rc = ERROR_SUCCESS;
521 SetLastError(rc);
523 else
525 HKEY key;
527 if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
528 GetCurrentProcess(), (LPHANDLE)&key,
529 dwFlags & CERT_STORE_READONLY_FLAG ? KEY_READ : KEY_ALL_ACCESS,
530 TRUE, 0))
532 WINECRYPT_CERTSTORE *memStore;
534 memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, hCryptProv,
535 CERT_STORE_CREATE_NEW_FLAG, NULL);
536 if (memStore)
538 WINE_REGSTOREINFO *regInfo = CryptMemAlloc(
539 sizeof(WINE_REGSTOREINFO));
541 if (regInfo)
543 CERT_STORE_PROV_INFO provInfo = { 0 };
545 regInfo->dwOpenFlags = dwFlags;
546 regInfo->memStore = memStore;
547 regInfo->key = key;
548 InitializeCriticalSection(&regInfo->cs);
549 regInfo->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PWINE_REGSTOREINFO->cs");
550 list_init(&regInfo->certsToDelete);
551 list_init(&regInfo->crlsToDelete);
552 list_init(&regInfo->ctlsToDelete);
553 CRYPT_RegReadFromReg(regInfo->key, regInfo->memStore, CERT_STORE_ADD_ALWAYS);
554 regInfo->dirty = FALSE;
555 provInfo.cbSize = sizeof(provInfo);
556 provInfo.cStoreProvFunc = ARRAY_SIZE(regProvFuncs);
557 provInfo.rgpvStoreProvFunc = regProvFuncs;
558 provInfo.hStoreProv = regInfo;
559 store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
560 /* Reg store doesn't need crypto provider, so close it */
561 if (hCryptProv &&
562 !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
563 CryptReleaseContext(hCryptProv, 0);
568 TRACE("returning %p\n", store);
569 return store;