DWORD NtlmCreateValidatedContext( IN PNTLM_RESPONSE_MESSAGE_V1 pNtlmRespMsg, IN DWORD dwMsgSize, IN PNTLM_CONTEXT pNtlmCtxtChlng, IN PBYTE pSessionKey, IN DWORD dwSessionKeyLen, IN NTLM_CRED_HANDLE hCred, OUT PNTLM_CONTEXT *ppNtlmContext ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_CONTEXT pNtlmContext = NULL; SEC_CHAR* pUserName = NULL; SEC_CHAR* pDomainName = NULL; PNTLM_RESPONSE_MESSAGE_V2 pV2Message = NULL; RC4_KEY Rc4Key; *ppNtlmContext = NULL; dwError = NtlmCreateContext(hCred, &pNtlmContext); BAIL_ON_LSA_ERROR(dwError); pNtlmContext->NtlmState = NtlmStateResponse; pNtlmContext->NegotiatedFlags = pNtlmCtxtChlng->NegotiatedFlags; dwError = LwAllocateStringPrintf( &pNtlmContext->pszClientUsername, "%s\\%s", pNtlmCtxtChlng->pUserInfo->pszDomain, pNtlmCtxtChlng->pUserInfo->pszAccount); BAIL_ON_LSA_ERROR(dwError); memcpy(pNtlmContext->SessionKey, pSessionKey, NTLM_SESSION_KEY_SIZE); pNtlmContext->cbSessionKeyLen = dwSessionKeyLen; pNtlmContext->bInitiatedSide = FALSE; if (pNtlmContext->NegotiatedFlags & NTLM_FLAG_KEY_EXCH) { pV2Message = (PNTLM_RESPONSE_MESSAGE_V2)pNtlmRespMsg; if (dwMsgSize < sizeof(*pV2Message)) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } if (LW_LTOH32(pV2Message->SessionKey.dwOffset) + LW_LTOH16(pV2Message->SessionKey.usLength) > dwMsgSize) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } if (LW_LTOH16(pV2Message->SessionKey.usLength) != NTLM_SESSION_KEY_SIZE) { dwError = ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } RC4_set_key( &Rc4Key, pNtlmContext->cbSessionKeyLen, pNtlmContext->SessionKey); RC4(&Rc4Key, NTLM_SESSION_KEY_SIZE, LW_LTOH32(pV2Message->SessionKey.dwOffset) + (PBYTE)pV2Message, pNtlmContext->SessionKey); } dwError = NtlmInitializeKeys(pNtlmContext); BAIL_ON_LSA_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pUserName); LW_SAFE_FREE_MEMORY(pDomainName); *ppNtlmContext = pNtlmContext; return dwError; error: if (pNtlmContext) { NtlmFreeContext(&pNtlmContext); } goto cleanup; }
DWORD NtlmCreateResponseContext( IN PNTLM_CHALLENGE_MESSAGE pChlngMsg, IN NTLM_CRED_HANDLE hCred, IN BOOLEAN bDoAnonymous, OUT PNTLM_CONTEXT* ppNtlmContext, OUT PSecBuffer pOutput ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_RESPONSE_MESSAGE_V1 pMessage = NULL; PCSTR pUserNameTemp = NULL; PCSTR pPassword = NULL; PNTLM_CONTEXT pNtlmContext = NULL; PBYTE pMasterKey = NULL; BYTE LmUserSessionKey[NTLM_SESSION_KEY_SIZE] = {0}; BYTE NtlmUserSessionKey[NTLM_SESSION_KEY_SIZE] = {0}; BYTE LanManagerSessionKey[NTLM_SESSION_KEY_SIZE] = {0}; BYTE SecondaryKey[NTLM_SESSION_KEY_SIZE] = {0}; PLSA_LOGIN_NAME_INFO pUserNameInfo = NULL; DWORD dwMessageSize = 0; NTLM_CONFIG config; DWORD dwNtRespType = 0; DWORD dwLmRespType = 0; *ppNtlmContext = NULL; dwError = NtlmReadRegistry(&config); BAIL_ON_LSA_ERROR(dwError); if (bDoAnonymous) { pUserNameTemp = ""; pPassword = ""; } else { NtlmGetCredentialInfo( hCred, &pUserNameTemp, &pPassword, NULL); if (!pUserNameTemp[0] && !pPassword[0]) { bDoAnonymous = TRUE; } } if (bDoAnonymous) { dwError = LwAllocateMemory( sizeof(*pUserNameInfo), OUT_PPVOID(&pUserNameInfo)); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString( "", &pUserNameInfo->pszName); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString( "", &pUserNameInfo->pszDomain); BAIL_ON_LSA_ERROR(dwError); } else { dwError = LsaSrvCrackDomainQualifiedName( pUserNameTemp, &pUserNameInfo); BAIL_ON_LSA_ERROR(dwError); } dwError = NtlmCreateContext(hCred, &pNtlmContext); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateString( pUserNameTemp, &pNtlmContext->pszClientUsername); BAIL_ON_LSA_ERROR(dwError); if (bDoAnonymous) { dwNtRespType = NTLM_RESPONSE_TYPE_ANON_NTLM; dwLmRespType = NTLM_RESPONSE_TYPE_ANON_LM; } else if (config.bSendNTLMv2) { dwNtRespType = NTLM_RESPONSE_TYPE_NTLMv2; // TODO: the correct thing is to use LMv2 dwLmRespType = NTLM_RESPONSE_TYPE_LM; } else if(LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_NTLM2) { dwLmRespType = NTLM_RESPONSE_TYPE_NTLM2; dwNtRespType = NTLM_RESPONSE_TYPE_NTLM2; } else { dwNtRespType = NTLM_RESPONSE_TYPE_NTLM; dwLmRespType = NTLM_RESPONSE_TYPE_LM; } dwError = NtlmCreateResponseMessage( pChlngMsg, pUserNameInfo->pszName, pUserNameInfo->pszDomain, pPassword, (PBYTE)&gXpSpoof, dwNtRespType, dwLmRespType, &dwMessageSize, &pMessage, LmUserSessionKey, NtlmUserSessionKey ); BAIL_ON_LSA_ERROR(dwError); // As a side effect of creating the response, we must also set/produce the // master session key... pMasterKey = NtlmUserSessionKey; if (LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_LM_KEY) { NtlmGenerateLanManagerSessionKey( pMessage, LmUserSessionKey, LanManagerSessionKey); pMasterKey = LanManagerSessionKey; } if (LW_LTOH32(pChlngMsg->NtlmFlags) & NTLM_FLAG_KEY_EXCH) { // This is the key we will use for session security... dwError = NtlmGetRandomBuffer( SecondaryKey, NTLM_SESSION_KEY_SIZE); BAIL_ON_LSA_ERROR(dwError); // Encrypt it with the "master key" set above and send it along with the // response NtlmStoreSecondaryKey( pMasterKey, SecondaryKey, pMessage); pMasterKey = SecondaryKey; } NtlmWeakenSessionKey( pChlngMsg, pMasterKey, &pNtlmContext->cbSessionKeyLen); memcpy(pNtlmContext->SessionKey, pMasterKey, NTLM_SESSION_KEY_SIZE); pNtlmContext->NegotiatedFlags = LW_LTOH32(pChlngMsg->NtlmFlags); pOutput->cbBuffer = dwMessageSize; pOutput->BufferType = SECBUFFER_TOKEN; pOutput->pvBuffer = pMessage; pNtlmContext->NtlmState = NtlmStateResponse; pNtlmContext->bInitiatedSide = TRUE; pNtlmContext->bDoAnonymous = bDoAnonymous; dwError = NtlmInitializeKeys(pNtlmContext); BAIL_ON_LSA_ERROR(dwError); cleanup: if (pUserNameInfo) { LsaSrvFreeNameInfo(pUserNameInfo); } *ppNtlmContext = pNtlmContext; return dwError; error: LW_SAFE_FREE_MEMORY(pMessage); if (pNtlmContext) { NtlmFreeContext(&pNtlmContext); } pOutput->cbBuffer = 0; pOutput->BufferType = 0; pOutput->pvBuffer = NULL; goto cleanup; }
DWORD NtlmCreateGuestContext( OUT PNTLM_CONTEXT *ppNtlmContext ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_CONTEXT pNtlmContext = NULL; HANDLE hConnection = (HANDLE)NULL; LSA_QUERY_LIST queryList = {0}; PLSA_SECURITY_OBJECT* ppObjects = NULL; PSTR pszGuestSid = NULL; *ppNtlmContext = NULL; dwError = NtlmCreateContext(NULL, &pNtlmContext); BAIL_ON_LSA_ERROR(dwError); pNtlmContext->NtlmState = NtlmStateResponse; // Set the NegotiatedFlags to 0 since there's the resulting // context has no direct relation to the original user authentication // request and no session key. This may change with future // investigation. pNtlmContext->NegotiatedFlags = 0; // Verify that the local Guest account has been enabled dwError = LsaSrvOpenServer(0, 0, getpid(), &hConnection); BAIL_ON_LSA_ERROR(dwError); dwError = NtlmGetLocalGuestAccountSid(&pszGuestSid); BAIL_ON_LSA_ERROR(dwError); queryList.ppszStrings = (PCSTR*)&pszGuestSid; dwError = LsaSrvFindObjects( hConnection, LSA_PROVIDER_TAG_LOCAL, 0, LSA_OBJECT_TYPE_USER, LSA_QUERY_TYPE_BY_SID, 1, queryList, &ppObjects); BAIL_ON_LSA_ERROR(dwError); if (!ppObjects[0]) { dwError = LW_ERROR_NO_SUCH_USER; BAIL_ON_LSA_ERROR(dwError); } if (ppObjects[0]->userInfo.bAccountDisabled) { dwError = LW_ERROR_ACCOUNT_DISABLED; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateStringPrintf( &pNtlmContext->pszClientUsername, "%s\\%s", ppObjects[0]->pszNetbiosDomainName, ppObjects[0]->pszSamAccountName); // NULL session key memset(pNtlmContext->SessionKey, 0x0, NTLM_SESSION_KEY_SIZE); pNtlmContext->cbSessionKeyLen = NTLM_SESSION_KEY_SIZE; pNtlmContext->bInitiatedSide = FALSE; pNtlmContext->MappedToGuest = TRUE; cleanup: LsaUtilFreeSecurityObjectList(1, ppObjects); if (hConnection) { LsaSrvCloseServer(hConnection); } LW_SAFE_FREE_STRING(pszGuestSid); *ppNtlmContext = pNtlmContext; return dwError; error: if (pNtlmContext) { NtlmFreeContext(&pNtlmContext); } goto cleanup; }
DWORD NtlmCreateNegotiateContext( IN NTLM_CRED_HANDLE hCred, IN DWORD fContextReq, IN PCSTR pDomain, IN PCSTR pWorkstation, IN PBYTE pOsVersion, OUT PNTLM_CONTEXT* ppNtlmContext, OUT PSecBuffer pOutput ) { DWORD dwError = LW_ERROR_SUCCESS; PNTLM_CONTEXT pNtlmContext = NULL; DWORD dwMessageSize = 0; PNTLM_NEGOTIATE_MESSAGE_V1 pMessage = NULL; NTLM_CONFIG config; DWORD dwDefaultOptions = // Always do signing and sealing since they cannot be turned off on // Windows NTLM_FLAG_SIGN | NTLM_FLAG_SEAL | NTLM_FLAG_OEM | NTLM_FLAG_REQUEST_TARGET | NTLM_FLAG_NTLM | NTLM_FLAG_DOMAIN | 0; DWORD dwDceStyleOptions = NTLM_FLAG_OEM | NTLM_FLAG_REQUEST_TARGET | NTLM_FLAG_NTLM | NTLM_FLAG_DOMAIN | 0; DWORD dwOptions = 0; *ppNtlmContext = NULL; dwError = NtlmCreateContext(hCred, &pNtlmContext); BAIL_ON_LSA_ERROR(dwError); dwError = NtlmReadRegistry(&config); BAIL_ON_LSA_ERROR(dwError); if (fContextReq & ISC_REQ_USE_DCE_STYLE) { dwOptions = dwDceStyleOptions; } else { dwOptions = dwDefaultOptions; } if (config.bSupportUnicode) { dwOptions |= NTLM_FLAG_UNICODE; } if (config.bSupportNTLM2SessionSecurity) { dwOptions |= NTLM_FLAG_NTLM2; } if (config.bSupportKeyExchange) { dwOptions |= NTLM_FLAG_KEY_EXCH; } if (config.bSupport56bit) { dwOptions |= NTLM_FLAG_56; } if (config.bSupport128bit) { dwOptions |= NTLM_FLAG_128; } if (fContextReq & ISC_REQ_INTEGRITY) { dwOptions |= NTLM_FLAG_SIGN; } if (fContextReq & ISC_REQ_CONFIDENTIALITY) { dwOptions |= NTLM_FLAG_SEAL; } if (fContextReq & ISC_REQ_NULL_SESSION) { pNtlmContext->bDoAnonymous = TRUE; } dwError = NtlmCreateNegotiateMessage( dwOptions, pDomain, pWorkstation, pOsVersion, &dwMessageSize, &pMessage); BAIL_ON_LSA_ERROR(dwError); pOutput->cbBuffer = dwMessageSize; pOutput->BufferType = SECBUFFER_TOKEN; pOutput->pvBuffer = pMessage; pNtlmContext->NtlmState = NtlmStateNegotiate; cleanup: *ppNtlmContext = pNtlmContext; return dwError; error: LW_SAFE_FREE_MEMORY(pMessage); pOutput->cbBuffer = 0; pOutput->BufferType = 0; pOutput->pvBuffer = NULL; if (pNtlmContext) { NtlmFreeContext(&pNtlmContext); } goto cleanup; }