DWORD NtlmCreateChallengeContext( IN const NTLM_NEGOTIATE_MESSAGE_V1* pNtlmNegMsg, IN NTLM_CRED_HANDLE hCred, OUT PNTLM_CONTEXT *ppNtlmContext, OUT PSecBuffer pOutput ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_CREDENTIALS pCred = (PNTLM_CREDENTIALS)hCred; PNTLM_CONTEXT pNtlmContext = NULL; DWORD dwMessageSize = 0; PNTLM_CHALLENGE_MESSAGE pMessage = NULL; PSTR pServerName = NULL; PSTR pDomainName = NULL; PSTR pDnsServerName = NULL; PSTR pDnsDomainName = NULL; BOOLEAN bInLock = FALSE; *ppNtlmContext = NULL; dwError = NtlmCreateContext(hCred, &pNtlmContext); BAIL_ON_LSA_ERROR(dwError); if (pCred) { NTLM_LOCK_MUTEX(bInLock, &pCred->Mutex); dwError = NtlmGetNameInformation( pCred->pszDomainName, &pServerName, &pDomainName, &pDnsServerName, &pDnsDomainName); BAIL_ON_LSA_ERROR(dwError); NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex); } else { dwError = NtlmGetNameInformation( NULL, &pServerName, &pDomainName, &pDnsServerName, &pDnsDomainName); BAIL_ON_LSA_ERROR(dwError); } dwError = NtlmGetRandomBuffer( pNtlmContext->Challenge, NTLM_CHALLENGE_SIZE ); BAIL_ON_LSA_ERROR(dwError); dwError = NtlmCreateChallengeMessage( pNtlmNegMsg, pServerName, pDomainName, pDnsServerName, pDnsDomainName, (PBYTE)&gW2KSpoof, pNtlmContext->Challenge, &dwMessageSize, &pMessage ); BAIL_ON_LSA_ERROR(dwError); pNtlmContext->NegotiatedFlags = LW_LTOH32(pMessage->NtlmFlags); pOutput->cbBuffer = dwMessageSize; pOutput->BufferType = SECBUFFER_TOKEN; pOutput->pvBuffer = pMessage; pNtlmContext->NtlmState = NtlmStateChallenge; cleanup: *ppNtlmContext = pNtlmContext; LW_SAFE_FREE_STRING(pServerName); LW_SAFE_FREE_STRING(pDomainName); LW_SAFE_FREE_STRING(pDnsServerName); LW_SAFE_FREE_STRING(pDnsDomainName); if (pCred) { NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex); } return dwError; error: LW_SAFE_FREE_MEMORY(pMessage); if (pNtlmContext) { NtlmReleaseContext(&pNtlmContext); *ppNtlmContext = NULL; } pOutput->cbBuffer = 0; pOutput->BufferType = 0; pOutput->pvBuffer = NULL; goto cleanup; }
DWORD NtlmServerAcceptSecurityContext( IN HANDLE Handle, IN NTLM_CRED_HANDLE hCred, IN OUT PNTLM_CONTEXT_HANDLE phContext, IN const SecBuffer* pInput, IN DWORD fContextReq, IN DWORD TargetDataRep, IN OUT PNTLM_CONTEXT_HANDLE phNewContext, OUT PSecBuffer pOutput, OUT PDWORD pfContextAttr, OUT PTimeStamp ptsTimeStamp ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_CONTEXT pNtlmContext = NULL; PNTLM_CONTEXT pNtlmCtxtOut = NULL; PNTLM_CONTEXT pNtlmCtxtChlng = NULL; NTLM_CONTEXT_HANDLE ContextHandle = NULL; const NTLM_NEGOTIATE_MESSAGE_V1* pNegMsg = NULL; PNTLM_RESPONSE_MESSAGE_V1 pRespMsg = NULL; DWORD dwMessageSize = 0; BYTE SessionKey[NTLM_SESSION_KEY_SIZE] = {0}; DWORD dwRetFlags = 0; ptsTimeStamp = 0; pOutput->pvBuffer = NULL; if (phContext) { pNtlmContext = *phContext; } if (!pNtlmContext) { if (pInput->BufferType != SECBUFFER_TOKEN || pInput->cbBuffer == 0) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } pNegMsg = pInput->pvBuffer; dwMessageSize = pInput->cbBuffer; if (dwMessageSize < sizeof(*pNegMsg)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } dwError = NtlmCreateChallengeContext( pNegMsg, hCred, &pNtlmCtxtOut, pOutput); BAIL_ON_LSA_ERROR(dwError); dwError = LW_WARNING_CONTINUE_NEEDED; } else { // The only time we should get a context handle passed in is when // we are validating a challenge and we need to look up the original // challenge sent pNtlmCtxtChlng = pNtlmContext; // In this case we need to grab the response message sent in if (pInput->BufferType != SECBUFFER_TOKEN || pInput->cbBuffer == 0) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } pRespMsg = pInput->pvBuffer; dwMessageSize = pInput->cbBuffer; dwError = NtlmValidateResponse( Handle, hCred, pRespMsg, dwMessageSize, pNtlmCtxtChlng, SessionKey); switch(dwError) { case LW_ERROR_SUCCESS: // The response has been validated and contains all the information we // are looking for; retain it... the original (challenge) context will // be freed when we return. dwError = NtlmCreateValidatedContext( pRespMsg, dwMessageSize, pNtlmCtxtChlng, SessionKey, NTLM_SESSION_KEY_SIZE, hCred, &pNtlmCtxtOut ); BAIL_ON_LSA_ERROR(dwError); pNtlmCtxtOut->pUserInfo = pNtlmCtxtChlng->pUserInfo; pNtlmCtxtChlng->pUserInfo = NULL; break; case LW_ERROR_NOT_HANDLED: // Attempt to fallback to Guest access dwError = NtlmCreateGuestContext(&pNtlmCtxtOut); // Restore previous error code on failure if (dwError != LW_ERROR_SUCCESS) { dwError = LW_ERROR_NOT_HANDLED; } BAIL_ON_LSA_ERROR(dwError); break; default: BAIL_ON_LSA_ERROR(dwError); break; } } ContextHandle = pNtlmCtxtOut; cleanup: *pfContextAttr = dwRetFlags; *phNewContext = ContextHandle; return(dwError); error: LW_SAFE_FREE_MEMORY(pOutput->pvBuffer); pOutput->cbBuffer = 0; pOutput->BufferType = 0; dwRetFlags = 0; if (ContextHandle) { NtlmReleaseContext(&ContextHandle); } else if (pNtlmCtxtOut) { NtlmReleaseContext(&pNtlmCtxtOut); } goto cleanup; }
DWORD NtlmServerInitializeSecurityContext( IN OPTIONAL NTLM_CRED_HANDLE hCredential, IN OPTIONAL const NTLM_CONTEXT_HANDLE hContext, IN OPTIONAL SEC_CHAR* pszTargetName, IN DWORD fContextReq, IN DWORD Reserved1, IN DWORD TargetDataRep, IN OPTIONAL const SecBuffer* pInput, IN DWORD Reserved2, IN OUT OPTIONAL PNTLM_CONTEXT_HANDLE phNewContext, OUT PSecBuffer pOutput, OUT PDWORD pfContextAttr, OUT OPTIONAL PTimeStamp ptsExpiry ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_CREDENTIALS pCred = (PNTLM_CREDENTIALS)hCredential; PNTLM_CONTEXT pNtlmContext = NULL; PSTR pWorkstation = NULL; PSTR pDomain = NULL; PNTLM_CHALLENGE_MESSAGE pMessage = NULL; DWORD dwMessageSize ATTRIBUTE_UNUSED = 0; BOOLEAN bInLock = FALSE; pOutput->pvBuffer = NULL; if (hContext) { pNtlmContext = hContext; } if (!pNtlmContext) { if (pCred) { NTLM_LOCK_MUTEX(bInLock, &pCred->Mutex); dwError = NtlmGetNameInformation( pCred->pszDomainName, &pWorkstation, &pDomain, NULL, NULL); BAIL_ON_LSA_ERROR(dwError); NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex); } else { dwError = NtlmGetNameInformation( NULL, &pWorkstation, &pDomain, NULL, NULL); BAIL_ON_LSA_ERROR(dwError); } // If we start with a NULL context, create a negotiate message dwError = NtlmCreateNegotiateContext( hCredential, fContextReq, pDomain, pWorkstation, (PBYTE)&gXpSpoof, //for now add OS ver info... config later &pNtlmContext, pOutput); BAIL_ON_LSA_ERROR(dwError); dwError = LW_WARNING_CONTINUE_NEEDED; } else { if (pInput->BufferType != SECBUFFER_TOKEN || pInput->cbBuffer == 0) { dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } pMessage = pInput->pvBuffer; dwMessageSize = pInput->cbBuffer; dwError = NtlmCreateResponseContext( pMessage, hCredential, pNtlmContext->bDoAnonymous, &pNtlmContext, pOutput); BAIL_ON_LSA_ERROR(dwError); } *phNewContext = pNtlmContext; if (pfContextAttr) { NtlmGetContextInfo( pNtlmContext, NULL, pfContextAttr, NULL, NULL, NULL); } cleanup: if (pCred) { NTLM_UNLOCK_MUTEX(bInLock, &pCred->Mutex); } LW_SAFE_FREE_STRING(pWorkstation); LW_SAFE_FREE_STRING(pDomain); return dwError; error: LW_SAFE_FREE_MEMORY(pOutput->pvBuffer); pOutput->cbBuffer = 0; pOutput->BufferType = 0; // If this function has already succeed once, we MUST make sure phNewContext // is set so the caller can cleanup whatever context is remaining. It // could be the original negotiate context or a new response context but // either way it is vital that the caller get a context they can actually // cleanup ONCE they've received ANY context from this function. // // If hContext is NULL, that indicates this is the first time through this // call and we can safely release our context. if ( pNtlmContext && !hContext) { NtlmReleaseContext(&pNtlmContext); phNewContext = NULL; } goto cleanup; }