mirror of https://github.com/lianthony/NT4.0
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.
4198 lines
115 KiB
4198 lines
115 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
stub.c
|
|
|
|
Abstract:
|
|
|
|
NT LM Security Support Provider client stubs.
|
|
|
|
Author:
|
|
|
|
Cliff Van Dyke (CliffV) 29-Jun-1993
|
|
|
|
Environment: User Mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include <msnssph.h>
|
|
#include <stdlib.h>
|
|
|
|
CRITICAL_SECTION g_EcbCritSection;
|
|
extern CRITICAL_SECTION g_LoadLibCritSection;
|
|
HINSTANCE hInstanceDLL;
|
|
int Mutex;
|
|
STRING SspGlobalComputerName;
|
|
TCHAR ComputerNameBuffer[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD g_dwPlatform;
|
|
|
|
extern LONG fNotInitBmp;
|
|
|
|
#ifndef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
BOOL fInited = FALSE;
|
|
#endif // ENDIF FOR_SSPS
|
|
|
|
#ifdef INTERNAL_SSP
|
|
void FitTo14(char *sz);
|
|
#endif // INTERNAL_SSP
|
|
|
|
BOOL
|
|
SspSetDefaultUser(
|
|
PSSP_CREDENTIAL
|
|
);
|
|
|
|
BOOL
|
|
SspGetUserInfo(
|
|
PSSP_CREDENTIAL
|
|
);
|
|
|
|
#if 0 // commented out
|
|
VOID
|
|
SspCreateSspiReg(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SspCreateSpmReg(
|
|
VOID
|
|
);
|
|
#endif // commented out
|
|
|
|
#ifndef FOR_SSPS // IF NOT PART OF MSNSSPS.DLL
|
|
|
|
static SecurityFunctionTableA FunctionTableA =
|
|
{
|
|
SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
|
|
EnumerateSecurityPackagesA,
|
|
0, // QueryCredentialsAttributes
|
|
AcquireCredentialsHandleA,
|
|
FreeCredentialsHandle,
|
|
0,
|
|
InitializeSecurityContextA,
|
|
0,
|
|
CompleteAuthToken,
|
|
DeleteSecurityContext,
|
|
ApplyControlToken,
|
|
QueryContextAttributesA,
|
|
0,
|
|
0,
|
|
MakeSignature,
|
|
VerifySignature,
|
|
FreeContextBuffer,
|
|
QuerySecurityPackageInfoA,
|
|
SealMessage,
|
|
UnsealMessage
|
|
};
|
|
|
|
static SecurityFunctionTableW FunctionTableW =
|
|
{
|
|
SECURITY_SUPPORT_PROVIDER_INTERFACE_VERSION,
|
|
EnumerateSecurityPackagesW,
|
|
0, // QueryCredentialsAttributes
|
|
AcquireCredentialsHandleW,
|
|
FreeCredentialsHandle,
|
|
0,
|
|
InitializeSecurityContextW,
|
|
0,
|
|
CompleteAuthToken,
|
|
DeleteSecurityContext,
|
|
ApplyControlToken,
|
|
QueryContextAttributesW,
|
|
0,
|
|
0,
|
|
MakeSignature,
|
|
VerifySignature,
|
|
FreeContextBuffer,
|
|
QuerySecurityPackageInfoW,
|
|
SealMessage,
|
|
UnsealMessage
|
|
};
|
|
|
|
#endif // not FOR_SSPS (NOT PART OF MSNSSPS.DLL)
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: InitClientMSNSsp()
|
|
//
|
|
// Synopsis: This function performs initialization for the client
|
|
// MSN SSP DLL
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: TRUE is successfully. Otherwise FALSE is returned.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL
|
|
InitClientMSNSsp (
|
|
VOID
|
|
)
|
|
{
|
|
DWORD NameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
OSVERSIONINFO VerInfo;
|
|
|
|
//
|
|
// Find out which plateform are we running
|
|
//
|
|
VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
|
if (!GetVersionEx (&VerInfo)) // If this fails, something gone wrong
|
|
{
|
|
SspPrint(( SSP_API, "InitClientMSNSsp: GetVersionEx() failed\n" ));
|
|
return (0);
|
|
}
|
|
|
|
if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ||
|
|
VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
{
|
|
g_dwPlatform = VerInfo.dwPlatformId;
|
|
}
|
|
else
|
|
{
|
|
SspPrint(( SSP_API, "InitClientMSNSsp: Unsupported Platform %d\n",
|
|
VerInfo.dwPlatformId ));
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Retrieve and store computer name in SspGlobalComputerName
|
|
//
|
|
|
|
SspGlobalComputerName.Buffer = ComputerNameBuffer;
|
|
SspGlobalComputerName.MaximumLength = sizeof(ComputerNameBuffer);
|
|
|
|
if ( !GetComputerName( SspGlobalComputerName.Buffer, &NameLength ) ) {
|
|
return(0);
|
|
}
|
|
|
|
SspGlobalComputerName.Length = (USHORT) NameLength * sizeof(TCHAR);
|
|
CharUpper( SspGlobalComputerName.Buffer );
|
|
|
|
// Initialize all Critical Sections, for DES_ECB_* function
|
|
// and for referencing dynamically loaded library
|
|
InitializeCriticalSection(&g_EcbCritSection);
|
|
|
|
InitializeCriticalSection(&g_LoadLibCritSection);
|
|
|
|
return (1);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CleanupClientMSNSsp()
|
|
//
|
|
// Synopsis: This function performs cleanup for the client MSN SSP DLL
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: 1 - no errors.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
CleanupClientMSNSsp (
|
|
VOID
|
|
)
|
|
{
|
|
MsnSspClosePwdCache ();
|
|
|
|
// Delete Critical Section for DES_ECB_* function
|
|
DeleteCriticalSection(&g_EcbCritSection);
|
|
|
|
DeleteCriticalSection(&g_LoadLibCritSection);
|
|
|
|
if (fNotInitBmp < 1)
|
|
{
|
|
//
|
|
// Cleanup the "BmpCC" class which is used for MSN UI dialog
|
|
//
|
|
FUnInitBmpCC (hInstanceDLL);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
#ifndef FOR_SSPS // IF NOT PART OF MSNSSPS.DLL
|
|
|
|
int FAR PASCAL LibMain (
|
|
HANDLE hInstance,
|
|
WORD wDataSeg,
|
|
WORD wHeapSize,
|
|
LPSTR lpszCmdLine
|
|
)
|
|
{
|
|
|
|
hInstanceDLL = hInstance;
|
|
|
|
Mutex = 0;
|
|
|
|
|
|
return (1);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: ProcAttach()
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: 1 - Ignore errors.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int ProcAttach()
|
|
{
|
|
|
|
if (!fInited) {
|
|
|
|
#if 0 // commented out
|
|
//
|
|
// Create SSPI and SPM registry entry
|
|
//
|
|
SspCreateSspiReg();
|
|
SspCreateSpmReg();
|
|
#endif // commented out
|
|
|
|
if (!InitClientMSNSsp ())
|
|
return (0);
|
|
|
|
fInited = TRUE;
|
|
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: ProcDetach()
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: None
|
|
//
|
|
// Returns: 1 - Ignore errors.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
int ProcDetach()
|
|
{
|
|
UCHAR lpszLsaDLL[] = TEXT("advapi32.dll");
|
|
|
|
CleanupClientMSNSsp ();
|
|
return(1);
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DllMain
|
|
//
|
|
// Synopsis: Initialize state for rascm.dll
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 5/16/95 SudK Created.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
BOOL WINAPI DllMain(
|
|
HANDLE hInstance,
|
|
ULONG dwReason,
|
|
void * lpReserved)
|
|
{
|
|
switch (dwReason)
|
|
{
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
//
|
|
// We are not interested in DLL_THREAD_ATTACH/DETACH notifications
|
|
//
|
|
DisableThreadLibraryCalls ( (HMODULE)hInstance );
|
|
if (hInstanceDLL != hInstance)
|
|
hInstanceDLL = hInstance;
|
|
return ( ProcAttach() );
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
return( ProcDetach() );
|
|
|
|
default:
|
|
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
#endif // not FOR_SSPS (NOT PART OF MSNSSPS.DLL)
|
|
|
|
|
|
BOOLEAN
|
|
SspGetWorkstation(
|
|
PSSP_CREDENTIAL pCredential
|
|
)
|
|
{
|
|
pCredential->Workstation =
|
|
(PCHAR) SspAlloc(SspGlobalComputerName.Length + sizeof(TCHAR));
|
|
if (pCredential->Workstation == NULL)
|
|
return(FALSE);
|
|
|
|
strcpy(pCredential->Workstation, SspGlobalComputerName.Buffer);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
#ifndef FOR_SSPS // IF NOT PART OF MSNSSPS.DLL
|
|
|
|
PSecurityFunctionTableA SEC_ENTRY
|
|
InitSecurityInterfaceA(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC calls this function to get the addresses of all the other functions
|
|
that it might call.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A pointer to our static SecurityFunctionTable. The caller need
|
|
not deallocate this table.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD NameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
OSVERSIONINFO VerInfo;
|
|
|
|
MsnSspInitPwdCache();
|
|
|
|
if (!fInited) {
|
|
|
|
//
|
|
// Find out which plateform are we running
|
|
//
|
|
VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
|
if (!GetVersionEx (&VerInfo)) // If this fails, something gone wrong
|
|
{
|
|
SspPrint(( SSP_API, "ProcAttach: GetVersionEx() failed\n" ));
|
|
return (NULL);
|
|
}
|
|
|
|
if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ||
|
|
VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
{
|
|
g_dwPlatform = VerInfo.dwPlatformId;
|
|
}
|
|
else
|
|
{
|
|
SspPrint(( SSP_API, "ProcAttach: Unsupported Platform %d\n",
|
|
VerInfo.dwPlatformId ));
|
|
return (NULL);
|
|
}
|
|
|
|
//
|
|
// Retrieve and store computer name in SspGlobalComputerName
|
|
//
|
|
|
|
SspGlobalComputerName.Buffer = ComputerNameBuffer;
|
|
SspGlobalComputerName.MaximumLength = sizeof(ComputerNameBuffer);
|
|
|
|
if ( !GetComputerName( SspGlobalComputerName.Buffer, &NameLength ) ) {
|
|
return(NULL);
|
|
}
|
|
|
|
SspGlobalComputerName.Length = (USHORT) NameLength * sizeof(TCHAR);
|
|
CharUpper( SspGlobalComputerName.Buffer );
|
|
|
|
// Initialize all Critical Sections, for DES_ECB_* function
|
|
// and for referencing dynamically loaded library
|
|
InitializeCriticalSection(&g_EcbCritSection);
|
|
|
|
InitializeCriticalSection(&g_LoadLibCritSection);
|
|
|
|
fInited = TRUE;
|
|
|
|
}
|
|
|
|
return &FunctionTableA;
|
|
}
|
|
|
|
|
|
|
|
PSecurityFunctionTableW SEC_ENTRY
|
|
InitSecurityInterfaceW(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
RPC calls this function to get the addresses of all the other functions
|
|
that it might call.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
A pointer to our static SecurityFunctionTable. The caller need
|
|
not deallocate this table.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD NameLength = MAX_COMPUTERNAME_LENGTH + 1;
|
|
OSVERSIONINFO VerInfo;
|
|
|
|
MsnSspInitPwdCache();
|
|
|
|
if (!fInited) {
|
|
|
|
//
|
|
// Find out which plateform are we running
|
|
//
|
|
VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
|
|
if (!GetVersionEx (&VerInfo)) // If this fails, something gone wrong
|
|
{
|
|
SspPrint(( SSP_API, "ProcAttach: GetVersionEx() failed\n" ));
|
|
return (0);
|
|
}
|
|
|
|
if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ||
|
|
VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
{
|
|
g_dwPlatform = VerInfo.dwPlatformId;
|
|
}
|
|
else
|
|
{
|
|
SspPrint(( SSP_API, "ProcAttach: Unsupported Platform %d\n",
|
|
VerInfo.dwPlatformId ));
|
|
return (0);
|
|
}
|
|
|
|
//
|
|
// Retrieve and store computer name in SspGlobalComputerName
|
|
//
|
|
|
|
SspGlobalComputerName.Buffer = ComputerNameBuffer;
|
|
SspGlobalComputerName.MaximumLength = sizeof(ComputerNameBuffer);
|
|
|
|
if ( !GetComputerName( SspGlobalComputerName.Buffer, &NameLength ) ) {
|
|
return(NULL);
|
|
}
|
|
|
|
SspGlobalComputerName.Length = (USHORT) NameLength * sizeof(TCHAR);
|
|
CharUpper( SspGlobalComputerName.Buffer );
|
|
|
|
// Initialize all Critical Sections, for DES_ECB_* function
|
|
// and for referencing dynamically loaded library
|
|
InitializeCriticalSection(&g_EcbCritSection);
|
|
|
|
InitializeCriticalSection(&g_LoadLibCritSection);
|
|
|
|
fInited = TRUE;
|
|
|
|
}
|
|
|
|
return &FunctionTableW;
|
|
}
|
|
|
|
#endif // not FOR_SSPS (NOT PART OF MSNSSPS.DLL)
|
|
|
|
|
|
#ifndef INTERNAL_SSP // IF NOT PART OF INTERNAL MSNSSPS.DLL for DATACENTER
|
|
// This should eventually be moved to siclib.
|
|
void FitTo14(char *sz)
|
|
{
|
|
// lstrlen(sz) will be <= 14 when the function returns
|
|
|
|
int num;
|
|
int i = 0;
|
|
int len = 0;
|
|
|
|
if (!sz || (len = lstrlen(sz)) <= 14)
|
|
return;
|
|
|
|
// distribute the 7 least significant bits of the 15th char
|
|
// into the most significant bits of the first 7 chars
|
|
for (num = sz[14] << 1; i < 7; i++, num = num << 1)
|
|
sz[i] = (sz[i] & 0x7f) | (num & 0x80);
|
|
|
|
// distribute the 7 least significant bits of the 16th char
|
|
// into the most significant bits of the chars 7 thru 13
|
|
if (len > 15) {
|
|
for (num = sz[15] << 1; i < 14; i++, num = num << 1)
|
|
sz[i] = (sz[i] & 0x7f) | (num & 0x80);
|
|
}
|
|
|
|
sz[14] = '\0'; // Put an end of string after 14th char
|
|
}
|
|
#endif // NOT PART OF INTERNAL MSNSSPS.DLL for DATACENTER
|
|
|
|
|
|
SECURITY_STATUS
|
|
SetCredentialsFromAuthDataA(
|
|
IN PVOID AuthData,
|
|
PSSP_CREDENTIAL Credential
|
|
)
|
|
{
|
|
SEC_WINNT_AUTH_IDENTITY_A *Identity = (SEC_WINNT_AUTH_IDENTITY_A *)AuthData;
|
|
char TmpText[AC_MAX_PASSWORD_LENGTH+4];
|
|
int Length;
|
|
int i;
|
|
|
|
if (Identity->User == NULL || Identity->Domain == NULL) {
|
|
return SEC_E_UNKNOWN_CREDENTIALS;
|
|
}
|
|
|
|
if (strlen((char *)Identity->User) > MAX_USERNAME_LENGTH)
|
|
return(SEC_E_UNKNOWN_CREDENTIALS);
|
|
|
|
Credential->Username = NULL;
|
|
Credential->Domain = NULL;
|
|
Credential->Password = NULL;
|
|
Credential->Workstation = NULL;
|
|
|
|
Credential->Username = (char *)SspAlloc(strlen((PCHAR)Identity->User) + 1);
|
|
if (Credential->Username == NULL) {
|
|
goto failure;
|
|
}
|
|
strcpy(Credential->Username, (PCHAR)Identity->User);
|
|
|
|
Credential->Domain = (char *)SspAlloc(strlen((PCHAR)Identity->Domain) + 1);
|
|
if (Credential->Domain == NULL) {
|
|
goto failure;
|
|
}
|
|
strcpy(Credential->Domain, (PCHAR)Identity->Domain);
|
|
|
|
// If netbios won't tell us the workstation name, make one up.
|
|
if (!SspGetWorkstation(Credential)) {
|
|
Credential->Workstation = (char *)SspAlloc(strlen("none") + 1);
|
|
if (Credential->Workstation == NULL) {
|
|
goto failure;
|
|
}
|
|
strcpy(Credential->Workstation, "none");
|
|
}
|
|
|
|
if (Identity->Password == NULL) {
|
|
Length = 0;
|
|
} else {
|
|
Length = strlen((PCHAR)Identity->Password);
|
|
}
|
|
|
|
if (Length > AC_MAX_PASSWORD_LENGTH) {
|
|
goto failure;
|
|
}
|
|
|
|
Credential->Password = (PLM_OWF_PASSWORD)SspAlloc (sizeof(LM_OWF_PASSWORD));
|
|
if (Credential->Password == NULL) {
|
|
goto failure;
|
|
}
|
|
|
|
// Allow NULL and "\0" passwords by prefilling TmpText with and
|
|
// empty string.
|
|
|
|
if (Length == 0) {
|
|
TmpText[0] = 0;
|
|
} else {
|
|
strcpy(TmpText, (char *)Identity->Password);
|
|
_strupr(TmpText);
|
|
}
|
|
|
|
//
|
|
// Fit a 16 char password into 14 characters length
|
|
//
|
|
FitTo14(TmpText);
|
|
|
|
CalculateLmOwfPassword((PLM_PASSWORD)TmpText, Credential->Password);
|
|
|
|
return (SEC_E_OK);
|
|
|
|
failure:
|
|
|
|
if (Credential->Username != NULL) {
|
|
SspFree(Credential->Username);
|
|
Credential->Username = NULL;
|
|
}
|
|
|
|
if (Credential->Domain != NULL) {
|
|
SspFree(Credential->Domain);
|
|
Credential->Domain = NULL;
|
|
}
|
|
|
|
if (Credential->Workstation != NULL) {
|
|
SspFree(Credential->Workstation);
|
|
Credential->Workstation = NULL;
|
|
}
|
|
|
|
if (Credential->Password != NULL) {
|
|
SspFree(Credential->Password);
|
|
Credential->Password = NULL;
|
|
}
|
|
|
|
return (SEC_E_INSUFFICIENT_MEMORY);
|
|
}
|
|
|
|
|
|
SECURITY_STATUS
|
|
SetCredentialsFromAuthDataW(
|
|
IN PVOID AuthData,
|
|
PSSP_CREDENTIAL Credential
|
|
)
|
|
{
|
|
SEC_WINNT_AUTH_IDENTITY_W *Identity = (SEC_WINNT_AUTH_IDENTITY_W *)AuthData;
|
|
char TmpText[AC_MAX_PASSWORD_LENGTH + 4];
|
|
int Length;
|
|
int i;
|
|
|
|
if (Identity->User == NULL || Identity->Domain == NULL) {
|
|
return SEC_E_UNKNOWN_CREDENTIALS;
|
|
}
|
|
|
|
if (wcslen(Identity->User) > MAX_USERNAME_LENGTH)
|
|
return(SEC_E_UNKNOWN_CREDENTIALS);
|
|
|
|
Credential->Username = NULL;
|
|
Credential->Domain = NULL;
|
|
Credential->Password = NULL;
|
|
Credential->Workstation = NULL;
|
|
|
|
i = wcslen(Identity->User);
|
|
Credential->Username = (char *)SspAlloc(i+1);
|
|
if (Credential->Username == NULL) {
|
|
goto failure;
|
|
}
|
|
wcstombs(Credential->Username, Identity->User, i+1);
|
|
|
|
i = wcslen(Identity->Domain);
|
|
Credential->Domain = (char *)SspAlloc(i + 1);
|
|
if (Credential->Domain == NULL) {
|
|
goto failure;
|
|
}
|
|
wcstombs(Credential->Domain, Identity->Domain, i+1);
|
|
|
|
// If netbios won't tell us the workstation name, make one up.
|
|
if (!SspGetWorkstation(Credential)) {
|
|
Credential->Workstation = (char *)SspAlloc(strlen("none") + 1);
|
|
if (Credential->Workstation == NULL) {
|
|
goto failure;
|
|
}
|
|
strcpy(Credential->Workstation, "none");
|
|
}
|
|
|
|
if (Identity->Password == NULL) {
|
|
Length = 0;
|
|
} else {
|
|
Length = wcslen(Identity->Password);
|
|
}
|
|
|
|
if (Length > AC_MAX_PASSWORD_LENGTH) {
|
|
goto failure;
|
|
}
|
|
|
|
Credential->Password = (PLM_OWF_PASSWORD)SspAlloc (sizeof(LM_OWF_PASSWORD));
|
|
if (Credential->Password == NULL) {
|
|
goto failure;
|
|
}
|
|
|
|
// Allow NULL and "\0" passwords by prefilling TmpText with and
|
|
// empty string.
|
|
|
|
if (Length == 0) {
|
|
TmpText[0] = 0;
|
|
} else {
|
|
wcstombs(TmpText, Identity->Password, Length);
|
|
_strupr(TmpText);
|
|
}
|
|
|
|
FitTo14(TmpText);
|
|
|
|
CalculateLmOwfPassword((PLM_PASSWORD)TmpText, Credential->Password);
|
|
|
|
return (SEC_E_OK);
|
|
|
|
failure:
|
|
|
|
if (Credential->Username != NULL) {
|
|
SspFree(Credential->Username);
|
|
Credential->Username = NULL;
|
|
}
|
|
|
|
if (Credential->Domain != NULL) {
|
|
SspFree(Credential->Domain);
|
|
Credential->Domain = NULL;
|
|
}
|
|
|
|
if (Credential->Workstation != NULL) {
|
|
SspFree(Credential->Workstation);
|
|
Credential->Workstation = NULL;
|
|
}
|
|
|
|
if (Credential->Password != NULL) {
|
|
SspFree(Credential->Password);
|
|
Credential->Password = NULL;
|
|
}
|
|
|
|
return (SEC_E_INSUFFICIENT_MEMORY);
|
|
}
|
|
|
|
#if 0
|
|
BOOLEAN
|
|
SspTimeHasElapsed(
|
|
IN DWORD StartTime,
|
|
IN DWORD Timeout
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if "Timeout" milliseconds have elapsed since StartTime.
|
|
|
|
Arguments:
|
|
|
|
StartTime - Specifies an absolute time when the event started
|
|
(in millisecond units).
|
|
|
|
Timeout - Specifies a relative time in milliseconds. 0xFFFFFFFF indicates
|
|
that the time will never expire.
|
|
|
|
Return Value:
|
|
|
|
TRUE -- iff Timeout milliseconds have elapsed since StartTime.
|
|
|
|
--*/
|
|
{
|
|
DWORD TimeNow;
|
|
DWORD ElapsedTime;
|
|
|
|
//
|
|
// If the period to too large to handle (i.e., 0xffffffff is forever),
|
|
// just indicate that the timer has not expired.
|
|
//
|
|
//
|
|
|
|
if ( Timeout == 0xffffffff ) {
|
|
return FALSE;
|
|
}
|
|
|
|
TimeNow = SspTicks();
|
|
|
|
ElapsedTime = TimeNow - StartTime;
|
|
|
|
if (ElapsedTime > Timeout) {
|
|
return (TRUE);
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
#endif // 0, completely commented out
|
|
|
|
|
|
#ifndef FOR_SSPS // IF NOT PART OF MSNSSPS.DLL
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
QuerySecurityPackageInfoA(
|
|
IN LPSTR PackageName,
|
|
OUT PSecPkgInfo SEC_FAR *PackageInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is intended to provide basic information about Security
|
|
Packages themselves. This information will include the bounds on sizes
|
|
of authentication information, credentials and contexts.
|
|
|
|
?? This is a local routine rather than the real API call since the API
|
|
call has a braindead interface that neither allows me to allocate the
|
|
buffer nor tells me how big the buffer is. Perhaps when the real API
|
|
is fixed, I'll make this the real API.
|
|
|
|
Arguments:
|
|
|
|
PackageName - Name of the package being queried.
|
|
|
|
PackageInfo - Returns a pointer to an allocated block describing the
|
|
security package. The allocated block must be freed using
|
|
FreeContextBuffer.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK -- Call completed successfully
|
|
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
{
|
|
char *Where;
|
|
|
|
//
|
|
// Ensure the correct package name was passed in.
|
|
//
|
|
if (!PackageName)
|
|
return (SEC_E_PACKAGE_UNKNOWN);
|
|
|
|
if ( strcmp( PackageName, (char *)MSNSP_NAME_A ) != 0 ) {
|
|
return SEC_E_PACKAGE_UNKNOWN;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer for the PackageInfo
|
|
//
|
|
|
|
*PackageInfo = (PSecPkgInfo) SspAlloc (sizeof(SecPkgInfo) +
|
|
sizeof(MSNSP_NAME_A) +
|
|
sizeof(MSNSP_COMMENT_A) );
|
|
|
|
if ( *PackageInfo == NULL ) {
|
|
return SEC_E_INSUFFICIENT_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Fill in the information.
|
|
//
|
|
|
|
(*PackageInfo)->fCapabilities = MSNSP_CAPABILITIES;
|
|
(*PackageInfo)->wVersion = MSNSP_VERSION;
|
|
(*PackageInfo)->wRPCID = MSNSP_RPCID;
|
|
(*PackageInfo)->cbMaxToken = MSNSP_MAX_TOKEN_SIZE;
|
|
|
|
Where = (char *)((*PackageInfo)+1);
|
|
|
|
(*PackageInfo)->Name = Where;
|
|
strcpy( Where, (char *)MSNSP_NAME_A);
|
|
Where += strlen(Where) + 1;
|
|
|
|
|
|
(*PackageInfo)->Comment = Where;
|
|
strcpy( Where, (char *)MSNSP_COMMENT_A);
|
|
Where += strlen(Where) + 1;
|
|
|
|
return SEC_E_OK;
|
|
}
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
QuerySecurityPackageInfoW(
|
|
IN LPWSTR PackageName,
|
|
OUT PSecPkgInfoW *PackageInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is intended to provide basic information about Security
|
|
Packages themselves. This information will include the bounds on sizes
|
|
of authentication information, credentials and contexts.
|
|
|
|
?? This is a local routine rather than the real API call since the API
|
|
call has a braindead interface that neither allows me to allocate the
|
|
buffer nor tells me how big the buffer is. Perhaps when the real API
|
|
is fixed, I'll make this the real API.
|
|
|
|
Arguments:
|
|
|
|
PackageName - Name of the package being queried.
|
|
|
|
PackageInfo - Returns a pointer to an allocated block describing the
|
|
security package. The allocated block must be freed using
|
|
FreeContextBuffer.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK -- Call completed successfully
|
|
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
{
|
|
WCHAR *Where;
|
|
|
|
//
|
|
// Ensure the correct package name was passed in.
|
|
//
|
|
if (!PackageName)
|
|
return (SEC_E_PACKAGE_UNKNOWN);
|
|
|
|
if ( wcscmp( PackageName, (WCHAR *)MSNSP_NAME_W ) != 0 ) {
|
|
return SEC_E_PACKAGE_UNKNOWN;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer for the PackageInfo
|
|
//
|
|
|
|
*PackageInfo = (PSecPkgInfoW) SspAlloc (sizeof(SecPkgInfo) +
|
|
sizeof(MSNSP_NAME_W) +
|
|
sizeof(MSNSP_COMMENT_W) );
|
|
|
|
if ( *PackageInfo == NULL ) {
|
|
return SEC_E_INSUFFICIENT_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Fill in the information.
|
|
//
|
|
|
|
(*PackageInfo)->fCapabilities = MSNSP_CAPABILITIES;
|
|
(*PackageInfo)->wVersion = MSNSP_VERSION;
|
|
(*PackageInfo)->wRPCID = MSNSP_RPCID;
|
|
(*PackageInfo)->cbMaxToken = MSNSP_MAX_TOKEN_SIZE;
|
|
|
|
Where = (WCHAR *)((*PackageInfo)+1);
|
|
|
|
(*PackageInfo)->Name = Where;
|
|
wcscpy( Where, (WCHAR *)MSNSP_NAME_W);
|
|
Where += wcslen(Where) + 1;
|
|
|
|
|
|
(*PackageInfo)->Comment = Where;
|
|
wcscpy( Where, (WCHAR *)MSNSP_COMMENT_W);
|
|
Where += wcslen(Where) + 1;
|
|
|
|
return SEC_E_OK;
|
|
}
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
EnumerateSecurityPackagesA(
|
|
OUT PULONG PackageCount,
|
|
OUT PSecPkgInfoA * PackageInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API returns a list of Security Packages available to client (i.e.
|
|
those that are either loaded or can be loaded on demand). The caller
|
|
must free the returned buffer with FreeContextBuffer. This API returns
|
|
a list of all the security packages available to a service. The names
|
|
returned can then be used to acquire credential handles, as well as
|
|
determine which package in the system best satisfies the requirements
|
|
of the caller. It is assumed that all available packages can be
|
|
included in the single call.
|
|
|
|
This is really a dummy API that just returns information about this
|
|
security package. It is provided to ensure this security package has the
|
|
same interface as the multiplexer DLL does.
|
|
|
|
Arguments:
|
|
|
|
PackageCount - Returns the number of packages supported.
|
|
|
|
PackageInfo - Returns an allocate array of structures
|
|
describing the security packages. The array must be freed
|
|
using FreeContextBuffer.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK -- Call completed successfully
|
|
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
//
|
|
// Get the information for this package.
|
|
//
|
|
|
|
SecStatus = QuerySecurityPackageInfoA( (CHAR *) MSNSP_NAME_A,
|
|
PackageInfo );
|
|
|
|
if ( SecStatus != SEC_E_OK ) {
|
|
return SecStatus;
|
|
}
|
|
|
|
*PackageCount = 1;
|
|
|
|
return (SEC_E_OK);
|
|
}
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
EnumerateSecurityPackagesW(
|
|
OUT PULONG PackageCount,
|
|
OUT PSecPkgInfoW * PackageInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API returns a list of Security Packages available to client (i.e.
|
|
those that are either loaded or can be loaded on demand). The caller
|
|
must free the returned buffer with FreeContextBuffer. This API returns
|
|
a list of all the security packages available to a service. The names
|
|
returned can then be used to acquire credential handles, as well as
|
|
determine which package in the system best satisfies the requirements
|
|
of the caller. It is assumed that all available packages can be
|
|
included in the single call.
|
|
|
|
This is really a dummy API that just returns information about this
|
|
security package. It is provided to ensure this security package has the
|
|
same interface as the multiplexer DLL does.
|
|
|
|
Arguments:
|
|
|
|
PackageCount - Returns the number of packages supported.
|
|
|
|
PackageInfo - Returns an allocate array of structures
|
|
describing the security packages. The array must be freed
|
|
using FreeContextBuffer.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK -- Call completed successfully
|
|
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
//
|
|
// Get the information for this package.
|
|
//
|
|
|
|
SecStatus = QuerySecurityPackageInfoW( (WCHAR *) MSNSP_NAME_W,
|
|
PackageInfo );
|
|
|
|
if ( SecStatus != SEC_E_OK ) {
|
|
return SecStatus;
|
|
}
|
|
|
|
*PackageCount = 1;
|
|
|
|
return (SEC_E_OK);
|
|
}
|
|
|
|
#endif // not FOR_SSPS (NOT PART OF MSNSSPS.DLL)
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspcGetCredentialHanldeA (
|
|
IN CHAR * PrincipalName,
|
|
IN CHAR * PackageName,
|
|
IN ULONG CredentialUseFlags,
|
|
IN PLUID LogonId,
|
|
IN PVOID AuthData,
|
|
IN SEC_GET_KEY_FN GetKeyFunction,
|
|
IN PVOID GetKeyArgument,
|
|
OUT PCredHandle CredentialHandle,
|
|
OUT PTimeStamp Lifetime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by AcquireCredentialsHandleA to acquire
|
|
credentials associated with the user on whose behalf the call is made
|
|
i.e. under the identity this application is running.
|
|
|
|
Arguments:
|
|
|
|
Same as AcquireCredentialsHandleA
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- Call completed successfully
|
|
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_PRINCIPAL_UNKNOWN -- No such principal
|
|
SEC_E_NOT_OWNER -- caller does not own the specified credentials
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
PSSP_CREDENTIAL Credential = NULL;
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspcGetCredentialHanldeA Entered\n" ));
|
|
#endif
|
|
|
|
if ( (CredentialUseFlags & SECPKG_CRED_OUTBOUND) &&
|
|
ARGUMENT_PRESENT(PrincipalName) && *PrincipalName != '\0' ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(LogonId) ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(GetKeyFunction) ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(GetKeyArgument) ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
//
|
|
// Allocate a credential block and initialize it.
|
|
//
|
|
|
|
Credential = SspCredentialAllocateCredential(CredentialUseFlags);
|
|
|
|
if ( Credential == NULL ) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (AuthData == NULL) {
|
|
|
|
//
|
|
// No credential information, initializes all pointers to NULL
|
|
//
|
|
Credential->Username = NULL;
|
|
Credential->Password = NULL;
|
|
Credential->Domain = NULL;
|
|
Credential->Workstation = NULL;
|
|
|
|
} else {
|
|
SecStatus = SetCredentialsFromAuthDataA(AuthData, Credential);
|
|
if (SecStatus != SEC_E_OK) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Cache the user name and encrypted password in shared memory
|
|
//
|
|
if (!MsnSspUpdPwdCache (Credential->Username, Credential->Password))
|
|
{
|
|
// BUGBUG: If we can't cache the password for any reason,
|
|
// do we need to do anything? We definitely don't want to
|
|
// return error merely because this password can not be cached.
|
|
SspPrint(( SSP_API,
|
|
"SspcGetCredentialHanldeA: Cannot save password in cache\n"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return output parameters to the caller.
|
|
//
|
|
CredentialHandle->dwUpper = (DWORD) Credential;
|
|
CredentialHandle->dwLower = 0;
|
|
// *Lifetime = 0xffffffffL; // BUGBUG
|
|
|
|
SecStatus = SEC_E_OK;
|
|
|
|
//
|
|
// Free and locally used resources.
|
|
//
|
|
Cleanup:
|
|
|
|
if ( SecStatus != SEC_E_OK ) {
|
|
|
|
if ( Credential != NULL ) {
|
|
SspFree( Credential );
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspcGetCredentialHanldeA returns 0x%x\n", SecStatus ));
|
|
#endif
|
|
return SecStatus;
|
|
}
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspcGetCredentialHanldeW (
|
|
IN WCHAR * PrincipalName,
|
|
IN WCHAR * PackageName,
|
|
IN ULONG CredentialUseFlags,
|
|
IN PLUID LogonId,
|
|
IN PVOID AuthData,
|
|
IN SEC_GET_KEY_FN GetKeyFunction,
|
|
IN PVOID GetKeyArgument,
|
|
OUT PCredHandle CredentialHandle,
|
|
OUT PTimeStamp Lifetime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by AcquireCredentialsHandleW to acquire a handle to
|
|
credentials associated with the user on whose behalf the call is made
|
|
i.e. under the identity this application is running.
|
|
|
|
Arguments:
|
|
|
|
Same as AcquireCredentialsHandleW
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- Call completed successfully
|
|
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_PRINCIPAL_UNKNOWN -- No such principal
|
|
SEC_E_NOT_OWNER -- caller does not own the specified credentials
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
PSSP_CREDENTIAL Credential = NULL;
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspcGetCredentialHanldeW Entered\n" ));
|
|
#endif
|
|
|
|
if ( (CredentialUseFlags & SECPKG_CRED_OUTBOUND) &&
|
|
ARGUMENT_PRESENT(PrincipalName) && *PrincipalName != '\0' ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(LogonId) ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(GetKeyFunction) ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
if ( ARGUMENT_PRESENT(GetKeyArgument) ) {
|
|
return (SEC_E_PRINCIPAL_UNKNOWN);
|
|
}
|
|
|
|
//
|
|
// Allocate a credential block and initialize it.
|
|
//
|
|
|
|
Credential = SspCredentialAllocateCredential(CredentialUseFlags);
|
|
|
|
if ( Credential == NULL ) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (AuthData == NULL) {
|
|
|
|
//
|
|
// No credential information, initializes all pointers to NULL
|
|
//
|
|
Credential->Username = NULL;
|
|
Credential->Password = NULL;
|
|
Credential->Domain = NULL;
|
|
Credential->Workstation = NULL;
|
|
|
|
} else {
|
|
SecStatus = SetCredentialsFromAuthDataW(AuthData, Credential);
|
|
if (SecStatus != SEC_E_OK) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Cache the user name and encrypted password in shared memory
|
|
//
|
|
if (!MsnSspUpdPwdCache (Credential->Username, Credential->Password))
|
|
{
|
|
// BUGBUG: If we can't cache the password for any reason,
|
|
// do we need to do anything? We definitely don't want to
|
|
// return error merely because this password can not be cached.
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: Cannot save password in cache\n"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return output parameters to the caller.
|
|
//
|
|
CredentialHandle->dwUpper = (DWORD) Credential;
|
|
CredentialHandle->dwLower = 0;
|
|
// *Lifetime = 0xffffffffL; // BUGBUG
|
|
|
|
SecStatus = SEC_E_OK;
|
|
|
|
//
|
|
// Free and locally used resources.
|
|
//
|
|
Cleanup:
|
|
|
|
if ( SecStatus != SEC_E_OK ) {
|
|
|
|
if ( Credential != NULL ) {
|
|
SspFree( Credential );
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspcGetCredentialHanldeW returns 0x%x\n", SecStatus ));
|
|
#endif
|
|
return SecStatus;
|
|
}
|
|
|
|
#ifndef FOR_SSPS // IF NOT PART OF MSNSSPS.DLL
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
AcquireCredentialsHandleA(
|
|
IN CHAR * PrincipalName,
|
|
IN CHAR * PackageName,
|
|
IN ULONG CredentialUseFlags,
|
|
IN PLUID LogonId,
|
|
IN PVOID AuthData,
|
|
IN SEC_GET_KEY_FN GetKeyFunction,
|
|
IN PVOID GetKeyArgument,
|
|
OUT PCredHandle CredentialHandle,
|
|
OUT PTimeStamp Lifetime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API allows applications to acquire a handle to pre-existing
|
|
credentials associated with the user on whose behalf the call is made
|
|
i.e. under the identity this application is running. These pre-existing
|
|
credentials have been established through a system logon not described
|
|
here. Note that this is different from "login to the network" and does
|
|
not imply gathering of credentials.
|
|
|
|
Note for DOS we will ignore the previous note. On DOS we will gather
|
|
logon credentials through the AuthData parameter.
|
|
|
|
This API returns a handle to the credentials of a principal (user, client)
|
|
as used by a specific security package. This handle can then be used
|
|
in subsequent calls to the Context APIs. This API will not let a
|
|
process obtain a handle to credentials that are not related to the
|
|
process; i.e. we won't allow a process to grab the credentials of
|
|
another user logged into the same machine. There is no way for us
|
|
to determine if a process is a trojan horse or not, if it is executed
|
|
by the user.
|
|
|
|
Arguments:
|
|
|
|
PrincipalName - Name of the principal for whose credentials the handle
|
|
will reference. Note, if the process requesting the handle does
|
|
not have access to the credentials, an error will be returned.
|
|
A null string indicates that the process wants a handle to the
|
|
credentials of the user under whose security it is executing.
|
|
|
|
PackageName - Name of the package with which these credentials will
|
|
be used.
|
|
|
|
CredentialUseFlags - Flags indicating the way with which these
|
|
credentials will be used.
|
|
|
|
#define CRED_INBOUND 0x00000001
|
|
#define CRED_OUTBOUND 0x00000002
|
|
#define CRED_BOTH 0x00000003
|
|
|
|
The credentials created with CRED_INBOUND option can only be used
|
|
for (validating incoming calls and can not be used for making accesses.
|
|
|
|
LogonId - Pointer to NT style Logon Id which is a LUID. (Provided for
|
|
file system ; processes such as network redirectors.)
|
|
|
|
CredentialHandle - Returned credential handle.
|
|
|
|
Lifetime - Time that these credentials expire. The value returned in
|
|
this field depends on the security package.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- Call completed successfully
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_PRINCIPAL_UNKNOWN -- No such principal
|
|
SEC_E_NOT_OWNER -- caller does not own the specified credentials
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspAcquireCredentialHandle Entered\n" ));
|
|
#endif
|
|
|
|
//
|
|
// Validate the arguments
|
|
//
|
|
|
|
if (!PackageName)
|
|
return (SEC_E_PACKAGE_UNKNOWN);
|
|
|
|
if ( strcmp( PackageName, (CHAR *)MSNSP_NAME_A ) != 0 ) {
|
|
return (SEC_E_PACKAGE_UNKNOWN);
|
|
}
|
|
|
|
//
|
|
// Ensure that appropriate Credential use bit is set
|
|
//
|
|
|
|
if (((CredentialUseFlags & (SECPKG_CRED_OUTBOUND)) == 0 ) ||
|
|
((CredentialUseFlags & (SECPKG_CRED_INBOUND)) == 1)
|
|
)
|
|
{
|
|
SspPrint(( SSP_API,
|
|
"SspAcquireCredentialHandle: invalid credential use.\n" ));
|
|
return (SEC_E_INVALID_CREDENTIAL_USE);
|
|
}
|
|
|
|
SecStatus = SspcGetCredentialHanldeA (PrincipalName,
|
|
PackageName,
|
|
CredentialUseFlags,
|
|
LogonId,
|
|
AuthData,
|
|
GetKeyFunction,
|
|
GetKeyArgument,
|
|
CredentialHandle,
|
|
Lifetime);
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint((SSP_API, "SspAcquireCredentialHandle returns 0x%x\n", SecStatus));
|
|
#endif
|
|
|
|
return (SecStatus);
|
|
}
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
AcquireCredentialsHandleW(
|
|
IN WCHAR * PrincipalName,
|
|
IN WCHAR * PackageName,
|
|
IN ULONG CredentialUseFlags,
|
|
IN PLUID LogonId,
|
|
IN PVOID AuthData,
|
|
IN SEC_GET_KEY_FN GetKeyFunction,
|
|
IN PVOID GetKeyArgument,
|
|
OUT PCredHandle CredentialHandle,
|
|
OUT PTimeStamp Lifetime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API allows applications to acquire a handle to pre-existing
|
|
credentials associated with the user on whose behalf the call is made
|
|
i.e. under the identity this application is running. These pre-existing
|
|
credentials have been established through a system logon not described
|
|
here. Note that this is different from "login to the network" and does
|
|
not imply gathering of credentials.
|
|
|
|
Note for DOS we will ignore the previous note. On DOS we will gather
|
|
logon credentials through the AuthData parameter.
|
|
|
|
This API returns a handle to the credentials of a principal (user, client)
|
|
as used by a specific security package. This handle can then be used
|
|
in subsequent calls to the Context APIs. This API will not let a
|
|
process obtain a handle to credentials that are not related to the
|
|
process; i.e. we won't allow a process to grab the credentials of
|
|
another user logged into the same machine. There is no way for us
|
|
to determine if a process is a trojan horse or not, if it is executed
|
|
by the user.
|
|
|
|
Arguments:
|
|
|
|
PrincipalName - Name of the principal for whose credentials the handle
|
|
will reference. Note, if the process requesting the handle does
|
|
not have access to the credentials, an error will be returned.
|
|
A null string indicates that the process wants a handle to the
|
|
credentials of the user under whose security it is executing.
|
|
|
|
PackageName - Name of the package with which these credentials will
|
|
be used.
|
|
|
|
CredentialUseFlags - Flags indicating the way with which these
|
|
credentials will be used.
|
|
|
|
#define CRED_INBOUND 0x00000001
|
|
#define CRED_OUTBOUND 0x00000002
|
|
#define CRED_BOTH 0x00000003
|
|
|
|
The credentials created with CRED_INBOUND option can only be used
|
|
for (validating incoming calls and can not be used for making accesses.
|
|
|
|
LogonId - Pointer to NT style Logon Id which is a LUID. (Provided for
|
|
file system ; processes such as network redirectors.)
|
|
|
|
CredentialHandle - Returned credential handle.
|
|
|
|
Lifetime - Time that these credentials expire. The value returned in
|
|
this field depends on the security package.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- Call completed successfully
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_PACKAGE_UNKNOWN -- Package being queried is not this package
|
|
SEC_E_PRINCIPAL_UNKNOWN -- No such principal
|
|
SEC_E_NOT_OWNER -- caller does not own the specified credentials
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspAcquireCredentialHandle Entered\n" ));
|
|
#endif
|
|
|
|
//
|
|
// Validate the arguments
|
|
//
|
|
if (!PackageName)
|
|
return (SEC_E_PACKAGE_UNKNOWN);
|
|
|
|
if ( wcscmp( PackageName, MSNSP_NAME_W ) != 0 ) {
|
|
return (SEC_E_PACKAGE_UNKNOWN);
|
|
}
|
|
|
|
//
|
|
// Ensure at least one Credential use bit is set.
|
|
//
|
|
|
|
if ( (CredentialUseFlags & (SECPKG_CRED_OUTBOUND)) == 0 ) {
|
|
SspPrint(( SSP_API,
|
|
"SspAcquireCredentialHandle: invalid credential use.\n" ));
|
|
return (SEC_E_INVALID_CREDENTIAL_USE);
|
|
}
|
|
|
|
SecStatus = SspcGetCredentialHanldeW (PrincipalName,
|
|
PackageName,
|
|
CredentialUseFlags,
|
|
LogonId,
|
|
AuthData,
|
|
GetKeyFunction,
|
|
GetKeyArgument,
|
|
CredentialHandle,
|
|
Lifetime);
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspAcquireCredentialHandle returns 0x%x\n", SecStatus ));
|
|
#endif
|
|
|
|
return (SecStatus);
|
|
}
|
|
|
|
#endif // not FOR_SSPS (NOT PART OF MSNSSPS.DLL)
|
|
|
|
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcFreeCredentialsHandle(
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
FreeCredentialsHandle(
|
|
#endif // FOR_SSPS
|
|
IN PCredHandle CredentialHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is used to notify the security system that the credentials are
|
|
no longer needed and allows the application to free the handle acquired
|
|
in the call described above. When all references to this credential
|
|
set has been removed then the credentials may themselves be removed.
|
|
|
|
Arguments:
|
|
|
|
CredentialHandle - Credential Handle obtained through
|
|
AcquireCredentialHandle.
|
|
|
|
Return Value:
|
|
|
|
|
|
STATUS_SUCCESS -- Call completed successfully
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_INVALID_HANDLE -- Credential Handle is invalid
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
PSSP_CREDENTIAL Credential;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspFreeCredentialHandle Entered\n" ));
|
|
#endif
|
|
|
|
//
|
|
// Find the referenced credential and delink it.
|
|
//
|
|
|
|
Credential = SspCredentialReferenceCredential(CredentialHandle, TRUE);
|
|
|
|
if ( Credential == NULL ) {
|
|
SecStatus = SEC_E_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
SspCredentialDereferenceCredential( Credential );
|
|
SspCredentialDereferenceCredential( Credential );
|
|
|
|
SecStatus = SEC_E_OK;
|
|
|
|
Cleanup:
|
|
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspFreeCredentialHandle returns 0x%x\n", SecStatus ));
|
|
#endif
|
|
return SecStatus;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SspGetTokenBuffer(
|
|
IN PSecBufferDesc TokenDescriptor OPTIONAL,
|
|
OUT PVOID * TokenBuffer,
|
|
OUT PULONG * TokenSize,
|
|
IN BOOLEAN ReadonlyOK
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses a Token Descriptor and pulls out the useful
|
|
information.
|
|
|
|
Arguments:
|
|
|
|
TokenDescriptor - Descriptor of the buffer containing (or to contain) the
|
|
token. If not specified, TokenBuffer and TokenSize will be returned
|
|
as NULL.
|
|
|
|
TokenBuffer - Returns a pointer to the buffer for the token.
|
|
|
|
TokenSize - Returns a pointer to the location of the size of the buffer.
|
|
|
|
ReadonlyOK - TRUE if the token buffer may be readonly.
|
|
|
|
Return Value:
|
|
|
|
TRUE - If token buffer was properly found.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
|
|
//
|
|
// If there is no TokenDescriptor passed in,
|
|
// just pass out NULL to our caller.
|
|
//
|
|
|
|
if ( !ARGUMENT_PRESENT( TokenDescriptor) ) {
|
|
*TokenBuffer = NULL;
|
|
*TokenSize = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Check the version of the descriptor.
|
|
//
|
|
|
|
if ( TokenDescriptor->ulVersion != 0 ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Loop through each described buffer.
|
|
//
|
|
|
|
for ( i=0; i<TokenDescriptor->cBuffers ; i++ ) {
|
|
PSecBuffer Buffer = &TokenDescriptor->pBuffers[i];
|
|
if ( (Buffer->BufferType & (~SECBUFFER_READONLY)) == SECBUFFER_TOKEN ) {
|
|
|
|
//
|
|
// If the buffer is readonly and readonly isn't OK,
|
|
// reject the buffer.
|
|
//
|
|
|
|
if ( !ReadonlyOK && (Buffer->BufferType & SECBUFFER_READONLY) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Return the requested information
|
|
//
|
|
|
|
*TokenBuffer = Buffer->pvBuffer;
|
|
*TokenSize = &Buffer->cbBuffer;
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
SECURITY_STATUS
|
|
MsnSspEncryptPassword (
|
|
LM_OWF_PASSWORD *pLmPassword,
|
|
LPSTR pPassword
|
|
)
|
|
{
|
|
char TmpText[AC_MAX_PASSWORD_LENGTH+4];
|
|
int ii;
|
|
int Length = strlen(pPassword);
|
|
|
|
if (Length > AC_MAX_PASSWORD_LENGTH)
|
|
{
|
|
return (SEC_E_INSUFFICIENT_MEMORY);
|
|
}
|
|
|
|
// Allow NULL and "\0" passwords by prefilling TmpText with and
|
|
// empty string.
|
|
if (Length == 0) {
|
|
TmpText[0] = 0;
|
|
} else {
|
|
strcpy(TmpText, pPassword);
|
|
_strupr(TmpText);
|
|
}
|
|
|
|
//
|
|
// Fit a 16 char password into 14 characters length
|
|
//
|
|
FitTo14(TmpText);
|
|
|
|
CalculateLmOwfPassword((PLM_PASSWORD)TmpText, pLmPassword);
|
|
|
|
return (SEC_E_OK);
|
|
}
|
|
|
|
|
|
SECURITY_STATUS
|
|
MsnSspSetCredentials(
|
|
PSSP_CREDENTIAL Credential,
|
|
PCHAR szUsername,
|
|
LM_OWF_PASSWORD *pLmPassword
|
|
)
|
|
{
|
|
UINT DomainLen;
|
|
|
|
if (strlen(szUsername) > MAX_USERNAME_LENGTH)
|
|
return(SEC_E_UNKNOWN_CREDENTIALS);
|
|
|
|
if (Credential->Username)
|
|
SspFree (Credential->Username);
|
|
|
|
Credential->Username = (char *)SspAlloc(strlen(szUsername) + 1);
|
|
if (Credential->Username == NULL)
|
|
{
|
|
goto failure;
|
|
}
|
|
strcpy(Credential->Username, szUsername);
|
|
|
|
DomainLen = strlen (MSNSP_NAME_A);
|
|
if (Credential->Domain && strlen(Credential->Domain) != DomainLen)
|
|
{
|
|
SspFree (Credential->Domain);
|
|
Credential->Domain = NULL;
|
|
}
|
|
|
|
if (Credential->Domain == NULL)
|
|
{
|
|
Credential->Domain = (char *)SspAlloc(DomainLen + 1);
|
|
if (Credential->Domain == NULL)
|
|
goto failure;
|
|
}
|
|
strcpy(Credential->Domain, MSNSP_NAME_A);
|
|
|
|
if (Credential->Password == NULL)
|
|
{
|
|
Credential->Password = (PLM_OWF_PASSWORD)SspAlloc (sizeof(LM_OWF_PASSWORD));
|
|
if (Credential->Password == NULL) {
|
|
goto failure;
|
|
}
|
|
}
|
|
memcpy (Credential->Password, pLmPassword, sizeof(LM_OWF_PASSWORD));
|
|
|
|
if (Credential->Workstation)
|
|
{
|
|
SspFree (Credential->Workstation);
|
|
Credential->Workstation = NULL;
|
|
}
|
|
|
|
return (SEC_E_OK);
|
|
|
|
failure:
|
|
|
|
if (Credential->Username != NULL) {
|
|
SspFree(Credential->Username);
|
|
Credential->Username = NULL;
|
|
}
|
|
|
|
if (Credential->Domain != NULL) {
|
|
SspFree(Credential->Domain);
|
|
Credential->Domain = NULL;
|
|
}
|
|
|
|
if (Credential->Workstation != NULL) {
|
|
SspFree(Credential->Workstation);
|
|
Credential->Workstation = NULL;
|
|
}
|
|
|
|
if (Credential->Password != NULL) {
|
|
SspFree(Credential->Password);
|
|
Credential->Password = NULL;
|
|
}
|
|
|
|
return (SEC_E_INSUFFICIENT_MEMORY);
|
|
}
|
|
|
|
#if 0 // commented out
|
|
VOID
|
|
MsnSspDeleteCredential(
|
|
PSSP_CREDENTIAL Credential
|
|
)
|
|
{
|
|
if (Credential->Username != NULL)
|
|
{
|
|
SspFree(Credential->Username);
|
|
Credential->Username = NULL;
|
|
}
|
|
|
|
if (Credential->Domain != NULL)
|
|
{
|
|
SspFree(Credential->Domain);
|
|
Credential->Domain = NULL;
|
|
}
|
|
|
|
if (Credential->Workstation != NULL)
|
|
{
|
|
SspFree(Credential->Workstation);
|
|
Credential->Workstation = NULL;
|
|
}
|
|
|
|
if (Credential->Password != NULL)
|
|
{
|
|
SspFree(Credential->Password);
|
|
Credential->Password = NULL;
|
|
}
|
|
}
|
|
#endif // commented out
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspHandleFirstCall(
|
|
IN PCredHandle CredentialHandle,
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN ULONG ContextReqFlags,
|
|
IN ULONG InputTokenSize,
|
|
IN PVOID InputToken,
|
|
IN OUT PULONG OutputTokenSize,
|
|
OUT PVOID OutputToken,
|
|
OUT PULONG ContextAttributes,
|
|
OUT PTimeStamp ExpirationTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle the First Call part of InitializeSecurityContext.
|
|
|
|
Arguments:
|
|
|
|
All arguments same as for InitializeSecurityContext
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -- All OK
|
|
SEC_I_CONTINUE_NEEDED -- Caller should call again later
|
|
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_INSUFFICIENT_MEMORY -- Buffer for output token isn't big enough
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
PSSP_CONTEXT Context = NULL;
|
|
PSSP_CREDENTIAL Credential = NULL;
|
|
char szName[AC_MAX_LOGIN_NAME_LENGTH+1];
|
|
char szPassword[AC_MAX_PASSWORD_LENGTH+1];
|
|
LM_OWF_PASSWORD LmOwfPassword;
|
|
|
|
NEGOTIATE_MESSAGE NegotiateMessage;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
*ContextAttributes = 0;
|
|
|
|
#ifdef FOR_SSPS // IF THIS IS PART OF MSNSSPS.DLL
|
|
//
|
|
// Check for misuse of credential handle
|
|
// Return error if this is a server credential for INBOUND security context
|
|
//
|
|
if (CredentialHandle->dwUpper == 55 &&
|
|
CredentialHandle->dwLower == 55)
|
|
{
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: invalid credential handle for INBOUND.\n" ));
|
|
SecStatus = SEC_E_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
#endif // FOR_SSPS (PART OF MSNSSPS.DLL)
|
|
|
|
//
|
|
// Get a pointer to the credential
|
|
//
|
|
|
|
Credential = SspCredentialReferenceCredential(
|
|
CredentialHandle,
|
|
FALSE );
|
|
|
|
if ( Credential == NULL ) {
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: invalid credential handle.\n" ));
|
|
SecStatus = SEC_E_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( (Credential->CredentialUseFlags & SECPKG_CRED_OUTBOUND) == 0 ) {
|
|
SspPrint(( SSP_API, "SspHandleFirstCall: invalid credential use.\n" ));
|
|
SecStatus = SEC_E_INVALID_CREDENTIAL_USE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Both ISC_REQ_PROMPT_FOR_CREDS and ISC_REQ_USE_SUPPLIED_CREDS can not
|
|
// be specified at the same time.
|
|
//
|
|
if ( (ContextReqFlags & ISC_REQ_PROMPT_FOR_CREDS) &&
|
|
(ContextReqFlags & ISC_REQ_USE_SUPPLIED_CREDS) )
|
|
{
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: invalid ContextReqFlags 0x%lx.\n",
|
|
ContextReqFlags ));
|
|
SecStatus = SEC_E_INVALID_CONTEXT_REQ;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (ContextReqFlags & ISC_REQ_USE_SUPPLIED_CREDS)
|
|
{
|
|
if (Credential->Username == NULL && Credential->Password == NULL)
|
|
{
|
|
SecStatus = SEC_E_NO_CREDENTIALS;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Create/update the user name/password cache.
|
|
//
|
|
if (!MsnSspUpdPwdCache (Credential->Username, Credential->Password))
|
|
{
|
|
// BUGBUG: If we can't cache the password for any reason,
|
|
// do we need to do anything? We definitely don't want to
|
|
// return error merely because this password can not be cached.
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: Cannot save password in cache\n"));
|
|
}
|
|
}
|
|
else if ( !(ContextReqFlags & ISC_REQ_PROMPT_FOR_CREDS) &&
|
|
Credential->Username == NULL && Credential->Password == NULL)
|
|
{
|
|
//
|
|
// Retrieve name and password from shared memory and store them
|
|
// in the Credential
|
|
//
|
|
if (!MsnSspGetPwdFromCache (Credential))
|
|
{
|
|
SecStatus = SEC_E_NO_CREDENTIALS;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if (ContextReqFlags & ISC_REQ_PROMPT_FOR_CREDS)
|
|
{
|
|
MsnPwdDlg InfoDlg;
|
|
|
|
memset (&InfoDlg, 0, sizeof (InfoDlg));
|
|
if (GetUserInfo (&InfoDlg) == NULL)
|
|
{
|
|
//
|
|
// MsnSspDeleteCredential (Credential);
|
|
//
|
|
SecStatus = SEC_E_NO_CREDENTIALS;
|
|
goto Cleanup;
|
|
}
|
|
|
|
SecStatus = MsnSspEncryptPassword (&LmOwfPassword, InfoDlg.Password);
|
|
if (SecStatus != SEC_E_OK)
|
|
{
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: Password exceeded maximum length\n"));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Save user name and the encrypted password in cache
|
|
//
|
|
if (!MsnSspUpdPwdCache (InfoDlg.Username, &LmOwfPassword))
|
|
{
|
|
// BUGBUG: If we can't cache the password for any reason,
|
|
// do we need to do anything? We definitely don't want to
|
|
// return error merely because this password can not be cached.
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: Cannot save password in cache\n"));
|
|
}
|
|
|
|
//
|
|
// Store the user name and the encrypted password in Credential
|
|
// ??? still don't know in what form will the password be passed back
|
|
// from the UI yet ???
|
|
//
|
|
SecStatus = MsnSspSetCredentials (Credential, InfoDlg.Username,
|
|
&LmOwfPassword);
|
|
if (SecStatus != SEC_E_OK)
|
|
{
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: Cannot save name/password in Credential\n"));
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate a new context
|
|
//
|
|
|
|
Context = SspContextAllocateContext();
|
|
|
|
if ( Context == NULL ) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Build a handle to the newly created context.
|
|
//
|
|
|
|
ContextHandle->dwUpper = (DWORD) Context;
|
|
ContextHandle->dwLower = 0;
|
|
|
|
//
|
|
// We don't support any options.
|
|
//
|
|
// Complain about those that require we do something.
|
|
//
|
|
|
|
if ( (ContextReqFlags & (ISC_REQ_ALLOCATE_MEMORY )) != 0 ) {
|
|
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: invalid ContextReqFlags 0x%lx.\n",
|
|
ContextReqFlags ));
|
|
SecStatus = SEC_E_INVALID_CONTEXT_REQ;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If this is the first call,
|
|
// build a Negotiate message.
|
|
//
|
|
// Offer to talk Oem character set.
|
|
//
|
|
|
|
strcpy( (char *) NegotiateMessage.Signature, NTLMSSP_SIGNATURE );
|
|
NegotiateMessage.MessageType = NtLmNegotiate;
|
|
NegotiateMessage.NegotiateFlags = NTLMSSP_NEGOTIATE_OEM |
|
|
NTLMSSP_NEGOTIATE_NTLM |
|
|
NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
|
|
|
if (Credential->Domain == NULL) {
|
|
NegotiateMessage.NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
|
|
}
|
|
|
|
if ( *OutputTokenSize < sizeof(NEGOTIATE_MESSAGE) ) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (ContextReqFlags & (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT)) {
|
|
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
|
|
NegotiateMessage.NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN |
|
|
NTLMSSP_NEGOTIATE_LM_KEY;
|
|
}
|
|
|
|
if (ContextReqFlags & ISC_REQ_CONFIDENTIALITY) {
|
|
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
|
|
NegotiateMessage.NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL |
|
|
NTLMSSP_NEGOTIATE_LM_KEY;
|
|
}
|
|
|
|
swaplong(NegotiateMessage.NegotiateFlags) ;
|
|
swaplong(NegotiateMessage.MessageType) ;
|
|
memcpy(OutputToken, &NegotiateMessage, sizeof(NEGOTIATE_MESSAGE));
|
|
|
|
*OutputTokenSize = sizeof(NEGOTIATE_MESSAGE);
|
|
|
|
//
|
|
// Return output parameters to the caller.
|
|
//
|
|
|
|
*ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
|
|
|
|
Context->Credential = SspCredentialReferenceCredential(
|
|
CredentialHandle,
|
|
FALSE);
|
|
|
|
|
|
SecStatus = SEC_I_CONTINUE_NEEDED;
|
|
Context->State = ClntNegotiateSentState;
|
|
|
|
//
|
|
// Free locally used resources.
|
|
//
|
|
Cleanup:
|
|
|
|
if ( Context != NULL ) {
|
|
|
|
if (SecStatus != SEC_I_CONTINUE_NEEDED) {
|
|
SspContextDereferenceContext( Context );
|
|
}
|
|
}
|
|
|
|
if ( Credential != NULL ) {
|
|
SspCredentialDereferenceCredential( Credential );
|
|
}
|
|
|
|
UNREFERENCED_PARAMETER( InputToken );
|
|
UNREFERENCED_PARAMETER( InputTokenSize );
|
|
|
|
return SecStatus;
|
|
}
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspHandleChallengeMessage(
|
|
IN PLUID LogonId,
|
|
IN PCredHandle CredentialHandle,
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN ULONG ContextReqFlags,
|
|
IN ULONG InputTokenSize,
|
|
IN PVOID InputToken,
|
|
IN OUT PULONG OutputTokenSize,
|
|
OUT PVOID OutputToken,
|
|
OUT PULONG ContextAttributes,
|
|
OUT PTimeStamp ExpirationTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle the Challenge message part of InitializeSecurityContext.
|
|
|
|
Arguments:
|
|
|
|
LogonId -- LogonId of the calling process.
|
|
|
|
All other arguments same as for InitializeSecurityContext
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Message handled
|
|
SEC_I_CONTINUE_NEEDED -- Caller should call again later
|
|
|
|
SEC_E_INVALID_TOKEN -- Token improperly formatted
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_INSUFFICIENT_MEMORY -- Buffer for output token isn't big enough
|
|
SEC_E_NO_CREDENTIALS -- There are no credentials for this client
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
PSSP_CONTEXT Context = NULL;
|
|
PSSP_CREDENTIAL Credential = NULL;
|
|
PCHALLENGE_MESSAGE ChallengeMessage = NULL;
|
|
PAUTHENTICATE_MESSAGE AuthenticateMessage = NULL;
|
|
ULONG AuthenticateMessageSize;
|
|
PCHAR Where;
|
|
LM_RESPONSE LmResponse;
|
|
PSTRING pString;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
*ContextAttributes = 0;
|
|
|
|
//
|
|
// Find the currently existing context.
|
|
//
|
|
|
|
Context = SspContextReferenceContext( ContextHandle, FALSE );
|
|
|
|
if ( Context == NULL ) {
|
|
SecStatus = SEC_E_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// If we have already sent the authenticate message, then this must be
|
|
// RPC calling Initialize a third time to re-authenticate a connection.
|
|
// This happens when a new interface is called over an existing
|
|
// connection. What we do here is build a NULL authenticate message
|
|
// that the server will recognize and also ignore.
|
|
//
|
|
|
|
if ( Context->State == ClntAuthenticateSentState ) {
|
|
AUTHENTICATE_MESSAGE NullMessage;
|
|
|
|
//
|
|
// To make sure this is the intended meaning of the call, check
|
|
// that the input token is NULL.
|
|
//
|
|
|
|
if ( (InputTokenSize != 0) || (InputToken != NULL) ) {
|
|
|
|
SecStatus = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( *OutputTokenSize < sizeof(NullMessage) ) {
|
|
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
|
|
} else {
|
|
|
|
strcpy( (char *)NullMessage.Signature, NTLMSSP_SIGNATURE );
|
|
NullMessage.MessageType = NtLmAuthenticate;
|
|
swaplong(NullMessage.MessageType) ;
|
|
|
|
memset(&NullMessage.LmChallengeResponse, 0, 5*sizeof(STRING));
|
|
*OutputTokenSize = sizeof(NullMessage);
|
|
memcpy(OutputToken, &NullMessage, sizeof(NullMessage));
|
|
SecStatus = SEC_E_OK;
|
|
}
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
if ( Context->State != ClntNegotiateSentState ) {
|
|
SspPrint(( SSP_API,
|
|
"SspHandleChallengeMessage: "
|
|
"Context not in ClntNegotiateSentState\n" ));
|
|
SecStatus = SEC_E_OUT_OF_SEQUENCE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// We don't support any options.
|
|
//
|
|
// Complain about those that require we do something.
|
|
//
|
|
|
|
if ( (ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY ) != 0 ) {
|
|
|
|
SspPrint(( SSP_API,
|
|
"SspHandleFirstCall: invalid ContextReqFlags 0x%lx.\n",
|
|
ContextReqFlags ));
|
|
SecStatus = SEC_E_INVALID_CONTEXT_REQ;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (ContextReqFlags & (ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT)) {
|
|
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN;
|
|
|
|
}
|
|
|
|
if (ContextReqFlags & ISC_REQ_CONFIDENTIALITY) {
|
|
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL;
|
|
}
|
|
//
|
|
// Ignore the Credential Handle.
|
|
//
|
|
// Since this is the second call,
|
|
// the credential is implied by the Context.
|
|
// We could double check that the Credential Handle is either NULL or
|
|
// correct. However, our implementation doesn't maintain a close
|
|
// association between the two (actually no association) so checking
|
|
// would require a lot of overhead.
|
|
//
|
|
|
|
UNREFERENCED_PARAMETER( CredentialHandle );
|
|
|
|
SSPASSERT(Context->Credential != NULL);
|
|
|
|
Credential = Context->Credential;
|
|
|
|
//
|
|
// Get the ChallengeMessage.
|
|
//
|
|
|
|
if ( InputTokenSize < sizeof(CHALLENGE_MESSAGE) ) {
|
|
SspPrint(( SSP_API,
|
|
"SspHandleChallengeMessage: "
|
|
"ChallengeMessage size wrong %ld\n",
|
|
InputTokenSize ));
|
|
SecStatus = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( InputTokenSize > NTLMSSP_MAX_MESSAGE_SIZE ) {
|
|
SspPrint(( SSP_API,
|
|
"SspHandleChallengeMessage: "
|
|
"InputTokenSize > NTLMSSP_MAX_MESSAGE_SIZE\n" ));
|
|
SecStatus = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ChallengeMessage = (PCHALLENGE_MESSAGE) InputToken;
|
|
swaplong(ChallengeMessage->MessageType) ;
|
|
swaplong(ChallengeMessage->NegotiateFlags) ;
|
|
|
|
if ( strncmp( (char *)ChallengeMessage->Signature,
|
|
NTLMSSP_SIGNATURE,
|
|
sizeof(NTLMSSP_SIGNATURE)) != 0 ||
|
|
ChallengeMessage->MessageType != NtLmChallenge ) {
|
|
SspPrint(( SSP_API,
|
|
"SspHandleChallengeMessage: "
|
|
"InputToken has invalid NTLMSSP signature\n" ));
|
|
SecStatus = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Only negotiate OEM
|
|
//
|
|
|
|
if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE ) {
|
|
SspPrint(( SSP_API,
|
|
"SspHandleChallengeMessage: "
|
|
"ChallengeMessage bad NegotiateFlags (UNICODE) 0x%lx\n",
|
|
ChallengeMessage->NegotiateFlags ));
|
|
SecStatus = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Check whether the server negotiated ALWAYS_SIGN
|
|
//
|
|
|
|
if ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN ) {
|
|
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
|
|
}
|
|
|
|
//
|
|
// Only negotiate NTLM
|
|
//
|
|
|
|
if ( ( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NETWARE ) &&
|
|
!( ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM ) ) {
|
|
SspPrint(( SSP_API,
|
|
"SspHandleChallengeMessage: "
|
|
"ChallengeMessage bad NegotiateFlags (NETWARE) 0x%lx\n",
|
|
ChallengeMessage->NegotiateFlags ));
|
|
SecStatus = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Make sure that if we are signing or sealing we only have to use the
|
|
// LM key
|
|
//
|
|
|
|
if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)) &&
|
|
!(ChallengeMessage->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY))
|
|
{
|
|
SspPrint(( SSP_API,
|
|
"SspHandleChallengeMessage: "
|
|
"ChallengeMessage bad NegotiateFlags (Sign or Seal but no LM key) 0x%lx\n",
|
|
ChallengeMessage->NegotiateFlags ));
|
|
SecStatus = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (Credential->Domain == NULL) {
|
|
|
|
SSPASSERT(ChallengeMessage->TargetName.Length != 0);
|
|
|
|
Credential->Domain = (char *)SspAlloc(ChallengeMessage->TargetName.Length + 1);
|
|
if (Credential->Domain == NULL) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
pString = &ChallengeMessage->TargetName;
|
|
memcpy(Credential->Domain, (PCHAR)ChallengeMessage + (ULONG)pString->Buffer, pString->Length);
|
|
Credential->Domain[pString->Length] = '\0';
|
|
}
|
|
|
|
//
|
|
// We will assume that the password is already in the Credential
|
|
//
|
|
#if 0
|
|
if (GetPassword(Credential, 0) == FALSE) {
|
|
SecStatus = SEC_E_NO_CREDENTIALS;
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
|
|
if (CalculateLmResponse((PLM_CHALLENGE)ChallengeMessage->Challenge, Credential->Password, &LmResponse) == FALSE) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Allocate an authenticate message
|
|
//
|
|
|
|
AuthenticateMessageSize = sizeof(*AuthenticateMessage)+LM_RESPONSE_LENGTH;
|
|
|
|
if (Credential->Domain != NULL) {
|
|
AuthenticateMessageSize += strlen(Credential->Domain);
|
|
}
|
|
if (Credential->Username != NULL) {
|
|
AuthenticateMessageSize += strlen(Credential->Username);
|
|
}
|
|
if (Credential->Workstation != NULL) {
|
|
AuthenticateMessageSize += strlen(Credential->Workstation);
|
|
}
|
|
|
|
if ( AuthenticateMessageSize > *OutputTokenSize ) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
AuthenticateMessage = (PAUTHENTICATE_MESSAGE) SspAlloc ((int)AuthenticateMessageSize );
|
|
|
|
if ( AuthenticateMessage == NULL ) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Build the authenticate message
|
|
//
|
|
|
|
strcpy( (char *)AuthenticateMessage->Signature, NTLMSSP_SIGNATURE );
|
|
AuthenticateMessage->MessageType = NtLmAuthenticate;
|
|
swaplong(AuthenticateMessage->MessageType) ;
|
|
|
|
Where = (PCHAR)(AuthenticateMessage+1);
|
|
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->LmChallengeResponse,
|
|
(PCHAR)&LmResponse,
|
|
LM_RESPONSE_LENGTH,
|
|
&Where);
|
|
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->NtChallengeResponse,
|
|
NULL,
|
|
0,
|
|
&Where);
|
|
|
|
if (Credential->Domain != NULL) {
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->DomainName,
|
|
Credential->Domain,
|
|
strlen(Credential->Domain),
|
|
&Where);
|
|
} else {
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->DomainName,
|
|
NULL, 0, &Where);
|
|
}
|
|
|
|
if (Credential->Username != NULL) {
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->UserName,
|
|
Credential->Username,
|
|
strlen(Credential->Username),
|
|
&Where);
|
|
} else {
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->UserName,
|
|
NULL, 0, &Where);
|
|
}
|
|
|
|
if (Credential->Workstation != NULL) {
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->Workstation,
|
|
Credential->Workstation,
|
|
strlen(Credential->Workstation),
|
|
&Where);
|
|
} else {
|
|
SspCopyStringFromRaw( AuthenticateMessage,
|
|
&AuthenticateMessage->Workstation,
|
|
NULL, 0, &Where);
|
|
}
|
|
|
|
memcpy(OutputToken, AuthenticateMessage, (int)AuthenticateMessageSize);
|
|
|
|
*OutputTokenSize = AuthenticateMessageSize;
|
|
|
|
//
|
|
// The session key is the password, so convert it to a rc4 key.
|
|
//
|
|
|
|
if (Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN |
|
|
NTLMSSP_NEGOTIATE_SEAL))
|
|
{
|
|
UCHAR Key[LM_SESSION_KEY_LENGTH];
|
|
LM_RESPONSE SessionKey;
|
|
LM_OWF_PASSWORD LmKey;
|
|
|
|
|
|
//
|
|
// The session key is the first 8 bytes of the challenge response,
|
|
// re-encrypted with the password with the second 8 bytes set to 0xbd
|
|
//
|
|
|
|
memcpy(&LmKey,Credential->Password,LM_SESSION_KEY_LENGTH);
|
|
|
|
memset( (PUCHAR)(&LmKey) + LM_SESSION_KEY_LENGTH,
|
|
0xbd,
|
|
LM_OWF_PASSWORD_LENGTH - LM_SESSION_KEY_LENGTH);
|
|
|
|
if (CalculateLmResponse( (PLM_CHALLENGE) &LmResponse,
|
|
&LmKey,
|
|
&SessionKey) == FALSE) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
memcpy(Key,&SessionKey,5);
|
|
|
|
SSPASSERT(LM_SESSION_KEY_LENGTH == 8);
|
|
//
|
|
// Put a well-known salt at the end of the key to limit
|
|
// the changing part to 40 bits.
|
|
//
|
|
|
|
Key[5] = 0xe5;
|
|
Key[6] = 0x38;
|
|
Key[7] = 0xb0;
|
|
|
|
Context->ReceiveKey = (struct RC4_KEYSTRUCT *)SspAlloc(sizeof(struct RC4_KEYSTRUCT));
|
|
if (Context->ReceiveKey == NULL)
|
|
{
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
Context->SendKey = (struct RC4_KEYSTRUCT *)SspAlloc(sizeof(struct RC4_KEYSTRUCT));
|
|
if (Context->SendKey == NULL)
|
|
{
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
rc4_key(Context->SendKey, LM_SESSION_KEY_LENGTH, Key);
|
|
*(Context->ReceiveKey) = *(Context->SendKey);
|
|
Context->SendNonce = 0;
|
|
Context->ReceiveNonce = 0;
|
|
}
|
|
|
|
//
|
|
// Return output parameters to the caller.
|
|
//
|
|
|
|
*ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
|
|
|
|
SecStatus = SEC_E_OK;
|
|
|
|
//
|
|
// Free and locally used resources.
|
|
//
|
|
Cleanup:
|
|
|
|
if ( Context != NULL ) {
|
|
//
|
|
// Don't allow this context to be used again.
|
|
//
|
|
if ( SecStatus == SEC_E_OK ) {
|
|
Context->State = ClntAuthenticateSentState;
|
|
} else {
|
|
Context->State = ClntIdleState;
|
|
}
|
|
SspContextDereferenceContext( Context );
|
|
}
|
|
|
|
if ( AuthenticateMessage != NULL ) {
|
|
SspFree( AuthenticateMessage );
|
|
}
|
|
|
|
return SecStatus;
|
|
}
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
InitializeSecurityContextA(
|
|
IN PCredHandle CredentialHandle,
|
|
IN PCtxtHandle OldContextHandle,
|
|
IN CHAR * TargetName,
|
|
IN ULONG ContextReqFlags,
|
|
IN ULONG Reserved1,
|
|
IN ULONG TargetDataRep,
|
|
IN PSecBufferDesc InputToken,
|
|
IN ULONG Reserved2,
|
|
OUT PCtxtHandle NewContextHandle,
|
|
OUT PSecBufferDesc OutputToken,
|
|
OUT PULONG ContextAttributes,
|
|
OUT PTimeStamp ExpirationTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initiates the outbound security context from a credential
|
|
handle. This results in the establishment of a security context
|
|
between the application and a remote peer. The routine returns a token
|
|
which must be passed to the remote peer which in turn submits it to the
|
|
local security implementation via the AcceptSecurityContext() call.
|
|
The token generated should be considered opaque by all callers.
|
|
|
|
This function is used by a client to initialize an outbound context.
|
|
For a two leg security package, the calling sequence is as follows: The
|
|
client calls the function with OldContextHandle set to NULL and
|
|
InputToken set either to NULL or to a pointer to a security package
|
|
specific data structure. The package returns a context handle in
|
|
NewContextHandle and a token in OutputToken. The handle can then be
|
|
used for message APIs if desired.
|
|
|
|
The OutputToken returned here is sent across to target server which
|
|
calls AcceptSecuirtyContext() with this token as an input argument and
|
|
may receive a token which is returned to the initiator so it can call
|
|
InitializeSecurityContext() again.
|
|
|
|
For a three leg (mutual authentication) security package, the calling
|
|
sequence is as follows: The client calls the function as above, but the
|
|
package will return SEC_I_CONTINUE_NEEDED. The client then sends the
|
|
output token to the server and waits for the server's reply. Upon
|
|
receipt of the server's response, the client calls this function again,
|
|
with OldContextHandle set to the handle that was returned from the
|
|
first call. The token received from the server is supplied in the
|
|
InputToken parameter. If the server has successfully responded, then
|
|
the package will respond with success, or it will invalidate the
|
|
context.
|
|
|
|
Initialization of security context may require more than one call to
|
|
this function depending upon the underlying authentication mechanism as
|
|
well as the "choices" indicated via ContextReqFlags. The
|
|
ContextReqFlags and ContextAttributes are bit masks representing
|
|
various context level functions viz. delegation, mutual
|
|
authentication, confidentiality, replay detection and sequence
|
|
detection.
|
|
|
|
When ISC_REQ_PROMPT_FOR_CREDS flag is set the security package always
|
|
prompts the user for credentials, irrespective of whether credentials
|
|
are present or not. If user indicated that the supplied credentials be
|
|
used then they will be stashed (overwriting existing ones if any) for
|
|
future use. The security packages will always prompt for credentials
|
|
if none existed, this optimizes for the most common case before a
|
|
credentials database is built. But the security packages can be
|
|
configured to not do that. Security packages will ensure that they
|
|
only prompt to the interactive user, for other logon sessions, this
|
|
flag is ignored.
|
|
|
|
When ISC_REQ_USE_SUPPLIED_CREDS flag is set the security package always
|
|
uses the credentials supplied in the InitializeSecurityContext() call
|
|
via InputToken parameter. If the package does not have any credentials
|
|
available it will prompt for them and record it as indicated above.
|
|
|
|
It is an error to set both these flags simultaneously.
|
|
|
|
If the ISC_REQ_ALLOCATE_MEMORY was specified then the caller must free
|
|
the memory pointed to by OutputToken by calling FreeContextBuffer().
|
|
|
|
For example, the InputToken may be the challenge from a LAN Manager or
|
|
NT file server. In this case, the OutputToken would be the NTLM
|
|
encrypted response to the challenge. The caller of this API can then
|
|
take the appropriate response (case-sensitive v. case-insensitive) and
|
|
return it to the server for an authenticated connection.
|
|
|
|
|
|
Arguments:
|
|
|
|
CredentialHandle - Handle to the credentials to be used to
|
|
create the context.
|
|
|
|
OldContextHandle - Handle to the partially formed context, if this is
|
|
a second call (see above) or NULL if this is the first call.
|
|
|
|
TargetName - String indicating the target of the context. The name will
|
|
be security package specific. For example it will be a fully
|
|
qualified Cairo name for Kerberos package and can be UNC name or
|
|
domain name for the NTLM package.
|
|
|
|
ContextReqFlags - Requirements of the context, package specific.
|
|
|
|
#define ISC_REQ_DELEGATE 0x00000001
|
|
#define ISC_REQ_MUTUAL_AUTH 0x00000002
|
|
#define ISC_REQ_REPLAY_DETECT 0x00000004
|
|
#define ISC_REQ_SEQUENCE_DETECT 0x00000008
|
|
#define ISC_REQ_CONFIDENTIALITY 0x00000010
|
|
#define ISC_REQ_USE_SESSION_KEY 0x00000020
|
|
#define ISC_REQ_PROMT_FOR__CREDS 0x00000040
|
|
#define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080
|
|
#define ISC_REQ_ALLOCATE_MEMORY 0x00000100
|
|
#define ISC_REQ_USE_DCE_STYLE 0x00000200
|
|
|
|
Reserved1 - Reserved value, MBZ.
|
|
|
|
TargetDataRep - Long indicating the data representation (byte ordering, etc)
|
|
on the target. The constant SECURITY_NATIVE_DREP may be supplied
|
|
by the transport indicating that the native format is in use.
|
|
|
|
InputToken - Pointer to the input token. In the first call this
|
|
token can either be NULL or may contain security package specific
|
|
information.
|
|
|
|
Reserved2 - Reserved value, MBZ.
|
|
|
|
NewContextHandle - New context handle. If this is a second call, this
|
|
can be the same as OldContextHandle.
|
|
|
|
OutputToken - Buffer to receive the output token.
|
|
|
|
ContextAttributes -Attributes of the context established.
|
|
|
|
#define ISC_RET_DELEGATE 0x00000001
|
|
#define ISC_RET_MUTUAL_AUTH 0x00000002
|
|
#define ISC_RET_REPLAY_DETECT 0x00000004
|
|
#define ISC_RET_SEQUENCE_DETECT 0x00000008
|
|
#define ISC_REP_CONFIDENTIALITY 0x00000010
|
|
#define ISC_REP_USE_SESSION_KEY 0x00000020
|
|
#define ISC_REP_USED_COLLECTED_CREDS 0x00000040
|
|
#define ISC_REP_USED_SUPPLIED_CREDS 0x00000080
|
|
#define ISC_REP_ALLOCATED_MEMORY 0x00000100
|
|
#define ISC_REP_USED_DCE_STYLE 0x00000200
|
|
|
|
ExpirationTime - Expiration time of the context.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Message handled
|
|
SEC_I_CONTINUE_NEEDED -- Caller should call again later
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_INVALID_TOKEN -- Token improperly formatted
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_INSUFFICIENT_MEMORY -- Buffer for output token isn't big enough
|
|
SEC_E_NO_CREDENTIALS -- There are no credentials for this client
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
PVOID InputTokenBuffer;
|
|
PULONG InputTokenSize;
|
|
ULONG LocalInputTokenSize;
|
|
|
|
PVOID OutputTokenBuffer;
|
|
PULONG OutputTokenSize;
|
|
|
|
SspPrint((SSP_API, "SspInitializeSecurityContext Entered\n"));
|
|
|
|
//
|
|
// Check argument validity
|
|
//
|
|
|
|
#ifdef notdef // ? RPC passes 0x10 or 0 here depending on attitude
|
|
if ( TargetDataRep != SECURITY_NATIVE_DREP ) {
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
#else // notdef
|
|
UNREFERENCED_PARAMETER( TargetDataRep );
|
|
#endif // notdef
|
|
|
|
if ( !SspGetTokenBuffer( InputToken,
|
|
&InputTokenBuffer,
|
|
&InputTokenSize,
|
|
TRUE ) ) {
|
|
return (SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
if ( InputTokenSize == 0 ) {
|
|
InputTokenSize = &LocalInputTokenSize;
|
|
LocalInputTokenSize = 0;
|
|
}
|
|
|
|
if ( !SspGetTokenBuffer( OutputToken,
|
|
&OutputTokenBuffer,
|
|
&OutputTokenSize,
|
|
FALSE ) ) {
|
|
return (SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
//
|
|
// If no previous context was passed in this is the first call.
|
|
//
|
|
|
|
if ( !ARGUMENT_PRESENT( OldContextHandle ) ) {
|
|
|
|
if ( !ARGUMENT_PRESENT( CredentialHandle ) ) {
|
|
return (SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
return SspHandleFirstCall(
|
|
CredentialHandle,
|
|
NewContextHandle,
|
|
ContextReqFlags,
|
|
*InputTokenSize,
|
|
InputTokenBuffer,
|
|
OutputTokenSize,
|
|
OutputTokenBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime );
|
|
|
|
//
|
|
// If context was passed in, continue where we left off.
|
|
//
|
|
|
|
} else {
|
|
|
|
*NewContextHandle = *OldContextHandle;
|
|
|
|
return SspHandleChallengeMessage(
|
|
NULL,
|
|
CredentialHandle,
|
|
NewContextHandle,
|
|
ContextReqFlags,
|
|
*InputTokenSize,
|
|
InputTokenBuffer,
|
|
OutputTokenSize,
|
|
OutputTokenBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime );
|
|
}
|
|
|
|
return (SecStatus);
|
|
}
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
InitializeSecurityContextW(
|
|
IN PCredHandle CredentialHandle,
|
|
IN PCtxtHandle OldContextHandle,
|
|
IN WCHAR * TargetName,
|
|
IN ULONG ContextReqFlags,
|
|
IN ULONG Reserved1,
|
|
IN ULONG TargetDataRep,
|
|
IN PSecBufferDesc InputToken,
|
|
IN ULONG Reserved2,
|
|
OUT PCtxtHandle NewContextHandle,
|
|
OUT PSecBufferDesc OutputToken,
|
|
OUT PULONG ContextAttributes,
|
|
OUT PTimeStamp ExpirationTime
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initiates the outbound security context from a credential
|
|
handle. This results in the establishment of a security context
|
|
between the application and a remote peer. The routine returns a token
|
|
which must be passed to the remote peer which in turn submits it to the
|
|
local security implementation via the AcceptSecurityContext() call.
|
|
The token generated should be considered opaque by all callers.
|
|
|
|
This function is used by a client to initialize an outbound context.
|
|
For a two leg security package, the calling sequence is as follows: The
|
|
client calls the function with OldContextHandle set to NULL and
|
|
InputToken set either to NULL or to a pointer to a security package
|
|
specific data structure. The package returns a context handle in
|
|
NewContextHandle and a token in OutputToken. The handle can then be
|
|
used for message APIs if desired.
|
|
|
|
The OutputToken returned here is sent across to target server which
|
|
calls AcceptSecuirtyContext() with this token as an input argument and
|
|
may receive a token which is returned to the initiator so it can call
|
|
InitializeSecurityContext() again.
|
|
|
|
For a three leg (mutual authentication) security package, the calling
|
|
sequence is as follows: The client calls the function as above, but the
|
|
package will return SEC_I_CONTINUE_NEEDED. The client then sends the
|
|
output token to the server and waits for the server's reply. Upon
|
|
receipt of the server's response, the client calls this function again,
|
|
with OldContextHandle set to the handle that was returned from the
|
|
first call. The token received from the server is supplied in the
|
|
InputToken parameter. If the server has successfully responded, then
|
|
the package will respond with success, or it will invalidate the
|
|
context.
|
|
|
|
Initialization of security context may require more than one call to
|
|
this function depending upon the underlying authentication mechanism as
|
|
well as the "choices" indicated via ContextReqFlags. The
|
|
ContextReqFlags and ContextAttributes are bit masks representing
|
|
various context level functions viz. delegation, mutual
|
|
authentication, confidentiality, replay detection and sequence
|
|
detection.
|
|
|
|
When ISC_REQ_PROMPT_FOR_CREDS flag is set the security package always
|
|
prompts the user for credentials, irrespective of whether credentials
|
|
are present or not. If user indicated that the supplied credentials be
|
|
used then they will be stashed (overwriting existing ones if any) for
|
|
future use. The security packages will always prompt for credentials
|
|
if none existed, this optimizes for the most common case before a
|
|
credentials database is built. But the security packages can be
|
|
configured to not do that. Security packages will ensure that they
|
|
only prompt to the interactive user, for other logon sessions, this
|
|
flag is ignored.
|
|
|
|
When ISC_REQ_USE_SUPPLIED_CREDS flag is set the security package always
|
|
uses the credentials supplied in the InitializeSecurityContext() call
|
|
via InputToken parameter. If the package does not have any credentials
|
|
available it will prompt for them and record it as indicated above.
|
|
|
|
It is an error to set both these flags simultaneously.
|
|
|
|
If the ISC_REQ_ALLOCATE_MEMORY was specified then the caller must free
|
|
the memory pointed to by OutputToken by calling FreeContextBuffer().
|
|
|
|
For example, the InputToken may be the challenge from a LAN Manager or
|
|
NT file server. In this case, the OutputToken would be the NTLM
|
|
encrypted response to the challenge. The caller of this API can then
|
|
take the appropriate response (case-sensitive v. case-insensitive) and
|
|
return it to the server for an authenticated connection.
|
|
|
|
|
|
Arguments:
|
|
|
|
CredentialHandle - Handle to the credentials to be used to
|
|
create the context.
|
|
|
|
OldContextHandle - Handle to the partially formed context, if this is
|
|
a second call (see above) or NULL if this is the first call.
|
|
|
|
TargetName - String indicating the target of the context. The name will
|
|
be security package specific. For example it will be a fully
|
|
qualified Cairo name for Kerberos package and can be UNC name or
|
|
domain name for the NTLM package.
|
|
|
|
ContextReqFlags - Requirements of the context, package specific.
|
|
|
|
#define ISC_REQ_DELEGATE 0x00000001
|
|
#define ISC_REQ_MUTUAL_AUTH 0x00000002
|
|
#define ISC_REQ_REPLAY_DETECT 0x00000004
|
|
#define ISC_REQ_SEQUENCE_DETECT 0x00000008
|
|
#define ISC_REQ_CONFIDENTIALITY 0x00000010
|
|
#define ISC_REQ_USE_SESSION_KEY 0x00000020
|
|
#define ISC_REQ_PROMT_FOR__CREDS 0x00000040
|
|
#define ISC_REQ_USE_SUPPLIED_CREDS 0x00000080
|
|
#define ISC_REQ_ALLOCATE_MEMORY 0x00000100
|
|
#define ISC_REQ_USE_DCE_STYLE 0x00000200
|
|
|
|
Reserved1 - Reserved value, MBZ.
|
|
|
|
TargetDataRep - Long indicating the data representation (byte ordering, etc)
|
|
on the target. The constant SECURITY_NATIVE_DREP may be supplied
|
|
by the transport indicating that the native format is in use.
|
|
|
|
InputToken - Pointer to the input token. In the first call this
|
|
token can either be NULL or may contain security package specific
|
|
information.
|
|
|
|
Reserved2 - Reserved value, MBZ.
|
|
|
|
NewContextHandle - New context handle. If this is a second call, this
|
|
can be the same as OldContextHandle.
|
|
|
|
OutputToken - Buffer to receive the output token.
|
|
|
|
ContextAttributes -Attributes of the context established.
|
|
|
|
#define ISC_RET_DELEGATE 0x00000001
|
|
#define ISC_RET_MUTUAL_AUTH 0x00000002
|
|
#define ISC_RET_REPLAY_DETECT 0x00000004
|
|
#define ISC_RET_SEQUENCE_DETECT 0x00000008
|
|
#define ISC_REP_CONFIDENTIALITY 0x00000010
|
|
#define ISC_REP_USE_SESSION_KEY 0x00000020
|
|
#define ISC_REP_USED_COLLECTED_CREDS 0x00000040
|
|
#define ISC_REP_USED_SUPPLIED_CREDS 0x00000080
|
|
#define ISC_REP_ALLOCATED_MEMORY 0x00000100
|
|
#define ISC_REP_USED_DCE_STYLE 0x00000200
|
|
|
|
ExpirationTime - Expiration time of the context.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Message handled
|
|
SEC_I_CONTINUE_NEEDED -- Caller should call again later
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_INVALID_TOKEN -- Token improperly formatted
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_INSUFFICIENT_MEMORY -- Buffer for output token isn't big enough
|
|
SEC_E_NO_CREDENTIALS -- There are no credentials for this client
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
|
|
PVOID InputTokenBuffer;
|
|
PULONG InputTokenSize;
|
|
ULONG LocalInputTokenSize;
|
|
|
|
PVOID OutputTokenBuffer;
|
|
PULONG OutputTokenSize;
|
|
|
|
SspPrint((SSP_API, "SspInitializeSecurityContext Entered\n"));
|
|
|
|
//
|
|
// Check argument validity
|
|
//
|
|
|
|
#ifdef notdef // ? RPC passes 0x10 or 0 here depending on attitude
|
|
if ( TargetDataRep != SECURITY_NATIVE_DREP ) {
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
#else // notdef
|
|
UNREFERENCED_PARAMETER( TargetDataRep );
|
|
#endif // notdef
|
|
|
|
if ( !SspGetTokenBuffer( InputToken,
|
|
&InputTokenBuffer,
|
|
&InputTokenSize,
|
|
TRUE ) ) {
|
|
return (SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
if ( InputTokenSize == 0 ) {
|
|
InputTokenSize = &LocalInputTokenSize;
|
|
LocalInputTokenSize = 0;
|
|
}
|
|
|
|
if ( !SspGetTokenBuffer( OutputToken,
|
|
&OutputTokenBuffer,
|
|
&OutputTokenSize,
|
|
FALSE ) ) {
|
|
return (SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
//
|
|
// If no previous context was passed in this is the first call.
|
|
//
|
|
|
|
if ( !ARGUMENT_PRESENT( OldContextHandle ) ) {
|
|
|
|
if ( !ARGUMENT_PRESENT( CredentialHandle ) ) {
|
|
return (SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
return SspHandleFirstCall(
|
|
CredentialHandle,
|
|
NewContextHandle,
|
|
ContextReqFlags,
|
|
*InputTokenSize,
|
|
InputTokenBuffer,
|
|
OutputTokenSize,
|
|
OutputTokenBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime );
|
|
|
|
//
|
|
// If context was passed in, continue where we left off.
|
|
//
|
|
|
|
} else {
|
|
|
|
*NewContextHandle = *OldContextHandle;
|
|
|
|
return SspHandleChallengeMessage(
|
|
NULL,
|
|
CredentialHandle,
|
|
NewContextHandle,
|
|
ContextReqFlags,
|
|
*InputTokenSize,
|
|
InputTokenBuffer,
|
|
OutputTokenSize,
|
|
OutputTokenBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime );
|
|
}
|
|
|
|
return (SecStatus);
|
|
}
|
|
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcQueryContextAttributesA (
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
QueryContextAttributesA(
|
|
#endif // FOR_SSPS
|
|
IN PCtxtHandle ContextHandle,
|
|
IN ULONG Attribute,
|
|
OUT PVOID Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API allows a customer of the security services to determine
|
|
certain attributes of the context. These are: sizes, names, and
|
|
lifespan.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Handle to the context to query.
|
|
|
|
Attribute - Attribute to query.
|
|
|
|
#define SECPKG_ATTR_SIZES 0
|
|
#define SECPKG_ATTR_NAMES 1
|
|
#define SECPKG_ATTR_LIFESPAN 2
|
|
|
|
Buffer - Buffer to copy the data into. The buffer must be large enough
|
|
to fit the queried attribute.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK - Call completed successfully
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_UNSUPPORTED_FUNCTION -- Function code is not supported
|
|
|
|
--*/
|
|
|
|
{
|
|
SecPkgContext_Sizes ContextSizes;
|
|
SecPkgContext_Lifespan ContextLifespan;
|
|
UCHAR ContextNamesBuffer[sizeof(SecPkgContext_Names)+20];
|
|
PSecPkgContext_NamesA ContextNames;
|
|
int ContextNamesSize;
|
|
SECURITY_STATUS SecStatus = SEC_E_OK;
|
|
PSSP_CONTEXT Context = NULL;
|
|
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
SspPrint(( SSP_API, "SspQueryContextAttributes Entered\n" ));
|
|
|
|
//
|
|
// Find the currently existing context.
|
|
//
|
|
|
|
Context = SspContextReferenceContext( ContextHandle,
|
|
FALSE );
|
|
|
|
if ( Context == NULL ) {
|
|
SecStatus = SEC_E_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Handle each of the various queried attributes
|
|
//
|
|
|
|
switch ( Attribute) {
|
|
case SECPKG_ATTR_SIZES:
|
|
|
|
ContextSizes.cbMaxToken = MSNSP_MAX_TOKEN_SIZE;
|
|
|
|
if (Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
|
|
NTLMSSP_NEGOTIATE_SIGN |
|
|
NTLMSSP_NEGOTIATE_SEAL ))
|
|
{
|
|
ContextSizes.cbMaxSignature = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
|
|
}
|
|
else
|
|
{
|
|
ContextSizes.cbMaxSignature = 0;
|
|
}
|
|
|
|
if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL)
|
|
{
|
|
ContextSizes.cbBlockSize = 1;
|
|
ContextSizes.cbSecurityTrailer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
|
|
}
|
|
else
|
|
{
|
|
ContextSizes.cbBlockSize = 0;
|
|
ContextSizes.cbSecurityTrailer = 0;
|
|
}
|
|
|
|
memcpy(Buffer, &ContextSizes, sizeof(ContextSizes));
|
|
|
|
break;
|
|
|
|
//
|
|
// No one uses the function so don't go to the overhead of maintaining
|
|
// the username in the context structure.
|
|
//
|
|
|
|
case SECPKG_ATTR_NAMES:
|
|
|
|
ContextNames = (PSecPkgContext_NamesA)Buffer;
|
|
ContextNames->sUserName = (SEC_CHAR *) SspAlloc(1);
|
|
|
|
if (ContextNames->sUserName == NULL) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
*ContextNames->sUserName = '\0';
|
|
|
|
break;
|
|
|
|
case SECPKG_ATTR_LIFESPAN:
|
|
|
|
// Use the correct times here
|
|
ContextLifespan.tsStart = SspContextGetTimeStamp( Context, FALSE );
|
|
ContextLifespan.tsExpiry = SspContextGetTimeStamp( Context, TRUE );
|
|
|
|
memcpy(Buffer, &ContextLifespan, sizeof(ContextLifespan));
|
|
|
|
break;
|
|
|
|
default:
|
|
SecStatus = SEC_E_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Free local resources
|
|
//
|
|
Cleanup:
|
|
|
|
if ( Context != NULL ) {
|
|
SspContextDereferenceContext( Context );
|
|
}
|
|
|
|
SspPrint(( SSP_API, "SspQueryContextAttributes returns 0x%x\n", SecStatus ));
|
|
return SecStatus;
|
|
}
|
|
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcQueryContextAttributesW (
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
QueryContextAttributesW(
|
|
#endif // FOR_SSPS
|
|
IN PCtxtHandle ContextHandle,
|
|
IN ULONG Attribute,
|
|
OUT PVOID Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API allows a customer of the security services to determine
|
|
certain attributes of the context. These are: sizes, names, and
|
|
lifespan.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Handle to the context to query.
|
|
|
|
Attribute - Attribute to query.
|
|
|
|
#define SECPKG_ATTR_SIZES 0
|
|
#define SECPKG_ATTR_NAMES 1
|
|
#define SECPKG_ATTR_LIFESPAN 2
|
|
|
|
Buffer - Buffer to copy the data into. The buffer must be large enough
|
|
to fit the queried attribute.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK - Call completed successfully
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_UNSUPPORTED_FUNCTION -- Function code is not supported
|
|
|
|
--*/
|
|
|
|
{
|
|
SecPkgContext_Sizes ContextSizes;
|
|
SecPkgContext_Lifespan ContextLifespan;
|
|
UCHAR ContextNamesBuffer[sizeof(SecPkgContext_Names)+20];
|
|
PSecPkgContext_NamesW ContextNames;
|
|
int ContextNamesSize;
|
|
SECURITY_STATUS SecStatus = SEC_E_OK;
|
|
PSSP_CONTEXT Context = NULL;
|
|
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
SspPrint(( SSP_API, "SspQueryContextAttributes Entered\n" ));
|
|
|
|
//
|
|
// Find the currently existing context.
|
|
//
|
|
|
|
Context = SspContextReferenceContext( ContextHandle,
|
|
FALSE );
|
|
|
|
if ( Context == NULL ) {
|
|
SecStatus = SEC_E_INVALID_HANDLE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Handle each of the various queried attributes
|
|
//
|
|
|
|
switch ( Attribute) {
|
|
case SECPKG_ATTR_SIZES:
|
|
|
|
ContextSizes.cbMaxToken = MSNSP_MAX_TOKEN_SIZE;
|
|
|
|
if (Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
|
|
NTLMSSP_NEGOTIATE_SIGN |
|
|
NTLMSSP_NEGOTIATE_SEAL ))
|
|
{
|
|
ContextSizes.cbMaxSignature = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
|
|
}
|
|
else
|
|
{
|
|
ContextSizes.cbMaxSignature = 0;
|
|
}
|
|
|
|
if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_SEAL)
|
|
{
|
|
ContextSizes.cbBlockSize = 1;
|
|
ContextSizes.cbSecurityTrailer = NTLMSSP_MESSAGE_SIGNATURE_SIZE;
|
|
}
|
|
else
|
|
{
|
|
ContextSizes.cbBlockSize = 0;
|
|
ContextSizes.cbSecurityTrailer = 0;
|
|
}
|
|
|
|
memcpy(Buffer, &ContextSizes, sizeof(ContextSizes));
|
|
|
|
break;
|
|
|
|
//
|
|
// No one uses the function so don't go to the overhead of maintaining
|
|
// the username in the context structure.
|
|
//
|
|
|
|
case SECPKG_ATTR_NAMES:
|
|
|
|
ContextNames = (PSecPkgContext_NamesW)Buffer;
|
|
ContextNames->sUserName = (WCHAR *) SspAlloc(1);
|
|
|
|
if (ContextNames->sUserName == NULL) {
|
|
SecStatus = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
*ContextNames->sUserName = L'\0';
|
|
|
|
break;
|
|
|
|
case SECPKG_ATTR_LIFESPAN:
|
|
|
|
// Use the correct times here
|
|
ContextLifespan.tsStart = SspContextGetTimeStamp( Context, FALSE );
|
|
ContextLifespan.tsExpiry = SspContextGetTimeStamp( Context, TRUE );
|
|
|
|
memcpy(Buffer, &ContextLifespan, sizeof(ContextLifespan));
|
|
|
|
break;
|
|
|
|
default:
|
|
SecStatus = SEC_E_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Free local resources
|
|
//
|
|
Cleanup:
|
|
|
|
if ( Context != NULL ) {
|
|
SspContextDereferenceContext( Context );
|
|
}
|
|
|
|
SspPrint(( SSP_API, "SspQueryContextAttributes returns 0x%x\n", SecStatus ));
|
|
return SecStatus;
|
|
}
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcDeleteSecurityContext (
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
DeleteSecurityContext (
|
|
#endif // FOR_SSPS
|
|
PCtxtHandle ContextHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes the local data structures associated with the specified
|
|
security context and generates a token which is passed to a remote peer
|
|
so it too can remove the corresponding security context.
|
|
|
|
This API terminates a context on the local machine, and optionally
|
|
provides a token to be sent to the other machine. The OutputToken
|
|
generated by this call is to be sent to the remote peer (initiator or
|
|
acceptor). If the context was created with the I _REQ_ALLOCATE_MEMORY
|
|
flag, then the package will allocate a buffer for the output token.
|
|
Otherwise, it is the responsibility of the caller.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Handle to the context to delete
|
|
|
|
TokenLength - Size of the output token (if any) that should be sent to
|
|
the process at the other end of the session.
|
|
|
|
Token - Pointer to the token to send.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK - Call completed successfully
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus;
|
|
PSSP_CONTEXT Context = NULL;
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
SspPrint(( SSP_API, "SspDeleteSecurityContext Entered\n" ));
|
|
|
|
//
|
|
// Find the currently existing context (and delink it).
|
|
//
|
|
|
|
Context = SspContextReferenceContext( ContextHandle,
|
|
TRUE );
|
|
|
|
if ( Context == NULL ) {
|
|
SecStatus = SEC_E_INVALID_HANDLE;
|
|
goto cleanup;
|
|
} else {
|
|
SspContextDereferenceContext( Context );
|
|
SecStatus = SEC_E_OK;
|
|
}
|
|
|
|
cleanup:
|
|
|
|
if (Context != NULL) {
|
|
|
|
SspContextDereferenceContext(Context);
|
|
|
|
Context = NULL;
|
|
}
|
|
|
|
SspPrint(( SSP_API, "SspDeleteSecurityContext returns 0x%x\n", SecStatus ));
|
|
return SecStatus;
|
|
}
|
|
|
|
|
|
#ifndef FOR_SSPS // IF NOT PART OF MSNSSPS.DLL
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
FreeContextBuffer (
|
|
void * ContextBuffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This API is provided to allow callers of security API such as
|
|
InitializeSecurityContext() for free the memory buffer allocated for
|
|
returning the outbound context token.
|
|
|
|
Arguments:
|
|
|
|
ContextBuffer - Address of the buffer to be freed.
|
|
|
|
Return Value:
|
|
|
|
SEC_E_OK - Call completed successfully
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// The only allocated buffer that NtLmSsp currently returns to the caller
|
|
// is from EnumeratePackages. It uses LocalAlloc to allocate memory. If
|
|
// we ever need memory to be allocated by the service, we have to rethink
|
|
// how this routine distinguishes between to two types of allocated memory.
|
|
//
|
|
|
|
SspFree( ContextBuffer );
|
|
|
|
return (SEC_E_OK);
|
|
}
|
|
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
ApplyControlToken (
|
|
PCtxtHandle ContextHandle,
|
|
PSecBufferDesc Input
|
|
)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
SspPrint(( SSP_API, "ApplyContextToken Called\n" ));
|
|
#endif // DEBUGRPC
|
|
UNREFERENCED_PARAMETER( ContextHandle );
|
|
UNREFERENCED_PARAMETER( Input );
|
|
return SEC_E_UNSUPPORTED_FUNCTION;
|
|
}
|
|
|
|
#endif // not FOR_SSPS (NOT PART OF MSNSSPS.DLL)
|
|
|
|
void
|
|
SsprGenCheckSum(
|
|
IN PSecBuffer pMessage,
|
|
OUT PNTLMSSP_MESSAGE_SIGNATURE pSig
|
|
)
|
|
{
|
|
Crc32(pSig->CheckSum,pMessage->cbBuffer,pMessage->pvBuffer,&pSig->CheckSum);
|
|
}
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcMakeSignature(
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
MakeSignature(
|
|
#endif // FOR_SSPS
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN ULONG fQOP,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo
|
|
)
|
|
{
|
|
PSSP_CONTEXT pContext;
|
|
PNTLMSSP_MESSAGE_SIGNATURE pSig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
pContext = SspContextReferenceContext(ContextHandle,FALSE);
|
|
|
|
if (!pContext ||
|
|
(pContext->SendKey == NULL && !(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)))
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
Signature = -1;
|
|
for (i = 0; i < pMessage->cBuffers; i++)
|
|
{
|
|
if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
|
|
{
|
|
Signature = i;
|
|
break;
|
|
}
|
|
}
|
|
if (Signature == -1)
|
|
{
|
|
SspContextDereferenceContext(pContext);
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
pSig = (PNTLMSSP_MESSAGE_SIGNATURE) pMessage->pBuffers[Signature].pvBuffer;
|
|
|
|
if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN))
|
|
{
|
|
memset(pSig,0,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
|
|
pSig->Version = NTLMSSP_SIGN_VERSION;
|
|
swaplong(pSig->Version) ; // MACBUG
|
|
SspContextDereferenceContext(pContext);
|
|
return(SEC_E_OK);
|
|
}
|
|
//
|
|
// required by CRC-32 algorithm
|
|
//
|
|
|
|
pSig->CheckSum = 0xffffffff;
|
|
|
|
for (i = 0; i < pMessage->cBuffers ; i++ )
|
|
{
|
|
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
|
|
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
|
|
{
|
|
SsprGenCheckSum(&pMessage->pBuffers[i], pSig);
|
|
}
|
|
}
|
|
|
|
EnterCriticalSection(&pContext->EncryptSection);
|
|
|
|
//
|
|
// Required by CRC-32 algorithm
|
|
//
|
|
|
|
pSig->CheckSum ^= 0xffffffff;
|
|
|
|
pSig->Nonce = pContext->SendNonce++;
|
|
pSig->Version = NTLMSSP_SIGN_VERSION; // MACBUG
|
|
|
|
swaplong(pSig->CheckSum) ;
|
|
swaplong(pSig->Nonce) ;
|
|
swaplong(pSig->Version) ;
|
|
|
|
rc4(pContext->SendKey, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
(unsigned char SEC_FAR *) &pSig->RandomPad);
|
|
pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
|
|
|
|
LeaveCriticalSection(&pContext->EncryptSection);
|
|
|
|
SspContextDereferenceContext(pContext);
|
|
return(SEC_E_OK);
|
|
|
|
|
|
}
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcVerifySignature(
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
VerifySignature(
|
|
#endif // FOR_SSPS
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo,
|
|
OUT PULONG pfQOP
|
|
)
|
|
{
|
|
PSSP_CONTEXT pContext;
|
|
PNTLMSSP_MESSAGE_SIGNATURE pSig;
|
|
NTLMSSP_MESSAGE_SIGNATURE Sig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
|
|
UNREFERENCED_PARAMETER(pfQOP);
|
|
UNREFERENCED_PARAMETER(MessageSeqNo);
|
|
|
|
pContext = SspContextReferenceContext(ContextHandle,FALSE);
|
|
|
|
if (!pContext ||
|
|
(pContext->ReceiveKey == NULL && !(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_ALWAYS_SIGN)))
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
Signature = -1;
|
|
for (i = 0; i < pMessage->cBuffers; i++)
|
|
{
|
|
if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
|
|
{
|
|
Signature = i;
|
|
break;
|
|
}
|
|
}
|
|
if (Signature == -1)
|
|
{
|
|
SspContextDereferenceContext(pContext);
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
pSig = (PNTLMSSP_MESSAGE_SIGNATURE) pMessage->pBuffers[Signature].pvBuffer;
|
|
swaplong(pSig->Version) ;
|
|
|
|
//
|
|
// Check if this is just a trailer and not a real signature
|
|
//
|
|
|
|
if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN))
|
|
{
|
|
SspContextDereferenceContext(pContext);
|
|
memset(&Sig,0,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
|
|
Sig.Version = NTLMSSP_SIGN_VERSION;
|
|
if (!memcmp(&Sig,pSig,NTLMSSP_MESSAGE_SIGNATURE_SIZE))
|
|
{
|
|
return(SEC_E_OK);
|
|
}
|
|
return(SEC_E_MESSAGE_ALTERED);
|
|
}
|
|
|
|
Sig.CheckSum = 0xffffffff;
|
|
for (i = 0; i < pMessage->cBuffers ; i++ )
|
|
{
|
|
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
|
|
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
|
|
{
|
|
SsprGenCheckSum(&pMessage->pBuffers[i], &Sig);
|
|
}
|
|
}
|
|
|
|
EnterCriticalSection(&pContext->EncryptSection);
|
|
|
|
Sig.CheckSum ^= 0xffffffff;
|
|
Sig.Nonce = pContext->ReceiveNonce++;
|
|
|
|
rc4(pContext->ReceiveKey, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
(unsigned char SEC_FAR *) &pSig->RandomPad);
|
|
|
|
LeaveCriticalSection(&pContext->EncryptSection);
|
|
|
|
SspContextDereferenceContext(pContext);
|
|
|
|
swaplong(pSig->CheckSum) ;
|
|
swaplong(pSig->Nonce) ;
|
|
|
|
if (pSig->CheckSum != Sig.CheckSum)
|
|
{
|
|
return(SEC_E_MESSAGE_ALTERED);
|
|
}
|
|
|
|
if (pSig->Nonce != Sig.Nonce)
|
|
{
|
|
return(SEC_E_OUT_OF_SEQUENCE);
|
|
}
|
|
|
|
return(SEC_E_OK);
|
|
}
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcSealMessage(
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
SealMessage(
|
|
#endif // FOR_SSPS
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN ULONG fQOP,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo
|
|
)
|
|
{
|
|
PSSP_CONTEXT pContext;
|
|
PNTLMSSP_MESSAGE_SIGNATURE pSig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(fQOP);
|
|
UNREFERENCED_PARAMETER(MessageSeqNo);
|
|
|
|
pContext = SspContextReferenceContext(ContextHandle, FALSE);
|
|
|
|
if (!pContext || pContext->SendKey == NULL)
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
Signature = -1;
|
|
for (i = 0; i < pMessage->cBuffers; i++)
|
|
{
|
|
if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
|
|
{
|
|
Signature = i;
|
|
break;
|
|
}
|
|
}
|
|
if (Signature == -1)
|
|
{
|
|
SspContextDereferenceContext(pContext);
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
pSig = (PNTLMSSP_MESSAGE_SIGNATURE) pMessage->pBuffers[Signature].pvBuffer;
|
|
|
|
EnterCriticalSection(&pContext->EncryptSection);
|
|
|
|
//
|
|
// required by CRC-32 algorithm
|
|
//
|
|
|
|
pSig->CheckSum = 0xffffffff;
|
|
|
|
for (i = 0; i < pMessage->cBuffers ; i++ )
|
|
{
|
|
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
|
|
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
|
|
{
|
|
SsprGenCheckSum(&pMessage->pBuffers[i], pSig);
|
|
rc4(pContext->SendKey, (int) pMessage->pBuffers[i].cbBuffer, (PUCHAR) pMessage->pBuffers[i].pvBuffer );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Required by CRC-32 algorithm
|
|
//
|
|
|
|
pSig->CheckSum ^= 0xffffffff;
|
|
|
|
pSig->Nonce = pContext->SendNonce++;
|
|
pSig->Version = NTLMSSP_SIGN_VERSION; // MACBUG
|
|
|
|
swaplong(pSig->CheckSum) ;
|
|
swaplong(pSig->Nonce) ;
|
|
swaplong(pSig->Version) ;
|
|
|
|
rc4(pContext->SendKey, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
(PUCHAR) &pSig->RandomPad);
|
|
pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
|
|
|
|
LeaveCriticalSection(&pContext->EncryptSection);
|
|
|
|
SspContextDereferenceContext(pContext);
|
|
|
|
return(SEC_E_OK);
|
|
|
|
|
|
}
|
|
|
|
|
|
#ifdef FOR_SSPS // IF PART OF MSNSSPS.DLL
|
|
SECURITY_STATUS
|
|
SspcUnsealMessage(
|
|
#else // OTHERWISE PART OF MSNSSPC.DLL
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
UnsealMessage(
|
|
#endif // FOR_SSPS
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo,
|
|
OUT PULONG pfQOP
|
|
)
|
|
{
|
|
PSSP_CONTEXT pContext;
|
|
PNTLMSSP_MESSAGE_SIGNATURE pSig;
|
|
NTLMSSP_MESSAGE_SIGNATURE Sig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(pfQOP);
|
|
UNREFERENCED_PARAMETER(MessageSeqNo);
|
|
|
|
pContext = SspContextReferenceContext(ContextHandle, FALSE);
|
|
|
|
if (!pContext || !pContext->ReceiveKey)
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
Signature = -1;
|
|
for (i = 0; i < pMessage->cBuffers; i++)
|
|
{
|
|
if ((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_TOKEN)
|
|
{
|
|
Signature = i;
|
|
break;
|
|
}
|
|
}
|
|
if (Signature == -1)
|
|
{
|
|
SspContextDereferenceContext(pContext);
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
pSig = (PNTLMSSP_MESSAGE_SIGNATURE) pMessage->pBuffers[Signature].pvBuffer;
|
|
|
|
EnterCriticalSection(&pContext->EncryptSection);
|
|
|
|
Sig.CheckSum = 0xffffffff;
|
|
for (i = 0; i < pMessage->cBuffers ; i++ )
|
|
{
|
|
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
|
|
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
|
|
{
|
|
rc4(pContext->ReceiveKey, (int) pMessage->pBuffers[i].cbBuffer, (unsigned char *) pMessage->pBuffers[i].pvBuffer );
|
|
SsprGenCheckSum(&pMessage->pBuffers[i], &Sig);
|
|
}
|
|
}
|
|
|
|
Sig.CheckSum ^= 0xffffffff;
|
|
Sig.Nonce = pContext->ReceiveNonce++;
|
|
|
|
rc4(pContext->ReceiveKey, sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
(unsigned char *) &pSig->RandomPad);
|
|
|
|
LeaveCriticalSection(&pContext->EncryptSection);
|
|
|
|
SspContextDereferenceContext(pContext);
|
|
|
|
swaplong(pSig->Nonce) ;
|
|
swaplong(pSig->CheckSum) ;
|
|
|
|
if (pSig->Nonce != Sig.Nonce)
|
|
{
|
|
return(SEC_E_OUT_OF_SEQUENCE);
|
|
}
|
|
|
|
if (pSig->CheckSum != Sig.CheckSum)
|
|
{
|
|
return(SEC_E_MESSAGE_ALTERED);
|
|
}
|
|
|
|
return(SEC_E_OK);
|
|
}
|
|
|
|
#ifndef FOR_SSPS // IF NOT PART OF MSNSSPS.DLL
|
|
|
|
MSNSSP_DLL SECURITY_STATUS SEC_ENTRY
|
|
CompleteAuthToken (
|
|
PCtxtHandle ContextHandle,
|
|
PSecBufferDesc BufferDescriptor
|
|
)
|
|
{
|
|
#ifdef DEBUGRPC
|
|
SspPrint(( SSP_API, "CompleteAuthToken Called\n" ));
|
|
#endif // DEBUGRPC
|
|
UNREFERENCED_PARAMETER( ContextHandle );
|
|
UNREFERENCED_PARAMETER( BufferDescriptor );
|
|
return SEC_E_UNSUPPORTED_FUNCTION;
|
|
}
|
|
|
|
#endif // not FOR_SSPS (NOT PART OF MSNSSPS.DLL)
|
|
|
|
#if 0 // commented out
|
|
//
|
|
// Setup registry entry for msnsspc.dll
|
|
// This function only *adds* to the registry if it does not already exist.
|
|
//
|
|
VOID
|
|
SspCreateSspiReg(
|
|
VOID
|
|
)
|
|
{
|
|
HKEY hConfigKey;
|
|
char szSspRegKey[] = TEXT("SYSTEM\\CurrentControlSet\\Control\\SecurityProviders");
|
|
char szSecurityProv[] = TEXT("SecurityProviders");
|
|
char szSspiSetup[] = TEXT("msnsspc.dll");
|
|
char szSspsName[] = TEXT("msnssps.dll");
|
|
char szRegValue[80];
|
|
char *pEndStr, *pBegStr;
|
|
LONG dwErr;
|
|
DWORD dwDis;
|
|
DWORD dwValType, dwBufSize, dwValueLen;
|
|
int ii;
|
|
|
|
dwErr = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
szSspRegKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hConfigKey);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwErr = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
|
|
szSspRegKey,
|
|
0,
|
|
"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hConfigKey,
|
|
&dwDis);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspCreateSspiReg: RegCreateKeyEx Failed\n" ));
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check if the registry is already setup for msnsspc.dll
|
|
//
|
|
dwBufSize = sizeof (szRegValue);
|
|
dwValType = REG_SZ;
|
|
|
|
dwErr = RegQueryValueEx (hConfigKey,
|
|
szSecurityProv,
|
|
NULL,
|
|
&dwValType,
|
|
(LPBYTE) szRegValue,
|
|
&dwBufSize);
|
|
//
|
|
// If the registry does not exist yet, simply add one for msnsspc.dll
|
|
//
|
|
if (dwErr != ERROR_SUCCESS)
|
|
strcpy (szRegValue, szSspiSetup);
|
|
else
|
|
{
|
|
//
|
|
// If there's already an registry entry for security providers
|
|
// Scan registry value data for "msnsspc.dll" and "msnssps.dll"
|
|
//
|
|
|
|
dwValueLen = strlen (szSspiSetup);
|
|
pBegStr = szRegValue;
|
|
do
|
|
{
|
|
// Strip leading blanks
|
|
while (*pBegStr == ' ') ++pBegStr;
|
|
|
|
if (_strnicmp (pBegStr, szSspiSetup, dwValueLen) == 0)
|
|
{
|
|
RegCloseKey (hConfigKey);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// If it already has msnssps.dll in the registry, we don't
|
|
// want to add msnsspc.dll to the registry then.
|
|
//
|
|
if (_strnicmp (pBegStr, szSspsName, strlen(szSspsName)) == 0)
|
|
{
|
|
RegCloseKey (hConfigKey);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Find next SSPI dll name in the registry
|
|
//
|
|
pEndStr = strchr (pBegStr, ',');
|
|
if (pEndStr)
|
|
pBegStr = pEndStr + 1;
|
|
}
|
|
while (pEndStr);
|
|
|
|
//
|
|
// So the existing registry does not include msnsspc.dll
|
|
// Add msnsspc.dll to the current registry value data
|
|
//
|
|
// Remove trailing blanks from the existing value data, if any
|
|
//
|
|
for (ii = strlen(szRegValue); ii > 0 && szRegValue[ii-1] == ' '; ii--);
|
|
|
|
if (ii > 0)
|
|
sprintf ((char *)(szRegValue + ii), ", %s", szSspiSetup);
|
|
else
|
|
strcpy (szRegValue, szSspiSetup);
|
|
}
|
|
|
|
//
|
|
// Set the registry for msnsspc.dll
|
|
//
|
|
dwValueLen = strlen (szRegValue) + 1;
|
|
dwValType = REG_SZ;
|
|
|
|
dwErr = RegSetValueEx (hConfigKey,
|
|
szSecurityProv,
|
|
0,
|
|
dwValType,
|
|
(CONST BYTE *) szRegValue,
|
|
dwValueLen);
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspCreateSspiReg: RegSetValueEx Failed\n" ));
|
|
#endif
|
|
}
|
|
|
|
RegCloseKey (hConfigKey);
|
|
}
|
|
|
|
//
|
|
// Setup registry entry for secsspi.dll
|
|
//
|
|
VOID
|
|
SspCreateSpmReg(
|
|
VOID
|
|
)
|
|
{
|
|
HKEY hConfigKey;
|
|
char szSpmRegKey[] = TEXT("SOFTWARE\\Microsoft\\Internet Explorer\\SecurityProtocols");
|
|
char szSpmProtocol[] = TEXT("MSN");
|
|
char szSpmSetup[] = TEXT("Ssp_Load,secsspi.dll");
|
|
LONG dwErr;
|
|
DWORD dwDis;
|
|
DWORD dwValType, dwBufSize;
|
|
|
|
dwErr = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
szSpmRegKey,
|
|
0,
|
|
KEY_ALL_ACCESS,
|
|
&hConfigKey);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
dwErr = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
|
|
szSpmRegKey,
|
|
0,
|
|
"",
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hConfigKey,
|
|
&dwDis);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspCreateSpmReg: RegCreateKeyEx Failed\n" ));
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
dwBufSize = strlen (szSpmSetup) + 1;
|
|
dwValType = REG_SZ;
|
|
|
|
dwErr = RegSetValueEx (hConfigKey,
|
|
szSpmProtocol,
|
|
0,
|
|
dwValType,
|
|
(CONST BYTE *) szSpmSetup,
|
|
dwBufSize);
|
|
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
#ifdef DEBUGRPC_DETAIL
|
|
SspPrint(( SSP_API, "SspCreateSpmReg: RegSetValueEx Failed\n" ));
|
|
#endif
|
|
}
|
|
|
|
RegCloseKey (hConfigKey);
|
|
}
|
|
#endif // commented out
|
|
|