| /* | 
 |  * Copyright 2002 Mike McCormack for CodeWeavers | 
 |  * Copyright 2005-2008 Juan Lang | 
 |  * Copyright 2006 Paul Vriens | 
 |  * | 
 |  * 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 <stdio.h> | 
 |  | 
 | #include "windef.h" | 
 | #include "winbase.h" | 
 | #include "wincrypt.h" | 
 | #include "winreg.h" | 
 | #include "winnls.h" | 
 | #include "mssip.h" | 
 | #include "winuser.h" | 
 |  | 
 | #include "wine/debug.h" | 
 | #include "wine/list.h" | 
 |  | 
 | WINE_DEFAULT_DEBUG_CHANNEL(crypt); | 
 |  | 
 | static const WCHAR szOID[] = { | 
 |     'S','o','f','t','w','a','r','e','\\', | 
 |     'M','i','c','r','o','s','o','f','t','\\', | 
 |     'C','r','y','p','t','o','g','r','a','p','h','y','\\', | 
 |     'O','I','D','\\', | 
 |     'E','n','c','o','d','i','n','g','T','y','p','e',' ','0','\\', | 
 |     'C','r','y','p','t','S','I','P','D','l','l', 0 }; | 
 |  | 
 | static const WCHAR szPutSigned[] = { | 
 |     'P','u','t','S','i','g','n','e','d','D','a','t','a','M','s','g','\\',0}; | 
 | static const WCHAR szGetSigned[] = { | 
 |     'G','e','t','S','i','g','n','e','d','D','a','t','a','M','s','g','\\',0}; | 
 | static const WCHAR szRemoveSigned[] = { | 
 |     'R','e','m','o','v','e','S','i','g','n','e','d','D','a','t','a','M','s','g','\\',0}; | 
 | static const WCHAR szCreate[] = { | 
 |     'C','r','e','a','t','e','I','n','d','i','r','e','c','t','D','a','t','a','\\',0}; | 
 | static const WCHAR szVerify[] = { | 
 |     'V','e','r','i','f','y','I','n','d','i','r','e','c','t','D','a','t','a','\\',0}; | 
 | static const WCHAR szIsMyFile[] = { | 
 |     'I','s','M','y','F','i','l','e','T','y','p','e','\\',0}; | 
 | static const WCHAR szIsMyFile2[] = { | 
 |     'I','s','M','y','F','i','l','e','T','y','p','e','2','\\',0}; | 
 |  | 
 | static const WCHAR szDllName[] = { 'D','l','l',0 }; | 
 | static const WCHAR szFuncName[] = { 'F','u','n','c','N','a','m','e',0 }; | 
 |  | 
 | /* convert a guid to a wide character string */ | 
 | static void CRYPT_guid2wstr( const GUID *guid, LPWSTR wstr ) | 
 | { | 
 |     char str[40]; | 
 |  | 
 |     sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", | 
 |            guid->Data1, guid->Data2, guid->Data3, | 
 |            guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], | 
 |            guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); | 
 |     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, 40 ); | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *              CRYPT_SIPDeleteFunction | 
 |  * | 
 |  * Helper function for CryptSIPRemoveProvider | 
 |  */ | 
 | static LONG CRYPT_SIPDeleteFunction( const GUID *guid, LPCWSTR szKey ) | 
 | { | 
 |     WCHAR szFullKey[ 0x100 ]; | 
 |     LONG r = ERROR_SUCCESS; | 
 |  | 
 |     /* max length of szFullKey depends on our code only, so we won't overrun */ | 
 |     lstrcpyW( szFullKey, szOID ); | 
 |     lstrcatW( szFullKey, szKey ); | 
 |     CRYPT_guid2wstr( guid, &szFullKey[ lstrlenW( szFullKey ) ] ); | 
 |  | 
 |     r = RegDeleteKeyW(HKEY_LOCAL_MACHINE, szFullKey); | 
 |  | 
 |     return r; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPRemoveProvider (CRYPT32.@) | 
 |  * | 
 |  * Remove a SIP provider and its functions from the registry. | 
 |  * | 
 |  * PARAMS | 
 |  *  pgProv     [I] Pointer to a GUID for this SIP provider | 
 |  * | 
 |  * RETURNS | 
 |  *  Success: TRUE. | 
 |  *  Failure: FALSE. (Look at GetLastError()). | 
 |  * | 
 |  * NOTES | 
 |  *  Registry errors are always reported via SetLastError(). Every registry | 
 |  *  deletion will be tried. | 
 |  */ | 
 | BOOL WINAPI CryptSIPRemoveProvider(GUID *pgProv) | 
 | { | 
 |     LONG r = ERROR_SUCCESS; | 
 |     LONG remove_error = ERROR_SUCCESS; | 
 |  | 
 |     TRACE("%s\n", debugstr_guid(pgProv)); | 
 |  | 
 |     if (!pgProv) | 
 |     { | 
 |         SetLastError(ERROR_INVALID_PARAMETER); | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |  | 
 | #define CRYPT_SIPREMOVEPROV( key ) \ | 
 |     r = CRYPT_SIPDeleteFunction( pgProv, key); \ | 
 |     if (r != ERROR_SUCCESS) remove_error = r | 
 |  | 
 |     CRYPT_SIPREMOVEPROV( szPutSigned); | 
 |     CRYPT_SIPREMOVEPROV( szGetSigned); | 
 |     CRYPT_SIPREMOVEPROV( szRemoveSigned); | 
 |     CRYPT_SIPREMOVEPROV( szCreate); | 
 |     CRYPT_SIPREMOVEPROV( szVerify); | 
 |     CRYPT_SIPREMOVEPROV( szIsMyFile); | 
 |     CRYPT_SIPREMOVEPROV( szIsMyFile2); | 
 |  | 
 | #undef CRYPT_SIPREMOVEPROV | 
 |  | 
 |     if (remove_error != ERROR_SUCCESS) | 
 |     { | 
 |         SetLastError(remove_error); | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 | /* | 
 |  * Helper for CryptSIPAddProvider | 
 |  * | 
 |  * Add a registry key containing a dll name and function under | 
 |  *  "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\<func>\\<guid>" | 
 |  */ | 
 | static LONG CRYPT_SIPWriteFunction( const GUID *guid, LPCWSTR szKey, | 
 |               LPCWSTR szDll, LPCWSTR szFunction ) | 
 | { | 
 |     WCHAR szFullKey[ 0x100 ]; | 
 |     LONG r = ERROR_SUCCESS; | 
 |     HKEY hKey; | 
 |  | 
 |     if( !szFunction ) | 
 |          return ERROR_SUCCESS; | 
 |  | 
 |     /* max length of szFullKey depends on our code only, so we won't overrun */ | 
 |     lstrcpyW( szFullKey, szOID ); | 
 |     lstrcatW( szFullKey, szKey ); | 
 |     CRYPT_guid2wstr( guid, &szFullKey[ lstrlenW( szFullKey ) ] ); | 
 |  | 
 |     TRACE("key is %s\n", debugstr_w( szFullKey ) ); | 
 |  | 
 |     r = RegCreateKeyW( HKEY_LOCAL_MACHINE, szFullKey, &hKey ); | 
 |     if( r != ERROR_SUCCESS ) goto error_close_key; | 
 |  | 
 |     /* write the values */ | 
 |     r = RegSetValueExW( hKey, szFuncName, 0, REG_SZ, (const BYTE*) szFunction, | 
 |                         ( lstrlenW( szFunction ) + 1 ) * sizeof (WCHAR) ); | 
 |     if( r != ERROR_SUCCESS ) goto error_close_key; | 
 |     r = RegSetValueExW( hKey, szDllName, 0, REG_SZ, (const BYTE*) szDll, | 
 |                         ( lstrlenW( szDll ) + 1) * sizeof (WCHAR) ); | 
 |  | 
 | error_close_key: | 
 |  | 
 |     RegCloseKey( hKey ); | 
 |  | 
 |     return r; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPAddProvider (CRYPT32.@) | 
 |  * | 
 |  * Add a SIP provider and its functions to the registry. | 
 |  * | 
 |  * PARAMS | 
 |  *  psNewProv       [I] Pointer to a structure with information about | 
 |  *                      the functions this SIP provider can perform. | 
 |  * | 
 |  * RETURNS | 
 |  *  Success: TRUE. | 
 |  *  Failure: FALSE. (Look at GetLastError()). | 
 |  * | 
 |  * NOTES | 
 |  *  Registry errors are always reported via SetLastError(). If a | 
 |  *  registry error occurs the rest of the registry write operations | 
 |  *  will be skipped. | 
 |  */ | 
 | BOOL WINAPI CryptSIPAddProvider(SIP_ADD_NEWPROVIDER *psNewProv) | 
 | { | 
 |     LONG r = ERROR_SUCCESS; | 
 |  | 
 |     TRACE("%p\n", psNewProv); | 
 |  | 
 |     if (!psNewProv || | 
 |         psNewProv->cbStruct != sizeof(SIP_ADD_NEWPROVIDER) || | 
 |         !psNewProv->pwszGetFuncName || | 
 |         !psNewProv->pwszPutFuncName || | 
 |         !psNewProv->pwszCreateFuncName || | 
 |         !psNewProv->pwszVerifyFuncName || | 
 |         !psNewProv->pwszRemoveFuncName) | 
 |     { | 
 |         SetLastError(ERROR_INVALID_PARAMETER); | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     TRACE("%s %s %s %s %s\n", | 
 |           debugstr_guid( psNewProv->pgSubject ), | 
 |           debugstr_w( psNewProv->pwszDLLFileName ), | 
 |           debugstr_w( psNewProv->pwszMagicNumber ), | 
 |           debugstr_w( psNewProv->pwszIsFunctionName ), | 
 |           debugstr_w( psNewProv->pwszIsFunctionNameFmt2 ) ); | 
 |  | 
 | #define CRYPT_SIPADDPROV( key, field ) \ | 
 |     r = CRYPT_SIPWriteFunction( psNewProv->pgSubject, key, \ | 
 |            psNewProv->pwszDLLFileName, psNewProv->field); \ | 
 |     if (r != ERROR_SUCCESS) goto end_function | 
 |  | 
 |     CRYPT_SIPADDPROV( szPutSigned, pwszPutFuncName ); | 
 |     CRYPT_SIPADDPROV( szGetSigned, pwszGetFuncName ); | 
 |     CRYPT_SIPADDPROV( szRemoveSigned, pwszRemoveFuncName ); | 
 |     CRYPT_SIPADDPROV( szCreate, pwszCreateFuncName ); | 
 |     CRYPT_SIPADDPROV( szVerify, pwszVerifyFuncName ); | 
 |     CRYPT_SIPADDPROV( szIsMyFile, pwszIsFunctionName ); | 
 |     CRYPT_SIPADDPROV( szIsMyFile2, pwszIsFunctionNameFmt2 ); | 
 |  | 
 | #undef CRYPT_SIPADDPROV | 
 |  | 
 | end_function: | 
 |  | 
 |     if (r != ERROR_SUCCESS) | 
 |     { | 
 |         SetLastError(r); | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 | static void *CRYPT_LoadSIPFuncFromKey(HKEY key, HMODULE *pLib) | 
 | { | 
 |     LONG r; | 
 |     DWORD size; | 
 |     WCHAR dllName[MAX_PATH]; | 
 |     char functionName[MAX_PATH]; | 
 |     HMODULE lib; | 
 |     void *func = NULL; | 
 |  | 
 |     /* Read the DLL entry */ | 
 |     size = sizeof(dllName); | 
 |     r = RegQueryValueExW(key, szDllName, NULL, NULL, (LPBYTE)dllName, &size); | 
 |     if (r) goto end; | 
 |  | 
 |     /* Read the Function entry */ | 
 |     size = sizeof(functionName); | 
 |     r = RegQueryValueExA(key, "FuncName", NULL, NULL, (LPBYTE)functionName, | 
 |      &size); | 
 |     if (r) goto end; | 
 |  | 
 |     lib = LoadLibraryW(dllName); | 
 |     if (!lib) | 
 |         goto end; | 
 |     func = GetProcAddress(lib, functionName); | 
 |     if (func) | 
 |         *pLib = lib; | 
 |     else | 
 |         FreeLibrary(lib); | 
 |  | 
 | end: | 
 |     return func; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPRetrieveSubjectGuid (CRYPT32.@) | 
 |  * | 
 |  * Determine the right SIP GUID for the given file. | 
 |  * | 
 |  * PARAMS | 
 |  *  FileName   [I] Filename. | 
 |  *  hFileIn    [I] Optional handle to the file. | 
 |  *  pgSubject  [O] The SIP's GUID. | 
 |  * | 
 |  * RETURNS | 
 |  *  Success: TRUE. pgSubject contains the SIP GUID. | 
 |  *  Failure: FALSE. (Look at GetLastError()). | 
 |  * | 
 |  * NOTES | 
 |  *  On failure pgSubject will contain a NULL GUID. | 
 |  *  The handle is always preferred above the filename. | 
 |  */ | 
 | BOOL WINAPI CryptSIPRetrieveSubjectGuid | 
 |       (LPCWSTR FileName, HANDLE hFileIn, GUID *pgSubject) | 
 | { | 
 |     HANDLE hFile; | 
 |     BOOL   bRet = FALSE; | 
 |     DWORD  count; | 
 |     LARGE_INTEGER zero, oldPos; | 
 |     /* FIXME, find out if there is a name for this GUID */ | 
 |     static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; | 
 |     static const GUID cabGUID = { 0xc689aaba, 0x8e78, 0x11d0, {0x8c,0x47,0x00,0xc0,0x4f,0xc2,0x95,0xee }}; | 
 |     static const GUID catGUID = { 0xDE351A43, 0x8E59, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; | 
 |     static const WORD dosHdr = IMAGE_DOS_SIGNATURE; | 
 |     static const BYTE cabHdr[] = { 'M','S','C','F' }; | 
 |     BYTE hdr[SIP_MAX_MAGIC_NUMBER]; | 
 |     WCHAR szFullKey[ 0x100 ]; | 
 |     LONG r = ERROR_SUCCESS; | 
 |     HKEY key; | 
 |  | 
 |     TRACE("(%s %p %p)\n", wine_dbgstr_w(FileName), hFileIn, pgSubject); | 
 |  | 
 |     if (!pgSubject || (!FileName && !hFileIn)) | 
 |     { | 
 |         SetLastError(ERROR_INVALID_PARAMETER); | 
 |         return FALSE; | 
 |     } | 
 |  | 
 |     /* Set pgSubject to zero's */ | 
 |     memset(pgSubject, 0 , sizeof(GUID)); | 
 |  | 
 |     if (hFileIn) | 
 |         /* Use the given handle, make sure not to close this one ourselves */ | 
 |         hFile = hFileIn; | 
 |     else | 
 |     { | 
 |         hFile = CreateFileW(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | 
 |         /* Last error is set by CreateFile */ | 
 |         if (hFile == INVALID_HANDLE_VALUE) return FALSE; | 
 |     } | 
 |  | 
 |     zero.QuadPart = 0; | 
 |     SetFilePointerEx(hFile, zero, &oldPos, FILE_CURRENT); | 
 |     SetFilePointer(hFile, 0, NULL, FILE_BEGIN); | 
 |     if (!ReadFile(hFile, hdr, sizeof(hdr), &count, NULL)) | 
 |         goto cleanup; | 
 |  | 
 |     if (count < SIP_MAX_MAGIC_NUMBER) | 
 |     { | 
 |         SetLastError(ERROR_INVALID_PARAMETER); | 
 |         goto cleanup; | 
 |     } | 
 |  | 
 |     TRACE("file magic = 0x%02x%02x%02x%02x\n", hdr[0], hdr[1], hdr[2], hdr[3]); | 
 |     /* As everything is in place now we start looking at the file header */ | 
 |     if (!memcmp(hdr, &dosHdr, sizeof(dosHdr))) | 
 |     { | 
 |         *pgSubject = unknown; | 
 |         SetLastError(S_OK); | 
 |         bRet = TRUE; | 
 |         goto cleanup; | 
 |     } | 
 |     /* Quick-n-dirty check for a cab file. */ | 
 |     if (!memcmp(hdr, cabHdr, sizeof(cabHdr))) | 
 |     { | 
 |         *pgSubject = cabGUID; | 
 |         SetLastError(S_OK); | 
 |         bRet = TRUE; | 
 |         goto cleanup; | 
 |     } | 
 |     /* If it's asn.1-encoded, it's probably a .cat file. */ | 
 |     if (hdr[0] == 0x30) | 
 |     { | 
 |         DWORD fileLen = GetFileSize(hFile, NULL); | 
 |  | 
 |         TRACE("fileLen = %d\n", fileLen); | 
 |         /* Sanity-check length */ | 
 |         if (hdr[1] < 0x80 && fileLen == 2 + hdr[1]) | 
 |         { | 
 |             *pgSubject = catGUID; | 
 |             SetLastError(S_OK); | 
 |             bRet = TRUE; | 
 |             goto cleanup; | 
 |         } | 
 |         else if (hdr[1] == 0x80) | 
 |         { | 
 |             /* Indefinite length, can't verify with just the header, assume it | 
 |              * is. | 
 |              */ | 
 |             *pgSubject = catGUID; | 
 |             SetLastError(S_OK); | 
 |             bRet = TRUE; | 
 |             goto cleanup; | 
 |         } | 
 |         else | 
 |         { | 
 |             BYTE lenBytes = hdr[1] & 0x7f; | 
 |  | 
 |             if (lenBytes == 1 && fileLen == 2 + lenBytes + hdr[2]) | 
 |             { | 
 |                 *pgSubject = catGUID; | 
 |                 SetLastError(S_OK); | 
 |                 bRet = TRUE; | 
 |                 goto cleanup; | 
 |             } | 
 |             else if (lenBytes == 2 && fileLen == 2 + lenBytes + | 
 |              (hdr[2] << 8 | hdr[3])) | 
 |             { | 
 |                 *pgSubject = catGUID; | 
 |                 SetLastError(S_OK); | 
 |                 bRet = TRUE; | 
 |                 goto cleanup; | 
 |             } | 
 |             else if (fileLen > 0xffff) | 
 |             { | 
 |                 /* The file size must be greater than 2 bytes in length, so | 
 |                  * assume it is a .cat file | 
 |                  */ | 
 |                 *pgSubject = catGUID; | 
 |                 SetLastError(S_OK); | 
 |                 bRet = TRUE; | 
 |                 goto cleanup; | 
 |             } | 
 |         } | 
 |     } | 
 |  | 
 |     /* Check for supported functions using CryptSIPDllIsMyFileType */ | 
 |     /* max length of szFullKey depends on our code only, so we won't overrun */ | 
 |     lstrcpyW(szFullKey, szOID); | 
 |     lstrcatW(szFullKey, szIsMyFile); | 
 |     r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &key); | 
 |     if (r == ERROR_SUCCESS) | 
 |     { | 
 |         DWORD index = 0, size; | 
 |         WCHAR subKeyName[MAX_PATH]; | 
 |  | 
 |         do { | 
 |             size = sizeof(subKeyName) / sizeof(subKeyName[0]); | 
 |             r = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, | 
 |              NULL, NULL); | 
 |             if (r == ERROR_SUCCESS) | 
 |             { | 
 |                 HKEY subKey; | 
 |  | 
 |                 r = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); | 
 |                 if (r == ERROR_SUCCESS) | 
 |                 { | 
 |                     HMODULE lib; | 
 |                     pfnIsFileSupported isMy = CRYPT_LoadSIPFuncFromKey(subKey, | 
 |                      &lib); | 
 |  | 
 |                     if (isMy) | 
 |                     { | 
 |                         bRet = isMy(hFile, pgSubject); | 
 |                         FreeLibrary(lib); | 
 |                     } | 
 |                     RegCloseKey(subKey); | 
 |                 } | 
 |             } | 
 |         } while (!bRet && r == ERROR_SUCCESS); | 
 |         RegCloseKey(key); | 
 |     } | 
 |  | 
 |     /* Check for supported functions using CryptSIPDllIsMyFileType2 */ | 
 |     if (!bRet) | 
 |     { | 
 |         lstrcpyW(szFullKey, szOID); | 
 |         lstrcatW(szFullKey, szIsMyFile2); | 
 |         r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &key); | 
 |         if (r == ERROR_SUCCESS) | 
 |         { | 
 |             DWORD index = 0, size; | 
 |             WCHAR subKeyName[MAX_PATH]; | 
 |  | 
 |             do { | 
 |                 size = sizeof(subKeyName) / sizeof(subKeyName[0]); | 
 |                 r = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, | 
 |                  NULL, NULL); | 
 |                 if (r == ERROR_SUCCESS) | 
 |                 { | 
 |                     HKEY subKey; | 
 |  | 
 |                     r = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); | 
 |                     if (r == ERROR_SUCCESS) | 
 |                     { | 
 |                         HMODULE lib; | 
 |                         pfnIsFileSupportedName isMy2 = | 
 |                          CRYPT_LoadSIPFuncFromKey(subKey, &lib); | 
 |  | 
 |                         if (isMy2) | 
 |                         { | 
 |                             bRet = isMy2((LPWSTR)FileName, pgSubject); | 
 |                             FreeLibrary(lib); | 
 |                         } | 
 |                         RegCloseKey(subKey); | 
 |                     } | 
 |                 } | 
 |             } while (!bRet && r == ERROR_SUCCESS); | 
 |             RegCloseKey(key); | 
 |         } | 
 |     } | 
 |  | 
 |     if (!bRet) | 
 |         SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN); | 
 |  | 
 | cleanup: | 
 |     /* If we didn't open this one we shouldn't close it (hFile is a copy), | 
 |      * but we should reset the file pointer to its original position. | 
 |      */ | 
 |     if (!hFileIn) | 
 |         CloseHandle(hFile); | 
 |     else | 
 |         SetFilePointerEx(hFile, oldPos, NULL, FILE_BEGIN); | 
 |  | 
 |     return bRet; | 
 | } | 
 |  | 
 | static LONG CRYPT_OpenSIPFunctionKey(const GUID *guid, LPCWSTR function, | 
 |  HKEY *key) | 
 | { | 
 |     WCHAR szFullKey[ 0x100 ]; | 
 |  | 
 |     lstrcpyW(szFullKey, szOID); | 
 |     lstrcatW(szFullKey, function); | 
 |     CRYPT_guid2wstr(guid, &szFullKey[lstrlenW(szFullKey)]); | 
 |     return RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, key); | 
 | } | 
 |  | 
 | /* Loads the function named function for the SIP specified by pgSubject, and | 
 |  * returns it if found.  Returns NULL on error.  If the function is loaded, | 
 |  * *pLib is set to the library in which it is found. | 
 |  */ | 
 | static void *CRYPT_LoadSIPFunc(const GUID *pgSubject, LPCWSTR function, | 
 |  HMODULE *pLib) | 
 | { | 
 |     LONG r; | 
 |     HKEY key; | 
 |     void *func = NULL; | 
 |  | 
 |     TRACE("(%s, %s)\n", debugstr_guid(pgSubject), debugstr_w(function)); | 
 |  | 
 |     r = CRYPT_OpenSIPFunctionKey(pgSubject, function, &key); | 
 |     if (!r) | 
 |     { | 
 |         func = CRYPT_LoadSIPFuncFromKey(key, pLib); | 
 |         RegCloseKey(key); | 
 |     } | 
 |     TRACE("returning %p\n", func); | 
 |     return func; | 
 | } | 
 |  | 
 | typedef struct _WINE_SIP_PROVIDER { | 
 |     GUID              subject; | 
 |     SIP_DISPATCH_INFO info; | 
 |     struct list       entry; | 
 | } WINE_SIP_PROVIDER; | 
 |  | 
 | static struct list providers = { &providers, &providers }; | 
 | static CRITICAL_SECTION providers_cs; | 
 | static CRITICAL_SECTION_DEBUG providers_cs_debug = | 
 | { | 
 |     0, 0, &providers_cs, | 
 |     { &providers_cs_debug.ProcessLocksList, | 
 |     &providers_cs_debug.ProcessLocksList }, | 
 |     0, 0, { (DWORD_PTR)(__FILE__ ": providers_cs") } | 
 | }; | 
 | static CRITICAL_SECTION providers_cs = { &providers_cs_debug, -1, 0, 0, 0, 0 }; | 
 |  | 
 | static void CRYPT_CacheSIP(const GUID *pgSubject, SIP_DISPATCH_INFO *info) | 
 | { | 
 |     WINE_SIP_PROVIDER *prov = CryptMemAlloc(sizeof(WINE_SIP_PROVIDER)); | 
 |  | 
 |     if (prov) | 
 |     { | 
 |         prov->subject = *pgSubject; | 
 |         prov->info = *info; | 
 |         EnterCriticalSection(&providers_cs); | 
 |         list_add_tail(&providers, &prov->entry); | 
 |         LeaveCriticalSection(&providers_cs); | 
 |     } | 
 | } | 
 |  | 
 | static WINE_SIP_PROVIDER *CRYPT_GetCachedSIP(const GUID *pgSubject) | 
 | { | 
 |     WINE_SIP_PROVIDER *provider = NULL, *ret = NULL; | 
 |  | 
 |     EnterCriticalSection(&providers_cs); | 
 |     LIST_FOR_EACH_ENTRY(provider, &providers, WINE_SIP_PROVIDER, entry) | 
 |     { | 
 |         if (IsEqualGUID(pgSubject, &provider->subject)) | 
 |             break; | 
 |     } | 
 |     if (provider && IsEqualGUID(pgSubject, &provider->subject)) | 
 |         ret = provider; | 
 |     LeaveCriticalSection(&providers_cs); | 
 |     return ret; | 
 | } | 
 |  | 
 | static inline BOOL CRYPT_IsSIPCached(const GUID *pgSubject) | 
 | { | 
 |     return CRYPT_GetCachedSIP(pgSubject) != NULL; | 
 | } | 
 |  | 
 | void crypt_sip_free(void) | 
 | { | 
 |     WINE_SIP_PROVIDER *prov, *next; | 
 |  | 
 |     LIST_FOR_EACH_ENTRY_SAFE(prov, next, &providers, WINE_SIP_PROVIDER, entry) | 
 |     { | 
 |         list_remove(&prov->entry); | 
 |         FreeLibrary(prov->info.hSIP); | 
 |         CryptMemFree(prov); | 
 |     } | 
 | } | 
 |  | 
 | /* Loads the SIP for pgSubject into the global cache.  Returns FALSE if the | 
 |  * SIP isn't registered or is invalid. | 
 |  */ | 
 | static BOOL CRYPT_LoadSIP(const GUID *pgSubject) | 
 | { | 
 |     SIP_DISPATCH_INFO sip = { 0 }; | 
 |     HMODULE lib = NULL, temp = NULL; | 
 |  | 
 |     sip.pfGet = CRYPT_LoadSIPFunc(pgSubject, szGetSigned, &lib); | 
 |     if (!sip.pfGet) | 
 |         goto error; | 
 |     sip.pfPut = CRYPT_LoadSIPFunc(pgSubject, szPutSigned, &temp); | 
 |     if (!sip.pfPut || temp != lib) | 
 |         goto error; | 
 |     FreeLibrary(temp); | 
 |     sip.pfCreate = CRYPT_LoadSIPFunc(pgSubject, szCreate, &temp); | 
 |     if (!sip.pfCreate || temp != lib) | 
 |         goto error; | 
 |     FreeLibrary(temp); | 
 |     sip.pfVerify = CRYPT_LoadSIPFunc(pgSubject, szVerify, &temp); | 
 |     if (!sip.pfVerify || temp != lib) | 
 |         goto error; | 
 |     FreeLibrary(temp); | 
 |     sip.pfRemove = CRYPT_LoadSIPFunc(pgSubject, szRemoveSigned, &temp); | 
 |     if (!sip.pfRemove || temp != lib) | 
 |         goto error; | 
 |     FreeLibrary(temp); | 
 |     sip.hSIP = lib; | 
 |     CRYPT_CacheSIP(pgSubject, &sip); | 
 |     return TRUE; | 
 |  | 
 | error: | 
 |     FreeLibrary(lib); | 
 |     FreeLibrary(temp); | 
 |     SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN); | 
 |     return FALSE; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPLoad (CRYPT32.@) | 
 |  * | 
 |  * Load some internal crypt32 functions into a SIP_DISPATCH_INFO structure. | 
 |  * | 
 |  * PARAMS | 
 |  *  pgSubject    [I] The GUID. | 
 |  *  dwFlags      [I] Flags. | 
 |  *  pSipDispatch [I] The loaded functions. | 
 |  * | 
 |  * RETURNS | 
 |  *  Success: TRUE. pSipDispatch contains the functions. | 
 |  *  Failure: FALSE. (Look at GetLastError()). | 
 |  * | 
 |  * NOTES | 
 |  *  CryptSIPLoad uses caching for the list of GUIDs and whether a SIP is | 
 |  *  already loaded. | 
 |  * | 
 |  *  An application calls CryptSipLoad which will return a structure with the | 
 |  *  function addresses of some internal crypt32 functions. The application will | 
 |  *  then call these functions which will be forwarded to the appropriate SIP. | 
 |  * | 
 |  *  CryptSIPLoad will load the needed SIP but doesn't unload this dll. The unloading | 
 |  *  is done when crypt32 is unloaded. | 
 |  */ | 
 | BOOL WINAPI CryptSIPLoad | 
 |        (const GUID *pgSubject, DWORD dwFlags, SIP_DISPATCH_INFO *pSipDispatch) | 
 | { | 
 |     TRACE("(%s %d %p)\n", debugstr_guid(pgSubject), dwFlags, pSipDispatch); | 
 |  | 
 |     if (!pgSubject || dwFlags != 0 || !pSipDispatch) | 
 |     { | 
 |         SetLastError(ERROR_INVALID_PARAMETER); | 
 |         return FALSE; | 
 |     } | 
 |     if (!CRYPT_IsSIPCached(pgSubject) && !CRYPT_LoadSIP(pgSubject)) | 
 |         return FALSE; | 
 |  | 
 |     pSipDispatch->hSIP = NULL; | 
 |     pSipDispatch->pfGet = CryptSIPGetSignedDataMsg; | 
 |     pSipDispatch->pfPut = CryptSIPPutSignedDataMsg; | 
 |     pSipDispatch->pfCreate = CryptSIPCreateIndirectData; | 
 |     pSipDispatch->pfVerify = CryptSIPVerifyIndirectData; | 
 |     pSipDispatch->pfRemove = CryptSIPRemoveSignedDataMsg; | 
 |  | 
 |     return TRUE; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPCreateIndirectData (CRYPT32.@) | 
 |  */ | 
 | BOOL WINAPI CryptSIPCreateIndirectData(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pcbIndirectData, | 
 |                                        SIP_INDIRECT_DATA* pIndirectData) | 
 | { | 
 |     WINE_SIP_PROVIDER *sip; | 
 |     BOOL ret = FALSE; | 
 |  | 
 |     TRACE("(%p %p %p)\n", pSubjectInfo, pcbIndirectData, pIndirectData); | 
 |  | 
 |     if (!pSubjectInfo || !pSubjectInfo->pgSubjectType || !pcbIndirectData) | 
 |     { | 
 |         SetLastError(ERROR_INVALID_PARAMETER); | 
 |         return FALSE; | 
 |     } | 
 |     if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) | 
 |         ret = sip->info.pfCreate(pSubjectInfo, pcbIndirectData, pIndirectData); | 
 |     TRACE("returning %d\n", ret); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPGetSignedDataMsg (CRYPT32.@) | 
 |  */ | 
 | BOOL WINAPI CryptSIPGetSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pdwEncodingType, | 
 |                                        DWORD dwIndex, DWORD* pcbSignedDataMsg, BYTE* pbSignedDataMsg) | 
 | { | 
 |     WINE_SIP_PROVIDER *sip; | 
 |     BOOL ret = FALSE; | 
 |  | 
 |     TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, | 
 |           pcbSignedDataMsg, pbSignedDataMsg); | 
 |  | 
 |     if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) | 
 |         ret = sip->info.pfGet(pSubjectInfo, pdwEncodingType, dwIndex, | 
 |          pcbSignedDataMsg, pbSignedDataMsg); | 
 |     TRACE("returning %d\n", ret); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPPutSignedDataMsg (CRYPT32.@) | 
 |  */ | 
 | BOOL WINAPI CryptSIPPutSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD pdwEncodingType, | 
 |                                        DWORD* pdwIndex, DWORD cbSignedDataMsg, BYTE* pbSignedDataMsg) | 
 | { | 
 |     WINE_SIP_PROVIDER *sip; | 
 |     BOOL ret = FALSE; | 
 |  | 
 |     TRACE("(%p %d %p %d %p)\n", pSubjectInfo, pdwEncodingType, pdwIndex, | 
 |           cbSignedDataMsg, pbSignedDataMsg); | 
 |  | 
 |     if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) | 
 |         ret = sip->info.pfPut(pSubjectInfo, pdwEncodingType, pdwIndex, | 
 |          cbSignedDataMsg, pbSignedDataMsg); | 
 |     TRACE("returning %d\n", ret); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPRemoveSignedDataMsg (CRYPT32.@) | 
 |  */ | 
 | BOOL WINAPI CryptSIPRemoveSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, | 
 |                                        DWORD dwIndex) | 
 | { | 
 |     WINE_SIP_PROVIDER *sip; | 
 |     BOOL ret = FALSE; | 
 |  | 
 |     TRACE("(%p %d)\n", pSubjectInfo, dwIndex); | 
 |  | 
 |     if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) | 
 |         ret = sip->info.pfRemove(pSubjectInfo, dwIndex); | 
 |     TRACE("returning %d\n", ret); | 
 |     return ret; | 
 | } | 
 |  | 
 | /*********************************************************************** | 
 |  *             CryptSIPVerifyIndirectData (CRYPT32.@) | 
 |  */ | 
 | BOOL WINAPI CryptSIPVerifyIndirectData(SIP_SUBJECTINFO* pSubjectInfo, | 
 |                                        SIP_INDIRECT_DATA* pIndirectData) | 
 | { | 
 |     WINE_SIP_PROVIDER *sip; | 
 |     BOOL ret = FALSE; | 
 |  | 
 |     TRACE("(%p %p)\n", pSubjectInfo, pIndirectData); | 
 |  | 
 |     if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType))) | 
 |         ret = sip->info.pfVerify(pSubjectInfo, pIndirectData); | 
 |     TRACE("returning %d\n", ret); | 
 |     return ret; | 
 | } |