You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1800 lines
45 KiB
1800 lines
45 KiB
/*++
|
|
|
|
Copyright (c) 1996, 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
crypt32.cpp
|
|
|
|
Abstract:
|
|
|
|
This module contains routines associated with server side Crypt32
|
|
operations.
|
|
|
|
Author:
|
|
|
|
Scott Field (sfield) 14-Aug-97
|
|
|
|
--*/
|
|
|
|
#include <pch.cpp>
|
|
#pragma hdrstop
|
|
#include <msaudite.h>
|
|
|
|
|
|
|
|
#define SECURITY_WIN32
|
|
#include <security.h>
|
|
|
|
#define CRYPTPROTECT_SVR_VERSION_1 0x01
|
|
|
|
DWORD
|
|
CPSCreateServerContext(
|
|
PCRYPT_SERVER_CONTEXT pServerContext,
|
|
handle_t hBinding
|
|
);
|
|
|
|
DWORD
|
|
CPSDeleteServerContext(
|
|
PCRYPT_SERVER_CONTEXT pServerContext
|
|
);
|
|
|
|
|
|
|
|
|
|
GUID g_guidDefaultProvider = CRYPTPROTECT_DEFAULT_PROVIDER;
|
|
|
|
|
|
|
|
//
|
|
// routines to initialize and destroy server state associated with
|
|
// server callbacks and performance improvements.
|
|
//
|
|
|
|
DWORD
|
|
CPSCreateServerContext(
|
|
PCRYPT_SERVER_CONTEXT pServerContext,
|
|
handle_t hBinding
|
|
)
|
|
{
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
|
|
ZeroMemory( pServerContext, sizeof(CRYPT_SERVER_CONTEXT) );
|
|
|
|
pServerContext->cbSize = sizeof(CRYPT_SERVER_CONTEXT);
|
|
pServerContext->hBinding = hBinding;
|
|
|
|
pServerContext->fImpersonating = FALSE;
|
|
|
|
if(NULL != hBinding)
|
|
{
|
|
dwLastError = RpcImpersonateClient( hBinding );
|
|
if(ERROR_SUCCESS != dwLastError)
|
|
{
|
|
return dwLastError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Grab the thread token.
|
|
//
|
|
if(OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
|
|
TRUE,
|
|
&pServerContext->hToken
|
|
))
|
|
{
|
|
pServerContext->fImpersonating = (NULL == hBinding);
|
|
}
|
|
else
|
|
{
|
|
HANDLE hProcessToken = NULL;
|
|
if(OpenProcessToken(GetCurrentProcess(),
|
|
TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE,
|
|
&hProcessToken))
|
|
{
|
|
if(!DuplicateTokenEx(hProcessToken,
|
|
0,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenImpersonation,
|
|
&pServerContext->hToken))
|
|
{
|
|
dwLastError = GetLastError();
|
|
}
|
|
|
|
CloseHandle(hProcessToken);
|
|
}
|
|
else
|
|
{
|
|
dwLastError = GetLastError();
|
|
}
|
|
}
|
|
if(hBinding)
|
|
{
|
|
DWORD rc;
|
|
|
|
rc = RpcRevertToSelfEx( hBinding );
|
|
if (rc != RPC_S_OK)
|
|
{
|
|
if (ERROR_SUCCESS == dwLastError)
|
|
{
|
|
dwLastError = rc;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Is this call from one of the well-known accounts?
|
|
//
|
|
|
|
{
|
|
WCHAR szUserName[MAX_PATH + 1];
|
|
DWORD cchUserName = MAX_PATH;
|
|
|
|
if(GetUserTextualSid(
|
|
pServerContext->hToken,
|
|
szUserName,
|
|
&cchUserName))
|
|
{
|
|
if(lstrcmpW(szUserName, TEXTUAL_SID_LOCAL_SYSTEM) == 0)
|
|
{
|
|
pServerContext->WellKnownAccount = DP_ACCOUNT_LOCAL_SYSTEM;
|
|
}
|
|
else if(lstrcmpW(szUserName, TEXTUAL_SID_LOCAL_SERVICE) == 0)
|
|
{
|
|
pServerContext->WellKnownAccount = DP_ACCOUNT_LOCAL_SERVICE;
|
|
}
|
|
else if(lstrcmpW(szUserName, TEXTUAL_SID_NETWORK_SERVICE) == 0)
|
|
{
|
|
pServerContext->WellKnownAccount = DP_ACCOUNT_NETWORK_SERVICE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
DWORD
|
|
CPSDeleteServerContext(
|
|
PCRYPT_SERVER_CONTEXT pServerContext
|
|
)
|
|
{
|
|
if(pServerContext->szUserStorageArea)
|
|
{
|
|
SSFree(pServerContext->szUserStorageArea);
|
|
pServerContext->szUserStorageArea = NULL;
|
|
}
|
|
if(pServerContext->hToken)
|
|
{
|
|
CloseHandle(pServerContext->hToken);
|
|
}
|
|
|
|
|
|
if(pServerContext->cbSize == sizeof(CRYPT_SERVER_CONTEXT))
|
|
ZeroMemory( pServerContext, sizeof(CRYPT_SERVER_CONTEXT) );
|
|
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSDuplicateContext(
|
|
IN PVOID pvContext,
|
|
IN OUT PVOID *ppvDuplicateContext
|
|
)
|
|
/*++
|
|
|
|
Duplicate an outstanding server context so that a provider may defer
|
|
processing associated with the outstanding context until a later time.
|
|
|
|
This is used to support asynchronous operations on behalf of the caller
|
|
to the Data Protection API.
|
|
|
|
The caller MUST be impersonating the security context of the client user
|
|
prior to making this call.
|
|
|
|
--*/
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
PCRYPT_SERVER_CONTEXT pNewContext = NULL;
|
|
|
|
HANDLE hToken = NULL;
|
|
HANDLE hDuplicateToken;
|
|
BOOL fSuccess = FALSE;
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
|
|
if( pServerContext == NULL ||
|
|
pServerContext->cbSize != sizeof(CRYPT_SERVER_CONTEXT) ||
|
|
ppvDuplicateContext == NULL
|
|
) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
pNewContext = (PCRYPT_SERVER_CONTEXT)SSAlloc( sizeof( CRYPT_SERVER_CONTEXT ) );
|
|
if( pNewContext == NULL )
|
|
return ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
|
|
|
CopyMemory( pNewContext, pServerContext, sizeof(CRYPT_SERVER_CONTEXT) );
|
|
pNewContext->hBinding = NULL;
|
|
|
|
if(pServerContext->szUserStorageArea)
|
|
{
|
|
pNewContext->szUserStorageArea = (LPWSTR)SSAlloc((wcslen(pServerContext->szUserStorageArea)+1)*
|
|
sizeof(WCHAR));
|
|
if(NULL != pNewContext->szUserStorageArea)
|
|
{
|
|
wcscpy(pNewContext->szUserStorageArea, pServerContext->szUserStorageArea);
|
|
}
|
|
}
|
|
|
|
fSuccess = DuplicateTokenEx(pServerContext->hToken,
|
|
0,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenImpersonation,
|
|
&pNewContext->hToken);
|
|
|
|
if( !fSuccess )
|
|
{
|
|
dwLastError = GetLastError();
|
|
pNewContext->hToken = NULL;
|
|
|
|
CPSFreeContext( pNewContext );
|
|
} else {
|
|
*ppvDuplicateContext = pNewContext;
|
|
}
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSFreeContext(
|
|
IN PVOID pvDuplicateContext
|
|
)
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvDuplicateContext;
|
|
|
|
if( pServerContext == NULL ||
|
|
pServerContext->cbSize != sizeof(CRYPT_SERVER_CONTEXT)
|
|
) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if( pServerContext->hToken )
|
|
CloseHandle( pServerContext->hToken );
|
|
|
|
if(pServerContext->szUserStorageArea)
|
|
{
|
|
SSFree(pServerContext->szUserStorageArea);
|
|
pServerContext->szUserStorageArea = NULL;
|
|
}
|
|
|
|
ZeroMemory( pServerContext, sizeof(CRYPT_SERVER_CONTEXT) );
|
|
SSFree( pServerContext );
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSImpersonateClient(
|
|
IN PVOID pvContext
|
|
)
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
DWORD dwLastError = ERROR_INVALID_PARAMETER;
|
|
|
|
if( pvContext == NULL )
|
|
return ERROR_SUCCESS;
|
|
|
|
if( pServerContext->cbSize == sizeof(CRYPT_SERVER_CONTEXT) )
|
|
{
|
|
|
|
if( pServerContext->fOverrideToLocalSystem ||
|
|
(pServerContext->WellKnownAccount != 0))
|
|
{
|
|
if(ImpersonateSelf(SecurityImpersonation))
|
|
{
|
|
dwLastError = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
dwLastError = GetLastError();
|
|
D_DebugLog((DEB_WARN, "Failed ImpersonateSelf call: 0x%x\n", dwLastError));
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// duplicated server context has access token included; use it directly
|
|
//
|
|
|
|
if( pServerContext->hToken )
|
|
{
|
|
if(!SetThreadToken( NULL, pServerContext->hToken ))
|
|
{
|
|
dwLastError = GetLastError();
|
|
D_DebugLog((DEB_WARN, "Failed SetThreadToken call: 0x%x\n", dwLastError));
|
|
goto cleanup;
|
|
}
|
|
|
|
dwLastError = ERROR_SUCCESS;
|
|
goto cleanup;
|
|
}
|
|
if(pServerContext->hBinding)
|
|
{
|
|
dwLastError = RpcImpersonateClient( pServerContext->hBinding );
|
|
}
|
|
else
|
|
{
|
|
dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
#if DBG
|
|
if(NT_SUCCESS(dwLastError) && (DPAPIInfoLevel & DEB_TRACE))
|
|
{
|
|
BYTE rgbTemp[256];
|
|
PTOKEN_USER pUser = (PTOKEN_USER)rgbTemp;
|
|
DWORD cbRetInfo;
|
|
UNICODE_STRING ucsSid;
|
|
HANDLE hToken;
|
|
NTSTATUS Status;
|
|
|
|
Status = NtOpenThreadToken(NtCurrentThread(), TOKEN_QUERY, TRUE, &hToken);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
Status = NtQueryInformationToken(hToken,
|
|
TokenUser,
|
|
pUser,
|
|
256,
|
|
&cbRetInfo);
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
if(NT_SUCCESS(RtlConvertSidToUnicodeString(&ucsSid, pUser->User.Sid, TRUE)))
|
|
{
|
|
D_DebugLog((DEB_TRACE, "Impersonating user:%ls\n", ucsSid.Buffer));
|
|
RtlFreeUnicodeString(&ucsSid);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
D_DebugLog((DEB_ERROR, "Unable read user info: 0x%x\n", Status));
|
|
}
|
|
CloseHandle(hToken);
|
|
}
|
|
else
|
|
{
|
|
D_DebugLog((DEB_ERROR, "Unable to open thread token: 0x%x\n", Status));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if(!NT_SUCCESS(dwLastError))
|
|
{
|
|
D_DebugLog((DEB_WARN, "CPSImpersonateClient returned 0x%x\n", dwLastError));
|
|
}
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSRevertToSelf(
|
|
IN PVOID pvContext
|
|
)
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
DWORD dwLastError = ERROR_INVALID_PARAMETER;
|
|
|
|
if( pvContext == NULL )
|
|
return ERROR_SUCCESS;
|
|
|
|
if( pServerContext->cbSize == sizeof(CRYPT_SERVER_CONTEXT) ) {
|
|
|
|
if( pServerContext->fOverrideToLocalSystem || pServerContext->hToken ) {
|
|
|
|
if(RevertToSelf()) {
|
|
dwLastError = ERROR_SUCCESS;
|
|
} else {
|
|
dwLastError = GetLastError();
|
|
}
|
|
|
|
} else {
|
|
if(pServerContext->hBinding)
|
|
{
|
|
dwLastError = RpcRevertToSelfEx( pServerContext->hBinding );
|
|
}
|
|
else
|
|
{
|
|
dwLastError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSOverrideToLocalSystem(
|
|
IN PVOID pvContext,
|
|
IN BOOL *pfLocalSystem, // if non-null, new over ride BOOL
|
|
IN OUT BOOL *pfCurrentlyLocalSystem // if non-null, prior over ride BOOL
|
|
)
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
|
|
if( pServerContext == NULL ||
|
|
pServerContext->cbSize != sizeof(CRYPT_SERVER_CONTEXT)
|
|
) {
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if( pfCurrentlyLocalSystem )
|
|
*pfCurrentlyLocalSystem = pServerContext->fOverrideToLocalSystem;
|
|
|
|
if( pfLocalSystem )
|
|
pServerContext->fOverrideToLocalSystem = *pfLocalSystem;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSSetWellKnownAccount(
|
|
IN PVOID pvContext,
|
|
IN DWORD dwAccount)
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
|
|
if( pServerContext == NULL ||
|
|
pServerContext->cbSize != sizeof(CRYPT_SERVER_CONTEXT))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(dwAccount != pServerContext->WellKnownAccount)
|
|
{
|
|
// We're setting the context account to a new value,
|
|
// so NULL out the cached path string. A new one will be
|
|
// created automatically, as necessary.
|
|
if(pServerContext->szUserStorageArea)
|
|
{
|
|
SSFree(pServerContext->szUserStorageArea);
|
|
pServerContext->szUserStorageArea = NULL;
|
|
}
|
|
|
|
pServerContext->WellKnownAccount = dwAccount;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSQueryWellKnownAccount(
|
|
IN PVOID pvContext,
|
|
OUT DWORD *pdwAccount)
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
|
|
if( pServerContext == NULL ||
|
|
pServerContext->cbSize != sizeof(CRYPT_SERVER_CONTEXT))
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*pdwAccount = pServerContext->WellKnownAccount;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CPSDuplicateClientAccessToken(
|
|
IN PVOID pvContext, // server context
|
|
IN OUT HANDLE *phToken
|
|
)
|
|
{
|
|
HANDLE hToken = NULL;
|
|
HANDLE hDuplicateToken;
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
BOOL fSuccess;
|
|
|
|
*phToken = NULL;
|
|
|
|
//
|
|
// make a duplicate of the client access token.
|
|
//
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
|
|
if(!DuplicateTokenEx(pServerContext->hToken,
|
|
0,
|
|
NULL,
|
|
SecurityImpersonation,
|
|
TokenImpersonation,
|
|
&hDuplicateToken ))
|
|
{
|
|
dwLastError = GetLastError();
|
|
}
|
|
else
|
|
*phToken = hDuplicateToken;
|
|
|
|
return dwLastError;
|
|
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSGetUserName(
|
|
IN PVOID pvContext,
|
|
OUT LPWSTR *ppszUserName,
|
|
OUT DWORD *pcchUserName
|
|
)
|
|
{
|
|
WCHAR szBuf[MAX_PATH+1];
|
|
DWORD cchBuf = MAX_PATH;
|
|
DWORD dwLastError = ERROR_INVALID_PARAMETER;
|
|
BOOL fLocalMachine = FALSE;
|
|
BOOL fSuccess = FALSE;
|
|
DWORD dwAccount = 0;
|
|
|
|
|
|
//
|
|
// if we are currently over-riding to Local System, we know the values
|
|
// that need to be returned.
|
|
//
|
|
|
|
CPSOverrideToLocalSystem(
|
|
pvContext,
|
|
NULL, // don't change current over-ride BOOL
|
|
&fLocalMachine
|
|
);
|
|
|
|
CPSQueryWellKnownAccount(pvContext,
|
|
&dwAccount);
|
|
|
|
if( fLocalMachine || dwAccount == DP_ACCOUNT_LOCAL_SYSTEM)
|
|
{
|
|
static const WCHAR szName1[] = TEXTUAL_SID_LOCAL_SYSTEM;
|
|
CopyMemory( szBuf, szName1, sizeof(szName1) );
|
|
cchBuf = sizeof(szName1) / sizeof(WCHAR);
|
|
fSuccess = TRUE;
|
|
}
|
|
else if(dwAccount == DP_ACCOUNT_LOCAL_SERVICE)
|
|
{
|
|
static const WCHAR szName2[] = TEXTUAL_SID_LOCAL_SERVICE;
|
|
CopyMemory( szBuf, szName2, sizeof(szName2) );
|
|
cchBuf = sizeof(szName2) / sizeof(WCHAR);
|
|
fSuccess = TRUE;
|
|
}
|
|
else if(dwAccount == DP_ACCOUNT_NETWORK_SERVICE)
|
|
{
|
|
static const WCHAR szName3[] = TEXTUAL_SID_NETWORK_SERVICE;
|
|
CopyMemory( szBuf, szName3, sizeof(szName3) );
|
|
cchBuf = sizeof(szName3) / sizeof(WCHAR);
|
|
fSuccess = TRUE;
|
|
}
|
|
else
|
|
{
|
|
dwLastError = CPSImpersonateClient( pvContext );
|
|
if(dwLastError != ERROR_SUCCESS)
|
|
return dwLastError;
|
|
|
|
fSuccess = GetUserTextualSid(
|
|
NULL,
|
|
szBuf,
|
|
&cchBuf
|
|
);
|
|
|
|
CPSRevertToSelf( pvContext );
|
|
}
|
|
|
|
dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
if( fSuccess )
|
|
{
|
|
*ppszUserName = (LPWSTR)SSAlloc( cchBuf * sizeof(WCHAR));
|
|
|
|
if(*ppszUserName)
|
|
{
|
|
CopyMemory( *ppszUserName, szBuf, cchBuf * sizeof(WCHAR));
|
|
|
|
if(pcchUserName)
|
|
*pcchUserName = cchBuf;
|
|
|
|
dwLastError = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSGetDerivedCredential(
|
|
IN PVOID pvContext,
|
|
OUT GUID *pCredentialID,
|
|
IN DWORD dwFlags,
|
|
IN PBYTE pbMixingBytes,
|
|
IN DWORD cbMixingBytes,
|
|
IN OUT BYTE rgbDerivedCredential[A_SHA_DIGEST_LEN]
|
|
)
|
|
{
|
|
LUID LogonId;
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
|
|
|
|
if( pServerContext != NULL && pServerContext->cbSize != sizeof(CRYPT_SERVER_CONTEXT) )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
if( cbMixingBytes == 0 || pbMixingBytes == NULL )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
//
|
|
// impersonate the client and get the LogonId associated with the client.
|
|
//
|
|
|
|
dwLastError = CPSImpersonateClient( pvContext );
|
|
|
|
if( dwLastError != ERROR_SUCCESS )
|
|
return dwLastError;
|
|
|
|
if(!GetThreadAuthenticationId( GetCurrentThread(), &LogonId ))
|
|
{
|
|
dwLastError = GetLastError();
|
|
CPSRevertToSelf( pvContext ); // don't check error return since we're already failing
|
|
return dwLastError;
|
|
}
|
|
|
|
|
|
|
|
|
|
dwLastError = QueryDerivedCredential( pCredentialID,
|
|
&LogonId,
|
|
dwFlags,
|
|
pbMixingBytes,
|
|
cbMixingBytes,
|
|
rgbDerivedCredential );
|
|
|
|
|
|
CPSRevertToSelf( pvContext );
|
|
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSGetSystemCredential(
|
|
IN PVOID pvContext,
|
|
IN BOOL fLocalMachine,
|
|
IN OUT BYTE rgbSystemCredential[A_SHA_DIGEST_LEN]
|
|
)
|
|
{
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
|
|
if( pServerContext != NULL && pServerContext->cbSize != sizeof(CRYPT_SERVER_CONTEXT) )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
return GetSystemCredential( fLocalMachine, rgbSystemCredential);
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSCreateWorkerThread(
|
|
IN PVOID pThreadFunc,
|
|
IN PVOID pThreadArg
|
|
)
|
|
{
|
|
|
|
if( !QueueUserWorkItem(
|
|
(PTHREAD_START_ROUTINE)pThreadFunc,
|
|
pThreadArg,
|
|
WT_EXECUTELONGFUNCTION
|
|
)) {
|
|
|
|
return GetLastError();
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
DWORD CPSAudit(
|
|
IN HANDLE hToken,
|
|
IN DWORD dwAuditID,
|
|
IN LPCWSTR wszMasterKeyID,
|
|
IN LPCWSTR wszRecoveryServer,
|
|
IN DWORD dwReason,
|
|
IN LPCWSTR wszRecoveryKeyID,
|
|
IN DWORD dwFailure)
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
UNICODE_STRING MasterKeyID;
|
|
UNICODE_STRING RecoveryServer;
|
|
UNICODE_STRING RecoveryKeyID;
|
|
|
|
BOOL fReasonField = FALSE;
|
|
PSID UserSid = NULL;
|
|
|
|
|
|
fReasonField = ((SE_AUDITID_DPAPI_PROTECT == dwAuditID) ||
|
|
(SE_AUDITID_DPAPI_UNPROTECT == dwAuditID) ||
|
|
(SE_AUDITID_DPAPI_RECOVERY == dwAuditID));
|
|
|
|
GetTokenUserSid(hToken, &UserSid);
|
|
|
|
|
|
if(wszMasterKeyID)
|
|
{
|
|
RtlInitUnicodeString(&MasterKeyID, wszMasterKeyID);
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(&MasterKeyID, L"");
|
|
}
|
|
|
|
if(wszRecoveryServer)
|
|
{
|
|
RtlInitUnicodeString(&RecoveryServer, wszRecoveryServer);
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(&RecoveryServer, L"");
|
|
}
|
|
|
|
if(wszRecoveryKeyID)
|
|
{
|
|
RtlInitUnicodeString(&RecoveryKeyID, wszRecoveryKeyID);
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(&RecoveryKeyID, L"");
|
|
}
|
|
|
|
|
|
Status = LsaIAuditDPAPIEvent(
|
|
dwAuditID,
|
|
UserSid,
|
|
&MasterKeyID,
|
|
&RecoveryServer,
|
|
fReasonField ? &dwReason : NULL,
|
|
&RecoveryKeyID,
|
|
&dwFailure
|
|
);
|
|
if(UserSid)
|
|
{
|
|
SSFree(UserSid);
|
|
}
|
|
return (DWORD)Status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
CPSGetUserStorageArea(
|
|
IN PVOID pvContext,
|
|
IN PSID pSid, // optional
|
|
IN BOOL fCreate, // Create the storage area if it doesn't exist
|
|
IN OUT LPWSTR *ppszUserStorageArea
|
|
)
|
|
{
|
|
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
|
|
WCHAR szUserStorageRoot[MAX_PATH+1];
|
|
DWORD cbUserStorageRoot;
|
|
|
|
const WCHAR szProductString[] = L"\\Microsoft\\Protect\\";
|
|
DWORD cbProductString = sizeof(szProductString) - sizeof(WCHAR);
|
|
|
|
const WCHAR szUserStorageForSystem[] = L"\\User";
|
|
|
|
LPWSTR pszUser = NULL;
|
|
DWORD cbUser;
|
|
DWORD cchUser;
|
|
|
|
LPCWSTR szOptionalTrailing;
|
|
DWORD cbOptionalTrailing = 0;
|
|
|
|
BOOL fLocalMachine = FALSE;
|
|
DWORD dwAccount = 0;
|
|
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
PBYTE pbCurrent;
|
|
|
|
BOOL fImpersonated = FALSE;
|
|
|
|
DWORD dwLastError = ERROR_CANTOPEN;
|
|
|
|
*ppszUserStorageArea = NULL;
|
|
|
|
|
|
if(NULL == pServerContext)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
if(NULL == pSid)
|
|
{
|
|
|
|
//
|
|
// If this is the current users sid, check to see if we've already
|
|
// calculated this string.
|
|
|
|
if(NULL != pServerContext->szUserStorageArea)
|
|
{
|
|
*ppszUserStorageArea = (LPWSTR)SSAlloc((wcslen(pServerContext->szUserStorageArea)+1)*sizeof(WCHAR));
|
|
if(NULL == *ppszUserStorageArea)
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
wcscpy(*ppszUserStorageArea, pServerContext->szUserStorageArea);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// get the user name associated with the call.
|
|
// Note: this is the textual Sid on NT, and the user name on Win95.
|
|
//
|
|
|
|
|
|
dwLastError = CPSGetUserName( pvContext, &pszUser, &cchUser );
|
|
if(dwLastError != ERROR_SUCCESS)
|
|
goto cleanup;
|
|
|
|
cbUser = (cchUser-1) * sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
WCHAR wszTextualSid[MAX_PATH+1];
|
|
cchUser = MAX_PATH;
|
|
|
|
// Note that the number of characters returned from
|
|
// GetTextualSid includes the zero-terminator.
|
|
if(!GetTextualSid(pSid, wszTextualSid, &cchUser))
|
|
{
|
|
dwLastError = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
cbUser = (cchUser-1) * sizeof(WCHAR);
|
|
pszUser = (LPWSTR)SSAlloc(cchUser*sizeof(WCHAR));
|
|
if(NULL == pszUser)
|
|
{
|
|
dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
wcscpy(pszUser, wszTextualSid);
|
|
}
|
|
|
|
|
|
//
|
|
// impersonate the client user to test and create storage area if necessary
|
|
//
|
|
|
|
dwLastError = CPSImpersonateClient( pvContext );
|
|
|
|
if( dwLastError != ERROR_SUCCESS )
|
|
goto cleanup;
|
|
|
|
fImpersonated = TRUE;
|
|
|
|
|
|
//
|
|
// see if the call is for shared, CRYPT_PROTECT_LOCAL_MACHINE
|
|
// disposition.
|
|
//
|
|
|
|
CPSOverrideToLocalSystem(
|
|
pvContext,
|
|
NULL, // don't change current over-ride BOOL
|
|
&fLocalMachine
|
|
);
|
|
|
|
CPSQueryWellKnownAccount(
|
|
pvContext,
|
|
&dwAccount);
|
|
|
|
//
|
|
// determine path to per-user storage area, based on whether this
|
|
// is a local machine disposition call or a per-user disposition call.
|
|
//
|
|
|
|
|
|
if(fLocalMachine || (dwAccount != 0))
|
|
{
|
|
|
|
cbUserStorageRoot = GetSystemDirectoryW(
|
|
szUserStorageRoot,
|
|
sizeof(szUserStorageRoot) / sizeof(WCHAR)
|
|
);
|
|
|
|
cbUserStorageRoot *= sizeof(WCHAR);
|
|
|
|
//
|
|
// when the Sid is the SYSTEM sid, and this isn't a Local Machine
|
|
// disposition call, add a trailing component to the storage path.
|
|
//
|
|
|
|
if((dwAccount == DP_ACCOUNT_LOCAL_SYSTEM) && !fLocalMachine)
|
|
{
|
|
cbOptionalTrailing = sizeof(szUserStorageForSystem) - sizeof(WCHAR);
|
|
szOptionalTrailing = szUserStorageForSystem;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
dwLastError = PRGetProfilePath(NULL,
|
|
szUserStorageRoot );
|
|
|
|
if( dwLastError != ERROR_SUCCESS )
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
cbUserStorageRoot = lstrlenW( szUserStorageRoot ) * sizeof(WCHAR);
|
|
}
|
|
|
|
//
|
|
// an empty string is not legal as the root component of the per-user
|
|
// storage area.
|
|
//
|
|
|
|
if( cbUserStorageRoot == 0 )
|
|
{
|
|
dwLastError = ERROR_CANTOPEN;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// ensure returned string does not have trailing \
|
|
//
|
|
|
|
if( szUserStorageRoot[ (cbUserStorageRoot / sizeof(WCHAR)) - 1 ] == L'\\' )
|
|
{
|
|
szUserStorageRoot[ (cbUserStorageRoot / sizeof(WCHAR)) - 1 ] = L'\0';
|
|
cbUserStorageRoot -= sizeof(WCHAR);
|
|
}
|
|
|
|
|
|
*ppszUserStorageArea = (LPWSTR)SSAlloc(
|
|
cbUserStorageRoot +
|
|
cbProductString +
|
|
cbUser +
|
|
cbOptionalTrailing +
|
|
(2 * sizeof(WCHAR)) // trailing slash and NULL
|
|
);
|
|
|
|
if( *ppszUserStorageArea == NULL )
|
|
{
|
|
dwLastError = ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
pbCurrent = (PBYTE)*ppszUserStorageArea;
|
|
|
|
CopyMemory(pbCurrent, szUserStorageRoot, cbUserStorageRoot);
|
|
pbCurrent += cbUserStorageRoot;
|
|
|
|
CopyMemory(pbCurrent, szProductString, cbProductString);
|
|
pbCurrent += cbProductString;
|
|
|
|
CopyMemory(pbCurrent, pszUser, cbUser);
|
|
pbCurrent += cbUser; // note: cbUser does not include terminal NULL
|
|
|
|
if(cbOptionalTrailing)
|
|
{
|
|
CopyMemory(pbCurrent, szOptionalTrailing, cbOptionalTrailing);
|
|
pbCurrent += cbOptionalTrailing;
|
|
}
|
|
|
|
if( *((LPWSTR)pbCurrent - 1) != L'\\' )
|
|
{
|
|
*(LPWSTR)pbCurrent = L'\\';
|
|
pbCurrent += sizeof(WCHAR);
|
|
}
|
|
|
|
*(LPWSTR)pbCurrent = L'\0';
|
|
|
|
|
|
//
|
|
// test for well-known file in the storage area. if it exists,
|
|
// don't bother trying to create directory structure.
|
|
//
|
|
|
|
dwLastError = OpenFileInStorageArea(
|
|
NULL, // NULL == already impersonating the client
|
|
GENERIC_READ,
|
|
*ppszUserStorageArea,
|
|
REGVAL_PREFERRED_MK,
|
|
&hFile
|
|
);
|
|
|
|
if( dwLastError == ERROR_SUCCESS)
|
|
{
|
|
CloseHandle( hFile );
|
|
}
|
|
else
|
|
{
|
|
if(fCreate)
|
|
{
|
|
dwLastError = DPAPICreateNestedDirectories(
|
|
*ppszUserStorageArea,
|
|
(LPWSTR)((LPBYTE)*ppszUserStorageArea + cbUserStorageRoot + sizeof(WCHAR))
|
|
);
|
|
}
|
|
}
|
|
if((ERROR_SUCCESS == dwLastError) &&
|
|
(NULL == pSid))
|
|
{
|
|
pServerContext->szUserStorageArea = (LPWSTR)SSAlloc((wcslen(*ppszUserStorageArea)+1)*sizeof(WCHAR));
|
|
if(NULL == pServerContext->szUserStorageArea)
|
|
{
|
|
dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
else
|
|
{
|
|
wcscpy(pServerContext->szUserStorageArea, *ppszUserStorageArea);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if( fImpersonated )
|
|
CPSRevertToSelf( pvContext );
|
|
|
|
if(pszUser)
|
|
SSFree(pszUser);
|
|
|
|
if( dwLastError != ERROR_SUCCESS && *ppszUserStorageArea )
|
|
{
|
|
SSFree( *ppszUserStorageArea );
|
|
*ppszUserStorageArea = NULL;
|
|
}
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
|
|
#if 0
|
|
HKEY GetLMRegistryProviderKey()
|
|
{
|
|
HKEY hBaseKey = NULL;
|
|
DWORD dwCreate;
|
|
DWORD dwDesiredAccess = KEY_READ | KEY_WRITE;
|
|
|
|
static const WCHAR szKeyName[] = REG_CRYPTPROTECT_LOC L"\\" REG_CRYPTPROTECT_PROVIDERS_SUBKEYLOC;
|
|
|
|
|
|
// Open Key //
|
|
if (ERROR_SUCCESS !=
|
|
RegCreateKeyExU(
|
|
HKEY_LOCAL_MACHINE,
|
|
szKeyName,
|
|
0,
|
|
NULL, // address of class string
|
|
0,
|
|
dwDesiredAccess,
|
|
NULL,
|
|
&hBaseKey,
|
|
&dwCreate))
|
|
goto Ret;
|
|
|
|
Ret:
|
|
return hBaseKey;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
DWORD GetPolicyBits()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
// RPC-exposed functions
|
|
//
|
|
// these functions return a DWORD equivalent to GetLastError().
|
|
// the client side stub code will check if the return code is not
|
|
// ERROR_SUCCESS, and if this is the case, the client stub will return
|
|
// FALSE and SetLastError() to this DWORD.
|
|
//
|
|
|
|
DWORD
|
|
s_SSCryptProtectData(
|
|
handle_t h,
|
|
BYTE __RPC_FAR *__RPC_FAR *ppbOut,
|
|
DWORD __RPC_FAR *pcbOut,
|
|
BYTE __RPC_FAR *pbIn,
|
|
DWORD cbIn,
|
|
LPCWSTR szDataDescr,
|
|
BYTE* pbOptionalEntropy,
|
|
DWORD cbOptionalEntropy,
|
|
PSSCRYPTPROTECTDATA_PROMPTSTRUCT pPromptStruct,
|
|
DWORD dwFlags,
|
|
BYTE* pbOptionalPassword,
|
|
DWORD cbOptionalPassword
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
DWORD dwHeaderSize = sizeof(GUID)+sizeof(DWORD);
|
|
PBYTE pbWritePtr;
|
|
PBYTE pTemp;
|
|
|
|
CRYPT_SERVER_CONTEXT ServerContext;
|
|
|
|
// User mode cannot request encryption of system blobs
|
|
if(dwFlags & CRYPTPROTECT_SYSTEM)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Create a server context.
|
|
dwRet = CPSCreateServerContext(&ServerContext, h);
|
|
if(dwRet != ERROR_SUCCESS)
|
|
{
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
// get policy for this level
|
|
|
|
// UNDONE: what do policy bits allow an admin to set?
|
|
// maybe a recovery agent, other defaults?
|
|
GetPolicyBits();
|
|
|
|
|
|
dwRet = SPCryptProtect(
|
|
&ServerContext,
|
|
ppbOut,
|
|
pcbOut,
|
|
pbIn,
|
|
cbIn,
|
|
szDataDescr,
|
|
pbOptionalEntropy,
|
|
cbOptionalEntropy,
|
|
pPromptStruct,
|
|
dwFlags,
|
|
pbOptionalPassword, // following 2 fields considered temporary
|
|
cbOptionalPassword // until SAS UI supported
|
|
);
|
|
|
|
RtlSecureZeroMemory( pbIn, cbIn );
|
|
if ( dwRet != ERROR_SUCCESS || *ppbOut == NULL )
|
|
goto Ret;
|
|
|
|
// move entire block down, sneak header in
|
|
pTemp = (PBYTE)SSReAlloc(*ppbOut, *pcbOut + dwHeaderSize);
|
|
|
|
if(NULL == pTemp)
|
|
{
|
|
dwRet = ERROR_NOT_ENOUGH_MEMORY;
|
|
SSFree(*ppbOut);
|
|
*ppbOut = NULL;
|
|
*pcbOut = 0;
|
|
goto Ret;
|
|
}
|
|
|
|
*ppbOut = pTemp;
|
|
|
|
MoveMemory(*ppbOut + dwHeaderSize, *ppbOut, *pcbOut);
|
|
*pcbOut += dwHeaderSize;
|
|
|
|
pbWritePtr = *ppbOut;
|
|
*(DWORD*)pbWritePtr = CRYPTPROTECT_SVR_VERSION_1;
|
|
pbWritePtr += sizeof(DWORD);
|
|
|
|
CopyMemory(pbWritePtr, &g_guidDefaultProvider, sizeof(GUID));
|
|
pbWritePtr += sizeof(GUID);
|
|
|
|
dwRet = ERROR_SUCCESS;
|
|
|
|
|
|
Ret:
|
|
CPSDeleteServerContext( &ServerContext );
|
|
return dwRet;
|
|
}
|
|
|
|
DWORD
|
|
s_SSCryptUnprotectData(
|
|
handle_t h,
|
|
BYTE __RPC_FAR *__RPC_FAR *ppbOut,
|
|
DWORD __RPC_FAR *pcbOut,
|
|
BYTE __RPC_FAR *pbIn,
|
|
DWORD cbIn,
|
|
LPWSTR* ppszDataDescr,
|
|
BYTE* pbOptionalEntropy,
|
|
DWORD cbOptionalEntropy,
|
|
PSSCRYPTPROTECTDATA_PROMPTSTRUCT pPromptStruct,
|
|
DWORD dwFlags,
|
|
BYTE* pbOptionalPassword,
|
|
DWORD cbOptionalPassword
|
|
)
|
|
{
|
|
DWORD dwRet;
|
|
PBYTE pbReadPtr = pbIn;
|
|
GUID guidProvider;
|
|
CRYPT_SERVER_CONTEXT ServerContext;
|
|
|
|
// Zero output parameters.
|
|
*ppbOut = NULL;
|
|
*pcbOut = 0;
|
|
|
|
// User mode cannot request decryption of system blobs
|
|
if(dwFlags & CRYPTPROTECT_SYSTEM)
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Error out if input buffer is smaller than the minumum size.
|
|
if(cbIn < sizeof(DWORD) + sizeof(GUID))
|
|
{
|
|
return ERROR_INVALID_DATA;
|
|
}
|
|
|
|
// Create a server context.
|
|
dwRet = CPSCreateServerContext(&ServerContext, h);
|
|
if(dwRet != ERROR_SUCCESS)
|
|
{
|
|
return dwRet;
|
|
}
|
|
|
|
// UNDONE: what do policy bits allow an admin to set?
|
|
// maybe a recovery agent, other defaults?
|
|
GetPolicyBits();
|
|
|
|
if (*(DWORD*)pbReadPtr != CRYPTPROTECT_SVR_VERSION_1)
|
|
{
|
|
dwRet = ERROR_INVALID_DATA;
|
|
goto Ret;
|
|
}
|
|
pbReadPtr += sizeof(DWORD);
|
|
|
|
// next field in Data is provider GUID
|
|
CopyMemory(&guidProvider, pbReadPtr, sizeof(GUID));
|
|
pbReadPtr += sizeof(GUID);
|
|
|
|
dwRet = SPCryptUnprotect(
|
|
&ServerContext,
|
|
ppbOut,
|
|
pcbOut,
|
|
pbReadPtr,
|
|
(cbIn - (LONG)(pbReadPtr - pbIn)) , // eg (200 - (0x00340020 - 0x00340000))
|
|
ppszDataDescr,
|
|
pbOptionalEntropy,
|
|
cbOptionalEntropy,
|
|
pPromptStruct,
|
|
dwFlags,
|
|
pbOptionalPassword, // following 2 fields considered temporary
|
|
cbOptionalPassword // until SAS UI supported
|
|
);
|
|
|
|
RtlSecureZeroMemory( pbIn, cbIn );
|
|
|
|
if (dwRet != ERROR_SUCCESS)
|
|
goto Ret;
|
|
|
|
|
|
dwRet = ERROR_SUCCESS;
|
|
|
|
Ret:
|
|
|
|
CPSDeleteServerContext( &ServerContext );
|
|
return dwRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
LsaICryptProtectData(
|
|
IN PVOID DataIn,
|
|
IN ULONG DataInLength,
|
|
IN PUNICODE_STRING DataDescr,
|
|
IN PVOID OptionalEntropy,
|
|
IN ULONG OptionalEntropyLength,
|
|
IN PVOID Reserved,
|
|
IN PVOID Reserved2,
|
|
IN ULONG Flags,
|
|
OUT PVOID * DataOut,
|
|
OUT PULONG DataOutLength)
|
|
{
|
|
DWORD dwRetVal = ERROR_SUCCESS;
|
|
CRYPT_SERVER_CONTEXT ServerContext;;
|
|
|
|
DWORD dwHeaderSize = sizeof(GUID)+sizeof(DWORD);
|
|
PBYTE pbWritePtr;
|
|
PBYTE pTemp;
|
|
|
|
|
|
|
|
dwRetVal = CPSCreateServerContext(&ServerContext, NULL);
|
|
if(dwRetVal != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(dwRetVal);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
// check params
|
|
if ((DataOut == NULL) ||
|
|
(DataIn == NULL) ||
|
|
(NULL == DataDescr))
|
|
{
|
|
dwRetVal = ERROR_INVALID_PARAMETER;
|
|
goto error;
|
|
}
|
|
|
|
if(ServerContext.fImpersonating)
|
|
{
|
|
CPSRevertToSelf(&ServerContext);
|
|
}
|
|
|
|
|
|
// get policy for this level
|
|
|
|
// UNDONE: what do policy bits allow an admin to set?
|
|
// maybe a recovery agent, other defaults?
|
|
GetPolicyBits();
|
|
|
|
*DataOut = NULL;
|
|
*DataOutLength = 0;
|
|
|
|
dwRetVal = SPCryptProtect(
|
|
&ServerContext,
|
|
(PBYTE *)DataOut,
|
|
DataOutLength,
|
|
(PBYTE)DataIn,
|
|
DataInLength,
|
|
DataDescr?DataDescr->Buffer:NULL,
|
|
(PBYTE)OptionalEntropy,
|
|
OptionalEntropyLength,
|
|
NULL,
|
|
Flags,
|
|
NULL, // following 2 fields considered temporary
|
|
0 // until SAS UI supported
|
|
);
|
|
|
|
if ( dwRetVal != ERROR_SUCCESS || *DataOut == NULL )
|
|
goto error;
|
|
|
|
// move entire block down, sneak header in
|
|
pTemp =(PBYTE) SSReAlloc(*DataOut, *DataOutLength + dwHeaderSize);
|
|
if(NULL == pTemp)
|
|
{
|
|
dwRetVal = ERROR_NOT_ENOUGH_MEMORY;
|
|
SSFree(*DataOut);
|
|
*DataOut = NULL;
|
|
*DataOutLength = 0;
|
|
goto error;
|
|
}
|
|
|
|
*DataOut = pTemp;
|
|
|
|
MoveMemory((PBYTE)*DataOut + dwHeaderSize, *DataOut, *DataOutLength);
|
|
*DataOutLength += dwHeaderSize;
|
|
|
|
pbWritePtr = (PBYTE)*DataOut;
|
|
*(DWORD*)pbWritePtr = CRYPTPROTECT_SVR_VERSION_1;
|
|
pbWritePtr += sizeof(DWORD);
|
|
|
|
CopyMemory(pbWritePtr, &g_guidDefaultProvider, sizeof(GUID));
|
|
pbWritePtr += sizeof(GUID);
|
|
|
|
error:
|
|
if(ServerContext.fImpersonating)
|
|
{
|
|
CPSImpersonateClient(&ServerContext);
|
|
}
|
|
|
|
CPSDeleteServerContext( &ServerContext );
|
|
|
|
|
|
if(dwRetVal != ERROR_SUCCESS) {
|
|
SetLastError(dwRetVal);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
LsaICryptUnprotectData(
|
|
IN PVOID DataIn,
|
|
IN ULONG DataInLength,
|
|
IN PVOID OptionalEntropy,
|
|
IN ULONG OptionalEntropyLength,
|
|
IN PVOID Reserved,
|
|
IN PVOID Reserved2,
|
|
IN ULONG Flags,
|
|
OUT PUNICODE_STRING DataDescr,
|
|
OUT PVOID * DataOut,
|
|
OUT PULONG DataOutLength)
|
|
{
|
|
DWORD dwRetVal = ERROR_SUCCESS;
|
|
CRYPT_SERVER_CONTEXT ServerContext;;
|
|
|
|
DWORD dwHeaderSize = sizeof(GUID)+sizeof(DWORD);
|
|
PBYTE pbWritePtr;
|
|
LPWSTR wszDataDescr = NULL;
|
|
|
|
|
|
|
|
dwRetVal = CPSCreateServerContext(&ServerContext, NULL);
|
|
if(dwRetVal != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(dwRetVal);
|
|
return FALSE;
|
|
}
|
|
|
|
// check params
|
|
if ((DataOut == NULL) ||
|
|
(DataIn == NULL))
|
|
{
|
|
dwRetVal = ERROR_INVALID_PARAMETER;
|
|
goto error;
|
|
}
|
|
|
|
if(ServerContext.fImpersonating)
|
|
{
|
|
CPSRevertToSelf(&ServerContext);
|
|
}
|
|
|
|
|
|
// don't validate flags parameter
|
|
|
|
|
|
// get policy for this level
|
|
|
|
// UNDONE: what do policy bits allow an admin to set?
|
|
// maybe a recovery agent, other defaults?
|
|
GetPolicyBits();
|
|
|
|
|
|
//
|
|
// define outer+inner wrapper for security blob.
|
|
// this won't be necessary once SAS support is provided by the OS.
|
|
//
|
|
|
|
typedef struct {
|
|
DWORD dwOuterVersion;
|
|
GUID guidProvider;
|
|
|
|
DWORD dwVersion;
|
|
GUID guidMK;
|
|
DWORD dwPromptFlags;
|
|
DWORD cbDataDescr;
|
|
WCHAR szDataDescr[1];
|
|
} sec_blob, *psec_blob;
|
|
|
|
sec_blob *SecurityBlob = (sec_blob*)(DataIn);
|
|
|
|
|
|
//
|
|
// zero so client stub allocates
|
|
//
|
|
|
|
*DataOut = NULL;
|
|
*DataOutLength = 0;
|
|
|
|
|
|
//
|
|
// only call UI function if prompt flags dictate, because we don't
|
|
// want to bring in cryptui.dll unless necessary.
|
|
//
|
|
|
|
if( ((SecurityBlob->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) ||
|
|
(SecurityBlob->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT))
|
|
)
|
|
{
|
|
|
|
dwRetVal = ERROR_INVALID_PARAMETER;
|
|
goto error;
|
|
|
|
} else {
|
|
if(SecurityBlob->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
|
|
{
|
|
dwRetVal = ERROR_INVALID_PARAMETER;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
|
|
if (SecurityBlob->dwOuterVersion != CRYPTPROTECT_SVR_VERSION_1)
|
|
{
|
|
dwRetVal = ERROR_INVALID_DATA;
|
|
goto error;
|
|
}
|
|
|
|
if(0 != memcmp(&SecurityBlob->guidProvider, &g_guidDefaultProvider, sizeof(GUID)))
|
|
{
|
|
dwRetVal = ERROR_INVALID_DATA;
|
|
goto error;
|
|
}
|
|
|
|
Flags |= CRYPTPROTECT_IN_PROCESS;
|
|
|
|
dwRetVal = SPCryptUnprotect(
|
|
&ServerContext,
|
|
(PBYTE *)DataOut,
|
|
DataOutLength,
|
|
(PBYTE)DataIn + sizeof(DWORD) + sizeof(GUID),
|
|
(DataInLength - (LONG)(sizeof(DWORD) + sizeof(GUID))) ,
|
|
DataDescr?&wszDataDescr:NULL,
|
|
(PBYTE)OptionalEntropy,
|
|
OptionalEntropyLength,
|
|
NULL,
|
|
Flags,
|
|
NULL, // following 2 fields considered temporary
|
|
0 // until SAS UI supported
|
|
);
|
|
|
|
if (dwRetVal != ERROR_SUCCESS)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
if(NULL != DataDescr)
|
|
{
|
|
RtlInitUnicodeString(DataDescr, wszDataDescr);
|
|
}
|
|
|
|
|
|
error:
|
|
if(ServerContext.fImpersonating)
|
|
{
|
|
// Impersonate back to the impersonation context
|
|
CPSImpersonateClient(&ServerContext);
|
|
}
|
|
CPSDeleteServerContext( &ServerContext );
|
|
|
|
|
|
SetLastError(dwRetVal);
|
|
if(dwRetVal != ERROR_SUCCESS && dwRetVal != CRYPT_I_NEW_PROTECTION_REQUIRED ) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
CPSGetSidHistory(
|
|
IN PVOID pvContext,
|
|
OUT PSID **papsidHistory,
|
|
OUT DWORD *cpsidHistory
|
|
)
|
|
{
|
|
DWORD dwLastError = ERROR_SUCCESS;
|
|
BYTE FastBuffer[256];
|
|
BYTE GroupsFastBuffer[256];
|
|
LPBYTE SlowBuffer = NULL;
|
|
PTOKEN_USER ptgUser;
|
|
PTOKEN_GROUPS ptgGroups = NULL;
|
|
DWORD cbBuffer;
|
|
DWORD cbSid;
|
|
DWORD cSids = 0;
|
|
PBYTE pbCurrentSid = NULL;
|
|
DWORD i;
|
|
|
|
|
|
PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
|
|
|
|
|
|
//
|
|
// try querying based on a fast stack based buffer first.
|
|
//
|
|
|
|
ptgUser = (PTOKEN_USER)FastBuffer;
|
|
cbBuffer = sizeof(FastBuffer);
|
|
|
|
if(!GetTokenInformation(
|
|
pServerContext->hToken, // identifies access token
|
|
TokenUser, // TokenUser info type
|
|
ptgUser, // retrieved info buffer
|
|
cbBuffer, // size of buffer passed-in
|
|
&cbBuffer // required buffer size
|
|
))
|
|
{
|
|
dwLastError = GetLastError();
|
|
|
|
if(dwLastError != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
//
|
|
// try again with the specified buffer size
|
|
//
|
|
|
|
ptgUser = (PTOKEN_USER)SSAlloc(cbBuffer);
|
|
if(NULL == ptgUser)
|
|
{
|
|
dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
|
|
|
|
|
|
if(!GetTokenInformation(
|
|
pServerContext->hToken, // identifies access token
|
|
TokenUser, // TokenUser info type
|
|
ptgUser, // retrieved info buffer
|
|
cbBuffer, // size of buffer passed-in
|
|
&cbBuffer // required buffer size
|
|
))
|
|
{
|
|
dwLastError = GetLastError();
|
|
goto error;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// try querying based on a fast stack based buffer first.
|
|
//
|
|
|
|
ptgGroups = (PTOKEN_GROUPS)GroupsFastBuffer;
|
|
cbBuffer = sizeof(GroupsFastBuffer);
|
|
|
|
if(!GetTokenInformation(
|
|
pServerContext->hToken, // identifies access token
|
|
TokenGroups, // TokenUser info type
|
|
ptgGroups, // retrieved info buffer
|
|
cbBuffer, // size of buffer passed-in
|
|
&cbBuffer // required buffer size
|
|
))
|
|
{
|
|
dwLastError = GetLastError();
|
|
|
|
if(dwLastError != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
goto error;
|
|
}
|
|
dwLastError = ERROR_SUCCESS;
|
|
|
|
//
|
|
// try again with the specified buffer size
|
|
//
|
|
|
|
ptgGroups = (PTOKEN_GROUPS)SSAlloc(cbBuffer);
|
|
if(NULL == ptgGroups)
|
|
{
|
|
dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
|
|
|
|
|
|
if(!GetTokenInformation(
|
|
pServerContext->hToken, // identifies access token
|
|
TokenGroups, // TokenUser info type
|
|
ptgGroups, // retrieved info buffer
|
|
cbBuffer, // size of buffer passed-in
|
|
&cbBuffer // required buffer size
|
|
))
|
|
{
|
|
dwLastError = GetLastError();
|
|
goto error;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// if we got the token info successfully, copy the
|
|
// relevant element for the caller.
|
|
//
|
|
|
|
cbSid = GetLengthSid(ptgUser->User.Sid);
|
|
cSids = 1;
|
|
|
|
for(i=0; i < ptgGroups->GroupCount; i++)
|
|
{
|
|
if(0 == (SE_GROUP_ENABLED & ptgGroups->Groups[i].Attributes))
|
|
{
|
|
continue;
|
|
}
|
|
if(0 == ((SE_GROUP_OWNER | SE_GROUP_USE_FOR_DENY_ONLY) & ptgGroups->Groups[i].Attributes))
|
|
{
|
|
continue;
|
|
}
|
|
cbSid += GetLengthSid(ptgGroups->Groups[i].Sid);
|
|
cSids ++;
|
|
|
|
}
|
|
|
|
|
|
*cpsidHistory = cSids;
|
|
*papsidHistory = (PSID *)SSAlloc(cSids*sizeof(PSID) + cbSid );
|
|
|
|
if(*papsidHistory == NULL)
|
|
{
|
|
dwLastError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto error;
|
|
}
|
|
else
|
|
{
|
|
pbCurrentSid = (PBYTE)((*papsidHistory)+cSids);
|
|
|
|
// Fill in the primary user SID
|
|
(*papsidHistory)[0] = (PSID)pbCurrentSid;
|
|
cbSid = GetLengthSid(ptgUser->User.Sid);
|
|
CopySid(cbSid, pbCurrentSid, ptgUser->User.Sid);
|
|
pbCurrentSid += cbSid;
|
|
|
|
cSids = 1;
|
|
|
|
// Fill in the rest of the SIDs
|
|
for(i=0; i < ptgGroups->GroupCount; i++)
|
|
{
|
|
if(0 == (SE_GROUP_ENABLED & ptgGroups->Groups[i].Attributes))
|
|
{
|
|
continue;
|
|
}
|
|
if(0 == ((SE_GROUP_OWNER | SE_GROUP_USE_FOR_DENY_ONLY) & ptgGroups->Groups[i].Attributes))
|
|
{
|
|
continue;
|
|
}
|
|
(*papsidHistory)[cSids++] = pbCurrentSid;
|
|
cbSid = GetLengthSid(ptgGroups->Groups[i].Sid);
|
|
CopySid(cbSid, pbCurrentSid,ptgGroups->Groups[i].Sid);
|
|
pbCurrentSid += cbSid;
|
|
}
|
|
}
|
|
|
|
|
|
error:
|
|
|
|
if(FastBuffer != (PBYTE)ptgUser)
|
|
{
|
|
SSFree(ptgUser);
|
|
}
|
|
|
|
if(GroupsFastBuffer != (PBYTE)ptgGroups)
|
|
{
|
|
SSFree(ptgGroups);
|
|
}
|
|
|
|
|
|
return dwLastError;
|
|
}
|
|
|
|
|