📄 userapi.cxx
字号:
SspPrint(( SSP_API, "Entering SpDeleteUserModeContext 0x%lx\n", ContextHandle ));
PNTLM_CLIENT_CONTEXT pContext = NULL;
NTSTATUS Status = STATUS_SUCCESS, SaveStatus = STATUS_SUCCESS;
//
// Find the currently existing user context and delink it // so that another context cannot Reference it before we
// Dereference this one.
//
pContext = ReferenceUserContext(ContextHandle, TRUE);
if (pContext == NULL)
{
//
// pContext is legally NULL when we are dealing with an incomplete
// context. This can often be the case when the second call to
// InitializeSecurityContext() fails.
//
/// Status = STATUS_INVALID_HANDLE;
Status = STATUS_SUCCESS;
SspPrint(( SSP_API_MORE, "SpDeleteUserModeContext, local pContext is NULL\n" ));
goto CleanUp;
}
RtlEnterCriticalSection(&NtLmUserContextLock);
if ((pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_EXPORTED_CONTEXT) != 0)
{
// Ignore all other errors and pass back
SaveStatus = SEC_I_NO_LSA_CONTEXT;
}
RtlLeaveCriticalSection(&NtLmUserContextLock);
CleanUp:
if (pContext != NULL)
{
Status = DereferenceUserContext(pContext);
}
if (SaveStatus == SEC_I_NO_LSA_CONTEXT)
{
Status = SaveStatus;
}
SspPrint(( SSP_API, "Leaving SpDeleteUserModeContext: 0x%lx\n", Status ));
return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
}
VOID
SspRc4Key(
IN ULONG NegotiateFlags,
OUT struct RC4_KEYSTRUCT *pRc4Key,
IN PUCHAR pSessionKey
)
/*++
RoutineDescription:
Create an RC4 key schedule, making sure key length is OK for export
Arguments:
NegotiateFlags negotiate feature flags; NTLM2 bit is only one looked at
pRc4Key pointer to RC4 key schedule structure; filled in by this routine
pSessionKey pointer to session key -- must be full 16 bytes
Return Value:
--*/
{
//
// For NTLM2, effective length was already cut down
//
if ((NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2) != 0) {
rc4_key(pRc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pSessionKey);
} else if( NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY ) {
UCHAR Key[MSV1_0_LANMAN_SESSION_KEY_LENGTH];
ULONG KeyLen;
ASSERT(MSV1_0_LANMAN_SESSION_KEY_LENGTH == 8);
// prior to Win2k, negotiated key strength had no bearing on
// key size. So, to allow proper interop to NT4, we don't
// worry about 128bit. 56bit and 40bit are the only supported options.
// 56bit is enabled because this was introduced in Win2k, and
// Win2k -> Win2k interops correctly.
//
#if 0
if( NegotiateFlags & NTLMSSP_NEGOTIATE_128 ) {
KeyLen = 8;
} else
#endif
if( NegotiateFlags & NTLMSSP_NEGOTIATE_56 ) {
KeyLen = 7;
//
// Put a well-known salt at the end of the key to
// limit the changing part to 56 bits.
//
Key[7] = 0xa0;
} else {
KeyLen = 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;
}
SspPrint(( SSP_SESSION_KEYS, "Non NTLMv2 LM_KEY session key size: %lu\n", KeyLen));
RtlCopyMemory(Key,pSessionKey,KeyLen);
rc4_key(pRc4Key, MSV1_0_LANMAN_SESSION_KEY_LENGTH, Key);
} else {
SspPrint(( SSP_SESSION_KEYS, "Non NTLMv2 (not LM_KEY) session key size: %lu\n", 16));
rc4_key(pRc4Key, MSV1_0_USER_SESSION_KEY_LENGTH, pSessionKey);
}
}
//+-------------------------------------------------------------------------
//
// Function: SpInitUserModeContext
//
// Synopsis: Creates a user-mode context from a packed LSA mode context
//
// Effects:
//
// Arguments: ContextHandle - Lsa mode context handle for the context
// PackedContext - A marshalled buffer containing the LSA
// mode context.
//
// Requires:
//
// Returns: STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES
//
// Notes:
//
//
//--------------------------------------------------------------------------
NTSTATUS NTAPI
SpInitUserModeContext(
IN ULONG_PTR ContextHandle,
IN PSecBuffer PackedContext
)
{
ASSERT(PackedContext);
SspPrint(( SSP_API, "Entering SpInitUserModeContext 0x%lx\n", ContextHandle ));
NTSTATUS Status = STATUS_SUCCESS;
PNTLM_CLIENT_CONTEXT pContext = NULL;
UINT Length = 0;
PNTLM_CLIENT_CONTEXT pTmpContext = (PNTLM_CLIENT_CONTEXT) PackedContext->pvBuffer;
if (PackedContext->cbBuffer < sizeof(NTLM_CLIENT_CONTEXT))
{
Status = STATUS_INVALID_PARAMETER;
SspPrint(( SSP_CRITICAL, "SpInitUserModeContext, ContextData size < NTLM_CLIENT_CONTEXT\n" ));
goto Cleanup;
}
pContext = (PNTLM_CLIENT_CONTEXT) NtLmAllocate( sizeof(NTLM_CLIENT_CONTEXT) );
if (!pContext)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
SspPrint(( SSP_CRITICAL, "SpInitUserModeContext, NtLmAllocate returns NULL\n" ));
goto Cleanup;
}
//
// If ClientTokenHandle is NULL, we are being called as
// as an effect of InitializeSecurityContext, else we are
// being called because of AcceptSecurityContext
//
if (pTmpContext->ClientTokenHandle != NULL)
{
pContext->ClientTokenHandle = pTmpContext->ClientTokenHandle;
if (FAILED(SspCreateTokenDacl(pTmpContext->ClientTokenHandle)))
{
Status = STATUS_INVALID_HANDLE;
SspPrint(( SSP_CRITICAL, "SpInitUserModeContext, SspCreateTokenDacl failed\n" ));
goto Cleanup;
}
}
// Copy contents of PackedContext->pvBuffer to pContext
pContext->LsaContext = ContextHandle;
pContext->NegotiateFlags = pTmpContext->NegotiateFlags;
pContext->References = 1;
//
// keep all 128 bits here, so signing can be strong even if encrypt can't be
//
RtlCopyMemory( pContext->SessionKey,
pTmpContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
//
// if doing full duplex as part of NTLM2, generate different sign
// and seal keys for each direction
// all we do is MD5 the base session key with a different magic constant
//
if ( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM2 ) {
MD5_CTX Md5Context;
ULONG KeyLen;
ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_128 )
KeyLen = 16;
else if( pContext->NegotiateFlags & NTLMSSP_NEGOTIATE_56 )
KeyLen = 7;
else
KeyLen = 5;
SspPrint(( SSP_SESSION_KEYS, "NTLMv2 session key size: %lu\n", KeyLen));
//
// make client to server encryption key
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
MD5Update(&Md5Context, (unsigned char*)CSSEALMAGIC, sizeof(CSSEALMAGIC));
MD5Final(&Md5Context);
//
// if TokenHandle == NULL, this is the client side
// put key in the right place: for client it's seal, for server it's unseal
//
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// make server to client encryption key
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, KeyLen);
MD5Update(&Md5Context, (unsigned char*)SCSEALMAGIC, sizeof(SCSEALMAGIC));
MD5Final(&Md5Context);
ASSERT(MD5DIGESTLEN == MSV1_0_USER_SESSION_KEY_LENGTH);
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->UnsealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->SealSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// make client to server signing key -- always 128 bits!
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
MD5Update(&Md5Context, (unsigned char*)CSSIGNMAGIC, sizeof(CSSIGNMAGIC));
MD5Final(&Md5Context);
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// make server to client signing key
//
MD5Init(&Md5Context);
MD5Update(&Md5Context, pContext->SessionKey, MSV1_0_USER_SESSION_KEY_LENGTH);
MD5Update(&Md5Context, (unsigned char*)SCSIGNMAGIC, sizeof(SCSIGNMAGIC));
MD5Final(&Md5Context);
if (pContext->ClientTokenHandle == NULL)
RtlCopyMemory(pContext->VerifySessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
else
RtlCopyMemory(pContext->SignSessionKey, Md5Context.digest, MSV1_0_USER_SESSION_KEY_LENGTH);
//
// set pointers to different key schedule and nonce for each direction
// key schedule will be filled in later...
//
pContext->pSealRc4Sched = &pContext->SealRc4Sched;
pContext->pUnsealRc4Sched = &pContext->UnsealRc4Sched;
pContext->pSendNonce = &pContext->SendNonce;
pContext->pRecvNonce = &pContext->RecvNonce;
} else {
//
// just copy session key to all four keys
// leave them 128 bits -- they get cut to 40 bits later
//
RtlCopyMemory( pContext->SealSessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
RtlCopyMemory( pContext->UnsealSessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
RtlCopyMemory( pContext->SignSessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
RtlCopyMemory( pContext->VerifySessionKey,
pContext->SessionKey,
MSV1_0_USER_SESSION_KEY_LENGTH);
//
// set pointers to share a key schedule and nonce for each direction
// (OK because half duplex!)
//
pContext->pSealRc4Sched = &pContext->SealRc4Sched;
pContext->pUnsealRc4Sched = &pContext->SealRc4Sched;
pContext->pSendNonce = &pContext->SendNonce;
pContext->pRecvNonce = &pContext->SendNonce;
}
Length = (UINT) (PackedContext->cbBuffer -
sizeof(NTLM_CLIENT_CONTEXT));
if (Length == 0)
{
//There's no string after the NTLM_CLIENT_CONTEXT struct
pContext->ContextNames = NULL;
}
else
{
pContext->ContextNames = (LPWSTR) NtLmAllocate(Length + sizeof(WCHAR));
if (!pContext->ContextNames)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Cleanup;
}
RtlCopyMemory(pContext->ContextNames, pTmpContext + 1, Length );
// null terminate the string
*(pContext->ContextNames + (Length/2)) = L'\0';
}
pContext->SendNonce = pTmpContext->SendNonce;
pContext->RecvNonce = pTmpContext->RecvNonce;
SspRc4Key(pContext->NegotiateFlags, &pContext->SealRc4Sched, pContext->SealSessionKey);
SspRc4Key(pContext->NegotiateFlags, &pContext->UnsealRc4Sched, pContext->UnsealSessionKey);
pContext->PasswordExpiry = pTmpContext->PasswordExpiry;
pContext->UserFlags = pTmpContext->UserFlags;
RtlEnterCriticalSection(&NtLmUserContextLock);
InsertHeadList ( &NtLmUserContextList, &pContext->Next );
RtlLeaveCriticalSection(&NtLmUserContextLock);
Cleanup:
if (!NT_SUCCESS(Status))
{
if (pContext != NULL)
{
FreeUserContext(pContext);
}
}
// Let FreeContextBuffer handle freeing the virtual allocs
if (PackedContext->pvBuffer != NULL)
{
FreeContextBuffer(PackedContext->pvBuffer);
PackedContext->pvBuffer = NULL;
}
SspPrint(( SSP_API, "Leaving SpInitUserModeContext: 0x%lx\n", Status ));
return(SspNtStatusToSecStatus(Status, SEC_E_INTERNAL_ERROR));
}
//
// 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:
Notes: This was stolen from net\svcdlls\ntlmssp\client\sign.c ,
routine SspGenCheckSum. It's possible that
bugs got copied too
--*/
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -