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.

568 lines
15 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. lsass.c
  5. Abstract:
  6. Local Security Authority Subsystem - Main Program.
  7. Author:
  8. Scott Birrell (ScottBi) Mar 12, 1991
  9. Environment:
  10. Revision History:
  11. --*/
  12. #include <lsapch2.h>
  13. #include "ntrpcp.h"
  14. #include "lmcons.h"
  15. #include "lmalert.h"
  16. #include "alertmsg.h"
  17. #include <samisrv.h>
  18. #include "safemode.h"
  19. /////////////////////////////////////////////////////////////////////////
  20. // //
  21. // Shared Global Variables //
  22. // //
  23. /////////////////////////////////////////////////////////////////////////
  24. #if DBG
  25. #ifdef _X86_
  26. extern DWORD_PTR __security_cookie; /* /GS security cookie */
  27. extern PVOID __safe_se_handler_table[]; /* base of safe handler entry table */
  28. extern BYTE __safe_se_handler_count; /* absolute symbol whose address is
  29. the count of table entries */
  30. #endif
  31. IMAGE_LOAD_CONFIG_DIRECTORY _load_config_used = {
  32. sizeof(_load_config_used), // Reserved
  33. 0, // Reserved
  34. 0, // Reserved
  35. 0, // Reserved
  36. 0, // GlobalFlagsClear
  37. 0, // GlobalFlagsSet
  38. 900000, // CriticalSectionTimeout (milliseconds)
  39. 0, // DeCommitFreeBlockThreshold
  40. 0, // DeCommitTotalFreeThreshold
  41. 0, // LockPrefixTable
  42. 0, 0, 0, 0, 0, 0, 0, // Reserved
  43. #ifdef _X86_
  44. (DWORD)&__security_cookie,
  45. (DWORD)__safe_se_handler_table,
  46. (DWORD)&__safe_se_handler_count
  47. #else
  48. 0, 0, 0
  49. #endif
  50. };
  51. #endif \\DBG
  52. /////////////////////////////////////////////////////////////////////////
  53. // //
  54. // Internal routine prototypes //
  55. // //
  56. /////////////////////////////////////////////////////////////////////////
  57. VOID
  58. LsapNotifyInitializationFinish(
  59. IN NTSTATUS CompletionStatus
  60. );
  61. /////////////////////////////////////////////////////////////////////////
  62. // //
  63. // Routines //
  64. // //
  65. /////////////////////////////////////////////////////////////////////////
  66. LONG
  67. WINAPI
  68. LsaTopLevelExceptionHandler(
  69. struct _EXCEPTION_POINTERS *ExceptionInfo
  70. )
  71. /*++
  72. Routine Description:
  73. The Top Level exception filter for lsass.exe.
  74. This ensures the entire process will be cleaned up if any of
  75. the threads fail. Since lsass.exe is a distributed application,
  76. it is better to fail the entire process than allow random threads
  77. to continue executing.
  78. Arguments:
  79. ExceptionInfo - Identifies the exception that occurred.
  80. Return Values:
  81. EXCEPTION_EXECUTE_HANDLER - Terminate the process.
  82. EXCEPTION_CONTINUE_SEARCH - Continue processing as though this filter
  83. was never called.
  84. --*/
  85. {
  86. return RtlUnhandledExceptionFilter(ExceptionInfo);
  87. }
  88. VOID __cdecl
  89. main ()
  90. {
  91. NTSTATUS Status = STATUS_SUCCESS;
  92. KPRIORITY BasePriority;
  93. BOOLEAN EnableAlignmentFaults = TRUE;
  94. LSADS_INIT_STATE LsaDsInitState;
  95. //
  96. // Define a top-level exception handler for the entire process.
  97. //
  98. SetErrorMode( SEM_FAILCRITICALERRORS );
  99. SetUnhandledExceptionFilter( &LsaTopLevelExceptionHandler );
  100. RtlSetProcessIsCritical(TRUE, NULL, TRUE);
  101. //
  102. // Run the LSA in the foreground.
  103. //
  104. // Several processes which depend on the LSA (like the lanman server)
  105. // run in the foreground. If we don't run in the foreground, they'll
  106. // starve waiting for us.
  107. //
  108. BasePriority = FOREGROUND_BASE_PRIORITY;
  109. Status = NtSetInformationProcess(
  110. NtCurrentProcess(),
  111. ProcessBasePriority,
  112. &BasePriority,
  113. sizeof(BasePriority)
  114. );
  115. if ( !NT_SUCCESS(Status) ) {
  116. goto Cleanup;
  117. }
  118. //
  119. // Do the following:
  120. //
  121. //
  122. // Check the boot environment
  123. // If this is a DC booted into safe mode, set the appropriate
  124. // flag so LsaISafeBoot returns TRUE.
  125. //
  126. // Initialize the service-controller service
  127. // dispatcher.
  128. //
  129. // Initialize LSA Pass-1
  130. // This starts the RPC server.
  131. // Does not do product type-specific initialization.
  132. //
  133. // Pause for installation if necessary
  134. // Allows product type-specific information to be
  135. // collected.
  136. //
  137. // Initialize LSA Pass-2
  138. // Product type-specific initialization.
  139. //
  140. // Initialize SAM
  141. //
  142. //
  143. // Analyse the boot environment
  144. //
  145. Status = LsapCheckBootMode();
  146. if (!NT_SUCCESS(Status)) {
  147. goto Cleanup;
  148. }
  149. //
  150. // Initialize the service dispatcher.
  151. //
  152. // We initialize the service dispatcher before the sam
  153. // service is started. This will make the service controller
  154. // start successfully even if SAM takes a long time to initialize.
  155. //
  156. Status = ServiceInit();
  157. if (!NT_SUCCESS(Status) ) {
  158. goto Cleanup;
  159. }
  160. //
  161. // Initialize the LSA.
  162. // If unsuccessful, we must exit with status so that the SM knows
  163. // something has gone wrong.
  164. //
  165. Status = LsapInitLsa();
  166. if (!NT_SUCCESS(Status)) {
  167. goto Cleanup;
  168. }
  169. //
  170. // Initialize SAM
  171. //
  172. Status = SamIInitialize();
  173. if (!NT_SUCCESS(Status) ) {
  174. goto Cleanup;
  175. }
  176. //
  177. // Do the second phase of the dc promote/demote API initialization
  178. //
  179. Status = LsapDsInitializePromoteInterface();
  180. if (!NT_SUCCESS(Status) ) {
  181. goto Cleanup;
  182. }
  183. //
  184. // Open a Trusted Handle to the local SAM server.
  185. //
  186. Status = LsapAuOpenSam( TRUE );
  187. if (!NT_SUCCESS(Status) ) {
  188. goto Cleanup;
  189. }
  190. //
  191. // Handle the LsaDs initialization
  192. //
  193. if ( NT_SUCCESS( Status ) ) {
  194. if ( SampUsingDsData() ) {
  195. LsaDsInitState = LsapDsDs;
  196. } else {
  197. LsaDsInitState = LsapDsNoDs;
  198. }
  199. Status = LsapDsInitializeDsStateInfo( LsaDsInitState );
  200. if ( !NT_SUCCESS( Status ) ) {
  201. goto Cleanup;
  202. }
  203. }
  204. Cleanup:
  205. LsapNotifyInitializationFinish(Status);
  206. ExitThread( Status );
  207. }
  208. VOID
  209. LsapNotifyInitializationFinish(
  210. IN NTSTATUS CompletionStatus
  211. )
  212. /*++
  213. Routine Description:
  214. This function handles the notification of successful or
  215. unsuccessful completion of initialization of the Security Process
  216. lsass.exe. If initialization was unsuccessful, a popup appears. If
  217. setup was run, one of two events is set. The SAM_SERVICE_STARTED event
  218. is set if LSA and SAM started OK and the SETUP_FAILED event is set if LSA
  219. or SAM server setup failed. Setup waits multiple on this object pair so
  220. that it can detect either event being set and notify the user if necessary
  221. that setup failed.
  222. Arguments:
  223. CompletionStatus - Contains a standard Nt Result Code specifying
  224. the success or otherwise of the initialization/installation.
  225. Return Values:
  226. None.
  227. --*/
  228. {
  229. NTSTATUS Status = STATUS_SUCCESS;
  230. ULONG Response;
  231. UNICODE_STRING EventName;
  232. OBJECT_ATTRIBUTES EventAttributes;
  233. HANDLE EventHandle = NULL;
  234. if (NT_SUCCESS(CompletionStatus)) {
  235. //
  236. // Set an event telling anyone wanting to call SAM that we're initialized.
  237. //
  238. RtlInitUnicodeString( &EventName, L"\\SAM_SERVICE_STARTED");
  239. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  240. Status = NtCreateEvent(
  241. &EventHandle,
  242. SYNCHRONIZE|EVENT_MODIFY_STATE,
  243. &EventAttributes,
  244. NotificationEvent,
  245. FALSE // The event is initially not signaled
  246. );
  247. if ( !NT_SUCCESS(Status)) {
  248. //
  249. // If the event already exists, a waiting thread beat us to
  250. // creating it. Just open it.
  251. //
  252. if( Status == STATUS_OBJECT_NAME_EXISTS ||
  253. Status == STATUS_OBJECT_NAME_COLLISION ) {
  254. Status = NtOpenEvent(
  255. &EventHandle,
  256. SYNCHRONIZE|EVENT_MODIFY_STATE,
  257. &EventAttributes
  258. );
  259. }
  260. if ( !NT_SUCCESS(Status)) {
  261. KdPrint(("SAMSS: Failed to open SAM_SERVICE_STARTED event. %lX\n",
  262. Status ));
  263. KdPrint((" Failing to initialize SAM Server.\n"));
  264. goto InitializationFinishError;
  265. }
  266. }
  267. //
  268. // Set the SAM_SERVICE_STARTED event. Except when an error occurs,
  269. // don't close the event. Closing it would delete the event and
  270. // a future waiter would never see it be set.
  271. //
  272. Status = NtSetEvent( EventHandle, NULL );
  273. if ( !NT_SUCCESS(Status)) {
  274. KdPrint(("SAMSS: Failed to set SAM_SERVICE_STARTED event. %lX\n",
  275. Status ));
  276. KdPrint((" Failing to initialize SAM Server.\n"));
  277. NtClose(EventHandle);
  278. goto InitializationFinishError;
  279. }
  280. } else {
  281. //
  282. // The initialization/installation of Lsa and/or SAM failed. Handle errors returned
  283. // from the initialization/installation of LSA or SAM. Issue a popup
  284. // and, if installing, set an event so that setup will continue and
  285. // clean up.
  286. //
  287. ULONG_PTR Parameters[1];
  288. //
  289. // don't reboot unless LSA was running as SYSTEM.
  290. // this prevents a user who runs lsass.exe from causing an instant reboot.
  291. //
  292. if(ImpersonateSelf( SecurityImpersonation ))
  293. {
  294. HANDLE hThreadToken;
  295. if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hThreadToken))
  296. {
  297. BOOL DoShutdown = TRUE;
  298. BOOL fIsMember;
  299. PSID psidSystem = NULL;
  300. SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
  301. if(AllocateAndInitializeSid(
  302. &sia,
  303. 1,
  304. SECURITY_LOCAL_SYSTEM_RID,
  305. 0,0,0,0,0,0,0,
  306. &psidSystem
  307. ))
  308. {
  309. if(CheckTokenMembership(hThreadToken, psidSystem, &fIsMember))
  310. {
  311. DoShutdown = fIsMember;
  312. }
  313. if( psidSystem != NULL )
  314. {
  315. FreeSid( psidSystem );
  316. }
  317. }
  318. CloseHandle( hThreadToken );
  319. RevertToSelf();
  320. if( !DoShutdown )
  321. {
  322. goto InitializationFinishFinish;
  323. }
  324. } else {
  325. RevertToSelf();
  326. }
  327. }
  328. Parameters[0] = MB_OK | MB_ICONSTOP | MB_SETFOREGROUND;
  329. Status = NtRaiseHardError(
  330. CompletionStatus | HARDERROR_OVERRIDE_ERRORMODE,
  331. 1,
  332. 0,
  333. Parameters,
  334. OptionOk,
  335. &Response
  336. );
  337. //
  338. // If setup.exe was run, signal the SETUP_FAILED event. setup.exe
  339. // waits multiple on the SAM_SERVICE_STARTED and SETUP_FAILED events
  340. // so setup will resume and cleanup/continue as appropriate if
  341. // either of these events are set.
  342. //
  343. if (LsaISetupWasRun()) {
  344. //
  345. // Once the user has clicked OK in response to the popup, we come
  346. // back to here. Set the event SETUP_FAILED. The Setup
  347. // program (if running) waits multiple on the SAM_SERVICE_STARTED
  348. // and SETUP_FAILED events.
  349. //
  350. RtlInitUnicodeString( &EventName, L"\\SETUP_FAILED");
  351. InitializeObjectAttributes( &EventAttributes, &EventName, 0, 0, NULL );
  352. //
  353. // Open the SETUP_FAILED event (exists if setup.exe is running).
  354. //
  355. Status = NtOpenEvent(
  356. &EventHandle,
  357. SYNCHRONIZE|EVENT_MODIFY_STATE,
  358. &EventAttributes
  359. );
  360. if ( !NT_SUCCESS(Status)) {
  361. //
  362. // Something is inconsistent. We know that setup was run
  363. // so the event should exist.
  364. //
  365. KdPrint(("LSA Server: Failed to open SETUP_FAILED event. %lX\n",
  366. Status ));
  367. KdPrint((" Failing to initialize Lsa Server.\n"));
  368. goto InitializationFinishError;
  369. }
  370. Status = NtSetEvent( EventHandle, NULL );
  371. } else if ( NT_SUCCESS( Status )) {
  372. //
  373. // This is not setup, so the only option is to shut down the system
  374. //
  375. BOOLEAN WasEnabled;
  376. //
  377. // issue shutdown request
  378. //
  379. RtlAdjustPrivilege(
  380. SE_SHUTDOWN_PRIVILEGE,
  381. TRUE, // enable shutdown privilege.
  382. FALSE,
  383. &WasEnabled
  384. );
  385. //
  386. // Shutdown and Reboot now.
  387. // Note: use NtRaiseHardError to shutdown the machine will result Bug C
  388. //
  389. NtShutdownSystem( ShutdownReboot );
  390. //
  391. // if Shutdown request failed, (returned from above API)
  392. // reset shutdown privilege to previous value.
  393. //
  394. RtlAdjustPrivilege(
  395. SE_SHUTDOWN_PRIVILEGE,
  396. WasEnabled, // reset to previous state.
  397. FALSE,
  398. &WasEnabled
  399. );
  400. }
  401. }
  402. if (!NT_SUCCESS(Status)) {
  403. goto InitializationFinishError;
  404. }
  405. InitializationFinishFinish:
  406. return;
  407. InitializationFinishError:
  408. goto InitializationFinishFinish;
  409. }