You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
517 lines
13 KiB
517 lines
13 KiB
//--------------------------------------------------------------------
|
|
// netlogon - implementation
|
|
// Copyright (C) Microsoft Corporation, 2001
|
|
//
|
|
// Created by: Duncan Bryce (duncanb), 06-24-2002
|
|
//
|
|
// Helper routines for w32time's interaction with the netlogon service.
|
|
// Copied from \\index1\sdnt\ds\netapi\svcdlls\logonsrv\client\getdcnam.c
|
|
//
|
|
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <winsvc.h>
|
|
#include <lmcons.h>
|
|
#include <lmsname.h>
|
|
#include "netlogon.h"
|
|
|
|
|
|
BOOLEAN
|
|
NlReadDwordHklmRegValue(
|
|
IN LPCSTR SubKey,
|
|
IN LPCSTR ValueName,
|
|
OUT PDWORD ValueRead
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads a DWORD from the specified registry location.
|
|
|
|
Arguments:
|
|
|
|
SubKey - Subkey of the value to read.
|
|
|
|
ValueName - The name of the value to read.
|
|
|
|
ValueRead - Returns the value read from the registry.
|
|
|
|
Return Status:
|
|
|
|
TRUE - We've successfully read the data.
|
|
FALSE - We've not been able to read the data successfully.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG RegStatus;
|
|
|
|
HKEY KeyHandle = NULL;
|
|
DWORD ValueType;
|
|
DWORD Value;
|
|
DWORD ValueSize;
|
|
|
|
//
|
|
// Open the key
|
|
//
|
|
|
|
RegStatus = RegOpenKeyExA(
|
|
HKEY_LOCAL_MACHINE,
|
|
SubKey,
|
|
0, //Reserved
|
|
KEY_QUERY_VALUE,
|
|
&KeyHandle );
|
|
|
|
if ( RegStatus != ERROR_SUCCESS ) {
|
|
if ( RegStatus != ERROR_FILE_NOT_FOUND ) {
|
|
// NlPrint(( NL_CRITICAL,
|
|
// "NlReadDwordHklmRegValue: Cannot open registy key 'HKLM\\%s' %ld.\n",
|
|
// SubKey,
|
|
// RegStatus ));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the value
|
|
//
|
|
|
|
ValueSize = sizeof(Value);
|
|
RegStatus = RegQueryValueExA(
|
|
KeyHandle,
|
|
ValueName,
|
|
0,
|
|
&ValueType,
|
|
(LPBYTE)&Value,
|
|
&ValueSize );
|
|
|
|
RegCloseKey( KeyHandle );
|
|
|
|
if ( RegStatus != ERROR_SUCCESS ) {
|
|
if ( RegStatus != ERROR_FILE_NOT_FOUND ) {
|
|
// NlPrint(( NL_CRITICAL,
|
|
// "NlReadDwordHklmRegValue: Cannot query value of 'HKLM\\%s\\%s' %ld.\n",
|
|
// SubKey,
|
|
// ValueName,
|
|
// RegStatus ));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if ( ValueType != REG_DWORD ) {
|
|
// NlPrint(( NL_CRITICAL,
|
|
// "NlReadDwordHklmRegValue: value of 'HKLM\\%s\\%s'is not a REG_DWORD %ld.\n",
|
|
// SubKey,
|
|
// ValueName,
|
|
// ValueType ));
|
|
return FALSE;
|
|
}
|
|
|
|
if ( ValueSize != sizeof(Value) ) {
|
|
// NlPrint(( NL_CRITICAL,
|
|
// "NlReadDwordHklmRegValue: value size of 'HKLM\\%s\\%s'is not 4 %ld.\n",
|
|
// SubKey,
|
|
// ValueName,
|
|
// ValueSize ));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// We've successfully read the data
|
|
//
|
|
|
|
*ValueRead = Value;
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
BOOLEAN
|
|
NlDoingSetup(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns TRUE if we're running setup.
|
|
|
|
Arguments:
|
|
|
|
NONE.
|
|
|
|
Return Status:
|
|
|
|
TRUE - We're currently running setup
|
|
FALSE - We're not running setup or aren't sure.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD Value;
|
|
|
|
if ( !NlReadDwordHklmRegValue( "SYSTEM\\Setup",
|
|
"SystemSetupInProgress",
|
|
&Value ) ) {
|
|
return FALSE;
|
|
}
|
|
|
|
if ( Value != 1 ) {
|
|
// NlPrint(( 0, "NlDoingSetup: not doing setup\n" ));
|
|
return FALSE;
|
|
}
|
|
|
|
// NlPrint(( 0, "NlDoingSetup: doing setup\n" ));
|
|
return TRUE;
|
|
}
|
|
|
|
NTSTATUS
|
|
NlWaitForEvent(
|
|
LPWSTR EventName,
|
|
ULONG Timeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait up to Timeout seconds for EventName to be triggered.
|
|
|
|
Arguments:
|
|
|
|
EventName - Name of event to wait on
|
|
|
|
Timeout - Timeout for event (in seconds).
|
|
|
|
Return Status:
|
|
|
|
STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
|
|
STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
HANDLE EventHandle;
|
|
OBJECT_ATTRIBUTES EventAttributes;
|
|
UNICODE_STRING EventNameString;
|
|
LARGE_INTEGER LocalTimeout;
|
|
|
|
|
|
//
|
|
// Create an event for us to wait on.
|
|
//
|
|
|
|
RtlInitUnicodeString( &EventNameString, EventName);
|
|
InitializeObjectAttributes( &EventAttributes, &EventNameString, 0, 0, NULL);
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
SYNCHRONIZE,
|
|
&EventAttributes,
|
|
NotificationEvent,
|
|
(BOOLEAN) FALSE // The event is initially not signaled
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// If the event already exists, the server beat us to creating it.
|
|
// Just open it.
|
|
//
|
|
|
|
if( Status == STATUS_OBJECT_NAME_EXISTS ||
|
|
Status == STATUS_OBJECT_NAME_COLLISION ) {
|
|
|
|
Status = NtOpenEvent( &EventHandle,
|
|
SYNCHRONIZE,
|
|
&EventAttributes );
|
|
|
|
}
|
|
if ( !NT_SUCCESS(Status)) {
|
|
// NlPrint((0,"[NETAPI32] OpenEvent failed %lx\n", Status ));
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Wait for NETLOGON to initialize. Wait a maximum of Timeout seconds.
|
|
//
|
|
|
|
LocalTimeout.QuadPart = ((LONGLONG)(Timeout)) * (-10000000);
|
|
Status = NtWaitForSingleObject( EventHandle, (BOOLEAN)FALSE, &LocalTimeout);
|
|
(VOID) NtClose( EventHandle );
|
|
|
|
if ( !NT_SUCCESS(Status) || Status == STATUS_TIMEOUT ) {
|
|
if ( Status == STATUS_TIMEOUT ) {
|
|
Status = STATUS_NETLOGON_NOT_STARTED; // Map to an error condition
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
NlWaitForNetlogon(
|
|
ULONG Timeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Wait up to Timeout seconds for the netlogon service to start.
|
|
|
|
Arguments:
|
|
|
|
Timeout - Timeout for event (in seconds).
|
|
|
|
Return Status:
|
|
|
|
STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
|
|
STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
NET_API_STATUS NetStatus;
|
|
SC_HANDLE ScManagerHandle = NULL;
|
|
SC_HANDLE ServiceHandle = NULL;
|
|
SERVICE_STATUS ServiceStatus;
|
|
LPQUERY_SERVICE_CONFIG ServiceConfig;
|
|
LPQUERY_SERVICE_CONFIG AllocServiceConfig = NULL;
|
|
QUERY_SERVICE_CONFIG DummyServiceConfig;
|
|
DWORD ServiceConfigSize;
|
|
|
|
//
|
|
// If the netlogon service is currently running,
|
|
// skip the rest of the tests.
|
|
//
|
|
|
|
Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 0 );
|
|
|
|
if ( NT_SUCCESS(Status) ) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// If we're in setup,
|
|
// don't bother waiting for netlogon to start.
|
|
//
|
|
|
|
if ( NlDoingSetup() ) {
|
|
return STATUS_NETLOGON_NOT_STARTED;
|
|
}
|
|
|
|
//
|
|
// Open a handle to the Netlogon Service.
|
|
//
|
|
|
|
ScManagerHandle = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_CONNECT );
|
|
|
|
if (ScManagerHandle == NULL) {
|
|
// NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenSCManager failed: "
|
|
// "%lu\n", GetLastError()));
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ServiceHandle = OpenService(
|
|
ScManagerHandle,
|
|
SERVICE_NETLOGON,
|
|
SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
|
|
|
|
if ( ServiceHandle == NULL ) {
|
|
//NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenService failed: "
|
|
// "%lu\n", GetLastError()));
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// If the Netlogon service isn't configured to be automatically started
|
|
// by the service controller, don't bother waiting for it to start.
|
|
//
|
|
// ?? Pass "DummyServiceConfig" and "sizeof(..)" since QueryService config
|
|
// won't allow a null pointer, yet.
|
|
|
|
if ( QueryServiceConfig(
|
|
ServiceHandle,
|
|
&DummyServiceConfig,
|
|
sizeof(DummyServiceConfig),
|
|
&ServiceConfigSize )) {
|
|
|
|
ServiceConfig = &DummyServiceConfig;
|
|
|
|
} else {
|
|
|
|
NetStatus = GetLastError();
|
|
if ( NetStatus != ERROR_INSUFFICIENT_BUFFER ) {
|
|
//NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig failed: "
|
|
// "%lu\n", NetStatus));
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
AllocServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc( 0, ServiceConfigSize );
|
|
ServiceConfig = AllocServiceConfig;
|
|
|
|
if ( AllocServiceConfig == NULL ) {
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( !QueryServiceConfig(
|
|
ServiceHandle,
|
|
ServiceConfig,
|
|
ServiceConfigSize,
|
|
&ServiceConfigSize )) {
|
|
|
|
//NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig "
|
|
// "failed again: %lu\n", GetLastError()));
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
if ( ServiceConfig->dwStartType != SERVICE_AUTO_START ) {
|
|
// NlPrint((0, "[NETAPI32] NlWaitForNetlogon: Netlogon start type invalid:"
|
|
// "%lu\n", ServiceConfig->dwStartType ));
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Loop waiting for the netlogon service to start.
|
|
// (Convert Timeout to a number of 10 second iterations)
|
|
//
|
|
|
|
Timeout = (Timeout+9)/10;
|
|
for (;;) {
|
|
|
|
|
|
//
|
|
// Query the status of the Netlogon service.
|
|
//
|
|
|
|
if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
|
|
|
|
// NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceStatus failed: "
|
|
// "%lu\n", GetLastError() ));
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Return or continue waiting depending on the state of
|
|
// the netlogon service.
|
|
//
|
|
|
|
switch( ServiceStatus.dwCurrentState) {
|
|
case SERVICE_RUNNING:
|
|
Status = STATUS_SUCCESS;
|
|
goto Cleanup;
|
|
|
|
case SERVICE_STOPPED:
|
|
|
|
//
|
|
// If Netlogon failed to start,
|
|
// error out now. The caller has waited long enough to start.
|
|
//
|
|
if ( ServiceStatus.dwWin32ExitCode != ERROR_SERVICE_NEVER_STARTED ){
|
|
#if NETLOGONDBG
|
|
// NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
|
|
// "Netlogon service couldn't start: %lu %lx\n",
|
|
// ServiceStatus.dwWin32ExitCode,
|
|
// ServiceStatus.dwWin32ExitCode ));
|
|
if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
|
|
// NlPrint((0, " Service specific error code: %lu %lx\n",
|
|
// ServiceStatus.dwServiceSpecificExitCode,
|
|
// ServiceStatus.dwServiceSpecificExitCode ));
|
|
}
|
|
#endif // DBG
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If Netlogon has never been started on this boot,
|
|
// continue waiting for it to start.
|
|
//
|
|
|
|
break;
|
|
|
|
//
|
|
// If Netlogon is trying to start up now,
|
|
// continue waiting for it to start.
|
|
//
|
|
case SERVICE_START_PENDING:
|
|
break;
|
|
|
|
//
|
|
// Any other state is bogus.
|
|
//
|
|
default:
|
|
// NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
|
|
// "Invalid service state: %lu\n",
|
|
// ServiceStatus.dwCurrentState ));
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Wait ten seconds for the netlogon service to start.
|
|
// If it has successfully started, just return now.
|
|
//
|
|
|
|
Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 10 );
|
|
|
|
if ( Status != STATUS_NETLOGON_NOT_STARTED ) {
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If we've waited long enough for netlogon to start,
|
|
// time out now.
|
|
//
|
|
|
|
if ( (--Timeout) == 0 ) {
|
|
Status = STATUS_NETLOGON_NOT_STARTED;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/* NOT REACHED */
|
|
|
|
Cleanup:
|
|
if ( ScManagerHandle != NULL ) {
|
|
(VOID) CloseServiceHandle(ScManagerHandle);
|
|
}
|
|
if ( ServiceHandle != NULL ) {
|
|
(VOID) CloseServiceHandle(ServiceHandle);
|
|
}
|
|
if ( AllocServiceConfig != NULL ) {
|
|
LocalFree( AllocServiceConfig );
|
|
}
|
|
return Status;
|
|
}
|