//-------------------------------------------------------------------- // 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 #include #include #include #include #include #include #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; }