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.
1811 lines
36 KiB
1811 lines
36 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sign.c
|
|
|
|
Abstract:
|
|
|
|
API and support routines for handling local security contexts.
|
|
|
|
Author:
|
|
|
|
MikeSw
|
|
|
|
Revision History:
|
|
|
|
29-Mar-1995 MikeSw Added SspCreateTokenDacl
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// Common include files.
|
|
//
|
|
|
|
#include <ntlmcomn.h> // Common definitions for DLL and SERVICE
|
|
#include <ntlmsspi.h> // Data private to the common routines
|
|
#include <ntlmsspc.h> // Include files common to DLL side of NtLmSsp
|
|
#include <crypt.h> // Encryption constants and routine
|
|
#include <rc4.h> // How to use RC4 routine
|
|
#include <ntseapi.h> // token information
|
|
#include "crc32.h" // How to use crc32
|
|
|
|
typedef struct _CheaterContext {
|
|
struct _CheaterContext *pNext;
|
|
CtxtHandle hContext;
|
|
TimeStamp PasswordExpiry;
|
|
ULONG NegotiateFlags;
|
|
HANDLE TokenHandle;
|
|
ULONG Nonce;
|
|
LPWSTR ContextNames;
|
|
struct RC4_KEYSTRUCT Rc4Key;
|
|
UCHAR SessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
|
|
} CheaterContext, * PCheaterContext;
|
|
|
|
CRITICAL_SECTION csCheaterList;
|
|
PCheaterContext pCheaterList;
|
|
|
|
NTSTATUS
|
|
SspGetTokenUser(
|
|
HANDLE Token,
|
|
PTOKEN_USER * pTokenUser
|
|
)
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Gets the TOKEN_USER from an open token
|
|
|
|
Arguments:
|
|
|
|
Token - Handle to a token open for TOKEN_QUERY access
|
|
|
|
Return Value:
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - not enough memory to complete the
|
|
function.
|
|
|
|
Errors from NtQueryInformationToken.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTOKEN_USER LocalTokenUser = NULL;
|
|
NTSTATUS Status;
|
|
ULONG TokenUserSize = 0;
|
|
|
|
//
|
|
// Query the token user. First pass in NULL to get back the
|
|
// required size.
|
|
//
|
|
|
|
Status = NtQueryInformationToken(
|
|
Token,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&TokenUserSize
|
|
);
|
|
|
|
if (Status != STATUS_BUFFER_TOO_SMALL)
|
|
{
|
|
ASSERT(Status != STATUS_SUCCESS);
|
|
return(Status);
|
|
}
|
|
|
|
//
|
|
// Now allocate the required ammount of memory and try again.
|
|
//
|
|
|
|
LocalTokenUser = (PTOKEN_USER) LocalAlloc(0,TokenUserSize);
|
|
if (LocalTokenUser == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
Status = NtQueryInformationToken(
|
|
Token,
|
|
TokenUser,
|
|
LocalTokenUser,
|
|
TokenUserSize,
|
|
&TokenUserSize
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
*pTokenUser = LocalTokenUser;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(LocalTokenUser);
|
|
}
|
|
return(Status);
|
|
}
|
|
|
|
NTSTATUS
|
|
SspCreateTokenDacl(
|
|
HANDLE Token
|
|
)
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Creates a new DACL for the token granting the server and client
|
|
all access to the token.
|
|
|
|
Arguments:
|
|
|
|
Token - Handle to an impersonation token open for TOKEN_QUERY and
|
|
WRITE_DAC
|
|
|
|
Return Value:
|
|
|
|
STATUS_INSUFFICIENT_RESOURCES - insufficient memory to complete
|
|
the function.
|
|
|
|
Errors from NtSetSecurityObject
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PTOKEN_USER ProcessTokenUser = NULL;
|
|
PTOKEN_USER ThreadTokenUser = NULL;
|
|
HANDLE ProcessToken = NULL;
|
|
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
|
|
ULONG AclLength;
|
|
PACL NewDacl = NULL;
|
|
SECURITY_DESCRIPTOR SecurityDescriptor;
|
|
|
|
//
|
|
// Build the two well known sids we need.
|
|
//
|
|
|
|
EnterCriticalSection(&csCheaterList);
|
|
|
|
if (SspGlobalLocalSystemSid == NULL)
|
|
{
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&NtAuthority,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0,0,0,0,0,0,0,
|
|
&SspGlobalLocalSystemSid
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
LeaveCriticalSection(&csCheaterList);
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if (SspGlobalAliasAdminsSid == NULL)
|
|
{
|
|
|
|
Status = RtlAllocateAndInitializeSid(
|
|
&NtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0,0,0,0,0,0,
|
|
&SspGlobalAliasAdminsSid
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
LeaveCriticalSection(&csCheaterList);
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&csCheaterList);
|
|
|
|
//
|
|
// Open the process token to find out the user sid
|
|
//
|
|
|
|
Status = NtOpenProcessToken(
|
|
NtCurrentProcess(),
|
|
TOKEN_QUERY,
|
|
&ProcessToken
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = SspGetTokenUser(
|
|
ProcessToken,
|
|
&ProcessTokenUser
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Now get the token user for the thread.
|
|
//
|
|
Status = SspGetTokenUser(
|
|
Token,
|
|
&ThreadTokenUser
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
AclLength = 4 * sizeof( ACCESS_ALLOWED_ACE ) - 4 * sizeof( ULONG ) +
|
|
RtlLengthSid( ProcessTokenUser->User.Sid ) +
|
|
RtlLengthSid( ThreadTokenUser->User.Sid ) +
|
|
RtlLengthSid( SspGlobalLocalSystemSid ) +
|
|
RtlLengthSid( SspGlobalAliasAdminsSid ) +
|
|
sizeof( ACL );
|
|
|
|
NewDacl = LocalAlloc(0, AclLength );
|
|
|
|
if (NewDacl == NULL) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 );
|
|
ASSERT(NT_SUCCESS( Status ));
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
NewDacl,
|
|
ACL_REVISION2,
|
|
TOKEN_ALL_ACCESS,
|
|
ProcessTokenUser->User.Sid
|
|
);
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
NewDacl,
|
|
ACL_REVISION2,
|
|
TOKEN_ALL_ACCESS,
|
|
ThreadTokenUser->User.Sid
|
|
);
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
NewDacl,
|
|
ACL_REVISION2,
|
|
TOKEN_ALL_ACCESS,
|
|
SspGlobalAliasAdminsSid
|
|
);
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
Status = RtlAddAccessAllowedAce (
|
|
NewDacl,
|
|
ACL_REVISION2,
|
|
TOKEN_ALL_ACCESS,
|
|
SspGlobalLocalSystemSid
|
|
);
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
Status = RtlCreateSecurityDescriptor (
|
|
&SecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION
|
|
);
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
Status = RtlSetDaclSecurityDescriptor(
|
|
&SecurityDescriptor,
|
|
TRUE,
|
|
NewDacl,
|
|
FALSE
|
|
);
|
|
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
Status = NtSetSecurityObject(
|
|
Token,
|
|
DACL_SECURITY_INFORMATION,
|
|
&SecurityDescriptor
|
|
);
|
|
|
|
ASSERT( NT_SUCCESS( Status ));
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (ThreadTokenUser != NULL) {
|
|
LocalFree( ThreadTokenUser );
|
|
}
|
|
|
|
if (ProcessTokenUser != NULL) {
|
|
LocalFree( ProcessTokenUser );
|
|
}
|
|
|
|
if (NewDacl != NULL) {
|
|
LocalFree( NewDacl );
|
|
}
|
|
|
|
if (ProcessToken != NULL)
|
|
{
|
|
NtClose(ProcessToken);
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SspInitLocalContexts(VOID)
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Initializes the local context list
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
InitializeCriticalSection(&csCheaterList);
|
|
pCheaterList = NULL;
|
|
}
|
|
|
|
PCheaterContext
|
|
SspLocateLocalContext(
|
|
IN PCtxtHandle phContext
|
|
)
|
|
{
|
|
PCheaterContext pContext;
|
|
|
|
EnterCriticalSection(&csCheaterList);
|
|
|
|
pContext = pCheaterList;
|
|
|
|
while (pContext)
|
|
{
|
|
if (pContext->hContext.dwUpper == phContext->dwUpper)
|
|
{
|
|
break;
|
|
}
|
|
pContext = pContext->pNext;
|
|
}
|
|
|
|
LeaveCriticalSection(&csCheaterList);
|
|
|
|
return(pContext);
|
|
}
|
|
|
|
PCheaterContext
|
|
SspAddLocalContext(
|
|
IN PCtxtHandle phContext,
|
|
IN PUCHAR pSessionKey,
|
|
IN ULONG NegotiateFlags,
|
|
IN HANDLE TokenHandle,
|
|
IN LPWSTR ContextNames
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Adds a context to the list of local contexts. If TokenHandle is
|
|
present, it will re-assign security to the token.
|
|
|
|
Arguments:
|
|
|
|
phContext - Context handle of this context.
|
|
pSessionKey - Session key of this context.
|
|
NegotiateFlags - NegotiateFlags of this context.
|
|
TokenHandle - Handle to a token for this context.
|
|
ContextNames - Name for this context.
|
|
|
|
Return Value:
|
|
|
|
Pointer to a new context, or NULL.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext pContext;
|
|
|
|
|
|
if (TokenHandle != NULL)
|
|
{
|
|
if (FAILED(SspCreateTokenDacl(TokenHandle)))
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
}
|
|
|
|
pContext = LocalAlloc( LMEM_ZEROINIT, sizeof(CheaterContext) );
|
|
|
|
if (!pContext)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
pContext->NegotiateFlags = NegotiateFlags;
|
|
|
|
#ifndef EXPORT_BUILD
|
|
if (NegotiateFlags & NTLMSSP_NEGOTIATE_STRONG_CRYPT) {
|
|
|
|
RtlCopyMemory( pContext->SessionKey,
|
|
pSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
} else
|
|
#endif // EXPORT_BUILD
|
|
|
|
if (NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) {
|
|
|
|
RtlCopyMemory( pContext->SessionKey,
|
|
pSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH);
|
|
} else {
|
|
|
|
RtlCopyMemory( pContext->SessionKey,
|
|
pSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
}
|
|
|
|
pContext->hContext = *phContext;
|
|
pContext->TokenHandle = TokenHandle;
|
|
|
|
pContext->ContextNames = (LPWSTR) LocalAlloc(0, (wcslen(ContextNames) + 1) * sizeof(WCHAR));
|
|
if (pContext->ContextNames == NULL)
|
|
{
|
|
LocalFree(pContext);
|
|
return(NULL);
|
|
}
|
|
wcscpy(pContext->ContextNames, ContextNames);
|
|
|
|
|
|
EnterCriticalSection(&csCheaterList);
|
|
|
|
ASSERT(SspLocateLocalContext(phContext) == NULL);
|
|
|
|
pContext->pNext = pCheaterList;
|
|
pCheaterList = pContext;
|
|
|
|
LeaveCriticalSection(&csCheaterList);
|
|
|
|
return(pContext);
|
|
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SspDeleteLocalContext(
|
|
IN PCheaterContext pContext
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Deletes a local context from the list of local context
|
|
|
|
Arguments:
|
|
|
|
pContext - Context to delete.
|
|
|
|
Return Value:
|
|
|
|
TRUE - the context was deleted
|
|
FALSE - the context was not on the list
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext pSearch;
|
|
BOOLEAN bRet = TRUE;
|
|
|
|
EnterCriticalSection(&csCheaterList);
|
|
|
|
// Two cases: Either this heads the list, or it doesn't.
|
|
|
|
if (pContext == pCheaterList)
|
|
{
|
|
pCheaterList = pContext->pNext;
|
|
}
|
|
else
|
|
{
|
|
pSearch = pCheaterList;
|
|
while ((pSearch) && (pSearch->pNext != pContext))
|
|
{
|
|
pSearch = pSearch->pNext;
|
|
}
|
|
if (pSearch == NULL)
|
|
{
|
|
bRet = FALSE;
|
|
}
|
|
else
|
|
{
|
|
pSearch->pNext = pContext->pNext;
|
|
}
|
|
|
|
}
|
|
|
|
LeaveCriticalSection(&csCheaterList);
|
|
|
|
return(bRet);
|
|
}
|
|
|
|
VOID
|
|
SspHandleLocalDelete(
|
|
IN PCtxtHandle phContext
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Handle deleting the local context for a real context
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext pcContext;
|
|
|
|
pcContext = SspLocateLocalContext(phContext);
|
|
if (pcContext)
|
|
{
|
|
if (pcContext->TokenHandle != NULL)
|
|
{
|
|
NtClose(pcContext->TokenHandle);
|
|
}
|
|
if (SspDeleteLocalContext(pcContext)) {
|
|
if (pcContext->ContextNames != NULL)
|
|
{
|
|
LocalFree(pcContext->ContextNames);
|
|
}
|
|
LocalFree(pcContext);
|
|
}
|
|
else SspPrint(( SSP_CRITICAL, "Error deleting known context!\n" ));
|
|
}
|
|
}
|
|
|
|
SECURITY_STATUS
|
|
SspMapContext(
|
|
IN PCtxtHandle phContext,
|
|
IN PUCHAR pSessionKey,
|
|
IN ULONG NegotiateFlags,
|
|
IN HANDLE TokenHandle,
|
|
IN LPWSTR ContextNames,
|
|
IN PTimeStamp PasswordExpiry OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Create a local context for a real context
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS scRet = SEC_E_OK;
|
|
PCheaterContext pContext;
|
|
|
|
|
|
pContext = SspAddLocalContext(
|
|
phContext,
|
|
pSessionKey,
|
|
NegotiateFlags,
|
|
TokenHandle,
|
|
ContextNames );
|
|
|
|
if (pContext)
|
|
{
|
|
if (ARGUMENT_PRESENT(PasswordExpiry))
|
|
{
|
|
pContext->PasswordExpiry = *PasswordExpiry;
|
|
}
|
|
else
|
|
{
|
|
pContext->PasswordExpiry.QuadPart = 0;
|
|
}
|
|
pContext->Nonce = 0;
|
|
#ifndef EXPORT_BUILD
|
|
if ((NegotiateFlags & NTLMSSP_NEGOTIATE_STRONG_CRYPT) != 0) {
|
|
rc4_key(&pContext->Rc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pContext->SessionKey);
|
|
|
|
} else
|
|
#endif
|
|
if (NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY)
|
|
{
|
|
UCHAR Key[MSV1_0_LANMAN_SESSION_KEY_LENGTH];
|
|
|
|
ASSERT(MSV1_0_LANMAN_SESSION_KEY_LENGTH == 8);
|
|
|
|
RtlCopyMemory(Key,pContext->SessionKey,5);
|
|
|
|
//
|
|
// 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;
|
|
|
|
rc4_key(&pContext->Rc4Key, MSV1_0_LANMAN_SESSION_KEY_LENGTH, Key);
|
|
} else {
|
|
rc4_key(&pContext->Rc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pContext->SessionKey);
|
|
}
|
|
}
|
|
else scRet = SEC_E_INVALID_HANDLE;
|
|
|
|
return(scRet);
|
|
}
|
|
|
|
|
|
//
|
|
// Bogus add-shift check sum
|
|
//
|
|
|
|
void
|
|
SspGenCheckSum(
|
|
IN PSecBuffer pMessage,
|
|
OUT PNTLMSSP_MESSAGE_SIGNATURE pSig
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Generate a crc-32 checksum for a buffer
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
Crc32(pSig->CheckSum,pMessage->cbBuffer,pMessage->pvBuffer,&pSig->CheckSum);
|
|
}
|
|
|
|
|
|
VOID
|
|
SspEncryptBuffer(
|
|
IN PCheaterContext pContext,
|
|
IN ULONG BufferSize,
|
|
IN OUT PVOID Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Encrypts a buffer with the RC4 key in the context. If the context
|
|
is for a datagram session, then the key is copied before being used
|
|
to encrypt the buffer.
|
|
|
|
Arguments:
|
|
|
|
pContext - Context containing the key to encrypt the data
|
|
|
|
BufferSize - Length of buffer in bytes
|
|
|
|
Buffer - Buffer to encrypt.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
struct RC4_KEYSTRUCT TemporaryKey;
|
|
struct RC4_KEYSTRUCT * EncryptionKey = &pContext->Rc4Key;
|
|
|
|
if (BufferSize == 0)
|
|
{
|
|
return;
|
|
}
|
|
//
|
|
// For datagram we copy the key before encrypting so we don't
|
|
// have a changing key.
|
|
//
|
|
|
|
if ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) != 0) {
|
|
RtlCopyMemory(
|
|
&TemporaryKey,
|
|
&pContext->Rc4Key,
|
|
sizeof(struct RC4_KEYSTRUCT)
|
|
);
|
|
EncryptionKey = &TemporaryKey;
|
|
|
|
}
|
|
|
|
rc4(
|
|
EncryptionKey,
|
|
BufferSize,
|
|
Buffer
|
|
);
|
|
}
|
|
|
|
SECURITY_STATUS
|
|
SspHandleSignMessage(
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN ULONG fQOP,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Handle signing a message
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext pContext;
|
|
NTLMSSP_MESSAGE_SIGNATURE Sig;
|
|
PVOID pSig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(fQOP);
|
|
UNREFERENCED_PARAMETER(MessageSeqNo);
|
|
pContext = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (!pContext)
|
|
{
|
|
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)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
if (pMessage->pBuffers[Signature].cbBuffer < NTLMSSP_MESSAGE_SIGNATURE_SIZE)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
pSig = pMessage->pBuffers[Signature].pvBuffer;
|
|
|
|
//
|
|
// If sequence detect wasn't requested, put on an empty
|
|
// security token
|
|
//
|
|
|
|
if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN))
|
|
{
|
|
RtlZeroMemory(&Sig,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
|
|
Sig.Version = NTLMSSP_SIGN_VERSION;
|
|
RtlCopyMemory(
|
|
pSig,
|
|
&Sig,
|
|
NTLMSSP_MESSAGE_SIGNATURE_SIZE
|
|
);
|
|
return(SEC_E_OK);
|
|
}
|
|
|
|
//
|
|
// required by CRC-32 algorithm
|
|
//
|
|
|
|
Sig.CheckSum = 0xffffffff;
|
|
|
|
for (i = 0; i < pMessage->cBuffers ; i++ )
|
|
{
|
|
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
|
|
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY))
|
|
{
|
|
SspGenCheckSum(&pMessage->pBuffers[i], &Sig);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Required by CRC-32 algorithm
|
|
//
|
|
|
|
Sig.CheckSum ^= 0xffffffff;
|
|
|
|
//
|
|
// For datagram we rely on the message sequence number.
|
|
//
|
|
|
|
|
|
if ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) == 0)
|
|
{
|
|
Sig.Nonce = pContext->Nonce++;
|
|
}
|
|
else
|
|
{
|
|
Sig.Nonce = MessageSeqNo;
|
|
}
|
|
|
|
Sig.Version = NTLMSSP_SIGN_VERSION;
|
|
|
|
SspEncryptBuffer(
|
|
pContext,
|
|
sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
&Sig.RandomPad
|
|
);
|
|
|
|
pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
|
|
|
|
RtlCopyMemory(
|
|
pSig,
|
|
&Sig,
|
|
NTLMSSP_MESSAGE_SIGNATURE_SIZE
|
|
);
|
|
|
|
|
|
return(SEC_E_OK);
|
|
|
|
|
|
}
|
|
|
|
SECURITY_STATUS
|
|
SspHandleVerifyMessage(
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo,
|
|
OUT PULONG pfQOP
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Handle verifying a signed message
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext pContext;
|
|
NTLMSSP_MESSAGE_SIGNATURE MessageSig;
|
|
NTLMSSP_MESSAGE_SIGNATURE Sig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(pfQOP);
|
|
UNREFERENCED_PARAMETER(MessageSeqNo);
|
|
|
|
pContext = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (!pContext)
|
|
{
|
|
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)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
if (pMessage->pBuffers[Signature].cbBuffer < NTLMSSP_MESSAGE_SIGNATURE_SIZE)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
&MessageSig,
|
|
pMessage->pBuffers[Signature].pvBuffer,
|
|
NTLMSSP_MESSAGE_SIGNATURE_SIZE
|
|
);
|
|
|
|
//
|
|
// If sequence detect wasn't requested, put on an empty
|
|
// security token
|
|
//
|
|
|
|
if (!(pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_SIGN))
|
|
{
|
|
|
|
RtlZeroMemory(&Sig,NTLMSSP_MESSAGE_SIGNATURE_SIZE);
|
|
Sig.Version = NTLMSSP_SIGN_VERSION;
|
|
if (!memcmp( &Sig, &MessageSig, 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))
|
|
{
|
|
SspGenCheckSum(&pMessage->pBuffers[i], &Sig);
|
|
}
|
|
}
|
|
|
|
Sig.CheckSum ^= 0xffffffff;
|
|
|
|
//
|
|
// For datagram, rely on the message sequence number
|
|
//
|
|
|
|
if ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) == 0)
|
|
{
|
|
Sig.Nonce = pContext->Nonce++;
|
|
}
|
|
else
|
|
{
|
|
Sig.Nonce = MessageSeqNo;
|
|
}
|
|
Sig.Version = NTLMSSP_SIGN_VERSION;
|
|
|
|
SspEncryptBuffer(
|
|
pContext,
|
|
sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
&MessageSig.RandomPad
|
|
);
|
|
|
|
|
|
|
|
if (MessageSig.CheckSum != Sig.CheckSum)
|
|
{
|
|
return(SEC_E_MESSAGE_ALTERED);
|
|
}
|
|
|
|
if (MessageSig.Nonce != Sig.Nonce)
|
|
{
|
|
return(SEC_E_OUT_OF_SEQUENCE);
|
|
}
|
|
|
|
|
|
return(SEC_E_OK);
|
|
|
|
}
|
|
|
|
SECURITY_STATUS
|
|
SspHandleSealMessage(
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN ULONG fQOP,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Handle encrypting a message
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext pContext;
|
|
NTLMSSP_MESSAGE_SIGNATURE Sig;
|
|
PVOID pSig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(fQOP);
|
|
UNREFERENCED_PARAMETER(MessageSeqNo);
|
|
pContext = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (!pContext)
|
|
{
|
|
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)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
if (pMessage->pBuffers[Signature].cbBuffer < NTLMSSP_MESSAGE_SIGNATURE_SIZE)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
pSig = pMessage->pBuffers[Signature].pvBuffer;
|
|
|
|
//
|
|
// required by CRC-32 algorithm
|
|
//
|
|
|
|
Sig.CheckSum = 0xffffffff;
|
|
|
|
for (i = 0; i < pMessage->cBuffers ; i++ )
|
|
{
|
|
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
|
|
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY) &&
|
|
(pMessage->pBuffers[i].cbBuffer != 0))
|
|
{
|
|
SspGenCheckSum(&pMessage->pBuffers[i], &Sig);
|
|
SspEncryptBuffer(
|
|
pContext,
|
|
pMessage->pBuffers[i].cbBuffer,
|
|
pMessage->pBuffers[i].pvBuffer
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Required by CRC-32 algorithm
|
|
//
|
|
|
|
Sig.CheckSum ^= 0xffffffff;
|
|
|
|
//
|
|
// For datagram we rely on the message sequence number.
|
|
//
|
|
|
|
if ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) == 0)
|
|
{
|
|
Sig.Nonce = pContext->Nonce++;
|
|
}
|
|
else
|
|
{
|
|
Sig.Nonce = MessageSeqNo;
|
|
}
|
|
|
|
|
|
Sig.Version = NTLMSSP_SIGN_VERSION;
|
|
|
|
SspEncryptBuffer(
|
|
pContext,
|
|
sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
&Sig.RandomPad
|
|
);
|
|
pMessage->pBuffers[Signature].cbBuffer = sizeof(NTLMSSP_MESSAGE_SIGNATURE);
|
|
|
|
RtlCopyMemory(
|
|
pSig,
|
|
&Sig,
|
|
NTLMSSP_MESSAGE_SIGNATURE_SIZE
|
|
);
|
|
|
|
return(SEC_E_OK);
|
|
|
|
|
|
}
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspHandleUnsealMessage(
|
|
IN OUT PCtxtHandle ContextHandle,
|
|
IN OUT PSecBufferDesc pMessage,
|
|
IN ULONG MessageSeqNo,
|
|
OUT PULONG pfQOP
|
|
)
|
|
|
|
/*++
|
|
|
|
RoutineDescription:
|
|
|
|
Handle decrypting a message.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext pContext;
|
|
NTLMSSP_MESSAGE_SIGNATURE MessageSig;
|
|
NTLMSSP_MESSAGE_SIGNATURE Sig;
|
|
int Signature;
|
|
ULONG i;
|
|
|
|
UNREFERENCED_PARAMETER(pfQOP);
|
|
UNREFERENCED_PARAMETER(MessageSeqNo);
|
|
|
|
pContext = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (!pContext)
|
|
{
|
|
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)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
if (pMessage->pBuffers[Signature].cbBuffer < NTLMSSP_MESSAGE_SIGNATURE_SIZE)
|
|
{
|
|
return(SEC_E_INVALID_TOKEN);
|
|
}
|
|
|
|
RtlCopyMemory(
|
|
&MessageSig,
|
|
pMessage->pBuffers[Signature].pvBuffer,
|
|
NTLMSSP_MESSAGE_SIGNATURE_SIZE
|
|
);
|
|
|
|
Sig.CheckSum = 0xffffffff;
|
|
for (i = 0; i < pMessage->cBuffers ; i++ )
|
|
{
|
|
if (((pMessage->pBuffers[i].BufferType & 0xFF) == SECBUFFER_DATA) &&
|
|
!(pMessage->pBuffers[i].BufferType & SECBUFFER_READONLY) &&
|
|
(pMessage->pBuffers[i].cbBuffer != 0))
|
|
{
|
|
SspEncryptBuffer(
|
|
pContext,
|
|
pMessage->pBuffers[i].cbBuffer,
|
|
pMessage->pBuffers[i].pvBuffer
|
|
);
|
|
SspGenCheckSum(&pMessage->pBuffers[i], &Sig);
|
|
}
|
|
}
|
|
|
|
Sig.CheckSum ^= 0xffffffff;
|
|
|
|
//
|
|
// For datagram, rely on the message sequence number
|
|
//
|
|
|
|
if ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_DATAGRAM) == 0)
|
|
{
|
|
Sig.Nonce = pContext->Nonce++;
|
|
}
|
|
else
|
|
{
|
|
Sig.Nonce = MessageSeqNo;
|
|
}
|
|
|
|
Sig.Version = NTLMSSP_SIGN_VERSION;
|
|
|
|
SspEncryptBuffer(
|
|
pContext,
|
|
sizeof(NTLMSSP_MESSAGE_SIGNATURE) - sizeof(ULONG),
|
|
&MessageSig.RandomPad
|
|
);
|
|
|
|
|
|
if (MessageSig.CheckSum != Sig.CheckSum)
|
|
{
|
|
return(SEC_E_MESSAGE_ALTERED);
|
|
}
|
|
|
|
if (MessageSig.Nonce != Sig.Nonce)
|
|
{
|
|
return(SEC_E_OUT_OF_SEQUENCE);
|
|
}
|
|
|
|
return(SEC_E_OK);
|
|
|
|
}
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspQuerySecurityContextToken(
|
|
IN PCtxtHandle ContextHandle,
|
|
OUT PHANDLE TokenHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns a copy of a context token.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Context handle to impersonate.
|
|
|
|
TokenHandle - Receives a copy of the context token.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Message handled
|
|
|
|
SEC_E_INVALID_HANDLE -- Context Handle is invalid
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext Context;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
NTSTATUS Status;
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Make sure the context handle came from NTLMSSP
|
|
//
|
|
|
|
if ((ContextHandle->dwLower != SEC_HANDLE_NTLMSSPS) &&
|
|
(ContextHandle->dwLower != SEC_HANDLE_SECURITY))
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
Context = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (Context == NULL) {
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
|
|
if (Context->TokenHandle == NULL) {
|
|
return(SEC_E_NO_IMPERSONATION);
|
|
}
|
|
|
|
//
|
|
// Impersonate the TokenHandle into the callers address space.
|
|
//
|
|
|
|
Status = NtDuplicateToken(
|
|
Context->TokenHandle,
|
|
0, // copy existing access
|
|
&ObjectAttributes,
|
|
FALSE, // not effective only
|
|
TokenImpersonation,
|
|
TokenHandle
|
|
);
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(SspNtStatusToSecStatus(Status, SEC_E_NO_IMPERSONATION));
|
|
}
|
|
|
|
return SEC_E_OK;
|
|
|
|
}
|
|
|
|
|
|
SECURITY_STATUS
|
|
SsprImpersonateSecurityContext(
|
|
IN PCtxtHandle ContextHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Impersonates a security context
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Context handle to impersonate.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Message handled
|
|
|
|
SEC_E_INVALID_HANDLE -- Context Handle is invalid
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext Context;
|
|
NTSTATUS Status;
|
|
|
|
|
|
Context = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (Context == NULL) {
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
|
|
if (Context->TokenHandle == NULL) {
|
|
return(SEC_E_NO_IMPERSONATION);
|
|
}
|
|
|
|
//
|
|
// Impersonate the TokenHandle into the callers address space.
|
|
//
|
|
|
|
Status = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
(PVOID) &Context->TokenHandle,
|
|
(ULONG) sizeof(HANDLE));
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(SspNtStatusToSecStatus(Status, SEC_E_NO_IMPERSONATION));
|
|
}
|
|
|
|
return SEC_E_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECURITY_STATUS
|
|
SsprRevertSecurityContext(
|
|
IN PCtxtHandle ContextHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reverts a thread from a security context
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Context handle to impersonate.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Message handled
|
|
|
|
SEC_E_INVALID_HANDLE -- Context Handle is invalid
|
|
|
|
--*/
|
|
|
|
{
|
|
PCheaterContext Context;
|
|
NTSTATUS Status;
|
|
HANDLE NullTokenHandle = NULL;
|
|
|
|
|
|
Context = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (Context == NULL) {
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
|
|
if (Context->TokenHandle == NULL) {
|
|
return(SEC_E_NO_IMPERSONATION);
|
|
}
|
|
|
|
//
|
|
// Impersonate the TokenHandle into the callers address space.
|
|
//
|
|
|
|
Status = NtSetInformationThread(
|
|
NtCurrentThread(),
|
|
ThreadImpersonationToken,
|
|
(PVOID) &NullTokenHandle,
|
|
(ULONG) sizeof(HANDLE));
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return(SspNtStatusToSecStatus(Status, SEC_E_NO_IMPERSONATION));
|
|
}
|
|
|
|
return SEC_E_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspGetContextNames(
|
|
IN PCheaterContext Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine obtains the names for a context by opening the token,
|
|
getting the User ID, and calling LookupAccountNameW on the user id.
|
|
|
|
Arguments:
|
|
|
|
Context - Context to obtain names for
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Call completed successfully
|
|
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_UNSUPPORTED_FUNCTION -- Function code is not supported
|
|
|
|
--*/
|
|
{
|
|
PTOKEN_USER TokenUserInfo = NULL;
|
|
ULONG TokenUserSize = 0;
|
|
NTSTATUS Status;
|
|
WCHAR UserName[UNLEN+1];
|
|
ULONG UserNameLength = UNLEN+1;
|
|
WCHAR DomainName[DNLEN+1];
|
|
ULONG DomainNameLength = DNLEN+1;
|
|
SID_NAME_USE SidUse;
|
|
LPWSTR ContextNames = NULL;
|
|
|
|
ASSERT(Context->TokenHandle != NULL);
|
|
|
|
|
|
//
|
|
// Get the LogonId from the token.
|
|
//
|
|
|
|
Status = NtQueryInformationToken(
|
|
Context->TokenHandle,
|
|
TokenUser,
|
|
TokenUserInfo,
|
|
TokenUserSize,
|
|
&TokenUserSize );
|
|
|
|
if ( Status != STATUS_BUFFER_TOO_SMALL ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
TokenUserInfo = LocalAlloc( 0, TokenUserSize );
|
|
|
|
if ( TokenUserInfo == NULL ) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = NtQueryInformationToken(
|
|
Context->TokenHandle,
|
|
TokenUser,
|
|
TokenUserInfo,
|
|
TokenUserSize,
|
|
&TokenUserSize );
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Now that we have the user ID, calling LookupAccountName to translate
|
|
// it to a SID.
|
|
//
|
|
|
|
if (!LookupAccountSidW(
|
|
NULL, // local system
|
|
TokenUserInfo->User.Sid,
|
|
UserName,
|
|
&UserNameLength,
|
|
DomainName,
|
|
&DomainNameLength,
|
|
&SidUse
|
|
)) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// We now have the use & domain name - put them in the context.
|
|
//
|
|
|
|
ContextNames = LocalAlloc(0, (wcslen(UserName) + wcslen(DomainName) + 2) * sizeof(WCHAR));
|
|
|
|
if (ContextNames == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (DomainName[0] != L'\0') {
|
|
wcscpy(ContextNames, DomainName);
|
|
wcscat(ContextNames, L"\\");
|
|
|
|
}
|
|
wcscat(ContextNames, UserName);
|
|
LocalFree(Context->ContextNames);
|
|
Context->ContextNames = ContextNames;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
if (TokenUserInfo != NULL)
|
|
{
|
|
LocalFree(TokenUserInfo);
|
|
}
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
SECURITY_STATUS
|
|
SspLocalQueryContextAttributes(
|
|
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:
|
|
|
|
STATUS_SUCCESS - Call completed successfully
|
|
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_UNSUPPORTED_FUNCTION -- Function code is not supported
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus = STATUS_SUCCESS;
|
|
PCheaterContext Context;
|
|
|
|
|
|
PSecPkgContext_Sizes ContextSizes;
|
|
PSecPkgContext_Lifespan ContextLifespan;
|
|
PSecPkgContext_DceInfo ContextDceInfo;
|
|
PSecPkgContext_Names ContextNames;
|
|
PSecPkgContext_PasswordExpiry PasswordExpires;
|
|
ULONG ContextNamesSize;
|
|
WCHAR Name[UNLEN+DNLEN+1];
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
SspPrint(( SSP_API, "SspQueryContextAttributes Entered\n" ));
|
|
|
|
Context = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (Context == NULL) {
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
//
|
|
// Handle each of the various queried attributes
|
|
//
|
|
|
|
switch ( Attribute) {
|
|
case SECPKG_ATTR_SIZES:
|
|
|
|
ContextSizes = (PSecPkgContext_Sizes) Buffer;
|
|
ContextSizes->cbMaxToken = NTLMSP_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;
|
|
}
|
|
|
|
break;
|
|
|
|
//
|
|
// No one uses the function so don't go to the overhead of maintaining
|
|
// the username in the context structure.
|
|
//
|
|
|
|
case SECPKG_ATTR_DCE_INFO:
|
|
|
|
//
|
|
// If the name isn't present and we have a token, get the name
|
|
// from the token.
|
|
//
|
|
|
|
if ((Context->ContextNames == NULL) ||
|
|
(Context->ContextNames[0] == L'\0') &&
|
|
(Context->TokenHandle != NULL))
|
|
{
|
|
}
|
|
|
|
ContextDceInfo = (PSecPkgContext_DceInfo) Buffer;
|
|
|
|
wcscpy(
|
|
(LPWSTR) ContextDceInfo->pPac,
|
|
Context->ContextNames
|
|
);
|
|
|
|
ContextDceInfo->AuthzSvc = 0;
|
|
|
|
break;
|
|
|
|
case SECPKG_ATTR_NAMES:
|
|
|
|
//
|
|
// If the name isn't present and we have a token, get the name
|
|
// from the token.
|
|
//
|
|
|
|
if (((Context->ContextNames == NULL) ||
|
|
(Context->ContextNames[0] == L'\0')) &&
|
|
(Context->TokenHandle != NULL)) {
|
|
SecStatus = SspGetContextNames(
|
|
Context
|
|
);
|
|
if (!NT_SUCCESS(SecStatus)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ContextNames = (PSecPkgContext_Names) Buffer;
|
|
|
|
wcscpy(
|
|
ContextNames->sUserName,
|
|
Context->ContextNames
|
|
);
|
|
|
|
break;
|
|
case SECPKG_ATTR_PASSWORD_EXPIRY:
|
|
PasswordExpires = (PSecPkgContext_PasswordExpiry) Buffer;
|
|
if (Context->PasswordExpiry.QuadPart != 0)
|
|
{
|
|
PasswordExpires->tsPasswordExpires = Context->PasswordExpiry;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// This is the case on a client context.
|
|
//
|
|
|
|
SecStatus = SEC_E_UNSUPPORTED_FUNCTION;
|
|
}
|
|
break;
|
|
case SECPKG_ATTR_LIFESPAN:
|
|
|
|
//
|
|
// We don't support this
|
|
//
|
|
|
|
default:
|
|
SecStatus = SEC_E_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// Free local resources
|
|
//
|
|
|
|
|
|
SspPrint(( SSP_API, "SspQueryContextAttributes returns 0x%lx\n", SecStatus ));
|
|
return SecStatus;
|
|
}
|
|
|
|
#ifdef notdef
|
|
|
|
SECURITY_STATUS
|
|
SspQueryPasswordExpiry(
|
|
IN PCtxtHandle ContextHandle,
|
|
OUT PTimeStamp PasswordExpiry
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the expiration time of a context user's password
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Handle to the context to query.
|
|
|
|
PasswordExpiry - Receives the date/time the password expires.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Call completed successfully
|
|
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
SEC_E_UNSUPPORTED_FUNCTION -- Function code is not supported
|
|
|
|
--*/
|
|
|
|
{
|
|
SECURITY_STATUS SecStatus = STATUS_SUCCESS;
|
|
PCheaterContext Context;
|
|
|
|
|
|
|
|
//
|
|
// Initialization
|
|
//
|
|
|
|
SspPrint(( SSP_API, "SspQueryPasswordExpiry Entered\n" ));
|
|
|
|
Context = SspLocateLocalContext(ContextHandle);
|
|
|
|
if (Context == NULL) {
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
//
|
|
// If the expiration time is zero then this is a client context
|
|
// and we don't support it
|
|
//
|
|
|
|
if (Context->PasswordExpiry.QuadPart == 0)
|
|
{
|
|
return(SEC_E_UNSUPPORTED_FUNCTION);
|
|
}
|
|
|
|
*PasswordExpiry = Context->PasswordExpiry;
|
|
|
|
return SEC_E_OK;
|
|
}
|
|
|
|
#endif
|