DWORD ADCacheFindUserByName( LSA_DB_HANDLE hDb, PLSA_AD_PROVIDER_STATE pState, PLSA_LOGIN_NAME_INFO pUserNameInfo, PLSA_SECURITY_OBJECT* ppObject ) { DWORD dwError = 0; PLSA_LOGIN_NAME_INFO pPrefixedName = NULL; dwError = (*gpCacheProvider->pfnFindUserByName)( hDb, pUserNameInfo, ppObject); switch (dwError) { case LW_ERROR_NOT_HANDLED: case LW_ERROR_NO_SUCH_USER: case LW_ERROR_NO_SUCH_GROUP: case LW_ERROR_NO_SUCH_OBJECT: case LW_ERROR_NOT_SUPPORTED: if (pUserNameInfo->nameType == NameType_Alias && AD_ShouldAssumeDefaultDomain(pState)) { dwError = ADGetDefaultDomainPrefixedName( pState, pUserNameInfo->pszName, &pPrefixedName); BAIL_ON_LSA_ERROR(dwError); dwError = (*gpCacheProvider->pfnFindUserByName)( hDb, pPrefixedName, ppObject); BAIL_ON_LSA_ERROR(dwError); } BAIL_ON_LSA_ERROR(dwError); break; default: BAIL_ON_LSA_ERROR(dwError); } cleanup: if (pPrefixedName) { LsaSrvFreeNameInfo(pPrefixedName); } return dwError; error: goto cleanup; }
static DWORD LocalDirFindObjectsInternal( IN HANDLE hProvider, IN LSA_FIND_FLAGS FindFlags, IN OPTIONAL LSA_OBJECT_TYPE ObjectType, IN LSA_QUERY_TYPE QueryType, IN DWORD dwCount, IN LSA_QUERY_LIST QueryList, IN OUT PLSA_SECURITY_OBJECT* ppObjects ) { DWORD dwError = 0; PLOCAL_PROVIDER_CONTEXT pContext = (PLOCAL_PROVIDER_CONTEXT)hProvider; static WCHAR wszAttrNameObjectClass[] = LOCAL_DIR_ATTR_OBJECT_CLASS; static WCHAR wszAttrNameUID[] = LOCAL_DIR_ATTR_UID; static WCHAR wszAttrNameGID[] = LOCAL_DIR_ATTR_GID; static WCHAR wszAttrNamePrimaryGroup[] = LOCAL_DIR_ATTR_PRIMARY_GROUP; static WCHAR wszAttrNameSamAccountName[] = LOCAL_DIR_ATTR_SAM_ACCOUNT_NAME; static WCHAR wszAttrNamePassword[] = LOCAL_DIR_ATTR_PASSWORD; static WCHAR wszAttrNameGecos[] = LOCAL_DIR_ATTR_GECOS; static WCHAR wszAttrNameShell[] = LOCAL_DIR_ATTR_SHELL; static WCHAR wszAttrNameHomedir[] = LOCAL_DIR_ATTR_HOME_DIR; static WCHAR wszAttrNameUPN[] = LOCAL_DIR_ATTR_USER_PRINCIPAL_NAME; static WCHAR wszAttrNameObjectSID[] = LOCAL_DIR_ATTR_OBJECT_SID; static WCHAR wszAttrNameDN[] = LOCAL_DIR_ATTR_DISTINGUISHED_NAME; static WCHAR wszAttrNameNetBIOSDomain[] = LOCAL_DIR_ATTR_NETBIOS_NAME; static WCHAR wszAttrNameUserInfoFlags[] = LOCAL_DIR_ATTR_ACCOUNT_FLAGS; static WCHAR wszAttrNameAccountExpiry[] = LOCAL_DIR_ATTR_ACCOUNT_EXPIRY; static WCHAR wszAttrNamePasswdLastSet[] = LOCAL_DIR_ATTR_PASSWORD_LAST_SET; static WCHAR wszAttrNameNTHash[] = LOCAL_DIR_ATTR_NT_HASH; static WCHAR wszAttrNameLMHash[] = LOCAL_DIR_ATTR_LM_HASH; static PWSTR wszAttrs[] = { wszAttrNameObjectClass, wszAttrNameUID, wszAttrNameGID, wszAttrNamePrimaryGroup, wszAttrNameSamAccountName, wszAttrNamePassword, wszAttrNameGecos, wszAttrNameShell, wszAttrNameHomedir, wszAttrNameUPN, wszAttrNameObjectSID, wszAttrNameDN, wszAttrNameNetBIOSDomain, wszAttrNameUserInfoFlags, wszAttrNameAccountExpiry, wszAttrNamePasswdLastSet, wszAttrNameNTHash, wszAttrNameLMHash, NULL }; PDIRECTORY_ENTRY pEntries = NULL; PDIRECTORY_ENTRY pEntry = NULL; DWORD dwNumEntries = 0; PCSTR pszFilterTemplateQualified = LOCAL_DB_DIR_ATTR_NETBIOS_NAME " = %Q" \ " AND " LOCAL_DB_DIR_ATTR_SAM_ACCOUNT_NAME " = %Q%s"; PCSTR pszFilterTemplateString = "%s = %Q%s"; PCSTR pszFilterTemplateDword = "%s = %u%s"; PCSTR pszFilterTemplateType = " AND " LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u"; PCSTR pszFilterTemplateUserOrGroup = " AND (" \ LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u OR " \ LOCAL_DB_DIR_ATTR_OBJECT_CLASS " = %u)"; PCSTR pszFilterBy = NULL; PSTR pszFilterType = NULL; PWSTR pwszFilter = NULL; DWORD dwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN; DWORD dwIndex = 0; PLSA_LOGIN_NAME_INFO pLoginInfo = NULL; BOOLEAN bLocked = FALSE; BOOLEAN bFoundInvalidObject = FALSE; /* FIXME: support generic queries */ switch (ObjectType) { case LSA_OBJECT_TYPE_UNDEFINED: dwObjectClass = LOCAL_OBJECT_CLASS_UNKNOWN; break; case LSA_OBJECT_TYPE_USER: dwObjectClass = LOCAL_OBJECT_CLASS_USER; break; case LSA_OBJECT_TYPE_GROUP: dwObjectClass = LOCAL_OBJECT_CLASS_GROUP; break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } switch (QueryType) { case LSA_QUERY_TYPE_BY_DN: pszFilterBy = LOCAL_DB_DIR_ATTR_DISTINGUISHED_NAME; break; case LSA_QUERY_TYPE_BY_SID: pszFilterBy = LOCAL_DB_DIR_ATTR_OBJECT_SID; break; case LSA_QUERY_TYPE_BY_NT4: case LSA_QUERY_TYPE_BY_ALIAS: break; case LSA_QUERY_TYPE_BY_UPN: pszFilterBy = LOCAL_DB_DIR_ATTR_USER_PRINCIPAL_NAME; break; case LSA_QUERY_TYPE_BY_UNIX_ID: if (dwObjectClass == LOCAL_OBJECT_CLASS_USER) { pszFilterBy = LOCAL_DB_DIR_ATTR_UID; } else { pszFilterBy = LOCAL_DB_DIR_ATTR_GID; } break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } if (dwObjectClass == LOCAL_OBJECT_CLASS_UNKNOWN) { dwError = LwAllocateStringPrintf( &pszFilterType, pszFilterTemplateUserOrGroup, LOCAL_OBJECT_CLASS_USER, LOCAL_OBJECT_CLASS_GROUP); BAIL_ON_LSA_ERROR(dwError); } else { dwError = LwAllocateStringPrintf( &pszFilterType, pszFilterTemplateType, dwObjectClass); BAIL_ON_LSA_ERROR(dwError); } for (dwIndex = 0; dwIndex < dwCount; dwIndex++) { bFoundInvalidObject = FALSE; switch (QueryType) { case LSA_QUERY_TYPE_BY_ALIAS: case LSA_QUERY_TYPE_BY_NT4: dwError = LsaSrvCrackDomainQualifiedName( QueryList.ppszStrings[dwIndex], &pLoginInfo); BAIL_ON_LSA_ERROR(dwError); if (!pLoginInfo->pszDomain) { LOCAL_RDLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock); dwError = LwAllocateString( gLPGlobals.pszNetBIOSName, &pLoginInfo->pszDomain); BAIL_ON_LSA_ERROR(dwError); LOCAL_UNLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock); } dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszFilterTemplateQualified, pLoginInfo->pszDomain, pLoginInfo->pszName, pszFilterType ? pszFilterType : ""); BAIL_ON_LSA_ERROR(dwError); break; case LSA_QUERY_TYPE_BY_DN: case LSA_QUERY_TYPE_BY_SID: case LSA_QUERY_TYPE_BY_UPN: dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszFilterTemplateString, pszFilterBy, QueryList.ppszStrings[dwIndex], pszFilterType ? pszFilterType : ""); BAIL_ON_LSA_ERROR(dwError); break; case LSA_QUERY_TYPE_BY_UNIX_ID: dwError = DirectoryAllocateWC16StringFilterPrintf( &pwszFilter, pszFilterTemplateDword, pszFilterBy, QueryList.pdwIds[dwIndex], pszFilterType ? pszFilterType : ""); BAIL_ON_LSA_ERROR(dwError); break; default: dwError = LW_ERROR_INVALID_PARAMETER; BAIL_ON_LSA_ERROR(dwError); } dwError = DirectorySearch( pContext->hDirectory, NULL, 0, pwszFilter, wszAttrs, FALSE, &pEntries, &dwNumEntries); BAIL_ON_LSA_ERROR(dwError); if (dwNumEntries > 1) { dwError = LW_ERROR_DATA_ERROR; BAIL_ON_LSA_ERROR(dwError); } else if (dwNumEntries == 1) { pEntry = &pEntries[0]; dwError = LocalMarshalEntryToSecurityObject( pEntry, &ppObjects[dwIndex]); if (dwError) { if (dwError == LW_ERROR_NO_SUCH_OBJECT) { bFoundInvalidObject = TRUE; dwError = 0; } else { BAIL_ON_LSA_ERROR(dwError); } } else { dwError = LocalDirResolveUserObjectPrimaryGroupSid( hProvider, ppObjects[dwIndex]); BAIL_ON_LSA_ERROR(dwError); } } if ((dwNumEntries == 0 || bFoundInvalidObject) && QueryType == LSA_QUERY_TYPE_BY_UPN) { /* UPN lookup might fail because the UPN is generated, so try again as an NT4 lookup */ LSA_QUERY_LIST Single; Single.ppszStrings = &QueryList.ppszStrings[dwIndex]; dwError = LocalDirFindObjectsInternal( hProvider, FindFlags, ObjectType, LSA_QUERY_TYPE_BY_NT4, 1, Single, &ppObjects[dwIndex]); BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); pEntries = NULL; } if (pLoginInfo) { LsaSrvFreeNameInfo(pLoginInfo); pLoginInfo = NULL; } } cleanup: LOCAL_UNLOCK_RWLOCK(bLocked, &gLPGlobals.rwlock); LW_SAFE_FREE_STRING(pszFilterType); LW_SAFE_FREE_MEMORY(pwszFilter); if (pEntries) { DirectoryFreeEntries(pEntries, dwNumEntries); } if (pLoginInfo) { LsaSrvFreeNameInfo(pLoginInfo); } return dwError; error: goto cleanup; }
DWORD LocalDirFindObjectByGenericName( HANDLE hProvider, IN LSA_FIND_FLAGS FindFlags, IN LSA_OBJECT_TYPE ObjectType, PCSTR pszName, PLSA_SECURITY_OBJECT* ppObject ) { DWORD dwError = 0; PLSA_SECURITY_OBJECT* ppObjects = NULL; LSA_QUERY_LIST QueryList; LSA_QUERY_TYPE QueryType = 0; PLSA_LOGIN_NAME_INFO pLoginInfo = NULL; BAIL_ON_INVALID_HANDLE(hProvider); dwError = LsaSrvCrackDomainQualifiedName( pszName, &pLoginInfo); BAIL_ON_LSA_ERROR(dwError); switch (pLoginInfo->nameType) { case NameType_NT4: QueryType = LSA_QUERY_TYPE_BY_NT4; break; case NameType_UPN: QueryType = LSA_QUERY_TYPE_BY_UPN; break; case NameType_Alias: QueryType = LSA_QUERY_TYPE_BY_ALIAS; break; default: dwError = LW_ERROR_INTERNAL; BAIL_ON_LSA_ERROR(dwError); } QueryList.ppszStrings = &pszName; dwError = LocalFindObjects( hProvider, FindFlags, ObjectType, QueryType, 1, QueryList, &ppObjects); BAIL_ON_LSA_ERROR(dwError); if (ppObjects[0] == NULL) { switch (ObjectType) { case LSA_OBJECT_TYPE_USER: dwError = LW_ERROR_NO_SUCH_USER; break; case LSA_OBJECT_TYPE_GROUP: dwError = LW_ERROR_NO_SUCH_GROUP; break; default: dwError = LW_ERROR_NO_SUCH_OBJECT; } BAIL_ON_LSA_ERROR(dwError); } *ppObject = ppObjects[0]; ppObjects[0] = NULL; cleanup: if (pLoginInfo) { LsaSrvFreeNameInfo(pLoginInfo); } LsaUtilFreeSecurityObjectList(1, ppObjects); return dwError; error: 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; }