| /* |
| * Copyright 2004-2007 Juan Lang |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| #include <stdarg.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wincrypt.h" |
| #include "winnls.h" |
| #include "wine/debug.h" |
| #include "crypt32_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(crypt); |
| |
| typedef struct _WINE_FILESTOREINFO |
| { |
| DWORD dwOpenFlags; |
| HCERTSTORE memStore; |
| HANDLE file; |
| BOOL dirty; |
| } WINE_FILESTOREINFO, *PWINE_FILESTOREINFO; |
| |
| static void WINAPI CRYPT_FileCloseStore(HCERTSTORE hCertStore, DWORD dwFlags) |
| { |
| PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; |
| |
| TRACE("(%p, %08x)\n", store, dwFlags); |
| if (store->dirty) |
| CRYPT_WriteSerializedFile(store->file, store->memStore); |
| CertCloseStore(store->memStore, dwFlags); |
| CloseHandle(store->file); |
| CryptMemFree(store); |
| } |
| |
| static BOOL WINAPI CRYPT_FileWriteCert(HCERTSTORE hCertStore, |
| PCCERT_CONTEXT cert, DWORD dwFlags) |
| { |
| PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; |
| |
| TRACE("(%p, %p, %d)\n", hCertStore, cert, dwFlags); |
| store->dirty = TRUE; |
| return TRUE; |
| } |
| |
| static BOOL WINAPI CRYPT_FileDeleteCert(HCERTSTORE hCertStore, |
| PCCERT_CONTEXT pCertContext, DWORD dwFlags) |
| { |
| PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; |
| |
| TRACE("(%p, %p, %08x)\n", hCertStore, pCertContext, dwFlags); |
| store->dirty = TRUE; |
| return TRUE; |
| } |
| |
| static BOOL WINAPI CRYPT_FileWriteCRL(HCERTSTORE hCertStore, |
| PCCRL_CONTEXT crl, DWORD dwFlags) |
| { |
| PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; |
| |
| TRACE("(%p, %p, %d)\n", hCertStore, crl, dwFlags); |
| store->dirty = TRUE; |
| return TRUE; |
| } |
| |
| static BOOL WINAPI CRYPT_FileDeleteCRL(HCERTSTORE hCertStore, |
| PCCRL_CONTEXT pCrlContext, DWORD dwFlags) |
| { |
| PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; |
| |
| TRACE("(%p, %p, %08x)\n", hCertStore, pCrlContext, dwFlags); |
| store->dirty = TRUE; |
| return TRUE; |
| } |
| |
| static BOOL WINAPI CRYPT_FileControl(HCERTSTORE hCertStore, DWORD dwFlags, |
| DWORD dwCtrlType, void const *pvCtrlPara) |
| { |
| PWINE_FILESTOREINFO store = (PWINE_FILESTOREINFO)hCertStore; |
| BOOL ret; |
| |
| TRACE("(%p, %08x, %d, %p)\n", hCertStore, dwFlags, dwCtrlType, |
| pvCtrlPara); |
| |
| switch (dwCtrlType) |
| { |
| case CERT_STORE_CTRL_RESYNC: |
| CRYPT_EmptyStore(store->memStore); |
| CRYPT_ReadSerializedFile(store->file, store); |
| ret = TRUE; |
| break; |
| case CERT_STORE_CTRL_COMMIT: |
| if (!(store->dwOpenFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) |
| { |
| SetLastError(ERROR_CALL_NOT_IMPLEMENTED); |
| ret = FALSE; |
| } |
| else if (store->dirty) |
| ret = CRYPT_WriteSerializedFile(store->file, store->memStore); |
| else |
| ret = TRUE; |
| break; |
| default: |
| FIXME("%d: stub\n", dwCtrlType); |
| ret = FALSE; |
| } |
| return ret; |
| } |
| |
| static void *fileProvFuncs[] = { |
| CRYPT_FileCloseStore, |
| NULL, /* CERT_STORE_PROV_READ_CERT_FUNC */ |
| CRYPT_FileWriteCert, |
| CRYPT_FileDeleteCert, |
| NULL, /* CERT_STORE_PROV_SET_CERT_PROPERTY_FUNC */ |
| NULL, /* CERT_STORE_PROV_READ_CRL_FUNC */ |
| CRYPT_FileWriteCRL, |
| CRYPT_FileDeleteCRL, |
| NULL, /* CERT_STORE_PROV_SET_CRL_PROPERTY_FUNC */ |
| NULL, /* CERT_STORE_PROV_READ_CTL_FUNC */ |
| NULL, /* CERT_STORE_PROV_WRITE_CTL_FUNC */ |
| NULL, /* CERT_STORE_PROV_DELETE_CTL_FUNC */ |
| NULL, /* CERT_STORE_PROV_SET_CTL_PROPERTY_FUNC */ |
| CRYPT_FileControl, |
| }; |
| |
| PWINECRYPT_CERTSTORE CRYPT_FileOpenStore(HCRYPTPROV hCryptProv, DWORD dwFlags, |
| const void *pvPara) |
| { |
| PWINECRYPT_CERTSTORE store = NULL; |
| HANDLE file = (HANDLE)pvPara; |
| |
| TRACE("(%ld, %08x, %p)\n", hCryptProv, dwFlags, pvPara); |
| |
| if (!pvPara) |
| { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return NULL; |
| } |
| if (dwFlags & CERT_STORE_DELETE_FLAG) |
| { |
| SetLastError(E_INVALIDARG); |
| return NULL; |
| } |
| if ((dwFlags & CERT_STORE_READONLY_FLAG) && |
| (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG)) |
| { |
| SetLastError(E_INVALIDARG); |
| return NULL; |
| } |
| |
| if (DuplicateHandle(GetCurrentProcess(), (HANDLE)pvPara, |
| GetCurrentProcess(), &file, dwFlags & CERT_STORE_READONLY_FLAG ? |
| GENERIC_READ : GENERIC_READ | GENERIC_WRITE, TRUE, 0)) |
| { |
| PWINECRYPT_CERTSTORE memStore; |
| |
| memStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, |
| CERT_STORE_CREATE_NEW_FLAG, NULL); |
| if (memStore) |
| { |
| if (CRYPT_ReadSerializedFile(file, memStore)) |
| { |
| PWINE_FILESTOREINFO info = CryptMemAlloc( |
| sizeof(WINE_FILESTOREINFO)); |
| |
| if (info) |
| { |
| CERT_STORE_PROV_INFO provInfo = { 0 }; |
| |
| info->dwOpenFlags = dwFlags; |
| info->memStore = memStore; |
| info->file = file; |
| info->dirty = FALSE; |
| provInfo.cbSize = sizeof(provInfo); |
| provInfo.cStoreProvFunc = sizeof(fileProvFuncs) / |
| sizeof(fileProvFuncs[0]); |
| provInfo.rgpvStoreProvFunc = fileProvFuncs; |
| provInfo.hStoreProv = info; |
| store = CRYPT_ProvCreateStore(dwFlags, memStore, &provInfo); |
| /* File store doesn't need crypto provider, so close it */ |
| if (hCryptProv && |
| !(dwFlags & CERT_STORE_NO_CRYPT_RELEASE_FLAG)) |
| CryptReleaseContext(hCryptProv, 0); |
| } |
| } |
| } |
| } |
| TRACE("returning %p\n", store); |
| return store; |
| } |
| |
| PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreW(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| HCERTSTORE store = 0; |
| LPCWSTR fileName = (LPCWSTR)pvPara; |
| DWORD access, create; |
| HANDLE file; |
| |
| TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, debugstr_w(fileName)); |
| |
| if (!fileName) |
| { |
| SetLastError(ERROR_PATH_NOT_FOUND); |
| return NULL; |
| } |
| |
| access = GENERIC_READ; |
| if (dwFlags & CERT_FILE_STORE_COMMIT_ENABLE_FLAG) |
| access |= GENERIC_WRITE; |
| if (dwFlags & CERT_STORE_CREATE_NEW_FLAG) |
| create = CREATE_NEW; |
| else if (dwFlags & CERT_STORE_OPEN_EXISTING_FLAG) |
| create = OPEN_EXISTING; |
| else |
| create = OPEN_ALWAYS; |
| file = CreateFileW(fileName, access, FILE_SHARE_READ, NULL, create, |
| FILE_ATTRIBUTE_NORMAL, NULL); |
| if (file != INVALID_HANDLE_VALUE) |
| { |
| /* FIXME: need to check whether it's a serialized store; if not, fall |
| * back to a PKCS#7 signed message, then to a single serialized cert. |
| */ |
| store = CertOpenStore(CERT_STORE_PROV_FILE, 0, hCryptProv, dwFlags, |
| file); |
| CloseHandle(file); |
| } |
| return (PWINECRYPT_CERTSTORE)store; |
| } |
| |
| PWINECRYPT_CERTSTORE CRYPT_FileNameOpenStoreA(HCRYPTPROV hCryptProv, |
| DWORD dwFlags, const void *pvPara) |
| { |
| int len; |
| PWINECRYPT_CERTSTORE ret = NULL; |
| |
| TRACE("(%ld, %08x, %s)\n", hCryptProv, dwFlags, |
| debugstr_a((LPCSTR)pvPara)); |
| |
| if (!pvPara) |
| { |
| SetLastError(ERROR_FILE_NOT_FOUND); |
| return NULL; |
| } |
| len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, NULL, 0); |
| if (len) |
| { |
| LPWSTR storeName = CryptMemAlloc(len * sizeof(WCHAR)); |
| |
| if (storeName) |
| { |
| MultiByteToWideChar(CP_ACP, 0, (LPCSTR)pvPara, -1, storeName, len); |
| ret = CRYPT_FileNameOpenStoreW(hCryptProv, dwFlags, storeName); |
| CryptMemFree(storeName); |
| } |
| } |
| return ret; |
| } |