/* 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:
*/