840 lines
26 KiB
C++
840 lines
26 KiB
C++
//+-----------------------------------------------------------------------
|
||
//
|
||
// 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;
|
||
|
||
}
|