/* Editor Settings: expandtabs and use 4 spaces for indentation * ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: * * -*- mode: c, c-basic-offset: 4 -*- */ /* * Copyright Likewise Software 2004-2008 * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. You should have received a copy of the GNU General * Public License along with this program. If not, see * . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Copyright (C) Likewise Software. All rights reserved. * * Module Name: * * adnetapi.c * * Abstract: * * Likewise Security and Authentication Subsystem (LSASS) * * Wrappers for calls to NETAPI * * Authors: Krishna Ganugapati (krishnag@likewisesoftware.com) * Sriram Nambakam (snambakam@likewisesoftware.com) * Wei Fu (wfu@likewisesoftware.com) * Gerald Carter */ #include "adprovider.h" #include "adnetapi.h" static NetrCredentials gSchannelCreds = { 0 }; static NetrCredentials* gpSchannelCreds = NULL; static handle_t ghSchannelBinding = NULL; static pthread_mutex_t gSchannelLock = PTHREAD_MUTEX_INITIALIZER; static BOOLEAN AD_NtStatusIsConnectionError( NTSTATUS status ); static BOOLEAN AD_WinErrorIsConnectionError( WINERR winError ); static DWORD AD_GetSystemCreds( LW_PIO_CREDS* ppCreds ) { LW_PIO_CREDS pCreds = NULL; DWORD dwError = 0; PSTR pszUsername = NULL; PSTR pszPassword = NULL; PSTR pszDomainDnsName = NULL; PSTR pszHostDnsDomain = NULL; PSTR pszMachPrincipal = NULL; dwError = LwKrb5GetMachineCreds( &pszUsername, &pszPassword, &pszDomainDnsName, &pszHostDnsDomain); BAIL_ON_LSA_ERROR(dwError); dwError = LwAllocateStringPrintf( &pszMachPrincipal, "%s@%s", pszUsername, pszDomainDnsName); BAIL_ON_LSA_ERROR(dwError); dwError = LwIoCreateKrb5CredsA( pszMachPrincipal, LSASS_CACHE_PATH, &pCreds); BAIL_ON_LSA_ERROR(dwError); *ppCreds = pCreds; cleanup: LW_SAFE_FREE_STRING(pszUsername); LW_SAFE_FREE_STRING(pszPassword); LW_SAFE_FREE_STRING(pszDomainDnsName); LW_SAFE_FREE_STRING(pszHostDnsDomain); LW_SAFE_FREE_STRING(pszMachPrincipal); return dwError; error: *ppCreds = NULL; if (pCreds != NULL) { LwIoDeleteCreds(pCreds); } goto cleanup; } DWORD AD_SetSystemAccess( OUT OPTIONAL LW_PIO_CREDS* ppOldToken ) { LW_PIO_CREDS pOldToken = NULL; LW_PIO_CREDS pSystemToken = NULL; DWORD dwError = 0; dwError = AD_GetSystemCreds(&pSystemToken); BAIL_ON_LSA_ERROR(dwError); if (ppOldToken) { dwError = LwIoGetThreadCreds(&pOldToken); BAIL_ON_LSA_ERROR(dwError); } dwError = LwIoSetThreadCreds(pSystemToken); BAIL_ON_LSA_ERROR(dwError); cleanup: if (pSystemToken != NULL) { LwIoDeleteCreds(pSystemToken); } if (ppOldToken) { *ppOldToken = pOldToken; } return dwError; error: if (pOldToken != NULL) { LwIoDeleteCreds(pOldToken); pOldToken = NULL; } goto cleanup; } static VOID AD_ClearSchannelState( VOID ); DWORD AD_NetInitMemory( VOID ) { DWORD dwError = 0; dwError = LsaRpcInitMemory(); BAIL_ON_LSA_ERROR(dwError); dwError = NetrInitMemory(); BAIL_ON_LSA_ERROR(dwError); dwError = SamrInitMemory(); BAIL_ON_LSA_ERROR(dwError); dwError = NetInitMemory(); BAIL_ON_LSA_ERROR(dwError); error: return dwError; } DWORD AD_NetShutdownMemory( VOID ) { DWORD dwError = 0; AD_ClearSchannelState(); dwError = NetDestroyMemory(); BAIL_ON_LSA_ERROR(dwError); dwError = SamrDestroyMemory(); BAIL_ON_LSA_ERROR(dwError); dwError = NetrDestroyMemory(); BAIL_ON_LSA_ERROR(dwError); dwError = LsaRpcDestroyMemory(); BAIL_ON_LSA_ERROR(dwError); error: return dwError; } DWORD AD_NetUserChangePassword( PCSTR pszDomainName, BOOLEAN bIsInOneWayTrustedDomain, PCSTR pszLoginId, PCSTR pszUserPrincipalName, PCSTR pszOldPassword, PCSTR pszNewPassword ) { DWORD dwError = 0; PWSTR pwszDomainName = NULL; PWSTR pwszLoginId = NULL; PWSTR pwszOldPassword = NULL; PWSTR pwszNewPassword = NULL; PLSA_CREDS_FREE_INFO pFreeInfo = NULL; LW_PIO_CREDS pOldCreds = NULL; BOOLEAN bChangedToken = FALSE; BAIL_ON_INVALID_STRING(pszDomainName); BAIL_ON_INVALID_STRING(pszLoginId); if (bIsInOneWayTrustedDomain) { dwError = LsaSetSMBCreds( pszDomainName, pszUserPrincipalName, pszOldPassword, FALSE, &pFreeInfo, &pOldCreds); BAIL_ON_LSA_ERROR(dwError); } else { dwError = AD_SetSystemAccess(&pOldCreds); BAIL_ON_LSA_ERROR(dwError); } bChangedToken = TRUE; dwError = LsaMbsToWc16s( pszDomainName, &pwszDomainName); BAIL_ON_LSA_ERROR(dwError); dwError = LsaMbsToWc16s( pszLoginId, &pwszLoginId); BAIL_ON_LSA_ERROR(dwError); if (!LW_IS_NULL_OR_EMPTY_STR(pszOldPassword)) { dwError = LsaMbsToWc16s( pszOldPassword, &pwszOldPassword); BAIL_ON_LSA_ERROR(dwError); } if (!LW_IS_NULL_OR_EMPTY_STR(pszNewPassword)) { dwError = LsaMbsToWc16s( pszNewPassword, &pwszNewPassword); BAIL_ON_LSA_ERROR(dwError); } dwError = NetUserChangePassword( pwszDomainName, pwszLoginId, pwszOldPassword, pwszNewPassword); BAIL_ON_LSA_ERROR(dwError); cleanup: LW_SAFE_FREE_MEMORY(pwszDomainName); LW_SAFE_FREE_MEMORY(pwszLoginId); LW_SAFE_FREE_MEMORY(pwszOldPassword); LW_SAFE_FREE_MEMORY(pwszNewPassword); LsaFreeSMBCreds(&pFreeInfo); if (bChangedToken) { LwIoSetThreadCreds(pOldCreds); } if (pOldCreds != NULL) { LwIoDeleteCreds(pOldCreds); } return AD_MapNetApiError(dwError); error: goto cleanup; } // ISSUE-2008/08/25-dalmeida -- This needs to be pulled in by header // with LsaOpenPolicy2 and LsaLookupNames2 functions. #ifndef STATUS_UNHANDLED_EXCEPTION #define STATUS_UNHANDLED_EXCEPTION 0xc0000144 #endif static LSA_OBJECT_TYPE GetObjectType( IN LsaSidType Type ) { LSA_OBJECT_TYPE ObjectType = LSA_OBJECT_TYPE_UNDEFINED; switch(Type) { case SID_TYPE_USER: ObjectType = LSA_OBJECT_TYPE_USER; break; case SID_TYPE_DOM_GRP: case SID_TYPE_ALIAS: case SID_TYPE_WKN_GRP: ObjectType = LSA_OBJECT_TYPE_GROUP; break; case SID_TYPE_DOMAIN: ObjectType = LSA_OBJECT_TYPE_DOMAIN; break; default: ObjectType = LSA_OBJECT_TYPE_UNDEFINED; } return ObjectType; } DWORD AD_NetLookupObjectSidByName( IN PCSTR pszHostname, IN PCSTR pszObjectName, OUT PSTR* ppszObjectSid, OUT LSA_OBJECT_TYPE* pObjectType, OUT PBOOLEAN pbIsNetworkError ) { DWORD dwError = 0; PLSA_TRANSLATED_NAME_OR_SID* ppTranslatedSids = NULL; PSTR pszObjectSid = NULL; BOOLEAN bIsNetworkError = FALSE; dwError = AD_NetLookupObjectSidsByNames( pszHostname, 1, (PSTR*)&pszObjectName, &ppTranslatedSids, NULL, &bIsNetworkError); BAIL_ON_LSA_ERROR(dwError); // In case of NOT found, the above function bails out with dwError == LW_ERROR_RPC_LSA_LOOKUPNAMES_FAILED // Double check here again if (!ppTranslatedSids || !ppTranslatedSids[0]) { dwError = LW_ERROR_NO_SUCH_OBJECT; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateString(ppTranslatedSids[0]->pszNT4NameOrSid, &pszObjectSid); BAIL_ON_LSA_ERROR(dwError); *ppszObjectSid = pszObjectSid; *pObjectType = ppTranslatedSids[0]->ObjectType; cleanup: *pbIsNetworkError = bIsNetworkError; if (ppTranslatedSids) { LsaFreeTranslatedNameList(ppTranslatedSids, 1); } return dwError; error: *ppszObjectSid = NULL; LW_SAFE_FREE_STRING(pszObjectSid); *pObjectType = LSA_OBJECT_TYPE_UNDEFINED; LSA_LOG_ERROR("Failed to find user, group, or domain by name (name = '%s', searched host = '%s') -> error = %d, symbol = %s", LSA_SAFE_LOG_STRING(pszObjectName), LSA_SAFE_LOG_STRING(pszHostname), dwError, LwWin32ExtErrorToName(dwError)); dwError = LW_ERROR_NO_SUCH_OBJECT; goto cleanup; } DWORD AD_NetLookupObjectSidsByNames( IN PCSTR pszHostname, IN DWORD dwNamesCount, IN PSTR* ppszNames, OUT PLSA_TRANSLATED_NAME_OR_SID** pppTranslatedSids, OUT OPTIONAL PDWORD pdwFoundSidsCount, OUT PBOOLEAN pbIsNetworkError ) { DWORD dwError = 0; PWSTR pwcHost = NULL; RPCSTATUS rpcStatus; NTSTATUS status = 0; handle_t lsa_binding = (HANDLE)NULL; DWORD dwAccess_rights = LSA_ACCESS_LOOKUP_NAMES_SIDS; POLICY_HANDLE hPolicy = NULL; DWORD dwLevel; DWORD dwFoundSidsCount = 0; PWSTR* ppwcNames = NULL; RefDomainList* pDomains = NULL; TranslatedSid2* pSids = NULL; PLSA_TRANSLATED_NAME_OR_SID* ppTranslatedSids = NULL; PSID pObject_sid = NULL; BOOLEAN bIsNetworkError = FALSE; DWORD i = 0; LW_PIO_CREDS pCreds = NULL; LW_PIO_CREDS pOldToken = NULL; BOOLEAN bChangedToken = FALSE; BAIL_ON_INVALID_STRING(pszHostname); dwError = LsaMbsToWc16s( pszHostname, &pwcHost); BAIL_ON_LSA_ERROR(dwError); dwError = AD_SetSystemAccess(&pOldToken); BAIL_ON_LSA_ERROR(dwError); bChangedToken = TRUE; status = LwIoGetThreadCreds(&pCreds); dwError = LwNtStatusToErrno(status); BAIL_ON_LSA_ERROR(dwError); rpcStatus = InitLsaBindingDefault(&lsa_binding, pszHostname, pCreds); if (rpcStatus != 0) { LSA_LOG_DEBUG("InitLsaBindingDefault() failed with %d (0x%08x)", rpcStatus, rpcStatus); dwError = LW_ERROR_RPC_LSABINDING_FAILED; bIsNetworkError = TRUE; BAIL_ON_LSA_ERROR(dwError); } if (lsa_binding == NULL) { dwError = LW_ERROR_RPC_LSABINDING_FAILED; BAIL_ON_LSA_ERROR(dwError); } // Convert ppszNames to ppwcNames dwError = LwAllocateMemory( sizeof(*ppwcNames)*dwNamesCount, (PVOID*)&ppwcNames); BAIL_ON_LSA_ERROR(dwError); for (i = 0; i < dwNamesCount; i++) { dwError = LsaMbsToWc16s( ppszNames[i], &ppwcNames[i]); BAIL_ON_LSA_ERROR(dwError); } status = LsaOpenPolicy2(lsa_binding, pwcHost, NULL, dwAccess_rights, &hPolicy); if (status != 0) { LSA_LOG_DEBUG("LsaOpenPolicy2() failed with %d (0x%08x)", status, status); dwError = LW_ERROR_RPC_OPENPOLICY_FAILED; if (AD_NtStatusIsConnectionError(status)) { bIsNetworkError = TRUE; } BAIL_ON_LSA_ERROR(dwError); } /* Lookup name to sid */ dwLevel = 1; status = LsaLookupNames2( lsa_binding, hPolicy, dwNamesCount, ppwcNames, &pDomains, &pSids, dwLevel, &dwFoundSidsCount); if (status != 0) { if (LW_STATUS_NONE_MAPPED == status) { // This is ok. LSA_LOG_DEBUG("LsaLookupNames2() empty results (0 out of %u)", dwNamesCount); dwFoundSidsCount = 0; dwError = LwAllocateMemory( sizeof(*ppTranslatedSids)*dwNamesCount, (PVOID*)&ppTranslatedSids); BAIL_ON_LSA_ERROR(dwError); dwError = 0; goto cleanup; } else if (LW_STATUS_SOME_NOT_MAPPED == status) { LSA_LOG_DEBUG("LsaLookupNames2() partial results (%u out of %u)", dwFoundSidsCount, dwNamesCount); dwError = 0; } else { LSA_LOG_DEBUG("LsaLookupNames2() failed with %d (0x%08x)", status, status); if (AD_NtStatusIsConnectionError(status)) { bIsNetworkError = TRUE; } dwError = LW_ERROR_RPC_LSA_LOOKUPNAME2_FAILED; BAIL_ON_LSA_ERROR(dwError); } } if (dwFoundSidsCount == 0) { dwError = LW_ERROR_RPC_LSA_LOOKUPNAME2_NOT_FOUND; BAIL_ON_LSA_ERROR(dwError); } else if (dwFoundSidsCount > dwNamesCount) { dwError = LW_ERROR_RPC_LSA_LOOKUPNAME2_FOUND_DUPLICATES; BAIL_ON_LSA_ERROR(dwError); } else if (!pSids || !pDomains) { dwError = LW_ERROR_RPC_LSA_LOOKUPNAME2_NOT_FOUND; BAIL_ON_LSA_ERROR(dwError); } // For incomplete results (LW_STATUS_SOME_NOT_MAPPED == status), leave ppTranslatedSids[i] as NULL for those NOT found // to maintain ppszNames[i] -> ppTranslatedSids[i] dwError = LwAllocateMemory( sizeof(*ppTranslatedSids)*dwNamesCount, (PVOID*)&ppTranslatedSids); BAIL_ON_LSA_ERROR(dwError); for (i = 0; i < dwNamesCount; i++) { LSA_OBJECT_TYPE ObjectType = LSA_OBJECT_TYPE_UNDEFINED; DWORD dwDomainSid_index = 0; ObjectType = GetObjectType(pSids[i].type); if (ObjectType == LSA_OBJECT_TYPE_UNDEFINED) { continue; } dwError = LwAllocateMemory( sizeof(*ppTranslatedSids[i]), (PVOID*)&ppTranslatedSids[i]); BAIL_ON_LSA_ERROR(dwError); ppTranslatedSids[i]->ObjectType = ObjectType; dwDomainSid_index = pSids[i].index; if (dwDomainSid_index >= pDomains->count) { dwError = LW_ERROR_RPC_LSA_LOOKUPNAME2_FAILED; BAIL_ON_LSA_ERROR(dwError); } LW_SAFE_FREE_MEMORY(pObject_sid); if (LSA_OBJECT_TYPE_DOMAIN == ObjectType) { dwError = LsaAllocateCStringFromSid( &ppTranslatedSids[i]->pszNT4NameOrSid, pDomains->domains[dwDomainSid_index].sid); BAIL_ON_LSA_ERROR(dwError); } else { dwError = LsaAllocateSidAppendRid( &pObject_sid, pDomains->domains[dwDomainSid_index].sid, pSids[i].rid); BAIL_ON_LSA_ERROR(dwError); dwError = LsaAllocateCStringFromSid( &ppTranslatedSids[i]->pszNT4NameOrSid, pObject_sid); BAIL_ON_LSA_ERROR(dwError); } } cleanup: LW_SAFE_FREE_MEMORY(pwcHost); if (ppwcNames) { for (i = 0; i < dwNamesCount; i++) { LW_SAFE_FREE_MEMORY(ppwcNames[i]); } LwFreeMemory(ppwcNames); } if (pDomains) { LsaRpcFreeMemory(pDomains); } if (pSids) { LsaRpcFreeMemory(pSids); } LW_SAFE_FREE_MEMORY(pObject_sid); status = LsaClose(lsa_binding, hPolicy); if (status != 0 && dwError == 0) { LSA_LOG_DEBUG("LsaClose() failed with %d (0x%08x)", status, status); dwError = LW_ERROR_RPC_CLOSEPOLICY_FAILED; } if (lsa_binding) { FreeLsaBinding(&lsa_binding); } if (bChangedToken) { LwIoSetThreadCreds(pOldToken); } if (pOldToken != NULL) { LwIoDeleteCreds(pOldToken); } if (pCreds) { LwIoDeleteCreds(pCreds); } *pppTranslatedSids = ppTranslatedSids; if (pdwFoundSidsCount) { *pdwFoundSidsCount = dwFoundSidsCount; } if (pbIsNetworkError) { *pbIsNetworkError = bIsNetworkError; } return dwError; error: if (ppTranslatedSids) { LsaFreeTranslatedNameList(ppTranslatedSids, dwNamesCount); ppTranslatedSids = NULL; } dwFoundSidsCount = 0; goto cleanup; } DWORD AD_NetLookupObjectNameBySid( IN PCSTR pszHostname, IN PCSTR pszObjectSid, OUT PSTR* ppszNT4Name, OUT LSA_OBJECT_TYPE* pObjectType, OUT PBOOLEAN pbIsNetworkError ) { DWORD dwError = 0; PLSA_TRANSLATED_NAME_OR_SID* ppTranslatedNames = NULL; PSTR pszNT4Name = NULL; BOOLEAN bIsNetworkError = FALSE; dwError = AD_NetLookupObjectNamesBySids( pszHostname, 1, (PSTR*)&pszObjectSid, &ppTranslatedNames, NULL, &bIsNetworkError); BAIL_ON_LSA_ERROR(dwError); // In case of NOT found, the above function bails out with dwError == LW_ERROR_RPC_LSA_LOOKUPSIDS_FAILED // Double check here again if (!ppTranslatedNames || !ppTranslatedNames[0]) { dwError = LW_ERROR_NO_SUCH_OBJECT; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateString(ppTranslatedNames[0]->pszNT4NameOrSid, &pszNT4Name); BAIL_ON_LSA_ERROR(dwError); *ppszNT4Name = pszNT4Name; *pObjectType = ppTranslatedNames[0]->ObjectType; cleanup: *pbIsNetworkError = bIsNetworkError; if (ppTranslatedNames) { LsaFreeTranslatedNameList(ppTranslatedNames, 1); } return dwError; error: *ppszNT4Name = NULL; LW_SAFE_FREE_STRING(pszNT4Name); *pObjectType = LSA_OBJECT_TYPE_UNDEFINED; LSA_LOG_ERROR("Failed to find user, group, or domain by sid (sid = '%s', searched host = '%s') -> error = %d, symbol = %s", LSA_SAFE_LOG_STRING(pszObjectSid), LSA_SAFE_LOG_STRING(pszHostname), dwError, LwWin32ExtErrorToName(dwError)); dwError = LW_ERROR_NO_SUCH_OBJECT; goto cleanup; } DWORD AD_NetLookupObjectNamesBySids( IN PCSTR pszHostname, IN DWORD dwSidsCount, IN PSTR* ppszObjectSids, OUT PLSA_TRANSLATED_NAME_OR_SID** pppTranslatedNames, OUT OPTIONAL PDWORD pdwFoundNamesCount, OUT PBOOLEAN pbIsNetworkError ) { DWORD dwError = 0; PWSTR pwcHost = NULL; RPCSTATUS rpcStatus; NTSTATUS status = 0; handle_t lsa_binding = (HANDLE)NULL; DWORD dwAccess_rights = LSA_ACCESS_LOOKUP_NAMES_SIDS; POLICY_HANDLE hPolicy = NULL; SidArray sid_array = {0}; DWORD dwLevel = 1; DWORD dwFoundNamesCount = 0; RefDomainList* pDomains = NULL; PSTR* ppszDomainNames = NULL; PSID pObjectSID = NULL; TranslatedName* name_array = NULL; PSTR pszUsername = NULL; PLSA_TRANSLATED_NAME_OR_SID* ppTranslatedNames = NULL; BOOLEAN bIsNetworkError = FALSE; DWORD i = 0; PIO_CREDS pCreds = NULL; LW_PIO_CREDS pOldToken = NULL; BOOLEAN bChangedToken = FALSE; BAIL_ON_INVALID_STRING(pszHostname); dwError = LsaMbsToWc16s( pszHostname, &pwcHost); BAIL_ON_LSA_ERROR(dwError); dwError = AD_SetSystemAccess(&pOldToken); BAIL_ON_LSA_ERROR(dwError); bChangedToken = TRUE; status = LwIoGetThreadCreds(&pCreds); dwError = LwNtStatusToErrno(status); BAIL_ON_LSA_ERROR(dwError); rpcStatus = InitLsaBindingDefault(&lsa_binding, pszHostname, pCreds); if (rpcStatus != 0) { LSA_LOG_DEBUG("InitLsaBindingDefault() failed with %d (0x%08x)", rpcStatus, rpcStatus); dwError = LW_ERROR_RPC_LSABINDING_FAILED; bIsNetworkError = TRUE; BAIL_ON_LSA_ERROR(dwError); } if (lsa_binding == NULL) { dwError = LW_ERROR_RPC_LSABINDING_FAILED; BAIL_ON_LSA_ERROR(dwError); } // Convert ppszObjectSids to sid_array sid_array.num_sids = dwSidsCount; dwError = LwAllocateMemory( sizeof(*sid_array.sids)*sid_array.num_sids, (PVOID*)&sid_array.sids); BAIL_ON_LSA_ERROR(dwError); for (i = 0; i < sid_array.num_sids; i++) { dwError = LsaAllocateSidFromCString( &pObjectSID, ppszObjectSids[i]); BAIL_ON_LSA_ERROR(dwError); sid_array.sids[i].sid = pObjectSID; pObjectSID = NULL; } status = LsaOpenPolicy2(lsa_binding, pwcHost, NULL, dwAccess_rights, &hPolicy); if (status != 0) { LSA_LOG_DEBUG("LsaOpenPolicy2() failed with %d (0x%08x)", status, status); dwError = LW_ERROR_RPC_OPENPOLICY_FAILED; if (AD_NtStatusIsConnectionError(status)) { bIsNetworkError = TRUE; } BAIL_ON_LSA_ERROR(dwError); } /* Lookup sid to name */ status = LsaLookupSids( lsa_binding, hPolicy, &sid_array, &pDomains, &name_array, dwLevel, &dwFoundNamesCount); if (status != 0) { if (LW_STATUS_NONE_MAPPED == status) { // This is ok. LSA_LOG_DEBUG("LsaLookupNames2() empty results (0 out of %u)", dwSidsCount); dwFoundNamesCount = 0; dwError = LwAllocateMemory( sizeof(*ppTranslatedNames)*dwSidsCount, (PVOID*)&ppTranslatedNames); BAIL_ON_LSA_ERROR(dwError); dwError = 0; goto cleanup; } else if (LW_STATUS_SOME_NOT_MAPPED == status) { LSA_LOG_DEBUG("LsaLookupSids() partial results (%u out of %u)", dwFoundNamesCount, dwSidsCount); dwError = 0; } else { LSA_LOG_DEBUG("LsaLookupSids() failed with %d (0x%08x)", status, status); if (AD_NtStatusIsConnectionError(status)) { bIsNetworkError = TRUE; } dwError = LW_ERROR_RPC_LSA_LOOKUPSIDS_FAILED; BAIL_ON_LSA_ERROR(dwError); } } if (dwFoundNamesCount == 0) { dwError = LW_ERROR_RPC_LSA_LOOKUPSIDS_NOT_FOUND; BAIL_ON_LSA_ERROR(dwError); } else if (dwFoundNamesCount > dwSidsCount) { dwError = LW_ERROR_RPC_LSA_LOOKUPSIDS_FOUND_DUPLICATES; BAIL_ON_LSA_ERROR(dwError); } else if (!name_array || !pDomains) { dwError = LW_ERROR_RPC_LSA_LOOKUPSIDS_NOT_FOUND; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateMemory( sizeof(*ppszDomainNames)*pDomains->count, (PVOID*)&ppszDomainNames); BAIL_ON_LSA_ERROR(dwError); for (i = 0; i < pDomains->count; i++) { if (pDomains->domains[i].name.len > 0) { dwError = LsaWc16snToMbs( pDomains->domains[i].name.string, &ppszDomainNames[i], pDomains->domains[i].name.len / 2); BAIL_ON_LSA_ERROR(dwError); } } // For incomplete results (LW_STATUS_SOME_NOT_MAPPED == status), leave ppTranslatedNames[i] as NULL for those NOT found // to maintain ppszObjectSids[i] -> ppTranslatedNames[i] dwError = LwAllocateMemory( sizeof(*ppTranslatedNames)*dwSidsCount, (PVOID*)&ppTranslatedNames); BAIL_ON_LSA_ERROR(dwError); for (i = 0; i < dwSidsCount; i++) { LSA_OBJECT_TYPE ObjectType = LSA_OBJECT_TYPE_UNDEFINED; PCSTR pszDomainName = NULL; ObjectType = GetObjectType(name_array[i].type); if (ObjectType == LSA_OBJECT_TYPE_UNDEFINED) { continue; } // Check for invalid domain indexing if (name_array[i].sid_index >= pDomains->count) { dwError = LW_ERROR_RPC_LSA_LOOKUPSIDS_NOT_FOUND; BAIL_ON_LSA_ERROR(dwError); } pszDomainName = ppszDomainNames[name_array[i].sid_index]; if (name_array[i].name.len > 0) { dwError = LsaWc16snToMbs( name_array[i].name.string, &pszUsername, name_array[i].name.len / 2); BAIL_ON_LSA_ERROR(dwError); } if (LW_IS_NULL_OR_EMPTY_STR(pszDomainName) || ((ObjectType != LSA_OBJECT_TYPE_DOMAIN) && LW_IS_NULL_OR_EMPTY_STR(pszUsername)) || ((ObjectType == LSA_OBJECT_TYPE_DOMAIN) && !LW_IS_NULL_OR_EMPTY_STR(pszUsername))) { dwError = LW_ERROR_RPC_LSA_LOOKUPSIDS_NOT_FOUND; BAIL_ON_LSA_ERROR(dwError); } dwError = LwAllocateMemory( sizeof(*ppTranslatedNames[i]), (PVOID*)&ppTranslatedNames[i]); BAIL_ON_LSA_ERROR(dwError); ppTranslatedNames[i]->ObjectType = ObjectType; if (ObjectType != LSA_OBJECT_TYPE_DOMAIN) { dwError = ADGetDomainQualifiedString( pszDomainName, pszUsername, &ppTranslatedNames[i]->pszNT4NameOrSid); BAIL_ON_LSA_ERROR(dwError); } else { dwError = LwAllocateString( pszDomainName, &ppTranslatedNames[i]->pszNT4NameOrSid); BAIL_ON_LSA_ERROR(dwError); LwStrToUpper(ppTranslatedNames[i]->pszNT4NameOrSid); } LW_SAFE_FREE_STRING(pszUsername); } cleanup: if (pDomains) { LwFreeStringArray(ppszDomainNames,pDomains->count); LsaRpcFreeMemory(pDomains); } LW_SAFE_FREE_STRING(pszUsername); LW_SAFE_FREE_MEMORY(pwcHost); if (name_array) { LsaRpcFreeMemory(name_array); } if (sid_array.sids) { for (i = 0; i < sid_array.num_sids; i++) { LW_SAFE_FREE_MEMORY(sid_array.sids[i].sid); } LW_SAFE_FREE_MEMORY(sid_array.sids); } LW_SAFE_FREE_MEMORY(pObjectSID); status = LsaClose(lsa_binding, hPolicy); if (status != 0 && dwError == 0){ LSA_LOG_DEBUG("LsaClose() failed with %d (0x%08x)", status, status); dwError = LW_ERROR_RPC_CLOSEPOLICY_FAILED; } if (lsa_binding) { FreeLsaBinding(&lsa_binding); } if (bChangedToken) { LwIoSetThreadCreds(pOldToken); } if (pOldToken != NULL) { LwIoDeleteCreds(pOldToken); } if (pCreds) { LwIoDeleteCreds(pCreds); } *pppTranslatedNames = ppTranslatedNames; if (pdwFoundNamesCount) { *pdwFoundNamesCount = dwFoundNamesCount; } if (pbIsNetworkError) { *pbIsNetworkError = bIsNetworkError; } return dwError; error: if (ppTranslatedNames) { LsaFreeTranslatedNameList(ppTranslatedNames, dwSidsCount); ppTranslatedNames = NULL; } dwFoundNamesCount = 0; goto cleanup; } DWORD AD_DsEnumerateDomainTrusts( IN PCSTR pszDomainControllerName, IN DWORD dwFlags, OUT NetrDomainTrust** ppTrusts, OUT PDWORD pdwCount, OUT OPTIONAL PBOOLEAN pbIsNetworkError ) { DWORD dwError = 0; PWSTR pwcDomainControllerName = NULL; RPCSTATUS status = 0; handle_t netr_b = NULL; WINERR winError = 0; NetrDomainTrust* pTrusts = NULL; DWORD dwCount = 0; BOOLEAN bIsNetworkError = FALSE; LW_PIO_CREDS pCreds = NULL; LW_PIO_CREDS pOldToken = NULL; BOOLEAN bChangedToken = FALSE; dwError = LsaMbsToWc16s(pszDomainControllerName, &pwcDomainControllerName); BAIL_ON_LSA_ERROR(dwError); dwError = AD_SetSystemAccess(&pOldToken); BAIL_ON_LSA_ERROR(dwError); bChangedToken = TRUE; status = LwIoGetThreadCreds(&pCreds); dwError = LwNtStatusToErrno(status); BAIL_ON_LSA_ERROR(dwError); status = InitNetlogonBindingDefault(&netr_b, pszDomainControllerName, pCreds, FALSE); if (status != 0) { LSA_LOG_DEBUG("Failed to bind to %s (error %d)", pszDomainControllerName, status); dwError = LW_ERROR_RPC_NETLOGON_FAILED; bIsNetworkError = TRUE; BAIL_ON_LSA_ERROR(dwError); } winError = DsrEnumerateDomainTrusts(netr_b, pwcDomainControllerName, dwFlags, &pTrusts, &dwCount); if (winError) { LSA_LOG_DEBUG("Failed to enumerate trusts at %s (error %d)", pszDomainControllerName, winError); switch (winError) { case ERROR_ACCESS_DENIED: dwError = winError; break; default: dwError = LW_ERROR_ENUM_DOMAIN_TRUSTS_FAILED; } if (AD_WinErrorIsConnectionError(winError)) { bIsNetworkError = TRUE; } BAIL_ON_LSA_ERROR(dwError); } cleanup: if (netr_b) { FreeNetlogonBinding(&netr_b); netr_b = NULL; } LW_SAFE_FREE_MEMORY(pwcDomainControllerName); if (bChangedToken) { LwIoSetThreadCreds(pOldToken); } if (pOldToken != NULL) { LwIoDeleteCreds(pOldToken); } if (pCreds != NULL) { LwIoDeleteCreds(pCreds); } *ppTrusts = pTrusts; *pdwCount = dwCount; if (pbIsNetworkError) { *pbIsNetworkError = bIsNetworkError; } return dwError; error: dwCount = 0; if (pTrusts) { NetrFreeMemory(pTrusts); pTrusts = NULL; } goto cleanup; } VOID AD_FreeDomainTrusts( IN OUT NetrDomainTrust** ppTrusts ) { if (ppTrusts && *ppTrusts) { NetrFreeMemory(*ppTrusts); *ppTrusts = NULL; } } DWORD AD_DsGetDcName( IN PCSTR pszServerName, IN PCSTR pszDomainName, IN BOOLEAN bReturnDnsName, OUT PSTR* ppszDomainDnsOrFlatName, OUT PSTR* ppszDomainForestDnsName, OUT OPTIONAL PBOOLEAN pbIsNetworkError ) { DWORD dwError = 0; PWSTR pwcServerName = NULL; PWSTR pwcDomainName = NULL; RPCSTATUS status = 0; handle_t netr_b = NULL; WINERR winError = 0; BOOLEAN bIsNetworkError = FALSE; LW_PIO_CREDS pCreds = NULL; LW_PIO_CREDS pOldToken = NULL; BOOLEAN bChangedToken = FALSE; const UINT32 dwGetDcNameflags = bReturnDnsName ? DS_RETURN_DNS_NAME : DS_RETURN_FLAT_NAME; DsrDcNameInfo* pDcNameInfo = NULL; PSTR pszDomainDnsOrFlatName = NULL; PSTR pszDomainForestDnsName = NULL; dwError = LsaMbsToWc16s(pszServerName, &pwcServerName); BAIL_ON_LSA_ERROR(dwError); dwError = AD_SetSystemAccess(&pOldToken); BAIL_ON_LSA_ERROR(dwError); bChangedToken = TRUE; status = LwIoGetThreadCreds(&pCreds); dwError = LwNtStatusToErrno(status); BAIL_ON_LSA_ERROR(dwError); status = InitNetlogonBindingDefault(&netr_b, pszServerName, pCreds, FALSE); if (status != 0) { LSA_LOG_DEBUG("Failed to bind to %s (error %d)", pszServerName, status); dwError = LW_ERROR_RPC_NETLOGON_FAILED; bIsNetworkError = TRUE; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaMbsToWc16s(pszDomainName, &pwcDomainName); BAIL_ON_LSA_ERROR(dwError); winError = DsrGetDcName(netr_b, pwcServerName, pwcDomainName, NULL, NULL, dwGetDcNameflags, &pDcNameInfo); if (winError) { LSA_LOG_DEBUG("Failed to get dc name information for %s at %s (error %d)", pszDomainName, pszServerName, winError); if (ERROR_NO_SUCH_DOMAIN == winError) { dwError = LW_ERROR_NO_SUCH_DOMAIN; } else { dwError = LW_ERROR_GET_DC_NAME_FAILED; } if (AD_WinErrorIsConnectionError(winError)) { bIsNetworkError = TRUE; } BAIL_ON_LSA_ERROR(dwError); } dwError = LsaWc16sToMbs(pDcNameInfo->domain_name, &pszDomainDnsOrFlatName); BAIL_ON_LSA_ERROR(dwError); dwError = LsaWc16sToMbs(pDcNameInfo->forest_name, &pszDomainForestDnsName); BAIL_ON_LSA_ERROR(dwError); cleanup: if (netr_b) { FreeNetlogonBinding(&netr_b); netr_b = NULL; } LW_SAFE_FREE_MEMORY(pwcServerName); LW_SAFE_FREE_MEMORY(pwcDomainName); if (bChangedToken) { LwIoSetThreadCreds(pOldToken); } if (pOldToken != NULL) { LwIoDeleteCreds(pOldToken); } if (pCreds != NULL) { LwIoDeleteCreds(pCreds); } NetrFreeMemory((void*)pDcNameInfo); *ppszDomainDnsOrFlatName = pszDomainDnsOrFlatName; *ppszDomainForestDnsName = pszDomainForestDnsName; if (pbIsNetworkError) { *pbIsNetworkError = bIsNetworkError; } return dwError; error: LW_SAFE_FREE_STRING(pszDomainDnsOrFlatName); LW_SAFE_FREE_STRING(pszDomainForestDnsName); goto cleanup; } DWORD AD_MapNetApiError( DWORD dwADError ) { DWORD dwError = 0; switch(dwADError) { case 1325: // There is no RPC error code for this at present. dwError = LW_ERROR_PASSWORD_RESTRICTION; break; default: dwError = dwADError; break; } return dwError; } void LsaFreeTranslatedNameInfo( IN OUT PLSA_TRANSLATED_NAME_OR_SID pNameInfo ) { LW_SAFE_FREE_STRING(pNameInfo->pszNT4NameOrSid); LwFreeMemory(pNameInfo); } void LsaFreeTranslatedNameList( IN OUT PLSA_TRANSLATED_NAME_OR_SID* pNameList, IN DWORD dwNumNames ) { DWORD iName = 0; for (iName = 0; iName < dwNumNames; iName++) { PLSA_TRANSLATED_NAME_OR_SID pNameInfo = pNameList[iName]; if (pNameInfo) { LsaFreeTranslatedNameInfo(pNameInfo); } } LwFreeMemory(pNameList); } INT64 WinTimeToInt64( WinNtTime WinTime ) { INT64 Int64Time = 0; Int64Time = WinTime.high; Int64Time = Int64Time << 32; Int64Time |= WinTime.low; return Int64Time; } static DWORD LsaCopyNetrUserInfo3( OUT PLSA_AUTH_USER_INFO pUserInfo, IN NetrValidationInfo *pNetrUserInfo3 ) { DWORD dwError = LW_ERROR_INTERNAL; NetrSamBaseInfo *pBase = NULL; NTSTATUS ntError = STATUS_UNSUCCESSFUL; RC4_KEY RC4Key; BAIL_ON_INVALID_POINTER(pUserInfo); BAIL_ON_INVALID_POINTER(pNetrUserInfo3); pBase = &pNetrUserInfo3->sam3->base; pUserInfo->dwUserFlags = pBase->user_flags; pUserInfo->LogonTime = WinTimeToInt64(pBase->last_logon); pUserInfo->LogoffTime = WinTimeToInt64(pBase->last_logoff); pUserInfo->KickoffTime = WinTimeToInt64(pBase->acct_expiry); pUserInfo->LastPasswordChange = WinTimeToInt64(pBase->last_password_change); pUserInfo->CanChangePassword = WinTimeToInt64(pBase->allow_password_change); pUserInfo->MustChangePassword = WinTimeToInt64(pBase->force_password_change); pUserInfo->LogonCount = pBase->logon_count; pUserInfo->BadPasswordCount = pBase->bad_password_count; pUserInfo->dwAcctFlags = pBase->acct_flags; dwError = LsaDataBlobStore(&pUserInfo->pSessionKey, sizeof(pBase->key.key), pBase->key.key); BAIL_ON_LSA_ERROR(dwError); /* We have to decrypt the user session key before we can use it */ RC4_set_key(&RC4Key, 16, gpSchannelCreds->session_key); RC4(&RC4Key, pUserInfo->pSessionKey->dwLen, pUserInfo->pSessionKey->pData, pUserInfo->pSessionKey->pData); dwError = LsaDataBlobStore(&pUserInfo->pLmSessionKey, sizeof(pBase->lmkey.key), pBase->lmkey.key); BAIL_ON_LSA_ERROR(dwError); RC4_set_key(&RC4Key, 16, gpSchannelCreds->session_key); RC4(&RC4Key, pUserInfo->pLmSessionKey->dwLen, pUserInfo->pLmSessionKey->pData, pUserInfo->pLmSessionKey->pData); pUserInfo->pszUserPrincipalName = NULL; pUserInfo->pszDnsDomain = NULL; if (pBase->account_name.len) { dwError = LsaWc16sToMbs(pBase->account_name.string, &pUserInfo->pszAccount); BAIL_ON_LSA_ERROR(dwError); } if (pBase->full_name.len) { dwError = LsaWc16sToMbs(pBase->full_name.string, &pUserInfo->pszFullName); BAIL_ON_LSA_ERROR(dwError); } if (pBase->domain.len) { dwError = LsaWc16sToMbs(pBase->domain.string, &pUserInfo->pszDomain); BAIL_ON_LSA_ERROR(dwError); } if (pBase->logon_server.len) { dwError = LsaWc16sToMbs(pBase->logon_server.string, &pUserInfo->pszLogonServer); BAIL_ON_LSA_ERROR(dwError); } if (pBase->logon_script.len) { dwError = LsaWc16sToMbs(pBase->logon_script.string, &pUserInfo->pszLogonScript); BAIL_ON_LSA_ERROR(dwError); } if (pBase->home_directory.len) { dwError = LsaWc16sToMbs(pBase->home_directory.string, &pUserInfo->pszHomeDirectory); BAIL_ON_LSA_ERROR(dwError); } if (pBase->home_drive.len) { dwError = LsaWc16sToMbs(pBase->home_drive.string, &pUserInfo->pszHomeDrive); BAIL_ON_LSA_ERROR(dwError); } if (pBase->profile_path.len) { dwError = LsaWc16sToMbs(pBase->profile_path.string, &pUserInfo->pszProfilePath); BAIL_ON_LSA_ERROR(dwError); } ntError = RtlAllocateCStringFromSid(&pUserInfo->pszDomainSid, pBase->domain_sid); BAIL_ON_NT_STATUS(dwError); pUserInfo->dwUserRid = pBase->rid; pUserInfo->dwPrimaryGroupRid = pBase->primary_gid; pUserInfo->dwNumRids = pBase->groups.count; if (pUserInfo->dwNumRids != 0) { int i = 0; dwError = LwAllocateMemory(sizeof(LSA_RID_ATTRIB)*(pUserInfo->dwNumRids), (PVOID*)&pUserInfo->pRidAttribList); BAIL_ON_LSA_ERROR(dwError); for (i=0; idwNumRids; i++) { pUserInfo->pRidAttribList[i].Rid = pBase->groups.rids[i].rid; pUserInfo->pRidAttribList[i].dwAttrib = pBase->groups.rids[i].attributes; } } pUserInfo->dwNumSids = pNetrUserInfo3->sam3->sidcount; if (pUserInfo->dwNumSids != 0) { int i = 0; dwError = LwAllocateMemory(sizeof(LSA_SID_ATTRIB)*(pUserInfo->dwNumSids), (PVOID*)&pUserInfo->pSidAttribList); BAIL_ON_LSA_ERROR(dwError); for (i=0; idwNumSids; i++) { PLSA_SID_ATTRIB pSidAttrib = &(pUserInfo->pSidAttribList[i]); pSidAttrib->dwAttrib = pNetrUserInfo3->sam3->sids[i].attribute; ntError = RtlAllocateCStringFromSid(&pSidAttrib->pszSid, pNetrUserInfo3->sam3->sids[i].sid); BAIL_ON_NT_STATUS(dwError); } } /* All done */ dwError = LW_ERROR_SUCCESS; cleanup: return dwError; error: goto cleanup; } DWORD AD_NetlogonAuthenticationUserEx( IN PSTR pszDomainController, IN PLSA_AUTH_USER_PARAMS pUserParams, OUT PLSA_AUTH_USER_INFO *ppUserInfo, OUT PBOOLEAN pbIsNetworkError ) { DWORD dwError = LW_ERROR_INTERNAL; PWSTR pwszDomainController = NULL; PWSTR pwszServerName = NULL; PWSTR pwszShortDomain = NULL; PWSTR pwszPrimaryShortDomain = NULL; PWSTR pwszUsername = NULL; PWSTR pwszComputer = NULL; PSTR pszHostname = NULL; HANDLE hPwdDb = (HANDLE)NULL; RPCSTATUS status = 0; handle_t netr_b = NULL; PLWPS_PASSWORD_INFO pMachAcctInfo = NULL; BOOLEAN bIsNetworkError = FALSE; NTSTATUS nt_status = STATUS_UNHANDLED_EXCEPTION; NetrValidationInfo *pValidationInfo = NULL; UINT8 dwAuthoritative = 0; PSTR pszServerName; DWORD dwDCNameLen = 0; PBYTE pChal = NULL; PBYTE pLMResp = NULL; DWORD LMRespLen = 0; PBYTE pNTResp = NULL; DWORD NTRespLen = 0; LW_PIO_CREDS pCreds = NULL; LW_PIO_CREDS pOldToken = NULL; BOOLEAN bChangedToken = FALSE; pthread_mutex_lock(&gSchannelLock); /* Grab the machine password and account info */ dwError = LwpsOpenPasswordStore(LWPS_PASSWORD_STORE_DEFAULT, &hPwdDb); BAIL_ON_LSA_ERROR(dwError); dwError = LsaDnsGetHostInfo(&pszHostname); BAIL_ON_LSA_ERROR(dwError); dwError = LwpsGetPasswordByHostName(hPwdDb, pszHostname, &pMachAcctInfo); BAIL_ON_LSA_ERROR(dwError); /* Gather other Schannel params */ /* Allocate space for the servername. Include room for the terminating NULL and \\ */ dwDCNameLen = strlen(pszDomainController) + 3; dwError = LwAllocateMemory(dwDCNameLen, (PVOID*)&pszServerName); BAIL_ON_LSA_ERROR(dwError); snprintf(pszServerName, dwDCNameLen, "\\\\%s", pszDomainController); dwError = LsaMbsToWc16s(pszServerName, &pwszServerName); BAIL_ON_LSA_ERROR(dwError); dwError = LsaMbsToWc16s(pUserParams->pszDomain, &pwszShortDomain); BAIL_ON_LSA_ERROR(dwError); pwszComputer = wc16sdup(pMachAcctInfo->pwszMachineAccount); if (!pwszComputer) { dwError = LW_ERROR_OUT_OF_MEMORY; } BAIL_ON_LSA_ERROR(dwError); // Remove $ from account name pwszComputer[wc16slen(pwszComputer) - 1] = 0; if (!ghSchannelBinding) { dwError = LsaMbsToWc16s(pszDomainController, &pwszDomainController); BAIL_ON_LSA_ERROR(dwError); dwError = LsaMbsToWc16s(gpADProviderData->szShortDomain, &pwszPrimaryShortDomain); BAIL_ON_LSA_ERROR(dwError); /* Establish the initial bind to \NETLOGON */ dwError = AD_SetSystemAccess(&pOldToken); BAIL_ON_LSA_ERROR(dwError); bChangedToken = TRUE; status = LwIoGetThreadCreds(&pCreds); dwError = LwNtStatusToErrno(status); BAIL_ON_LSA_ERROR(dwError); status = InitNetlogonBindingDefault(&netr_b,(const char*)pszDomainController, pCreds, FALSE); if (status != 0) { LSA_LOG_DEBUG("Failed to bind to %s (error %d)", pszDomainController, status); dwError = LW_ERROR_RPC_NETLOGON_FAILED; bIsNetworkError = TRUE; BAIL_ON_LSA_ERROR(dwError); } /* Now setup the Schannel session */ nt_status = NetrOpenSchannel(netr_b, pMachAcctInfo->pwszMachineAccount, pwszDomainController, pwszServerName, pwszPrimaryShortDomain, pwszComputer, pMachAcctInfo->pwszMachinePassword, &gSchannelCreds, &ghSchannelBinding); if (nt_status != STATUS_SUCCESS) { LSA_LOG_DEBUG("NetrOpenSchannel() failed with %d (0x%08x)", nt_status, nt_status); dwError = LW_ERROR_RPC_ERROR; BAIL_ON_LSA_ERROR(dwError); } gpSchannelCreds = &gSchannelCreds; } /* Time to do the authentication */ dwError = LsaMbsToWc16s(pUserParams->pszAccountName, &pwszUsername); BAIL_ON_LSA_ERROR(dwError); /* Get the data blob buffers */ if (pUserParams->pass.chap.pChallenge) pChal = LsaDataBlobBuffer(pUserParams->pass.chap.pChallenge); if (pUserParams->pass.chap.pLM_resp) { pLMResp = LsaDataBlobBuffer(pUserParams->pass.chap.pLM_resp); LMRespLen = LsaDataBlobLength(pUserParams->pass.chap.pLM_resp); } if (pUserParams->pass.chap.pNT_resp) { pNTResp = LsaDataBlobBuffer(pUserParams->pass.chap.pNT_resp); NTRespLen = LsaDataBlobLength(pUserParams->pass.chap.pNT_resp); } nt_status = NetrSamLogonNetwork(ghSchannelBinding, &gSchannelCreds, pwszServerName, pwszShortDomain, pwszComputer, pwszUsername, pChal, pLMResp, LMRespLen, pNTResp, NTRespLen, 2, /* Network login */ 3, /* Return NetSamInfo3 */ &pValidationInfo, &dwAuthoritative); if (nt_status != STATUS_SUCCESS) { LSA_LOG_DEBUG("NetrSamLogonNetwork() failed with %d (0x%08x) (symbol: '%s')", nt_status, nt_status, LSA_SAFE_LOG_STRING(LwNtStatusToName(nt_status))); dwError = LW_ERROR_RPC_NETLOGON_FAILED; BAIL_ON_LSA_ERROR(dwError); } /* Translate the returned NetrValidationInfo to the LSA_AUTH_USER_INFO out param */ dwError = LwAllocateMemory(sizeof(LSA_AUTH_USER_INFO), (PVOID*)ppUserInfo); BAIL_ON_LSA_ERROR(dwError); dwError = LsaCopyNetrUserInfo3(*ppUserInfo, pValidationInfo); BAIL_ON_LSA_ERROR(dwError); cleanup: if (hPwdDb) { if (pMachAcctInfo) { LwpsFreePasswordInfo(hPwdDb, pMachAcctInfo); } LwpsClosePasswordStore(hPwdDb); hPwdDb = (HANDLE)NULL; } if (netr_b) { FreeNetlogonBinding(&netr_b); netr_b = NULL; } if (bChangedToken) { LwIoSetThreadCreds(pOldToken); } if (pOldToken != NULL) { LwIoDeleteCreds(pOldToken); } if (pCreds != NULL) { LwIoDeleteCreds(pCreds); } if (pValidationInfo) { NetrFreeMemory((void*)pValidationInfo); } LW_SAFE_FREE_MEMORY(pszHostname); LW_SAFE_FREE_MEMORY(pszServerName); LW_SAFE_FREE_MEMORY(pwszUsername); LW_SAFE_FREE_MEMORY(pwszDomainController); LW_SAFE_FREE_MEMORY(pwszServerName); LW_SAFE_FREE_MEMORY(pwszShortDomain); LW_SAFE_FREE_MEMORY(pwszPrimaryShortDomain); LW_SAFE_FREE_MEMORY(pwszComputer); pthread_mutex_unlock(&gSchannelLock); return dwError; error: LsaFreeAuthUserInfo(ppUserInfo); goto cleanup; } static VOID AD_ClearSchannelState( VOID ) { pthread_mutex_lock(&gSchannelLock); if (ghSchannelBinding) { NetrCloseSchannel(ghSchannelBinding); ghSchannelBinding = NULL; memset(&gSchannelCreds, 0, sizeof(gSchannelCreds)); gpSchannelCreds = NULL; } pthread_mutex_unlock(&gSchannelLock); } static BOOLEAN AD_NtStatusIsConnectionError( NTSTATUS status ) { switch (status) { case STATUS_INVALID_CONNECTION: return TRUE; default: return FALSE; } } static BOOLEAN AD_WinErrorIsConnectionError( WINERR winError ) { switch (winError) { case ERROR_UNEXP_NET_ERR: return TRUE; case LW_STATUS_INVALID_CONNECTION: return TRUE; default: return FALSE; } } /* local variables: mode: c c-basic-offset: 4 indent-tabs-mode: nil tab-width: 4 end: */