|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: ldapc.hxx
//
// Contents:
//
// History: 06-16-96 yihsins Created.
//
//----------------------------------------------------------------------------
#include "ldapc.hxx"
#pragma hdrstop
CRITICAL_SECTION g_DomainDnsCache;
#define ENTER_DOMAINDNS_CRITSECT() EnterCriticalSection(&g_DomainDnsCache)
#define LEAVE_DOMAINDNS_CRITSECT() LeaveCriticalSection(&g_DomainDnsCache)
BOOL g_fDllsLoaded = FALSE; HANDLE g_hDllNetApi32 = NULL; HANDLE g_hDllSecur32 = NULL;
extern "C" {
typedef struct _WKSTA_USER_INFO_1A { LPSTR wkui1_username; LPSTR wkui1_logon_domain; LPSTR wkui1_oth_domains; LPSTR wkui1_logon_server; }WKSTA_USER_INFO_1A, *PWKSTA_USER_INFO_1A, *LPWKSTA_USER_INFO_1A;
NET_API_STATUS NET_API_FUNCTION NetWkstaUserGetInfoA ( IN LPSTR reserved, IN DWORD level, OUT LPBYTE *bufptr );
}
int AnsiToUnicodeString( LPSTR pAnsi, LPWSTR pUnicode, DWORD StringLength );
//
// Binds to all the dll's that we need to load dynamically.
// The list is
// netapi32.dll
// secur32.dll
//
// The global flag g_fDllsLoaded is updated appropriately.
//
void BindToDlls() { if (g_fDllsLoaded) { return; }
//
// Use the domaindns critical section to control access.
// There is no real need to define another CS for this as this
// will utmost be called once.
//
DWORD dwLastErr = 0; ENTER_DOMAINDNS_CRITSECT();
//
// In case someones came in when we were loading the dll's.
//
if (g_fDllsLoaded) { LEAVE_DOMAINDNS_CRITSECT(); return; }
//
// Load dll's - each load lib could have set an error if it fails.
//
if (!(g_hDllNetApi32 = LoadLibrary(L"NETAPI32.DLL"))) { dwLastErr = GetLastError(); }
g_hDllSecur32 = LoadLibrary(L"SECUR32.DLL");
//
// We need to set this as the last error since one of the
// loads failed. This will not work as we add more dll's
// but for now should be ok. This may not even be needed
// cause finally we are interested in the actual functions
// not just the ability to load/unload the dll.
//
if (dwLastErr) { SetLastError (dwLastErr); }
g_fDllsLoaded = TRUE;
LEAVE_DOMAINDNS_CRITSECT();
return; }
//
// LoadNetApi32Function
//
// Args:
// Function to load.
//
// Returns: function pointer if successfully loads the function from
// NETAPI32.DLL. Returns NULL otherwise.
//
//
PVOID LoadNetApi32Function(CHAR *function) { if (!g_fDllsLoaded) { BindToDlls(); }
if (g_hDllNetApi32) { return ((PVOID) GetProcAddress((HMODULE)g_hDllNetApi32, function)); }
return NULL; }
//
// LoadSecur32Function
//
// Args:
// Function to load.
//
// Returns: function pointer if successfully loads the function from
// secur32.DLL. Returns NULL otherwise.
//
//
PVOID LoadSecur32Function(CHAR *function) { if (!g_fDllsLoaded) { BindToDlls(); }
if (g_hDllSecur32) { return ((PVOID) GetProcAddress((HMODULE)g_hDllSecur32, function)); }
return NULL; }
//
// Definition for DsGetDcName
//
typedef DWORD (*PF_DsGetDcName) ( IN LPCWSTR ComputerName OPTIONAL, IN LPCWSTR DomainName OPTIONAL, IN GUID *DomainGuid OPTIONAL, IN LPCWSTR SiteName OPTIONAL, IN ULONG Flags, OUT PDOMAIN_CONTROLLER_INFO *DomainControllerInfo );
//
// Definition for LsaConnectUntrusted()
//
typedef DWORD (*PF_LsaConnectUntrusted) ( OUT PHANDLE LsaHandle );
//
// For LsaCallAuthenticationPackage
//
typedef DWORD (*PF_LsaCallAuthenticationPackage) ( IN HANDLE LsaHandle, IN ULONG AuthenticationPackage, IN PVOID ProtocolSubmitBuffer, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferLength, OUT PNTSTATUS ProtocolStatus );
//
// For LsaDeregisterLogonProcess
//
typedef DWORD (*PF_LsaDeregisterLogonProcess) ( IN HANDLE LsaHandle );
//
// For LsaFreeReturnBuffer
//
typedef DWORD (*PF_LsaFreeReturnBuffer) ( IN PVOID Buffer );
#ifdef UNICODE
#define GETDCNAME_API "DsGetDcNameW"
#else
#define GETDCNAME_API "DsGetDcNameA"
#endif
//
// These are same for all entry points
//
#define LSACONNECT_UNTRUSTED "LsaConnectUntrusted"
#define LSACALL_AUTH_PACAKAGE "LsaCallAuthenticationPackage"
#define LSA_DEREG_LOGON_PROC "LsaDeregisterLogonProcess"
#define LSAFREE_RET_BUFFER "LsaFreeReturnBuffer"
//
// We will always dynamically laod the dsgetdc api so that
// we can have single binary for NT4.0 and NT5.0
//
DWORD DsGetDcNameWrapper( IN LPCWSTR ComputerName OPTIONAL, IN LPCWSTR DomainName OPTIONAL, IN GUID *DomainGuid OPTIONAL, IN LPCWSTR SiteName OPTIONAL, IN ULONG Flags, OUT PDOMAIN_CONTROLLER_INFO *DomainControllerInfo ) { static PF_DsGetDcName pfDsGetDcName = NULL ; static BOOL f_LoadAttempted = FALSE;
//
// Load the function if necessary and only once.
//
if (pfDsGetDcName == NULL && !f_LoadAttempted) { pfDsGetDcName = (PF_DsGetDcName) LoadNetApi32Function(GETDCNAME_API) ; f_LoadAttempted = TRUE; }
if (pfDsGetDcName != NULL) {
return ((*pfDsGetDcName)( ComputerName, DomainName, DomainGuid, SiteName, Flags, DomainControllerInfo ) ); } else { //
// Could not load library
//
return (ERROR_GEN_FAILURE); }
}
//
// Wrapper function for LsaConnectUntrusted.
//
DWORD LsaConnectUntrustedWrapper( OUT PHANDLE LsaHandle ) { static PF_LsaConnectUntrusted pfLsaConnectUntrusted = NULL ; static BOOL f_LoadAttempted = FALSE;
//
// Load the function if necessary and only once.
//
if (pfLsaConnectUntrusted == NULL && !f_LoadAttempted) { pfLsaConnectUntrusted = (PF_LsaConnectUntrusted) LoadSecur32Function(LSACONNECT_UNTRUSTED); f_LoadAttempted = TRUE; }
if (pfLsaConnectUntrusted != NULL) {
return ((*pfLsaConnectUntrusted)( LsaHandle ) ); } else { //
// Could not load library
//
return (ERROR_GEN_FAILURE); }
}
//
// Wrapper function for LsaCallAuthenticationPackage.
//
DWORD LsaCallAuthenticationPackageWrapper( IN HANDLE LsaHandle, IN ULONG AuthenticationPackage, IN PVOID ProtocolSubmitBuffer, IN ULONG SubmitBufferLength, OUT PVOID *ProtocolReturnBuffer, OUT PULONG ReturnBufferLength, OUT PNTSTATUS ProtocolStatus ) { static PF_LsaCallAuthenticationPackage pfLsaCallAuthPackage = NULL; static BOOL f_LoadAttempted = FALSE;
//
// Load the function if necessary and only once.
//
if (pfLsaCallAuthPackage == NULL && !f_LoadAttempted) { pfLsaCallAuthPackage = (PF_LsaCallAuthenticationPackage) LoadSecur32Function( LSACALL_AUTH_PACAKAGE ); f_LoadAttempted = TRUE; }
if (pfLsaCallAuthPackage != NULL) {
return ((*pfLsaCallAuthPackage)( LsaHandle, AuthenticationPackage, ProtocolSubmitBuffer, SubmitBufferLength, ProtocolReturnBuffer, ReturnBufferLength, ProtocolStatus ) ); } else { //
// Could not load library
//
return (ERROR_GEN_FAILURE); }
}
//
// Wrapper function for LsaDeregisterLogonProcess.
//
DWORD LsaDeregisterLogonProcessWrapper( IN HANDLE LsaHandle ) { static PF_LsaDeregisterLogonProcess pfLsaDerefLgnProc = NULL; static BOOL f_LoadAttempted = FALSE;
//
// Load the function if necessary and only once.
//
if (pfLsaDerefLgnProc == NULL && !f_LoadAttempted) { pfLsaDerefLgnProc = (PF_LsaDeregisterLogonProcess) LoadSecur32Function(LSA_DEREG_LOGON_PROC); f_LoadAttempted = TRUE; }
if (pfLsaDerefLgnProc != NULL) {
return ((*pfLsaDerefLgnProc)( LsaHandle ) ); } else { //
// Could not load library
//
return (ERROR_GEN_FAILURE); }
}
//
// Wrapper function for LsaFreeReturnBuffer.
//
DWORD LsaFreeReturnBufferWrapper( IN PVOID Buffer ) { static PF_LsaFreeReturnBuffer pfLsaFreeRetBuffer = NULL; static BOOL f_LoadAttempted = FALSE;
//
// Load the function if necessary and only once.
//
if (pfLsaFreeRetBuffer == NULL && !f_LoadAttempted) { pfLsaFreeRetBuffer = (PF_LsaFreeReturnBuffer) LoadSecur32Function(LSAFREE_RET_BUFFER); f_LoadAttempted = TRUE; }
if (pfLsaFreeRetBuffer != NULL) {
return ((*pfLsaFreeRetBuffer)( Buffer ) ); } else { //
// Could not load library
//
return (ERROR_GEN_FAILURE); }
}
HANDLE g_hLsa = INVALID_HANDLE_VALUE;
DWORD GetUserDomainFlatName( LPWSTR pszUserName, LPWSTR pszDomainFlatName ) {
NTSTATUS dwStatus = NO_ERROR, dwSubStatus = NO_ERROR;
CHAR pszDomainFlatNameA[MAX_PATH]; CHAR pszUserNameA[MAX_PATH];
PWKSTA_USER_INFO_1 pNetWkstaUserInfo = NULL;
PWKSTA_USER_INFO_1A pNetWkstaUserInfoA = NULL;
PWKSTA_INFO_100 pNetWkstaInfo = NULL;
NEGOTIATE_CALLER_NAME_REQUEST Req; PNEGOTIATE_CALLER_NAME_RESPONSE pResp = NULL; DWORD dwSize = 0; LPWSTR pszTempUserName = NULL; PLSA_UNICODE_STRING pLsaStrUserNameTemp = NULL; PLSA_UNICODE_STRING pLsaStrDomainNameTemp = NULL;
#if (defined WIN95)
dwStatus = NetWkstaUserGetInfoA( NULL, 1, (LPBYTE *)&pNetWkstaUserInfoA );
if (dwStatus != NO_ERROR && dwStatus != ERROR_NO_SUCH_LOGON_SESSION) { goto error; }
if (dwStatus == NO_ERROR) { AnsiToUnicodeString( pNetWkstaUserInfoA->wkui1_logon_domain, pszDomainFlatName, 0 ); AnsiToUnicodeString( pNetWkstaUserInfoA->wkui1_username, pszUserName, 0 );
}
#else
ENTER_DOMAINDNS_CRITSECT(); if (g_hLsa == INVALID_HANDLE_VALUE) { dwStatus = LsaConnectUntrustedWrapper(&g_hLsa); } LEAVE_DOMAINDNS_CRITSECT(); if (dwStatus == 0) {
memset(&Req, 0, sizeof(Req)); Req.MessageType = NegGetCallerName;
dwStatus = LsaCallAuthenticationPackageWrapper( g_hLsa, 0, &Req, sizeof(Req), (void **)&pResp, &dwSize, &dwSubStatus );
if ((dwStatus == 0) && (dwSubStatus == 0)) { dwStatus = NO_ERROR; pszTempUserName = wcschr(pResp->CallerName, L'\\'); if (!pszTempUserName) { //
// Looks like there was no domain default to machine then
//
dwStatus = ERROR_NO_SUCH_LOGON_SESSION; } else { //
// Copy over the relevant information
//
*pszTempUserName = L'\0'; wcscpy(pszDomainFlatName, pResp->CallerName); *pszTempUserName = L'\\'; pszTempUserName++; wcscpy(pszUserName, pszTempUserName); LsaFreeReturnBufferWrapper(pResp); } } else { if (!dwStatus) dwStatus = dwSubStatus; } }
if (dwStatus != NO_ERROR) { //
// Call LsaGetUserName when there is a failure with the above.
//
dwStatus = LsaGetUserName( &pLsaStrUserNameTemp, &pLsaStrDomainNameTemp );
if (dwStatus == NO_ERROR) { //
// Unicode string may not be NULL terminated.
//
memcpy( pszDomainFlatName, pLsaStrDomainNameTemp->Buffer, pLsaStrDomainNameTemp->Length ); pszDomainFlatName[pLsaStrDomainNameTemp->Length / sizeof(WCHAR)] = L'\0'; memcpy( pszUserName, pLsaStrUserNameTemp->Buffer, pLsaStrUserNameTemp->Length ); pszUserName[pLsaStrUserNameTemp->Length / sizeof(WCHAR)] = L'\0';
//
// Can cleanup the LsaGetUserName mem
//
LsaFreeMemory(pLsaStrUserNameTemp->Buffer); LsaFreeMemory(pLsaStrUserNameTemp); LsaFreeMemory(pLsaStrDomainNameTemp->Buffer); LsaFreeMemory(pLsaStrDomainNameTemp); } else if (dwStatus != ERROR_NO_SUCH_LOGON_SESSION){ goto error; }
} //
// Make sure this is not NT AUTHORITY
//
if (dwStatus == NO_ERROR && !_wcsicmp(g_szNT_Authority, pszDomainFlatName) ) { //
// Force fallback to NetWkstaGetInfo as we want machine domain
//
dwStatus = ERROR_NO_SUCH_LOGON_SESSION; }
if (dwStatus == NO_ERROR) { //
// Do nothing here, we need the else clause already have data.
//
}
#endif
else {
dwStatus = NetWkstaGetInfo( NULL, 100, (LPBYTE *)&pNetWkstaInfo ); if (dwStatus) { goto error; }
wcscpy(pszDomainFlatName, pNetWkstaInfo->wki100_langroup);
}
error:
if (pNetWkstaUserInfoA) {
NetApiBufferFree(pNetWkstaUserInfoA); }
if (pNetWkstaUserInfo) {
NetApiBufferFree(pNetWkstaUserInfo); }
if (pNetWkstaInfo) {
NetApiBufferFree(pNetWkstaInfo); }
return(dwStatus);
}
DWORD GetDomainDNSNameForDomain( LPWSTR pszDomainFlatName, BOOL fVerify, BOOL fWriteable, LPWSTR pszServerName, LPWSTR pszDomainDNSName ) { PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL; DWORD dwStatus = 0; DWORD Flags = DS_DIRECTORY_SERVICE_REQUIRED | DS_RETURN_DNS_NAME;
if (fVerify) Flags |= DS_FORCE_REDISCOVERY ;
if (fWriteable) Flags |= DS_WRITABLE_REQUIRED ;
dwStatus = DsGetDcNameWrapper( NULL, pszDomainFlatName, NULL, NULL, Flags, &pDomainControllerInfo ) ;
if (dwStatus == NO_ERROR) {
wcscpy(pszServerName,pDomainControllerInfo->DomainControllerName+2);
wcscpy(pszDomainDNSName,pDomainControllerInfo->DomainName);
(void) NetApiBufferFree(pDomainControllerInfo) ;
}
return(dwStatus); }
typedef struct _domaindnslist { LPWSTR pszUserName; LPWSTR pszUserDomainName; LPWSTR pszDomainDns; LPWSTR pszServer; struct _domaindnslist *pNext; } DOMAINDNSLIST, *PDOMAINDNSLIST;
PDOMAINDNSLIST gpDomainDnsList = NULL;
BOOL EquivalentDomains( PDOMAINDNSLIST pTemp, LPWSTR pszUserDomainName );
DWORD GetDefaultDomainName( LPWSTR szDomainDnsName, LPWSTR szServerName, BOOL fWriteable, BOOL fVerify ) {
DWORD dwStatus = 0; WCHAR szUserDomainName[MAX_PATH]; WCHAR szUserName[MAX_PATH];
PDOMAINDNSLIST pTemp = NULL; PDOMAINDNSLIST pNewNode = NULL;
dwStatus = GetUserDomainFlatName( szUserName, szUserDomainName ); if (dwStatus) { goto error; }
// We want do a DsGetDc if the fVerify flags is specified
// so we do not want to look at our list if that is the case.
if (!fVerify) {
ENTER_DOMAINDNS_CRITSECT();
pTemp = gpDomainDnsList;
while (pTemp) {
if (EquivalentDomains(pTemp, szUserDomainName)){
wcscpy(szDomainDnsName,pTemp->pszDomainDns); wcscpy(szServerName,pTemp->pszServer);
LEAVE_DOMAINDNS_CRITSECT();
return(NO_ERROR); }
pTemp = pTemp->pNext;
}
LEAVE_DOMAINDNS_CRITSECT(); }
// We will hit this block if either fVerify == TRUE or if
// we did not find a match in our list above.
dwStatus = GetDomainDNSNameForDomain( szUserDomainName, fVerify, fWriteable, szServerName, szDomainDnsName ); if (dwStatus) { goto error; }
ENTER_DOMAINDNS_CRITSECT();
pTemp = gpDomainDnsList;
while (pTemp) {
if (EquivalentDomains(pTemp, szUserDomainName)) { //
// Found a match -looks like someone has come in before us
//
wcscpy(szDomainDnsName, pTemp->pszDomainDns); wcscpy(szServerName,pTemp->pszServer);
LEAVE_DOMAINDNS_CRITSECT();
return(NO_ERROR); }
pTemp = pTemp->pNext;
}
pNewNode = (PDOMAINDNSLIST)AllocADsMem(sizeof(DOMAINDNSLIST));
if (!pNewNode) {
LEAVE_DOMAINDNS_CRITSECT();
return(dwStatus = (DWORD) E_OUTOFMEMORY); }
pNewNode->pNext = gpDomainDnsList;
pNewNode->pszUserName = AllocADsStr(szUserName); pNewNode->pszUserDomainName = AllocADsStr(szUserDomainName); pNewNode->pszDomainDns = AllocADsStr(szDomainDnsName); pNewNode->pszServer = AllocADsStr(szServerName);
gpDomainDnsList = pNewNode;
LEAVE_DOMAINDNS_CRITSECT();
error:
return(dwStatus); }
DWORD GetGCDomainName( LPWSTR pszDomainDNSName, LPWSTR pszServerName ) { PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL; DWORD dwStatus = 0; DWORD Flags = DS_GC_SERVER_REQUIRED | DS_RETURN_DNS_NAME;
/*
Flags |= DS_FORCE_REDISCOVERY ; Flags |= DS_WRITABLE_REQUIRED ; */
dwStatus = DsGetDcNameWrapper( NULL, NULL, NULL, NULL, Flags, &pDomainControllerInfo ) ;
if (dwStatus == NO_ERROR) {
wcscpy(pszServerName,pDomainControllerInfo->DomainControllerName+2);
wcscpy(pszDomainDNSName,pDomainControllerInfo->DnsForestName);
(void) NetApiBufferFree(pDomainControllerInfo) ;
}
return(dwStatus); }
DWORD GetDefaultServer( DWORD dwPort, BOOL fVerify, LPWSTR szDomainDnsName, LPWSTR szServerName, BOOL fWriteable ) { LPWSTR pszAddresses[5]; DWORD dwStatus = NO_ERROR;
if (dwPort == USE_DEFAULT_GC_PORT) { dwStatus = GetGCDomainName( szDomainDnsName, szServerName); } else { dwStatus = GetDefaultDomainName( szDomainDnsName, szServerName, fWriteable, fVerify ); }
return(dwStatus);
}
//
// Helper to see if we can use the cache for an domain DNS name
// given a domain flat name.
//
BOOL EquivalentDomains( PDOMAINDNSLIST pTemp, LPWSTR pszUserDomainName ) {
if (!pszUserDomainName || !*pszUserDomainName) { return(FALSE); }
#ifdef WIN95
if (!_wcsicmp(pszUserDomainName, pTemp->pszUserDomainName)) { #else
if (CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, pszUserDomainName, -1, pTemp->pszUserDomainName, -1 ) == CSTR_EQUAL ) { #endif
return(TRUE);
} return(FALSE); }
|