📄 context.cxx
字号:
// capabilities in the challenge message.
//
if ((ContextReqFlags & ISC_REQ_DATAGRAM) == 0) {
BOOLEAN CheckForLocal;
if ( (Credential->DomainName.Buffer == NULL &&
Credential->UserName.Buffer == NULL &&
Credential->Password.Buffer == NULL ) &&
(Credential->ClientTokenHandle != NULL) )
{
CheckForLocal = TRUE;
} else {
CheckForLocal = FALSE;
}
if( CheckForLocal ) {
//
// snap up a copy of the globals so we can just take the critsect once.
// the old way took the critsect twice, once to read sizes, second time
// to grab buffers - bad news if the global got bigger in between.
//
EnterCriticalSection (&NtLmGlobalCritSect);
if( NtLmGlobalOemComputerNameString.Buffer == NULL ||
NtLmGlobalOemPrimaryDomainNameString.Buffer == NULL ) {
//
// user has picked a computer name or domain name
// that failed to convert to OEM. disable the loopback
// detection.
// Sometime beyond Win2k, Negotiate package should have
// a general, robust scheme for detecting loopback.
//
CheckForLocal = FALSE;
} else {
Status = NtLmDuplicateString(
&NtLmLocalOemComputerNameString,
&NtLmGlobalOemComputerNameString
);
if( NT_SUCCESS(Status) ) {
Status = NtLmDuplicateString(
&NtLmLocalOemPrimaryDomainNameString,
&NtLmGlobalOemPrimaryDomainNameString
);
}
}
LeaveCriticalSection (&NtLmGlobalCritSect);
if (!NT_SUCCESS(Status)) {
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: NtLmDuplicateUnicodeString (GlobalOemComputerName or GlobalOemPrimaryDomainName) returned %d\n", Status ));
goto Cleanup;
}
}
//
// Allocate a Negotiate message
//
NegotiateMessageSize = sizeof(*NegotiateMessage) +
NtLmLocalOemComputerNameString.Length +
NtLmLocalOemPrimaryDomainNameString.Length;
if ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0)
{
if ( NegotiateMessageSize > *OutputTokenSize ) {
Status = SEC_E_BUFFER_TOO_SMALL;
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: OutputTokenSize is %d\n", *OutputTokenSize));
goto Cleanup;
}
}
NegotiateMessage = (PNEGOTIATE_MESSAGE)
NtLmAllocate( NegotiateMessageSize );
if ( NegotiateMessage == NULL) {
Status = STATUS_NO_MEMORY;
SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: Error allocating NegotiateMessage.\n"));
goto Cleanup;
}
//
// If this is the first call,
// build a Negotiate message.
//
strcpy( (char *) NegotiateMessage->Signature, NTLMSSP_SIGNATURE );
NegotiateMessage->MessageType = NtLmNegotiate;
NegotiateMessage->NegotiateFlags = Context->NegotiateFlags;
IF_DEBUG( REQUEST_TARGET ) {
NegotiateMessage->NegotiateFlags |= NTLMSSP_REQUEST_TARGET;
}
//
// Copy the DomainName and ComputerName into the negotiate message so
// the other side can determine if this is a call from the local system.
//
// Pass the names in the OEM character set since the character set
// hasn't been negotiated yet.
//
// Skip passing the workstation name if credentials were specified. This
// ensures the other side doesn't fall into the case that this is the
// local system. We wan't to ensure the new credentials are
// authenticated.
//
Where = (PCHAR)(NegotiateMessage+1);
if ( CheckForLocal ) {
SspContextCopyString( NegotiateMessage,
&NegotiateMessage->OemWorkstationName,
&NtLmLocalOemComputerNameString,
&Where );
NegotiateMessage->NegotiateFlags |=
NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
//
// OEM_DOMAIN_SUPPLIED used to always be supplied - but the
// only case it is ever used is when NTLMSSP_NEGOTIATE_LOCAL_CALL
// is set.
//
SspContextCopyString( NegotiateMessage,
&NegotiateMessage->OemDomainName,
&NtLmLocalOemPrimaryDomainNameString,
&Where );
NegotiateMessage->NegotiateFlags |=
NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
}
if ((ContextReqFlags & ISC_REQ_ALLOCATE_MEMORY) == 0)
{
RtlCopyMemory( *OutputToken,
NegotiateMessage,
NegotiateMessageSize );
}
else
{
*OutputToken = NegotiateMessage;
NegotiateMessage = NULL;
*ContextAttributes |= ISC_RET_ALLOCATED_MEMORY;
}
*OutputTokenSize = NegotiateMessageSize;
}
//
// Save a reference to the credential in the context.
//
Context->Credential = Credential;
Credential = NULL;
//
// Check for a caller requesting datagram security.
//
if ((ContextReqFlags & ISC_REQ_DATAGRAM) != 0) {
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_DATAGRAM;
Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_NT_ONLY;
Context->ContextFlags |= ISC_RET_DATAGRAM;
*ContextAttributes |= ISC_RET_DATAGRAM;
// If datagram security is required, then we don't send back a token
*OutputTokenSize = 0;
//
// Generate a session key for this context if sign or seal was
// requested.
//
if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN |
NTLMSSP_NEGOTIATE_SEAL)) != 0) {
Status = SspGenerateRandomBits(
Context->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
if( !NT_SUCCESS( Status ) ) {
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: SspGenerateRandomBits failed\n"));
goto Cleanup;
}
}
RtlCopyMemory(
SessionKey,
Context->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
//
// Unless client wants to force its use,
// Turn off strong crypt, because we can't negotiate it.
//
if (!NtLmGlobalDatagramUse128BitEncryption) {
Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_128;
}
//
// likewise for 56bit. note that package init handles turning
// off 56bit if 128bit is configured for datagram.
//
if(!NtLmGlobalDatagramUse56BitEncryption) {
Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_56;
}
//
// Unless client wants to require NTLM2, can't use its
// message processing features because we start using
// MD5 sigs, full duplex mode, and datagram rekey before
// we know if the server supports NTLM2.
//
if (!NtLmGlobalRequireNtlm2) {
Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_NTLM2;
}
//
// done fiddling with the negotiate flags, output them.
//
*NegotiateFlags = Context->NegotiateFlags;
//
// send back the negotiate flags to control signing and sealing
//
*NegotiateFlags |= NTLMSSP_APP_SEQ;
}
if( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH )
{
Status = SspGenerateRandomBits(
Context->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
if( !NT_SUCCESS( Status ) ) {
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: SspGenerateRandomBits failed\n"));
goto Cleanup;
}
RtlCopyMemory(
SessionKey,
Context->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
}
//
// Return output parameters to the caller.
//
*ExpirationTime = SspContextGetTimeStamp( Context, TRUE );
Status = SEC_I_CONTINUE_NEEDED;
Context->State = NegotiateSentState;
SspPrint(( SSP_NEGOTIATE_FLAGS,
"SsprHandleFirstCall: NegotiateFlags = %lx\n", Context->NegotiateFlags));
//
// Check that caller asked for minimum security required.
//
if (!SsprCheckMinimumSecurity(
Context->NegotiateFlags,
NtLmGlobalMinimumClientSecurity)) {
Status = SEC_E_UNSUPPORTED_FUNCTION;
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: "
"Caller didn't request minimum security requirements (caller=0x%lx wanted=0x%lx).\n",
Context->NegotiateFlags, NtLmGlobalMinimumClientSecurity ));
goto Cleanup;
}
//
// Free and locally used resources.
//
Cleanup:
if ( Context != NULL ) {
//
// If we failed,
// deallocate the context we allocated above.
//
// Delinking is a side effect of referencing, so do that.
//
if ( !NT_SUCCESS(Status) ) {
PSSP_CONTEXT LocalContext;
LocalContext = SspContextReferenceContext( *ContextHandle, TRUE );
ASSERT( LocalContext != NULL );
if ( LocalContext != NULL ) {
SspContextDereferenceContext( LocalContext );
}
}
// Always dereference it.
SspContextDereferenceContext( Context );
}
if ( NegotiateMessage != NULL ) {
(VOID) NtLmFree( NegotiateMessage );
}
if ( Credential != NULL ) {
SspCredentialDereferenceCredential( Credential );
}
if ( NtLmLocalOemComputerNameString.Buffer != NULL ) {
(VOID) NtLmFree( NtLmLocalOemComputerNameString.Buffer );
}
if ( NtLmLocalOemPrimaryDomainNameString.Buffer != NULL ) {
(VOID) NtLmFree( NtLmLocalOemPrimaryDomainNameString.Buffer );
}
SspPrint(( SSP_API_MORE, "Leaving SsprHandleFirstCall: 0x%lx\n", Status ));
return Status;
UNREFERENCED_PARAMETER( InputToken );
UNREFERENCED_PARAMETER( InputTokenSize );
}
NTSTATUS
SsprHandleNegotiateMessage(
IN ULONG_PTR CredentialHandle,
IN OUT PULONG_PTR 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 Negotiate message part of AcceptSecurityContext.
Arguments:
All arguments same as for AcceptSecurityContext
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_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PSSP_CONTEXT Context = NULL;
PSSP_CREDENTIAL Credential = NULL;
STRING TargetName;
ULONG TargetFlags = 0;
PNEGOTIATE_MESSAGE NegotiateMessage = NULL;
PCHALLENGE_MESSAGE ChallengeMessage = NULL;
ULONG ChallengeMessageSize = 0;
PCHAR Where = NULL;
ULONG NegotiateFlagsKeyStrength;
UNICODE_STRING NtLmLocalUnicodeTargetName;
UNICODE_STRING TargetInfo;
STRING NtLmLocalOemTargetName;
STRING OemWorkstationName;
STRING OemDomainName;
SspPrint(( SSP_API_MORE, "Entering SsprNegotiateMessage\n" ));
//
// Initialization
//
*ContextAttributes = 0;
RtlInitString( &TargetName, NULL );
RtlInitUnicodeString( &NtLmLocalUnicodeTargetName, NULL );
RtlInitString( &NtLmLocalOemTargetName, NULL );
RtlInitUnicodeString( &TargetInfo, NULL );
//
// Get a pointer to the credential
//
Status = SspCredentialReferenceCredential(
CredentialHandle,
FALSE,
FALSE,
&Credential );
if ( !NT_SUCCESS( Status ) ) {
SspPrint(( SSP_CRITICAL,
"SsprHandleNegotiateMessage: invalid credential handle.\n" ));
goto Cleanup;
}
if ( (Credential->CredentialUseFlags & SECPKG_CRED_INBOUND) == 0 ) {
Status = SEC_E_INVALID_CREDENTIAL_USE;
SspPrint(( SSP_CRITICAL,
"SsprHandleNegotiateMessage: invalid credential use.\n" ));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -