mirror of https://github.com/tongzx/nt5src
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.
839 lines
26 KiB
839 lines
26 KiB
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1992 - 1996
|
|
//
|
|
// File: ctxtapi.cxx
|
|
//
|
|
// Contents: Context APIs for the NtLm security package
|
|
// Main entry points into this dll:
|
|
// SpDeleteContext
|
|
// SpInitLsaModeContext
|
|
// SpApplyControlToken
|
|
// SpAcceptLsaModeContext
|
|
//
|
|
// History: ChandanS 26-Jul-1996 Stolen from kerberos\client2\ctxtapi.cxx
|
|
// JClark 28-Jun-2000 Added WMI Trace Logging Support
|
|
//
|
|
//------------------------------------------------------------------------
|
|
#define NTLM_CTXTAPI
|
|
#include <global.h>
|
|
#include "Trace.h"
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SpDeleteContext
|
|
//
|
|
// Synopsis: Deletes an NtLm context
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments: ContextHandle - The context to delete
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns: STATUS_SUCCESS or STATUS_INVALID_HANDLE
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
SpDeleteContext(
|
|
IN ULONG_PTR ContextHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes the local data structures associated with the specified
|
|
security context.
|
|
|
|
This API terminates a context on the local machine.
|
|
|
|
Arguments:
|
|
|
|
ContextHandle - Handle to the context to delete
|
|
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - Call completed successfully
|
|
|
|
SEC_E_NO_SPM -- Security Support Provider is not running
|
|
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG_PTR TempContextHandle = ContextHandle;
|
|
SspPrint((SSP_API, "Entering SpDeleteContext for 0x%x\n", ContextHandle));
|
|
|
|
Status = SsprDeleteSecurityContext(
|
|
TempContextHandle );
|
|
|
|
SspPrint((SSP_API, "Leaving SpDeleteContext for 0x%x\n", ContextHandle));
|
|
return (SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
|
|
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SpInitLsaModeContext
|
|
//
|
|
// Synopsis: NtLm implementation of InitializeSecurityContext
|
|
// while in Lsa mode. If we return TRUE in *MappedContext,
|
|
// secur32 will call SpInitUserModeContext with
|
|
// the returned context handle and ContextData
|
|
// as input. Fill in whatever info needed for
|
|
// the user mode apis
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes: This function can be called in various ways:
|
|
// 1. Generic users of ntlm make the first call to
|
|
// InitializeSecurityContext and we return a NEGOTIATE_MESSAGE
|
|
// 2. The rdr makes the first call to InitializeSecurityContext
|
|
// with no contextHandle but info is passed in through a
|
|
// CHALLENGE_MESSAGE (& possibly an NTLM_CHALLENGE_MESSAGE),
|
|
// we return an AUTHENTICATE_MESSAGE and an
|
|
// NTLM_INITIALIZE_RESPONSE
|
|
// 3. Generic users of NTLM make the second call to
|
|
// InitializeSecurityContext, passing in a CHALLENGE_MESSAGE
|
|
// and we return an AUTHENTICATE_MESSAGE
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
SpInitLsaModeContext(
|
|
IN OPTIONAL ULONG_PTR CredentialHandle,
|
|
IN OPTIONAL ULONG_PTR OldContextHandle,
|
|
IN OPTIONAL PUNICODE_STRING TargetName,
|
|
IN ULONG ContextReqFlags,
|
|
IN ULONG TargetDataRep,
|
|
IN PSecBufferDesc InputBuffers,
|
|
OUT PULONG_PTR NewContextHandle,
|
|
IN OUT PSecBufferDesc OutputBuffers,
|
|
OUT PULONG ContextAttributes,
|
|
OUT PTimeStamp ExpirationTime,
|
|
OUT PBOOLEAN MappedContext,
|
|
OUT PSecBuffer ContextData
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
SecBuffer TempTokens[4];
|
|
PSecBuffer FirstInputToken;
|
|
PSecBuffer SecondInputToken;
|
|
PSecBuffer FirstOutputToken;
|
|
PSecBuffer SecondOutputToken;
|
|
|
|
ULONG_PTR OriginalContextHandle = NULL;
|
|
ULONG_PTR TempContextHandle = NULL;
|
|
ULONG NegotiateFlags = 0;
|
|
UCHAR SessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
|
|
|
|
//Tracing State
|
|
NTLM_TRACE_INFO TraceInfo = {0};
|
|
UINT32 TraceHint = 0;
|
|
|
|
|
|
SspPrint((SSP_API, "Entering SpInitLsaModeContext for Old:0x%x, New:0x%x\n", OldContextHandle, *NewContextHandle));
|
|
|
|
|
|
//Begin tracing an InitializeSecurityContext call for NTLM
|
|
if (NtlmGlobalEventTraceFlag){
|
|
|
|
//Header goo
|
|
SET_TRACE_HEADER(TraceInfo,
|
|
NtlmInitializeGuid,
|
|
EVENT_TRACE_TYPE_START,
|
|
WNODE_FLAG_TRACED_GUID|WNODE_FLAG_USE_MOF_PTR,
|
|
2);
|
|
|
|
TraceHint = (OldContextHandle == 0)?
|
|
TRACE_INIT_FIRST:
|
|
TRACE_INIT_CHALLENGE;
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_STAGEHINT,
|
|
TraceHint);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_INCONTEXT,
|
|
OldContextHandle);
|
|
|
|
TraceEvent(NtlmGlobalTraceLoggerHandle,
|
|
(PEVENT_TRACE_HEADER)&TraceInfo);
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(
|
|
TempTokens,
|
|
sizeof(TempTokens)
|
|
);
|
|
|
|
FirstInputToken = &TempTokens[0];
|
|
SecondInputToken = &TempTokens[1];
|
|
FirstOutputToken = &TempTokens[2];
|
|
SecondOutputToken = &TempTokens[3];
|
|
|
|
|
|
*MappedContext = FALSE;
|
|
|
|
ASSERT(ContextData);
|
|
|
|
ContextData->pvBuffer = NULL;
|
|
ContextData->cbBuffer = 0;
|
|
|
|
RtlZeroMemory(SessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH);
|
|
|
|
UNREFERENCED_PARAMETER( TargetDataRep );
|
|
|
|
//
|
|
// Extract tokens from the SecBuffers
|
|
//
|
|
|
|
if ( !SspGetTokenBuffer( InputBuffers,
|
|
0, // get the first SECBUFFER_TOKEN
|
|
&FirstInputToken,
|
|
TRUE
|
|
) ) {
|
|
Status = SEC_E_INVALID_TOKEN;
|
|
SspPrint((SSP_CRITICAL, "SpInitLsaModeContext, SspGetTokenBuffer (FirstInputToken) returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If we are using supplied credentials, get the second SECBUFFER_TOKEN
|
|
//
|
|
|
|
if (ContextReqFlags & ISC_REQ_USE_SUPPLIED_CREDS)
|
|
{
|
|
if ( !SspGetTokenBuffer( InputBuffers,
|
|
1, // get the second SECBUFFER_TOKEN
|
|
&SecondInputToken,
|
|
TRUE
|
|
) ) {
|
|
Status = SEC_E_INVALID_TOKEN;
|
|
SspPrint((SSP_CRITICAL, "SpInitLsaModeContext, SspGetTokenBuffer (SecondInputToken) returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if ( !SspGetTokenBuffer( OutputBuffers,
|
|
0, // get the first SECBUFFER_TOKEN
|
|
&FirstOutputToken,
|
|
FALSE
|
|
) ) {
|
|
Status = SEC_E_INVALID_TOKEN;
|
|
SspPrint((SSP_CRITICAL, "SpInitLsaModeContext, SspGetTokenBuffer (FirstOutputToken) returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !SspGetTokenBuffer( OutputBuffers,
|
|
1, // get the second SECBUFFER_TOKEN
|
|
&SecondOutputToken,
|
|
FALSE
|
|
) ) {
|
|
Status = SEC_E_INVALID_TOKEN;
|
|
SspPrint((SSP_CRITICAL, "SpInitLsaModeContext, SspGetTokenBuffer (SecondOutputToken) returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Save the old context handle, in case someone changes it
|
|
//
|
|
|
|
TempContextHandle = OldContextHandle;
|
|
OriginalContextHandle = OldContextHandle;
|
|
|
|
//
|
|
// If no previous context was passed
|
|
// and if no legitimate input token existed, this is the first call
|
|
//
|
|
|
|
if ((OriginalContextHandle == 0 ) &&
|
|
(FirstInputToken->cbBuffer == 0))
|
|
{
|
|
|
|
if ( !ARGUMENT_PRESENT( CredentialHandle ) ) {
|
|
Status = STATUS_INVALID_HANDLE;
|
|
SspPrint((SSP_CRITICAL, "SpInitLsaModeContext, No CredentialHandle\n"));
|
|
goto Cleanup;
|
|
}
|
|
|
|
*NewContextHandle = 0;
|
|
|
|
Status = SsprHandleFirstCall(
|
|
CredentialHandle,
|
|
NewContextHandle,
|
|
ContextReqFlags,
|
|
FirstInputToken->cbBuffer,
|
|
FirstInputToken->pvBuffer,
|
|
TargetName,
|
|
&FirstOutputToken->cbBuffer,
|
|
&FirstOutputToken->pvBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime,
|
|
SessionKey,
|
|
&NegotiateFlags );
|
|
|
|
TempContextHandle = *NewContextHandle;
|
|
//
|
|
// If context was passed in, continue where we left off.
|
|
// Or if the redir's passing in stuff in the InputBuffers,
|
|
// skip the first call and get on with the second
|
|
//
|
|
|
|
} else {
|
|
|
|
*NewContextHandle = OldContextHandle;
|
|
|
|
Status = SsprHandleChallengeMessage(
|
|
CredentialHandle,
|
|
&TempContextHandle,
|
|
ContextReqFlags,
|
|
FirstInputToken->cbBuffer,
|
|
FirstInputToken->pvBuffer,
|
|
SecondInputToken->cbBuffer,
|
|
SecondInputToken->pvBuffer,
|
|
TargetName,
|
|
&FirstOutputToken->cbBuffer,
|
|
&FirstOutputToken->pvBuffer,
|
|
&SecondOutputToken->cbBuffer,
|
|
&SecondOutputToken->pvBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime,
|
|
SessionKey,
|
|
&NegotiateFlags
|
|
);
|
|
}
|
|
|
|
//
|
|
// If the original handle is zero, set it to be the TempContextHandle.
|
|
// This is for the datagram case, where we map the context after the
|
|
// first call to initialize.
|
|
//
|
|
|
|
if (OriginalContextHandle == 0) {
|
|
|
|
OriginalContextHandle = TempContextHandle;
|
|
*NewContextHandle = OriginalContextHandle;
|
|
}
|
|
//
|
|
// Only map the context if this is the real authentication, not a re-auth
|
|
// or if this was datagram.
|
|
//
|
|
|
|
if (((Status == SEC_I_CONTINUE_NEEDED) &&
|
|
((*ContextAttributes & ISC_RET_DATAGRAM) != 0)) ||
|
|
((Status == SEC_E_OK) &&
|
|
((*ContextAttributes & (SSP_RET_REAUTHENTICATION | ISC_RET_DATAGRAM)) == 0))) {
|
|
|
|
NTSTATUS TempStatus;
|
|
|
|
TempStatus = SspMapContext(
|
|
&OriginalContextHandle,
|
|
SessionKey,
|
|
NegotiateFlags,
|
|
NULL, // no token handle for clients
|
|
NULL, // no password expiry for clients
|
|
0, // no userflags
|
|
ContextData
|
|
);
|
|
|
|
if (!NT_SUCCESS(TempStatus)) {
|
|
Status = TempStatus;
|
|
SspPrint((SSP_CRITICAL, "SpInitLsaModeContext, SspMapContext returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
SspPrint((SSP_SESSION_KEYS, "Init sessionkey %lx %lx %lx %lx\n",
|
|
((DWORD*)SessionKey)[0],
|
|
((DWORD*)SessionKey)[1],
|
|
((DWORD*)SessionKey)[2],
|
|
((DWORD*)SessionKey)[3]
|
|
));
|
|
|
|
|
|
//
|
|
// Yes, do load msv1_0.dll in the client's process
|
|
// and ContextData will contain info to be passed on
|
|
// to the InitializeSecurityContext counterpart that
|
|
// runs in the client's process
|
|
|
|
*MappedContext = TRUE;
|
|
}
|
|
|
|
//
|
|
// Make sure this bit isn't sent to the caller
|
|
//
|
|
|
|
*ContextAttributes &= ~SSP_RET_REAUTHENTICATION;
|
|
|
|
|
|
Cleanup:
|
|
|
|
// Send the output stuff
|
|
// pvBuffer is reassigned in case ISC-REQ_ALLOCATE_MEMORY has ben defined
|
|
|
|
// if (OutputBuffers != NULL && OutputBuffers->cBuffers > 0 && OutputBuffers->pBuffers != NULL)
|
|
// {
|
|
// OutputBuffers->pBuffers->cbBuffer = FirstOutputToken.cbBuffer;
|
|
// OutputBuffers->pBuffers->pvBuffer = FirstOutputToken.pvBuffer;
|
|
// }
|
|
|
|
SspPrint((SSP_API, "Leaving SpInitLsaModeContext for Old:0x%x, New:0x%x\n", OldContextHandle, *NewContextHandle));
|
|
|
|
//
|
|
// Convert and save, will be (perhaps traced then) returned
|
|
//
|
|
Status = (SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
|
|
|
|
//
|
|
//Trace the end of this call
|
|
//
|
|
if (NtlmGlobalEventTraceFlag){
|
|
|
|
//Header goo
|
|
SET_TRACE_HEADER(TraceInfo,
|
|
NtlmInitializeGuid,
|
|
EVENT_TRACE_TYPE_END,
|
|
WNODE_FLAG_TRACED_GUID|WNODE_FLAG_USE_MOF_PTR,
|
|
4);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_STAGEHINT,
|
|
TraceHint);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_INCONTEXT,
|
|
OldContextHandle);
|
|
|
|
SET_TRACE_DATAPTR(TraceInfo,
|
|
TRACE_INITACC_OUTCONTEXT,
|
|
NewContextHandle);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_STATUS,
|
|
Status);
|
|
|
|
TraceEvent(
|
|
NtlmGlobalTraceLoggerHandle,
|
|
(PEVENT_TRACE_HEADER)&TraceInfo
|
|
);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
SpApplyControlToken(
|
|
IN ULONG_PTR ContextHandle,
|
|
IN PSecBufferDesc ControlToken
|
|
)
|
|
{
|
|
SspPrint((SSP_API, "Entering SpApplyControlToken\n"));
|
|
UNREFERENCED_PARAMETER(ContextHandle);
|
|
UNREFERENCED_PARAMETER(ControlToken);
|
|
SspPrint((SSP_API, "Leaving SpApplyControlToken\n"));
|
|
return(SEC_E_UNSUPPORTED_FUNCTION);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: SpAcceptLsaModeContext
|
|
//
|
|
// Synopsis: NtLm implementation of AcceptSecurityContext call.
|
|
// This routine accepts an AP request message from a client
|
|
// and verifies that it is a valid ticket. If mutual
|
|
// authentication is desired an AP reply is generated to
|
|
// send back to the client.
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
SpAcceptLsaModeContext(
|
|
IN OPTIONAL ULONG_PTR CredentialHandle,
|
|
IN OPTIONAL ULONG_PTR OldContextHandle,
|
|
IN PSecBufferDesc InputBuffers,
|
|
IN ULONG ContextReqFlags,
|
|
IN ULONG TargetDataRep,
|
|
OUT PULONG_PTR NewContextHandle,
|
|
OUT PSecBufferDesc OutputBuffers,
|
|
OUT PULONG ContextAttributes,
|
|
OUT PTimeStamp ExpirationTime,
|
|
OUT PBOOLEAN MappedContext,
|
|
OUT PSecBuffer ContextData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allows a remotely initiated security context between the application
|
|
and a remote peer to be established. To complete the establishment of
|
|
context one or more reply tokens may be required from remote peer.
|
|
|
|
This function is the server counterpart to the
|
|
InitializeSecurityContext API. The ContextAttributes is a bit mask
|
|
representing various context level functions viz. delegation, mutual
|
|
authentication, confidentiality, replay detection and sequence
|
|
detection. This API is used by the server side. When a request comes
|
|
in, the server uses the ContextReqFlags parameter to specify what
|
|
it requires of the session. In this fashion, a server can specify that
|
|
clients must be capable of using a confidential or integrity checked
|
|
session, and fail clients that can't meet that demand. Alternatively,
|
|
a server can require nothing, and whatever the client can provide or
|
|
requires is returned in the pfContextAttributes parameter. For a
|
|
package that supports 3 leg mutual authentication, the calling sequence
|
|
would be: Client provides a token, server calls Accept the first time,
|
|
generating a reply token. The client uses this in a second call to
|
|
InitializeSecurityContext, and generates a final token. This token is
|
|
then used in the final call to Accept to complete the session. Another
|
|
example would be the LAN Manager/NT authentication style. The client
|
|
connects to negotiate a protocol. The server calls Accept to set up a
|
|
context and generate a challenge to the client. The client calls
|
|
InitializeSecurityContext and creates a response. The server then
|
|
calls Accept the final time to allow the package to verify the response
|
|
is appropriate for the challenge.
|
|
|
|
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.
|
|
|
|
InputToken - Pointer to the input token. In the first call this
|
|
token can either be NULL or may contain security package specific
|
|
information.
|
|
|
|
ContextReqFlags - Requirements of the context, package specific.
|
|
|
|
#define ASC_REQ_DELEGATE 0x00000001
|
|
#define ASC_REQ_MUTUAL_AUTH 0x00000002
|
|
#define ASC_REQ_REPLAY_DETECT 0x00000004
|
|
#define ASC_REQ_SEQUENCE_DETECT 0x00000008
|
|
#define ASC_REQ_CONFIDENTIALITY 0x00000010
|
|
#define ASC_REQ_ALLOCATE_MEMORY 0x00000100
|
|
#define ASC_REQ_USE_DCE_STYLE 0x00000200
|
|
|
|
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.
|
|
|
|
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 ASC_RET_DELEGATE 0x00000001
|
|
#define ASC_RET_MUTUAL_AUTH 0x00000002
|
|
#define ASC_RET_REPLAY_DETECT 0x00000004
|
|
#define ASC_RET_SEQUENCE_DETECT 0x00000008
|
|
#define ASC_RET_CONFIDENTIALITY 0x00000010
|
|
#define ASC_RET_ALLOCATED_BUFFERS 0x00000100
|
|
#define ASC_RET_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_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
|
|
SEC_E_LOGON_DENIED -- User is no allowed to logon to this server
|
|
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
SecBuffer TempTokens[3];
|
|
PSecBuffer FirstInputToken;
|
|
PSecBuffer SecondInputToken;
|
|
PSecBuffer FirstOutputToken;
|
|
|
|
ULONG NegotiateFlags = 0;
|
|
UCHAR SessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
|
|
HANDLE TokenHandle = NULL;
|
|
NTSTATUS SubStatus = STATUS_SUCCESS;
|
|
|
|
TimeStamp PasswordExpiry;
|
|
ULONG UserFlags;
|
|
|
|
//Tracing State
|
|
NTLM_TRACE_INFO TraceInfo = {0};
|
|
UINT32 TraceHint = 0;
|
|
|
|
SspPrint((SSP_API, "Entering SpAcceptLsaModeContext for Old:0x%x, New:0x%x\n", OldContextHandle, *NewContextHandle));
|
|
|
|
//Begin tracing an AcceptSecurityContext call for NTLM
|
|
if (NtlmGlobalEventTraceFlag){
|
|
|
|
|
|
//Header goo
|
|
SET_TRACE_HEADER(TraceInfo,
|
|
NtlmAcceptGuid,
|
|
EVENT_TRACE_TYPE_START,
|
|
WNODE_FLAG_TRACED_GUID|WNODE_FLAG_USE_MOF_PTR,
|
|
2);
|
|
|
|
TraceHint = (OldContextHandle == 0)?
|
|
TRACE_ACCEPT_NEGOTIATE:
|
|
TRACE_ACCEPT_AUTHENTICATE;
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_STAGEHINT,
|
|
TraceHint);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_INCONTEXT,
|
|
OldContextHandle);
|
|
|
|
TraceEvent(NtlmGlobalTraceLoggerHandle,
|
|
(PEVENT_TRACE_HEADER)&TraceInfo);
|
|
}
|
|
|
|
FirstInputToken = &TempTokens[0];
|
|
SecondInputToken = &TempTokens[1];
|
|
FirstOutputToken = &TempTokens[2];
|
|
|
|
RtlZeroMemory(
|
|
TempTokens,
|
|
sizeof(TempTokens)
|
|
);
|
|
|
|
RtlZeroMemory(
|
|
SessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH
|
|
);
|
|
|
|
*MappedContext = FALSE;
|
|
|
|
//
|
|
// Validate the arguments
|
|
//
|
|
|
|
UNREFERENCED_PARAMETER( TargetDataRep );
|
|
|
|
|
|
if ( !SspGetTokenBuffer( InputBuffers,
|
|
0, // get the first SECBUFFER_TOKEN
|
|
&FirstInputToken,
|
|
TRUE ) ) {
|
|
Status = SEC_E_INVALID_TOKEN;
|
|
SspPrint((SSP_CRITICAL, "SpAcceptLsaModeContext, SspGetTokenBuffer (FirstInputToken) returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !SspGetTokenBuffer( InputBuffers,
|
|
1, // get the second SECBUFFER_TOKEN
|
|
&SecondInputToken,
|
|
TRUE ) ) {
|
|
Status = SEC_E_INVALID_TOKEN;
|
|
SspPrint((SSP_CRITICAL, "SpAcceptLsaModeContext, SspGetTokenBuffer (SecondInputToken) returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !SspGetTokenBuffer( OutputBuffers,
|
|
0, // get the first SECBUFFER_TOKEN
|
|
&FirstOutputToken,
|
|
FALSE ) ) {
|
|
Status = SEC_E_INVALID_TOKEN;
|
|
SspPrint((SSP_CRITICAL, "SpAcceptLsaModeContext, SspGetTokenBuffer (FirstOutputToken) returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If no previous context was passed in this is the first call.
|
|
//
|
|
|
|
if ( (OldContextHandle == 0 ) &&
|
|
(SecondInputToken->cbBuffer == 0)) {
|
|
|
|
if ( !ARGUMENT_PRESENT( CredentialHandle ) ) {
|
|
Status = SEC_E_INVALID_HANDLE;
|
|
SspPrint((SSP_CRITICAL, "SpAcceptLsaModeContext, No CredentialHandle\n"));
|
|
goto Cleanup;
|
|
}
|
|
|
|
Status = SsprHandleNegotiateMessage(
|
|
CredentialHandle,
|
|
NewContextHandle,
|
|
ContextReqFlags,
|
|
FirstInputToken->cbBuffer,
|
|
FirstInputToken->pvBuffer,
|
|
&FirstOutputToken->cbBuffer,
|
|
&FirstOutputToken->pvBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime );
|
|
|
|
//
|
|
// If context was passed in, continue where we left off.
|
|
//
|
|
|
|
} else {
|
|
|
|
*NewContextHandle = OldContextHandle;
|
|
|
|
Status = SsprHandleAuthenticateMessage(
|
|
CredentialHandle,
|
|
NewContextHandle,
|
|
ContextReqFlags,
|
|
FirstInputToken->cbBuffer,
|
|
FirstInputToken->pvBuffer,
|
|
SecondInputToken->cbBuffer,
|
|
SecondInputToken->pvBuffer,
|
|
&FirstOutputToken->cbBuffer,
|
|
&FirstOutputToken->pvBuffer,
|
|
ContextAttributes,
|
|
ExpirationTime,
|
|
SessionKey,
|
|
&NegotiateFlags,
|
|
&TokenHandle,
|
|
&SubStatus,
|
|
&PasswordExpiry,
|
|
&UserFlags
|
|
);
|
|
|
|
//
|
|
// for errors such as PASSWORD_EXPIRED, return the SubStatus, which
|
|
// is more descriptive than the generic error code.
|
|
//
|
|
|
|
if( Status == STATUS_ACCOUNT_RESTRICTION )
|
|
Status = SubStatus;
|
|
}
|
|
|
|
if ((Status == SEC_E_OK) &&
|
|
!(*ContextAttributes & SSP_RET_REAUTHENTICATION)) {
|
|
Status = SspMapContext(
|
|
NewContextHandle,
|
|
SessionKey,
|
|
NegotiateFlags,
|
|
TokenHandle,
|
|
&PasswordExpiry,
|
|
UserFlags,
|
|
ContextData
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
SspPrint((SSP_CRITICAL, "SpAcceptLsaModeContext, SspMapContext returns %d\n", Status));
|
|
goto Cleanup;
|
|
}
|
|
|
|
SspPrint((SSP_SESSION_KEYS, "Accept sessionkey %lx %lx %lx %lx\n",
|
|
((DWORD*)SessionKey)[0],
|
|
((DWORD*)SessionKey)[1],
|
|
((DWORD*)SessionKey)[2],
|
|
((DWORD*)SessionKey)[3]
|
|
));
|
|
|
|
*MappedContext = TRUE;
|
|
|
|
|
|
} else {
|
|
|
|
//
|
|
// Make sure this bit isn't sent to the caller
|
|
//
|
|
|
|
*ContextAttributes &= ~SSP_RET_REAUTHENTICATION;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if (TokenHandle != NULL) {
|
|
NtClose(TokenHandle);
|
|
}
|
|
|
|
// TODO: this really necessary since we're in LSA mode???
|
|
SetLastError(RtlNtStatusToDosError(SubStatus));
|
|
|
|
|
|
SspPrint((SSP_API, "Leaving SpAcceptLsaModeContext for Old:0x%x, New:0x%x\n", OldContextHandle, *NewContextHandle));
|
|
|
|
//Convert and save, will be (perhaps traced then) returned
|
|
Status = (SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
|
|
|
|
//Trace the end of this call
|
|
if (NtlmGlobalEventTraceFlag){
|
|
|
|
//Header goo
|
|
SET_TRACE_HEADER(TraceInfo,
|
|
NtlmAcceptGuid,
|
|
EVENT_TRACE_TYPE_END,
|
|
WNODE_FLAG_TRACED_GUID|WNODE_FLAG_USE_MOF_PTR,
|
|
4);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_STAGEHINT,
|
|
TraceHint);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_INCONTEXT,
|
|
OldContextHandle);
|
|
|
|
SET_TRACE_DATAPTR(TraceInfo,
|
|
TRACE_INITACC_OUTCONTEXT,
|
|
NewContextHandle);
|
|
|
|
SET_TRACE_DATA(TraceInfo,
|
|
TRACE_INITACC_STATUS,
|
|
Status);
|
|
|
|
TraceEvent(
|
|
NtlmGlobalTraceLoggerHandle,
|
|
(PEVENT_TRACE_HEADER)&TraceInfo
|
|
);
|
|
}
|
|
|
|
// Converted to SecStatus before tracing
|
|
return Status;
|
|
|
|
}
|