|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
llssrv.c
Abstract:
Main routine to setup the exception handlers and initialize everything to listen to LPC and RPC port requests.
Author:
Arthur Hanson (arth) Dec 07, 1994
Environment:
Revision History:
Jeff Parham (jeffparh) 05-Dec-1995 o Added certificate database support. o Expanded file load time (the update limit sent to the service controller) to account for certificate database loading. o Reordered initialization such that the license purchase subsystem is initialized before the service subsystem. (The service subsystem now uses the license subsystem.) o Increased internal version number.
--*/
#include <nt.h>
#include <ntlsa.h>
#include <ntsam.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <tchar.h>
#define COBJMACROS
#include <objbase.h>
#pragma warning (push)
#pragma warning (disable : 4201) //iads.h(1003) : nonstandard extension used : nameless struct/union
#include <iads.h>
#pragma warning (pop)
#include <adshlp.h>
#include <adserr.h>
#include <lm.h>
#include <alertmsg.h>
#include <winsock2.h>
#include <dsgetdc.h>
#include <ntdsapi.h>
#include "llsapi.h"
#include "debug.h"
#include "llsutil.h"
#include "llssrv.h"
#include "service.h"
#include "registry.h"
#include "mapping.h"
#include "msvctbl.h"
#include "svctbl.h"
#include "perseat.h"
#include "purchase.h"
#include "server.h"
#include "repl.h"
#include "scaven.h"
#include "llsrpc_s.h"
#include "certdb.h"
#include <strsafe.h> //include last
BOOL CompareMachineName( LPCWSTR pwszName1, LPCWSTR pwszName2); VOID DNSToFlatName( LPCWSTR pwszDNSName, DWORD ccBufferLen, LPWSTR pwszBuffer); NTSTATUS GetDCInfo( DWORD cbDomain, WCHAR *wszDomain, DOMAIN_CONTROLLER_INFO ** ppDCInfo); HRESULT GetSiteServer( LPCWSTR pwszDomain, LPCWSTR pwszSiteName, BOOL fIsDC, LPWSTR * ppwszSiteServer); HRESULT BecomeSiteServer( DS_NAME_RESULT **ppDsResult, IADs *pADs2, LPWSTR *ppwszDN, LPCWSTR pwszDomain);
LPWSTR GetSiteServerFromRegistry( VOID); LPWSTR GetEnterpriseServerFromRegistry( VOID); HRESULT GetLicenseSettingsObject( LPCWSTR pwszSiteName, LPCWSTR pwszConfigContainer, IADs ** ppADs); HRESULT GetSiteObject( LPCWSTR pwszSiteName, LPCWSTR pwszConfigContainer, IADsContainer ** ppADsContainer); HRESULT CreateLicenseSettingsObject( LPCWSTR pwszSiteName, LPCWSTR pwszConfigContainer, IADs ** ppADs); BOOL IsDC( VOID); VOID LLSRpcInit(); BOOLEAN LLSpLPCInitialize( VOID); VOID LoadAll(); VOID SetSiteRegistrySettings( LPCWSTR pwszSiteServer);
NTSTATUS FilePrintTableInit();
#define INTERNAL_VERSION 0x0006
#define DEFAULT_LICENSE_CHECK_TIME 24
#define DEFAULT_REPLICATION_TIME 12 * 60 * 60
CONFIG_RECORD ConfigInfo; RTL_CRITICAL_SECTION ConfigInfoLock;
#if DBG
DWORD TraceFlags = 0; #endif
//
// this event is signalled when the service should end
//
HANDLE hServerStopEvent = NULL; TCHAR MyDomain[MAX_COMPUTERNAME_LENGTH + 2]; ULONG MyDomainSize;
BOOL IsMaster = FALSE;
//
// Files
//
TCHAR MappingFileName[MAX_PATH + 1]; TCHAR UserFileName[MAX_PATH + 1]; TCHAR LicenseFileName[MAX_PATH + 1]; TCHAR CertDbFileName[MAX_PATH + 1];
extern SERVICE_STATUS_HANDLE sshStatusHandle;
RTL_CRITICAL_SECTION g_csLock; volatile BOOL g_fInitializationComplete = FALSE; volatile BOOL g_fDoingInitialization = FALSE;
//
// SBS mods (bug# 505640), declarations for per server licensing problems hotfix
//
PPER_SERVER_USER_RECORD PerServerList = NULL; RTL_CRITICAL_SECTION PerServerListLock; BOOL SBSPerServerHotfix = FALSE;
//
// end SBS mods
//
HANDLE g_hThrottleConfig = NULL; HANDLE g_hThrottleConnect = NULL;
BOOL g_fRunning = FALSE;
extern RTL_CRITICAL_SECTION MappingFileLock; extern RTL_CRITICAL_SECTION UserFileLock;
/////////////////////////////////////////////////////////////////////////
NTSTATUS GetDCInfo( DWORD cbDomain, WCHAR *wszDomain, DOMAIN_CONTROLLER_INFO ** ppDCInfo )
/*++
Routine Description:
Arguments:
Return Value:
None.
--*/
{ DWORD Status; HRESULT hr;
ASSERT(NULL != wszDomain);
Status = DsGetDcNameW(NULL, NULL, NULL, NULL, DS_DIRECTORY_SERVICE_PREFERRED | DS_RETURN_FLAT_NAME | DS_BACKGROUND_ONLY, ppDCInfo);
if (Status == STATUS_SUCCESS) { ASSERT(NULL != ppDCInfo); hr = StringCbCopy(wszDomain, cbDomain, (*ppDCInfo)->DomainName); ASSERT(SUCCEEDED(hr)); } else { *wszDomain = L'\0'; *ppDCInfo = NULL; }
return(Status); } // GetDCInfo
/////////////////////////////////////////////////////////////////////////
DWORD LlsTimeGet( )
/*++
Routine Description:
Arguments:
Return Value:
Seconds since midnight.
--*/
{ DWORD Seconds; SYSTEMTIME SysTime;
GetLocalTime(&SysTime);
Seconds = (SysTime.wHour * 24 * 60) + (SysTime.wMinute * 60) + (SysTime.wSecond); return Seconds;
} // LlsTimeGet
/////////////////////////////////////////////////////////////////////////
VOID ConfigInfoRegistryUpdate( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ DWORD ReplicationType, ReplicationTime;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: ConfigInfoRegistryUpdate\n")); #endif
#if DELAY_INITIALIZATION
EnsureInitialized(); #endif
ConfigInfoUpdate(NULL,FALSE);
RtlEnterCriticalSection(&ConfigInfoLock);
//
// Update values from Registry
//
ReplicationTime = ConfigInfo.ReplicationTime; ReplicationType = ConfigInfo.ReplicationType; ConfigInfoRegistryInit( &ConfigInfo.ReplicationType, &ConfigInfo.ReplicationTime, &ConfigInfo.LogLevel, &ConfigInfo.PerServerCapacityWarning );
if ( (ConfigInfo.ReplicationTime == 0) && (LLS_REPLICATION_TYPE_TIME != ConfigInfo.ReplicationType) ) ConfigInfo.ReplicationTime = DEFAULT_REPLICATION_TIME;
//
// Adjust replication time if it has changed
//
if ((ReplicationTime != ConfigInfo.ReplicationTime) || (ReplicationType != ConfigInfo.ReplicationType)) ReplicationTimeSet();
RtlLeaveCriticalSection(&ConfigInfoLock);
} // ConfigInfoRegistryUpdate
/////////////////////////////////////////////////////////////////////////
VOID ConfigInfoUpdate( DOMAIN_CONTROLLER_INFO * pDCInfo, BOOL fForceUpdate )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ BOOL fIsDC = FALSE; BOOL fSiteServerFromRegistry = FALSE; BOOL fInDomain = FALSE; LPWSTR pwszSiteName = NULL; LPWSTR pwszSiteServer = NULL; LPWSTR pwszPropagationTarget = NULL; DOMAIN_CONTROLLER_INFO * pDCInfoLocal = NULL; DWORD ReplicationType, ReplicationTime; TCHAR szDomain[MAX_COMPUTERNAME_LENGTH + 1] = { TEXT('\0') }; DWORD dwWait; HRESULT hr; size_t cch;
#if DBG
if (TraceFlags & TRACE_FUNCTION_TRACE) dprintf(TEXT("LLS TRACE: ConfigInfoUpdate2\n")); #endif
if (!fForceUpdate) { dwWait = WaitForSingleObject(g_hThrottleConfig, 0);
if (dwWait == WAIT_TIMEOUT) { // We've already updated in the past 15 minutes; return immediately
return; } }
//
// Get domain/DC information.
//
if (pDCInfo == NULL) { GetDCInfo(sizeof(szDomain), szDomain, &pDCInfoLocal); pDCInfo = pDCInfoLocal; } else { //
// Copy the domain name.
//
if (pDCInfo->DomainName != NULL) { wcsncpy(szDomain, pDCInfo->DomainName, MAX_COMPUTERNAME_LENGTH); } }
if (*szDomain) { fInDomain = TRUE;
if (NO_ERROR != DsGetSiteName(NULL, &pwszSiteName)) { pwszSiteName = NULL; }
fIsDC = IsDC();
if (fIsDC && (NULL != pwszSiteName)) { GetSiteServer(szDomain, pwszSiteName, fIsDC, &pwszSiteServer); }
}
if (!fIsDC) {
//
// Domain or Workgroup member
//
pwszSiteServer = GetSiteServerFromRegistry();
fSiteServerFromRegistry = TRUE; }
if ( fIsDC ) { //
// This server is a DC. Propagate to the site server.
//
if (pwszSiteServer == NULL) { //
// The attempt to obtain it from the DS failed, default to
// the local registry.
//
pwszSiteServer = GetSiteServerFromRegistry(); fSiteServerFromRegistry = TRUE; }
pwszPropagationTarget = pwszSiteServer; } else if ( fInDomain ) { //
// This server is a member server. Propagate to a DC, providing
// it is in the same site as this server; else, propagate
// directly to the site server.
//
if (pDCInfo != NULL && pwszSiteName != NULL && pDCInfo->DcSiteName != NULL && lstrcmpi(pwszSiteName, pDCInfo->DcSiteName) == 0) {
//
// DC and server are in same site. Propagate to DC.
//
// Create DC name copy so the info struct can be freed.
//
if (pDCInfo->DomainControllerName != NULL) { cch = lstrlen(pDCInfo->DomainControllerName) + 1; pwszPropagationTarget = LocalAlloc( LPTR, cch * sizeof(TCHAR));
if (pwszPropagationTarget != NULL) { hr = StringCchCopy(pwszPropagationTarget, cch, pDCInfo->DomainControllerName); ASSERT(SUCCEEDED(hr)); } else { #if DBG
dprintf(TEXT("LLS: DC name allocation failure\n")); #endif
goto CleanExit; } } } else { //
// DC is in another site. Propagate to the site server.
//
if ((NULL == pwszSiteServer) && (NULL != pwszSiteName)) {
//
// No value found in registry, try Active Directory
//
fSiteServerFromRegistry = FALSE;
GetSiteServer(szDomain, pwszSiteName, fIsDC, &pwszSiteServer); }
pwszPropagationTarget = pwszSiteServer; } } else { //
// Standalone server. Propagate directly to the enterprise
// server
//
pwszPropagationTarget = GetEnterpriseServerFromRegistry();
if (pwszPropagationTarget == NULL) { //
// Don't have an enterprise server, try site server
//
pwszPropagationTarget = pwszSiteServer; } }
//
// Update ConfigInfo fields from information obtained above.
//
RtlEnterCriticalSection(&ConfigInfoLock);
//
// Check if the propagation target is actually this
// machine. i.e., this is the site server.
//
if ((pwszPropagationTarget != NULL) && (*pwszPropagationTarget != 0)) { if (CompareMachineName(pwszPropagationTarget, ConfigInfo.ComputerName)) { //
// This is the site server - don't propagate.
//
if (pwszPropagationTarget != pwszSiteServer) { LocalFree(pwszPropagationTarget); } pwszPropagationTarget = NULL; // For free below.
ConfigInfo.IsMaster = TRUE; ConfigInfo.Replicate = FALSE; } }
//
// Update the SiteServer ConfigInfo field.
//
if (pwszSiteServer != NULL) { if (ConfigInfo.SiteServer != ConfigInfo.ReplicateTo) { LocalFree(ConfigInfo.SiteServer); } ConfigInfo.SiteServer = pwszSiteServer; pwszSiteServer = NULL; // For free below.
//
// Update the site related registry values.
//
if (!fSiteServerFromRegistry) { SetSiteRegistrySettings(ConfigInfo.SiteServer); } }
//
// Update the ReplicateTo ConfigInfo field.
//
if ((pwszPropagationTarget != NULL) && (*pwszPropagationTarget != 0)) { //
// This server is propgagating to the site server or the DC.
//
ConfigInfo.IsMaster = FALSE; ConfigInfo.Replicate = TRUE;
if ((ConfigInfo.ReplicateTo != NULL) && (ConfigInfo.ReplicateTo != ConfigInfo.SiteServer)) { LocalFree(ConfigInfo.ReplicateTo); } ConfigInfo.ReplicateTo = pwszPropagationTarget; pwszPropagationTarget = NULL; // For free below.
} else if (!ConfigInfo.IsMaster) { //
// Standalone server, and Site Server not specified in registry.
// Do not replicate.
//
ConfigInfo.IsMaster = FALSE; ConfigInfo.Replicate = FALSE; }
//
// Update remaining ConfigInfo fields from registry.
//
// NB : Hardcode to *always* use the enterprise - new with NT 5.0.
//
ConfigInfo.UseEnterprise = 1;
ReplicationTime = ConfigInfo.ReplicationTime; ReplicationType = ConfigInfo.ReplicationType;
ConfigInfoRegistryInit( &ConfigInfo.ReplicationType, &ConfigInfo.ReplicationTime, &ConfigInfo.LogLevel, &ConfigInfo.PerServerCapacityWarning );
//
// Finally, adjust replication time if it has changed
//
if ((ReplicationTime != ConfigInfo.ReplicationTime) || (ReplicationType != ConfigInfo.ReplicationType)) { ReplicationTimeSet(); }
IsMaster = ConfigInfo.IsMaster;
RtlLeaveCriticalSection(&ConfigInfoLock);
CleanExit: if (pDCInfoLocal != NULL) { NetApiBufferFree(pDCInfoLocal); // Allocated from DsGetDcName
}
if (pwszSiteName != NULL) { // Allocated from DsGetSiteName
NetApiBufferFree(pwszSiteName); }
if (pwszSiteServer != NULL && pwszSiteServer == pwszPropagationTarget) { LocalFree(pwszSiteServer); pwszPropagationTarget = NULL; } if (pwszPropagationTarget != NULL) { LocalFree(pwszPropagationTarget); } }
/////////////////////////////////////////////////////////////////////////
BOOL IsDC( VOID )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ NT_PRODUCT_TYPE NtType;
//
// If we aren't a DC, then count us as a member
//
NtType = NtProductLanManNt; RtlGetNtProductType(&NtType); if (NtType != NtProductLanManNt) return(FALSE); else { return(TRUE); } }
/////////////////////////////////////////////////////////////////////////
NTSTATUS ConfigInfoInit( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ DWORD Size; TCHAR DataPath[MAX_PATH + 1]; NTSTATUS status; HRESULT hr; size_t cb; DWORD cch;
//
// First zero init the memory
//
memset(&ConfigInfo, 0, sizeof(ConfigInfo));
ConfigInfo.ComputerName = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 1) * sizeof(TCHAR)); ConfigInfo.ReplicateTo = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 3) * sizeof(TCHAR)); ConfigInfo.EnterpriseServer = LocalAlloc(LPTR, (MAX_COMPUTERNAME_LENGTH + 3) * sizeof(TCHAR)); cch = MAX_PATH + 1; ConfigInfo.SystemDir = LocalAlloc(LPTR, cch * sizeof(TCHAR));
if ((ConfigInfo.ComputerName == NULL) || (ConfigInfo.ReplicateTo == NULL) || (ConfigInfo.EnterpriseServer == NULL) || (ConfigInfo.SystemDir == NULL) ) { ASSERT(FALSE); }
ConfigInfo.Version = INTERNAL_VERSION; GetLocalTime(&ConfigInfo.Started);
//
// LastReplicated is just for display, LlsReplTime is what is used to
// Calculate it.
GetLocalTime(&ConfigInfo.LastReplicated); ConfigInfo.LastReplicatedSeconds = DateSystemGet();
if (ConfigInfo.SystemDir != NULL) { //swi, code review, no return check?
GetSystemDirectory(ConfigInfo.SystemDir, cch); hr = StringCchCat(ConfigInfo.SystemDir, cch, TEXT("\\")); ASSERT(SUCCEEDED(hr)); }
ConfigInfo.IsMaster = FALSE;
ConfigInfo.Replicate = FALSE; ConfigInfo.IsReplicating = FALSE; ConfigInfo.PerServerCapacityWarning = TRUE;
ConfigInfo.ReplicationType = REPLICATE_DELTA; ConfigInfo.ReplicationTime = DEFAULT_REPLICATION_TIME;
if (ConfigInfo.ComputerName != NULL) { Size = MAX_COMPUTERNAME_LENGTH + 1; GetComputerName(ConfigInfo.ComputerName, &Size); }
status = RtlInitializeCriticalSection(&ConfigInfoLock);
if (!NT_SUCCESS(status)) return status;
ConfigInfo.LogLevel = 0;
if (ConfigInfo.SystemDir != NULL) { //
// Create File paths
//
cb = sizeof(MappingFileName); hr = StringCbCopy(MappingFileName, cb, ConfigInfo.SystemDir); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(MappingFileName, cb, TEXT(LLS_FILE_SUBDIR)); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(MappingFileName, cb, TEXT("\\")); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(MappingFileName, cb, TEXT(MAP_FILE_NAME)); ASSERT(SUCCEEDED(hr)); cb = sizeof(UserFileName); hr = StringCbCopy(UserFileName, cb, ConfigInfo.SystemDir); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(UserFileName, cb, TEXT(LLS_FILE_SUBDIR)); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(UserFileName, cb, TEXT("\\")); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(UserFileName, cb, TEXT(USER_FILE_NAME)); ASSERT(SUCCEEDED(hr));
cb = sizeof(CertDbFileName); hr = StringCbCopy(CertDbFileName, cb, ConfigInfo.SystemDir); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(CertDbFileName, cb, TEXT(LLS_FILE_SUBDIR)); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(CertDbFileName, cb, TEXT("\\")); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(CertDbFileName, cb, TEXT(CERT_DB_FILE_NAME)); ASSERT(SUCCEEDED(hr));
cb = sizeof(LicenseFileName); hr = StringCbCopy(LicenseFileName, cb, ConfigInfo.SystemDir); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(LicenseFileName, cb, TEXT(LICENSE_FILE_NAME)); ASSERT(SUCCEEDED(hr));
//
// Make sure our directory is there.
//
cb = sizeof(DataPath); hr = StringCbCopy(DataPath, cb, ConfigInfo.SystemDir); ASSERT(SUCCEEDED(hr)); hr = StringCbCat(DataPath, cb, TEXT(LLS_FILE_SUBDIR)); ASSERT(SUCCEEDED(hr)); CreateDirectory(DataPath, NULL); } else { MappingFileName[0] = 0; UserFileName[0] = 0; CertDbFileName[0] = 0; LicenseFileName[0] = 0; }
return STATUS_SUCCESS;
} // ConfigInfoInit
/////////////////////////////////////////////////////////////////////////
DWORD WINAPI LLSTopLevelExceptionHandler( struct _EXCEPTION_POINTERS *ExceptionInfo )
/*++
Routine Description:
The Top Level exception filter for LLSMain.exe.
This ensures the entire process will be cleaned up if any of the threads fail. Since LLSMain.exe is a distributed application, it is better to fail the entire process than allow random threads to continue executing.
Arguments:
ExceptionInfo - Identifies the exception that occurred.
Return Values:
EXCEPTION_EXECUTE_HANDLER - Terminate the process.
EXCEPTION_CONTINUE_SEARCH - Continue processing as though this filter was never called.
--*/ { HANDLE hModule;
//
// Raise an alert
//
hModule = LoadLibraryA("netapi32");
if ( hModule != NULL ) { NET_API_STATUS (NET_API_FUNCTION *NetAlertRaiseExFunction) (LPTSTR, LPVOID, DWORD, LPTSTR);
NetAlertRaiseExFunction = (NET_API_STATUS (NET_API_FUNCTION *) (LPTSTR, LPVOID, DWORD, LPTSTR)) GetProcAddress(hModule, "NetAlertRaiseEx");
if ( NetAlertRaiseExFunction != NULL ) { NTSTATUS Status; UNICODE_STRING Strings;
char message[ALERTSZ + sizeof(ADMIN_OTHER_INFO)]; PADMIN_OTHER_INFO admin = (PADMIN_OTHER_INFO) message;
//
// Build the variable data
//
admin->alrtad_errcode = ALERT_UnhandledException; admin->alrtad_numstrings = 0;
Strings.Buffer = (LPWSTR) ALERT_VAR_DATA(admin); Strings.Length = 0; Strings.MaximumLength = ALERTSZ;
ASSERT(NULL != ExceptionInfo); Status = RtlIntegerToUnicodeString( (ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode, 16, &Strings );
if ( NT_SUCCESS(Status) ) { if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) { Status = STATUS_BUFFER_TOO_SMALL; } else { admin->alrtad_numstrings++; *(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0'; Strings.Length += sizeof(WCHAR);
Status = RtlAppendUnicodeToString( &Strings, L"LLS" ); }
}
if ( NT_SUCCESS(Status) ) { if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) { Status = STATUS_BUFFER_TOO_SMALL; } else { admin->alrtad_numstrings++; *(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0'; Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1; Strings.MaximumLength -= Strings.Length + sizeof(WCHAR); Strings.Length = 0;
Status = RtlIntPtrToUnicodeString( (ULONG_PTR)(ExceptionInfo->ExceptionRecord->ExceptionAddress), 16, &Strings ); }
}
if ( NT_SUCCESS(Status) ) { if ( Strings.Length + sizeof(WCHAR) >= Strings.MaximumLength) { Status = STATUS_BUFFER_TOO_SMALL; } else { admin->alrtad_numstrings++; *(Strings.Buffer+(Strings.Length/sizeof(WCHAR))) = L'\0'; Strings.Buffer += (Strings.Length/sizeof(WCHAR)) + 1;
(VOID) (*NetAlertRaiseExFunction)( ALERT_ADMIN_EVENT, message, (DWORD)((PCHAR)Strings.Buffer - (PCHAR)message), L"LLS" ); }
}
}
(VOID) FreeLibrary( hModule ); }
//
// Just continue processing the exception.
//
return EXCEPTION_CONTINUE_SEARCH;
} // LLSTopLevelExceptionHandler
DWORD ServiceStartDelayed( ) /*++
Routine Description:
Do the stuff that used to be done at service startup time, but can wait until the first RPC.
Arguments:
None.
Return Values:
None.
--*/ { NTSTATUS dwErr = STATUS_SUCCESS;
//
// SBS mods (bug# 505640), locals for per server licensing hotfix
//
OSVERSIONINFOEX VersionInfo = {sizeof(OSVERSIONINFOEX)};
//
// end SBS mods
//
dwErr = RtlInitializeCriticalSection(&MappingFileLock); if (!NT_SUCCESS(dwErr)) goto Cleanup;
dwErr = RtlInitializeCriticalSection(&UserFileLock); if (!NT_SUCCESS(dwErr)) goto Cleanup;
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
//
// Create the FilePrint table
//
dwErr = FilePrintTableInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
// Initialize the Service Table
dwErr = LicenseListInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
dwErr = MasterServiceListInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
dwErr = LocalServiceListInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
dwErr = ServiceListInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
dwErr = MappingListInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
// Initialize the Per-Seat Table
dwErr = UserListInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
// Initialize the Service Table
dwErr = ServerListInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
// Initialize the Certificate Database
dwErr = CertDbInit();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
if (!NT_SUCCESS(dwErr)) goto Cleanup;
// Load data files
LoadAll();
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT);
//
// SBS mods (bug# 505640) - initialization for per server licensing problem hotfix
//
// ensure that our QFE only runs on SBS.
if (GetVersionEx((LPOSVERSIONINFO)&VersionInfo) && (VersionInfo.wSuiteMask & (VER_SUITE_SMALLBUSINESS_RESTRICTED | VER_SUITE_SMALLBUSINESS))) { SBSPerServerHotfix = TRUE; RtlInitializeCriticalSection(&PerServerListLock);
// This next is probably unneccessary, but certainly won't hurt anything.
ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT); }
//
// end SBS mods
//
Cleanup:
return dwErr; }
DWORD EnsureInitialized ( VOID ) { DWORD dwErr;
// Most common case is we're already initialized. Perform a quick
// check for this.
//
if (g_fInitializationComplete) { return NOERROR; }
dwErr = NOERROR;
// Make no assumptions about how many threads may be trying to
// initialize us at the same time.
//
RtlEnterCriticalSection (&g_csLock);
// Need to re-check after acquiring the lock because another thread
// may have just finished initializing and released the lock allowing
// us to get it.
//
if ((!g_fInitializationComplete) && (!g_fDoingInitialization)) { // set this now so this thread can't call ServiceStartDelayed twice
g_fDoingInitialization = TRUE; dwErr = ServiceStartDelayed();
g_fInitializationComplete = TRUE; }
RtlLeaveCriticalSection (&g_csLock);
return dwErr; }
/////////////////////////////////////////////////////////////////////////
VOID ServiceStart ( DWORD dwArgc, LPTSTR *lpszArgv ) /*++
Routine Description:
The code that starts everything, is really the main().
Arguments:
None. *** argc and argv unused ***
Return Values:
None.
--*/ { DWORD dwWait; NTSTATUS Status = STATUS_SUCCESS; KPRIORITY BasePriority; HANDLE hThread = NULL; BOOL fCoInitialized = FALSE; LARGE_INTEGER liWait; BOOL fRet;
UNREFERENCED_PARAMETER(dwArgc); UNREFERENCED_PARAMETER(lpszArgv);
///////////////////////////////////////////////////
//
// Service initialization
//
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
//
// Define a top-level exception handler for the entire process.
//
(VOID) SetErrorMode( SEM_FAILCRITICALERRORS );
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
#pragma warning (push)
#pragma warning (disable : 4057) //'LPTOP_LEVEL_EXCEPTION_FILTER' differs in indirection to slightly different base types from 'DWORD (__stdcall *)(_EXCEPTION_POINTERS *)'
(VOID) SetUnhandledExceptionFilter( &LLSTopLevelExceptionHandler ); #pragma warning (pop)
//
// Run the LLS in the foreground.
//
// Several processes which depend on the LLS (like the lanman server)
// run in the foreground. If we don't run in the foreground, they'll
// starve waiting for us.
//
BasePriority = FOREGROUND_BASE_PRIORITY;
Status = NtSetInformationProcess( NtCurrentProcess(), ProcessBasePriority, &BasePriority, sizeof(BasePriority) );
// BUGBUG: ignore error for now; may be caused by running as NetworkService
#if 0
if (!NT_SUCCESS(Status)) { goto Cleanup; } #endif
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
//
// Create an event to throttle ConfigInfoUpdate
//
g_hThrottleConfig = CreateWaitableTimer(NULL, // SecurityAttributes,
FALSE, // bManualReset
NULL // lpName
);
if (NULL == g_hThrottleConfig) { Status = GetLastError(); goto Cleanup; }
liWait.QuadPart = (LONGLONG) (-1); // Start immediately
fRet = SetWaitableTimer(g_hThrottleConfig, &liWait, 1000*60*15, // lPeriod, 15 minutes
NULL, // pfnCompletionRoutine
NULL, // lpArgToCompletionRoutine
FALSE // fResume (from suspended)
);
if (!fRet) { Status = GetLastError(); goto Cleanup; }
//
// Create an event to throttle Per Seat purchase replication
//
g_hThrottleConnect = CreateWaitableTimer(NULL, // SecurityAttributes,
FALSE, // bManualReset
NULL // lpName
);
if (NULL == g_hThrottleConnect) { Status = GetLastError(); goto Cleanup; }
liWait.QuadPart = (LONGLONG) (-1); // Start immediately
fRet = SetWaitableTimer(g_hThrottleConnect, &liWait, 1000*60*15, // lPeriod, 15 minutes
NULL, // pfnCompletionRoutine
NULL, // lpArgToCompletionRoutine
FALSE // fResume (from suspended)
);
if (!fRet) { Status = GetLastError(); goto Cleanup; }
//
// Start separate thread to contact the DS
//
hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ConfigInfoInit, NULL, 0, NULL);
Status = RtlInitializeCriticalSection(&g_csLock); if (!NT_SUCCESS(Status)) { goto Cleanup; }
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
//
// Create the event object. The control handler function signals
// this event when it receives the "stop" control code.
//
hServerStopEvent = CreateEvent( NULL, // no security attributes
TRUE, // manual reset event
FALSE, // not-signalled
NULL); // no name
if ( hServerStopEvent == NULL) goto Cleanup;
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
// Initialize Replication...
ReplicationInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
// Initialize the Registry values...
RegistryInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
// Initialize scavenger thread...
ScavengerInit();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
//
// wait for ConfigInfoInit to complete before accepting clients
//
while (hThread != NULL) { dwWait = WaitForSingleObject(hThread,NSERVICEWAITHINT/2);
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
if (dwWait == WAIT_OBJECT_0) { GetExitCodeThread(hThread, (LPDWORD)(&Status));
// Check if critsec creation failed
if (!NT_SUCCESS(Status)) goto Cleanup;
CloseHandle(hThread); hThread = NULL; break; } }
// Initialize RegistryMonitor thread...
RegistryStartMonitor();
//
// Report the status to the service control manager.
//
if (!ReportStatusToSCMgr( SERVICE_START_PENDING, NO_ERROR, NSERVICEWAITHINT)) // wait hint
goto Cleanup;
// Initialize COM
if (!FAILED(CoInitialize(NULL))) { fCoInitialized = TRUE; }
// Do all the stuff that used to be delayed
EnsureInitialized();
// Initialize RPC Stuff... (start accepting clients)
LLSRpcInit();
//
// End of initialization
//
////////////////////////////////////////////////////////
//
// Tell SCM we are up and running!
//
if (!ReportStatusToSCMgr( SERVICE_RUNNING, NO_ERROR, 0)) goto Cleanup;
g_fRunning = TRUE;
////////////////////////////////////////////////////////
//
// Service is now running, perform work until shutdown
//
dwWait = WaitForSingleObject(hServerStopEvent, INFINITE);
Cleanup: if (fCoInitialized) CoUninitialize();
if (hThread != NULL) CloseHandle(hThread);
if (hServerStopEvent) CloseHandle(hServerStopEvent);
if (sshStatusHandle) ReportStatusToSCMgr( SERVICE_STOPPED, NO_ERROR, 0);
} // ServiceStart
/////////////////////////////////////////////////////////////////////////
VOID ServiceStop() /*++
Routine Description:
Stops the service.
If a ServiceStop procedure is going to take longer than 3 seconds to execute, it should spawn a thread to execute the stop code, and return. Otherwise, the ServiceControlManager will believe that the service has stopped responding.
Arguments:
None.
Return Values:
None.
--*/ { if ( hServerStopEvent ) SetEvent(hServerStopEvent); } // ServiceStop
#define FIND_DNSNAME_SEPARATOR(pwsz) { \
while (*pwsz && *pwsz != TEXT('.')) { \ pwsz++; \ } \ }
/////////////////////////////////////////////////////////////////////////
VOID DNSToFlatName( LPCWSTR pwszDNSName, DWORD ccBufferLen, LPWSTR pwszBuffer )
/*++
Routine Description:
Arguments: pwszDNSName ccBufferLen pwszBuffer
Return Value:
--*/
{ LPWSTR pwszFlatName = (LPWSTR)pwszDNSName; SIZE_T ccFlatNameLen;
ASSERT(pwszDNSName != NULL);
FIND_DNSNAME_SEPARATOR(pwszFlatName);
ccFlatNameLen = (DWORD)(pwszFlatName - pwszDNSName);
if (ccFlatNameLen && ccFlatNameLen < ccBufferLen) { lstrcpyn(pwszBuffer, pwszDNSName, (int)ccFlatNameLen + 1); pwszBuffer[ccFlatNameLen] = TEXT('\0'); } else { *pwszBuffer = TEXT('\0'); } }
/////////////////////////////////////////////////////////////////////////
BOOL CompareMachineName( LPCWSTR pwszName1, LPCWSTR pwszName2 )
/*++
Routine Description:
Arguments: pwszName1 pwszName2
Return Value: TRUE -- The names match. FALSE -- Otherwise.
--*/
{ TCHAR szFlatName[MAX_COMPUTERNAME_LENGTH + 3]; LPWSTR pwszTmp1 = (LPWSTR)pwszName1; LPWSTR pwszTmp2 = (LPWSTR)pwszName2;
if (pwszName1 == NULL || pwszName2 == NULL) { return FALSE; }
//
// Identify if both/either name are DNS names by checking for the
// existence of a '.' separator.
//
FIND_DNSNAME_SEPARATOR(pwszTmp1); FIND_DNSNAME_SEPARATOR(pwszTmp2);
if ((*pwszTmp1 && *pwszTmp2) || (!*pwszTmp1 && !*pwszTmp2)) { //
// Non-differing name types. Both are either DNS or flat.
//
return (lstrcmpi(pwszName1, pwszName2) == 0); } else if (*pwszTmp1) { //
// Name 1 is DNS, name 2 is flat.
// Convert DNS to flat, then compare.
//
DNSToFlatName(pwszName1, MAX_COMPUTERNAME_LENGTH + 3, szFlatName);
return (lstrcmpi(szFlatName, pwszName2) == 0); } else { //
// Name 2 is DNS, name 1 is flat.
// Convert DNS to flat, then compare.
//
DNSToFlatName(pwszName2, MAX_COMPUTERNAME_LENGTH + 3, szFlatName);
return (lstrcmpi(szFlatName, pwszName1) == 0); } }
#define REG_LS_PARAMETERS \
TEXT("System\\CurrentControlSet\\Services\\LicenseService\\Parameters") #define REG_LS_SITESERVER \
TEXT("SiteServer") #define REG_LS_ENTERPRISESERVER \
TEXT("EnterpriseServer") #define REG_LS_USEENTERPRISE \
TEXT("UseEnterprise")
/////////////////////////////////////////////////////////////////////////
LPWSTR GetSiteServerFromRegistry( VOID )
/*++
Routine Description:
Arguments: None.
Return Value:
--*/
{ HKEY hKey = NULL; DWORD dwType, dwSize; LPWSTR pwszSiteServer = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_LS_PARAMETERS, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
//
// Allocate SiteServer on the heap since it could be quite large.
//
dwSize = 0;
if (RegQueryValueEx(hKey, REG_LS_SITESERVER, NULL, &dwType, (LPBYTE)NULL, &dwSize) == ERROR_SUCCESS) { // Bug# 685884
// dwSize is always 2 sizeof(WCHAR)(for unicode null character) even if the key is empty.
// Allocate only if dwSize > 2
if(dwSize > sizeof(WCHAR)) { pwszSiteServer = LocalAlloc(LPTR, dwSize);
if (pwszSiteServer != NULL) { if (RegQueryValueEx(hKey, REG_LS_SITESERVER, NULL, &dwType, (LPBYTE)pwszSiteServer, &dwSize) != ERROR_SUCCESS) { LocalFree(pwszSiteServer); pwszSiteServer = NULL; } } } }
RegCloseKey(hKey); }
return pwszSiteServer; }
/////////////////////////////////////////////////////////////////////////
LPWSTR GetEnterpriseServerFromRegistry( VOID )
/*++
Routine Description:
Arguments: None.
Return Value:
--*/
{ HKEY hKey = NULL; DWORD dwType, dwSize; LPWSTR pwszEnterpriseServer = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_LS_PARAMETERS, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
//
// Allocate EnterpriseServer on the heap since it could be quite large.
//
dwSize = 0;
if (RegQueryValueEx(hKey, REG_LS_ENTERPRISESERVER, NULL, &dwType, (LPBYTE)NULL, &dwSize) == ERROR_SUCCESS) { pwszEnterpriseServer = LocalAlloc(LPTR, dwSize);
if (pwszEnterpriseServer != NULL) { if (RegQueryValueEx(hKey, REG_LS_ENTERPRISESERVER, NULL, &dwType, (LPBYTE)pwszEnterpriseServer, &dwSize) != ERROR_SUCCESS) { LocalFree(pwszEnterpriseServer); pwszEnterpriseServer = NULL; } } }
RegCloseKey(hKey); }
return pwszEnterpriseServer; }
/////////////////////////////////////////////////////////////////////////
VOID SetSiteRegistrySettings( LPCWSTR pwszSiteServer )
/*++
Routine Description:
Arguments: pwszSiteServer
Return Value:
--*/
{ HKEY hKey; DWORD dwSize; DWORD dwType = REG_SZ;
ASSERT(pwszSiteServer != NULL);
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_LS_PARAMETERS, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS) {
//
// Write the SiteServer value.
//
dwSize = (lstrlen(pwszSiteServer) + 1) * sizeof(TCHAR);
RegSetValueEx(hKey, REG_LS_SITESERVER, 0, dwType, (LPBYTE)pwszSiteServer, dwSize);
RegCloseKey(hKey); } }
//
// Pre-fill the ADSI cache with only the attribute we want, then get it
// Only use if exactly one attribute is needed
//
HRESULT GetWithGetInfoEx( IADs *pADs, LPWSTR wszAttribute, VARIANT *pvar ) { HRESULT hr;
ASSERT(NULL != wszAttribute);
hr = ADsBuildVarArrayStr( &wszAttribute, 1, pvar ); if( SUCCEEDED( hr ) ) { hr = IADs_GetInfoEx( pADs, *pvar, 0L ); VariantClear( pvar );
if (SUCCEEDED(hr)) { hr = IADs_Get( pADs, wszAttribute, pvar ); } }
return hr; }
//
// Pre-fill the ADSI cache with only the attributes we want, then get them
// Only use if exactly two attributes are needed
//
HRESULT GetWithGetInfoEx2( IADs *pADs, LPWSTR wszAttribute1, LPWSTR wszAttribute2, VARIANT *pvar1, VARIANT *pvar2, HRESULT * phr2 ) { HRESULT hr; #pragma warning (push)
#pragma warning (disable : 4204) // following init violates W4, nonstandard extension used : non-constant aggregate initializer
LPWSTR rgwszAttributes[] = {wszAttribute1,wszAttribute2}; #pragma warning (pop)
hr = ADsBuildVarArrayStr( rgwszAttributes, 2, pvar1 ); if( SUCCEEDED( hr ) ) { hr = IADs_GetInfoEx( pADs, *pvar1, 0L ); VariantClear( pvar1 );
if (SUCCEEDED(hr)) { hr = IADs_Get( pADs, wszAttribute1, pvar1 );
if (SUCCEEDED(hr)) { *phr2 = IADs_Get( pADs, wszAttribute2, pvar2 ); } } }
return hr; }
#define CWSTR_SIZE(x) (sizeof(x) - (sizeof(WCHAR) * 2))
#define DWSTR_SIZE(x) ((wcslen(x) + 1) * sizeof(WCHAR))
#define ROOT_DSE_PATH L"LDAP://RootDSE"
#define CONFIG_CNTNR L"ConfigurationNamingContext"
#define SITE_SERVER L"siteServer"
#define DNS_MACHINE_NAME L"dNSHostName"
#define IS_DELETED L"isDeleted"
/////////////////////////////////////////////////////////////////////////
HRESULT GetSiteServer( LPCWSTR pwszDomain, LPCWSTR pwszSiteName, BOOL fIsDC, LPWSTR * ppwszSiteServer )
/*++
Routine Description:
Arguments: pwszSiteName fIsDC ppwszSiteServer
Return Value:
--*/
{ LPWSTR pwszDN = NULL; LPWSTR pwszConfigContainer; LPWSTR pwszBindPath; IADs * pADs = NULL; IADs * pADs2 = NULL; IADs * pADs3 = NULL; DS_NAME_RESULT * pDsResult = NULL; VARIANT var; VARIANT var2; HRESULT hr, hr2; DWORD dwRet = 0; BOOL fAlreadyTookSiteServer = FALSE; BOOL fCoInitialized = FALSE; size_t cb, cch;
ASSERT(pwszSiteName != NULL); ASSERT(ppwszSiteServer != NULL);
*ppwszSiteServer = NULL;
VariantInit(&var); VariantInit(&var2);
hr = CoInitialize(NULL);
if (FAILED(hr)) { ERR(hr); goto CleanExit; }
fCoInitialized = TRUE;
//
// Obtain the path to the configuration container.
//
hr = ADsGetObject(ROOT_DSE_PATH, &IID_IADs, (void **)&pADs);
if (FAILED(hr)) { ERR(hr); goto CleanExit; }
hr = IADs_Get(pADs, CONFIG_CNTNR, &var);
if (FAILED(hr)) { ERR(hr); goto CleanExit; }
if (V_VT(&var) != VT_BSTR) { ASSERT(V_VT(&var) == VT_BSTR); dwRet = ERROR_INVALID_DATA; ERR(dwRet); goto CleanExit; }
pwszConfigContainer = var.bstrVal; // For sake of readability.
//
// Bind to the license settings object.
//
hr = GetLicenseSettingsObject(pwszSiteName, pwszConfigContainer, &pADs2);
if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT)) { //
// The license settings object doesn't exist. Create it.
//
hr = CreateLicenseSettingsObject(pwszSiteName, pwszConfigContainer, &pADs2); }
if (FAILED(hr)) { //
// Failed to bind or create the license settings object.
//
goto CleanExit; }
ASSERT(pADs2 != NULL);
//
// Consult the site server property on the license settings object.
// It's a DN to the machine object of the site server.
//
VariantClear(&var);
hr = GetWithGetInfoEx(pADs2, SITE_SERVER, &var);
//
// If the site server property has not been set and this server
// is a DC, designate this server as the site server.
//
if (hr == E_ADS_PROPERTY_NOT_FOUND && fIsDC) { dwRet = BecomeSiteServer(&pDsResult,pADs2,&pwszDN,pwszDomain);
if (dwRet) goto CleanExit; } else if (SUCCEEDED(hr)) { if (V_VT(&var) != VT_BSTR) { ASSERT(V_VT(&var) == VT_BSTR); dwRet = ERROR_INVALID_DATA; ERR(dwRet); goto CleanExit; }
pwszDN = V_BSTR(&var); } else { goto CleanExit; }
TryNewSiteServer: //
// Bind to the computer object referenced by the Site-Server property.
//
if (pwszDN == NULL) { hr = E_FAIL; ERR(hr); goto CleanExit; }
// LDAP:// + pwszDN + 1
cch = wcslen(pwszDN) + 8; pwszBindPath = LocalAlloc(LPTR, cch * sizeof(WCHAR));
if (pwszBindPath == NULL) { hr = E_OUTOFMEMORY; ERR(hr); goto CleanExit; }
hr = StringCchPrintf(pwszBindPath, cch, L"LDAP://%ws", pwszDN); ASSERT(SUCCEEDED(hr));
hr = ADsOpenObject(pwszBindPath, NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND | ADS_SERVER_BIND, &IID_IADs, (void **)&pADs3);
LocalFree(pwszBindPath);
if (FAILED(hr)) { if (fIsDC && !fAlreadyTookSiteServer) { //
// Existing SiteServer is gone, claim it
//
if (pDsResult != NULL) { DsFreeNameResult(pDsResult); }
dwRet = BecomeSiteServer(&pDsResult,pADs2,&pwszDN,pwszDomain); if (dwRet) { goto CleanExit; } else { fAlreadyTookSiteServer = TRUE;
if (pADs3 != NULL) { IADs_Release(pADs3); } goto TryNewSiteServer; } } else { ERR(hr); goto CleanExit; } }
//
// Fetch the Machine-DNS-Name property.
//
VariantClear(&var);
hr = GetWithGetInfoEx2(pADs3, DNS_MACHINE_NAME, IS_DELETED, &var, &var2, &hr2);
if (FAILED(hr)) { ERR(hr); goto CleanExit; }
if (SUCCEEDED(hr2)) {
hr = VariantChangeType(&var2,&var2,0,VT_BOOL);
if (FAILED(hr)) { ERR(hr); goto CleanExit; }
if (V_BOOL(&var2)) { // object has been deleted - pretend it isn't set
hr = E_ADS_PROPERTY_NOT_SET;
if (fIsDC && !fAlreadyTookSiteServer) { //
// Existing SiteServer is gone, claim it
//
if (pDsResult != NULL) { DsFreeNameResult(pDsResult); }
dwRet = BecomeSiteServer(&pDsResult,pADs2,&pwszDN,pwszDomain); if (dwRet) { goto CleanExit; } else { fAlreadyTookSiteServer = TRUE;
if (pADs3 != NULL) { IADs_Release(pADs3); } goto TryNewSiteServer; } } else { ERR(hr); goto CleanExit; } } }
//
// Allocate a return copy of the DNS-Machine-Name.
//
cb = SysStringByteLen(V_BSTR(&var)) + sizeof(WCHAR); *ppwszSiteServer = (LPWSTR)LocalAlloc(LPTR, cb);
if (*ppwszSiteServer != NULL) { hr = StringCbCopy(*ppwszSiteServer, cb, V_BSTR(&var)); ASSERT(SUCCEEDED(hr)); } else { hr = E_OUTOFMEMORY; ERR(hr); }
CleanExit: // Do not free pwszDN, pwszConfigContainer or pwszBindPath.
if (pADs != NULL) { IADs_Release(pADs); } if (pADs2 != NULL) { IADs_Release(pADs2); } if (pADs3 != NULL) { IADs_Release(pADs3); } if (pDsResult != NULL) { DsFreeNameResult(pDsResult); }
if (dwRet) { // If dwRet has no facility, then make into HRESULT
if (dwRet != ERROR_SUCCESS && HRESULT_CODE(dwRet) == dwRet) hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet); }
VariantClear(&var); VariantClear(&var2);
if (fCoInitialized) { CoUninitialize(); }
return hr; }
HRESULT BecomeSiteServer( DS_NAME_RESULT **ppDsResult, IADs *pADs2, LPWSTR *ppwszDN, LPCWSTR pwszDomain ) { HANDLE hDS; WCHAR wszName[MAX_PATH + 1]; LPWSTR rgpwszNames[2]; DWORD dwRet = 0; VARIANT var; DS_NAME_RESULT * pDsResult = NULL; LPWSTR pwszDN = NULL; HRESULT hr = S_OK; size_t cb;
ASSERT(ppDsResult != NULL); ASSERT(ppwszDN != NULL);
VariantInit(&var);
//
// Bind to the DS (get a handle for use with DsCrackNames).
//
if (ConfigInfo.ComputerName == NULL) { hr = E_UNEXPECTED; goto CleanExit; }
if (DsBind(NULL, (WCHAR *)pwszDomain, &hDS) == ERROR_SUCCESS) { //
// Request the DS-DN of this server's computer object.
// Offer the domain\server$ name of this server.
//
cb = sizeof(wszName); hr = StringCbCopy(wszName, cb, pwszDomain); if (S_OK != hr) { goto CleanExit; } hr = StringCbCat(wszName, cb, L"\\"); if (S_OK != hr) { goto CleanExit; } hr = StringCbCat(wszName, cb, ConfigInfo.ComputerName); if (S_OK != hr) { goto CleanExit; } hr = StringCbCat(wszName, cb, L"$"); if (S_OK != hr) { goto CleanExit; }
rgpwszNames[0] = wszName; rgpwszNames[1] = NULL;
if (DsCrackNames(hDS, DS_NAME_NO_FLAGS, DS_UNKNOWN_NAME, DS_FQDN_1779_NAME, 1, &rgpwszNames[0], &pDsResult) == ERROR_SUCCESS) {
if (pDsResult->rItems[0].status != DS_NAME_NO_ERROR) { if (pDsResult->rItems[0].status == DS_NAME_ERROR_RESOLVING) { dwRet = ERROR_PATH_NOT_FOUND; ERR(dwRet); } else { ERR(pDsResult->rItems[0].status); hr = E_FAIL; }
goto CleanExit; }
if (pDsResult->rItems[0].pName == NULL) { hr = E_FAIL; goto CleanExit; }
//
// Update the site server property on the license
// settings object.
//
VariantInit(&var); V_VT(&var) = VT_BSTR; V_BSTR(&var) = pwszDN = pDsResult->rItems[0].pName; hr = IADs_Put(pADs2, SITE_SERVER, var);
V_VT(&var) = VT_EMPTY; // For VariantClear below
if (SUCCEEDED(hr)) { hr = IADs_SetInfo(pADs2);
if (FAILED(hr)) { ERR(hr); } } else { ERR(hr); } } else { dwRet = GetLastError(); ERR(dwRet); } DsUnBind(&hDS); } else { dwRet = GetLastError(); ERR(dwRet); }
CleanExit: *ppDsResult = pDsResult; *ppwszDN = pwszDN;
if (!SUCCEEDED(hr) && SUCCEEDED(dwRet)) dwRet = hr;
return dwRet; }
#define SITE_FORMAT L"LDAP://CN=%ws,CN=%ws,%ws"
#define SITES L"sites"
#define SITE_FORMAT_SIZE CWSTR_SIZE(SITE_FORMAT)
#define SITES_SIZE CWSTR_SIZE(SITES)
HRESULT GetSiteObject(LPCWSTR pwszSiteName, LPCWSTR pwszConfigContainer, IADsContainer ** ppADsContainer) { LPWSTR pwszSite; HRESULT hr; size_t cb;
ASSERT(NULL != ppADsContainer); *ppADsContainer = NULL;
//
// Build the X.500 path to the Site object.
//
cb = SITE_FORMAT_SIZE + DWSTR_SIZE(pwszSiteName) + SITES_SIZE + DWSTR_SIZE(pwszConfigContainer) + sizeof(WCHAR); pwszSite = (LPWSTR)LocalAlloc(LPTR, cb);
if (pwszSite == NULL) { hr = E_OUTOFMEMORY; ERR(hr); goto Exit; }
hr = StringCbPrintf(pwszSite, cb, SITE_FORMAT, pwszSiteName, SITES, pwszConfigContainer); ASSERT(SUCCEEDED(hr));
hr = ADsGetObject(pwszSite, &IID_IADsContainer, (void **)ppADsContainer);
LocalFree(pwszSite);
if (FAILED(hr)) { ERR(hr); }
Exit: return hr; }
#define LICENSE_SETTINGS L"Licensing Site Settings"
#define LICENSE_SETTINGS_FORMAT L"LDAP://CN=%ws,CN=%ws,CN=%ws,%ws"
#define LICENSE_SETTINGS_SIZE CWSTR_SIZE(LICENSE_SETTINGS)
#define LICENSE_SETTINGS_FORMAT_SIZE CWSTR_SIZE(LICENSE_SETTINGS_FORMAT)
HRESULT GetLicenseSettingsObject(LPCWSTR pwszSiteName, LPCWSTR pwszConfigContainer, IADs ** ppADs) { LPWSTR pwszLicenseSettings; HRESULT hr; size_t cb;
ASSERT(NULL != ppADs); *ppADs = NULL;
//
// Build the X.500 path to the LicenseSettings object.
//
cb = LICENSE_SETTINGS_FORMAT_SIZE + LICENSE_SETTINGS_SIZE + DWSTR_SIZE(pwszSiteName) + SITES_SIZE + DWSTR_SIZE(pwszConfigContainer) + sizeof(WCHAR); pwszLicenseSettings = (LPWSTR)LocalAlloc(LPTR, cb);
if (pwszLicenseSettings == NULL) { hr = E_OUTOFMEMORY; ERR(hr); goto Exit; }
hr = StringCbPrintf(pwszLicenseSettings, cb, LICENSE_SETTINGS_FORMAT, LICENSE_SETTINGS, pwszSiteName, SITES, pwszConfigContainer); ASSERT(SUCCEEDED(hr));
hr = ADsOpenObject(pwszLicenseSettings, NULL, NULL, ADS_SECURE_AUTHENTICATION | ADS_FAST_BIND, &IID_IADs, (void **)ppADs);
LocalFree(pwszLicenseSettings);
if (FAILED(hr)) { ERR(hr); }
Exit: return hr; }
HRESULT CreateLicenseSettingsObject(LPCWSTR pwszSiteName, LPCWSTR pwszConfigContainer, IADs ** ppADs) { IADsContainer * pADsContainer; IDispatch * pDisp; HRESULT hr;
ASSERT(NULL != ppADs); *ppADs = NULL;
//
// Obtain the site container object.
//
hr = GetSiteObject(pwszSiteName, pwszConfigContainer, &pADsContainer);
if (SUCCEEDED(hr)) { //
// Create the license settings leaf object.
//
hr = IADsContainer_Create(pADsContainer, LICENSE_SETTINGS, LICENSE_SETTINGS, &pDisp);
if (SUCCEEDED(hr)) {
//
// Return an IADs to the new license settings object.
//
hr = IDispatch_QueryInterface(pDisp, &IID_IADs, (void **)ppADs);
if (SUCCEEDED(hr)) { //
// Persist the change via SetInfo.
//
hr = IADs_SetInfo(*ppADs);
if (FAILED(hr)) { ERR(hr); IADs_Release(*ppADs); *ppADs = NULL; } } else { ERR(hr); }
IDispatch_Release(pDisp); } else { ERR(hr); }
IADsContainer_Release(pADsContainer); } else { ERR(hr); }
return hr; }
#if DBG
/////////////////////////////////////////////////////////////////////////
VOID ConfigInfoDebugDump( )
/*++
Routine Description:
Arguments:
Return Value:
--*/
{ ConfigInfoUpdate(NULL,TRUE);
RtlEnterCriticalSection(&ConfigInfoLock);
dprintf(TEXT("License Logging Service - Version: 0x%lX\n"), ConfigInfo.Version); dprintf(TEXT(" Started: %u-%u-%u @ %u:%u:%u\n"), (UINT) ConfigInfo.Started.wDay, (UINT) ConfigInfo.Started.wMonth, (UINT) ConfigInfo.Started.wYear, (UINT) ConfigInfo.Started.wHour, (UINT) ConfigInfo.Started.wMinute, (UINT) ConfigInfo.Started.wSecond );
dprintf(TEXT(" Replication\n")); dprintf(TEXT(" +--------------+\n")); if (ConfigInfo.IsMaster) dprintf(TEXT(" Master Server\n")); else dprintf(TEXT(" NOT Master Server\n"));
if (ConfigInfo.Replicate) dprintf(TEXT(" Replicates\n")); else dprintf(TEXT(" Does not Replicate\n"));
if (ConfigInfo.IsReplicating) dprintf(TEXT(" Currently Replicating\n")); else dprintf(TEXT(" NOT Currently Replicating\n"));
dprintf(TEXT(" Replicates To: %s\n"), ConfigInfo.ReplicateTo); dprintf(TEXT(" Enterprise Server: %s\n"), ConfigInfo.EnterpriseServer);
if (ConfigInfo.ReplicationType == REPLICATE_DELTA) dprintf(TEXT(" Replicate Every: %lu Seconds\n"), ConfigInfo.ReplicationTime ); else dprintf(TEXT(" Replicate @: %lu\n"), ConfigInfo.ReplicationTime );
dprintf(TEXT("\n Last Replicated: %u-%u-%u @ %u:%u:%u\n\n"), (UINT) ConfigInfo.LastReplicated.wDay, (UINT) ConfigInfo.LastReplicated.wMonth, (UINT) ConfigInfo.LastReplicated.wYear, (UINT) ConfigInfo.LastReplicated.wHour, (UINT) ConfigInfo.LastReplicated.wMinute, (UINT) ConfigInfo.LastReplicated.wSecond );
dprintf(TEXT(" Number Servers Currently Replicating: %lu\n"), ConfigInfo.NumReplicating);
dprintf(TEXT(" Current Backoff Time Delta: %lu\n"), ConfigInfo.BackoffTime);
dprintf(TEXT(" Current Replication Speed: %lu\n"), ConfigInfo.ReplicationSpeed);
RtlLeaveCriticalSection(&ConfigInfoLock);
} // ConfigInfoDebugDump
#endif
|