//depot/Lab03_N/DS/security/cryptoapi/cryptsvc/keysvr.cpp#9 - edit change 6380 (text) #include #include #include #include #include // SVCS_ #include #include #include #include #include #include #include #include "keysvc.h" #include "keysvr.h" #include "pfx.h" #include "cryptui.h" #include "lenroll.h" #include "unicode.h" #include "unicode5.h" #include // Link List structure typedef struct _ContextList { KEYSVC_HANDLE hKeySvc; KEYSVC_CONTEXT *pContext; _ContextList *pNext; } CONTEXTLIST, *PCONTEXTLIST; static PCONTEXTLIST g_pContextList = NULL; // critical section for context linked list static CRITICAL_SECTION g_ListCritSec; BOOL GetTextualSid( IN PSID pSid, // binary Sid IN OUT LPWSTR TextualSid, // buffer for Textual representaion of Sid IN OUT LPDWORD dwBufferLen // required/provided TextualSid buffersize ); BOOL GetUserTextualSid( IN OUT LPWSTR lpBuffer, IN OUT LPDWORD nSize ); static BOOL g_fStartedKeyService = FALSE; #define KEYSVC_DEFAULT_ENDPOINT TEXT("\\pipe\\keysvc") #define KEYSVC_DEFAULT_PROT_SEQ TEXT("ncacn_np") #define MAXPROTSEQ 20 #define ARRAYSIZE(rg) (sizeof(rg) / sizeof((rg)[0])) RPC_BINDING_VECTOR *pKeySvcBindingVector = NULL; void InitLsaString( PLSA_UNICODE_STRING LsaString, // destination LPWSTR String // source (Unicode) ); void *MyAlloc(size_t len) { return LocalAlloc(LMEM_ZEROINIT, len); } void MyFree(void *p) { LocalFree(p); } DWORD StartKeyService( VOID ) { DWORD dwLastError = ERROR_SUCCESS; // // WinNT4, Win95: do nothing, just return success // if( !FIsWinNT5() ) return ERROR_SUCCESS; // initialize the context list critical section __try { InitializeCriticalSection(&g_ListCritSec); } __except (EXCEPTION_EXECUTE_HANDLER) { dwLastError = _exception_code(); } if( dwLastError == ERROR_SUCCESS ) g_fStartedKeyService = TRUE; return dwLastError; } DWORD StopKeyService( VOID ) { DWORD dwLastError = ERROR_SUCCESS; if( !g_fStartedKeyService ) return ERROR_SUCCESS; // delete the context list critical section which was inited in startup DeleteCriticalSection(&g_ListCritSec); return dwLastError; } BOOL IsAdministrator2( VOID ) /*++ This function determines if the calling user is an Administrator. On Windows 95, this function always returns FALSE, as there is no difference between users on that platform. NOTE : This function originally returned TRUE on Win95, but since this would allow machine key administration by anyone this was changed to FALSE. On Windows NT, the caller of this function must be impersonating the user which is to be queried. If the caller is not impersonating, this function will always return FALSE. --*/ { HANDLE hAccessToken; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; PSID psidAdministrators = NULL; BOOL bSuccess; // // If we aren't on WinNT (on Win95) just return TRUE // if(!FIsWinNT()) return FALSE; if(!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &hAccessToken )) return FALSE; bSuccess = AllocateAndInitializeSid( &siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators ); if( bSuccess ) { BOOL fIsMember = FALSE; bSuccess = CheckTokenMembership( hAccessToken, psidAdministrators, &fIsMember ); if( bSuccess && !fIsMember ) bSuccess = FALSE; } CloseHandle( hAccessToken ); if(psidAdministrators) FreeSid(psidAdministrators); return bSuccess; } // Use QueryServiceConfig() to get the service user name and domain DWORD GetServiceDomain( LPWSTR pszServiceName, LPWSTR *ppszUserName, LPWSTR *ppszDomainName ) { SC_HANDLE hSCManager = 0; SC_HANDLE hService = 0; QUERY_SERVICE_CONFIGW serviceConfigIgnore; QUERY_SERVICE_CONFIGW *pServiceConfig = NULL; DWORD cbServiceConfig; DWORD i; DWORD cch; WCHAR *pch; DWORD dwErr = 0; // Initialization: memset(&serviceConfigIgnore, 0, sizeof(serviceConfigIgnore)); // open the service control manager if (0 == (hSCManager = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT))) { dwErr = NTE_FAIL; goto Ret; } // open the service if (0 == (hService = OpenServiceW(hSCManager, pszServiceName, SERVICE_QUERY_CONFIG))) { dwErr = NTE_FAIL; goto Ret; } QueryServiceConfigW(hService, &serviceConfigIgnore, 0, &cbServiceConfig); if (NULL == (pServiceConfig = (QUERY_SERVICE_CONFIGW*)MyAlloc(cbServiceConfig))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } if (FALSE == QueryServiceConfigW(hService, pServiceConfig, cbServiceConfig, &cbServiceConfig)) { dwErr = NTE_FAIL; goto Ret; } // get the domain name and the user name cch = wcslen((LPWSTR)pServiceConfig->lpServiceStartName); pch = (LPWSTR)pServiceConfig->lpServiceStartName; for(i=1;i<=cch;i++) { // quit when the \ is hit if (0x005C == pch[i-1]) break; } pch = pServiceConfig->lpServiceStartName; if (NULL == (*ppszDomainName = (WCHAR*)MyAlloc((i + 1) * sizeof(WCHAR)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } memcpy(*ppszDomainName, pch, (i - 1) * sizeof(WCHAR)); if (NULL == (*ppszUserName = (WCHAR*)MyAlloc(((cch - i) + 1) * sizeof(WCHAR)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } memcpy(*ppszUserName, &pch[i], (cch - i) * sizeof(WCHAR)); Ret: if (pServiceConfig) MyFree(pServiceConfig); return dwErr; } //************************************************************* // // TestIfUserProfileLoaded() // // Purpose: Test to see if this user's profile is loaded. // // Parameters: hToken - user's token // *pfLoaded - OUT - TRUE if loaded false if not // // Return: TRUE if successful // FALSE if an error occurs // // Comments: // //************************************************************* BOOL TestIfUserProfileLoaded( HANDLE hToken, BOOL *pfLoaded ) { WCHAR szSID[MAX_PATH+1]; DWORD cchSID = sizeof(szSID) / sizeof(WCHAR); HKEY hRegKey = 0;; BOOL fRet = FALSE; *pfLoaded = FALSE; // // Get the Sid string for the user // if(!ImpersonateLoggedOnUser( hToken )) goto Ret; fRet = GetUserTextualSid(szSID, &cchSID); RevertToSelf(); if( !fRet ) goto Ret; fRet = FALSE; if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_USERS, szSID, 0, MAXIMUM_ALLOWED, &hRegKey)) { *pfLoaded = TRUE; } fRet = TRUE; Ret: if(hRegKey) RegCloseKey(hRegKey); return fRet; } #define SERVICE_KEYNAME_PREFIX L"_SC_" DWORD LogonToService( LPWSTR pszServiceName, HANDLE *phLogonToken, HANDLE *phProfile ) { DWORD dwErr = 0; LSA_OBJECT_ATTRIBUTES ObjectAttributes; NTSTATUS Status; LSA_HANDLE hPolicy = 0; LSA_UNICODE_STRING KeyName; LPWSTR pszTmpKeyName = NULL; LSA_UNICODE_STRING *pServicePassword = NULL; PROFILEINFOW ProfileInfoW; LPWSTR pszUserName = NULL; LPWSTR pszDomainName = NULL; WCHAR rgwchPassword[PWLEN + 1]; BOOL fProfileLoaded = FALSE; *phLogonToken = 0; *phProfile = 0; memset(&ObjectAttributes, 0, sizeof(ObjectAttributes)); memset(&rgwchPassword, 0, sizeof(rgwchPassword)); // set up the key name if (NULL == (pszTmpKeyName = (LPWSTR)MyAlloc((sizeof(SERVICE_KEYNAME_PREFIX) + wcslen(pszServiceName) + 1) * sizeof(WCHAR)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } wcscpy(pszTmpKeyName, SERVICE_KEYNAME_PREFIX); wcscat(pszTmpKeyName, pszServiceName); InitLsaString(&KeyName, pszTmpKeyName); // open the policy if (STATUS_SUCCESS != (Status = LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_GET_PRIVATE_INFORMATION, &hPolicy))) { dwErr = NTE_FAIL; goto Ret; } // get the service password if ((STATUS_SUCCESS != (Status = LsaRetrievePrivateData(hPolicy, &KeyName, &pServicePassword))) || (NULL == pServicePassword)) { dwErr = NTE_FAIL; goto Ret; } if(pServicePassword->Length > sizeof(rgwchPassword)) { dwErr = NTE_FAIL; goto Ret; } memcpy(rgwchPassword, pServicePassword->Buffer, pServicePassword->Length); // get the username + domain name if (0 != (dwErr = GetServiceDomain(pszServiceName, &pszUserName, &pszDomainName))) { goto Ret; } // log the service on if (0 == LogonUserW(pszUserName, pszDomainName, rgwchPassword, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, phLogonToken)) { dwErr = GetLastError(); goto Ret; } // check if the profile is already loaded if (!TestIfUserProfileLoaded(*phLogonToken, &fProfileLoaded)) { dwErr = GetLastError(); goto Ret; } // if necessary load the hive associated with the service if (!fProfileLoaded) { memset(&ProfileInfoW, 0, sizeof(ProfileInfoW)); ProfileInfoW.dwSize = sizeof(ProfileInfoW); ProfileInfoW.lpUserName = pszServiceName; ProfileInfoW.dwFlags = PI_NOUI; if (FALSE == LoadUserProfileW(*phLogonToken, &ProfileInfoW)) { dwErr = GetLastError(); goto Ret; } *phProfile = ProfileInfoW.hProfile; } // impersonate the service if (FALSE == ImpersonateLoggedOnUser(*phLogonToken)) { dwErr = GetLastError(); } Ret: if (0 != dwErr) { if (*phProfile) UnloadUserProfile(*phLogonToken, *phProfile); *phProfile = 0; if (*phLogonToken) CloseHandle(*phLogonToken); *phLogonToken = 0; } if (pServicePassword) { ZeroMemory( pServicePassword->Buffer, pServicePassword->Length ); LsaFreeMemory(pServicePassword); } if (pszUserName) MyFree(pszUserName); if (pszDomainName) MyFree(pszDomainName); if (pszTmpKeyName) MyFree(pszTmpKeyName); if (hPolicy) LsaClose(hPolicy); return dwErr; } DWORD LogoffService( HANDLE hLogonToken, HANDLE hProfile ) { DWORD dwErr = 0; // revert to self RevertToSelf(); // unload the profile if (hProfile) UnloadUserProfile(hLogonToken, hProfile); // close the Token handle gotten with LogonUser if (hLogonToken) CloseHandle(hLogonToken); return dwErr; } DWORD CheckIfAdmin( handle_t hRPCBinding ) { DWORD dwErr = 0; if (0 != (dwErr = RpcImpersonateClient((RPC_BINDING_HANDLE)hRPCBinding))) goto Ret; if (!IsAdministrator2()) dwErr = (DWORD)NTE_PERM; Ret: RpcRevertToSelfEx((RPC_BINDING_HANDLE)hRPCBinding); return dwErr; } DWORD KeySvrImpersonate( handle_t hRPCBinding, KEYSVC_CONTEXT *pContext ) { DWORD dwErr = 0; switch(pContext->dwType) { case KeySvcMachine: dwErr = CheckIfAdmin(hRPCBinding); break; case KeySvcService: if (0 != (dwErr = CheckIfAdmin(hRPCBinding))) goto Ret; dwErr = LogonToService(pContext->pszServiceName, &pContext->hLogonToken, &pContext->hProfile); break; } Ret: return dwErr; } DWORD KeySvrRevert( handle_t hRPCBinding, KEYSVC_CONTEXT *pContext ) { DWORD dwErr = 0; if (pContext) { switch(pContext->dwType) { case KeySvcService: dwErr = LogoffService(pContext->hLogonToken, pContext->hProfile); pContext->hProfile = 0; pContext->hLogonToken = 0; break; } } return dwErr; } // // Function: MakeNewHandle // // Description: Creates a random key service handle. // KEYSVC_HANDLE MakeNewHandle() { KEYSVC_HANDLE hKeySvc = 0; // get a random handle value RtlGenRandom((BYTE*)&hKeySvc, sizeof(KEYSVC_HANDLE)); return hKeySvc; } // // Function: CheckIfHandleInList // // Description: Goes through the link list of contexts and checks // if the passed in handle is in the list. If so // the list entry is returned. // PCONTEXTLIST CheckIfHandleInList( KEYSVC_HANDLE hKeySvc ) { PCONTEXTLIST pContextList = g_pContextList; while (1) { if ((NULL == pContextList) || (pContextList->hKeySvc == hKeySvc)) { break; } pContextList = pContextList->pNext; } return pContextList; } // // Function: MakeKeySvcHandle // // Description: The function takes a context pointer and returns a handle // to that context. An element in the context list is added // with the handle and the context pointer. // KEYSVC_HANDLE MakeKeySvcHandle( KEYSVC_CONTEXT *pContext ) { DWORD dwRet = ERROR_INVALID_PARAMETER; KEYSVC_HANDLE hKeySvc = 0; BOOL fIncrementedRefCount = FALSE; BOOL fInCritSec = FALSE; PCONTEXTLIST pContextList = NULL; // allocate a new element for the list if (NULL == (pContextList = (PCONTEXTLIST)MyAlloc(sizeof(CONTEXTLIST)))) { dwRet = ERROR_NOT_ENOUGH_MEMORY; goto Error; } pContextList->pContext = pContext; if (0 >= InterlockedIncrement(&(pContext->iRefCount))) { dwRet = ERROR_INVALID_PARAMETER; goto Error; } fIncrementedRefCount = TRUE; // enter critical section EnterCriticalSection(&g_ListCritSec); fInCritSec = TRUE; __try { pContextList->pNext = g_pContextList; while (1) { hKeySvc = MakeNewHandle(); if (NULL == CheckIfHandleInList(hKeySvc)) break; } // add new element to the front of the list pContextList->hKeySvc = hKeySvc; g_pContextList = pContextList; } __except ( EXCEPTION_EXECUTE_HANDLER ) { hKeySvc = 0; goto Error; } dwRet = ERROR_SUCCESS; Ret: // leave critical section if (fInCritSec) { LeaveCriticalSection(&g_ListCritSec); } SetLastError(dwRet); return hKeySvc; Error: if (NULL != pContextList) { MyFree(pContextList); } if (fIncrementedRefCount) { InterlockedDecrement(&(pContext->iRefCount)); } goto Ret; } // // Function: CheckKeySvcHandle // // Description: The function takes a handle and returns the context pointer // associated with that handle. If the handle is not in the // list then the function returns NULL. // KEYSVC_CONTEXT *CheckKeySvcHandle( KEYSVC_HANDLE hKeySvc ) { PCONTEXTLIST pContextList = NULL; KEYSVC_CONTEXT *pContext = NULL; // enter critical section EnterCriticalSection(&g_ListCritSec); __try { if (NULL != (pContextList = CheckIfHandleInList(hKeySvc))) { pContext = pContextList->pContext; // increment the ref count if (0 >= InterlockedIncrement(&(pContext->iRefCount))) { pContext = NULL; } } } __except ( EXCEPTION_EXECUTE_HANDLER ) { goto Ret; } Ret: // leave critical section LeaveCriticalSection(&g_ListCritSec); return pContext; } // // Function: FreeContext // // Description: The function frees a context pointer. // void FreeContext( KEYSVC_CONTEXT *pContext ) { if (NULL != pContext->pszServiceName) MyFree(pContext->pszServiceName); MyFree(pContext); } // // Function: FreeContext // // Description: The function frees a context pointer if the ref count is 0. // void ReleaseContext( IN KEYSVC_CONTEXT *pContext ) { if (NULL != pContext) { if (0 >= InterlockedDecrement(&(pContext->iRefCount))) { FreeContext(pContext); } } } // // Function: RemoveKeySvcHandle // // Description: The function takes a handle and removes the element in // the list associated with this handle. // DWORD RemoveKeySvcHandle( KEYSVC_HANDLE hKeySvc ) { PCONTEXTLIST pContextList = g_pContextList; PCONTEXTLIST pPrevious = NULL; DWORD dwErr = ERROR_INVALID_PARAMETER; // enter critical section EnterCriticalSection(&g_ListCritSec); __try { while (1) { // have we hit the end, if so exit without removing anything if (NULL == pContextList) { break; } // have we found the list entry if (hKeySvc == pContextList->hKeySvc) { if (pContextList == g_pContextList) { g_pContextList = pContextList->pNext; } else { pPrevious->pNext = pContextList->pNext; } // free the memory ReleaseContext(pContextList->pContext); MyFree(pContextList); dwErr = 0; break; } pPrevious = pContextList; pContextList = pContextList->pNext; } } __except ( EXCEPTION_EXECUTE_HANDLER ) { goto Ret; } Ret: // leave critical section LeaveCriticalSection(&g_ListCritSec); return dwErr; } DWORD AllocAndAssignString( IN PKEYSVC_UNICODE_STRING pUnicodeString, OUT LPWSTR *ppwsz ) { DWORD dwErr = 0; if ((NULL != pUnicodeString->Buffer) && (0 != pUnicodeString->Length)) { if ((pUnicodeString->Length > pUnicodeString->MaximumLength) || (pUnicodeString->Length & 1) || (pUnicodeString->MaximumLength & 1)) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } if (NULL == (*ppwsz = (LPWSTR)MyAlloc(pUnicodeString->MaximumLength + sizeof(WCHAR)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } memcpy(*ppwsz, pUnicodeString->Buffer, pUnicodeString->Length); } Ret: return dwErr; } // key service functions ULONG s_KeyrOpenKeyService( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_TYPE OwnerType, /* [in] */ PKEYSVC_UNICODE_STRING pOwnerName, /* [in] */ ULONG ulDesiredAccess, /* [in] */ PKEYSVC_BLOB pAuthentication, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [out] */ KEYSVC_HANDLE *phKeySvc) { KEYSVC_CONTEXT *pContext = NULL; BOOL fImpersonated = FALSE; HANDLE hThread = 0; HANDLE hToken = 0; WCHAR pszUserName[UNLEN + 1]; DWORD cbUserName; DWORD dwErr = 0; __try { *phKeySvc = 0; if (NULL == ppReserved || NULL != *ppReserved) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } // Return a blob representing the version: (*ppReserved) = (PKEYSVC_BLOB)MyAlloc(sizeof(KEYSVC_BLOB) + sizeof(KEYSVC_OPEN_KEYSVC_INFO)); if (NULL == (*ppReserved)) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } (*ppReserved)->cb = sizeof(KEYSVC_OPEN_KEYSVC_INFO); (*ppReserved)->pb = ((LPBYTE)(*ppReserved)) + sizeof(KEYSVC_BLOB); KEYSVC_OPEN_KEYSVC_INFO sOpenKeySvcInfo = { sizeof(KEYSVC_OPEN_KEYSVC_INFO), KEYSVC_VERSION_WHISTLER }; memcpy((*ppReserved)->pb, &sOpenKeySvcInfo, sizeof(sOpenKeySvcInfo)); // allocate a new context structure if (NULL == (pContext = (KEYSVC_CONTEXT*)MyAlloc(sizeof(KEYSVC_CONTEXT)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pContext->dwType = OwnerType; // take action depending on type of key owner switch(OwnerType) { case KeySvcMachine: if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; break; case KeySvcService: if (0 == pOwnerName->Length) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } if (0 != (dwErr = AllocAndAssignString( pOwnerName, &pContext->pszServiceName))) { goto Ret; } // impersonate the service if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; break; default: dwErr = ERROR_INVALID_PARAMETER; goto Ret; } pContext->dwAccess = ulDesiredAccess; if (0 == (*phKeySvc = MakeKeySvcHandle(pContext))) { dwErr = GetLastError(); } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (hToken) CloseHandle(hToken); if (hThread) CloseHandle(hThread); if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); // if error then free the context if necessary if (dwErr) { if(pContext) { FreeContext(pContext); } if((*ppReserved)) { MyFree((*ppReserved)); (*ppReserved) = NULL; } } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrEnumerateProviders( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [in, out] */ ULONG *pcProviderCount, /* [in, out][size_is(,*pcProviderCount)] */ PKEYSVC_PROVIDER_INFO *ppProviders) { PTMP_LIST_INFO pStart = NULL; PTMP_LIST_INFO pTmpList = NULL; PTMP_LIST_INFO pPrevious = NULL; PKEYSVC_PROVIDER_INFO pProvInfo; DWORD dwProvType; DWORD cbName; DWORD cbTotal = 0; DWORD cTypes = 0; DWORD i; DWORD j; BYTE *pb; KEYSVC_CONTEXT *pContext = NULL; BOOL fImpersonated = FALSE; DWORD dwErr = 0; __try { *pcProviderCount = 0; *ppProviders = NULL; if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; // CryptoAPI enumerates one at a time // so we must accumulate for total enumeration for (i=0;;i++) { if (!CryptEnumProvidersW(i, NULL, 0, &dwProvType, NULL, &cbName)) { if (ERROR_NO_MORE_ITEMS != GetLastError()) { dwErr = NTE_FAIL; goto Ret; } break; } if (NULL == (pTmpList = (PTMP_LIST_INFO)MyAlloc(sizeof(TMP_LIST_INFO)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } if (NULL == (pTmpList->pInfo = MyAlloc(sizeof(KEYSVC_PROVIDER_INFO) + cbName))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pProvInfo = (PKEYSVC_PROVIDER_INFO)pTmpList->pInfo; pProvInfo->Name.Length = (USHORT)cbName; pProvInfo->Name.MaximumLength = (USHORT)cbName; pProvInfo->Name.Buffer = (USHORT*)((BYTE*)(pProvInfo) + sizeof(KEYSVC_PROVIDER_INFO)); if (!CryptEnumProvidersW(i, NULL, 0, &pProvInfo->ProviderType, pProvInfo->Name.Buffer, &cbName)) { if (ERROR_NO_MORE_ITEMS != GetLastError()) { MyFree(pProvInfo); dwErr = NTE_FAIL; goto Ret; } break; } cbTotal += cbName; if (0 == i) { pStart = pTmpList; } else { pPrevious->pNext = pTmpList; } pPrevious = pTmpList; pTmpList = NULL; } // now copy into one big structure pPrevious = pStart; if (0 != i) { *pcProviderCount = i; if (NULL == (*ppProviders = (PKEYSVC_PROVIDER_INFO)MyAlloc((i * sizeof(KEYSVC_PROVIDER_INFO)) + cbTotal))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pb = (BYTE*)(*ppProviders) + i * sizeof(KEYSVC_PROVIDER_INFO); // copy the provider information over for (j=0;jpInfo; (*ppProviders)[j].ProviderType = pProvInfo->ProviderType; (*ppProviders)[j].Name.Length = pProvInfo->Name.Length; (*ppProviders)[j].Name.MaximumLength = pProvInfo->Name.MaximumLength; memcpy(pb, (BYTE*)(pProvInfo->Name.Buffer), (*ppProviders)[j].Name.Length); (*ppProviders)[j].Name.Buffer = (USHORT*)pb; pb += (*ppProviders)[j].Name.Length; pPrevious = pPrevious->pNext; } } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (pTmpList) MyFree(pTmpList); // free the list for (i=0;;i++) { if (NULL == pStart) break; pPrevious = pStart; pStart = pPrevious->pNext; if (pPrevious->pInfo) MyFree(pPrevious->pInfo); MyFree(pPrevious); } if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrEnumerateProviderTypes( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [in, out] */ ULONG *pcProviderCount, /* [in, out][size_is(,*pcProviderCount)] */ PKEYSVC_PROVIDER_INFO *ppProviders) { PTMP_LIST_INFO pStart = NULL; PTMP_LIST_INFO pTmpList = NULL; PTMP_LIST_INFO pPrevious = NULL; PKEYSVC_PROVIDER_INFO pProvInfo; DWORD dwProvType; DWORD cbName = 0;; DWORD cbTotal = 0; DWORD cTypes = 0; DWORD i; DWORD j; BYTE *pb; KEYSVC_CONTEXT *pContext = NULL; BOOL fImpersonated = FALSE; DWORD dwErr = 0; __try { *pcProviderCount = 0; *ppProviders = NULL; if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; // CryptoAPI enumerates one at a time // so we must accumulate for total enumeration for (i=0;;i++) { if (!CryptEnumProviderTypesW(i, NULL, 0, &dwProvType, NULL, &cbName)) { if (ERROR_NO_MORE_ITEMS != GetLastError()) { dwErr = NTE_FAIL; goto Ret; } break; } if (NULL == (pTmpList = (PTMP_LIST_INFO)MyAlloc(sizeof(TMP_LIST_INFO)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } if (NULL == (pTmpList->pInfo = MyAlloc(sizeof(KEYSVC_PROVIDER_INFO) + cbName))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pProvInfo = (PKEYSVC_PROVIDER_INFO)pTmpList->pInfo; pProvInfo->Name.Length = (USHORT)cbName; pProvInfo->Name.MaximumLength = (USHORT)cbName; if (0 != cbName) { pProvInfo->Name.Buffer = (USHORT*)((BYTE*)(pProvInfo) + sizeof(KEYSVC_PROVIDER_INFO)); } if (!CryptEnumProviderTypesW(i, NULL, 0, &pProvInfo->ProviderType, pProvInfo->Name.Buffer, &cbName)) { if (ERROR_NO_MORE_ITEMS != GetLastError()) { MyFree(pProvInfo); dwErr = NTE_FAIL; goto Ret; } break; } cbTotal += cbName; if (0 == i) { pStart = pTmpList; } else { pPrevious->pNext = pTmpList; } pPrevious = pTmpList; pTmpList = NULL; } // now copy into one big structure pPrevious = pStart; if (0 != i) { *pcProviderCount = i; if (NULL == (*ppProviders = (PKEYSVC_PROVIDER_INFO)MyAlloc((i * sizeof(KEYSVC_PROVIDER_INFO)) + cbTotal))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pb = (BYTE*)(*ppProviders) + i * sizeof(KEYSVC_PROVIDER_INFO); // copy the provider information over for (j=0;jpInfo; (*ppProviders)[j].ProviderType = pProvInfo->ProviderType; (*ppProviders)[j].Name.Length = pProvInfo->Name.Length; (*ppProviders)[j].Name.MaximumLength = pProvInfo->Name.MaximumLength; if (0 != (*ppProviders)[j].Name.Length) { memcpy(pb, (BYTE*)(pProvInfo->Name.Buffer), (*ppProviders)[j].Name.Length); (*ppProviders)[j].Name.Buffer = (USHORT*)pb; } pb += (*ppProviders)[j].Name.Length; pPrevious = pPrevious->pNext; } } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (pTmpList) MyFree(pTmpList); // free the list for (i=0;;i++) { if (NULL == pStart) break; pPrevious = pStart; pStart = pPrevious->pNext; if (pPrevious->pInfo) MyFree(pPrevious->pInfo); MyFree(pPrevious); } if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } DWORD GetKeyIDs( KEYSVC_PROVIDER_INFO *pProvider, LPWSTR pszContainerName, DWORD *pcKeyIDs, PKEY_ID *ppKeyIDs, DWORD dwFlags) { HCRYPTPROV hProv = 0; HCRYPTKEY hKey = 0; KEY_ID rgKeyIDs[2]; DWORD cbData; DWORD dwKeySpec; DWORD i; DWORD dwErr = 0; *pcKeyIDs = 0; memset(rgKeyIDs, 0, sizeof(rgKeyIDs)); // acquire the context if (!CryptAcquireContextU(&hProv, pszContainerName, pProvider->Name.Buffer, pProvider->ProviderType, dwFlags)) { dwErr = GetLastError(); goto Ret; } // try and get the AT_SIGNATURE key for (i=0;i<2;i++) { // probably need to enumerate all key specs if (0 == i) dwKeySpec = AT_SIGNATURE; else dwKeySpec = AT_KEYEXCHANGE; if (CryptGetUserKey(hProv, dwKeySpec, &hKey)) { rgKeyIDs[*pcKeyIDs].dwKeySpec = dwKeySpec; cbData = sizeof(ALG_ID); if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)(&rgKeyIDs[*pcKeyIDs].Algid), &cbData, 0)) { dwErr = GetLastError(); goto Ret; } (*pcKeyIDs)++; CryptDestroyKey(hKey); hKey = 0; } } // allocate the final structure to hold the key ids and copy them in if (*pcKeyIDs) { if (NULL == (*ppKeyIDs = (PKEY_ID)MyAlloc(*pcKeyIDs * sizeof(KEY_ID)))) { goto Ret; } for (i=0;i<*pcKeyIDs;i++) { memcpy((BYTE*)(&(*ppKeyIDs)[i]), (BYTE*)(&rgKeyIDs[i]), sizeof(KEY_ID)); } } Ret: if (hKey) CryptDestroyKey(hKey); if (hProv) CryptReleaseContext(hProv, 0); return dwErr; } ULONG s_KeyrEnumerateProvContainers( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in] */ KEYSVC_PROVIDER_INFO Provider, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [in, out] */ ULONG *pcContainerCount, /* [in, out][size_is(,*pcContainerCount)] */ PKEYSVC_UNICODE_STRING *ppContainers) { HCRYPTPROV hProv = 0; PTMP_LIST_INFO pStart = NULL; PTMP_LIST_INFO pTmpList = NULL; PTMP_LIST_INFO pPrevious = NULL; PKEYSVC_UNICODE_STRING pContainer; DWORD i; DWORD j; BYTE *pb; DWORD cbContainerName; DWORD cbMaxContainerName = 0; LPSTR pszContainerName = NULL; DWORD cbContainerTotal = 0; KEYSVC_CONTEXT *pContext = NULL; DWORD dwFlags = 0; DWORD dwMachineFlag = 0; BOOL fImpersonated = FALSE; BYTE *pbJunk = NULL; DWORD cch; DWORD dwErr = 0; __try { *pcContainerCount = 0; *ppContainers = NULL; if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; if (KeySvcMachine == pContext->dwType) { dwMachineFlag = CRYPT_MACHINE_KEYSET; } if (!CryptAcquireContextU(&hProv, NULL, Provider.Name.Buffer, Provider.ProviderType, dwMachineFlag | CRYPT_VERIFYCONTEXT)) { dwErr = GetLastError(); goto Ret; } // CryptoAPI enumerates one at a time // so we must accumulate for total enumeration CryptGetProvParam(hProv, PP_ENUMCONTAINERS, NULL, &cbMaxContainerName, CRYPT_FIRST); if (cbMaxContainerName > 0) { if (NULL == (pszContainerName = (LPSTR)MyAlloc(cbMaxContainerName))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } } for (i=0;;i++) { if (0 == i) dwFlags = CRYPT_FIRST; else dwFlags = CRYPT_NEXT; if (NULL == (pTmpList = (PTMP_LIST_INFO)MyAlloc(sizeof(TMP_LIST_INFO)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } cbContainerName = cbMaxContainerName; if (!CryptGetProvParam(hProv, PP_ENUMCONTAINERS, (BYTE*)pszContainerName, &cbContainerName, dwFlags)) { // BUG in rsabase - doesn't return correct error code // if (ERROR_NO_MORE_ITEMS != GetLastError()) // { // dwErr = NTE_FAIL; // goto Ret; // } break; } // convert from ansi to unicode if (0 == (cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pszContainerName, -1, NULL, cch))) { dwErr = GetLastError(); goto Ret; } if (NULL == (pTmpList->pInfo = MyAlloc(sizeof(KEYSVC_UNICODE_STRING) + (cch + 1) * sizeof(WCHAR)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pContainer = (PKEYSVC_UNICODE_STRING)pTmpList->pInfo; pContainer->Length = (USHORT)(cch * sizeof(WCHAR)); pContainer->MaximumLength = (USHORT)((cch + 1) * sizeof(WCHAR)); pContainer->Buffer = (USHORT*)((BYTE*)(pContainer) + sizeof(KEYSVC_UNICODE_STRING)); if (0 == (cch = MultiByteToWideChar(CP_ACP, MB_COMPOSITE, pszContainerName, -1, pContainer->Buffer, cch))) { goto Ret; } cbContainerTotal += pContainer->Length + sizeof(WCHAR); if (0 == i) { pStart = pTmpList; } else { pPrevious->pNext = pTmpList; } pPrevious = pTmpList; pTmpList = NULL; } // now copy into one big structure pPrevious = pStart; if (0 != i) { *pcContainerCount = i; if (NULL == (*ppContainers = (PKEYSVC_UNICODE_STRING)MyAlloc((i * sizeof(KEYSVC_UNICODE_STRING)) + cbContainerTotal))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pb = (BYTE*)(*ppContainers) + i * sizeof(KEYSVC_UNICODE_STRING); // copy the provider information over for (j=0;jpInfo; (*ppContainers)[j].Length = pContainer->Length; (*ppContainers)[j].MaximumLength = pContainer->MaximumLength; if (0 != (*ppContainers)[j].Length) { memcpy(pb, (BYTE*)(pContainer->Buffer), (*ppContainers)[j].Length + sizeof(WCHAR)); (*ppContainers)[j].Buffer = (USHORT*)pb; } pb += (*ppContainers)[j].Length + sizeof(WCHAR); pPrevious = pPrevious->pNext; } } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (pszContainerName) MyFree(pszContainerName); if (hProv) CryptReleaseContext(hProv, 0); if (pTmpList) MyFree(pTmpList); // free the list for (i=0;;i++) { if (NULL == pStart) break; pPrevious = pStart; pStart = pPrevious->pNext; if (pPrevious->pInfo) MyFree(pPrevious->pInfo); MyFree(pPrevious); } if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrCloseKeyService( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in, out] */ PKEYSVC_BLOB *ppReserved) { DWORD dwErr = 0; __try { dwErr = RemoveKeySvcHandle(hKeySvc); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: return dwErr; } ULONG s_KeyrGetDefaultProvider( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in] */ ULONG ulProvType, /* [in] */ ULONG ulFlags, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [out] */ ULONG *pulDefType, /* [out] */ PKEYSVC_PROVIDER_INFO *ppProvider) { KEYSVC_CONTEXT *pContext = NULL; BYTE *pb = NULL; DWORD cbProvName; DWORD dwFlags = CRYPT_USER_DEFAULT; PKEYSVC_PROVIDER_INFO pProvInfo = NULL; BOOL fImpersonated = FALSE; DWORD dwErr = 0; __try { *ppProvider = NULL; if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) goto Ret; if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; // set flag for MACHINE_KEYSET if necessary if (KeySvcMachine != pContext->dwType) { if (!CryptGetDefaultProviderW(ulProvType, NULL, dwFlags, NULL, &cbProvName)) { dwFlags = CRYPT_MACHINE_DEFAULT; } } else { dwFlags = CRYPT_MACHINE_DEFAULT; } if (CRYPT_MACHINE_DEFAULT == dwFlags) { if (!CryptGetDefaultProviderW(ulProvType, NULL, dwFlags, NULL, &cbProvName)) { dwErr = GetLastError(); goto Ret; } } // alloc space for and place info into the ppProvider structure if (NULL == (*ppProvider = (PKEYSVC_PROVIDER_INFO)MyAlloc(sizeof(KEYSVC_PROVIDER_INFO) + cbProvName))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pb = (BYTE*)(*ppProvider) + sizeof(KEYSVC_PROVIDER_INFO); (*ppProvider)->ProviderType = ulProvType; (*ppProvider)->Name.Length = (USHORT)cbProvName; (*ppProvider)->Name.MaximumLength = (USHORT)cbProvName; if (!CryptGetDefaultProviderW(ulProvType, NULL, dwFlags, (USHORT*)pb, &cbProvName)) { dwErr = GetLastError(); goto Ret; } (*ppProvider)->Name.Buffer = (USHORT*)pb; if (CRYPT_MACHINE_DEFAULT == dwFlags) { *pulDefType = DefMachineProv; } else { *pulDefType = DefUserProv; } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (dwErr && *ppProvider) { MyFree(*ppProvider); *ppProvider = NULL; } if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrSetDefaultProvider( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in] */ ULONG ulFlags, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [in] */ KEYSVC_PROVIDER_INFO Provider) { KEYSVC_CONTEXT *pContext = NULL; DWORD dwFlags = CRYPT_USER_DEFAULT; BOOL fImpersonated = FALSE; LPWSTR pwszProvName = NULL; DWORD dwErr = 0; __try { if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) goto Ret; if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; // set flag for MACHINE_KEYSET if necessary if (KeySvcMachine == pContext->dwType) dwFlags = CRYPT_MACHINE_DEFAULT; if (0 != (dwErr = AllocAndAssignString(&(Provider.Name), &pwszProvName))) { goto Ret; } if (!CryptSetProviderExW(pwszProvName, Provider.ProviderType, NULL, dwFlags)) { dwErr = GetLastError(); goto Ret; } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (pwszProvName) MyFree(pwszProvName); if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrEnroll( /* [in] */ handle_t hRPCBinding, /* [in] */ BOOL fKeyService, /* [in] */ ULONG ulPurpose, /* [in] */ PKEYSVC_UNICODE_STRING pAcctName, /* [in] */ PKEYSVC_UNICODE_STRING pCALocation, /* [in] */ PKEYSVC_UNICODE_STRING pCAName, /* [in] */ BOOL fNewKey, /* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW pKeyNew, /* [in] */ PKEYSVC_BLOB __RPC_FAR pCert, /* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW pRenewKey, /* [in] */ PKEYSVC_UNICODE_STRING pHashAlg, /* [in] */ PKEYSVC_UNICODE_STRING pDesStore, /* [in] */ ULONG ulStoreFlags, /* [in] */ PKEYSVC_CERT_ENROLL_INFO pRequestInfo, /* [in] */ ULONG ulFlags, /* [out][in] */ PKEYSVC_BLOB __RPC_FAR *ppReserved, /* [out] */ PKEYSVC_BLOB __RPC_FAR *ppPKCS7Blob, /* [out] */ PKEYSVC_BLOB __RPC_FAR *ppHashBlob, /* [out] */ ULONG __RPC_FAR *pulStatus) { CERT_REQUEST_PVK_NEW KeyNew; CERT_REQUEST_PVK_NEW RenewKey; DWORD cbExtensions; PBYTE pbExtensions = NULL; PCERT_REQUEST_PVK_NEW pTmpRenewKey = NULL; PCERT_REQUEST_PVK_NEW pTmpKeyNew = NULL; LPWSTR pwszAcctName = NULL; LPWSTR pwszProv = NULL; LPWSTR pwszCont = NULL; LPWSTR pwszRenewProv = NULL; LPWSTR pwszRenewCont = NULL; LPWSTR pwszDesStore = NULL; LPWSTR pwszAttributes = NULL; LPWSTR pwszFriendly = NULL; LPWSTR pwszDescription = NULL; LPWSTR pwszUsage = NULL; LPWSTR pwszCALocation = NULL; LPWSTR pwszCertDNName = NULL; LPWSTR pwszCAName = NULL; LPWSTR pwszHashAlg = NULL; HANDLE hLogonToken = 0; HANDLE hProfile = 0; CERT_BLOB CertBlob; CERT_BLOB *pCertBlob = NULL; CERT_BLOB PKCS7Blob; CERT_BLOB HashBlob; CERT_ENROLL_INFO EnrollInfo; DWORD dwErr = 0; __try { memset(&KeyNew, 0, sizeof(KeyNew)); memset(&RenewKey, 0, sizeof(RenewKey)); memset(&EnrollInfo, 0, sizeof(EnrollInfo)); memset(&PKCS7Blob, 0, sizeof(PKCS7Blob)); memset(&HashBlob, 0, sizeof(HashBlob)); memset(&CertBlob, 0, sizeof(CertBlob)); *ppPKCS7Blob = NULL; *ppHashBlob = NULL; // check if the client is an admin if (0 != (dwErr = CheckIfAdmin(hRPCBinding))) goto Ret; // if enrolling for a service account then need to logon and load profile if (0 != pAcctName->Length) { if (0 != (dwErr = AllocAndAssignString(pAcctName, &pwszAcctName))) goto Ret; if (0 != (dwErr = LogonToService(pwszAcctName, &hLogonToken, &hProfile))) goto Ret; } // assign all the values in the passed in structure to the // temporary structure KeyNew.dwSize = sizeof(CERT_REQUEST_PVK_NEW); KeyNew.dwProvType = pKeyNew->ulProvType; if (0 != (dwErr = AllocAndAssignString(&pKeyNew->Provider, &pwszProv))) goto Ret; KeyNew.pwszProvider = pwszProv; KeyNew.dwProviderFlags = pKeyNew->ulProviderFlags; if (0 != (dwErr = AllocAndAssignString(&pKeyNew->KeyContainer, &pwszCont))) goto Ret; KeyNew.pwszKeyContainer = pwszCont; KeyNew.dwKeySpec = pKeyNew->ulKeySpec; KeyNew.dwGenKeyFlags = pKeyNew->ulGenKeyFlags; pTmpKeyNew = &KeyNew; if (pCert->cb) { // if necessary assign the cert to be renewed values // temporary structure CertBlob.cbData = pCert->cb; CertBlob.pbData = pCert->pb; pCertBlob = &CertBlob; } if (CRYPTUI_WIZ_CERT_RENEW == ulPurpose) { // assign all the values in the passed in structure to the // temporary structure RenewKey.dwSize = sizeof(CERT_REQUEST_PVK_NEW); RenewKey.dwProvType = pRenewKey->ulProvType; if (0 != (dwErr = AllocAndAssignString(&pRenewKey->Provider, &pwszRenewProv))) goto Ret; RenewKey.pwszProvider = pwszRenewProv; RenewKey.dwProviderFlags = pRenewKey->ulProviderFlags; if (0 != (dwErr = AllocAndAssignString(&pRenewKey->KeyContainer, &pwszRenewCont))) goto Ret; RenewKey.pwszKeyContainer = pwszRenewCont; RenewKey.dwKeySpec = pRenewKey->ulKeySpec; RenewKey.dwGenKeyFlags = pRenewKey->ulGenKeyFlags; pTmpRenewKey = &RenewKey; } // check if the destination cert store was passed in if (0 != (dwErr = AllocAndAssignString(pDesStore, &pwszDesStore))) goto Ret; // copy over the request info EnrollInfo.dwSize = sizeof(EnrollInfo); if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->UsageOID, &pwszUsage))) goto Ret; EnrollInfo.pwszUsageOID = pwszUsage; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->CertDNName, &pwszCertDNName))) goto Ret; EnrollInfo.pwszCertDNName = pwszCertDNName; // cast the cert extensions EnrollInfo.dwExtensions = pRequestInfo->cExtensions; cbExtensions = (sizeof(CERT_EXTENSIONS)+sizeof(PCERT_EXTENSIONS)) * pRequestInfo->cExtensions; for (DWORD dwIndex = 0; dwIndex < pRequestInfo->cExtensions; dwIndex++) { cbExtensions += sizeof(CERT_EXTENSION) * pRequestInfo->prgExtensions[dwIndex]->cExtension; } EnrollInfo.prgExtensions = (PCERT_EXTENSIONS *)MyAlloc(cbExtensions); if (NULL == EnrollInfo.prgExtensions) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pbExtensions = (PBYTE)(EnrollInfo.prgExtensions + EnrollInfo.dwExtensions); for (DWORD dwIndex = 0; dwIndex < EnrollInfo.dwExtensions; dwIndex++) { EnrollInfo.prgExtensions[dwIndex] = (PCERT_EXTENSIONS)pbExtensions; pbExtensions += sizeof(CERT_EXTENSIONS); EnrollInfo.prgExtensions[dwIndex]->cExtension = pRequestInfo->prgExtensions[dwIndex]->cExtension; EnrollInfo.prgExtensions[dwIndex]->rgExtension = (PCERT_EXTENSION)pbExtensions; pbExtensions += sizeof(CERT_EXTENSION) * EnrollInfo.prgExtensions[dwIndex]->cExtension; for (DWORD dwSubIndex = 0; dwSubIndex < EnrollInfo.prgExtensions[dwIndex]->cExtension; dwSubIndex++) { EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].pszObjId = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].pszObjId; EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].fCritical = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].fCritical; EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].Value.cbData = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].cbData; EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].Value.pbData = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].pbData; } } EnrollInfo.dwPostOption = pRequestInfo->ulPostOption; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->FriendlyName, &pwszFriendly))) goto Ret; EnrollInfo.pwszFriendlyName = pwszFriendly; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->Description, &pwszDescription))) goto Ret; EnrollInfo.pwszDescription = pwszDescription; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->Attributes, &pwszAttributes))) goto Ret; if (0 != (dwErr = AllocAndAssignString(pHashAlg, &pwszHashAlg))) goto Ret; if (0 != (dwErr = AllocAndAssignString(pCALocation, &pwszCALocation))) goto Ret; if (0 != (dwErr = AllocAndAssignString(pCAName, &pwszCAName))) goto Ret; // call the local enrollment API __try { dwErr = LocalEnroll(0, pwszAttributes, NULL, fKeyService, ulPurpose, FALSE, 0, NULL, 0, pwszCALocation, pwszCAName, pCertBlob, pTmpRenewKey, fNewKey, pTmpKeyNew, pwszHashAlg, pwszDesStore, ulStoreFlags, &EnrollInfo, &PKCS7Blob, &HashBlob, pulStatus, NULL); } __except( EXCEPTION_EXECUTE_HANDLER ) { // TODO: convert to Winerror dwErr = GetExceptionCode(); } if( dwErr != 0 ) goto Ret; // alloc and copy for the RPC out parameters if (NULL == (*ppPKCS7Blob = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB) + PKCS7Blob.cbData))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } (*ppPKCS7Blob)->cb = PKCS7Blob.cbData; (*ppPKCS7Blob)->pb = (BYTE*)(*ppPKCS7Blob) + sizeof(KEYSVC_BLOB); memcpy((*ppPKCS7Blob)->pb, PKCS7Blob.pbData, (*ppPKCS7Blob)->cb); if (NULL == (*ppHashBlob = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB) + HashBlob.cbData))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } (*ppHashBlob)->cb = HashBlob.cbData; (*ppHashBlob)->pb = (BYTE*)(*ppHashBlob) + sizeof(KEYSVC_BLOB); memcpy((*ppHashBlob)->pb, HashBlob.pbData, (*ppHashBlob)->cb); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (pwszAcctName) MyFree(pwszAcctName); if (pwszProv) MyFree(pwszProv); if (pwszCont) MyFree(pwszCont); if (pwszRenewProv) MyFree(pwszRenewProv); if (pwszRenewCont) MyFree(pwszRenewCont); if (pwszDesStore) MyFree(pwszDesStore); if (pwszAttributes) MyFree(pwszAttributes); if (pwszFriendly) MyFree(pwszFriendly); if (pwszDescription) MyFree(pwszDescription); if (pwszUsage) MyFree(pwszUsage); if (pwszCertDNName) MyFree(pwszCertDNName); if (pwszCAName) MyFree(pwszCAName); if (pwszCALocation) MyFree(pwszCALocation); if (pwszHashAlg) MyFree(pwszHashAlg); if (PKCS7Blob.pbData) { MyFree(PKCS7Blob.pbData); } if (HashBlob.pbData) { MyFree(HashBlob.pbData); } if (hLogonToken || hProfile) { LogoffService(&hLogonToken, &hProfile); } if (EnrollInfo.prgExtensions) MyFree(EnrollInfo.prgExtensions); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } DWORD MoveCertsFromSystemToMemStore( PKEYSVC_UNICODE_STRING pCertStore, DWORD dwStoreFlags, ULONG cHashCount, KEYSVC_CERT_HASH *pHashes, HCERTSTORE *phMemStore ) { DWORD i; HCERTSTORE hStore = 0; PCCERT_CONTEXT pCertContext = NULL; CRYPT_HASH_BLOB HashBlob; DWORD dwErr = 0; if (NULL == (hStore = CertOpenStore(sz_CERT_STORE_PROV_SYSTEM_W, 0, 0, dwStoreFlags, pCertStore->Buffer))) { dwErr = GetLastError(); goto Ret; } if (NULL == (*phMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL))) { dwErr = GetLastError(); goto Ret; } // get the certs out of the system store and put them in the mem store for(i=0;idwType) { dwStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE; } // move the requested certs from the system store to a memory store if (0 != (dwErr = MoveCertsFromSystemToMemStore(pCertStore, dwStoreFlags, cHashCount, pHashes, &hMemStore))) goto Ret; if (!PFXExportCertStore(hMemStore, &PFXBlob, pPassword->Buffer, ulFlags)) { dwErr = GetLastError(); goto Ret; } if (NULL == (PFXBlob.pbData = (BYTE*)MyAlloc(PFXBlob.cbData))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } if (!PFXExportCertStore(hMemStore, &PFXBlob, pPassword->Buffer, ulFlags)) { dwErr = GetLastError(); goto Ret; } // set up the blob for return through RPC if (NULL == (*ppPFXBlob = (PKEYSVC_BLOB)MyAlloc(sizeof(KEYSVC_BLOB) + PFXBlob.cbData))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } (*ppPFXBlob)->cb = PFXBlob.cbData; (*ppPFXBlob)->pb = (BYTE*)*ppPFXBlob + sizeof(KEYSVC_BLOB); memcpy((*ppPFXBlob)->pb, PFXBlob.pbData, (*ppPFXBlob)->cb); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (PFXBlob.pbData) LocalFree(PFXBlob.pbData); if (hMemStore) CertCloseStore(hMemStore, 0); if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } DWORD MoveCertsFromMemToSystemStore( PKEYSVC_UNICODE_STRING pCertStore, DWORD dwStoreFlags, HCERTSTORE hMemStore ) { DWORD i; HCERTSTORE hStore = 0; PCCERT_CONTEXT pCertContext = NULL; PCCERT_CONTEXT pPrevCertContext = NULL; DWORD dwErr = 0; if (NULL == (hStore = CertOpenStore(sz_CERT_STORE_PROV_SYSTEM_W, 0, 0, dwStoreFlags, pCertStore->Buffer))) { dwErr = GetLastError(); goto Ret; } // get the certs out of the system store and put them in the mem store for(i=0;;i++) { if (NULL == (pCertContext = CertEnumCertificatesInStore(hMemStore, pPrevCertContext))) { pPrevCertContext = NULL; if (CRYPT_E_NOT_FOUND != GetLastError()) { dwErr = GetLastError(); goto Ret; } break; } pPrevCertContext = NULL; if (!CertAddCertificateContextToStore(hStore, pCertContext, CERT_STORE_ADD_USE_EXISTING, NULL)) { dwErr = GetLastError(); goto Ret; } pPrevCertContext = pCertContext; } Ret: if (pCertContext) CertFreeCertificateContext(pCertContext); if (hStore) CertCloseStore(hStore, 0); return dwErr; } ULONG s_KeyrImportCert( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in] */ PKEYSVC_UNICODE_STRING pPassword, /* [in] */ KEYSVC_UNICODE_STRING *pCertStore, /* [in] */ PKEYSVC_BLOB pPFXBlob, /* [in] */ ULONG ulFlags, /* [in, out] */ PKEYSVC_BLOB *ppReserved) { HCERTSTORE hMemStore = 0; KEYSVC_CONTEXT *pContext = NULL; BOOL fImpersonated = FALSE; CRYPT_DATA_BLOB PFXBlob; DWORD dwStoreFlags = CERT_SYSTEM_STORE_CURRENT_USER; DWORD dwErr = 0; __try { if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) goto Ret; if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; // set the cert store information if (KeySvcMachine == pContext->dwType) { dwStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE; } PFXBlob.cbData = pPFXBlob->cb; PFXBlob.pbData = pPFXBlob->pb; if (NULL == (hMemStore = PFXImportCertStore(&PFXBlob, pPassword->Buffer, ulFlags))) { dwErr = GetLastError(); goto Ret; } // open the specified store and transfer all the certs into it dwErr = MoveCertsFromMemToSystemStore(pCertStore, dwStoreFlags, hMemStore); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (hMemStore) CertCloseStore(hMemStore, 0); if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrEnumerateAvailableCertTypes( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [out][in] */ ULONG *pcCertTypeCount, /* [in, out][size_is(,*pcCertTypeCount)] */ PKEYSVC_UNICODE_STRING *ppCertTypes) { KEYSVC_CONTEXT *pContext = NULL; BOOL fImpersonated = FALSE; DWORD dwErr = E_UNEXPECTED; HCERTTYPE hType = NULL; DWORD cTypes = 0; DWORD cTrustedTypes = 0; DWORD i; LPWSTR *awszTrustedTypes = NULL; DWORD cbTrustedTypes = 0; PKEYSVC_UNICODE_STRING awszResult = NULL; LPWSTR wszCurrentName; __try { *pcCertTypeCount = 0; *ppCertTypes = NULL; if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) goto Ret; if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; dwErr = CAEnumCertTypes(CT_FIND_LOCAL_SYSTEM | CT_ENUM_MACHINE_TYPES, &hType); if(dwErr != S_OK) { goto Ret; } cTypes = CACountCertTypes(hType); awszTrustedTypes = (LPWSTR *)MyAlloc(sizeof(LPWSTR)*cTypes); if(awszTrustedTypes == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } while(hType) { HCERTTYPE hNextType = NULL; LPWSTR *awszTypeName = NULL; dwErr = CAGetCertTypeProperty(hType, CERTTYPE_PROP_DN, &awszTypeName); if((dwErr == S_OK) && (awszTypeName)) { if(awszTypeName[0]) { dwErr = CACertTypeAccessCheck(hType, NULL); if(dwErr == S_OK) { awszTrustedTypes[cTrustedTypes] = (LPWSTR)MyAlloc((wcslen(awszTypeName[0])+1)*sizeof(WCHAR)); if(awszTrustedTypes[cTrustedTypes]) { wcscpy(awszTrustedTypes[cTrustedTypes], awszTypeName[0]); cbTrustedTypes += (wcslen(awszTypeName[0])+1)*sizeof(WCHAR); cTrustedTypes++; } } } CAFreeCertTypeProperty(hType, awszTypeName); } dwErr = CAEnumNextCertType(hType, &hNextType); if(dwErr != S_OK) { break; } CACloseCertType(hType); hType = hNextType; } cbTrustedTypes += sizeof(KEYSVC_UNICODE_STRING)*cTrustedTypes; awszResult = (PKEYSVC_UNICODE_STRING)MyAlloc(cbTrustedTypes); if(awszResult == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } wszCurrentName = (LPWSTR)(&awszResult[cTrustedTypes]); for(i=0; i < cTrustedTypes; i++) { wcscpy(wszCurrentName, awszTrustedTypes[i]); awszResult[i].Length = (wcslen(awszTrustedTypes[i]) + 1)*sizeof(WCHAR); awszResult[i].MaximumLength = awszResult[i].Length; awszResult[i].Buffer = wszCurrentName; wszCurrentName += wcslen(awszTrustedTypes[i]) + 1; } *pcCertTypeCount = cTrustedTypes; *ppCertTypes = awszResult; awszResult = NULL; dwErr = ERROR_SUCCESS; } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = _exception_code(); } Ret: __try { // free the list if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if(awszTrustedTypes) { for(i=0; i < cTrustedTypes; i++) { if(awszTrustedTypes[i]) { MyFree(awszTrustedTypes[i]); } } MyFree(awszTrustedTypes); } if(awszResult) { MyFree(awszResult); } if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrEnumerateCAs( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [in] */ ULONG ulFlags, /* [out][in] */ ULONG *pcCACount, /* [in, out][size_is(,*pcCACount)] */ PKEYSVC_UNICODE_STRING *ppCAs) { KEYSVC_CONTEXT *pContext = NULL; BOOL fImpersonated = FALSE; DWORD dwErr = E_UNEXPECTED; HCAINFO hCA = NULL; DWORD cCAs = 0; DWORD cTrustedCAs = 0; DWORD i; LPWSTR *awszTrustedCAs = NULL; DWORD cbTrustedCAs = 0; PKEYSVC_UNICODE_STRING awszResult = NULL; LPWSTR wszCurrentName; __try { *pcCACount = 0; *ppCAs = NULL; if (NULL == (pContext = CheckKeySvcHandle(hKeySvc))) goto Ret; if (0 != (dwErr = KeySvrImpersonate(hRPCBinding, pContext))) goto Ret; fImpersonated = TRUE; dwErr = CAEnumFirstCA(NULL, ulFlags, &hCA); if(dwErr != S_OK) { goto Ret; } cCAs = CACountCAs(hCA); awszTrustedCAs = (LPWSTR *)MyAlloc(sizeof(LPWSTR)*cCAs); if(awszTrustedCAs == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } while(hCA) { HCAINFO hNextCA = NULL; LPWSTR *awszCAName = NULL; dwErr = CAGetCAProperty(hCA, CA_PROP_NAME, &awszCAName); if((dwErr == S_OK) && (awszCAName)) { if(awszCAName[0]) { dwErr = CAAccessCheck(hCA, NULL); if(dwErr == S_OK) { awszTrustedCAs[cTrustedCAs] = (LPWSTR)MyAlloc((wcslen(awszCAName[0])+1)*sizeof(WCHAR)); if(awszTrustedCAs[cTrustedCAs]) { wcscpy(awszTrustedCAs[cTrustedCAs], awszCAName[0]); cbTrustedCAs += (wcslen(awszCAName[0])+1)*sizeof(WCHAR); cTrustedCAs++; } } } CAFreeCAProperty(hCA, awszCAName); } dwErr = CAEnumNextCA(hCA, &hNextCA); if(dwErr != S_OK) { break; } CACloseCA(hCA); hCA = hNextCA; } cbTrustedCAs += sizeof(KEYSVC_UNICODE_STRING)*cTrustedCAs; awszResult = (PKEYSVC_UNICODE_STRING)MyAlloc(cbTrustedCAs); if(awszResult == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } wszCurrentName = (LPWSTR)(&awszResult[cTrustedCAs]); for(i=0; i < cTrustedCAs; i++) { wcscpy(wszCurrentName, awszTrustedCAs[i]); awszResult[i].Length = (wcslen(awszTrustedCAs[i]) + 1)*sizeof(WCHAR); awszResult[i].MaximumLength = awszResult[i].Length; awszResult[i].Buffer = wszCurrentName; wszCurrentName += wcslen(awszTrustedCAs[i]) + 1; } *pcCACount = cTrustedCAs; *ppCAs = awszResult; awszResult = NULL; dwErr = ERROR_SUCCESS; } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = _exception_code(); } Ret: __try { // free the list if (fImpersonated) KeySvrRevert(hRPCBinding, pContext); if(awszTrustedCAs) { for(i=0; i < cTrustedCAs; i++) { if(awszTrustedCAs[i]) { MyFree(awszTrustedCAs[i]); } } MyFree(awszTrustedCAs); } if(awszResult) { MyFree(awszResult); } if (pContext) ReleaseContext(pContext); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } BOOL GetTokenUserSid( IN HANDLE hToken, // token to query IN OUT PSID *ppUserSid // resultant user sid ) /*++ This function queries the access token specified by the hToken parameter, and returns an allocated copy of the TokenUser information on success. The access token specified by hToken must be opened for TOKEN_QUERY access. On success, the return value is TRUE. The caller is responsible for freeing the resultant UserSid via a call to MyFree(). On failure, the return value is FALSE. The caller does not need to free any buffer. --*/ { BYTE FastBuffer[256]; LPBYTE SlowBuffer = NULL; PTOKEN_USER ptgUser; DWORD cbBuffer; BOOL fSuccess = FALSE; *ppUserSid = NULL; // // try querying based on a fast stack based buffer first. // ptgUser = (PTOKEN_USER)FastBuffer; cbBuffer = sizeof(FastBuffer); fSuccess = GetTokenInformation( hToken, // identifies access token TokenUser, // TokenUser info type ptgUser, // retrieved info buffer cbBuffer, // size of buffer passed-in &cbBuffer // required buffer size ); if(!fSuccess) { if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) { // // try again with the specified buffer size // SlowBuffer = (LPBYTE)MyAlloc(cbBuffer); if(SlowBuffer != NULL) { ptgUser = (PTOKEN_USER)SlowBuffer; fSuccess = GetTokenInformation( hToken, // identifies access token TokenUser, // TokenUser info type ptgUser, // retrieved info buffer cbBuffer, // size of buffer passed-in &cbBuffer // required buffer size ); } } } // // if we got the token info successfully, copy the // relevant element for the caller. // if(fSuccess) { DWORD cbSid; // reset to assume failure fSuccess = FALSE; cbSid = GetLengthSid(ptgUser->User.Sid); *ppUserSid = MyAlloc( cbSid ); if(*ppUserSid != NULL) { fSuccess = CopySid(cbSid, *ppUserSid, ptgUser->User.Sid); } } if(!fSuccess) { if(*ppUserSid) { MyFree(*ppUserSid); *ppUserSid = NULL; } } if(SlowBuffer) MyFree(SlowBuffer); return fSuccess; } BOOL GetUserTextualSid( IN OUT LPWSTR lpBuffer, IN OUT LPDWORD nSize ) { HANDLE hToken; PSID pSidUser = NULL; BOOL fSuccess = FALSE; if(!OpenThreadToken( GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken )) { return FALSE; } fSuccess = GetTokenUserSid(hToken, &pSidUser); if(fSuccess) { // // obtain the textual representaion of the Sid // fSuccess = GetTextualSid( pSidUser, // user binary Sid lpBuffer, // buffer for TextualSid nSize // required/result buffer size in chars (including NULL) ); } if(pSidUser) MyFree(pSidUser); CloseHandle(hToken); return fSuccess; } BOOL GetTextualSid( IN PSID pSid, // binary Sid IN OUT LPWSTR TextualSid, // buffer for Textual representaion of Sid IN OUT LPDWORD dwBufferLen // required/provided TextualSid buffersize ) { PSID_IDENTIFIER_AUTHORITY psia; DWORD dwSubAuthorities; DWORD dwCounter; DWORD dwSidSize; if(!IsValidSid(pSid)) return FALSE; // obtain SidIdentifierAuthority psia = GetSidIdentifierAuthority(pSid); // obtain sidsubauthority count dwSubAuthorities = *GetSidSubAuthorityCount(pSid); // // compute buffer length (conservative guess) // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL // dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(WCHAR); // // check provided buffer length. // If not large enough, indicate proper size and setlasterror // if(*dwBufferLen < dwSidSize) { *dwBufferLen = dwSidSize; SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } // // prepare S-SID_REVISION- // dwSidSize = wsprintfW(TextualSid, L"S-%lu-", SID_REVISION ); // // prepare SidIdentifierAuthority // if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) { dwSidSize += wsprintfW(TextualSid + dwSidSize, L"0x%02hx%02hx%02hx%02hx%02hx%02hx", (USHORT)psia->Value[0], (USHORT)psia->Value[1], (USHORT)psia->Value[2], (USHORT)psia->Value[3], (USHORT)psia->Value[4], (USHORT)psia->Value[5]); } else { dwSidSize += wsprintfW(TextualSid + dwSidSize, L"%lu", (ULONG)(psia->Value[5] ) + (ULONG)(psia->Value[4] << 8) + (ULONG)(psia->Value[3] << 16) + (ULONG)(psia->Value[2] << 24) ); } // // loop through SidSubAuthorities // for (dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++) { dwSidSize += wsprintfW(TextualSid + dwSidSize, L"-%lu", *GetSidSubAuthority(pSid, dwCounter) ); } *dwBufferLen = dwSidSize + 1; // tell caller how many chars (include NULL) return TRUE; } void InitLsaString( PLSA_UNICODE_STRING LsaString, LPWSTR String ) { DWORD StringLength; if(String == NULL) { LsaString->Buffer = NULL; LsaString->Length = 0; LsaString->MaximumLength = 0; return; } StringLength = lstrlenW(String); LsaString->Buffer = String; LsaString->Length = (USHORT) StringLength * sizeof(WCHAR); LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR); } ULONG s_KeyrEnroll_V2 (/* [in] */ handle_t hRPCBinding, /* [in] */ BOOL fKeyService, /* [in] */ ULONG ulPurpose, /* [in] */ ULONG ulFlags, /* [in] */ PKEYSVC_UNICODE_STRING pAcctName, /* [in] */ PKEYSVC_UNICODE_STRING pCALocation, /* [in] */ PKEYSVC_UNICODE_STRING pCAName, /* [in] */ BOOL fNewKey, /* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW_V2 pKeyNew, /* [in] */ PKEYSVC_BLOB __RPC_FAR pCert, /* [in] */ PKEYSVC_CERT_REQUEST_PVK_NEW_V2 pRenewKey, /* [in] */ PKEYSVC_UNICODE_STRING pHashAlg, /* [in] */ PKEYSVC_UNICODE_STRING pDesStore, /* [in] */ ULONG ulStoreFlags, /* [in] */ PKEYSVC_CERT_ENROLL_INFO pRequestInfo, /* [in] */ ULONG ulReservedFlags, /* [out][in] */ PKEYSVC_BLOB __RPC_FAR *ppReserved, /* [out][in] */ PKEYSVC_BLOB __RPC_FAR *ppRequest, /* [out] */ PKEYSVC_BLOB __RPC_FAR *ppPKCS7Blob, /* [out] */ PKEYSVC_BLOB __RPC_FAR *ppHashBlob, /* [out] */ ULONG __RPC_FAR *pulStatus) { CERT_REQUEST_PVK_NEW KeyNew; CERT_REQUEST_PVK_NEW RenewKey; DWORD cbExtensions; PBYTE pbExtensions = NULL; PCERT_REQUEST_PVK_NEW pTmpRenewKey = NULL; PCERT_REQUEST_PVK_NEW pTmpKeyNew = NULL; LPWSTR pwszAcctName = NULL; LPWSTR pwszProv = NULL; LPWSTR pwszCont = NULL; LPWSTR pwszRenewProv = NULL; LPWSTR pwszRenewCont = NULL; LPWSTR pwszDesStore = NULL; LPWSTR pwszAttributes = NULL; LPWSTR pwszFriendly = NULL; LPWSTR pwszDescription = NULL; LPWSTR pwszUsage = NULL; LPWSTR pwszCALocation = NULL; LPWSTR pwszCertDNName = NULL; LPWSTR pwszCAName = NULL; LPWSTR pwszHashAlg = NULL; HANDLE hLogonToken = 0; HANDLE hProfile = 0; CERT_BLOB CertBlob; CERT_BLOB *pCertBlob = NULL; CERT_BLOB PKCS7Blob; CERT_BLOB HashBlob; CERT_ENROLL_INFO EnrollInfo; DWORD dwErr = 0; HANDLE hRequest = *ppRequest; KEYSVC_BLOB ReservedBlob; BOOL fCreateRequest = 0 == (ulFlags & (CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY)); BOOL fFreeRequest = 0 == (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY)); BOOL fSubmitRequest = 0 == (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY)); __try { ////////////////////////////////////////////////////////////// // // INITIALIZATION: // ////////////////////////////////////////////////////////////// memset(&KeyNew, 0, sizeof(KeyNew)); memset(&RenewKey, 0, sizeof(RenewKey)); memset(&EnrollInfo, 0, sizeof(EnrollInfo)); memset(&PKCS7Blob, 0, sizeof(PKCS7Blob)); memset(&HashBlob, 0, sizeof(HashBlob)); memset(&CertBlob, 0, sizeof(CertBlob)); memset(&ReservedBlob, 0, sizeof(ReservedBlob)); *ppPKCS7Blob = NULL; *ppHashBlob = NULL; ////////////////////////////////////////////////////////////// // // INPUT VALIDATION: // ////////////////////////////////////////////////////////////// BOOL fValidInput = TRUE; fValidInput &= fCreateRequest || fSubmitRequest || fFreeRequest; switch (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY)) { case CRYPTUI_WIZ_CREATE_ONLY: fValidInput &= NULL == *ppRequest; break; case CRYPTUI_WIZ_SUBMIT_ONLY: case CRYPTUI_WIZ_FREE_ONLY: fValidInput &= NULL != *ppRequest; break; case 0: default: ; } if (FALSE == fValidInput) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } ////////////////////////////////////////////////////////////// // // PROCEDURE BODY: // ////////////////////////////////////////////////////////////// // check if the client is an admin if (0 != (dwErr = CheckIfAdmin(hRPCBinding))) goto Ret; // if enrolling for a service account then need to logon and load profile if (0 != pAcctName->Length) { if (0 != (dwErr = AllocAndAssignString(pAcctName, &pwszAcctName))) goto Ret; if (0 != (dwErr = LogonToService(pwszAcctName, &hLogonToken, &hProfile))) goto Ret; } // assign all the values in the passed in structure to the // temporary structure KeyNew.dwSize = sizeof(CERT_REQUEST_PVK_NEW); KeyNew.dwProvType = pKeyNew->ulProvType; if (0 != (dwErr = AllocAndAssignString(&pKeyNew->Provider, &pwszProv))) goto Ret; KeyNew.pwszProvider = pwszProv; KeyNew.dwProviderFlags = pKeyNew->ulProviderFlags; if (0 != (dwErr = AllocAndAssignString(&pKeyNew->KeyContainer, &pwszCont))) goto Ret; KeyNew.pwszKeyContainer = pwszCont; KeyNew.dwKeySpec = pKeyNew->ulKeySpec; KeyNew.dwGenKeyFlags = pKeyNew->ulGenKeyFlags; KeyNew.dwEnrollmentFlags = pKeyNew->ulEnrollmentFlags; KeyNew.dwSubjectNameFlags = pKeyNew->ulSubjectNameFlags; KeyNew.dwPrivateKeyFlags = pKeyNew->ulPrivateKeyFlags; KeyNew.dwGeneralFlags = pKeyNew->ulGeneralFlags; pTmpKeyNew = &KeyNew; if (pCert->cb) { // if necessary assign the cert to be renewed values // temporary structure CertBlob.cbData = pCert->cb; CertBlob.pbData = pCert->pb; pCertBlob = &CertBlob; } if (CRYPTUI_WIZ_CERT_RENEW == ulPurpose) { // assign all the values in the passed in structure to the // temporary structure RenewKey.dwSize = sizeof(CERT_REQUEST_PVK_NEW); RenewKey.dwProvType = pRenewKey->ulProvType; if (0 != (dwErr = AllocAndAssignString(&pRenewKey->Provider, &pwszRenewProv))) goto Ret; RenewKey.pwszProvider = pwszRenewProv; RenewKey.dwProviderFlags = pRenewKey->ulProviderFlags; if (0 != (dwErr = AllocAndAssignString(&pRenewKey->KeyContainer, &pwszRenewCont))) goto Ret; RenewKey.pwszKeyContainer = pwszRenewCont; RenewKey.dwKeySpec = pRenewKey->ulKeySpec; RenewKey.dwGenKeyFlags = pRenewKey->ulGenKeyFlags; RenewKey.dwEnrollmentFlags = pRenewKey->ulEnrollmentFlags; RenewKey.dwSubjectNameFlags = pRenewKey->ulSubjectNameFlags; RenewKey.dwPrivateKeyFlags = pRenewKey->ulPrivateKeyFlags; RenewKey.dwGeneralFlags = pRenewKey->ulGeneralFlags; pTmpRenewKey = &RenewKey; } // For SUBMIT and FREE operations, hRequest is an IN parameter. if (0 != ((CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY) & ulFlags)) { memcpy(&hRequest, (*ppRequest)->pb, sizeof(hRequest)); } // check if the destination cert store was passed in if (0 != (dwErr = AllocAndAssignString(pDesStore, &pwszDesStore))) goto Ret; // copy over the request info EnrollInfo.dwSize = sizeof(EnrollInfo); if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->UsageOID, &pwszUsage))) goto Ret; EnrollInfo.pwszUsageOID = pwszUsage; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->CertDNName, &pwszCertDNName))) goto Ret; EnrollInfo.pwszCertDNName = pwszCertDNName; // cast the cert extensions EnrollInfo.dwExtensions = pRequestInfo->cExtensions; cbExtensions = (sizeof(CERT_EXTENSIONS)+sizeof(PCERT_EXTENSIONS)) * pRequestInfo->cExtensions; for (DWORD dwIndex = 0; dwIndex < pRequestInfo->cExtensions; dwIndex++) { cbExtensions += sizeof(CERT_EXTENSION) * pRequestInfo->prgExtensions[dwIndex]->cExtension; } EnrollInfo.prgExtensions = (PCERT_EXTENSIONS *)MyAlloc(cbExtensions); if (NULL == EnrollInfo.prgExtensions) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } pbExtensions = (PBYTE)(EnrollInfo.prgExtensions + EnrollInfo.dwExtensions); for (DWORD dwIndex = 0; dwIndex < EnrollInfo.dwExtensions; dwIndex++) { EnrollInfo.prgExtensions[dwIndex] = (PCERT_EXTENSIONS)pbExtensions; pbExtensions += sizeof(CERT_EXTENSIONS); EnrollInfo.prgExtensions[dwIndex]->cExtension = pRequestInfo->prgExtensions[dwIndex]->cExtension; EnrollInfo.prgExtensions[dwIndex]->rgExtension = (PCERT_EXTENSION)pbExtensions; pbExtensions += sizeof(CERT_EXTENSION) * EnrollInfo.prgExtensions[dwIndex]->cExtension; for (DWORD dwSubIndex = 0; dwSubIndex < EnrollInfo.prgExtensions[dwIndex]->cExtension; dwSubIndex++) { EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].pszObjId = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].pszObjId; EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].fCritical = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].fCritical; EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].Value.cbData = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].cbData; EnrollInfo.prgExtensions[dwIndex]->rgExtension[dwSubIndex].Value.pbData = pRequestInfo->prgExtensions[dwIndex]->rgExtension[dwSubIndex].pbData; } } EnrollInfo.dwPostOption = pRequestInfo->ulPostOption; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->FriendlyName, &pwszFriendly))) goto Ret; EnrollInfo.pwszFriendlyName = pwszFriendly; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->Description, &pwszDescription))) goto Ret; EnrollInfo.pwszDescription = pwszDescription; if (0 != (dwErr = AllocAndAssignString(&pRequestInfo->Attributes, &pwszAttributes))) goto Ret; if (0 != (dwErr = AllocAndAssignString(pHashAlg, &pwszHashAlg))) goto Ret; if (0 != (dwErr = AllocAndAssignString(pCALocation, &pwszCALocation))) goto Ret; if (0 != (dwErr = AllocAndAssignString(pCAName, &pwszCAName))) goto Ret; // call the local enrollment API __try { dwErr = LocalEnrollNoDS(ulFlags, pwszAttributes, NULL, fKeyService, ulPurpose, FALSE, 0, NULL, 0, pwszCALocation, pwszCAName, pCertBlob, pTmpRenewKey, fNewKey, pTmpKeyNew, pwszHashAlg, pwszDesStore, ulStoreFlags, &EnrollInfo, &PKCS7Blob, &HashBlob, pulStatus, &hRequest); } __except( EXCEPTION_EXECUTE_HANDLER ) { // TODO: convert to Winerror dwErr = GetExceptionCode(); } if( dwErr != 0 ) goto Ret; // Assign OUT parameters based on what kind of request we've just made. // Possible requests are: // // 1) CREATE only // Assign "ppRequest" to contain a HANDLE to the cert request. // 2) SUBMIT only // Assign "ppPKCS7Blob" and "ppHashBlob" to the values returned from LocalEnrollNoDS() // 3) FREE only // No need to assign OUT params. // 4) Complete (all 3). switch (ulFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY)) { case CRYPTUI_WIZ_CREATE_ONLY: // We've done the request creation portion of a 3-stage request, // assign the "request" out parameter now: if (NULL == (*ppRequest = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB)+ sizeof(hRequest)))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } (*ppRequest)->cb = sizeof(hRequest); (*ppRequest)->pb = (BYTE*)(*ppRequest) + sizeof(KEYSVC_BLOB); memcpy((*ppRequest)->pb, &hRequest, sizeof(hRequest)); break; case CRYPTUI_WIZ_SUBMIT_ONLY: case 0: // We've done the request submittal portion of a 3-stage request, // or we've done a 1-stage request. Assign the "certificate" out parameters now: // alloc and copy for the RPC out parameters if (NULL == (*ppPKCS7Blob = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB) + PKCS7Blob.cbData))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } (*ppPKCS7Blob)->cb = PKCS7Blob.cbData; (*ppPKCS7Blob)->pb = (BYTE*)(*ppPKCS7Blob) + sizeof(KEYSVC_BLOB); memcpy((*ppPKCS7Blob)->pb, PKCS7Blob.pbData, (*ppPKCS7Blob)->cb); if (NULL == (*ppHashBlob = (KEYSVC_BLOB*)MyAlloc(sizeof(KEYSVC_BLOB) + HashBlob.cbData))) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto Ret; } (*ppHashBlob)->cb = HashBlob.cbData; (*ppHashBlob)->pb = (BYTE*)(*ppHashBlob) + sizeof(KEYSVC_BLOB); memcpy((*ppHashBlob)->pb, HashBlob.pbData, (*ppHashBlob)->cb); break; case CRYPTUI_WIZ_FREE_ONLY: default: *ppRequest = NULL; break; } } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } Ret: __try { if (pwszAcctName) MyFree(pwszAcctName); if (pwszProv) MyFree(pwszProv); if (pwszCont) MyFree(pwszCont); if (pwszRenewProv) MyFree(pwszRenewProv); if (pwszRenewCont) MyFree(pwszRenewCont); if (pwszDesStore) MyFree(pwszDesStore); if (pwszAttributes) MyFree(pwszAttributes); if (pwszFriendly) MyFree(pwszFriendly); if (pwszDescription) MyFree(pwszDescription); if (pwszUsage) MyFree(pwszUsage); if (pwszCertDNName) MyFree(pwszCertDNName); if (pwszCAName) MyFree(pwszCAName); if (pwszCALocation) MyFree(pwszCALocation); if (pwszHashAlg) MyFree(pwszHashAlg); if (PKCS7Blob.pbData) { MyFree(PKCS7Blob.pbData); } if (HashBlob.pbData) { MyFree(HashBlob.pbData); } if (hLogonToken || hProfile) { LogoffService(&hLogonToken, &hProfile); } if (EnrollInfo.prgExtensions) MyFree(EnrollInfo.prgExtensions); } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; } return dwErr; } ULONG s_KeyrQueryRequestStatus (/* [in] */ handle_t hRPCBinding, /* [in] */ unsigned __int64 u64Request, /* [out, ref] */ KEYSVC_QUERY_CERT_REQUEST_INFO *pQueryInfo) { CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO QueryInfo; DWORD dwErr = 0; HANDLE hRequest = (HANDLE)u64Request; __try { // check if the client is an admin if (0 != (dwErr = CheckIfAdmin(hRPCBinding))) goto Ret; // We have the permission necessary to query the request. Proceed. ZeroMemory(&QueryInfo, sizeof(QueryInfo)); // Query the request. dwErr = LocalEnrollNoDS(CRYPTUI_WIZ_QUERY_ONLY, NULL, &QueryInfo, FALSE, 0, FALSE, NULL, NULL, 0, NULL, NULL, NULL, NULL, FALSE, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, &hRequest); if (ERROR_SUCCESS != dwErr) goto Ret; } __except ( EXCEPTION_EXECUTE_HANDLER ) { dwErr = ERROR_INVALID_PARAMETER; goto Ret; } pQueryInfo->ulSize = QueryInfo.dwSize; pQueryInfo->ulStatus = QueryInfo.dwStatus; Ret: return dwErr; } ULONG s_RKeyrPFXInstall (/* [in] */ handle_t hRPCBinding, /* [in] */ PKEYSVC_BLOB pPFX, /* [in] */ PKEYSVC_UNICODE_STRING pPassword, /* [in] */ ULONG ulFlags) { BOOL fIsImpersonatingClient = FALSE; CRYPT_DATA_BLOB PFXBlob; DWORD dwCertOpenStoreFlags; DWORD dwData; DWORD dwResult; HCERTSTORE hSrcStore = NULL; HCERTSTORE hCAStore = NULL; HCERTSTORE hMyStore = NULL; HCERTSTORE hRootStore = NULL; LPWSTR pwszPassword = NULL; PCCERT_CONTEXT pCertContext = NULL; struct Stores { HANDLE *phStore; LPCWSTR pwszStoreName; } rgStores[] = { { &hMyStore, L"my" }, { &hCAStore, L"ca" }, { &hRootStore, L"root" } }; __try { // Initialize locals: PFXBlob.cbData = pPFX->cb; PFXBlob.pbData = pPFX->pb; switch (ulFlags & (CRYPT_MACHINE_KEYSET | CRYPT_USER_KEYSET)) { case CRYPT_MACHINE_KEYSET: dwCertOpenStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE; break; case CRYPT_USER_KEYSET: // not supported default: dwResult = ERROR_INVALID_PARAMETER; goto error; } dwResult = RpcImpersonateClient(hRPCBinding); if (RPC_S_OK != dwResult) goto error; fIsImpersonatingClient = TRUE; if (ERROR_SUCCESS != (dwResult = AllocAndAssignString((PKEYSVC_UNICODE_STRING)pPassword, &pwszPassword))) goto error; // Get an in-memory store which contains all of the certs in the PFX // blob. if (NULL == (hSrcStore = PFXImportCertStore(&PFXBlob, pwszPassword, ulFlags))) { dwResult = GetLastError(); goto error; } // Open the stores we'll need: for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStores); dwIndex++) { *(rgStores[dwIndex].phStore) = CertOpenStore (CERT_STORE_PROV_SYSTEM_W, // store provider type PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, // cert encoding type NULL, // hCryptProv dwCertOpenStoreFlags, // open store flags rgStores[dwIndex].pwszStoreName // store name ); if (NULL == *(rgStores[dwIndex].phStore)) { dwResult = GetLastError(); goto error; } } // Enumerate the certs in the in-memory store, and add them to the local machine's // "my" store. NOTE: CertEnumCertificatesInStore frees the previous cert context // before returning the new context. while (NULL != (pCertContext = CertEnumCertificatesInStore(hSrcStore, pCertContext))) { HCERTSTORE hCertStore; // check if the certificate has the property on it // make sure the private key matches the certificate // search for both machine key and user keys if (CertGetCertificateContextProperty (pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwData) && CryptFindCertificateKeyProvInfo (pCertContext, 0, NULL)) { hCertStore = hMyStore; } else if (TrustIsCertificateSelfSigned (pCertContext, pCertContext->dwCertEncodingType, 0)) { hCertStore = hRootStore; } else { hCertStore = hCAStore; } if (!CertAddCertificateContextToStore (hCertStore, pCertContext, CERT_STORE_ADD_NEW, NULL)) { dwResult = GetLastError(); goto error; } } } __except (EXCEPTION_EXECUTE_HANDLER) { dwResult = GetExceptionCode(); goto error; } // We're done! dwResult = ERROR_SUCCESS; error: if (fIsImpersonatingClient) { RpcRevertToSelfEx(hRPCBinding); } if (NULL != hSrcStore) { CertCloseStore(hSrcStore, 0); } // Close all of the destination stores we've opened. for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStores); dwIndex++) if (NULL != *(rgStores[dwIndex].phStore)) CertCloseStore(*(rgStores[dwIndex].phStore), 0); if (NULL != pwszPassword) { MyFree(pwszPassword); } if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); } return dwResult; } ULONG s_RKeyrOpenKeyService( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_TYPE OwnerType, /* [in] */ PKEYSVC_UNICODE_STRING pOwnerName, /* [in] */ ULONG ulDesiredAccess, /* [in] */ PKEYSVC_BLOB pAuthentication, /* [in, out] */ PKEYSVC_BLOB *ppReserved, /* [out] */ KEYSVC_HANDLE *phKeySvc) { return s_KeyrOpenKeyService (hRPCBinding, OwnerType, pOwnerName, ulDesiredAccess, pAuthentication, ppReserved, phKeySvc); } ULONG s_RKeyrCloseKeyService( /* [in] */ handle_t hRPCBinding, /* [in] */ KEYSVC_HANDLE hKeySvc, /* [in, out] */ PKEYSVC_BLOB *ppReserved) { return s_KeyrCloseKeyService (hRPCBinding, hKeySvc, ppReserved); }