crypt32: Create file store directly in CRYPT_FileNameOpenStoreW.
[wine] / dlls / crypt32 / filestore.c
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 "wincrypt.h"
22 #include "winnls.h"
23 #include "wine/debug.h"
24 #include "crypt32_private.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
27
28 typedef struct _WINE_FILESTOREINFO
29 {
30     DWORD      dwOpenFlags;
31     HCERTSTORE memStore;
32     HANDLE     file;
33     BOOL       dirty;
34 } WINE_FILESTOREINFO, *PWINE_FILESTOREINFO;
35
36 static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
37 {
38     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
39
40     TRACE("(%p, %08x)\n", store, dwFlags);
41     if (store->dirty)
42         CertSaveStore(store->memStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
43          CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, store->file, 0);
44     CertCloseStore(store->memStore, dwFlags);
45     CloseHandle(store->file);
46     CryptMemFree(store);
47 }
48
49 static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore,
50  PCCERT_CONTEXT cert, DWORD dwFlags)
51 {
52     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
53
54     TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags);
55     store->dirty = TRUE;
56     return TRUE;
57 }
58
59 static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore,
60  PCCERT_CONTEXT pCertContext, DWORD dwFlags)
61 {
62     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
63
64     TRACE("(%p, %p, %08x)\n", hCertStore, pCertContext, dwFlags);
65     store->dirty = TRUE;
66     return TRUE;
67 }
68
69 static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore,
70  PCCRL_CONTEXT crl, DWORD dwFlags)
71 {
72     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
73
74     TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags);
75     store->dirty = TRUE;
76     return TRUE;
77 }
78
79 static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore,
80  PCCRL_CONTEXT pCrlContext, DWORD dwFlags)
81 {
82     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
83
84     TRACE("(%p, %p, %08x)\n", hCertStore, pCrlContext, dwFlags);
85     store->dirty = TRUE;
86     return TRUE;
87 }
88
89 static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags,
90  DWORD dwCtrlType, void const *pvCtrlPara)
91 {
92     PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore;
93     BOOL ret;
94
95     TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType,
96      pvCtrlPara);
97
98     switch (dwCtrlType)
99     {
100     case CERT_STORE_CTRL_RESYNC:
101         CRYPT_EmptyStore(store->memStore);
102         store->dirty = FALSE;
103         ret = CRYPT_ReadSerializedStoreFromFile(store->file, store->memStore);
104         break;
105     case CERT_STORE_CTRL_COMMIT:
106         if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
107         {
108             SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
109             ret = FALSE;
110         }
111         else if (store->dirty)
112             ret = CertSaveStore(store->memStore,
113              X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
114              CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_FILE, store->file, 0);
115         else
116             ret = TRUE;
117         break;
118     default:
119         FIXME("%d: stub\n", dwCtrlType);
120         ret = FALSE;
121     }
122     return ret;
123 }
124
125 static void *fileProvFuncs[] = {
126     CRYPT_FileCloseStore,
127     NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */
128     CRYPT_FileWriteCert,
129     CRYPT_FileDeleteCert,
130     NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */
131     NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */
132     CRYPT_FileWriteCRL,
133     CRYPT_FileDeleteCRL,
134     NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */
135     NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */
136     NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */
137     NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */
138     NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */
139     CRYPT_FileControl,
140 };
141
142 static PWINECRYPT_CERTSTORE CRYPT_CreateFileStore(DWORD dwFlags,
143  HCERTSTORE memStore, HANDLE file)
144 {
145     PWINECRYPT_CERTSTORE store = NULL;
146     PWINE_FILESTOREINFO info = CryptMemAlloc(sizeof(WINE_FILESTOREINFO));
147
148     if (info)
149     {
150         CERT_STORE_PROV_INFO provInfo = { 0 };
151
152         info->dwOpenFlags = dwFlags;
153         info->memStore = memStore;
154         info->file = file;
155         info->dirty = FALSE;
156         provInfo.cbSize = sizeof(provInfo);
157         provInfo.cStoreProvFunc = sizeof(fileProvFuncs) /
158          sizeof(fileProvFuncs[0]);
159         provInfo.rgpvStoreProvFunc = fileProvFuncs;
160         provInfo.hStoreProv = info;
161         store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo);
162     }
163     return store;
164 }
165
166 PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags,
167  const void *pvPara)
168 {
169     PWINECRYPT_CERTSTORE store = NULL;
170     HANDLE file = (HANDLE)pvPara;
171
172     TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara);
173
174     if (!pvPara)
175     {
176         SetLastError(ERROR_INVALID_HANDLE);
177         return NULL;
178     }
179     if (dwFlags & CERT_STORE_DELETE_FLAG)
180     {
181         SetLastError(E_INVALIDARG);
182         return NULL;
183     }
184     if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
185      (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
186     {
187         SetLastError(E_INVALIDARG);
188         return NULL;
189     }
190
191     if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara,
192      GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ?
193      GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0))
194     {
195         HCERTSTORE memStore;
196
197         memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
198          CERT_STORE_CREATE_NEW_FLAG, NULL);
199         if (memStore)
200         {
201             if (CRYPT_ReadSerializedStoreFromFile(file, memStore))
202             {
203                 store = CRYPT_CreateFileStore(dwFlags, memStore, file);
204                 /* File store doesn't need crypto provider, so close it */
205                 if (hCryptProv &&
206                  !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
207                     CryptReleaseContext(hCryptProv, 0);
208             }
209         }
210     }
211     TRACE("returning %p\n", store);
212     return store;
213 }
214
215 PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv,
216  DWORD dwFlags, const void *pvPara)
217 {
218     HCERTSTORE store = 0;
219     LPCWSTR fileName = (LPCWSTR)pvPara;
220     DWORD access, create;
221     HANDLE file;
222
223     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName));
224
225     if (!fileName)
226     {
227         SetLastError(ERROR_PATH_NOT_FOUND);
228         return NULL;
229     }
230     if ((dwFlags & CERT_STORE_READONLY_FLAG) &&
231      (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG))
232     {
233         SetLastError(E_INVALIDARG);
234         return NULL;
235     }
236
237     access = GENERIC_READ;
238     if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)
239         access |= GENERIC_WRITE;
240     if (dwFlags & CERT_STORE_CREATE_NEW_FLAG)
241         create = CREATE_NEW;
242     else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG)
243         create = OPEN_EXISTING;
244     else
245         create = OPEN_ALWAYS;
246     file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create,
247      FILE_ATTRIBUTE_NORMAL, NULL);
248     if (file != INVALID_HANDLE_VALUE)
249     {
250         HCERTSTORE memStore;
251
252         memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
253          CERT_STORE_CREATE_NEW_FLAG, NULL);
254         if (memStore)
255         {
256             if (CRYPT_ReadSerializedStoreFromFile(file, memStore))
257             {
258                 store = CRYPT_CreateFileStore(dwFlags, memStore, file);
259                 /* File store doesn't need crypto provider, so close it */
260                 if (hCryptProv &&
261                  !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG))
262                     CryptReleaseContext(hCryptProv, 0);
263             }
264             else
265             {
266                 /* FIXME: fall back to a PKCS#7 signed message, then to a
267                  * single serialized cert.
268                  */
269             }
270         }
271     }
272     return (PWINECRYPT_CERTSTORE)store;
273 }
274
275 PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv,
276  DWORD dwFlags, const void *pvPara)
277 {
278     int len;
279     PWINECRYPT_CERTSTORE ret = NULL;
280
281     TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags,
282      debugstr_a((LPCSTR)pvPara));
283
284     if (!pvPara)
285     {
286         SetLastError(ERROR_FILE_NOT_FOUND);
287         return NULL;
288     }
289     len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0);
290     if (len)
291     {
292         LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR));
293
294         if (storeName)
295         {
296             MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len);
297             ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName);
298             CryptMemFree(storeName);
299         }
300     }
301     return ret;
302 }