📄 context.cxx
字号:
// Context->SessionKey has the session key to be used for the rest of the session
// if (DatagramSessionKey != NULL) then if KEY_EXCH then it has the encrypted session key
// to send to the server, else it is zero length
//
--*/
{
NTSTATUS Status;
UCHAR LocalSessionKey[MSV1_0_USER_SESSION_KEY_LENGTH];
// if we don't need to make any keys, just return
// RDR/SRV expect session key but don't ask for it! work-around this...
// if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN| NTLMSSP_NEGOTIATE_SEAL)) == 0)
// return(SEC_E_OK);
if ((Context->NegotiateFlags & (NTLMSSP_NEGOTIATE_SIGN| NTLMSSP_NEGOTIATE_SEAL)) == 0)
{
RtlCopyMemory(
Context->SessionKey,
NtUserSessionKey,
sizeof(LocalSessionKey)
);
return SEC_E_OK;
}
if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2)
{
//
// when using NTLM2, LSA gets passed flags that cause
// it to make good session keys -- nothing for us to do
//
RtlCopyMemory(
LocalSessionKey,
NtUserSessionKey,
sizeof(LocalSessionKey)
);
}
else if( Context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY )
{
LM_OWF_PASSWORD LmKey;
LM_RESPONSE LmResponseKey;
BYTE TemporaryResponse[ LM_RESPONSE_LENGTH ];
RtlZeroMemory(
LocalSessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
if (LmChallengeResponse->Length > LM_RESPONSE_LENGTH)
return(SEC_E_UNSUPPORTED_FUNCTION);
ZeroMemory( TemporaryResponse, sizeof(TemporaryResponse) );
CopyMemory( TemporaryResponse, LmChallengeResponse->Buffer, LmChallengeResponse->Length );
//
// The LM session key is made by taking the LM sesion key
// given to us by the LSA, extending it to LM_OWF_LENGTH
// with our salt, and then producing a new challenge-response
// with it and the original challenge response. The key is
// made from the first 8 bytes of the key.
//
RtlCopyMemory( &LmKey,
LanmanSessionKey,
MSV1_0_LANMAN_SESSION_KEY_LENGTH );
memset( (PUCHAR)(&LmKey) + MSV1_0_LANMAN_SESSION_KEY_LENGTH,
NTLMSSP_KEY_SALT,
LM_OWF_PASSWORD_LENGTH - MSV1_0_LANMAN_SESSION_KEY_LENGTH );
Status = RtlCalculateLmResponse(
(PLM_CHALLENGE) TemporaryResponse,
&LmKey,
&LmResponseKey
);
ZeroMemory( TemporaryResponse, sizeof(TemporaryResponse) );
if (!NT_SUCCESS(Status))
return(SspNtStatusToSecStatus(Status, SEC_E_NO_CREDENTIALS));
RtlCopyMemory(
LocalSessionKey,
&LmResponseKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
} else {
RtlCopyMemory(
LocalSessionKey,
NtUserSessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
}
//
// If we aren't doing key exchange, store the session key in the
// context. Otherwise encrypt the session key to send to the
// server.
//
if (Context->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) {
struct RC4_KEYSTRUCT Rc4Key;
//
// make a key schedule from the temp key to form key exchange key
//
rc4_key(
&Rc4Key,
MSV1_0_USER_SESSION_KEY_LENGTH,
LocalSessionKey
);
if (DatagramSessionKey == NULL)
{
//
// decrypt what's in Context->SessionKey, leave it there
//
rc4(
&Rc4Key,
MSV1_0_USER_SESSION_KEY_LENGTH,
Context->SessionKey
);
} else {
//
// set the proper length so client will send something (length was 0)
//
DatagramSessionKey->Length =
DatagramSessionKey->MaximumLength =
MSV1_0_USER_SESSION_KEY_LENGTH;
//
// copy randomly generated key to buffer to send to server
//
RtlCopyMemory(
DatagramSessionKey->Buffer,
Context->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
//
// encrypt it with the key exchange key
//
rc4(
&Rc4Key,
MSV1_0_USER_SESSION_KEY_LENGTH,
(unsigned char*)DatagramSessionKey->Buffer
);
}
} else {
//
// just make the temp key into the real one
//
RtlCopyMemory(
Context->SessionKey,
LocalSessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH
);
}
return(SEC_E_OK);
}
NTSTATUS
SsprHandleFirstCall(
IN LSA_SEC_HANDLE CredentialHandle,
IN OUT PLSA_SEC_HANDLE ContextHandle,
IN ULONG ContextReqFlags,
IN ULONG InputTokenSize,
IN PVOID InputToken,
IN OUT PULONG OutputTokenSize,
OUT PVOID *OutputToken,
OUT PULONG ContextAttributes,
OUT PTimeStamp ExpirationTime,
OUT PUCHAR SessionKey,
OUT PULONG NegotiateFlags
)
/*++
Routine Description:
Handle the First Call part of InitializeSecurityContext.
Arguments:
All arguments same as for InitializeSecurityContext
Return Value:
STATUS_SUCCESS -- All OK
SEC_I_CONTINUE_NEEDED -- Caller should call again later
SEC_E_INVALID_HANDLE -- Credential/Context Handle is invalid
SEC_E_BUFFER_TOO_SMALL -- Buffer for output token isn't big enough
SEC_E_INSUFFICIENT_MEMORY -- Not enough memory
--*/
{
SspPrint(( SSP_API_MORE, "Entering SsprHandleFirstCall\n" ));
NTSTATUS Status = STATUS_SUCCESS;
PSSP_CONTEXT Context = NULL;
PSSP_CREDENTIAL Credential = NULL;
PNEGOTIATE_MESSAGE NegotiateMessage = NULL;
ULONG NegotiateMessageSize = 0;
PCHAR Where = NULL;
ULONG NegotiateFlagsKeyStrength;
STRING NtLmLocalOemComputerNameString;
STRING NtLmLocalOemPrimaryDomainNameString;
INC_CLIENT_AUTH();
//
// Initialization
//
*ContextAttributes = 0;
*NegotiateFlags = 0;
RtlInitString( &NtLmLocalOemComputerNameString, NULL );
RtlInitString( &NtLmLocalOemPrimaryDomainNameString, NULL );
//
// Get a pointer to the credential
//
Status = SspCredentialReferenceCredential(
CredentialHandle,
FALSE,
FALSE,
&Credential );
if ( !NT_SUCCESS( Status ) )
{
SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: invalid credential handle.\n" ));
goto Cleanup;
}
if ( (Credential->CredentialUseFlags & SECPKG_CRED_OUTBOUND) == 0 ) {
Status = SEC_E_INVALID_CREDENTIAL_USE;
SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: invalid credential use.\n" ));
goto Cleanup;
}
//
// Allocate a new context
//
Context = SspContextAllocateContext( );
if ( Context == NULL) {
Status = STATUS_NO_MEMORY;
SspPrint(( SSP_CRITICAL, "SsprHandleFirstCall: SspContextAllocateContext returned NULL\n"));
goto Cleanup;
}
//
// Build a handle to the newly created context.
//
*ContextHandle = (LSA_SEC_HANDLE) Context;
//
// We don't support any options.
//
// Complain about those that require we do something.
//
if ( (ContextReqFlags & ISC_REQ_PROMPT_FOR_CREDS) != 0 ) {
Status = SEC_E_INVALID_CONTEXT_REQ;
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: invalid ContextReqFlags 0x%lx.\n",
ContextReqFlags ));
goto Cleanup;
}
//
// Capture the default credentials from the credential structure.
//
if ( Credential->DomainName.Buffer != NULL ) {
Status = NtLmDuplicateUnicodeString(
&Context->DomainName,
&Credential->DomainName
);
if (!NT_SUCCESS(Status)) {
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: NtLmDuplicateUnicodeString (DomainName) returned %d\n",Status));
goto Cleanup;
}
}
if ( Credential->UserName.Buffer != NULL ) {
Status = NtLmDuplicateUnicodeString(
&Context->UserName,
&Credential->UserName
);
if (!NT_SUCCESS(Status)) {
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: NtLmDuplicateUnicodeString (UserName) returned %d\n", Status ));
goto Cleanup;
}
}
Status = SspCredentialGetPassword(
Credential,
&Context->Password
);
if (!NT_SUCCESS(Status)) {
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: SspCredentialGetPassword returned %d\n", Status ));
goto Cleanup;
}
//
// Compute the negotiate flags
//
//
// Supported key strength(s)
//
NegotiateFlagsKeyStrength = NTLMSSP_NEGOTIATE_56;
if( NtLmSecPkg.MachineState & SECPKG_STATE_STRONG_ENCRYPTION_PERMITTED )
{
NegotiateFlagsKeyStrength |= NTLMSSP_NEGOTIATE_128;
}
Context->NegotiateFlags = NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_OEM |
NTLMSSP_NEGOTIATE_NTLM |
((NtLmGlobalLmProtocolSupported != 0)
? NTLMSSP_NEGOTIATE_NTLM2 : 0 ) |
NTLMSSP_REQUEST_TARGET |
NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
NegotiateFlagsKeyStrength;
//
// If the caller specified INTEGRITY, SEQUENCE_DETECT or REPLAY_DETECT,
// that means they want to use the MakeSignature/VerifySignature
// calls. Add this to the negotiate.
//
if (ContextReqFlags &
(ISC_REQ_INTEGRITY | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT))
{
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SIGN |
NTLMSSP_NEGOTIATE_KEY_EXCH |
NTLMSSP_NEGOTIATE_LM_KEY ;
}
if ((ContextReqFlags & ISC_REQ_INTEGRITY) != 0)
{
*ContextAttributes |= ISC_RET_INTEGRITY;
Context->ContextFlags |= ISC_RET_INTEGRITY;
}
if ((ContextReqFlags & ISC_REQ_SEQUENCE_DETECT) != 0)
{
*ContextAttributes |= ISC_RET_SEQUENCE_DETECT;
Context->ContextFlags |= ISC_RET_SEQUENCE_DETECT;
}
if ((ContextReqFlags & ISC_REQ_REPLAY_DETECT) != 0)
{
*ContextAttributes |= ISC_RET_REPLAY_DETECT;
Context->ContextFlags |= ISC_RET_REPLAY_DETECT;
}
if ( (ContextReqFlags & ISC_REQ_NULL_SESSION ) != 0) {
*ContextAttributes |= ISC_RET_NULL_SESSION;
Context->ContextFlags |= ISC_RET_NULL_SESSION;
}
if ( (ContextReqFlags & ISC_REQ_CONNECTION ) != 0) {
*ContextAttributes |= ISC_RET_CONNECTION;
Context->ContextFlags |= ISC_RET_CONNECTION;
}
if ((ContextReqFlags & ISC_REQ_CONFIDENTIALITY) != 0) {
if (NtLmGlobalEncryptionEnabled) {
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_SEAL |
NTLMSSP_NEGOTIATE_LM_KEY |
NTLMSSP_NEGOTIATE_KEY_EXCH ;
*ContextAttributes |= ISC_RET_CONFIDENTIALITY;
Context->ContextFlags |= ISC_RET_CONFIDENTIALITY;
} else {
Status = STATUS_NOT_SUPPORTED;
SspPrint(( SSP_CRITICAL,
"SsprHandleFirstCall: NtLmGlobalEncryptionEnabled is FALSE\n"));
goto Cleanup;
}
}
//
// Check if the caller wants identify level
//
if ((ContextReqFlags & ISC_REQ_IDENTIFY)!= 0) {
Context->NegotiateFlags |= NTLMSSP_NEGOTIATE_IDENTIFY;
*ContextAttributes |= ISC_RET_IDENTIFY;
Context->ContextFlags |= ISC_RET_IDENTIFY;
}
IF_DEBUG( USE_OEM ) {
Context->NegotiateFlags &= ~NTLMSSP_NEGOTIATE_UNICODE;
}
if ( ((ContextReqFlags & ISC_REQ_MUTUAL_AUTH) != 0 ) &&
(NtLmGlobalMutualAuthLevel < 2 ) ) {
*ContextAttributes |= ISC_RET_MUTUAL_AUTH ;
if ( NtLmGlobalMutualAuthLevel == 0 )
{
Context->ContextFlags |= ISC_RET_MUTUAL_AUTH ;
}
}
//
// For connection oriented security, we send a negotiate message to
// the server. For datagram, we get back the server's
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -