Leaked source code of windows server 2003
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

  1. //--------------------------------------------------------------------
  2. // netlogon - implementation
  3. // Copyright (C) Microsoft Corporation, 2001
  4. //
  5. // Created by: Duncan Bryce (duncanb), 06-24-2002
  6. //
  7. // Helper routines for w32time's interaction with the netlogon service.
  8. // Copied from \\index1\sdnt\ds\netapi\svcdlls\logonsrv\client\getdcnam.c
  9. //
  10. #include <nt.h>
  11. #include <ntrtl.h>
  12. #include <nturtl.h>
  13. #include <windows.h>
  14. #include <winsvc.h>
  15. #include <lmcons.h>
  16. #include <lmsname.h>
  17. #include "netlogon.h"
  18. BOOLEAN
  19. NlReadDwordHklmRegValue(
  20. IN LPCSTR SubKey,
  21. IN LPCSTR ValueName,
  22. OUT PDWORD ValueRead
  23. )
  24. /*++
  25. Routine Description:
  26. Reads a DWORD from the specified registry location.
  27. Arguments:
  28. SubKey - Subkey of the value to read.
  29. ValueName - The name of the value to read.
  30. ValueRead - Returns the value read from the registry.
  31. Return Status:
  32. TRUE - We've successfully read the data.
  33. FALSE - We've not been able to read the data successfully.
  34. --*/
  35. {
  36. LONG RegStatus;
  37. HKEY KeyHandle = NULL;
  38. DWORD ValueType;
  39. DWORD Value;
  40. DWORD ValueSize;
  41. //
  42. // Open the key
  43. //
  44. RegStatus = RegOpenKeyExA(
  45. HKEY_LOCAL_MACHINE,
  46. SubKey,
  47. 0, //Reserved
  48. KEY_QUERY_VALUE,
  49. &KeyHandle );
  50. if ( RegStatus != ERROR_SUCCESS ) {
  51. if ( RegStatus != ERROR_FILE_NOT_FOUND ) {
  52. // NlPrint(( NL_CRITICAL,
  53. // "NlReadDwordHklmRegValue: Cannot open registy key 'HKLM\\%s' %ld.\n",
  54. // SubKey,
  55. // RegStatus ));
  56. }
  57. return FALSE;
  58. }
  59. //
  60. // Get the value
  61. //
  62. ValueSize = sizeof(Value);
  63. RegStatus = RegQueryValueExA(
  64. KeyHandle,
  65. ValueName,
  66. 0,
  67. &ValueType,
  68. (LPBYTE)&Value,
  69. &ValueSize );
  70. RegCloseKey( KeyHandle );
  71. if ( RegStatus != ERROR_SUCCESS ) {
  72. if ( RegStatus != ERROR_FILE_NOT_FOUND ) {
  73. // NlPrint(( NL_CRITICAL,
  74. // "NlReadDwordHklmRegValue: Cannot query value of 'HKLM\\%s\\%s' %ld.\n",
  75. // SubKey,
  76. // ValueName,
  77. // RegStatus ));
  78. }
  79. return FALSE;
  80. }
  81. if ( ValueType != REG_DWORD ) {
  82. // NlPrint(( NL_CRITICAL,
  83. // "NlReadDwordHklmRegValue: value of 'HKLM\\%s\\%s'is not a REG_DWORD %ld.\n",
  84. // SubKey,
  85. // ValueName,
  86. // ValueType ));
  87. return FALSE;
  88. }
  89. if ( ValueSize != sizeof(Value) ) {
  90. // NlPrint(( NL_CRITICAL,
  91. // "NlReadDwordHklmRegValue: value size of 'HKLM\\%s\\%s'is not 4 %ld.\n",
  92. // SubKey,
  93. // ValueName,
  94. // ValueSize ));
  95. return FALSE;
  96. }
  97. //
  98. // We've successfully read the data
  99. //
  100. *ValueRead = Value;
  101. return TRUE;
  102. }
  103. BOOLEAN
  104. NlDoingSetup(
  105. VOID
  106. )
  107. /*++
  108. Routine Description:
  109. Returns TRUE if we're running setup.
  110. Arguments:
  111. NONE.
  112. Return Status:
  113. TRUE - We're currently running setup
  114. FALSE - We're not running setup or aren't sure.
  115. --*/
  116. {
  117. DWORD Value;
  118. if ( !NlReadDwordHklmRegValue( "SYSTEM\\Setup",
  119. "SystemSetupInProgress",
  120. &Value ) ) {
  121. return FALSE;
  122. }
  123. if ( Value != 1 ) {
  124. // NlPrint(( 0, "NlDoingSetup: not doing setup\n" ));
  125. return FALSE;
  126. }
  127. // NlPrint(( 0, "NlDoingSetup: doing setup\n" ));
  128. return TRUE;
  129. }
  130. NTSTATUS
  131. NlWaitForEvent(
  132. LPWSTR EventName,
  133. ULONG Timeout
  134. )
  135. /*++
  136. Routine Description:
  137. Wait up to Timeout seconds for EventName to be triggered.
  138. Arguments:
  139. EventName - Name of event to wait on
  140. Timeout - Timeout for event (in seconds).
  141. Return Status:
  142. STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
  143. STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
  144. --*/
  145. {
  146. NTSTATUS Status;
  147. HANDLE EventHandle;
  148. OBJECT_ATTRIBUTES EventAttributes;
  149. UNICODE_STRING EventNameString;
  150. LARGE_INTEGER LocalTimeout;
  151. //
  152. // Create an event for us to wait on.
  153. //
  154. RtlInitUnicodeString( &EventNameString, EventName);
  155. InitializeObjectAttributes( &EventAttributes, &EventNameString, 0, 0, NULL);
  156. Status = NtCreateEvent(
  157. &EventHandle,
  158. SYNCHRONIZE,
  159. &EventAttributes,
  160. NotificationEvent,
  161. (BOOLEAN) FALSE // The event is initially not signaled
  162. );
  163. if ( !NT_SUCCESS(Status)) {
  164. //
  165. // If the event already exists, the server beat us to creating it.
  166. // Just open it.
  167. //
  168. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  169. Status == STATUS_OBJECT_NAME_COLLISION ) {
  170. Status = NtOpenEvent( &EventHandle,
  171. SYNCHRONIZE,
  172. &EventAttributes );
  173. }
  174. if ( !NT_SUCCESS(Status)) {
  175. // NlPrint((0,"[NETAPI32] OpenEvent failed %lx\n", Status ));
  176. return Status;
  177. }
  178. }
  179. //
  180. // Wait for NETLOGON to initialize. Wait a maximum of Timeout seconds.
  181. //
  182. LocalTimeout.QuadPart = ((LONGLONG)(Timeout)) * (-10000000);
  183. Status = NtWaitForSingleObject( EventHandle, (BOOLEAN)FALSE, &LocalTimeout);
  184. (VOID) NtClose( EventHandle );
  185. if ( !NT_SUCCESS(Status) || Status == STATUS_TIMEOUT ) {
  186. if ( Status == STATUS_TIMEOUT ) {
  187. Status = STATUS_NETLOGON_NOT_STARTED; // Map to an error condition
  188. }
  189. return Status;
  190. }
  191. return STATUS_SUCCESS;
  192. }
  193. NTSTATUS
  194. NlWaitForNetlogon(
  195. ULONG Timeout
  196. )
  197. /*++
  198. Routine Description:
  199. Wait up to Timeout seconds for the netlogon service to start.
  200. Arguments:
  201. Timeout - Timeout for event (in seconds).
  202. Return Status:
  203. STATUS_SUCCESS - Indicates NETLOGON successfully initialized.
  204. STATUS_NETLOGON_NOT_STARTED - Timeout occurred.
  205. --*/
  206. {
  207. NTSTATUS Status;
  208. NET_API_STATUS NetStatus;
  209. SC_HANDLE ScManagerHandle = NULL;
  210. SC_HANDLE ServiceHandle = NULL;
  211. SERVICE_STATUS ServiceStatus;
  212. LPQUERY_SERVICE_CONFIG ServiceConfig;
  213. LPQUERY_SERVICE_CONFIG AllocServiceConfig = NULL;
  214. QUERY_SERVICE_CONFIG DummyServiceConfig;
  215. DWORD ServiceConfigSize;
  216. //
  217. // If the netlogon service is currently running,
  218. // skip the rest of the tests.
  219. //
  220. Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 0 );
  221. if ( NT_SUCCESS(Status) ) {
  222. return Status;
  223. }
  224. //
  225. // If we're in setup,
  226. // don't bother waiting for netlogon to start.
  227. //
  228. if ( NlDoingSetup() ) {
  229. return STATUS_NETLOGON_NOT_STARTED;
  230. }
  231. //
  232. // Open a handle to the Netlogon Service.
  233. //
  234. ScManagerHandle = OpenSCManager(
  235. NULL,
  236. NULL,
  237. SC_MANAGER_CONNECT );
  238. if (ScManagerHandle == NULL) {
  239. // NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenSCManager failed: "
  240. // "%lu\n", GetLastError()));
  241. Status = STATUS_NETLOGON_NOT_STARTED;
  242. goto Cleanup;
  243. }
  244. ServiceHandle = OpenService(
  245. ScManagerHandle,
  246. SERVICE_NETLOGON,
  247. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG );
  248. if ( ServiceHandle == NULL ) {
  249. //NlPrint((0, "[NETAPI32] NlWaitForNetlogon: OpenService failed: "
  250. // "%lu\n", GetLastError()));
  251. Status = STATUS_NETLOGON_NOT_STARTED;
  252. goto Cleanup;
  253. }
  254. //
  255. // If the Netlogon service isn't configured to be automatically started
  256. // by the service controller, don't bother waiting for it to start.
  257. //
  258. // ?? Pass "DummyServiceConfig" and "sizeof(..)" since QueryService config
  259. // won't allow a null pointer, yet.
  260. if ( QueryServiceConfig(
  261. ServiceHandle,
  262. &DummyServiceConfig,
  263. sizeof(DummyServiceConfig),
  264. &ServiceConfigSize )) {
  265. ServiceConfig = &DummyServiceConfig;
  266. } else {
  267. NetStatus = GetLastError();
  268. if ( NetStatus != ERROR_INSUFFICIENT_BUFFER ) {
  269. //NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig failed: "
  270. // "%lu\n", NetStatus));
  271. Status = STATUS_NETLOGON_NOT_STARTED;
  272. goto Cleanup;
  273. }
  274. AllocServiceConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc( 0, ServiceConfigSize );
  275. ServiceConfig = AllocServiceConfig;
  276. if ( AllocServiceConfig == NULL ) {
  277. Status = STATUS_NO_MEMORY;
  278. goto Cleanup;
  279. }
  280. if ( !QueryServiceConfig(
  281. ServiceHandle,
  282. ServiceConfig,
  283. ServiceConfigSize,
  284. &ServiceConfigSize )) {
  285. //NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceConfig "
  286. // "failed again: %lu\n", GetLastError()));
  287. Status = STATUS_NETLOGON_NOT_STARTED;
  288. goto Cleanup;
  289. }
  290. }
  291. if ( ServiceConfig->dwStartType != SERVICE_AUTO_START ) {
  292. // NlPrint((0, "[NETAPI32] NlWaitForNetlogon: Netlogon start type invalid:"
  293. // "%lu\n", ServiceConfig->dwStartType ));
  294. Status = STATUS_NETLOGON_NOT_STARTED;
  295. goto Cleanup;
  296. }
  297. //
  298. // Loop waiting for the netlogon service to start.
  299. // (Convert Timeout to a number of 10 second iterations)
  300. //
  301. Timeout = (Timeout+9)/10;
  302. for (;;) {
  303. //
  304. // Query the status of the Netlogon service.
  305. //
  306. if (! QueryServiceStatus( ServiceHandle, &ServiceStatus )) {
  307. // NlPrint((0, "[NETAPI32] NlWaitForNetlogon: QueryServiceStatus failed: "
  308. // "%lu\n", GetLastError() ));
  309. Status = STATUS_NETLOGON_NOT_STARTED;
  310. goto Cleanup;
  311. }
  312. //
  313. // Return or continue waiting depending on the state of
  314. // the netlogon service.
  315. //
  316. switch( ServiceStatus.dwCurrentState) {
  317. case SERVICE_RUNNING:
  318. Status = STATUS_SUCCESS;
  319. goto Cleanup;
  320. case SERVICE_STOPPED:
  321. //
  322. // If Netlogon failed to start,
  323. // error out now. The caller has waited long enough to start.
  324. //
  325. if ( ServiceStatus.dwWin32ExitCode != ERROR_SERVICE_NEVER_STARTED ){
  326. #if NETLOGONDBG
  327. // NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
  328. // "Netlogon service couldn't start: %lu %lx\n",
  329. // ServiceStatus.dwWin32ExitCode,
  330. // ServiceStatus.dwWin32ExitCode ));
  331. if ( ServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR ) {
  332. // NlPrint((0, " Service specific error code: %lu %lx\n",
  333. // ServiceStatus.dwServiceSpecificExitCode,
  334. // ServiceStatus.dwServiceSpecificExitCode ));
  335. }
  336. #endif // DBG
  337. Status = STATUS_NETLOGON_NOT_STARTED;
  338. goto Cleanup;
  339. }
  340. //
  341. // If Netlogon has never been started on this boot,
  342. // continue waiting for it to start.
  343. //
  344. break;
  345. //
  346. // If Netlogon is trying to start up now,
  347. // continue waiting for it to start.
  348. //
  349. case SERVICE_START_PENDING:
  350. break;
  351. //
  352. // Any other state is bogus.
  353. //
  354. default:
  355. // NlPrint((0, "[NETAPI32] NlWaitForNetlogon: "
  356. // "Invalid service state: %lu\n",
  357. // ServiceStatus.dwCurrentState ));
  358. Status = STATUS_NETLOGON_NOT_STARTED;
  359. goto Cleanup;
  360. }
  361. //
  362. // Wait ten seconds for the netlogon service to start.
  363. // If it has successfully started, just return now.
  364. //
  365. Status = NlWaitForEvent( L"\\NETLOGON_SERVICE_STARTED", 10 );
  366. if ( Status != STATUS_NETLOGON_NOT_STARTED ) {
  367. goto Cleanup;
  368. }
  369. //
  370. // If we've waited long enough for netlogon to start,
  371. // time out now.
  372. //
  373. if ( (--Timeout) == 0 ) {
  374. Status = STATUS_NETLOGON_NOT_STARTED;
  375. goto Cleanup;
  376. }
  377. }
  378. /* NOT REACHED */
  379. Cleanup:
  380. if ( ScManagerHandle != NULL ) {
  381. (VOID) CloseServiceHandle(ScManagerHandle);
  382. }
  383. if ( ServiceHandle != NULL ) {
  384. (VOID) CloseServiceHandle(ServiceHandle);
  385. }
  386. if ( AllocServiceConfig != NULL ) {
  387. LocalFree( AllocServiceConfig );
  388. }
  389. return Status;
  390. }