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.

801 lines
18 KiB

  1. /*++
  2. Copyright (c) 1987-1996 Microsoft Corporation
  3. Module Name:
  4. error.c
  5. Abstract:
  6. Error routines for Netlogon service
  7. Author:
  8. Ported from Lan Man 2.0
  9. Environment:
  10. User mode only.
  11. Contains NT-specific code.
  12. Requires ANSI C extensions: slash-slash comments, long external names.
  13. Revision History:
  14. 29-May-1991 (cliffv)
  15. Ported to NT. Converted to NT style.
  16. --*/
  17. //
  18. // Common include files.
  19. //
  20. #include "logonsrv.h" // Include files common to entire service
  21. #pragma hdrstop
  22. //
  23. // Include files specific to this .c file
  24. //
  25. #include <lmalert.h> // LAN Manager alert routines
  26. #include <Secobj.h> // need for NetpDeleteSecurityObject
  27. NET_API_STATUS
  28. NlCleanup(
  29. VOID
  30. )
  31. /*++
  32. Routine Description:
  33. Cleanup all global resources.
  34. Arguments:
  35. None.
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. NTSTATUS Status;
  41. NET_API_STATUS NetStatus;
  42. PLIST_ENTRY ListEntry;
  43. DWORD i;
  44. BOOLEAN WaitForMsv;
  45. //
  46. // Let the ChangeLog routines know that Netlogon is not started.
  47. //
  48. NlGlobalChangeLogNetlogonState = NetlogonStopped;
  49. //
  50. // Let everybody know we are to terminate
  51. //
  52. NlGlobalTerminate = TRUE;
  53. //
  54. // Indicate to external waiters that we're not running.
  55. //
  56. if ( NlGlobalStartedEvent != NULL ) {
  57. //
  58. // Reset it first in case some other process is preventing its deletion.
  59. //
  60. (VOID) ResetEvent( NlGlobalStartedEvent );
  61. (VOID) CloseHandle( NlGlobalStartedEvent );
  62. NlGlobalStartedEvent = NULL;
  63. }
  64. //
  65. // Stop the RPC server (Wait for outstanding calls to complete)
  66. //
  67. if ( NlGlobalRpcServerStarted ) {
  68. Status = RpcServerUnregisterIf ( logon_ServerIfHandle, 0, TRUE );
  69. NlAssert( Status == RPC_S_OK );
  70. NlGlobalRpcServerStarted = FALSE;
  71. }
  72. //
  73. // Tell all the MSV threads to leave netlogon.dll.
  74. //
  75. EnterCriticalSection( &NlGlobalMsvCritSect );
  76. if ( NlGlobalMsvEnabled ) {
  77. NlGlobalMsvEnabled = FALSE;
  78. WaitForMsv = (NlGlobalMsvThreadCount > 0 );
  79. } else {
  80. WaitForMsv = FALSE;
  81. }
  82. LeaveCriticalSection( &NlGlobalMsvCritSect );
  83. //
  84. // Wait for the MSV threads to leave netlogon.dll
  85. //
  86. if ( NlGlobalMsvTerminateEvent != NULL ) {
  87. if ( WaitForMsv ) {
  88. WaitForSingleObject( NlGlobalMsvTerminateEvent, INFINITE );
  89. }
  90. (VOID) CloseHandle( NlGlobalMsvTerminateEvent );
  91. NlGlobalMsvTerminateEvent = NULL;
  92. }
  93. //
  94. // Shut down the worker threads.
  95. //
  96. NlWorkerTermination();
  97. //
  98. // Clean up hosted domains.
  99. //
  100. NlUninitializeDomains();
  101. NlAssert( IsListEmpty( &NlGlobalBdcServerSessionList ) );
  102. NlAssert( IsListEmpty( &NlGlobalPendingBdcList ) );
  103. //
  104. // Close the browser
  105. //
  106. NlBrowserClose();
  107. //
  108. // Free the transport list
  109. //
  110. NlTransportClose();
  111. DeleteCriticalSection( &NlGlobalTransportCritSect );
  112. //
  113. // Free the DNS name list
  114. //
  115. NlDnsShutdown();
  116. DeleteCriticalSection( &NlGlobalDnsCritSect );
  117. //
  118. // Free the DNS tree name.
  119. //
  120. NlSetDnsForestName( NULL, NULL );
  121. //
  122. // Free the DNS tree name alias
  123. //
  124. EnterCriticalSection( &NlGlobalDnsForestNameCritSect );
  125. if ( NlGlobalUtf8DnsForestNameAlias != NULL ) {
  126. NetpMemoryFree( NlGlobalUtf8DnsForestNameAlias );
  127. NlGlobalUtf8DnsForestNameAlias = NULL;
  128. }
  129. LeaveCriticalSection( &NlGlobalDnsForestNameCritSect );
  130. DeleteCriticalSection( &NlGlobalDnsForestNameCritSect );
  131. //
  132. // Free the Site list
  133. //
  134. NlSiteTerminate();
  135. NlParseFree( &NlGlobalParameters );
  136. //
  137. // Free the list of outstanding challenges
  138. //
  139. NlRemoveChallengeForClient( NULL, NULL, FALSE );
  140. NlAssert( IsListEmpty( &NlGlobalChallengeList ) );
  141. NlAssert( NlGlobalChallengeCount == 0 );
  142. DeleteCriticalSection( &NlGlobalChallengeCritSect );
  143. //
  144. // Free the Trusted Domain List
  145. //
  146. EnterCriticalSection( &NlGlobalDcDiscoveryCritSect );
  147. if ( NlGlobalTrustedDomainList != NULL ) {
  148. NetpMemoryFree( NlGlobalTrustedDomainList );
  149. NlGlobalTrustedDomainList = NULL;
  150. NlGlobalTrustedDomainCount = 0;
  151. NlGlobalTrustedDomainListTime.QuadPart = 0;
  152. }
  153. LeaveCriticalSection( &NlGlobalDcDiscoveryCritSect );
  154. DeleteCriticalSection( &NlGlobalDcDiscoveryCritSect );
  155. //
  156. // Delete any notifications we didn't get to.
  157. //
  158. LOCK_CHANGELOG();
  159. while ( !IsListEmpty( &NlGlobalChangeLogNotifications ) ) {
  160. PCHANGELOG_NOTIFICATION Notification;
  161. ListEntry = RemoveHeadList( &NlGlobalChangeLogNotifications );
  162. Notification = CONTAINING_RECORD( ListEntry, CHANGELOG_NOTIFICATION, Next );
  163. NetpMemoryFree( Notification );
  164. }
  165. UNLOCK_CHANGELOG();
  166. //
  167. // Free up resources
  168. //
  169. if ( NlGlobalNetlogonSecurityDescriptor != NULL ) {
  170. NetpDeleteSecurityObject( &NlGlobalNetlogonSecurityDescriptor );
  171. NlGlobalNetlogonSecurityDescriptor = NULL;
  172. }
  173. if ( NlGlobalUnicodeComputerName != NULL ) {
  174. NetApiBufferFree( NlGlobalUnicodeComputerName );
  175. NlGlobalUnicodeComputerName = NULL;
  176. }
  177. //
  178. // delete well known SIDs if they are allocated already.
  179. //
  180. NetpFreeWellKnownSids();
  181. //
  182. // Clean up the scavenger crit sect
  183. //
  184. DeleteCriticalSection( &NlGlobalScavengerCritSect );
  185. //
  186. // Clean up the replicator crit sect
  187. //
  188. DeleteCriticalSection( &NlGlobalReplicatorCritSect );
  189. //
  190. // Delete the timer event
  191. //
  192. if ( NlGlobalTimerEvent != NULL ) {
  193. (VOID) CloseHandle( NlGlobalTimerEvent );
  194. NlGlobalTimerEvent = NULL;
  195. }
  196. //
  197. // Cleanup Winsock.
  198. //
  199. if ( NlGlobalWinSockInitialized ) {
  200. WSACleanup();
  201. }
  202. //
  203. // Unregister WMI trace Guids
  204. //
  205. if ( NlpTraceRegistrationHandle != (TRACEHANDLE)0 ) {
  206. UnregisterTraceGuids( NlpTraceRegistrationHandle );
  207. NlpEventTraceFlag = FALSE;
  208. NlpTraceRegistrationHandle = (TRACEHANDLE) 0;
  209. NlpTraceLoggerHandle = (TRACEHANDLE) 0;
  210. }
  211. //
  212. // Free the Authz resource manager
  213. //
  214. NlFreeAuthzRm();
  215. //
  216. // Free the list of events that have already been logged.
  217. //
  218. NetpEventlogSetTimeout ( NlGlobalEventlogHandle, 0 ); // Set timeout back to zero seconds
  219. NetpEventlogClearList ( NlGlobalEventlogHandle );
  220. //
  221. // Unload ntdsa.dll
  222. //
  223. if ( NlGlobalNtDsaHandle != NULL ) {
  224. FreeLibrary( NlGlobalNtDsaHandle );
  225. NlGlobalNtDsaHandle = NULL;
  226. }
  227. if ( NlGlobalIsmDllHandle != NULL ) {
  228. FreeLibrary( NlGlobalIsmDllHandle );
  229. NlGlobalIsmDllHandle = NULL;
  230. }
  231. if ( NlGlobalDsApiDllHandle != NULL ) {
  232. FreeLibrary( NlGlobalDsApiDllHandle );
  233. NlGlobalDsApiDllHandle = NULL;
  234. }
  235. //
  236. // Unload the DLL if requested.
  237. //
  238. if ( NlGlobalUnloadNetlogon ) {
  239. NetStatus = NlpFreeNetlogonDllHandles();
  240. NlPrint((NL_MISC, "Netlogon.dll unloaded (%ld).\n", NetStatus ));
  241. }
  242. //
  243. // Delete the Event used to ask Netlogon to exit.
  244. //
  245. if( !CloseHandle( NlGlobalTerminateEvent ) ) {
  246. NlPrint((NL_CRITICAL,
  247. "CloseHandle NlGlobalTerminateEvent error: %lu\n",
  248. GetLastError() ));
  249. }
  250. //
  251. // Remove the wait routine for the DS paused event
  252. //
  253. if ( NlGlobalDsPausedWaitHandle != NULL ) {
  254. UnregisterWaitEx( NlGlobalDsPausedWaitHandle,
  255. INVALID_HANDLE_VALUE ); // Wait until routine finishes execution
  256. NlGlobalDsPausedWaitHandle = NULL;
  257. }
  258. //
  259. // Free the event used to see if the DS is paused.
  260. //
  261. if ( NlGlobalDsPausedEvent != NULL ) {
  262. CloseHandle( NlGlobalDsPausedEvent );
  263. NlGlobalDsPausedEvent = NULL;
  264. }
  265. //
  266. // free cryptographic service provider.
  267. //
  268. if ( NlGlobalCryptProvider ) {
  269. CryptReleaseContext( NlGlobalCryptProvider, 0 );
  270. NlGlobalCryptProvider = (HCRYPTPROV)NULL;
  271. }
  272. //
  273. // Close the handle to the debug file.
  274. //
  275. #if NETLOGONDBG
  276. EnterCriticalSection( &NlGlobalLogFileCritSect );
  277. if ( NlGlobalLogFile != INVALID_HANDLE_VALUE ) {
  278. CloseHandle( NlGlobalLogFile );
  279. NlGlobalLogFile = INVALID_HANDLE_VALUE;
  280. }
  281. if ( NlGlobalLogFileOutputBuffer != NULL ) {
  282. LocalFree( NlGlobalLogFileOutputBuffer );
  283. NlGlobalLogFileOutputBuffer = NULL;
  284. }
  285. LeaveCriticalSection( &NlGlobalLogFileCritSect );
  286. if( NlGlobalDebugSharePath != NULL ) {
  287. NetpMemoryFree( NlGlobalDebugSharePath );
  288. NlGlobalDebugSharePath = NULL;
  289. }
  290. #endif // NETLOGONDBG
  291. //
  292. // Clean up the global parameters crit sect
  293. //
  294. DeleteCriticalSection( &NlGlobalParametersCritSect );
  295. //
  296. // Set the service state to uninstalled, and tell the service controller.
  297. // Do this as the last step to prevent the service controller from
  298. // starting netlogon while we are in the middle of shutdown.
  299. //
  300. NlGlobalServiceStatus.dwCurrentState = SERVICE_STOPPED;
  301. NlGlobalServiceStatus.dwCheckPoint = 0;
  302. NlGlobalServiceStatus.dwWaitHint = 0;
  303. #ifdef _DC_NETLOGON
  304. if( !SetServiceStatus( NlGlobalServiceHandle,
  305. &NlGlobalServiceStatus ) ) {
  306. IF_NL_DEBUG( CRITICAL ) {
  307. NetpKdPrint(( "[NETLOGON] NlCleanup: SetServiceStatus failed: %lu\n",
  308. GetLastError() ));
  309. }
  310. }
  311. #endif // _DC_NETLOGON
  312. //
  313. // Return an exit status to our caller.
  314. //
  315. return (NET_API_STATUS)
  316. ((NlGlobalServiceStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR) ?
  317. NlGlobalServiceStatus.dwServiceSpecificExitCode :
  318. NlGlobalServiceStatus.dwWin32ExitCode);
  319. }
  320. VOID
  321. NlExit(
  322. IN DWORD ServiceError,
  323. IN NET_API_STATUS Data,
  324. IN NL_EXIT_CODE ExitCode,
  325. IN LPWSTR ErrorString
  326. )
  327. /*++
  328. Routine Description:
  329. Registers service as uninstalled with error code.
  330. Arguments:
  331. ServiceError - Service specific error code
  332. Data - a DWORD of data to be logged with the message.
  333. No data is logged if this is zero.
  334. ExitCode - Indicates whether the message should be logged to the eventlog
  335. and whether Data is a status code that should be appended to the bottom
  336. of the message:
  337. ErrorString - Error string, used to print it on debugger.
  338. Return Value:
  339. None.
  340. --*/
  341. {
  342. IF_NL_DEBUG( MISC ) {
  343. NlPrint((NL_MISC, "NlExit: Netlogon exiting %lu 0x%lx",
  344. ServiceError,
  345. ServiceError ));
  346. if ( Data ) {
  347. NlPrint((NL_MISC, " Data: %lu 0x%lx", Data, Data ));
  348. }
  349. if( ErrorString != NULL ) {
  350. NlPrint((NL_MISC, " '%ws'", ErrorString ));
  351. }
  352. NlPrint(( NL_MISC, "\n"));
  353. }
  354. //
  355. // Record our exit in the event log.
  356. //
  357. if ( ExitCode != DontLogError ) {
  358. LPWSTR MsgStrings[2];
  359. ULONG MessageCount = 0;
  360. if ( ErrorString != NULL ) {
  361. MsgStrings[MessageCount] = ErrorString;
  362. MessageCount ++;
  363. }
  364. if ( ExitCode == LogErrorAndNtStatus ) {
  365. MsgStrings[MessageCount] = (LPWSTR) ULongToPtr( Data );
  366. MessageCount ++;
  367. MessageCount |= NETP_LAST_MESSAGE_IS_NTSTATUS;
  368. } else if ( ExitCode == LogErrorAndNetStatus ) {
  369. MsgStrings[MessageCount] = (LPWSTR) ULongToPtr( Data );
  370. MessageCount ++;
  371. MessageCount |= NETP_LAST_MESSAGE_IS_NETSTATUS;
  372. }
  373. NlpWriteEventlog( ServiceError,
  374. EVENTLOG_ERROR_TYPE,
  375. (Data) ? (LPBYTE) &Data : NULL,
  376. (Data) ? sizeof(Data) : 0,
  377. (MessageCount != 0) ? MsgStrings : NULL,
  378. MessageCount );
  379. }
  380. //
  381. // Set the service state to stop pending.
  382. //
  383. NlGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  384. NlGlobalServiceStatus.dwWaitHint = NETLOGON_INSTALL_WAIT;
  385. NlGlobalServiceStatus.dwCheckPoint = 1;
  386. SET_SERVICE_EXITCODE(
  387. Data,
  388. NlGlobalServiceStatus.dwWin32ExitCode,
  389. NlGlobalServiceStatus.dwServiceSpecificExitCode
  390. );
  391. #ifdef _DC_NETLOGON
  392. //
  393. // Tell the service controller what our state is.
  394. //
  395. if( !SetServiceStatus( NlGlobalServiceHandle,
  396. &NlGlobalServiceStatus ) ) {
  397. NlPrint((NL_CRITICAL, "SetServiceStatus error: %lu\n",
  398. GetLastError() ));
  399. }
  400. #endif // _DC_NETLOGON
  401. //
  402. // Indicate that all threads should exit.
  403. //
  404. NlGlobalTerminate = TRUE;
  405. if ( !SetEvent( NlGlobalTerminateEvent ) ) {
  406. NlPrint((NL_CRITICAL, "Cannot set termination event: %lu\n",
  407. GetLastError() ));
  408. }
  409. }
  410. BOOL
  411. GiveInstallHints(
  412. IN BOOL Started
  413. )
  414. /*++
  415. Routine Description:
  416. Give hints to the installer of the service that installation is progressing.
  417. Arguments:
  418. Started -- Set true to tell the service controller that we're done starting.
  419. Return Value:
  420. TRUE -- iff install hint was accepted.
  421. --*/
  422. {
  423. static DWORD LastHintTime = 0;
  424. //
  425. // Previous incarnations of this routine attempted to return FALSE if
  426. // NlGlobalTerminate was set. That's bogus. There's no way to
  427. // differentiate whether the caller is trying to start the netlogon service
  428. // (and we should return FALSE) or whether the caller is trying to
  429. // stop the netlogon service (and we should give a shutdown hint).
  430. //
  431. //
  432. // Don't do anything unless we're currently starting or stopping.
  433. //
  434. if ( NlGlobalServiceStatus.dwCurrentState != SERVICE_START_PENDING &&
  435. NlGlobalServiceStatus.dwCurrentState != SERVICE_STOP_PENDING ) {
  436. return TRUE;
  437. }
  438. //
  439. // Tell the service controller our current state.
  440. //
  441. if ( Started ) {
  442. if ( NlGlobalServiceStatus.dwCurrentState != SERVICE_START_PENDING ) {
  443. NlPrint((NL_CRITICAL,
  444. "Tried to set a STOP_PENDING service to RUNNING\n" ));
  445. NlExit( NELOG_NetlogonSystemError, GetLastError(), LogErrorAndNetStatus, NULL);
  446. return FALSE;
  447. }
  448. NlGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
  449. NlGlobalServiceStatus.dwCheckPoint = 0;
  450. NlGlobalServiceStatus.dwWaitHint = 0;
  451. } else {
  452. //
  453. // If it has been less than 1 second since the last time we gave a hint,
  454. // avoid giving a superfluous hint.
  455. //
  456. if ( NetpDcElapsedTime( LastHintTime ) < 1000 ) {
  457. NlPrint((NL_SITE_MORE, "Hint avoided. %ld\n", NetpDcElapsedTime( LastHintTime ) ));
  458. return TRUE;
  459. }
  460. LastHintTime = GetTickCount();
  461. NlGlobalServiceStatus.dwCheckPoint++;
  462. }
  463. if( !SetServiceStatus( NlGlobalServiceHandle, &NlGlobalServiceStatus ) ) {
  464. NlExit( NELOG_NetlogonSystemError, GetLastError(), LogErrorAndNetStatus, NULL);
  465. return FALSE;
  466. }
  467. return TRUE;
  468. }
  469. VOID
  470. NlControlHandler(
  471. IN DWORD opcode
  472. )
  473. /*++
  474. Routine Description:
  475. Process and respond to a control signal from the service controller.
  476. Arguments:
  477. opcode - Supplies a value which specifies the action for the Netlogon
  478. service to perform.
  479. Return Value:
  480. None.
  481. --*/
  482. {
  483. NlPrint((NL_MISC, "In control handler (Opcode: %ld)\n", opcode ));
  484. //
  485. // Handle an uninstall request.
  486. //
  487. switch (opcode) {
  488. case SERVICE_CONTROL_STOP: /* Uninstall required */
  489. //
  490. // Request the service to exit.
  491. //
  492. // NlExit also sets the service status to UNINSTALL_PENDING
  493. // and tells the service controller.
  494. //
  495. NlExit( NERR_Success, NO_ERROR, DontLogError, NULL);
  496. return;
  497. //
  498. // Pause the service.
  499. //
  500. case SERVICE_CONTROL_PAUSE:
  501. NlGlobalServiceStatus.dwCurrentState = SERVICE_PAUSED;
  502. break;
  503. //
  504. // Continute the service.
  505. //
  506. case SERVICE_CONTROL_CONTINUE:
  507. NlGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
  508. break;
  509. //
  510. // Dns changes
  511. //
  512. case SERVICE_CONTROL_DNS_SERVER_START: // Dns telling us that the DNS server has started on this machine
  513. (VOID) NlSendChangeLogNotification( ChangeDnsNames,
  514. NULL,
  515. NULL,
  516. 1, // Force names to re-register
  517. NULL, // Object GUID,
  518. NULL, // Domain GUID,
  519. NULL ); // Domain Name
  520. break;
  521. //
  522. // By default, just return the current status.
  523. //
  524. case SERVICE_CONTROL_INTERROGATE:
  525. default:
  526. break;
  527. }
  528. //
  529. // Always respond with the current status.
  530. //
  531. if( !SetServiceStatus( NlGlobalServiceHandle,
  532. &NlGlobalServiceStatus ) ) {
  533. NlPrint((NL_CRITICAL, "SetServiceStatus error: %lu\n",
  534. GetLastError() ));
  535. }
  536. return;
  537. }
  538. #ifdef notdef
  539. BOOL
  540. NlMessageBox(
  541. IN LPSTR MessageText,
  542. IN LPSTR Caption,
  543. UINT Type
  544. )
  545. /*++
  546. Routine Description:
  547. Raise a hard error popup.
  548. Arguments:
  549. MessageText - Message to display in the popup.
  550. Caption - Caption for the message box.
  551. Type - Type of message. MB_SERVICE_NOTIFICATION is implied. Other flags are as defined
  552. for the MessageBox API.
  553. Return Value:
  554. TRUE - Box was displayed successfully.
  555. FALSE - Box could not be displayed for some reason.
  556. --*/
  557. {
  558. int Status;
  559. Status = MessageBoxA( NULL,
  560. MessageText,
  561. Caption,
  562. MB_SERVICE_NOTIFICATION | Type );
  563. return ( Status == IDOK );
  564. }
  565. #endif // notdef