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.

7103 lines
220 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. sminit.c
  5. Abstract:
  6. Session Manager Initialization
  7. Author:
  8. Mark Lucovsky (markl) 04-Oct-1989
  9. Revision History:
  10. --*/
  11. #include "smsrvp.h"
  12. #include "pagefile.h"
  13. #include <stdio.h>
  14. #include <string.h>
  15. #include <safeboot.h>
  16. #include <wow64t.h>
  17. #if defined(REMOTE_BOOT)
  18. #include <windows.h>
  19. #ifdef DeleteFile
  20. #undef DeleteFile
  21. #endif
  22. #include <shdcom.h> // CSC definitions
  23. #endif // defined(REMOTE_BOOT)
  24. #include "sfcfiles.h"
  25. void
  26. SmpDisplayString( char *s );
  27. //
  28. // Protection mode flags
  29. //
  30. #define SMP_NO_PROTECTION (0x0)
  31. #define SMP_STANDARD_PROTECTION (0x1)
  32. #define SMP_PROTECTION_REQUIRED (SMP_STANDARD_PROTECTION)
  33. #define REMOTE_BOOT_CFG_FILE L"RemoteBoot.cfg"
  34. //
  35. // Shows where was SmpInit execution when it returned
  36. // with an error code. This aids debugging smss crashes a lot.
  37. //
  38. ULONG SmpInitProgressByLine;
  39. NTSTATUS SmpInitReturnStatus;
  40. PVOID SmpInitLastCall;
  41. #define SAVE_SMPINIT_STATUS(caller, status) { \
  42. \
  43. SmpInitProgressByLine = __LINE__; \
  44. SmpInitReturnStatus = (status); \
  45. SmpInitLastCall = (PVOID)(caller); \
  46. }
  47. PSECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor;
  48. SECURITY_DESCRIPTOR SmpPrimarySDBody;
  49. PSECURITY_DESCRIPTOR SmpLiberalSecurityDescriptor;
  50. SECURITY_DESCRIPTOR SmpLiberalSDBody;
  51. PSECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor;
  52. SECURITY_DESCRIPTOR SmpKnownDllsSDBody;
  53. PSECURITY_DESCRIPTOR SmpApiPortSecurityDescriptor;
  54. SECURITY_DESCRIPTOR SmpApiPortSDBody;
  55. ULONG SmpProtectionMode = SMP_STANDARD_PROTECTION;
  56. UCHAR TmpBuffer[ 1024 + 2 * DOS_MAX_PATH_LENGTH * sizeof(WCHAR)];
  57. ULONG AttachedSessionId = (-1);
  58. #if defined(REMOTE_BOOT)
  59. WCHAR wszRemoteBootCfgFile[DOS_MAX_PATH_LENGTH];
  60. #endif // defined(REMOTE_BOOT)
  61. #if DBG
  62. BOOLEAN SmpEnableDots = FALSE;
  63. #else
  64. BOOLEAN SmpEnableDots = TRUE;
  65. #endif
  66. WCHAR InitialCommandBuffer[ 256 ];
  67. UNICODE_STRING SmpDebugKeyword;
  68. UNICODE_STRING SmpASyncKeyword;
  69. UNICODE_STRING SmpAutoChkKeyword;
  70. #if defined(REMOTE_BOOT)
  71. UNICODE_STRING SmpAutoFmtKeyword;
  72. #endif // defined(REMOTE_BOOT)
  73. UNICODE_STRING SmpKnownDllPath;
  74. #ifdef _WIN64
  75. UNICODE_STRING SmpKnownDllPath32;
  76. #endif
  77. HANDLE SmpWindowsSubSysProcess;
  78. ULONG_PTR SmpWindowsSubSysProcessId;
  79. ULONG_PTR SmpInitialCommandProcessId;
  80. UNICODE_STRING PosixName;
  81. UNICODE_STRING Os2Name;
  82. BOOLEAN RegPosixSingleInstance; // Make Softway Work.
  83. ULONG SmpAllowProtectedRenames;
  84. BOOLEAN MiniNTBoot = FALSE;
  85. ULONG SmpCalledConfigEnv = 0;
  86. LIST_ENTRY SmpBootExecuteList;
  87. LIST_ENTRY SmpSetupExecuteList;
  88. LIST_ENTRY SmpPagingFileList;
  89. LIST_ENTRY SmpDosDevicesList;
  90. LIST_ENTRY SmpFileRenameList;
  91. LIST_ENTRY SmpKnownDllsList;
  92. LIST_ENTRY SmpExcludeKnownDllsList;
  93. LIST_ENTRY SmpSubSystemList;
  94. LIST_ENTRY SmpSubSystemsToLoad;
  95. LIST_ENTRY SmpSubSystemsToDefer;
  96. LIST_ENTRY SmpExecuteList;
  97. NTSTATUS
  98. SmpCreateSecurityDescriptors(
  99. IN BOOLEAN InitialCall
  100. );
  101. NTSTATUS
  102. SmpLoadDataFromRegistry(
  103. OUT PUNICODE_STRING InitialCommand
  104. );
  105. NTSTATUS
  106. SmpCreateDynamicEnvironmentVariables(
  107. VOID
  108. );
  109. NTSTATUS
  110. SmpConfigureProtectionMode(
  111. IN PWSTR ValueName,
  112. IN ULONG ValueType,
  113. IN PVOID ValueData,
  114. IN ULONG ValueLength,
  115. IN PVOID Context,
  116. IN PVOID EntryContext
  117. );
  118. NTSTATUS
  119. SmpConfigureAllowProtectedRenames(
  120. IN PWSTR ValueName,
  121. IN ULONG ValueType,
  122. IN PVOID ValueData,
  123. IN ULONG ValueLength,
  124. IN PVOID Context,
  125. IN PVOID EntryContext
  126. );
  127. NTSTATUS
  128. SmpConfigureObjectDirectories(
  129. IN PWSTR ValueName,
  130. IN ULONG ValueType,
  131. IN PVOID ValueData,
  132. IN ULONG ValueLength,
  133. IN PVOID Context,
  134. IN PVOID EntryContext
  135. );
  136. NTSTATUS
  137. SmpConfigureExecute(
  138. IN PWSTR ValueName,
  139. IN ULONG ValueType,
  140. IN PVOID ValueData,
  141. IN ULONG ValueLength,
  142. IN PVOID Context,
  143. IN PVOID EntryContext
  144. );
  145. NTSTATUS
  146. SmpConfigureFileRenames(
  147. IN PWSTR ValueName,
  148. IN ULONG ValueType,
  149. IN PVOID ValueData,
  150. IN ULONG ValueLength,
  151. IN PVOID Context,
  152. IN PVOID EntryContext
  153. );
  154. NTSTATUS
  155. SmpConfigureMemoryMgmt(
  156. IN PWSTR ValueName,
  157. IN ULONG ValueType,
  158. IN PVOID ValueData,
  159. IN ULONG ValueLength,
  160. IN PVOID Context,
  161. IN PVOID EntryContext
  162. );
  163. NTSTATUS
  164. SmpConfigureDosDevices(
  165. IN PWSTR ValueName,
  166. IN ULONG ValueType,
  167. IN PVOID ValueData,
  168. IN ULONG ValueLength,
  169. IN PVOID Context,
  170. IN PVOID EntryContext
  171. );
  172. NTSTATUS
  173. SmpConfigureKnownDlls(
  174. IN PWSTR ValueName,
  175. IN ULONG ValueType,
  176. IN PVOID ValueData,
  177. IN ULONG ValueLength,
  178. IN PVOID Context,
  179. IN PVOID EntryContext
  180. );
  181. NTSTATUS
  182. SmpConfigureExcludeKnownDlls(
  183. IN PWSTR ValueName,
  184. IN ULONG ValueType,
  185. IN PVOID ValueData,
  186. IN ULONG ValueLength,
  187. IN PVOID Context,
  188. IN PVOID EntryContext
  189. );
  190. NTSTATUS
  191. SmpConfigureSubSystems(
  192. IN PWSTR ValueName,
  193. IN ULONG ValueType,
  194. IN PVOID ValueData,
  195. IN ULONG ValueLength,
  196. IN PVOID Context,
  197. IN PVOID EntryContext
  198. );
  199. NTSTATUS
  200. SmpConfigureEnvironment(
  201. IN PWSTR ValueName,
  202. IN ULONG ValueType,
  203. IN PVOID ValueData,
  204. IN ULONG ValueLength,
  205. IN PVOID Context,
  206. IN PVOID EntryContext
  207. );
  208. ULONGLONG
  209. SmpGetFileVersion(
  210. IN HANDLE FileHandle,
  211. IN PUNICODE_STRING FileName
  212. );
  213. NTSTATUS
  214. SmpCallCsrCreateProcess(
  215. IN OUT PSBAPIMSG m,
  216. IN size_t ArgLength,
  217. IN HANDLE CommunicationPort
  218. );
  219. RTL_QUERY_REGISTRY_TABLE SmpRegistryConfigurationTable[] = {
  220. //
  221. // Note that the SmpConfigureProtectionMode entry should preceed others
  222. // to ensure we set up the right protection for use by the others.
  223. //
  224. {SmpConfigureProtectionMode, 0,
  225. L"ProtectionMode", NULL,
  226. REG_DWORD, (PVOID)0, 0},
  227. {SmpConfigureAllowProtectedRenames, RTL_QUERY_REGISTRY_DELETE,
  228. L"AllowProtectedRenames", NULL,
  229. REG_DWORD, (PVOID)0, 0},
  230. {SmpConfigureObjectDirectories, 0,
  231. L"ObjectDirectories", NULL,
  232. REG_MULTI_SZ, (PVOID)L"\\Windows\0\\RPC Control\0", 0},
  233. {SmpConfigureExecute, 0,
  234. L"BootExecute", &SmpBootExecuteList,
  235. REG_MULTI_SZ, L"autocheck AutoChk.exe *\0", 0},
  236. {SmpConfigureExecute, RTL_QUERY_REGISTRY_TOPKEY,
  237. L"SetupExecute", &SmpSetupExecuteList,
  238. REG_NONE, NULL, 0},
  239. {SmpConfigureFileRenames, RTL_QUERY_REGISTRY_DELETE,
  240. L"PendingFileRenameOperations", &SmpFileRenameList,
  241. REG_NONE, NULL, 0},
  242. {SmpConfigureFileRenames, RTL_QUERY_REGISTRY_DELETE,
  243. L"PendingFileRenameOperations2", &SmpFileRenameList,
  244. REG_NONE, NULL, 0},
  245. {SmpConfigureExcludeKnownDlls, 0,
  246. L"ExcludeFromKnownDlls", &SmpExcludeKnownDllsList,
  247. REG_MULTI_SZ, L"\0", 0},
  248. {NULL, RTL_QUERY_REGISTRY_SUBKEY,
  249. L"Memory Management", NULL,
  250. REG_NONE, NULL, 0},
  251. {SmpConfigureMemoryMgmt, 0,
  252. L"PagingFiles", &SmpPagingFileList,
  253. REG_MULTI_SZ, L"?:\\pagefile.sys\0", 0},
  254. {SmpConfigureDosDevices, RTL_QUERY_REGISTRY_SUBKEY,
  255. L"DOS Devices", &SmpDosDevicesList,
  256. REG_NONE, NULL, 0},
  257. {SmpConfigureKnownDlls, RTL_QUERY_REGISTRY_SUBKEY,
  258. L"KnownDlls", &SmpKnownDllsList,
  259. REG_NONE, NULL, 0},
  260. //
  261. // NOTICE-2002/05/23-ELi
  262. // SmpConfigureEnvironment assumes that it will be called twice
  263. // If you change the number of times SmpConfigureEnvironment is called,
  264. // then make sure that you do not break SmpConfigureEnvironment.
  265. // see bug 318452 in the old Windows NT Bugs RAID database for the
  266. // reason why SmpConfigureEnvironment is called twice.
  267. //
  268. //
  269. // this needs to happen twice so that forward references to environment
  270. // variables, which may be defined under the Environment registry key, are
  271. // properly resolved
  272. //
  273. {SmpConfigureEnvironment, RTL_QUERY_REGISTRY_SUBKEY,
  274. L"Environment", NULL,
  275. REG_NONE, NULL, 0},
  276. {SmpConfigureEnvironment, RTL_QUERY_REGISTRY_SUBKEY,
  277. L"Environment", NULL,
  278. REG_NONE, NULL, 0},
  279. {SmpConfigureSubSystems, RTL_QUERY_REGISTRY_SUBKEY,
  280. L"SubSystems", &SmpSubSystemList,
  281. REG_NONE, NULL, 0},
  282. {SmpConfigureSubSystems, RTL_QUERY_REGISTRY_NOEXPAND,
  283. L"Required", &SmpSubSystemList,
  284. REG_MULTI_SZ, L"Debug\0Windows\0", 0},
  285. {SmpConfigureSubSystems, RTL_QUERY_REGISTRY_NOEXPAND,
  286. L"Optional", &SmpSubSystemList,
  287. REG_NONE, NULL, 0},
  288. {SmpConfigureSubSystems, 0,
  289. L"Kmode", &SmpSubSystemList,
  290. REG_NONE, NULL, 0},
  291. {SmpConfigureExecute, RTL_QUERY_REGISTRY_TOPKEY,
  292. L"Execute", &SmpExecuteList,
  293. REG_NONE, NULL, 0},
  294. {NULL, 0,
  295. NULL, NULL,
  296. REG_NONE, NULL, 0}
  297. };
  298. NTSTATUS
  299. SmpInvokeAutoChk(
  300. IN PUNICODE_STRING ImageFileName,
  301. IN PUNICODE_STRING CurrentDirectory,
  302. IN PUNICODE_STRING Arguments,
  303. IN ULONG Flags
  304. );
  305. #if defined(REMOTE_BOOT)
  306. NTSTATUS
  307. SmpInvokeAutoFmt(
  308. IN PUNICODE_STRING ImageFileName,
  309. IN PUNICODE_STRING CurrentDirectory,
  310. IN PUNICODE_STRING Arguments,
  311. IN ULONG Flags
  312. );
  313. #endif // defined(REMOTE_BOOT)
  314. NTSTATUS
  315. SmpLoadSubSystem(
  316. IN PUNICODE_STRING ImageFileName,
  317. IN PUNICODE_STRING CurrentDirectory,
  318. IN PUNICODE_STRING CommandLine,
  319. IN ULONG MuSessionId,
  320. OUT PULONG_PTR pWindowsSubSysProcessId,
  321. IN ULONG Flags
  322. );
  323. NTSTATUS
  324. SmpExecuteCommand(
  325. IN PUNICODE_STRING CommandLine,
  326. IN ULONG MuSessionId,
  327. OUT PULONG_PTR pWindowsSubSysProcessId,
  328. IN ULONG Flags
  329. );
  330. NTSTATUS
  331. SmpInitializeDosDevices( VOID );
  332. NTSTATUS
  333. SmpInitializeKnownDlls( VOID );
  334. NTSTATUS
  335. SmpInitializeKnownDllPath(
  336. IN PUNICODE_STRING KnownDllPath,
  337. IN PVOID ValueData,
  338. IN ULONG ValueLength);
  339. NTSTATUS
  340. SmpInitializeKnownDllsInternal(
  341. IN PUNICODE_STRING ObjectDirectoryName,
  342. IN PUNICODE_STRING KnownDllPath
  343. );
  344. #if defined(REMOTE_BOOT)
  345. NTSTATUS
  346. SmpExecuteCommandLineArguments( VOID );
  347. #endif // defined(REMOTE_BOOT)
  348. VOID
  349. SmpProcessFileRenames( VOID );
  350. NTSTATUS
  351. SmpParseToken(
  352. IN PUNICODE_STRING Source,
  353. IN BOOLEAN RemainderOfSource,
  354. OUT PUNICODE_STRING Token
  355. );
  356. NTSTATUS
  357. SmpParseCommandLine(
  358. IN PUNICODE_STRING CommandLine,
  359. OUT PULONG Flags,
  360. OUT PUNICODE_STRING ImageFileName,
  361. OUT PUNICODE_STRING ImageFileDirectory OPTIONAL,
  362. OUT PUNICODE_STRING Arguments
  363. );
  364. #define SMP_DEBUG_FLAG 0x00000001
  365. #define SMP_ASYNC_FLAG 0x00000002
  366. #define SMP_AUTOCHK_FLAG 0x00000004
  367. #define SMP_SUBSYSTEM_FLAG 0x00000008
  368. #define SMP_IMAGE_NOT_FOUND 0x00000010
  369. #define SMP_DONT_START 0x00000020
  370. #if defined(REMOTE_BOOT)
  371. #define SMP_AUTOFMT_FLAG 0x00000040
  372. #endif // defined(REMOTE_BOOT)
  373. #define SMP_POSIX_SI_FLAG 0x00000080
  374. #define SMP_POSIX_FLAG 0x00000100
  375. #define SMP_OS2_FLAG 0x00000200
  376. ULONG
  377. SmpConvertInteger(
  378. IN PWSTR String
  379. );
  380. VOID
  381. SmpTranslateSystemPartitionInformation( VOID );
  382. #if defined(REMOTE_BOOT)
  383. //
  384. // Useful functions for iterating thru directories and files
  385. //
  386. typedef enum {
  387. NormalReturn, // if the whole process completes uninterrupted
  388. EnumFileError, // if an error occurs while enumerating files
  389. CallbackReturn // if the callback returns FALSE, causing termination
  390. } ENUMFILESRESULT;
  391. typedef BOOLEAN (*ENUMFILESPROC) (
  392. IN PWSTR,
  393. IN PFILE_BOTH_DIR_INFORMATION,
  394. OUT PULONG,
  395. IN PVOID
  396. );
  397. typedef struct {
  398. PVOID OptionalPtr;
  399. ENUMFILESPROC EnumProc;
  400. } RECURSION_DATA, *PRECURSION_DATA;
  401. ENUMFILESRESULT
  402. SmpEnumFiles(
  403. IN PWSTR DirName,
  404. IN ENUMFILESPROC EnumFilesProc,
  405. OUT PULONG ReturnData,
  406. IN PVOID Pointer
  407. );
  408. ENUMFILESRESULT
  409. SmpEnumFilesRecursive (
  410. IN PWSTR DirName,
  411. IN ENUMFILESPROC EnumFilesProc,
  412. OUT PULONG ReturnData,
  413. IN PVOID Pointer OPTIONAL
  414. );
  415. VOID
  416. SmpConcatenatePaths(
  417. IN OUT LPWSTR Path1,
  418. IN LPCWSTR Path2
  419. );
  420. BOOLEAN
  421. SmppRecursiveEnumProc (
  422. IN PWSTR DirName,
  423. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  424. OUT PULONG ret,
  425. IN PVOID Param
  426. );
  427. BOOLEAN
  428. SmpDelEnumFile(
  429. IN PWSTR DirName,
  430. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  431. OUT PULONG ret,
  432. IN PVOID Pointer
  433. );
  434. #endif // defined(REMOTE_BOOT)
  435. //
  436. // routines
  437. //
  438. BOOLEAN
  439. SmpQueryRegistrySosOption(
  440. VOID
  441. )
  442. /*++
  443. Routine Description:
  444. This function queries the registry to determine if the loadoptions
  445. boot environment variable contains the string "SOS".
  446. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control:SystemStartOptions
  447. Arguments:
  448. None.
  449. Return Value:
  450. TRUE if "SOS" was set. Otherwise FALSE.
  451. --*/
  452. {
  453. NTSTATUS Status;
  454. UNICODE_STRING KeyName;
  455. UNICODE_STRING ValueName;
  456. OBJECT_ATTRIBUTES ObjectAttributes;
  457. HANDLE Key;
  458. UCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  459. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  460. ULONG ValueLength;
  461. //
  462. // Open the registry key.
  463. //
  464. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  465. RtlInitUnicodeString(&KeyName,
  466. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control");
  467. InitializeObjectAttributes(&ObjectAttributes,
  468. &KeyName,
  469. OBJ_CASE_INSENSITIVE,
  470. NULL,
  471. NULL);
  472. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  473. if (!NT_SUCCESS(Status)) {
  474. KdPrintEx((DPFLTR_SMSS_ID,
  475. DPFLTR_WARNING_LEVEL,
  476. "SMSS: can't open control key: 0x%x\n",
  477. Status));
  478. return FALSE;
  479. }
  480. //
  481. // Query the key value.
  482. //
  483. RtlInitUnicodeString(&ValueName, L"SystemStartOptions");
  484. Status = NtQueryValueKey(Key,
  485. &ValueName,
  486. KeyValuePartialInformation,
  487. (PVOID)KeyValueInfo,
  488. sizeof (ValueBuffer),
  489. &ValueLength);
  490. ASSERT(ValueLength < VALUE_BUFFER_SIZE);
  491. NtClose(Key);
  492. if (!NT_SUCCESS(Status)) {
  493. KdPrintEx((DPFLTR_SMSS_ID,
  494. DPFLTR_WARNING_LEVEL,
  495. "SMSS: can't query value key: 0x%x\n",
  496. Status));
  497. return FALSE;
  498. }
  499. //
  500. // Check is "sos" or "SOS" ois specified.
  501. //
  502. if (NULL != wcsstr((PWCHAR)&KeyValueInfo->Data, L"SOS") ||
  503. NULL != wcsstr((PWCHAR)&KeyValueInfo->Data, L"sos")) {
  504. return TRUE;
  505. }
  506. return FALSE;
  507. }
  508. NTSTATUS
  509. SmpInit(
  510. OUT PUNICODE_STRING InitialCommand,
  511. OUT PHANDLE WindowsSubSystem
  512. )
  513. {
  514. NTSTATUS st;
  515. OBJECT_ATTRIBUTES ObjA;
  516. HANDLE SmpApiConnectionPort;
  517. UNICODE_STRING Unicode;
  518. NTSTATUS Status, Status2;
  519. ULONG HardErrorMode;
  520. UNICODE_STRING UnicodeString;
  521. HANDLE VolumeSafeEvent;
  522. SmBaseTag = RtlCreateTagHeap( RtlProcessHeap(),
  523. 0,
  524. L"SMSS!",
  525. L"INIT\0"
  526. L"DBG\0"
  527. L"SM\0"
  528. );
  529. //
  530. // Make sure we specify hard error popups
  531. //
  532. HardErrorMode = 1;
  533. NtSetInformationProcess( NtCurrentProcess(),
  534. ProcessDefaultHardErrorMode,
  535. (PVOID) &HardErrorMode,
  536. sizeof( HardErrorMode )
  537. );
  538. RtlInitUnicodeString( &SmpSubsystemName, L"NT-Session Manager" );
  539. RtlInitializeCriticalSection(&SmpKnownSubSysLock);
  540. InitializeListHead(&SmpKnownSubSysHead);
  541. RtlInitializeCriticalSection(&SmpSessionListLock);
  542. InitializeListHead(&SmpSessionListHead);
  543. SmpNextSessionId = 1;
  544. SmpNextSessionIdScanMode = FALSE;
  545. SmpDbgSsLoaded = FALSE;
  546. //
  547. // Initialize security descriptors to grant wide access
  548. // (protection mode not yet read in from registry).
  549. //
  550. st = SmpCreateSecurityDescriptors( TRUE );
  551. if (!NT_SUCCESS(st)) {
  552. SAVE_SMPINIT_STATUS (SmpCreateSecurityDescriptors, st);
  553. return(st);
  554. }
  555. InitializeListHead(&NativeProcessList);
  556. SmpHeap = RtlProcessHeap();
  557. RtlInitUnicodeString( &PosixName, L"POSIX" );
  558. RtlInitUnicodeString( &Os2Name, L"OS2" );
  559. RtlInitUnicodeString( &Unicode, L"\\SmApiPort" );
  560. InitializeObjectAttributes( &ObjA, &Unicode, 0, NULL, SmpApiPortSecurityDescriptor);
  561. st = NtCreatePort(
  562. &SmpApiConnectionPort,
  563. &ObjA,
  564. sizeof(SBCONNECTINFO),
  565. sizeof(SMMESSAGE_SIZE),
  566. sizeof(SBAPIMSG) * 32
  567. );
  568. ASSERT( NT_SUCCESS(st) );
  569. SmpDebugPort = SmpApiConnectionPort;
  570. st = RtlCreateUserThread(
  571. NtCurrentProcess(),
  572. NULL,
  573. FALSE,
  574. 0L,
  575. 0L,
  576. 0L,
  577. SmpApiLoop,
  578. (PVOID) SmpApiConnectionPort,
  579. NULL,
  580. NULL
  581. );
  582. ASSERT( NT_SUCCESS(st) );
  583. st = RtlCreateUserThread(
  584. NtCurrentProcess(),
  585. NULL,
  586. FALSE,
  587. 0L,
  588. 0L,
  589. 0L,
  590. SmpApiLoop,
  591. (PVOID) SmpApiConnectionPort,
  592. NULL,
  593. NULL
  594. );
  595. ASSERT( NT_SUCCESS(st) );
  596. //
  597. // Create a event to signal that volume are safe for write access opens.
  598. // Call this event 'VolumesSafeForWriteAccess'. This event will be
  599. // signalled after AUTOCHK/AUTOCONV/AUTOFMT have done their business.
  600. //
  601. RtlInitUnicodeString( &UnicodeString, L"\\Device\\VolumesSafeForWriteAccess");
  602. InitializeObjectAttributes( &ObjA,
  603. &UnicodeString,
  604. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  605. NULL,
  606. NULL
  607. );
  608. Status2 = NtCreateEvent( &VolumeSafeEvent,
  609. EVENT_ALL_ACCESS,
  610. &ObjA,
  611. NotificationEvent,
  612. FALSE
  613. );
  614. if (!NT_SUCCESS( Status2 )) {
  615. KdPrintEx((DPFLTR_SMSS_ID,
  616. DPFLTR_WARNING_LEVEL,
  617. "SMSS: Unable to create %wZ event - Status == %lx\n",
  618. &UnicodeString,
  619. Status2));
  620. ASSERT( NT_SUCCESS(Status2) );
  621. }
  622. //
  623. // Configure the system
  624. //
  625. Status = SmpLoadDataFromRegistry( InitialCommand );
  626. if (NT_SUCCESS( Status )) {
  627. *WindowsSubSystem = SmpWindowsSubSysProcess;
  628. }
  629. //
  630. // AUTOCHK/AUTOCONV/AUTOFMT are finished.
  631. //
  632. if (NT_SUCCESS(Status2)) {
  633. NtSetEvent(VolumeSafeEvent, NULL);
  634. NtClose(VolumeSafeEvent);
  635. }
  636. return( Status );
  637. }
  638. NTSTATUS
  639. SmpLoadDataFromRegistry(
  640. OUT PUNICODE_STRING InitialCommand
  641. )
  642. /*++
  643. Routine Description:
  644. This function loads all of the configurable data for the NT Session
  645. Manager from the registry.
  646. Arguments:
  647. None
  648. Return Value:
  649. Status of operation
  650. --*/
  651. {
  652. NTSTATUS Status;
  653. PLIST_ENTRY Head, Next;
  654. PSMP_REGISTRY_VALUE p;
  655. PVOID OriginalEnvironment;
  656. ULONG MuSessionId = 0;
  657. UNICODE_STRING KeyName;
  658. OBJECT_ATTRIBUTES ObjectAttributes;
  659. HANDLE Key;
  660. UNICODE_STRING SessionDirName;
  661. #if defined(REMOTE_BOOT)
  662. HANDLE RdrHandle = NULL;
  663. IO_STATUS_BLOCK Iosb;
  664. SHADOWINFO ShadowInfo;
  665. #endif // defined(REMOTE_BOOT)
  666. RtlInitUnicodeString( &SmpDebugKeyword, L"debug" );
  667. RtlInitUnicodeString( &SmpASyncKeyword, L"async" );
  668. RtlInitUnicodeString( &SmpAutoChkKeyword, L"autocheck" );
  669. #if defined(REMOTE_BOOT)
  670. RtlInitUnicodeString( &SmpAutoFmtKeyword, L"autoformat" );
  671. #endif // defined(REMOTE_BOOT)
  672. InitializeListHead( &SmpBootExecuteList );
  673. InitializeListHead( &SmpSetupExecuteList );
  674. InitializeListHead( &SmpPagingFileList );
  675. InitializeListHead( &SmpDosDevicesList );
  676. InitializeListHead( &SmpFileRenameList );
  677. InitializeListHead( &SmpKnownDllsList );
  678. InitializeListHead( &SmpExcludeKnownDllsList );
  679. InitializeListHead( &SmpSubSystemList );
  680. InitializeListHead( &SmpSubSystemsToLoad );
  681. InitializeListHead( &SmpSubSystemsToDefer );
  682. InitializeListHead( &SmpExecuteList );
  683. SmpPagingFileInitialize ();
  684. Status = RtlCreateEnvironment( TRUE, &SmpDefaultEnvironment );
  685. if (!NT_SUCCESS( Status )) {
  686. KdPrintEx((DPFLTR_SMSS_ID,
  687. DPFLTR_WARNING_LEVEL,
  688. "SMSS: Unable to allocate default environment - Status == %X\n",
  689. Status));
  690. SAVE_SMPINIT_STATUS (RtlCreateEnvironment, Status);
  691. return( Status );
  692. }
  693. RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\MiniNT" );
  694. InitializeObjectAttributes( &ObjectAttributes,
  695. &KeyName,
  696. OBJ_CASE_INSENSITIVE,
  697. NULL,
  698. NULL
  699. );
  700. Status = NtOpenKey( &Key, KEY_ALL_ACCESS, &ObjectAttributes );
  701. if (NT_SUCCESS( Status )) {
  702. NtClose( Key );
  703. MiniNTBoot = TRUE;
  704. }
  705. if (MiniNTBoot) {
  706. DbgPrint("SMSS: !!! MiniNT Boot !!!\n");
  707. }
  708. //
  709. // before the environment is created we MUST delete the
  710. // safemode reg value
  711. //
  712. RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Environment" );
  713. InitializeObjectAttributes( &ObjectAttributes,
  714. &KeyName,
  715. OBJ_CASE_INSENSITIVE,
  716. NULL,
  717. NULL
  718. );
  719. Status = NtOpenKey( &Key, KEY_ALL_ACCESS, &ObjectAttributes );
  720. if (NT_SUCCESS( Status )) {
  721. RtlInitUnicodeString( &KeyName, L"SAFEBOOT_OPTION" );
  722. NtDeleteValueKey( Key, &KeyName );
  723. NtClose( Key );
  724. }
  725. //
  726. // In order to track growth in smpdefaultenvironment, make it sm's environment
  727. // while doing the registry groveling and then restore it
  728. //
  729. OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
  730. NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment;
  731. Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
  732. L"Session Manager",
  733. SmpRegistryConfigurationTable,
  734. NULL,
  735. NULL
  736. );
  737. SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment;
  738. NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment;
  739. if (!NT_SUCCESS( Status )) {
  740. KdPrintEx((DPFLTR_SMSS_ID,
  741. DPFLTR_WARNING_LEVEL,
  742. "SMSS: RtlQueryRegistryValues failed - Status == %lx\n",
  743. Status));
  744. SAVE_SMPINIT_STATUS (RtlQueryRegistryValues, Status);
  745. return( Status );
  746. }
  747. Status = SmpInitializeDosDevices();
  748. if (!NT_SUCCESS( Status )) {
  749. KdPrintEx((DPFLTR_SMSS_ID,
  750. DPFLTR_WARNING_LEVEL,
  751. "SMSS: Unable to initialize DosDevices configuration - Status == %lx\n",
  752. Status));
  753. SAVE_SMPINIT_STATUS (SmpInitializeDosDevices, Status);
  754. return( Status );
  755. }
  756. //
  757. // Create the root "Sessions Directory". This is the container for all session
  758. // specific directories. Each session specific CSRSS during startup will
  759. // create a <sessionid> direcotry under "\Sessions". "\Sessions\<sessionid>
  760. // directory will be the container for that session.
  761. //
  762. RtlInitUnicodeString( &SessionDirName, L"\\Sessions" );
  763. InitializeObjectAttributes( &ObjectAttributes,
  764. &SessionDirName,
  765. OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
  766. NULL,
  767. SmpPrimarySecurityDescriptor
  768. );
  769. if (!NT_SUCCESS(Status = NtCreateDirectoryObject( &SmpSessionsObjectDirectory,
  770. DIRECTORY_ALL_ACCESS,
  771. &ObjectAttributes
  772. ))) {
  773. KdPrintEx((DPFLTR_SMSS_ID,
  774. DPFLTR_WARNING_LEVEL,
  775. "SMSS: Unable to create %wZ object directory - Status == %lx\n",
  776. &SessionDirName,
  777. Status));
  778. SAVE_SMPINIT_STATUS (NtCreateDirectoryObject, Status);
  779. return Status;
  780. }
  781. #if defined(REMOTE_BOOT)
  782. //
  783. // On a remote boot client, the client-side cache is already initialized.
  784. // We need to tell CSC not to cache database handles during the next phase
  785. // so that autochk can run.
  786. //
  787. if (SmpNetboot) {
  788. OBJECT_ATTRIBUTES ObjectAttributes;
  789. UNICODE_STRING RdrNameString;
  790. RtlInitUnicodeString( &RdrNameString, L"\\Device\\LanmanRedirector" );
  791. InitializeObjectAttributes(
  792. &ObjectAttributes,
  793. &RdrNameString,
  794. OBJ_CASE_INSENSITIVE,
  795. NULL,
  796. NULL
  797. );
  798. Status = NtCreateFile(
  799. &RdrHandle,
  800. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  801. &ObjectAttributes,
  802. &Iosb,
  803. NULL,
  804. 0,
  805. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  806. FILE_OPEN,
  807. FILE_SYNCHRONOUS_IO_NONALERT,
  808. NULL,
  809. 0
  810. );
  811. if ( !NT_SUCCESS(Status) ) {
  812. KdPrintEx((DPFLTR_SMSS_ID,
  813. DPFLTR_WARNING_LEVEL,
  814. "SmpLoadDataFromRegistry: Unable to open redirector: %x\n",
  815. Status));
  816. RdrHandle = NULL;
  817. }
  818. else {
  819. ShadowInfo.uOp = SHADOW_CHANGE_HANDLE_CACHING_STATE;
  820. ShadowInfo.uStatus = FALSE;
  821. Status = NtDeviceIoControlFile(
  822. RdrHandle,
  823. NULL,
  824. NULL,
  825. NULL,
  826. &Iosb,
  827. IOCTL_DO_SHADOW_MAINTENANCE,
  828. &ShadowInfo,
  829. sizeof(ShadowInfo),
  830. NULL,
  831. 0
  832. );
  833. if ( NT_SUCCESS(Status) ) {
  834. Status = Iosb.Status;
  835. }
  836. if ( !NT_SUCCESS(Status) ) {
  837. KdPrintEx((DPFLTR_SMSS_ID,
  838. DPFLTR_WARNING_LEVEL,
  839. "SmpLoadDataFromRegistry: Unable to IOCTL CSC: %x\n",
  840. Status));
  841. }
  842. }
  843. }
  844. Status = SmpExecuteCommandLineArguments();
  845. if (!NT_SUCCESS( Status )) {
  846. KdPrintEx((DPFLTR_SMSS_ID,
  847. DPFLTR_WARNING_LEVEL,
  848. "SMSS: Unable to process command line arguments - Status == %lx\n",
  849. Status));
  850. return( Status );
  851. }
  852. #endif // defined(REMOTE_BOOT)
  853. Head = &SmpBootExecuteList;
  854. while (!IsListEmpty( Head )) {
  855. Next = RemoveHeadList( Head );
  856. p = CONTAINING_RECORD( Next,
  857. SMP_REGISTRY_VALUE,
  858. Entry
  859. );
  860. #if SMP_SHOW_REGISTRY_DATA
  861. DbgPrint( "SMSS: BootExecute( %wZ )\n", &p->Name );
  862. #endif
  863. SmpExecuteCommand( &p->Name, 0, NULL, 0 );
  864. if (p->AnsiValue) { RtlFreeHeap( RtlProcessHeap(), 0, p->AnsiValue ); }
  865. if (p->Value.Buffer) { RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer ); }
  866. RtlFreeHeap( RtlProcessHeap(), 0, p );
  867. }
  868. #if defined(REMOTE_BOOT)
  869. //
  870. // On a remote boot client, we can now reenable CSC handle caching.
  871. //
  872. if (SmpNetboot && (RdrHandle != NULL)) {
  873. ShadowInfo.uOp = SHADOW_CHANGE_HANDLE_CACHING_STATE;
  874. ShadowInfo.uStatus = TRUE;
  875. Status = NtDeviceIoControlFile(
  876. RdrHandle,
  877. NULL,
  878. NULL,
  879. NULL,
  880. &Iosb,
  881. IOCTL_DO_SHADOW_MAINTENANCE,
  882. &ShadowInfo,
  883. sizeof(ShadowInfo),
  884. NULL,
  885. 0
  886. );
  887. if ( NT_SUCCESS(Status) ) {
  888. Status = Iosb.Status;
  889. }
  890. if ( !NT_SUCCESS(Status) ) {
  891. KdPrintEx((DPFLTR_SMSS_ID,
  892. DPFLTR_WARNING_LEVEL,
  893. "SmpLoadDataFromRegistry: Unable to IOCTL CSC (2): %x\n",
  894. Status));
  895. }
  896. }
  897. #endif // defined(REMOTE_BOOT)
  898. if (!MiniNTBoot) {
  899. SmpProcessFileRenames();
  900. }
  901. //
  902. // Begin process of verifying system DLL's
  903. //
  904. Status = SmpInitializeKnownDlls();
  905. if (!NT_SUCCESS( Status )) {
  906. KdPrintEx((DPFLTR_SMSS_ID,
  907. DPFLTR_WARNING_LEVEL,
  908. "SMSS: Unable to initialize KnownDll configuration - Status == %lx\n",
  909. Status));
  910. SAVE_SMPINIT_STATUS (SmpInitializeKnownDlls, Status);
  911. return( Status );
  912. }
  913. //
  914. // Create paging files.
  915. //
  916. if (! MiniNTBoot) {
  917. Head = &SmpPagingFileList;
  918. try {
  919. //
  920. // Process the list of paging file descriptors
  921. // read from registry.
  922. //
  923. while (! IsListEmpty (Head)) {
  924. Next = RemoveHeadList (Head);
  925. p = CONTAINING_RECORD (Next,
  926. SMP_REGISTRY_VALUE,
  927. Entry);
  928. SmpCreatePagingFileDescriptor (&p->Name);
  929. if (p->AnsiValue) { RtlFreeHeap( RtlProcessHeap(), 0, p->AnsiValue ); }
  930. if (p->Value.Buffer) { RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer ); }
  931. RtlFreeHeap (RtlProcessHeap(), 0, p);
  932. }
  933. //
  934. // Create any paging files specified.
  935. //
  936. SmpCreatePagingFiles();
  937. }
  938. except (SmpPagingFileExceptionFilter (_exception_code(), _exception_info())) {
  939. //
  940. // Nothing.
  941. //
  942. }
  943. }
  944. //
  945. // Finish registry initialization
  946. //
  947. NtInitializeRegistry(REG_INIT_BOOT_SM);
  948. Status = SmpCreateDynamicEnvironmentVariables( );
  949. if (!NT_SUCCESS( Status )) {
  950. SAVE_SMPINIT_STATUS (SmpCreateDynamicEnvironmentVariables, Status);
  951. return Status;
  952. }
  953. //
  954. // Load subsystems for the console session. Console always has
  955. // MuSessionId = 0
  956. //
  957. Status = SmpLoadSubSystemsForMuSession( &MuSessionId,
  958. &SmpWindowsSubSysProcessId, InitialCommand );
  959. ASSERT(MuSessionId == 0);
  960. if (! NT_SUCCESS(Status)) {
  961. SAVE_SMPINIT_STATUS (SmpLoadSubSystemsForMuSession, Status);
  962. }
  963. return( Status );
  964. }
  965. NTSTATUS
  966. SmpLoadSubSystemsForMuSession(
  967. PULONG pMuSessionId,
  968. PULONG_PTR pWindowsSubSysProcessId,
  969. PUNICODE_STRING InitialCommand )
  970. /*++
  971. Routine Description:
  972. This function starts all of the configured subsystems for the
  973. specified Multi-User Session. For regular NT this routine is called once
  974. to start CSRSS etc. For Terminal Server, this routine is called every time
  975. we want to start a new Multi-User Session to start session specific subsystems
  976. Arguments:
  977. Return Value:
  978. Status of operation
  979. --*/
  980. {
  981. NTSTATUS Status = 0, Status1;
  982. PLIST_ENTRY Head, Next;
  983. PSMP_REGISTRY_VALUE p;
  984. //
  985. // Translate the system partition information stored during IoInitSystem into
  986. // a DOS path and store in Win32-standard location.
  987. //
  988. SmpTranslateSystemPartitionInformation();
  989. //
  990. // Second pass of execution.
  991. //
  992. Next = SmpSetupExecuteList.Flink;
  993. while( Next != &SmpSetupExecuteList ) {
  994. p = CONTAINING_RECORD( Next,
  995. SMP_REGISTRY_VALUE,
  996. Entry
  997. );
  998. #if SMP_SHOW_REGISTRY_DATA
  999. DbgPrint( "SMSS: SetupExecute( %wZ )\n", &p->Name );
  1000. #endif
  1001. SmpExecuteCommand( &p->Name, 0, NULL, 0 );
  1002. //
  1003. // Note this function is reentrant and is called every time we start
  1004. // a new Multi-User Session.
  1005. //
  1006. Next = Next->Flink;
  1007. }
  1008. Next = SmpSubSystemList.Flink;
  1009. while ( Next != &SmpSubSystemList ) {
  1010. p = CONTAINING_RECORD( Next,
  1011. SMP_REGISTRY_VALUE,
  1012. Entry
  1013. );
  1014. if ( !_wcsicmp( p->Name.Buffer, L"Kmode" )) {
  1015. BOOLEAN TranslationStatus;
  1016. UNICODE_STRING FileName;
  1017. UNICODE_STRING Win32kFileName;
  1018. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1019. p->Value.Buffer,
  1020. &FileName,
  1021. NULL,
  1022. NULL
  1023. );
  1024. if ( TranslationStatus ) {
  1025. PVOID State;
  1026. Status = SmpAcquirePrivilege( SE_LOAD_DRIVER_PRIVILEGE, &State );
  1027. if (NT_SUCCESS( Status )) {
  1028. //
  1029. // Create a session space before loading any extended
  1030. // service table providers. This call will create a session
  1031. // space for the Multi-User session. The session mananger
  1032. // will see the instance of the newly created session space
  1033. // after this call. Once session manager is done creating
  1034. // CSRSS and winlogon it will detach itself from this
  1035. // session space.
  1036. //
  1037. ASSERT( AttachedSessionId == -1 );
  1038. Status = NtSetSystemInformation(
  1039. SystemSessionCreate,
  1040. (PVOID)pMuSessionId,
  1041. sizeof(*pMuSessionId)
  1042. );
  1043. if ( !NT_SUCCESS(Status) ) {
  1044. KdPrintEx((DPFLTR_SMSS_ID,
  1045. DPFLTR_WARNING_LEVEL,
  1046. "SMSS: Session space creation failed\n"));
  1047. //
  1048. // Do not load any subsystems without SessionSpace.
  1049. //
  1050. SmpReleasePrivilege( State );
  1051. RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
  1052. return( Status );
  1053. };
  1054. AttachedSessionId = *pMuSessionId;
  1055. RtlInitUnicodeString(&Win32kFileName,L"\\SystemRoot\\System32\\win32k.sys");
  1056. Status = NtSetSystemInformation(
  1057. SystemExtendServiceTableInformation,
  1058. (PVOID)&Win32kFileName,
  1059. sizeof(Win32kFileName)
  1060. );
  1061. RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
  1062. SmpReleasePrivilege( State );
  1063. if ( !NT_SUCCESS(Status) ) {
  1064. //
  1065. // Do not load any subsystems without WIN32K!
  1066. //
  1067. KdPrintEx((DPFLTR_SMSS_ID,
  1068. DPFLTR_ERROR_LEVEL,
  1069. "SMSS: Load of WIN32K failed.\n"));
  1070. return( Status );
  1071. }
  1072. }
  1073. else {
  1074. RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer);
  1075. }
  1076. }
  1077. else {
  1078. Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
  1079. }
  1080. }
  1081. #if SMP_SHOW_REGISTRY_DATA
  1082. DbgPrint( "SMSS: Unused SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value );
  1083. #endif
  1084. Next = Next->Flink;
  1085. }
  1086. Next = SmpSubSystemsToLoad.Flink;
  1087. while ( Next != &SmpSubSystemsToLoad ) {
  1088. p = CONTAINING_RECORD( Next,
  1089. SMP_REGISTRY_VALUE,
  1090. Entry
  1091. );
  1092. #if SMP_SHOW_REGISTRY_DATA
  1093. DbgPrint( "SMSS: Loaded SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value );
  1094. #endif
  1095. if (!_wcsicmp( p->Name.Buffer, L"debug" )) {
  1096. Status = SmpExecuteCommand( &p->Value, *pMuSessionId, pWindowsSubSysProcessId, SMP_SUBSYSTEM_FLAG | SMP_DEBUG_FLAG );
  1097. }
  1098. else {
  1099. Status = SmpExecuteCommand( &p->Value, *pMuSessionId, pWindowsSubSysProcessId, SMP_SUBSYSTEM_FLAG );
  1100. }
  1101. if ( !NT_SUCCESS(Status) ) {
  1102. DbgPrint ("SMSS: Subsystem execute failed (%WZ)\n", &p->Value);
  1103. return( Status );
  1104. }
  1105. Next = Next->Flink;
  1106. }
  1107. Head = &SmpExecuteList;
  1108. if ( !IsListEmpty( Head ) ) {
  1109. Next = Head->Blink;
  1110. p = CONTAINING_RECORD( Next,
  1111. SMP_REGISTRY_VALUE,
  1112. Entry
  1113. );
  1114. *InitialCommand = p->Name;
  1115. //
  1116. // This path is only taken when people want to run ntsd -p -1 winlogon
  1117. //
  1118. // This is nearly impossible to do in a race free manner. In some
  1119. // cases, we can get in a state where we can not properly fail
  1120. // a debug API. This is due to the subsystem switch that occurs
  1121. // when ntsd is invoked on csr. If csr is relatively idle, this
  1122. // does not occur. If it is active when you attach, then we can get
  1123. // into a potential race. The slimy fix is to do a 5 second delay
  1124. // if the command line is anything other that the default.
  1125. //
  1126. {
  1127. LARGE_INTEGER DelayTime;
  1128. DelayTime.QuadPart = Int32x32To64( 5000, -10000 );
  1129. NtDelayExecution(
  1130. FALSE,
  1131. &DelayTime
  1132. );
  1133. }
  1134. }
  1135. else {
  1136. RtlInitUnicodeString( InitialCommand, L"winlogon.exe" );
  1137. InitialCommandBuffer[ 0 ] = UNICODE_NULL;
  1138. Status1 = LdrQueryImageFileExecutionOptions( InitialCommand,
  1139. L"Debugger",
  1140. REG_SZ,
  1141. InitialCommandBuffer,
  1142. sizeof( InitialCommandBuffer ) - InitialCommand->Length - sizeof (WCHAR),
  1143. NULL);
  1144. if (NT_SUCCESS (Status1) && InitialCommandBuffer[ 0 ] != UNICODE_NULL) {
  1145. wcscat( InitialCommandBuffer, L" " );
  1146. wcscat( InitialCommandBuffer, InitialCommand->Buffer );
  1147. RtlInitUnicodeString( InitialCommand, InitialCommandBuffer );
  1148. }
  1149. }
  1150. Next = SmpExecuteList.Flink;
  1151. while( Next != &SmpExecuteList ) {
  1152. //
  1153. // We do not want to execute the last entry. It's
  1154. // the winlogon initial command.
  1155. //
  1156. if( Next == SmpExecuteList.Blink ) {
  1157. Next = Next->Flink;
  1158. continue;
  1159. }
  1160. p = CONTAINING_RECORD( Next,
  1161. SMP_REGISTRY_VALUE,
  1162. Entry
  1163. );
  1164. #if SMP_SHOW_REGISTRY_DATA
  1165. DbgPrint( "SMSS: Execute( %wZ )\n", &p->Name );
  1166. #endif
  1167. SmpExecuteCommand( &p->Name, *pMuSessionId, NULL, 0 );
  1168. Next = Next->Flink;
  1169. }
  1170. #if SMP_SHOW_REGISTRY_DATA
  1171. DbgPrint( "SMSS: InitialCommand( %wZ )\n", InitialCommand );
  1172. #endif
  1173. return( Status );
  1174. }
  1175. NTSTATUS
  1176. SmpCreateDynamicEnvironmentVariables(
  1177. VOID
  1178. )
  1179. {
  1180. NTSTATUS Status;
  1181. SYSTEM_BASIC_INFORMATION SystemInfo;
  1182. SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
  1183. OBJECT_ATTRIBUTES ObjectAttributes;
  1184. UNICODE_STRING KeyName;
  1185. UNICODE_STRING ValueName;
  1186. PWSTR ValueData;
  1187. WCHAR ValueBuffer[ 256 ];
  1188. WCHAR ValueBuffer1[ 256 ];
  1189. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  1190. ULONG ValueLength;
  1191. HANDLE Key, Key1;
  1192. Status = NtQuerySystemInformation( SystemBasicInformation,
  1193. &SystemInfo,
  1194. sizeof( SystemInfo ),
  1195. NULL
  1196. );
  1197. if (!NT_SUCCESS( Status )) {
  1198. KdPrintEx((DPFLTR_SMSS_ID,
  1199. DPFLTR_WARNING_LEVEL,
  1200. "SMSS: Unable to query system basic information - %x\n",
  1201. Status));
  1202. return Status;
  1203. }
  1204. Status = NtQuerySystemInformation( SystemProcessorInformation,
  1205. &ProcessorInfo,
  1206. sizeof( ProcessorInfo ),
  1207. NULL
  1208. );
  1209. if (!NT_SUCCESS( Status )) {
  1210. KdPrintEx((DPFLTR_SMSS_ID,
  1211. DPFLTR_WARNING_LEVEL,
  1212. "SMSS: Unable to query system processor information - %x\n",
  1213. Status));
  1214. return Status;
  1215. }
  1216. RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Environment" );
  1217. InitializeObjectAttributes( &ObjectAttributes,
  1218. &KeyName,
  1219. OBJ_CASE_INSENSITIVE,
  1220. NULL,
  1221. NULL
  1222. );
  1223. Status = NtOpenKey( &Key, KEY_ALL_ACCESS, &ObjectAttributes );
  1224. if (!NT_SUCCESS( Status )) {
  1225. KdPrintEx((DPFLTR_SMSS_ID,
  1226. DPFLTR_WARNING_LEVEL,
  1227. "SMSS: Unable to open %wZ - %x\n",
  1228. &KeyName,
  1229. Status));
  1230. return Status;
  1231. }
  1232. RtlInitUnicodeString( &ValueName, L"OS" );
  1233. ValueData = L"Windows_NT";
  1234. Status = NtSetValueKey( Key,
  1235. &ValueName,
  1236. 0,
  1237. REG_SZ,
  1238. ValueData,
  1239. (wcslen( ValueData ) + 1) * sizeof( WCHAR )
  1240. );
  1241. if (!NT_SUCCESS( Status )) {
  1242. KdPrintEx((DPFLTR_SMSS_ID,
  1243. DPFLTR_WARNING_LEVEL,
  1244. "SMSS: Failed writing %wZ environment variable - %x\n",
  1245. &ValueName,
  1246. Status));
  1247. goto failexit;
  1248. }
  1249. RtlInitUnicodeString( &ValueName, L"PROCESSOR_ARCHITECTURE" );
  1250. switch( ProcessorInfo.ProcessorArchitecture ) {
  1251. case PROCESSOR_ARCHITECTURE_INTEL:
  1252. ValueData = L"x86";
  1253. break;
  1254. case PROCESSOR_ARCHITECTURE_IA64:
  1255. ValueData = L"IA64";
  1256. break;
  1257. case PROCESSOR_ARCHITECTURE_AMD64:
  1258. ValueData = L"AMD64";
  1259. break;
  1260. default:
  1261. ValueData = L"Unknown";
  1262. break;
  1263. }
  1264. Status = NtSetValueKey( Key,
  1265. &ValueName,
  1266. 0,
  1267. REG_SZ,
  1268. ValueData,
  1269. (wcslen( ValueData ) + 1) * sizeof( WCHAR )
  1270. );
  1271. if (!NT_SUCCESS( Status )) {
  1272. KdPrintEx((DPFLTR_SMSS_ID,
  1273. DPFLTR_WARNING_LEVEL,
  1274. "SMSS: Failed writing %wZ environment variable - %x\n",
  1275. &ValueName,
  1276. Status));
  1277. goto failexit;
  1278. }
  1279. RtlInitUnicodeString( &ValueName, L"PROCESSOR_LEVEL" );
  1280. switch( ProcessorInfo.ProcessorArchitecture ) {
  1281. case PROCESSOR_ARCHITECTURE_INTEL:
  1282. case PROCESSOR_ARCHITECTURE_IA64:
  1283. case PROCESSOR_ARCHITECTURE_AMD64:
  1284. default:
  1285. //
  1286. // All others use a single level number
  1287. //
  1288. swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel );
  1289. break;
  1290. }
  1291. Status = NtSetValueKey( Key,
  1292. &ValueName,
  1293. 0,
  1294. REG_SZ,
  1295. ValueBuffer,
  1296. (wcslen( ValueBuffer ) + 1) * sizeof( WCHAR )
  1297. );
  1298. if (!NT_SUCCESS( Status )) {
  1299. KdPrintEx((DPFLTR_SMSS_ID,
  1300. DPFLTR_WARNING_LEVEL,
  1301. "SMSS: Failed writing %wZ environment variable - %x\n",
  1302. &ValueName,
  1303. Status));
  1304. goto failexit;
  1305. }
  1306. RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor\\0" );
  1307. InitializeObjectAttributes( &ObjectAttributes,
  1308. &KeyName,
  1309. OBJ_CASE_INSENSITIVE,
  1310. NULL,
  1311. NULL
  1312. );
  1313. Status = NtOpenKey( &Key1, KEY_READ, &ObjectAttributes );
  1314. if (!NT_SUCCESS( Status )) {
  1315. KdPrintEx((DPFLTR_SMSS_ID,
  1316. DPFLTR_WARNING_LEVEL,
  1317. "SMSS: Unable to open %wZ - %x\n",
  1318. &KeyName,
  1319. Status));
  1320. goto failexit;
  1321. }
  1322. RtlInitUnicodeString( &ValueName, L"Identifier" );
  1323. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  1324. Status = NtQueryValueKey( Key1,
  1325. &ValueName,
  1326. KeyValuePartialInformation,
  1327. (PVOID)KeyValueInfo,
  1328. sizeof( ValueBuffer ),
  1329. &ValueLength
  1330. );
  1331. if (!NT_SUCCESS( Status )) {
  1332. NtClose( Key1 );
  1333. KdPrintEx((DPFLTR_SMSS_ID,
  1334. DPFLTR_WARNING_LEVEL,
  1335. "SMSS: Unable to read %wZ\\%wZ - %x\n",
  1336. &KeyName,
  1337. &ValueName,
  1338. Status));
  1339. goto failexit;
  1340. }
  1341. ValueData = (PWSTR)KeyValueInfo->Data;
  1342. RtlInitUnicodeString( &ValueName, L"VendorIdentifier" );
  1343. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer1;
  1344. Status = NtQueryValueKey( Key1,
  1345. &ValueName,
  1346. KeyValuePartialInformation,
  1347. (PVOID)KeyValueInfo,
  1348. sizeof( ValueBuffer1 ),
  1349. &ValueLength
  1350. );
  1351. NtClose( Key1 );
  1352. if (NT_SUCCESS( Status )) {
  1353. swprintf( ValueData + wcslen( ValueData ),
  1354. L", %ws",
  1355. (PWSTR)KeyValueInfo->Data
  1356. );
  1357. }
  1358. RtlInitUnicodeString( &ValueName, L"PROCESSOR_IDENTIFIER" );
  1359. Status = NtSetValueKey( Key,
  1360. &ValueName,
  1361. 0,
  1362. REG_SZ,
  1363. ValueData,
  1364. (wcslen( ValueData ) + 1) * sizeof( WCHAR )
  1365. );
  1366. if (!NT_SUCCESS( Status )) {
  1367. KdPrintEx((DPFLTR_SMSS_ID,
  1368. DPFLTR_WARNING_LEVEL,
  1369. "SMSS: Failed writing %wZ environment variable - %x\n",
  1370. &ValueName,
  1371. Status));
  1372. goto failexit;
  1373. }
  1374. RtlInitUnicodeString( &ValueName, L"PROCESSOR_REVISION" );
  1375. switch( ProcessorInfo.ProcessorArchitecture ) {
  1376. case PROCESSOR_ARCHITECTURE_INTEL:
  1377. if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF) {
  1378. //
  1379. // Intel 386/486 are An stepping format
  1380. //
  1381. swprintf( ValueBuffer, L"%02x",
  1382. ProcessorInfo.ProcessorRevision & 0xFF
  1383. );
  1384. _wcsupr( ValueBuffer );
  1385. break;
  1386. }
  1387. //
  1388. // Post-486 processors will fall through
  1389. //
  1390. case PROCESSOR_ARCHITECTURE_IA64:
  1391. case PROCESSOR_ARCHITECTURE_AMD64:
  1392. //
  1393. // Modern X86 processors, IA64 and Amd64 use a fixed point
  1394. // binary number. Output is 4 hex digits, no formatting.
  1395. //
  1396. swprintf( ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision );
  1397. break;
  1398. default:
  1399. //
  1400. // All others use a single revision number
  1401. //
  1402. swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision );
  1403. break;
  1404. }
  1405. Status = NtSetValueKey( Key,
  1406. &ValueName,
  1407. 0,
  1408. REG_SZ,
  1409. ValueBuffer,
  1410. (wcslen( ValueBuffer ) + 1) * sizeof( WCHAR )
  1411. );
  1412. if (!NT_SUCCESS( Status )) {
  1413. KdPrintEx((DPFLTR_SMSS_ID,
  1414. DPFLTR_WARNING_LEVEL,
  1415. "SMSS: Failed writing %wZ environment variable - %x\n",
  1416. &ValueName,
  1417. Status));
  1418. goto failexit;
  1419. }
  1420. RtlInitUnicodeString( &ValueName, L"NUMBER_OF_PROCESSORS" );
  1421. swprintf( ValueBuffer, L"%u", SystemInfo.NumberOfProcessors );
  1422. Status = NtSetValueKey( Key,
  1423. &ValueName,
  1424. 0,
  1425. REG_SZ,
  1426. ValueBuffer,
  1427. (wcslen( ValueBuffer ) + 1) * sizeof( WCHAR )
  1428. );
  1429. if (!NT_SUCCESS( Status )) {
  1430. KdPrintEx((DPFLTR_SMSS_ID,
  1431. DPFLTR_WARNING_LEVEL,
  1432. "SMSS: Failed writing %wZ environment variable - %x\n",
  1433. &ValueName,
  1434. Status));
  1435. goto failexit;
  1436. }
  1437. //
  1438. // get the safeboot option
  1439. //
  1440. RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Safeboot\\Option" );
  1441. InitializeObjectAttributes(
  1442. &ObjectAttributes,
  1443. &KeyName,
  1444. OBJ_CASE_INSENSITIVE,
  1445. NULL,
  1446. NULL
  1447. );
  1448. Status = NtOpenKey( &Key1, KEY_ALL_ACCESS, &ObjectAttributes );
  1449. if (NT_SUCCESS(Status)) {
  1450. RtlInitUnicodeString( &ValueName, L"OptionValue" );
  1451. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  1452. Status = NtQueryValueKey(
  1453. Key1,
  1454. &ValueName,
  1455. KeyValuePartialInformation,
  1456. (PVOID)KeyValueInfo,
  1457. sizeof(ValueBuffer),
  1458. &ValueLength
  1459. );
  1460. NtClose( Key1 );
  1461. if (NT_SUCCESS(Status)) {
  1462. RtlInitUnicodeString( &ValueName, L"SAFEBOOT_OPTION" );
  1463. switch (*(PULONG)(KeyValueInfo->Data)) {
  1464. case SAFEBOOT_MINIMAL:
  1465. wcscpy(ValueBuffer,SAFEBOOT_MINIMAL_STR_W);
  1466. break;
  1467. case SAFEBOOT_NETWORK:
  1468. wcscpy(ValueBuffer,SAFEBOOT_NETWORK_STR_W);
  1469. break;
  1470. case SAFEBOOT_DSREPAIR:
  1471. wcscpy(ValueBuffer,SAFEBOOT_DSREPAIR_STR_W);
  1472. break;
  1473. }
  1474. Status = NtSetValueKey(
  1475. Key,
  1476. &ValueName,
  1477. 0,
  1478. REG_SZ,
  1479. ValueBuffer,
  1480. (wcslen(ValueBuffer)+1) * sizeof( WCHAR )
  1481. );
  1482. if (!NT_SUCCESS( Status )) {
  1483. KdPrintEx((DPFLTR_SMSS_ID,
  1484. DPFLTR_WARNING_LEVEL,
  1485. "SMSS: Failed writing %wZ environment variable - %x\n",
  1486. &ValueName,
  1487. Status));
  1488. goto failexit;
  1489. }
  1490. } else {
  1491. KdPrintEx((DPFLTR_SMSS_ID,
  1492. DPFLTR_WARNING_LEVEL,
  1493. "SMSS: Failed querying safeboot option = %x\n",
  1494. Status));
  1495. }
  1496. }
  1497. Status = STATUS_SUCCESS;
  1498. failexit:
  1499. NtClose( Key );
  1500. return Status;
  1501. }
  1502. NTSTATUS
  1503. SmpInitializeDosDevices( VOID )
  1504. {
  1505. NTSTATUS Status;
  1506. PLIST_ENTRY Head, Next;
  1507. PSMP_REGISTRY_VALUE p;
  1508. UNICODE_STRING UnicodeString;
  1509. OBJECT_ATTRIBUTES ObjectAttributes;
  1510. HANDLE LinkHandle;
  1511. SECURITY_DESCRIPTOR_CONTROL OriginalSdControl=0;
  1512. //
  1513. // Do DosDevices initialization - the directory object is created in I/O init
  1514. //
  1515. RtlInitUnicodeString( &UnicodeString, L"\\??" );
  1516. InitializeObjectAttributes( &ObjectAttributes,
  1517. &UnicodeString,
  1518. OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
  1519. NULL,
  1520. NULL
  1521. );
  1522. Status = NtOpenDirectoryObject( &SmpDosDevicesObjectDirectory,
  1523. DIRECTORY_ALL_ACCESS,
  1524. &ObjectAttributes
  1525. );
  1526. if (!NT_SUCCESS( Status )) {
  1527. KdPrintEx((DPFLTR_SMSS_ID,
  1528. DPFLTR_WARNING_LEVEL,
  1529. "SMSS: Unable to open %wZ directory - Status == %lx\n",
  1530. &UnicodeString,
  1531. Status));
  1532. return( Status );
  1533. }
  1534. //
  1535. // Process the list of defined DOS devices and create their
  1536. // associated symbolic links in the \DosDevices object directory.
  1537. //
  1538. Head = &SmpDosDevicesList;
  1539. while (!IsListEmpty( Head )) {
  1540. Next = RemoveHeadList( Head );
  1541. p = CONTAINING_RECORD( Next,
  1542. SMP_REGISTRY_VALUE,
  1543. Entry
  1544. );
  1545. #if SMP_SHOW_REGISTRY_DATA
  1546. DbgPrint( "SMSS: DosDevices( %wZ = %wZ )\n", &p->Name, &p->Value );
  1547. #endif
  1548. InitializeObjectAttributes( &ObjectAttributes,
  1549. &p->Name,
  1550. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF,
  1551. SmpDosDevicesObjectDirectory,
  1552. SmpPrimarySecurityDescriptor
  1553. );
  1554. SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //Use inheritable protection if available
  1555. Status = NtCreateSymbolicLinkObject( &LinkHandle,
  1556. SYMBOLIC_LINK_ALL_ACCESS,
  1557. &ObjectAttributes,
  1558. &p->Value
  1559. );
  1560. if (Status == STATUS_OBJECT_NAME_EXISTS) {
  1561. NtMakeTemporaryObject( LinkHandle );
  1562. NtClose( LinkHandle );
  1563. if (p->Value.Length != 0) {
  1564. ObjectAttributes.Attributes &= ~OBJ_OPENIF;
  1565. Status = NtCreateSymbolicLinkObject( &LinkHandle,
  1566. SYMBOLIC_LINK_ALL_ACCESS,
  1567. &ObjectAttributes,
  1568. &p->Value
  1569. );
  1570. }
  1571. else {
  1572. Status = STATUS_SUCCESS;
  1573. }
  1574. }
  1575. SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl );
  1576. if (!NT_SUCCESS( Status )) {
  1577. KdPrintEx((DPFLTR_SMSS_ID,
  1578. DPFLTR_WARNING_LEVEL,
  1579. "SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n",
  1580. &p->Name,
  1581. &p->Value,
  1582. Status));
  1583. return( Status );
  1584. }
  1585. NtClose( LinkHandle );
  1586. if (p->AnsiValue) { RtlFreeHeap( RtlProcessHeap(), 0, p->AnsiValue ); }
  1587. if (p->Value.Buffer) { RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer ); }
  1588. RtlFreeHeap( RtlProcessHeap(), 0, p );
  1589. }
  1590. return( Status );
  1591. }
  1592. VOID
  1593. SmpProcessModuleImports(
  1594. IN PVOID Parameter,
  1595. IN PCHAR ModuleName
  1596. )
  1597. {
  1598. NTSTATUS Status;
  1599. WCHAR NameBuffer[ DOS_MAX_PATH_LENGTH ];
  1600. UNICODE_STRING UnicodeString;
  1601. ANSI_STRING AnsiString;
  1602. PWSTR Name, Value;
  1603. ULONG n;
  1604. PWSTR s;
  1605. //
  1606. // Skip NTDLL.DLL as it is implicitly added to KnownDll list by kernel
  1607. // before SMSS.EXE is started.
  1608. //
  1609. if (!_stricmp( ModuleName, "ntdll.dll" )) {
  1610. return;
  1611. }
  1612. RtlInitAnsiString( &AnsiString, ModuleName );
  1613. UnicodeString.Buffer = NameBuffer;
  1614. UnicodeString.Length = 0;
  1615. UnicodeString.MaximumLength = sizeof( NameBuffer );
  1616. Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE );
  1617. if (!NT_SUCCESS( Status )) {
  1618. return;
  1619. }
  1620. UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length + sizeof( UNICODE_NULL ));
  1621. s = UnicodeString.Buffer;
  1622. n = 0;
  1623. while (n < UnicodeString.Length) {
  1624. if (*s == L'.') {
  1625. break;
  1626. } else {
  1627. n += sizeof( WCHAR );
  1628. s += 1;
  1629. }
  1630. }
  1631. Value = UnicodeString.Buffer;
  1632. Name = UnicodeString.Buffer + (UnicodeString.MaximumLength / sizeof( WCHAR ));
  1633. n = n / sizeof( WCHAR );
  1634. if ((Name - Value) + n >= DOS_MAX_PATH_LENGTH) {
  1635. return;
  1636. }
  1637. wcsncpy( Name, Value, n );
  1638. Name[ n ] = UNICODE_NULL;
  1639. Status = SmpSaveRegistryValue( (PLIST_ENTRY)&SmpKnownDllsList,
  1640. Name,
  1641. Value,
  1642. TRUE
  1643. );
  1644. if (Status == STATUS_OBJECT_NAME_EXISTS || !NT_SUCCESS( Status )) {
  1645. return;
  1646. }
  1647. return;
  1648. }
  1649. NTSTATUS
  1650. SmpInitializeKnownDlls( VOID )
  1651. {
  1652. NTSTATUS Status;
  1653. UNICODE_STRING DirectoryObjectName;
  1654. PLIST_ENTRY Head, Next;
  1655. PSMP_REGISTRY_VALUE p;
  1656. RtlInitUnicodeString( &DirectoryObjectName, L"\\KnownDlls" );
  1657. Status = SmpInitializeKnownDllsInternal(
  1658. &DirectoryObjectName,
  1659. &SmpKnownDllPath);
  1660. #ifdef _WIN64
  1661. if (!MiniNTBoot && NT_SUCCESS(Status))
  1662. {
  1663. RtlInitUnicodeString( &DirectoryObjectName, L"\\KnownDlls32" );
  1664. Status = SmpInitializeKnownDllsInternal(
  1665. &DirectoryObjectName,
  1666. &SmpKnownDllPath32);
  1667. }
  1668. #endif
  1669. Head = &SmpKnownDllsList;
  1670. while (!IsListEmpty( Head )) {
  1671. Next = RemoveHeadList( Head );
  1672. p = CONTAINING_RECORD( Next,
  1673. SMP_REGISTRY_VALUE,
  1674. Entry
  1675. );
  1676. if (p->AnsiValue) { RtlFreeHeap( RtlProcessHeap(), 0, p->AnsiValue ); }
  1677. if (p->Value.Buffer) { RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer ); }
  1678. RtlFreeHeap( RtlProcessHeap(), 0, p );
  1679. }
  1680. return Status;
  1681. }
  1682. NTSTATUS
  1683. SmpInitializeKnownDllsInternal(
  1684. IN PUNICODE_STRING ObjectDirectoryName,
  1685. IN PUNICODE_STRING KnownDllPath
  1686. )
  1687. {
  1688. NTSTATUS Status, Status1;
  1689. PLIST_ENTRY Head, Next;
  1690. PSMP_REGISTRY_VALUE p;
  1691. PSMP_REGISTRY_VALUE pExclude;
  1692. UNICODE_STRING UnicodeString;
  1693. OBJECT_ATTRIBUTES ObjectAttributes;
  1694. HANDLE LinkHandle, FileHandle, SectionHandle;
  1695. IO_STATUS_BLOCK IoStatusBlock;
  1696. UNICODE_STRING FileName;
  1697. SECURITY_DESCRIPTOR_CONTROL OriginalSdControl;
  1698. USHORT ImageCharacteristics;
  1699. HANDLE KnownDllFileDirectory = NULL;
  1700. HANDLE KnownDllObjectDirectory = NULL;
  1701. FileName.Buffer = NULL;
  1702. //
  1703. // Create \KnownDllsxx object directory
  1704. //
  1705. InitializeObjectAttributes (&ObjectAttributes,
  1706. ObjectDirectoryName,
  1707. OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
  1708. NULL,
  1709. SmpKnownDllsSecurityDescriptor);
  1710. Status = NtCreateDirectoryObject (&KnownDllObjectDirectory,
  1711. DIRECTORY_ALL_ACCESS,
  1712. &ObjectAttributes);
  1713. if (!NT_SUCCESS (Status)) {
  1714. KdPrintEx((DPFLTR_SMSS_ID,
  1715. DPFLTR_WARNING_LEVEL,
  1716. "SMSS: Unable to create %wZ directory - Status == %lx\n",
  1717. ObjectDirectoryName,
  1718. Status));
  1719. return Status;
  1720. }
  1721. //
  1722. // Open a handle to the file system directory that contains all the
  1723. // known DLL files so we can do relative opens.
  1724. //
  1725. if (!RtlDosPathNameToNtPathName_U (KnownDllPath->Buffer,
  1726. &FileName,
  1727. NULL,
  1728. NULL)) {
  1729. KdPrintEx((DPFLTR_SMSS_ID,
  1730. DPFLTR_WARNING_LEVEL,
  1731. "SMSS: Unable to to convert %wZ to an Nt path\n",
  1732. KnownDllPath));
  1733. Status = STATUS_OBJECT_NAME_INVALID;
  1734. goto exit_and_free;
  1735. }
  1736. InitializeObjectAttributes (&ObjectAttributes,
  1737. &FileName,
  1738. OBJ_CASE_INSENSITIVE,
  1739. NULL,
  1740. NULL);
  1741. //
  1742. // Open a handle to the known dll file directory. Don't allow
  1743. // deletes of the directory.
  1744. //
  1745. Status = NtOpenFile (&KnownDllFileDirectory,
  1746. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  1747. &ObjectAttributes,
  1748. &IoStatusBlock,
  1749. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1750. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  1751. if (!NT_SUCCESS (Status)) {
  1752. KdPrintEx((DPFLTR_SMSS_ID,
  1753. DPFLTR_WARNING_LEVEL,
  1754. "SMSS: Unable to open a handle to the KnownDll directory (%wZ) - Status == %lx\n",
  1755. KnownDllPath,
  1756. Status));
  1757. KnownDllFileDirectory = NULL;
  1758. goto exit_and_free;
  1759. }
  1760. RtlInitUnicodeString (&UnicodeString, L"KnownDllPath");
  1761. InitializeObjectAttributes (&ObjectAttributes,
  1762. &UnicodeString,
  1763. OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
  1764. KnownDllObjectDirectory,
  1765. SmpPrimarySecurityDescriptor);
  1766. SmpSetDaclDefaulted (&ObjectAttributes, &OriginalSdControl); //Use inheritable protection if available
  1767. Status = NtCreateSymbolicLinkObject (&LinkHandle,
  1768. SYMBOLIC_LINK_ALL_ACCESS,
  1769. &ObjectAttributes,
  1770. KnownDllPath);
  1771. SmpRestoreDaclDefaulted (&ObjectAttributes, OriginalSdControl);
  1772. if (!NT_SUCCESS (Status)) {
  1773. KdPrintEx((DPFLTR_SMSS_ID,
  1774. DPFLTR_WARNING_LEVEL,
  1775. "SMSS: Unable to create %wZ symbolic link - Status == %lx\n",
  1776. &UnicodeString,
  1777. Status));
  1778. LinkHandle = NULL;
  1779. goto exit_and_free;
  1780. }
  1781. Status1 = NtClose (LinkHandle);
  1782. ASSERT (NT_SUCCESS (Status1));
  1783. Head = &SmpKnownDllsList;
  1784. Next = Head->Flink;
  1785. while (Next != Head) {
  1786. HANDLE ObjectDirectory;
  1787. ObjectDirectory = NULL;
  1788. p = CONTAINING_RECORD (Next,
  1789. SMP_REGISTRY_VALUE,
  1790. Entry);
  1791. pExclude = SmpFindRegistryValue (&SmpExcludeKnownDllsList, p->Name.Buffer);
  1792. if (pExclude == NULL) {
  1793. pExclude = SmpFindRegistryValue (&SmpExcludeKnownDllsList, p->Value.Buffer);
  1794. }
  1795. if (pExclude != NULL) {
  1796. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1797. } else {
  1798. #if SMP_SHOW_REGISTRY_DATA
  1799. DbgPrint( "SMSS: KnownDll( %wZ = %wZ )\n", &p->Name, &p->Value );
  1800. #endif
  1801. InitializeObjectAttributes (&ObjectAttributes,
  1802. &p->Value,
  1803. OBJ_CASE_INSENSITIVE,
  1804. KnownDllFileDirectory,
  1805. NULL);
  1806. Status = NtOpenFile (&FileHandle,
  1807. SYNCHRONIZE | FILE_EXECUTE,
  1808. &ObjectAttributes,
  1809. &IoStatusBlock,
  1810. FILE_SHARE_READ | FILE_SHARE_DELETE,
  1811. FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
  1812. }
  1813. if (NT_SUCCESS (Status)) {
  1814. //
  1815. // We want the side effects of this call (import
  1816. // callout, but don't want to checksum anymore, so supress with
  1817. // handle tag bit
  1818. //
  1819. ObjectDirectory = KnownDllObjectDirectory;
  1820. Status = LdrVerifyImageMatchesChecksum ((HANDLE)((UINT_PTR)FileHandle|1),
  1821. SmpProcessModuleImports,
  1822. Next,
  1823. &ImageCharacteristics);
  1824. if ( Status == STATUS_IMAGE_CHECKSUM_MISMATCH ) {
  1825. ULONG_PTR ErrorParameters;
  1826. ULONG ErrorResponse;
  1827. //
  1828. // Hard error time. One of the know DLL's is corrupt !
  1829. //
  1830. ErrorParameters = (ULONG_PTR)(&p->Value);
  1831. NtRaiseHardError (Status,
  1832. 1,
  1833. 1,
  1834. &ErrorParameters,
  1835. OptionOk,
  1836. &ErrorResponse);
  1837. } else if (ImageCharacteristics & IMAGE_FILE_DLL) {
  1838. InitializeObjectAttributes (&ObjectAttributes,
  1839. &p->Value,
  1840. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  1841. ObjectDirectory,
  1842. SmpLiberalSecurityDescriptor);
  1843. SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //use inheritable protection if available
  1844. Status = NtCreateSection (&SectionHandle,
  1845. SECTION_ALL_ACCESS,
  1846. &ObjectAttributes,
  1847. NULL,
  1848. PAGE_EXECUTE,
  1849. SEC_IMAGE,
  1850. FileHandle);
  1851. SmpRestoreDaclDefaulted (&ObjectAttributes, OriginalSdControl);
  1852. if (!NT_SUCCESS (Status)) {
  1853. KdPrintEx((DPFLTR_SMSS_ID,
  1854. DPFLTR_WARNING_LEVEL,
  1855. "SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n",
  1856. &p->Value,
  1857. Status));
  1858. } else {
  1859. Status1 = NtClose (SectionHandle);
  1860. ASSERT (NT_SUCCESS (Status1));
  1861. }
  1862. } else {
  1863. KdPrintEx((DPFLTR_SMSS_ID,
  1864. DPFLTR_WARNING_LEVEL,
  1865. "SMSS: Ignoring %wZ as KnownDll since it is not a DLL\n",
  1866. &p->Value));
  1867. }
  1868. Status1 = NtClose (FileHandle);
  1869. ASSERT (NT_SUCCESS (Status1));
  1870. }
  1871. Next = Next->Flink;
  1872. //
  1873. // Note that section remains open. This will keep it around.
  1874. // Maybe this should be a permenent section ?
  1875. //
  1876. }
  1877. Status = STATUS_SUCCESS;
  1878. exit_and_free:
  1879. if (KnownDllObjectDirectory != NULL) {
  1880. Status1 = NtClose (KnownDllObjectDirectory);
  1881. ASSERT (NT_SUCCESS (Status1));
  1882. }
  1883. if (KnownDllFileDirectory != NULL) {
  1884. Status1 = NtClose (KnownDllFileDirectory);
  1885. ASSERT (NT_SUCCESS (Status1));
  1886. }
  1887. if (FileName.Buffer != NULL) {
  1888. RtlFreeHeap (RtlProcessHeap (), 0, FileName.Buffer);
  1889. }
  1890. return Status;
  1891. }
  1892. NTSTATUS
  1893. SmpSetProtectedFilesEnvVars(
  1894. IN BOOLEAN SetEnvVar
  1895. )
  1896. /*++
  1897. Routine Description:
  1898. This function sets some environment variables that are not part of the
  1899. default environment. (These environment variables are normally set by
  1900. winlogon.) The environment variables need to be set for us to resolve
  1901. all the environment variables in our protected files list.
  1902. Note that SFC mirrors the data into the location below since smss can't
  1903. get at the actual variable location
  1904. The variables are:
  1905. ProgramFiles
  1906. CommonProgramFiles
  1907. ProgramFiles(x86)
  1908. CommonProgramFiles(x86)
  1909. Arguments:
  1910. SetEnvVar - if TRUE, we should query the registry for this variables and
  1911. set them. if FALSE, we should clear the environment variables
  1912. Return Value:
  1913. Status of operation
  1914. --*/
  1915. {
  1916. NTSTATUS Status;
  1917. UNICODE_STRING KeyName;
  1918. UNICODE_STRING ValueName;
  1919. UNICODE_STRING EnvVar;
  1920. UNICODE_STRING EnvVarValue;
  1921. OBJECT_ATTRIBUTES ObjectAttributes;
  1922. HANDLE Key;
  1923. WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  1924. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  1925. ULONG ValueLength;
  1926. ULONG Count;
  1927. PCWSTR RegistryValues[] = {
  1928. L"ProgramFilesDir"
  1929. , L"CommonFilesDir"
  1930. #ifdef WX86
  1931. , L"ProgramFilesDir(x86)"
  1932. , L"CommonFilesDir(x86)"
  1933. #endif
  1934. };
  1935. PCWSTR EnvVars[] = {
  1936. L"ProgramFiles"
  1937. , L"CommonProgramFiles"
  1938. #ifdef WX86
  1939. , L"ProgramFiles(x86)"
  1940. , L"CommonProgramFiles(x86)"
  1941. #endif
  1942. };
  1943. #define EnvVarCount sizeof(RegistryValues)/sizeof(PCWSTR)
  1944. if (SetEnvVar) {
  1945. //
  1946. // Open the registry key.
  1947. //
  1948. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  1949. RtlInitUnicodeString(&KeyName,
  1950. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\SFC");
  1951. InitializeObjectAttributes(&ObjectAttributes,
  1952. &KeyName,
  1953. OBJ_CASE_INSENSITIVE,
  1954. NULL,
  1955. NULL);
  1956. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  1957. if (!NT_SUCCESS(Status)) {
  1958. KdPrintEx((DPFLTR_SMSS_ID,
  1959. DPFLTR_WARNING_LEVEL,
  1960. "SMSS: can't open control key: 0x%x\n",
  1961. Status));
  1962. return Status;
  1963. }
  1964. //
  1965. // Query the key values.
  1966. //
  1967. for (Count = 0; Count < EnvVarCount; Count++) {
  1968. RtlInitUnicodeString(&ValueName, RegistryValues[Count]);
  1969. Status = NtQueryValueKey(Key,
  1970. &ValueName,
  1971. KeyValuePartialInformation,
  1972. (PVOID)KeyValueInfo,
  1973. sizeof (ValueBuffer),
  1974. &ValueLength);
  1975. ASSERT(ValueLength < VALUE_BUFFER_SIZE);
  1976. if (!NT_SUCCESS(Status)) {
  1977. KdPrintEx((DPFLTR_SMSS_ID,
  1978. DPFLTR_WARNING_LEVEL,
  1979. "SMSS: can't query value key %ws: 0x%x\n",
  1980. RegistryValues[Count],
  1981. Status));
  1982. } else {
  1983. ASSERT(KeyValueInfo->Type == REG_SZ);
  1984. RtlInitUnicodeString(&EnvVar, EnvVars[Count]);
  1985. EnvVarValue.Length = (USHORT)KeyValueInfo->DataLength;
  1986. EnvVarValue.MaximumLength = (USHORT)KeyValueInfo->DataLength;
  1987. EnvVarValue.Buffer = (PWSTR)KeyValueInfo->Data;
  1988. Status = RtlSetEnvironmentVariable( NULL,
  1989. &EnvVar,
  1990. &EnvVarValue
  1991. );
  1992. if (!NT_SUCCESS(Status)) {
  1993. KdPrintEx((DPFLTR_SMSS_ID,
  1994. DPFLTR_WARNING_LEVEL,
  1995. "SMSS: can't set environment variable %ws: 0x%x\n",
  1996. EnvVars[Count],
  1997. Status));
  1998. }
  1999. }
  2000. }
  2001. NtClose(Key);
  2002. } else {
  2003. //
  2004. // clear out the variables
  2005. //
  2006. for (Count = 0; Count < EnvVarCount; Count++) {
  2007. RtlInitUnicodeString(&EnvVar, EnvVars[Count]);
  2008. RtlInitUnicodeString(&EnvVarValue, NULL);
  2009. Status = RtlSetEnvironmentVariable( NULL,
  2010. &EnvVar,
  2011. &EnvVarValue
  2012. );
  2013. if (!NT_SUCCESS(Status)) {
  2014. KdPrintEx((DPFLTR_SMSS_ID,
  2015. DPFLTR_WARNING_LEVEL,
  2016. "SMSS: can't clear environment variable %ws: 0x%x\n",
  2017. EnvVars[Count],
  2018. Status));
  2019. }
  2020. }
  2021. }
  2022. return Status;
  2023. }
  2024. NTSTATUS
  2025. SmpGetProtectedFiles(
  2026. OUT PPROTECT_FILE_ENTRY *Files,
  2027. OUT PULONG FileCount,
  2028. OUT PVOID *hModule
  2029. )
  2030. {
  2031. NTSTATUS Status;
  2032. UNICODE_STRING DllName;
  2033. STRING ProcedureName;
  2034. PSFCGETFILES pSfcGetFiles;
  2035. ASSERT(hModule != NULL);
  2036. *hModule = NULL;
  2037. RtlInitUnicodeString( &DllName, L"sfcfiles.dll" );
  2038. Status = LdrLoadDll(
  2039. NULL,
  2040. NULL,
  2041. &DllName,
  2042. hModule
  2043. );
  2044. if (!NT_SUCCESS( Status )) {
  2045. KdPrintEx((DPFLTR_SMSS_ID,
  2046. DPFLTR_WARNING_LEVEL,
  2047. "SMSS: LdrLoadDll failed for %ws, ec=%lx\n",
  2048. DllName.Buffer,
  2049. Status));
  2050. return Status;
  2051. }
  2052. RtlInitString( &ProcedureName, "SfcGetFiles" );
  2053. Status = LdrGetProcedureAddress(
  2054. *hModule,
  2055. &ProcedureName,
  2056. 0,
  2057. (PVOID*)&pSfcGetFiles
  2058. );
  2059. if (NT_SUCCESS(Status)) {
  2060. #if SMP_SHOW_REGISTRY_DATA
  2061. DbgPrint( "SMSS: sfcfile.dll loaded successfully, address=%08x\n", *hModule );
  2062. #endif
  2063. Status = pSfcGetFiles( Files, FileCount );
  2064. }
  2065. else {
  2066. KdPrintEx((DPFLTR_SMSS_ID,
  2067. DPFLTR_WARNING_LEVEL,
  2068. "SMSS: LdrGetProcedureAddress failed for %ws, ec=%lx\n",
  2069. ProcedureName.Buffer,
  2070. Status));
  2071. LdrUnloadDll(*hModule);
  2072. *hModule = NULL;
  2073. }
  2074. return Status;
  2075. }
  2076. LONG
  2077. SpecialStringCompare(
  2078. PUNICODE_STRING s1,
  2079. PUNICODE_STRING s2
  2080. )
  2081. {
  2082. UNICODE_STRING tmp;
  2083. if (s1->Buffer[0] != L'!') {
  2084. return RtlCompareUnicodeString( s1, s2, TRUE );
  2085. }
  2086. tmp.Length = s1->Length - sizeof(WCHAR);
  2087. tmp.MaximumLength = s1->MaximumLength - sizeof(WCHAR);
  2088. tmp.Buffer = s1->Buffer + 1;
  2089. return RtlCompareUnicodeString( &tmp, s2, TRUE );
  2090. }
  2091. VOID
  2092. SmpProcessFileRenames( VOID )
  2093. {
  2094. NTSTATUS Status,OpenStatus;
  2095. PLIST_ENTRY Head, Next;
  2096. PSMP_REGISTRY_VALUE p;
  2097. OBJECT_ATTRIBUTES ObjectAttributes;
  2098. IO_STATUS_BLOCK IoStatusBlock;
  2099. HANDLE OldFileHandle,SetAttributesHandle;
  2100. PFILE_RENAME_INFORMATION RenameInformation;
  2101. FILE_DISPOSITION_INFORMATION DeleteInformation;
  2102. FILE_INFORMATION_CLASS SetInfoClass;
  2103. FILE_BASIC_INFORMATION BasicInfo;
  2104. ULONG SetInfoLength;
  2105. PVOID SetInfoBuffer;
  2106. PWSTR s;
  2107. BOOLEAN WasEnabled;
  2108. UNICODE_STRING NewName;
  2109. ULONG i;
  2110. UNICODE_STRING ProtFileName = {0};
  2111. UNICODE_STRING Tier2Name;
  2112. UNICODE_STRING ProtName;
  2113. PPROTECT_FILE_ENTRY Tier2Files;
  2114. ULONG CountTier2Files;
  2115. PVOID hModule = NULL;
  2116. BOOLEAN EnvVarSet;
  2117. Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  2118. TRUE,
  2119. FALSE,
  2120. &WasEnabled
  2121. );
  2122. if (!NT_SUCCESS( Status )) {
  2123. WasEnabled = TRUE;
  2124. }
  2125. if (SmpAllowProtectedRenames == 0) {
  2126. Status = SmpGetProtectedFiles( &Tier2Files, &CountTier2Files, &hModule );
  2127. if (!NT_SUCCESS( Status )) {
  2128. KdPrintEx((DPFLTR_SMSS_ID,
  2129. DPFLTR_WARNING_LEVEL,
  2130. "SMSS: SmpGetProtectedFiles failed, ec=%08x\n",
  2131. Status));
  2132. SmpAllowProtectedRenames = 1;
  2133. }
  2134. }
  2135. //
  2136. // our list of protected files includes environment variables that are not
  2137. // in the default environment, they are normally set by winlogon. Set
  2138. // those environment variables temporarily until we process the file rename
  2139. // section, then we can clear them out again.
  2140. //
  2141. EnvVarSet = TRUE;
  2142. Status = SmpSetProtectedFilesEnvVars( TRUE );
  2143. if (!NT_SUCCESS( Status )) {
  2144. KdPrintEx((DPFLTR_SMSS_ID,
  2145. DPFLTR_WARNING_LEVEL,
  2146. "SMSS: SmpSetProtectedFilesEnvVars failed, ec=%08x\n",
  2147. Status));
  2148. EnvVarSet = FALSE;
  2149. }
  2150. //
  2151. // Process the list of file rename operations.
  2152. //
  2153. Head = &SmpFileRenameList;
  2154. while (!IsListEmpty( Head )) {
  2155. Next = RemoveHeadList( Head );
  2156. p = CONTAINING_RECORD( Next, SMP_REGISTRY_VALUE, Entry );
  2157. #if SMP_SHOW_REGISTRY_DATA
  2158. DbgPrint( "SMSS: FileRename( [%wZ] => [%wZ] )\n", &p->Name, &p->Value );
  2159. #endif
  2160. //
  2161. // ignore any file that is protected
  2162. //
  2163. if (SmpAllowProtectedRenames == 0) {
  2164. ProtName.MaximumLength = 256 * sizeof(WCHAR);
  2165. ProtName.Buffer = (PWSTR) RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), ProtName.MaximumLength );
  2166. if (ProtName.Buffer) {
  2167. for (i=0; i<CountTier2Files; i++) {
  2168. //
  2169. // if the file name is prefixed by the '@' character
  2170. // then we ignore the check and say the file is ok
  2171. //
  2172. if (p->Name.Buffer[0] == '@' || p->Value.Buffer[0] == L'@') {
  2173. break;
  2174. }
  2175. //
  2176. // convert the tier2 file name to an nt style file name
  2177. //
  2178. RtlInitUnicodeString(&Tier2Name,Tier2Files[i].FileName);
  2179. ProtName.Length = 0;
  2180. RtlZeroMemory( ProtName.Buffer, ProtName.MaximumLength );
  2181. if (ProtName.Buffer == NULL) {
  2182. continue;
  2183. }
  2184. Status = RtlExpandEnvironmentStrings_U(
  2185. NULL,
  2186. &Tier2Name,
  2187. &ProtName,
  2188. NULL
  2189. );
  2190. if (!NT_SUCCESS(Status)) {
  2191. continue;
  2192. }
  2193. if (!RtlDosPathNameToNtPathName_U( ProtName.Buffer, &ProtFileName, NULL, NULL )) {
  2194. continue;
  2195. }
  2196. //
  2197. // check for matches against both file names
  2198. //
  2199. if (SpecialStringCompare( &p->Name, &ProtFileName ) == 0 ||
  2200. SpecialStringCompare( &p->Value, &ProtFileName ) == 0)
  2201. {
  2202. break;
  2203. }
  2204. RtlFreeUnicodeString(&ProtFileName);
  2205. ProtFileName.Buffer = NULL;
  2206. }
  2207. RtlFreeHeap( RtlProcessHeap(), 0, ProtName.Buffer );
  2208. if (i < CountTier2Files) {
  2209. if (p->Name.Buffer[0] == L'@' || p->Value.Buffer[0] == L'@') {
  2210. } else {
  2211. #if SMP_SHOW_REGISTRY_DATA
  2212. DbgPrint( "SMSS: Skipping rename because it is protected\n" );
  2213. #endif
  2214. //
  2215. // delete the source file so we don't leave any turds
  2216. //
  2217. if (p->Value.Length > 0 && ProtFileName.Buffer && SpecialStringCompare( &p->Name, &ProtFileName ) != 0) {
  2218. InitializeObjectAttributes(
  2219. &ObjectAttributes,
  2220. &p->Name,
  2221. OBJ_CASE_INSENSITIVE,
  2222. NULL,
  2223. NULL
  2224. );
  2225. Status = NtOpenFile(
  2226. &OldFileHandle,
  2227. (ACCESS_MASK)DELETE | SYNCHRONIZE,
  2228. &ObjectAttributes,
  2229. &IoStatusBlock,
  2230. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2231. FILE_SYNCHRONOUS_IO_NONALERT
  2232. );
  2233. if (NT_SUCCESS( Status )) {
  2234. SetInfoClass = FileDispositionInformation;
  2235. SetInfoLength = sizeof( DeleteInformation );
  2236. SetInfoBuffer = &DeleteInformation;
  2237. DeleteInformation.DeleteFile = TRUE;
  2238. Status = NtSetInformationFile(
  2239. OldFileHandle,
  2240. &IoStatusBlock,
  2241. SetInfoBuffer,
  2242. SetInfoLength,
  2243. SetInfoClass
  2244. );
  2245. NtClose( OldFileHandle );
  2246. }
  2247. }
  2248. RtlFreeHeap( RtlProcessHeap(), 0, p );
  2249. RtlFreeUnicodeString(&ProtFileName);
  2250. ProtFileName.Buffer = NULL;
  2251. continue;
  2252. }
  2253. } else {
  2254. #if SMP_SHOW_REGISTRY_DATA
  2255. DbgPrint( "SMSS: File is not in the protected list\n" );
  2256. #endif
  2257. }
  2258. if (ProtFileName.Buffer) {
  2259. RtlFreeUnicodeString(&ProtFileName);
  2260. ProtFileName.Buffer = NULL;
  2261. }
  2262. }
  2263. }
  2264. //
  2265. // Open the file for delete access
  2266. //
  2267. if (p->Value.Length == 0 && p->Name.Buffer[0] == '@') {
  2268. p->Name.Buffer += 1;
  2269. p->Name.Length -= sizeof(WCHAR);
  2270. }
  2271. InitializeObjectAttributes(
  2272. &ObjectAttributes,
  2273. &p->Name,
  2274. OBJ_CASE_INSENSITIVE,
  2275. NULL,
  2276. NULL
  2277. );
  2278. Status = NtOpenFile( &OldFileHandle,
  2279. (ACCESS_MASK)DELETE | SYNCHRONIZE,
  2280. &ObjectAttributes,
  2281. &IoStatusBlock,
  2282. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2283. FILE_SYNCHRONOUS_IO_NONALERT
  2284. );
  2285. if (NT_SUCCESS( Status )) {
  2286. if (p->Value.Length == 0) {
  2287. SetInfoClass = FileDispositionInformation;
  2288. SetInfoLength = sizeof( DeleteInformation );
  2289. SetInfoBuffer = &DeleteInformation;
  2290. DeleteInformation.DeleteFile = TRUE;
  2291. RenameInformation = NULL;
  2292. } else {
  2293. SetInfoClass = FileRenameInformation;
  2294. SetInfoLength = p->Value.Length +
  2295. sizeof( *RenameInformation );
  2296. s = p->Value.Buffer;
  2297. if (*s == L'!' || *s == L'@') {
  2298. s++;
  2299. SetInfoLength -= sizeof( UNICODE_NULL );
  2300. }
  2301. SetInfoBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
  2302. SetInfoLength
  2303. );
  2304. if (SetInfoBuffer != NULL) {
  2305. RenameInformation = SetInfoBuffer;
  2306. RenameInformation->ReplaceIfExists = (BOOLEAN)(s != p->Value.Buffer);
  2307. RenameInformation->RootDirectory = NULL;
  2308. RenameInformation->FileNameLength = SetInfoLength - sizeof( *RenameInformation );
  2309. RtlCopyMemory( RenameInformation->FileName,
  2310. s,
  2311. RenameInformation->FileNameLength
  2312. );
  2313. } else {
  2314. Status = STATUS_NO_MEMORY;
  2315. }
  2316. }
  2317. if (NT_SUCCESS( Status )) {
  2318. Status = NtSetInformationFile( OldFileHandle,
  2319. &IoStatusBlock,
  2320. SetInfoBuffer,
  2321. SetInfoLength,
  2322. SetInfoClass
  2323. );
  2324. if (!NT_SUCCESS( Status ) && SetInfoClass == FileRenameInformation && Status == STATUS_OBJECT_NAME_COLLISION && RenameInformation->ReplaceIfExists ) {
  2325. KdPrintEx((DPFLTR_SMSS_ID,
  2326. DPFLTR_WARNING_LEVEL,
  2327. "\nSMSS: %wZ => %wZ failed - Status == %x, Possible readonly target\n",
  2328. &p->Name,
  2329. &p->Value,
  2330. Status));
  2331. //
  2332. // A rename was attempted, but the source existing file is readonly.
  2333. // this is a problem because folks that use movefileex to do delayed
  2334. // renames expect this to work and can leave a machine unbootable if
  2335. // the rename fails
  2336. //
  2337. //
  2338. // Open the file for Write Attributes access
  2339. //
  2340. NewName.Length = p->Value.Length - sizeof(L'!');
  2341. NewName.MaximumLength = p->Value.MaximumLength - sizeof(L'!');
  2342. NewName.Buffer = s;;
  2343. InitializeObjectAttributes(
  2344. &ObjectAttributes,
  2345. &NewName,
  2346. OBJ_CASE_INSENSITIVE,
  2347. NULL,
  2348. NULL
  2349. );
  2350. OpenStatus = NtOpenFile( &SetAttributesHandle,
  2351. (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  2352. &ObjectAttributes,
  2353. &IoStatusBlock,
  2354. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2355. FILE_SYNCHRONOUS_IO_NONALERT
  2356. );
  2357. if (NT_SUCCESS( OpenStatus )) {
  2358. KdPrintEx((DPFLTR_SMSS_ID,
  2359. DPFLTR_INFO_LEVEL,
  2360. " SMSS: Open Existing Success\n"));
  2361. RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
  2362. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  2363. OpenStatus = NtSetInformationFile(
  2364. SetAttributesHandle,
  2365. &IoStatusBlock,
  2366. &BasicInfo,
  2367. sizeof(BasicInfo),
  2368. FileBasicInformation
  2369. );
  2370. NtClose( SetAttributesHandle );
  2371. if ( NT_SUCCESS(OpenStatus) ) {
  2372. KdPrintEx((DPFLTR_SMSS_ID,
  2373. DPFLTR_INFO_LEVEL,
  2374. " SMSS: Set To NORMAL OK\n"));
  2375. Status = NtSetInformationFile( OldFileHandle,
  2376. &IoStatusBlock,
  2377. SetInfoBuffer,
  2378. SetInfoLength,
  2379. SetInfoClass
  2380. );
  2381. if ( NT_SUCCESS(Status) ) {
  2382. KdPrintEx((DPFLTR_SMSS_ID,
  2383. DPFLTR_INFO_LEVEL,
  2384. " SMSS: Re-Rename Worked OK\n"));
  2385. }
  2386. else {
  2387. KdPrintEx((DPFLTR_SMSS_ID,
  2388. DPFLTR_WARNING_LEVEL,
  2389. " SMSS: Re-Rename Failed - Status == %x\n",
  2390. Status));
  2391. }
  2392. }
  2393. else {
  2394. KdPrintEx((DPFLTR_SMSS_ID,
  2395. DPFLTR_WARNING_LEVEL,
  2396. " SMSS: Set To NORMAL Failed - Status == %x\n",
  2397. OpenStatus));
  2398. }
  2399. }
  2400. else {
  2401. KdPrintEx((DPFLTR_SMSS_ID,
  2402. DPFLTR_WARNING_LEVEL,
  2403. " SMSS: Open Existing file Failed - Status == %x\n",
  2404. OpenStatus));
  2405. }
  2406. }
  2407. }
  2408. NtClose( OldFileHandle );
  2409. }
  2410. if (!NT_SUCCESS( Status )) {
  2411. KdPrintEx((DPFLTR_SMSS_ID,
  2412. DPFLTR_WARNING_LEVEL,
  2413. "SMSS: %wZ => %wZ failed - Status == %x\n",
  2414. &p->Name,
  2415. &p->Value,
  2416. Status));
  2417. }
  2418. else
  2419. if (p->Value.Length == 0) {
  2420. KdPrintEx((DPFLTR_SMSS_ID,
  2421. DPFLTR_INFO_LEVEL,
  2422. "SMSS: %wZ (deleted)\n",
  2423. &p->Name ));
  2424. }
  2425. else {
  2426. KdPrintEx((DPFLTR_SMSS_ID,
  2427. DPFLTR_INFO_LEVEL,
  2428. "SMSS: %wZ (renamed to) %wZ\n",
  2429. &p->Name,
  2430. &p->Value ));
  2431. }
  2432. if (p->AnsiValue) { RtlFreeHeap( RtlProcessHeap(), 0, p->AnsiValue ); }
  2433. if (p->Value.Buffer) { RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer ); }
  2434. RtlFreeHeap( RtlProcessHeap(), 0, p );
  2435. }
  2436. if (EnvVarSet) {
  2437. SmpSetProtectedFilesEnvVars( FALSE );
  2438. }
  2439. if (!WasEnabled) {
  2440. Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE,
  2441. FALSE,
  2442. FALSE,
  2443. &WasEnabled
  2444. );
  2445. }
  2446. if (hModule) {
  2447. LdrUnloadDll( hModule );
  2448. }
  2449. return;
  2450. }
  2451. NTSTATUS
  2452. SmpConfigureObjectDirectories(
  2453. IN PWSTR ValueName,
  2454. IN ULONG ValueType,
  2455. IN PVOID ValueData,
  2456. IN ULONG ValueLength,
  2457. IN PVOID Context,
  2458. IN PVOID EntryContext
  2459. )
  2460. {
  2461. PWSTR s;
  2462. UNICODE_STRING UnicodeString;
  2463. UNICODE_STRING RpcControl;
  2464. UNICODE_STRING Windows;
  2465. NTSTATUS Status;
  2466. OBJECT_ATTRIBUTES ObjectAttributes;
  2467. HANDLE DirectoryHandle;
  2468. PSECURITY_DESCRIPTOR SecurityDescriptor;
  2469. UNREFERENCED_PARAMETER( Context );
  2470. RtlInitUnicodeString( &RpcControl, L"\\RPC Control");
  2471. RtlInitUnicodeString( &Windows, L"\\Windows");
  2472. #if SMP_SHOW_REGISTRY_DATA
  2473. SmpDumpQuery( L"SMSS", "ObjectDirectories", ValueName, ValueType, ValueData, ValueLength );
  2474. #else
  2475. UNREFERENCED_PARAMETER( ValueName );
  2476. UNREFERENCED_PARAMETER( ValueType );
  2477. UNREFERENCED_PARAMETER( ValueLength );
  2478. #endif
  2479. s = (PWSTR)ValueData;
  2480. while (*s) {
  2481. RtlInitUnicodeString( &UnicodeString, s );
  2482. //
  2483. // This is NOT how I would choose to do this if starting from
  2484. // scratch, but we are very close to shipping Daytona and I
  2485. // needed to get the right protection on these objects.
  2486. //
  2487. SecurityDescriptor = SmpPrimarySecurityDescriptor;
  2488. if (RtlEqualString( (PSTRING)&UnicodeString, (PSTRING)&RpcControl, TRUE ) ||
  2489. RtlEqualString( (PSTRING)&UnicodeString, (PSTRING)&Windows, TRUE) ) {
  2490. SecurityDescriptor = SmpLiberalSecurityDescriptor;
  2491. }
  2492. InitializeObjectAttributes( &ObjectAttributes,
  2493. &UnicodeString,
  2494. OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT,
  2495. NULL,
  2496. SecurityDescriptor
  2497. );
  2498. Status = NtCreateDirectoryObject( &DirectoryHandle,
  2499. DIRECTORY_ALL_ACCESS,
  2500. &ObjectAttributes
  2501. );
  2502. if (!NT_SUCCESS( Status )) {
  2503. KdPrintEx((DPFLTR_SMSS_ID,
  2504. DPFLTR_WARNING_LEVEL,
  2505. "SMSS: Unable to create %wZ object directory - Status == %lx\n",
  2506. &UnicodeString,
  2507. Status));
  2508. }
  2509. else {
  2510. NtClose( DirectoryHandle );
  2511. }
  2512. while (*s++) {
  2513. }
  2514. }
  2515. //
  2516. // We dont care if the creates failed.
  2517. //
  2518. return( STATUS_SUCCESS );
  2519. }
  2520. NTSTATUS
  2521. SmpConfigureExecute(
  2522. IN PWSTR ValueName,
  2523. IN ULONG ValueType,
  2524. IN PVOID ValueData,
  2525. IN ULONG ValueLength,
  2526. IN PVOID Context,
  2527. IN PVOID EntryContext
  2528. )
  2529. {
  2530. UNREFERENCED_PARAMETER( Context );
  2531. #if SMP_SHOW_REGISTRY_DATA
  2532. SmpDumpQuery( L"SMSS", "Execute", ValueName, ValueType, ValueData, ValueLength );
  2533. #else
  2534. UNREFERENCED_PARAMETER( ValueName );
  2535. UNREFERENCED_PARAMETER( ValueType );
  2536. UNREFERENCED_PARAMETER( ValueLength );
  2537. #endif
  2538. return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
  2539. ValueData,
  2540. NULL,
  2541. TRUE
  2542. )
  2543. );
  2544. }
  2545. NTSTATUS
  2546. SmpConfigureMemoryMgmt(
  2547. IN PWSTR ValueName,
  2548. IN ULONG ValueType,
  2549. IN PVOID ValueData,
  2550. IN ULONG ValueLength,
  2551. IN PVOID Context,
  2552. IN PVOID EntryContext
  2553. )
  2554. {
  2555. UNREFERENCED_PARAMETER( Context );
  2556. #if SMP_SHOW_REGISTRY_DATA
  2557. SmpDumpQuery( L"SMSS", "MemoryMgmt", ValueName, ValueType, ValueData, ValueLength );
  2558. #else
  2559. UNREFERENCED_PARAMETER( ValueName );
  2560. UNREFERENCED_PARAMETER( ValueType );
  2561. UNREFERENCED_PARAMETER( ValueLength );
  2562. #endif
  2563. return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
  2564. ValueData,
  2565. NULL,
  2566. TRUE
  2567. )
  2568. );
  2569. }
  2570. NTSTATUS
  2571. SmpConfigureFileRenames(
  2572. IN PWSTR ValueName,
  2573. IN ULONG ValueType,
  2574. IN PVOID ValueData,
  2575. IN ULONG ValueLength,
  2576. IN PVOID Context,
  2577. IN PVOID EntryContext
  2578. )
  2579. {
  2580. NTSTATUS Status;
  2581. static PWSTR OldName = NULL;
  2582. UNREFERENCED_PARAMETER( Context );
  2583. #if SMP_SHOW_REGISTRY_DATA
  2584. SmpDumpQuery( L"SMSS", "FileRenameOperation", ValueName, ValueType, ValueData, ValueLength );
  2585. #else
  2586. UNREFERENCED_PARAMETER( ValueType );
  2587. #endif
  2588. //
  2589. // This routine gets called for each string in the MULTI_SZ. The
  2590. // first string we get is the old name, the next string is the new name.
  2591. //
  2592. if (OldName == NULL) {
  2593. //
  2594. // Save a pointer to the old name, we'll need it on the next
  2595. // callback.
  2596. //
  2597. OldName = ValueData;
  2598. return(STATUS_SUCCESS);
  2599. } else {
  2600. Status = SmpSaveRegistryValue((PLIST_ENTRY)EntryContext,
  2601. OldName,
  2602. ValueData,
  2603. FALSE);
  2604. if (!NT_SUCCESS(Status)) {
  2605. #if SMP_SHOW_REGISTRY_DATA
  2606. DbgPrint("SMSS: SmpSaveRegistryValue returned %08lx for FileRenameOperation\n", Status);
  2607. DbgPrint("SMSS: %ws %ws\n", OldName, ValueData);
  2608. #endif
  2609. }
  2610. OldName = NULL;
  2611. return(Status);
  2612. }
  2613. }
  2614. NTSTATUS
  2615. SmpConfigureDosDevices(
  2616. IN PWSTR ValueName,
  2617. IN ULONG ValueType,
  2618. IN PVOID ValueData,
  2619. IN ULONG ValueLength,
  2620. IN PVOID Context,
  2621. IN PVOID EntryContext
  2622. )
  2623. {
  2624. UNREFERENCED_PARAMETER( Context );
  2625. #if SMP_SHOW_REGISTRY_DATA
  2626. SmpDumpQuery( L"SMSS", "DosDevices", ValueName, ValueType, ValueData, ValueLength );
  2627. #else
  2628. UNREFERENCED_PARAMETER( ValueType );
  2629. UNREFERENCED_PARAMETER( ValueLength );
  2630. #endif
  2631. return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
  2632. ValueName,
  2633. ValueData,
  2634. TRUE
  2635. )
  2636. );
  2637. }
  2638. NTSTATUS
  2639. SmpInitializeKnownDllPath(
  2640. IN PUNICODE_STRING KnownDllPath,
  2641. IN PVOID ValueData,
  2642. IN ULONG ValueLength)
  2643. {
  2644. KnownDllPath->Buffer = RtlAllocateHeap(
  2645. RtlProcessHeap(),
  2646. MAKE_TAG( INIT_TAG ),
  2647. ValueLength);
  2648. if (KnownDllPath->Buffer == NULL) {
  2649. return STATUS_NO_MEMORY;
  2650. }
  2651. KnownDllPath->Length = (USHORT)( ValueLength - sizeof( UNICODE_NULL ) );
  2652. KnownDllPath->MaximumLength = (USHORT)ValueLength;
  2653. RtlCopyMemory(
  2654. KnownDllPath->Buffer,
  2655. ValueData,
  2656. ValueLength);
  2657. return STATUS_SUCCESS;
  2658. }
  2659. NTSTATUS
  2660. SmpConfigureKnownDlls(
  2661. IN PWSTR ValueName,
  2662. IN ULONG ValueType,
  2663. IN PVOID ValueData,
  2664. IN ULONG ValueLength,
  2665. IN PVOID Context,
  2666. IN PVOID EntryContext
  2667. )
  2668. {
  2669. UNREFERENCED_PARAMETER( Context );
  2670. #if SMP_SHOW_REGISTRY_DATA
  2671. SmpDumpQuery( L"SMSS", "KnownDlls", ValueName, ValueType, ValueData, ValueLength );
  2672. #else
  2673. UNREFERENCED_PARAMETER( ValueType );
  2674. #endif
  2675. if (!_wcsicmp( ValueName, L"DllDirectory" )) {
  2676. return SmpInitializeKnownDllPath( &SmpKnownDllPath,
  2677. ValueData,
  2678. ValueLength
  2679. );
  2680. }
  2681. #ifdef _WIN64
  2682. if (!MiniNTBoot && !_wcsicmp( ValueName, L"DllDirectory32" )) {
  2683. return SmpInitializeKnownDllPath( &SmpKnownDllPath32,
  2684. ValueData,
  2685. ValueLength
  2686. );
  2687. }
  2688. #endif
  2689. else {
  2690. return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
  2691. ValueName,
  2692. ValueData,
  2693. TRUE
  2694. )
  2695. );
  2696. }
  2697. }
  2698. NTSTATUS
  2699. SmpConfigureExcludeKnownDlls(
  2700. IN PWSTR ValueName,
  2701. IN ULONG ValueType,
  2702. IN PVOID ValueData,
  2703. IN ULONG ValueLength,
  2704. IN PVOID Context,
  2705. IN PVOID EntryContext
  2706. )
  2707. {
  2708. NTSTATUS Status;
  2709. UNREFERENCED_PARAMETER( Context );
  2710. #if SMP_SHOW_REGISTRY_DATA
  2711. SmpDumpQuery( L"SMSS", "ExcludeKnownDlls", ValueName, ValueType, ValueData, ValueLength );
  2712. #else
  2713. UNREFERENCED_PARAMETER( ValueType );
  2714. #endif
  2715. if (ValueType == REG_MULTI_SZ || ValueType == REG_SZ) {
  2716. PWSTR s;
  2717. s = (PWSTR)ValueData;
  2718. while (*s != UNICODE_NULL) {
  2719. Status = SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
  2720. s,
  2721. NULL,
  2722. TRUE
  2723. );
  2724. if (!NT_SUCCESS( Status ) || ValueType == REG_SZ) {
  2725. return Status;
  2726. }
  2727. while (*s++ != UNICODE_NULL) {
  2728. }
  2729. }
  2730. }
  2731. return( STATUS_SUCCESS );
  2732. }
  2733. NTSTATUS
  2734. SmpConfigureEnvironment(
  2735. IN PWSTR ValueName,
  2736. IN ULONG ValueType,
  2737. IN PVOID ValueData,
  2738. IN ULONG ValueLength,
  2739. IN PVOID Context,
  2740. IN PVOID EntryContext
  2741. )
  2742. {
  2743. NTSTATUS Status;
  2744. UNICODE_STRING Name, Value;
  2745. UNREFERENCED_PARAMETER( Context );
  2746. UNREFERENCED_PARAMETER( EntryContext );
  2747. #if SMP_SHOW_REGISTRY_DATA
  2748. SmpDumpQuery( L"SMSS", "Environment", ValueName, ValueType, ValueData, ValueLength );
  2749. #else
  2750. UNREFERENCED_PARAMETER( ValueType );
  2751. #endif
  2752. RtlInitUnicodeString( &Name, ValueName );
  2753. RtlInitUnicodeString( &Value, ValueData );
  2754. Status = RtlSetEnvironmentVariable( NULL,
  2755. &Name,
  2756. &Value
  2757. );
  2758. if (!NT_SUCCESS( Status )) {
  2759. KdPrintEx((DPFLTR_SMSS_ID,
  2760. DPFLTR_WARNING_LEVEL,
  2761. "SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n",
  2762. &Name,
  2763. &Value,
  2764. Status));
  2765. return( Status );
  2766. }
  2767. if (!_wcsicmp( ValueName, L"Path" )) {
  2768. SmpCalledConfigEnv++;
  2769. //
  2770. // Check if this is the second time this function is invoked
  2771. // This routine is called twice to resolve forward references to
  2772. // other environment variables defined in this key
  2773. //
  2774. if( SmpCalledConfigEnv == 2 ) {
  2775. SmpDefaultLibPathBuffer = RtlAllocateHeap(
  2776. RtlProcessHeap(),
  2777. MAKE_TAG( INIT_TAG ),
  2778. ValueLength
  2779. );
  2780. if ( !SmpDefaultLibPathBuffer ) {
  2781. return ( STATUS_NO_MEMORY );
  2782. }
  2783. RtlCopyMemory( SmpDefaultLibPathBuffer,
  2784. ValueData,
  2785. ValueLength
  2786. );
  2787. RtlInitUnicodeString( &SmpDefaultLibPath, SmpDefaultLibPathBuffer );
  2788. }
  2789. }
  2790. return( STATUS_SUCCESS );
  2791. }
  2792. NTSTATUS
  2793. SmpConfigureSubSystems(
  2794. IN PWSTR ValueName,
  2795. IN ULONG ValueType,
  2796. IN PVOID ValueData,
  2797. IN ULONG ValueLength,
  2798. IN PVOID Context,
  2799. IN PVOID EntryContext
  2800. )
  2801. {
  2802. UNREFERENCED_PARAMETER( Context );
  2803. #if SMP_SHOW_REGISTRY_DATA
  2804. SmpDumpQuery( L"SMSS", "SubSystems", ValueName, ValueType, ValueData, ValueLength );
  2805. #else
  2806. UNREFERENCED_PARAMETER( ValueLength );
  2807. #endif
  2808. if (!_wcsicmp( ValueName, L"Required" ) || !_wcsicmp( ValueName, L"Optional" )) {
  2809. if (ValueType == REG_MULTI_SZ) {
  2810. //
  2811. // Here if processing Required= or Optional= values, since they are
  2812. // the only REG_MULTI_SZ value types under the SubSystem key.
  2813. //
  2814. PSMP_REGISTRY_VALUE p;
  2815. PWSTR s;
  2816. s = (PWSTR)ValueData;
  2817. while (*s != UNICODE_NULL) {
  2818. p = SmpFindRegistryValue( (PLIST_ENTRY)EntryContext,
  2819. s
  2820. );
  2821. if (p != NULL) {
  2822. RemoveEntryList( &p->Entry );
  2823. //
  2824. // Required Subsystems are loaded. Optional subsystems are
  2825. // defered.
  2826. //
  2827. if (!_wcsicmp( ValueName, L"Required" ) ) {
  2828. InsertTailList( &SmpSubSystemsToLoad, &p->Entry );
  2829. }
  2830. else {
  2831. InsertTailList( &SmpSubSystemsToDefer, &p->Entry );
  2832. }
  2833. }
  2834. else {
  2835. KdPrintEx((DPFLTR_SMSS_ID,
  2836. DPFLTR_WARNING_LEVEL,
  2837. "SMSS: Invalid subsystem name - %ws\n",
  2838. s));
  2839. }
  2840. while (*s++ != UNICODE_NULL) {
  2841. }
  2842. }
  2843. }
  2844. return( STATUS_SUCCESS );
  2845. }
  2846. else if (!_wcsicmp( ValueName, L"PosixSingleInstance" ) &&
  2847. (ValueType == REG_DWORD)) {
  2848. RegPosixSingleInstance = TRUE;
  2849. #if 0
  2850. KdPrintEx((DPFLTR_SMSS_ID,
  2851. DPFLTR_INFO_LEVEL,
  2852. "SMSS: Single Instance Posix Subsystem Configured\n"));
  2853. #endif
  2854. return( STATUS_SUCCESS );
  2855. }
  2856. else {
  2857. return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext,
  2858. ValueName,
  2859. ValueData,
  2860. TRUE
  2861. )
  2862. );
  2863. }
  2864. }
  2865. NTSTATUS
  2866. SmpParseToken(
  2867. IN PUNICODE_STRING Source,
  2868. IN BOOLEAN RemainderOfSource,
  2869. OUT PUNICODE_STRING Token
  2870. )
  2871. {
  2872. PWSTR s, s1;
  2873. ULONG i, cb;
  2874. RtlInitUnicodeString( Token, NULL );
  2875. s = Source->Buffer;
  2876. if (Source->Length == 0) {
  2877. return( STATUS_SUCCESS );
  2878. }
  2879. i = 0;
  2880. while ((USHORT)i < Source->Length && *s <= L' ') {
  2881. s++;
  2882. i += 2;
  2883. }
  2884. if (RemainderOfSource) {
  2885. cb = Source->Length - (i * sizeof( WCHAR ));
  2886. s1 = (PWSTR)((PCHAR)s + cb);
  2887. i = Source->Length / sizeof( WCHAR );
  2888. } else {
  2889. s1 = s;
  2890. while ((USHORT)i < Source->Length && *s1 > L' ') {
  2891. s1++;
  2892. i += 2;
  2893. }
  2894. cb = (ULONG)((PCHAR)s1 - (PCHAR)s);
  2895. while ((USHORT)i < Source->Length && *s1 <= L' ') {
  2896. s1++;
  2897. i += 2;
  2898. }
  2899. }
  2900. if (cb > 0) {
  2901. Token->Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), cb + sizeof( UNICODE_NULL ) );
  2902. if (Token->Buffer == NULL) {
  2903. return( STATUS_NO_MEMORY );
  2904. }
  2905. Token->Length = (USHORT)cb;
  2906. Token->MaximumLength = (USHORT)(cb + sizeof( UNICODE_NULL ));
  2907. RtlCopyMemory( Token->Buffer, s, cb );
  2908. Token->Buffer[ cb / sizeof( WCHAR ) ] = UNICODE_NULL;
  2909. }
  2910. Source->Length -= (USHORT)((PCHAR)s1 - (PCHAR)Source->Buffer);
  2911. Source->Buffer = s1;
  2912. return( STATUS_SUCCESS );
  2913. }
  2914. NTSTATUS
  2915. SmpParseCommandLine(
  2916. IN PUNICODE_STRING CommandLine,
  2917. OUT PULONG Flags OPTIONAL,
  2918. OUT PUNICODE_STRING ImageFileName,
  2919. OUT PUNICODE_STRING ImageFileDirectory,
  2920. OUT PUNICODE_STRING Arguments
  2921. )
  2922. {
  2923. NTSTATUS Status;
  2924. UNICODE_STRING Input, Token;
  2925. UNICODE_STRING PathVariableName;
  2926. UNICODE_STRING PathVariableValue;
  2927. PWSTR DosFilePart;
  2928. WCHAR FullDosPathBuffer[ DOS_MAX_PATH_LENGTH ];
  2929. ULONG SpResult;
  2930. RtlInitUnicodeString( ImageFileName, NULL );
  2931. RtlInitUnicodeString( Arguments, NULL );
  2932. if (ARGUMENT_PRESENT( ImageFileDirectory )) {
  2933. RtlInitUnicodeString( ImageFileDirectory, NULL );
  2934. }
  2935. //
  2936. // make sure lib path has systemroot\system32. Otherwise, the system will
  2937. // not boot properly
  2938. //
  2939. if ( !SmpSystemRoot.Length ) {
  2940. UNICODE_STRING NewLibString;
  2941. RtlInitUnicodeString( &SmpSystemRoot,USER_SHARED_DATA->NtSystemRoot );
  2942. NewLibString.Length = 0;
  2943. NewLibString.MaximumLength =
  2944. SmpSystemRoot.MaximumLength +
  2945. 20 + // length of \system32;
  2946. SmpDefaultLibPath.MaximumLength;
  2947. NewLibString.Buffer = RtlAllocateHeap(
  2948. RtlProcessHeap(),
  2949. MAKE_TAG( INIT_TAG ),
  2950. NewLibString.MaximumLength
  2951. );
  2952. if ( NewLibString.Buffer ) {
  2953. RtlAppendUnicodeStringToString(&NewLibString,&SmpSystemRoot );
  2954. RtlAppendUnicodeToString(&NewLibString,L"\\system32;");
  2955. RtlAppendUnicodeStringToString(&NewLibString,&SmpDefaultLibPath );
  2956. RtlFreeHeap(RtlProcessHeap(), 0, SmpDefaultLibPath.Buffer );
  2957. SmpDefaultLibPath = NewLibString;
  2958. }
  2959. }
  2960. Input = *CommandLine;
  2961. while (TRUE) {
  2962. Status = SmpParseToken( &Input, FALSE, &Token );
  2963. if (!NT_SUCCESS( Status ) || Token.Buffer == NULL) {
  2964. return( STATUS_UNSUCCESSFUL );
  2965. }
  2966. if (ARGUMENT_PRESENT( Flags )) {
  2967. if (RtlEqualUnicodeString( &Token, &SmpDebugKeyword, TRUE )) {
  2968. *Flags |= SMP_DEBUG_FLAG;
  2969. RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
  2970. continue;
  2971. }
  2972. else
  2973. if (RtlEqualUnicodeString( &Token, &SmpASyncKeyword, TRUE )) {
  2974. *Flags |= SMP_ASYNC_FLAG;
  2975. RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
  2976. continue;
  2977. }
  2978. else
  2979. if (RtlEqualUnicodeString( &Token, &SmpAutoChkKeyword, TRUE )) {
  2980. *Flags |= SMP_AUTOCHK_FLAG;
  2981. RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
  2982. continue;
  2983. }
  2984. #if defined(REMOTE_BOOT)
  2985. else
  2986. if (RtlEqualUnicodeString( &Token, &SmpAutoFmtKeyword, TRUE )) {
  2987. *Flags |= SMP_AUTOFMT_FLAG;
  2988. RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
  2989. continue;
  2990. }
  2991. #endif // defined(REMOTE_BOOT)
  2992. }
  2993. SpResult = 0;
  2994. RtlInitUnicodeString( &PathVariableName, L"Path" );
  2995. PathVariableValue.Length = 0;
  2996. PathVariableValue.MaximumLength = 4096;
  2997. PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
  2998. PathVariableValue.MaximumLength
  2999. );
  3000. if (PathVariableValue.Buffer == NULL) {
  3001. RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
  3002. return STATUS_INSUFFICIENT_RESOURCES;
  3003. }
  3004. Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment,
  3005. &PathVariableName,
  3006. &PathVariableValue
  3007. );
  3008. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  3009. RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer );
  3010. PathVariableValue.MaximumLength = PathVariableValue.Length + 2;
  3011. PathVariableValue.Length = 0;
  3012. PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ),
  3013. PathVariableValue.MaximumLength
  3014. );
  3015. if (PathVariableValue.Buffer == NULL) {
  3016. RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
  3017. return STATUS_INSUFFICIENT_RESOURCES;
  3018. }
  3019. Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment,
  3020. &PathVariableName,
  3021. &PathVariableValue
  3022. );
  3023. }
  3024. if (!NT_SUCCESS( Status )) {
  3025. KdPrintEx((DPFLTR_SMSS_ID,
  3026. DPFLTR_WARNING_LEVEL,
  3027. "SMSS: %wZ environment variable not defined.\n",
  3028. &PathVariableName));
  3029. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3030. }
  3031. else
  3032. if (!ARGUMENT_PRESENT( Flags ) ||
  3033. #pragma prefast(suppress: 209, "This *does* take a byte count--not a character count")
  3034. !(SpResult = RtlDosSearchPath_U( PathVariableValue.Buffer,
  3035. Token.Buffer,
  3036. L".exe",
  3037. sizeof( FullDosPathBuffer ),
  3038. FullDosPathBuffer,
  3039. &DosFilePart
  3040. ))
  3041. ) {
  3042. if (!ARGUMENT_PRESENT( Flags )) {
  3043. wcscpy( FullDosPathBuffer, Token.Buffer );
  3044. }
  3045. else {
  3046. if ( !SpResult ) {
  3047. //
  3048. // The search path call failed. Now try the call again using
  3049. // the default lib path. This always has systemroot\system32
  3050. // at the front.
  3051. //
  3052. #pragma prefast(suppress: 209, "This *does* take a byte count--not a character count")
  3053. SpResult = RtlDosSearchPath_U(
  3054. SmpDefaultLibPath.Buffer,
  3055. Token.Buffer,
  3056. L".exe",
  3057. sizeof( FullDosPathBuffer ),
  3058. FullDosPathBuffer,
  3059. &DosFilePart
  3060. );
  3061. }
  3062. if ( !SpResult ) {
  3063. *Flags |= SMP_IMAGE_NOT_FOUND;
  3064. *ImageFileName = Token;
  3065. RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer );
  3066. return( STATUS_SUCCESS );
  3067. }
  3068. }
  3069. }
  3070. RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer );
  3071. RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer );
  3072. if (NT_SUCCESS( Status ) &&
  3073. !RtlDosPathNameToNtPathName_U( FullDosPathBuffer,
  3074. ImageFileName,
  3075. NULL,
  3076. NULL
  3077. )
  3078. ) {
  3079. KdPrintEx((DPFLTR_SMSS_ID,
  3080. DPFLTR_WARNING_LEVEL,
  3081. "SMSS: Unable to translate %ws into an NT File Name\n",
  3082. FullDosPathBuffer));
  3083. Status = STATUS_OBJECT_PATH_INVALID;
  3084. }
  3085. if (!NT_SUCCESS( Status )) {
  3086. return( Status );
  3087. }
  3088. if (ARGUMENT_PRESENT( ImageFileDirectory )) {
  3089. if (DosFilePart > FullDosPathBuffer) {
  3090. *--DosFilePart = UNICODE_NULL;
  3091. RtlCreateUnicodeString( ImageFileDirectory,
  3092. FullDosPathBuffer
  3093. );
  3094. }
  3095. else {
  3096. RtlInitUnicodeString( ImageFileDirectory, NULL );
  3097. }
  3098. }
  3099. break;
  3100. }
  3101. Status = SmpParseToken( &Input, TRUE, Arguments );
  3102. return( Status );
  3103. }
  3104. ULONG
  3105. SmpConvertInteger(
  3106. IN PWSTR String
  3107. )
  3108. {
  3109. NTSTATUS Status;
  3110. UNICODE_STRING UnicodeString;
  3111. ULONG Value;
  3112. RtlInitUnicodeString( &UnicodeString, String );
  3113. Status = RtlUnicodeStringToInteger( &UnicodeString, 0, &Value );
  3114. if (NT_SUCCESS( Status )) {
  3115. return( Value );
  3116. }
  3117. else {
  3118. return( 0 );
  3119. }
  3120. }
  3121. NTSTATUS
  3122. SmpExecuteImage(
  3123. IN PUNICODE_STRING ImageFileName,
  3124. IN PUNICODE_STRING CurrentDirectory,
  3125. IN PUNICODE_STRING CommandLine,
  3126. IN ULONG MuSessionId,
  3127. IN ULONG Flags,
  3128. IN OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation OPTIONAL
  3129. )
  3130. /*++
  3131. Routine Description:
  3132. This function creates and starts a process specified by the
  3133. CommandLine parameter. After starting the process, the procedure
  3134. will optionally wait for the first thread in the process to
  3135. terminate.
  3136. Arguments:
  3137. ImageFileName - Supplies the full NT path for the image file to
  3138. execute. Presumably computed or extracted from the first
  3139. token of the CommandLine.
  3140. CommandLine - Supplies the command line to execute. The first blank
  3141. separate token on the command line must be a fully qualified NT
  3142. Path name of an image file to execute.
  3143. Flags - Supplies information about how to invoke the command.
  3144. ProcessInformation - Optional parameter, which if specified, receives
  3145. information for images invoked with the SMP_ASYNC_FLAG. Ignore
  3146. if this flag is not set.
  3147. Return Value:
  3148. Status of operation
  3149. --*/
  3150. {
  3151. NTSTATUS Status;
  3152. RTL_USER_PROCESS_INFORMATION MyProcessInformation;
  3153. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  3154. #if 0
  3155. BOOLEAN ImageWhacked;
  3156. #endif
  3157. if (!ARGUMENT_PRESENT( ProcessInformation )) {
  3158. ProcessInformation = &MyProcessInformation;
  3159. }
  3160. #if 0
  3161. //
  3162. // this seems to break setup's sense of what SystemRoot is
  3163. ImageWhacked = FALSE;
  3164. if ( ImageFileName && ImageFileName->Length > 8 ) {
  3165. if ( ImageFileName->Buffer[0] == L'\\'
  3166. && ImageFileName->Buffer[1] == L'?'
  3167. && ImageFileName->Buffer[2] == L'?'
  3168. && ImageFileName->Buffer[3] == L'\\' ) {
  3169. ImageWhacked = TRUE;
  3170. ImageFileName->Buffer[1] = L'\\';
  3171. }
  3172. }
  3173. #endif
  3174. Status = RtlCreateProcessParameters( &ProcessParameters,
  3175. ImageFileName,
  3176. (SmpDefaultLibPath.Length == 0 ?
  3177. NULL : &SmpDefaultLibPath
  3178. ),
  3179. CurrentDirectory,
  3180. CommandLine,
  3181. SmpDefaultEnvironment,
  3182. NULL,
  3183. NULL,
  3184. NULL,
  3185. NULL
  3186. );
  3187. #if 0
  3188. if ( ImageWhacked ) {
  3189. ImageFileName->Buffer[1] = L'?';
  3190. }
  3191. #endif
  3192. ASSERTMSG( "RtlCreateProcessParameters", NT_SUCCESS( Status ) );
  3193. if ( !NT_SUCCESS( Status ) ) {
  3194. KdPrintEx((DPFLTR_SMSS_ID,
  3195. DPFLTR_WARNING_LEVEL,
  3196. "SMSS: RtlCreateProcessParameters failed for %wZ - Status == %lx\n",
  3197. ImageFileName,
  3198. Status));
  3199. return( Status );
  3200. }
  3201. if (Flags & SMP_DEBUG_FLAG) {
  3202. ProcessParameters->DebugFlags = TRUE;
  3203. }
  3204. else {
  3205. ProcessParameters->DebugFlags = SmpDebug;
  3206. }
  3207. if ( Flags & SMP_SUBSYSTEM_FLAG ) {
  3208. ProcessParameters->Flags |= RTL_USER_PROC_RESERVE_1MB;
  3209. }
  3210. ProcessInformation->Length = sizeof( RTL_USER_PROCESS_INFORMATION );
  3211. Status = RtlCreateUserProcess( ImageFileName,
  3212. OBJ_CASE_INSENSITIVE,
  3213. ProcessParameters,
  3214. NULL,
  3215. NULL,
  3216. NULL,
  3217. FALSE,
  3218. NULL,
  3219. NULL,
  3220. ProcessInformation
  3221. );
  3222. RtlDestroyProcessParameters( ProcessParameters );
  3223. if ( !NT_SUCCESS( Status ) ) {
  3224. KdPrintEx((DPFLTR_SMSS_ID,
  3225. DPFLTR_WARNING_LEVEL,
  3226. "SMSS: Failed load of %wZ - Status == %lx\n",
  3227. ImageFileName,
  3228. Status));
  3229. return( Status );
  3230. }
  3231. //
  3232. // Set the MuSessionId in the PEB of the new process.
  3233. //
  3234. Status = SmpSetProcessMuSessionId( ProcessInformation->Process, MuSessionId );
  3235. if (!(Flags & SMP_DONT_START)) {
  3236. if (ProcessInformation->ImageInformation.SubSystemType !=
  3237. IMAGE_SUBSYSTEM_NATIVE
  3238. ) {
  3239. NtTerminateProcess( ProcessInformation->Process,
  3240. STATUS_INVALID_IMAGE_FORMAT
  3241. );
  3242. NtWaitForSingleObject( ProcessInformation->Thread, FALSE, NULL );
  3243. NtClose( ProcessInformation->Thread );
  3244. NtClose( ProcessInformation->Process );
  3245. KdPrintEx((DPFLTR_SMSS_ID,
  3246. DPFLTR_WARNING_LEVEL,
  3247. "SMSS: Not an NT image - %wZ\n",
  3248. ImageFileName));
  3249. return( STATUS_INVALID_IMAGE_FORMAT );
  3250. }
  3251. NtResumeThread( ProcessInformation->Thread, NULL );
  3252. if (!(Flags & SMP_ASYNC_FLAG)) {
  3253. NtWaitForSingleObject( ProcessInformation->Thread, FALSE, NULL );
  3254. }
  3255. NtClose( ProcessInformation->Thread );
  3256. NtClose( ProcessInformation->Process );
  3257. }
  3258. return( Status );
  3259. }
  3260. NTSTATUS
  3261. SmpExecuteCommand(
  3262. IN PUNICODE_STRING CommandLine,
  3263. IN ULONG MuSessionId,
  3264. OUT PULONG_PTR pWindowsSubSysProcessId,
  3265. IN ULONG Flags
  3266. )
  3267. /*++
  3268. Routine Description:
  3269. This function is called to execute a command.
  3270. The format of CommandLine is:
  3271. Nt-Path-To-AutoChk.exe Nt-Path-To-Disk-Partition
  3272. If the NT path to the disk partition is an asterisk, then invoke
  3273. the AutoChk.exe utility on all hard disk partitions.
  3274. #if defined(REMOTE_BOOT)
  3275. -or-
  3276. Nt-Path-To-AutoFmt.exe Nt-Path-To-Disk-Partition
  3277. #endif // defined(REMOTE_BOOT)
  3278. Arguments:
  3279. CommandLine - Supplies the Command line to invoke.
  3280. Flags - Specifies the type of command and options.
  3281. Return Value:
  3282. Status of operation
  3283. --*/
  3284. {
  3285. NTSTATUS Status;
  3286. UNICODE_STRING ImageFileName;
  3287. UNICODE_STRING CurrentDirectory;
  3288. UNICODE_STRING Arguments;
  3289. if (Flags & SMP_DEBUG_FLAG) {
  3290. return( STATUS_SUCCESS );
  3291. }
  3292. Status = SmpParseCommandLine( CommandLine,
  3293. &Flags,
  3294. &ImageFileName,
  3295. &CurrentDirectory,
  3296. &Arguments
  3297. );
  3298. if (!NT_SUCCESS( Status )) {
  3299. KdPrintEx((DPFLTR_SMSS_ID,
  3300. DPFLTR_WARNING_LEVEL,
  3301. "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n",
  3302. CommandLine,
  3303. Status));
  3304. return( Status );
  3305. }
  3306. if (Flags & SMP_AUTOCHK_FLAG) {
  3307. Status = SmpInvokeAutoChk( &ImageFileName, &CurrentDirectory, &Arguments, Flags );
  3308. }
  3309. #if defined(REMOTE_BOOT)
  3310. else
  3311. if (Flags & SMP_AUTOFMT_FLAG) {
  3312. Status = SmpInvokeAutoFmt( &ImageFileName, &CurrentDirectory, &Arguments, Flags );
  3313. }
  3314. #endif // defined(REMOTE_BOOT)
  3315. else
  3316. if (Flags & SMP_SUBSYSTEM_FLAG) {
  3317. Status = SmpLoadSubSystem( &ImageFileName, &CurrentDirectory, CommandLine, MuSessionId, pWindowsSubSysProcessId, Flags );
  3318. }
  3319. else {
  3320. if (Flags & SMP_IMAGE_NOT_FOUND) {
  3321. KdPrintEx((DPFLTR_SMSS_ID,
  3322. DPFLTR_WARNING_LEVEL,
  3323. "SMSS: Image file (%wZ) not found\n",
  3324. &ImageFileName));
  3325. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  3326. }
  3327. else {
  3328. Status = SmpExecuteImage( &ImageFileName,
  3329. &CurrentDirectory,
  3330. CommandLine,
  3331. MuSessionId,
  3332. Flags,
  3333. NULL
  3334. );
  3335. }
  3336. }
  3337. // ImageFileName may be returned even
  3338. // when SMP_IMAGE_NOT_FOUND flag is set
  3339. if (ImageFileName.Buffer) {
  3340. RtlFreeHeap( RtlProcessHeap(), 0, ImageFileName.Buffer );
  3341. if (CurrentDirectory.Buffer != NULL) {
  3342. RtlFreeHeap( RtlProcessHeap(), 0, CurrentDirectory.Buffer );
  3343. }
  3344. }
  3345. if (Arguments.Buffer) {
  3346. RtlFreeHeap( RtlProcessHeap(), 0, Arguments.Buffer );
  3347. }
  3348. if (!NT_SUCCESS( Status )) {
  3349. KdPrintEx((DPFLTR_SMSS_ID,
  3350. DPFLTR_WARNING_LEVEL,
  3351. "SMSS: Command '%wZ' failed - Status == %x\n",
  3352. CommandLine,
  3353. Status));
  3354. }
  3355. return( Status );
  3356. }
  3357. BOOLEAN
  3358. SmpSaveAndClearBootStatusData(
  3359. OUT PBOOLEAN BootOkay,
  3360. OUT PBOOLEAN ShutdownOkay
  3361. )
  3362. /*++
  3363. Routine Description:
  3364. This routine saves the boot status flags in the boot status data and then
  3365. sets the data file to indicate a successful boot and shutdown. This is
  3366. used to avoid triggering auto-recovery in the loader if autoconvert or
  3367. autochk reboots the machine as part of its run.
  3368. The caller is responsible for calling SmpRestoreBootStatusData if the
  3369. auto* program allows boot to continue.
  3370. Arguments:
  3371. BootOkay - the status of the boot
  3372. ShutdownOkay - the status of the shutdown
  3373. Return Value:
  3374. TRUE if the values were saved and should be restored.
  3375. FALSE if an error occurred and no values were saved.
  3376. --*/
  3377. {
  3378. NTSTATUS Status;
  3379. PVOID BootStatusDataHandle;
  3380. *BootOkay = FALSE;
  3381. *ShutdownOkay = FALSE;
  3382. Status = RtlLockBootStatusData(&BootStatusDataHandle);
  3383. if(NT_SUCCESS(Status)) {
  3384. BOOLEAN t = TRUE;
  3385. RtlGetSetBootStatusData(BootStatusDataHandle,
  3386. TRUE,
  3387. RtlBsdItemBootGood,
  3388. BootOkay,
  3389. sizeof(BOOLEAN),
  3390. NULL);
  3391. RtlGetSetBootStatusData(BootStatusDataHandle,
  3392. TRUE,
  3393. RtlBsdItemBootShutdown,
  3394. ShutdownOkay,
  3395. sizeof(BOOLEAN),
  3396. NULL);
  3397. RtlGetSetBootStatusData(BootStatusDataHandle,
  3398. FALSE,
  3399. RtlBsdItemBootGood,
  3400. &t,
  3401. sizeof(BOOLEAN),
  3402. NULL);
  3403. RtlGetSetBootStatusData(BootStatusDataHandle,
  3404. FALSE,
  3405. RtlBsdItemBootShutdown,
  3406. &t,
  3407. sizeof(BOOLEAN),
  3408. NULL);
  3409. RtlUnlockBootStatusData(BootStatusDataHandle);
  3410. return TRUE;
  3411. }
  3412. return FALSE;
  3413. }
  3414. VOID
  3415. SmpRestoreBootStatusData(
  3416. IN BOOLEAN BootOkay,
  3417. IN BOOLEAN ShutdownOkay
  3418. )
  3419. /*++
  3420. Routine Description:
  3421. This routine restores the boot status flags in the boot status data to
  3422. the provided values.
  3423. Arguments:
  3424. BootOkay - the status of the boot
  3425. ShutdownOkay - the status of the shutdown
  3426. Return Value:
  3427. none.
  3428. --*/
  3429. {
  3430. NTSTATUS Status;
  3431. PVOID BootStatusDataHandle;
  3432. Status = RtlLockBootStatusData(&BootStatusDataHandle);
  3433. if(NT_SUCCESS(Status)) {
  3434. RtlGetSetBootStatusData(BootStatusDataHandle,
  3435. FALSE,
  3436. RtlBsdItemBootGood,
  3437. &BootOkay,
  3438. sizeof(BOOLEAN),
  3439. NULL);
  3440. RtlGetSetBootStatusData(BootStatusDataHandle,
  3441. FALSE,
  3442. RtlBsdItemBootShutdown,
  3443. &ShutdownOkay,
  3444. sizeof(BOOLEAN),
  3445. NULL);
  3446. RtlUnlockBootStatusData(BootStatusDataHandle);
  3447. }
  3448. return;
  3449. }
  3450. NTSTATUS
  3451. SmpInvokeAutoChk(
  3452. IN PUNICODE_STRING ImageFileName,
  3453. IN PUNICODE_STRING CurrentDirectory,
  3454. IN PUNICODE_STRING Arguments,
  3455. IN ULONG Flags
  3456. )
  3457. {
  3458. NTSTATUS Status;
  3459. CHAR DisplayBuffer[ MAXIMUM_FILENAME_LENGTH ];
  3460. ANSI_STRING AnsiDisplayString;
  3461. UNICODE_STRING DisplayString;
  3462. UNICODE_STRING CmdLine;
  3463. WCHAR CmdLineBuffer[ 2 * MAXIMUM_FILENAME_LENGTH ];
  3464. BOOLEAN BootStatusDataSaved = FALSE;
  3465. BOOLEAN BootOkay;
  3466. BOOLEAN ShutdownOkay;
  3467. //
  3468. // Query the system environment variable "osloadoptions" to determine
  3469. // if SOS is specified. What for though? No one is using it.
  3470. //
  3471. if (SmpQueryRegistrySosOption() != FALSE) {
  3472. SmpEnableDots = FALSE;
  3473. }
  3474. if (Flags & SMP_IMAGE_NOT_FOUND) {
  3475. sprintf( DisplayBuffer,
  3476. "%wZ program not found - skipping AUTOCHECK\n",
  3477. ImageFileName
  3478. );
  3479. RtlInitAnsiString( &AnsiDisplayString, DisplayBuffer );
  3480. Status = RtlAnsiStringToUnicodeString( &DisplayString,
  3481. &AnsiDisplayString,
  3482. TRUE
  3483. );
  3484. if (NT_SUCCESS( Status )) {
  3485. NtDisplayString( &DisplayString );
  3486. RtlFreeUnicodeString( &DisplayString );
  3487. }
  3488. return( STATUS_SUCCESS );
  3489. }
  3490. //
  3491. // Save away the boot & shutdown status flags in the boot status data
  3492. // and restore them after autochk returns. This way if autochk forces
  3493. // a reboot the loader won't put up the autorecovery menu.
  3494. //
  3495. BootStatusDataSaved = SmpSaveAndClearBootStatusData(&BootOkay,
  3496. &ShutdownOkay);
  3497. CmdLine.Buffer = CmdLineBuffer;
  3498. CmdLine.MaximumLength = sizeof( CmdLineBuffer );
  3499. CmdLine.Length = 0;
  3500. RtlAppendUnicodeStringToString( &CmdLine, ImageFileName );
  3501. RtlAppendUnicodeToString( &CmdLine, L" " );
  3502. RtlAppendUnicodeStringToString( &CmdLine, Arguments );
  3503. SmpExecuteImage( ImageFileName,
  3504. CurrentDirectory,
  3505. &CmdLine,
  3506. 0, // MuSessionId
  3507. Flags & ~SMP_AUTOCHK_FLAG,
  3508. NULL
  3509. );
  3510. //
  3511. // If autochk doesn't shut us down then we end up back here. Restore the
  3512. // values we saved.
  3513. //
  3514. if(BootStatusDataSaved) {
  3515. SmpRestoreBootStatusData(BootOkay, ShutdownOkay);
  3516. }
  3517. return( STATUS_SUCCESS );
  3518. }
  3519. #if defined(REMOTE_BOOT)
  3520. NTSTATUS
  3521. SmpInvokeAutoFmt(
  3522. IN PUNICODE_STRING ImageFileName,
  3523. IN PUNICODE_STRING CurrentDirectory,
  3524. IN PUNICODE_STRING Arguments,
  3525. IN ULONG Flags
  3526. )
  3527. {
  3528. NTSTATUS Status;
  3529. CHAR DisplayBuffer[ MAXIMUM_FILENAME_LENGTH ];
  3530. ANSI_STRING AnsiDisplayString;
  3531. UNICODE_STRING DisplayString;
  3532. UNICODE_STRING CmdLine;
  3533. WCHAR CmdLineBuffer[ 2 * MAXIMUM_FILENAME_LENGTH ];
  3534. BOOLEAN BootStatusDataSaved;
  3535. BOOLEAN BootOkay;
  3536. BOOLEAN ShutdownOkay;
  3537. //
  3538. // Query the system environment variable "osloadoptions" to determine
  3539. // if SOS is specified.
  3540. //
  3541. if (SmpQueryRegistrySosOption() != FALSE) {
  3542. SmpEnableDots = FALSE;
  3543. }
  3544. if (Flags & SMP_IMAGE_NOT_FOUND) {
  3545. sprintf( DisplayBuffer,
  3546. "%wZ program not found - skipping AUTOFMT\n",
  3547. ImageFileName
  3548. );
  3549. RtlInitAnsiString( &AnsiDisplayString, DisplayBuffer );
  3550. Status = RtlAnsiStringToUnicodeString( &DisplayString,
  3551. &AnsiDisplayString,
  3552. TRUE
  3553. );
  3554. if (NT_SUCCESS( Status )) {
  3555. NtDisplayString( &DisplayString );
  3556. RtlFreeUnicodeString( &DisplayString );
  3557. }
  3558. return( STATUS_SUCCESS );
  3559. }
  3560. BootStatusDataSaved = SmpSaveAndClearBootStatusData(&BootOkay,
  3561. &ShutdownOkay);
  3562. CmdLine.Buffer = CmdLineBuffer;
  3563. CmdLine.MaximumLength = sizeof( CmdLineBuffer );
  3564. CmdLine.Length = 0;
  3565. RtlAppendUnicodeStringToString( &CmdLine, ImageFileName );
  3566. RtlAppendUnicodeToString( &CmdLine, L" " );
  3567. RtlAppendUnicodeStringToString( &CmdLine, Arguments );
  3568. SmpExecuteImage( ImageFileName,
  3569. CurrentDirectory,
  3570. &CmdLine,
  3571. 0, //Console MuSessionId
  3572. Flags & ~SMP_AUTOFMT_FLAG,
  3573. NULL
  3574. );
  3575. if(BootStatusDataSaved) {
  3576. SmpRestoreBootStatusData(BootOkay, ShutdownOkay);
  3577. }
  3578. return( STATUS_SUCCESS );
  3579. }
  3580. #endif // defined(REMOTE_BOOT)
  3581. NTSTATUS
  3582. SmpLoadSubSystem(
  3583. IN PUNICODE_STRING ImageFileName,
  3584. IN PUNICODE_STRING CurrentDirectory,
  3585. IN PUNICODE_STRING CommandLine,
  3586. IN ULONG MuSessionId,
  3587. OUT PULONG_PTR pWindowsSubSysProcessId,
  3588. IN ULONG Flags
  3589. )
  3590. /*++
  3591. Routine Description:
  3592. This function loads and starts the specified system service
  3593. emulation subsystem. The system freezes until the loaded subsystem
  3594. completes the subsystem connection protocol by connecting to SM,
  3595. and then accepting a connection from SM.
  3596. For terminal server, the subsystem is started by csrss so that the
  3597. correct session is used.
  3598. Arguments:
  3599. CommandLine - Supplies the command line to execute the subsystem.
  3600. Return Value:
  3601. TBD
  3602. --*/
  3603. {
  3604. NTSTATUS Status;
  3605. RTL_USER_PROCESS_INFORMATION ProcessInformation;
  3606. PSMPKNOWNSUBSYS KnownSubSys = NULL;
  3607. PSMPKNOWNSUBSYS TargetSubSys = NULL;
  3608. PSMPKNOWNSUBSYS CreatorSubSys = NULL;
  3609. LARGE_INTEGER Timeout;
  3610. ULONG SubsysMuSessionId = MuSessionId;
  3611. PVOID State;
  3612. NTSTATUS AcquirePrivilegeStatus = STATUS_SUCCESS;
  3613. if (Flags & SMP_IMAGE_NOT_FOUND) {
  3614. KdPrintEx((DPFLTR_SMSS_ID,
  3615. DPFLTR_WARNING_LEVEL,
  3616. "SMSS: Unable to find subsystem - %wZ\n",
  3617. ImageFileName));
  3618. return( STATUS_OBJECT_NAME_NOT_FOUND );
  3619. }
  3620. //
  3621. // Check for single instance POSIX subsystem
  3622. //
  3623. if (Flags & SMP_POSIX_SI_FLAG) {
  3624. // Run only one copy using the console Logon Id
  3625. SubsysMuSessionId = 0;
  3626. }
  3627. //
  3628. // There is a race condition on hydra loading subsystems. Two
  3629. // requests can be received from the same MuSessionId to load
  3630. // the same subsystem. There is a window in hydra since the
  3631. // ImageType == 0xFFFFFFFF until the newly started subsystem connects
  3632. // back. Non-hydra didn't have this problem since the optional
  3633. // subsystem entry was destroyed once started. Hydra does not do this
  3634. // since multiple sessions may want to start an optional subsystem.
  3635. //
  3636. // To close this window, on hydra this value is looked up based on
  3637. // the MuSessionId to see if any subsystems are starting.
  3638. // If so, we wait for the Active event. We can then
  3639. // run our checks for the subsystem already being loaded. This has
  3640. // the effect of serializing the startup of a subsystem on hydra
  3641. // per MuSessionId, but not across the system. IE: Posix and
  3642. // OS2 can't start at the same time, but will wait until
  3643. // the other has started on a MuSessionId basis.
  3644. //
  3645. // We also use the SmpKnownSubSysLock to handle existing
  3646. // race conditions since we have multiple SmpApiLoop() threads.
  3647. //
  3648. RtlEnterCriticalSection( &SmpKnownSubSysLock );
  3649. do {
  3650. TargetSubSys = SmpLocateKnownSubSysByType(
  3651. SubsysMuSessionId,
  3652. 0xFFFFFFFF
  3653. );
  3654. if( TargetSubSys ) {
  3655. HANDLE hEvent = TargetSubSys->Active;
  3656. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3657. Status = NtWaitForSingleObject( hEvent, FALSE, NULL );
  3658. RtlEnterCriticalSection( &SmpKnownSubSysLock );
  3659. SmpDeferenceKnownSubSys(TargetSubSys);
  3660. }
  3661. } while ( TargetSubSys != NULL );
  3662. if (Flags & SMP_POSIX_FLAG) {
  3663. TargetSubSys = SmpLocateKnownSubSysByType(
  3664. SubsysMuSessionId,
  3665. IMAGE_SUBSYSTEM_POSIX_CUI
  3666. );
  3667. if( TargetSubSys ) {
  3668. SmpDeferenceKnownSubSys(TargetSubSys);
  3669. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3670. return( STATUS_SUCCESS );
  3671. }
  3672. }
  3673. if (Flags & SMP_OS2_FLAG) {
  3674. TargetSubSys = SmpLocateKnownSubSysByType(
  3675. SubsysMuSessionId,
  3676. IMAGE_SUBSYSTEM_OS2_CUI
  3677. );
  3678. if( TargetSubSys ) {
  3679. SmpDeferenceKnownSubSys(TargetSubSys);
  3680. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3681. return( STATUS_SUCCESS );
  3682. }
  3683. }
  3684. //
  3685. // Create and register KnownSubSys entry before releasing the lock
  3686. // so that other threads will see that we are starting a subsystem
  3687. // on this MuSessionId.
  3688. //
  3689. KnownSubSys = RtlAllocateHeap( SmpHeap, MAKE_TAG( INIT_TAG ), sizeof( SMPKNOWNSUBSYS ) );
  3690. if ( KnownSubSys == NULL ) {
  3691. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3692. return( STATUS_NO_MEMORY );
  3693. }
  3694. KnownSubSys->Deleting = FALSE;
  3695. KnownSubSys->Process = NULL;
  3696. KnownSubSys->Active = NULL;
  3697. KnownSubSys->MuSessionId = SubsysMuSessionId;
  3698. KnownSubSys->ImageType = (ULONG)0xFFFFFFFF;
  3699. KnownSubSys->SmApiCommunicationPort = (HANDLE) NULL;
  3700. KnownSubSys->SbApiCommunicationPort = (HANDLE) NULL;
  3701. KnownSubSys->RefCount = 1;
  3702. Status = NtCreateEvent( &KnownSubSys->Active,
  3703. EVENT_ALL_ACCESS,
  3704. NULL,
  3705. NotificationEvent,
  3706. FALSE
  3707. );
  3708. if( !NT_SUCCESS(Status) ) {
  3709. RtlFreeHeap( SmpHeap, 0, KnownSubSys );
  3710. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3711. return( STATUS_NO_MEMORY );
  3712. }
  3713. InsertHeadList( &SmpKnownSubSysHead, &KnownSubSys->Links );
  3714. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3715. Flags |= SMP_DONT_START;
  3716. if (((Flags & SMP_OS2_FLAG) || (Flags & SMP_POSIX_FLAG))) {
  3717. SBAPIMSG m;
  3718. PSBCREATEPROCESS args = &m.u.CreateProcess;
  3719. //
  3720. // Create it in csrss instead.
  3721. //
  3722. CreatorSubSys = SmpLocateKnownSubSysByType(SubsysMuSessionId,
  3723. IMAGE_SUBSYSTEM_WINDOWS_GUI);
  3724. //
  3725. // CSRSS must have been started.
  3726. //
  3727. if (CreatorSubSys == NULL) {
  3728. KdPrintEx((DPFLTR_SMSS_ID,
  3729. DPFLTR_WARNING_LEVEL,
  3730. "SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed\n"));
  3731. goto cleanup2;
  3732. }
  3733. args->i.ImageFileName = ImageFileName;
  3734. args->i.CurrentDirectory = CurrentDirectory;
  3735. args->i.CommandLine = CommandLine;
  3736. args->i.DefaultLibPath = (SmpDefaultLibPath.Length == 0 ?
  3737. NULL : &SmpDefaultLibPath
  3738. );
  3739. args->i.Flags = Flags;
  3740. args->i.DefaultDebugFlags = SmpDebug;
  3741. Status = SmpCallCsrCreateProcess(&m,
  3742. sizeof(*args),
  3743. CreatorSubSys->SbApiCommunicationPort
  3744. );
  3745. if (!NT_SUCCESS( Status )) {
  3746. KdPrintEx((DPFLTR_SMSS_ID,
  3747. DPFLTR_WARNING_LEVEL,
  3748. "SMSS: SmpLoadSubSystem - SmpCallCsrCreateProcess Failed with Status %lx\n",
  3749. Status));
  3750. goto cleanup2;
  3751. }
  3752. //
  3753. // Copy the output parameters to where smss expects them.
  3754. //
  3755. ProcessInformation.Process = args->o.Process;
  3756. ProcessInformation.Thread = args->o.Thread;
  3757. ProcessInformation.ClientId.UniqueProcess = args->o.ClientId.UniqueProcess;
  3758. ProcessInformation.ClientId.UniqueThread = args->o.ClientId.UniqueThread;
  3759. ProcessInformation.ImageInformation.SubSystemType = args->o.SubSystemType;
  3760. } else {
  3761. Status = SmpExecuteImage( ImageFileName,
  3762. CurrentDirectory,
  3763. CommandLine,
  3764. SubsysMuSessionId,
  3765. Flags,
  3766. &ProcessInformation
  3767. );
  3768. if (!NT_SUCCESS( Status )) {
  3769. KdPrintEx((DPFLTR_SMSS_ID,
  3770. DPFLTR_WARNING_LEVEL,
  3771. "SMSS: SmpLoadSubSystem - SmpExecuteImage Failed with Status %lx\n",
  3772. Status));
  3773. goto cleanup2;
  3774. }
  3775. }
  3776. KnownSubSys->Process = ProcessInformation.Process;
  3777. KnownSubSys->InitialClientId = ProcessInformation.ClientId;
  3778. //
  3779. // Now that we have the process all set, make sure that the
  3780. // subsystem is either an NT native app, or an app type of
  3781. // a previously loaded subsystem.
  3782. //
  3783. if (ProcessInformation.ImageInformation.SubSystemType !=
  3784. IMAGE_SUBSYSTEM_NATIVE ) {
  3785. SBAPIMSG SbApiMsg;
  3786. PSBCREATESESSION args;
  3787. ULONG SessionId;
  3788. args = &SbApiMsg.u.CreateSession;
  3789. args->ProcessInformation = ProcessInformation;
  3790. args->DebugSession = 0;
  3791. args->DebugUiClientId.UniqueProcess = NULL;
  3792. args->DebugUiClientId.UniqueThread = NULL;
  3793. TargetSubSys = SmpLocateKnownSubSysByType(
  3794. MuSessionId,
  3795. ProcessInformation.ImageInformation.SubSystemType
  3796. );
  3797. if ( !TargetSubSys ) {
  3798. Status = STATUS_NO_SUCH_PACKAGE;
  3799. KdPrintEx((DPFLTR_SMSS_ID,
  3800. DPFLTR_WARNING_LEVEL,
  3801. "SMSS: SmpLoadSubSystem - SmpLocateKnownSubSysByType Failed with Status %lx for sessionid %ld\n",
  3802. Status,
  3803. MuSessionId));
  3804. goto cleanup;
  3805. }
  3806. //
  3807. // Transfer the handles to the subsystem responsible for this
  3808. // process.
  3809. //
  3810. Status = NtDuplicateObject( NtCurrentProcess(),
  3811. ProcessInformation.Process,
  3812. TargetSubSys->Process,
  3813. &args->ProcessInformation.Process,
  3814. PROCESS_ALL_ACCESS,
  3815. 0,
  3816. 0
  3817. );
  3818. if (!NT_SUCCESS( Status )) {
  3819. KdPrintEx((DPFLTR_SETUP_ID,
  3820. DPFLTR_WARNING_LEVEL,
  3821. "SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %ld\n",
  3822. Status,
  3823. MuSessionId));
  3824. goto cleanup;
  3825. }
  3826. Status = NtDuplicateObject( NtCurrentProcess(),
  3827. ProcessInformation.Thread,
  3828. TargetSubSys->Process,
  3829. &args->ProcessInformation.Thread,
  3830. THREAD_ALL_ACCESS,
  3831. 0,
  3832. 0
  3833. );
  3834. if (!NT_SUCCESS( Status )) {
  3835. KdPrintEx((DPFLTR_SETUP_ID,
  3836. DPFLTR_WARNING_LEVEL,
  3837. "SMSS: SmpLoadSubSystem - NtDuplicateObject Failed with Status %lx for sessionid %ld\n",
  3838. Status,
  3839. MuSessionId));
  3840. goto cleanup;
  3841. }
  3842. SessionId = SmpAllocateSessionId( TargetSubSys,
  3843. NULL
  3844. );
  3845. args->SessionId = SessionId;
  3846. SbApiMsg.ApiNumber = SbCreateSessionApi;
  3847. SbApiMsg.h.u1.s1.DataLength = sizeof(*args) + 8;
  3848. SbApiMsg.h.u1.s1.TotalLength = sizeof(SbApiMsg);
  3849. SbApiMsg.h.u2.ZeroInit = 0L;
  3850. Status = NtRequestWaitReplyPort(
  3851. TargetSubSys->SbApiCommunicationPort,
  3852. (PPORT_MESSAGE) &SbApiMsg,
  3853. (PPORT_MESSAGE) &SbApiMsg
  3854. );
  3855. if (NT_SUCCESS( Status )) {
  3856. Status = SbApiMsg.ReturnedStatus;
  3857. }
  3858. if (!NT_SUCCESS( Status )) {
  3859. SmpDeleteSession( SessionId);
  3860. KdPrintEx((DPFLTR_SMSS_ID,
  3861. DPFLTR_WARNING_LEVEL,
  3862. "SMSS: SmpLoadSubSystem - NtRequestWaitReplyPort Failed with Status %lx for sessionid %ld\n",
  3863. Status,
  3864. MuSessionId));
  3865. goto cleanup;
  3866. }
  3867. }
  3868. else {
  3869. if ( pWindowsSubSysProcessId ) {
  3870. if ( *pWindowsSubSysProcessId == (ULONG_PTR)NULL ) {
  3871. *pWindowsSubSysProcessId = (ULONG_PTR)
  3872. ProcessInformation.ClientId.UniqueProcess;
  3873. }
  3874. }
  3875. if ( !MuSessionId ) { // Only for console
  3876. SmpWindowsSubSysProcessId = (ULONG_PTR)
  3877. ProcessInformation.ClientId.UniqueProcess;
  3878. SmpWindowsSubSysProcess = ProcessInformation.Process;
  3879. }
  3880. }
  3881. ASSERTMSG( "NtCreateEvent", NT_SUCCESS( Status ) );
  3882. Status = NtResumeThread( ProcessInformation.Thread, NULL );
  3883. if (!NT_SUCCESS(Status)) {
  3884. KdPrintEx((DPFLTR_SMSS_ID,
  3885. DPFLTR_WARNING_LEVEL,
  3886. "SMSS: SmpLoadSubSystem - NtResumeThread failed Status %lx\n",
  3887. Status));
  3888. goto cleanup;
  3889. }
  3890. if(MuSessionId != 0) {
  3891. //
  3892. // Wait a max of 60 seconds for the subsystem to connect.
  3893. //
  3894. Timeout = RtlEnlargedIntegerMultiply( 60000, -10000 );
  3895. Status = NtWaitForSingleObject( KnownSubSys->Active, FALSE, &Timeout );
  3896. if ( !SmpCheckDuplicateMuSessionId( MuSessionId ) ) {
  3897. KdPrintEx((DPFLTR_SMSS_ID,
  3898. DPFLTR_INFO_LEVEL,
  3899. "SMSS: SmpLoadSubSystem - session deleted\n"));
  3900. return( STATUS_DELETE_PENDING );
  3901. }
  3902. if (Status != STATUS_SUCCESS) {
  3903. KdPrintEx((DPFLTR_SMSS_ID,
  3904. DPFLTR_WARNING_LEVEL,
  3905. "SMSS: SmpLoadSubSystem - Timeout waiting for subsystem connect with Status %lx for sessionid %ld \n",
  3906. Status,
  3907. MuSessionId));
  3908. goto cleanup;
  3909. }
  3910. } else {
  3911. NtWaitForSingleObject( KnownSubSys->Active, FALSE, NULL );
  3912. }
  3913. // Close this now since we never need it again
  3914. NtClose( ProcessInformation.Thread );
  3915. RtlEnterCriticalSection( &SmpKnownSubSysLock );
  3916. if (KnownSubSys) {
  3917. SmpDeferenceKnownSubSys(KnownSubSys);
  3918. }
  3919. if (TargetSubSys) {
  3920. SmpDeferenceKnownSubSys(TargetSubSys);
  3921. }
  3922. if (CreatorSubSys) {
  3923. SmpDeferenceKnownSubSys(CreatorSubSys);
  3924. }
  3925. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3926. return STATUS_SUCCESS;
  3927. cleanup:
  3928. if ((AttachedSessionId != (-1))
  3929. && !(Flags & SMP_POSIX_FLAG)
  3930. && !(Flags & SMP_OS2_FLAG)
  3931. && NT_SUCCESS(AcquirePrivilegeStatus = SmpAcquirePrivilege( SE_LOAD_DRIVER_PRIVILEGE, &State ))) {
  3932. NTSTATUS St;
  3933. //
  3934. // If we are attached to a session space, leave it
  3935. // so we can create a new one
  3936. //
  3937. if (NT_SUCCESS(St = NtSetSystemInformation(
  3938. SystemSessionDetach,
  3939. (PVOID)&AttachedSessionId,
  3940. sizeof(MuSessionId)
  3941. ))) {
  3942. AttachedSessionId = (-1);
  3943. } else {
  3944. //
  3945. // This has to succeed otherwise we will bugcheck while trying to
  3946. // create another session
  3947. //
  3948. KdPrintEx((DPFLTR_SMSS_ID,
  3949. DPFLTR_WARNING_LEVEL,
  3950. "SMSS: SmpStartCsr, Couldn't Detach from Session Space. Status=%x\n",
  3951. St));
  3952. ASSERT(NT_SUCCESS(St));
  3953. }
  3954. SmpReleasePrivilege( State );
  3955. }
  3956. else
  3957. {
  3958. KdPrintEx((DPFLTR_SMSS_ID,
  3959. DPFLTR_INFO_LEVEL,
  3960. "SMSS: Did not detach from Session Space: SessionId=%x Flags=%x Status=%x\n",
  3961. AttachedSessionId,
  3962. Flags,
  3963. AcquirePrivilegeStatus));
  3964. }
  3965. // There is a lot of cleanup that must be done here
  3966. NtTerminateProcess( ProcessInformation.Process, Status );
  3967. NtClose( ProcessInformation.Thread );
  3968. cleanup2:
  3969. RtlEnterCriticalSection( &SmpKnownSubSysLock );
  3970. if (TargetSubSys) {
  3971. SmpDeferenceKnownSubSys(TargetSubSys);
  3972. }
  3973. if (CreatorSubSys) {
  3974. SmpDeferenceKnownSubSys(CreatorSubSys);
  3975. }
  3976. RemoveEntryList( &KnownSubSys->Links );
  3977. NtSetEvent( KnownSubSys->Active, NULL );
  3978. KnownSubSys->Deleting = TRUE;
  3979. SmpDeferenceKnownSubSys(KnownSubSys);
  3980. RtlLeaveCriticalSection( &SmpKnownSubSysLock );
  3981. return( Status );
  3982. }
  3983. NTSTATUS
  3984. SmpExecuteInitialCommand(
  3985. IN ULONG MuSessionId,
  3986. IN PUNICODE_STRING InitialCommand,
  3987. OUT PHANDLE InitialCommandProcess,
  3988. OUT PULONG_PTR InitialCommandProcessId
  3989. )
  3990. {
  3991. NTSTATUS Status;
  3992. RTL_USER_PROCESS_INFORMATION ProcessInformation;
  3993. ULONG Flags;
  3994. UNICODE_STRING ImageFileName;
  3995. UNICODE_STRING CurrentDirectory;
  3996. UNICODE_STRING Arguments;
  3997. static HANDLE SmApiPort = NULL;
  3998. if ( SmApiPort == NULL ) {
  3999. Status = SmConnectToSm( NULL,
  4000. NULL,
  4001. 0,
  4002. &SmApiPort
  4003. );
  4004. if (!NT_SUCCESS( Status )) {
  4005. KdPrintEx((DPFLTR_SMSS_ID,
  4006. DPFLTR_WARNING_LEVEL,
  4007. "SMSS: Unable to connect to SM - Status == %lx\n",
  4008. Status));
  4009. return( Status );
  4010. }
  4011. }
  4012. Flags = 0;
  4013. Status = SmpParseCommandLine( InitialCommand,
  4014. &Flags,
  4015. &ImageFileName,
  4016. &CurrentDirectory,
  4017. &Arguments
  4018. );
  4019. if (Flags & SMP_IMAGE_NOT_FOUND) {
  4020. KdPrintEx((DPFLTR_SMSS_ID,
  4021. DPFLTR_WARNING_LEVEL,
  4022. "SMSS: Initial command image (%wZ) not found\n",
  4023. &ImageFileName));
  4024. if (ImageFileName.Buffer)
  4025. RtlFreeHeap( RtlProcessHeap(), 0, ImageFileName.Buffer );
  4026. return( STATUS_OBJECT_NAME_NOT_FOUND );
  4027. }
  4028. if (!NT_SUCCESS( Status )) {
  4029. KdPrintEx((DPFLTR_SMSS_ID,
  4030. DPFLTR_WARNING_LEVEL,
  4031. "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n",
  4032. InitialCommand,
  4033. Status));
  4034. return( Status );
  4035. }
  4036. Status = SmpExecuteImage( &ImageFileName,
  4037. &CurrentDirectory,
  4038. InitialCommand,
  4039. MuSessionId,
  4040. SMP_DONT_START,
  4041. &ProcessInformation
  4042. );
  4043. if (ImageFileName.Buffer) {
  4044. RtlFreeHeap( RtlProcessHeap(), 0, ImageFileName.Buffer );
  4045. if (CurrentDirectory.Buffer != NULL) {
  4046. RtlFreeHeap( RtlProcessHeap(), 0, CurrentDirectory.Buffer );
  4047. }
  4048. }
  4049. if (Arguments.Buffer) {
  4050. RtlFreeHeap( RtlProcessHeap(), 0, Arguments.Buffer );
  4051. }
  4052. if (!NT_SUCCESS( Status )) {
  4053. return( Status );
  4054. }
  4055. Status = NtDuplicateObject( NtCurrentProcess(),
  4056. ProcessInformation.Process,
  4057. NtCurrentProcess(),
  4058. InitialCommandProcess,
  4059. PROCESS_ALL_ACCESS,
  4060. 0,
  4061. 0
  4062. );
  4063. if (!NT_SUCCESS(Status) ) {
  4064. KdPrintEx((DPFLTR_SMSS_ID,
  4065. DPFLTR_WARNING_LEVEL,
  4066. "SMSS: DupObject Failed. Status == %lx\n",
  4067. Status));
  4068. NtTerminateProcess( ProcessInformation.Process, Status );
  4069. NtResumeThread( ProcessInformation.Thread, NULL );
  4070. NtClose( ProcessInformation.Thread );
  4071. NtClose( ProcessInformation.Process );
  4072. return( Status );
  4073. }
  4074. if ( InitialCommandProcessId != NULL )
  4075. *InitialCommandProcessId =
  4076. (ULONG_PTR)ProcessInformation.ClientId.UniqueProcess;
  4077. if ( !MuSessionId )
  4078. SmpInitialCommandProcessId =
  4079. (ULONG_PTR)ProcessInformation.ClientId.UniqueProcess;
  4080. Status = SmExecPgm( SmApiPort,
  4081. &ProcessInformation,
  4082. FALSE
  4083. );
  4084. if (!NT_SUCCESS( Status )) {
  4085. KdPrintEx((DPFLTR_SMSS_ID,
  4086. DPFLTR_WARNING_LEVEL,
  4087. "SMSS: SmExecPgm Failed. Status == %lx\n",
  4088. Status));
  4089. return( Status );
  4090. }
  4091. return( Status );
  4092. }
  4093. void
  4094. SmpDisplayString( char *s )
  4095. {
  4096. ANSI_STRING AnsiString;
  4097. UNICODE_STRING UnicodeString;
  4098. RtlInitAnsiString( &AnsiString, s );
  4099. RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );
  4100. NtDisplayString( &UnicodeString );
  4101. RtlFreeUnicodeString( &UnicodeString );
  4102. }
  4103. NTSTATUS
  4104. SmpLoadDeferedSubsystem(
  4105. IN PSMAPIMSG SmApiMsg,
  4106. IN PSMP_CLIENT_CONTEXT CallingClient,
  4107. IN HANDLE CallPort
  4108. )
  4109. {
  4110. NTSTATUS Status;
  4111. PLIST_ENTRY Head, Next;
  4112. PSMP_REGISTRY_VALUE p;
  4113. UNICODE_STRING DeferedName;
  4114. PSMLOADDEFERED args;
  4115. ULONG MuSessionId;
  4116. ULONG Flags;
  4117. args = &SmApiMsg->u.LoadDefered;
  4118. DeferedName.Length = (USHORT)args->SubsystemNameLength;
  4119. DeferedName.MaximumLength = (USHORT)args->SubsystemNameLength;
  4120. DeferedName.Buffer = args->SubsystemName;
  4121. Head = &SmpSubSystemsToDefer;
  4122. //
  4123. // Get the pointer to the client process's Terminal Server session.
  4124. //
  4125. SmpGetProcessMuSessionId( CallingClient->ClientProcessHandle, &MuSessionId );
  4126. if ( !SmpCheckDuplicateMuSessionId( MuSessionId ) ) {
  4127. KdPrintEx((DPFLTR_SMSS_ID,
  4128. DPFLTR_WARNING_LEVEL,
  4129. "SMSS: Defered subsystem load ( %wZ ) for MuSessionId %u, status=0x%x\n",
  4130. &DeferedName,
  4131. MuSessionId,
  4132. STATUS_OBJECT_NAME_NOT_FOUND));
  4133. return( STATUS_OBJECT_NAME_NOT_FOUND );
  4134. }
  4135. Next = Head->Flink;
  4136. while (Next != Head ) {
  4137. p = CONTAINING_RECORD( Next,
  4138. SMP_REGISTRY_VALUE,
  4139. Entry
  4140. );
  4141. if ( RtlEqualUnicodeString(&DeferedName,&p->Name,TRUE)) {
  4142. //
  4143. // This is it. Load the subsystem...
  4144. //
  4145. // To keep from loading multiple subsystems, we must
  4146. // flag the type so we can see if its running.
  4147. // This is only a problem with "Optional" subsystems.
  4148. // Other optional subsystems can still be added, but
  4149. // they may have startup race conditions.
  4150. //
  4151. Flags = SMP_SUBSYSTEM_FLAG;
  4152. if ( RtlEqualUnicodeString(&DeferedName,&PosixName,TRUE)) {
  4153. Flags |= SMP_POSIX_FLAG;
  4154. }
  4155. if ( RtlEqualUnicodeString(&DeferedName,&Os2Name,TRUE)) {
  4156. Flags |= SMP_OS2_FLAG;
  4157. }
  4158. if (RegPosixSingleInstance &&
  4159. RtlEqualUnicodeString(&DeferedName,&PosixName,TRUE)) {
  4160. Flags |= SMP_POSIX_SI_FLAG;
  4161. }
  4162. Status = SmpExecuteCommand( &p->Value, MuSessionId, NULL, Flags );
  4163. return Status;
  4164. }
  4165. Next = Next->Flink;
  4166. }
  4167. return STATUS_OBJECT_NAME_NOT_FOUND;
  4168. }
  4169. NTSTATUS
  4170. SmpConfigureProtectionMode(
  4171. IN PWSTR ValueName,
  4172. IN ULONG ValueType,
  4173. IN PVOID ValueData,
  4174. IN ULONG ValueLength,
  4175. IN PVOID Context,
  4176. IN PVOID EntryContext
  4177. )
  4178. /*++
  4179. Routine Description:
  4180. This function is a dispatch routine for the QueryRegistry call
  4181. (see SmpRegistryConfigurationTable[] earlier in this file).
  4182. The purpose of this routine is to read the Base Object Protection
  4183. Mode out of the registry. This information is kept in
  4184. Key Name: \\Hkey_Local_Machine\System\CurrentControlSet\SessionManager
  4185. Value: ProtectionMode [REG_DWORD]
  4186. The value is a flag word, with the following flags defined:
  4187. SMP_NO_PROTECTION - No base object protection
  4188. SMP_STANDARD_PROTECTION - Apply standard base
  4189. object protection
  4190. This information will be placed in the global variable
  4191. SmpProtectionMode.
  4192. No value, or an invalid value length or type results in no base
  4193. object protection being applied.
  4194. Arguments:
  4195. None.
  4196. Return Value:
  4197. --*/
  4198. {
  4199. #if SMP_SHOW_REGISTRY_DATA
  4200. SmpDumpQuery( L"SMSS", "BaseObjectsProtection", ValueName, ValueType, ValueData, ValueLength );
  4201. #else
  4202. UNREFERENCED_PARAMETER( ValueName );
  4203. UNREFERENCED_PARAMETER( ValueType );
  4204. #endif
  4205. if (ValueLength != sizeof(ULONG)) {
  4206. //
  4207. // Key value not valid. Run protected
  4208. //
  4209. SmpProtectionMode = SMP_STANDARD_PROTECTION;
  4210. } else {
  4211. SmpProtectionMode = (*((PULONG)(ValueData)));
  4212. //
  4213. // Change the security descriptors
  4214. //
  4215. }
  4216. (VOID)SmpCreateSecurityDescriptors( FALSE );
  4217. return( STATUS_SUCCESS );
  4218. }
  4219. NTSTATUS
  4220. SmpConfigureAllowProtectedRenames(
  4221. IN PWSTR ValueName,
  4222. IN ULONG ValueType,
  4223. IN PVOID ValueData,
  4224. IN ULONG ValueLength,
  4225. IN PVOID Context,
  4226. IN PVOID EntryContext
  4227. )
  4228. {
  4229. if (ValueLength != sizeof(ULONG)) {
  4230. SmpAllowProtectedRenames = 0;
  4231. } else {
  4232. SmpAllowProtectedRenames = (*((PULONG)(ValueData)));
  4233. }
  4234. return( STATUS_SUCCESS );
  4235. }
  4236. NTSTATUS
  4237. SmpCreateSecurityDescriptors(
  4238. IN BOOLEAN InitialCall
  4239. )
  4240. /*++
  4241. Routine Description:
  4242. This function allocates and initializes security descriptors
  4243. used in SM.
  4244. The security descriptors include:
  4245. SmpPrimarySecurityDescriptor - (global variable) This is
  4246. used to assign protection to objects created by
  4247. SM that need to be accessed by others, but not modified.
  4248. This descriptor grants the following access:
  4249. Grant: World: Execute | Read (Inherit)
  4250. Grant: Restricted: Execute | Read (Inherit)
  4251. Grant: Admin: All Access (Inherit)
  4252. Grant: Owner: All Access (Inherit Only)
  4253. SmpLiberalSecurityDescriptor = (globalVariable) This is used
  4254. to assign protection objects created by SM that need
  4255. to be modified by others (such as writing to a shared
  4256. memory section).
  4257. This descriptor grants the following access:
  4258. Grant: World: Execute | Read | Write (Inherit)
  4259. Grant: Restricted: Execute | Read | Write (Inherit)
  4260. Grant: Admin: All Access (Inherit)
  4261. Grant: Owner: All Access (Inherit Only)
  4262. SmpKnownDllsSecurityDescriptor = (globalVariable) This is used
  4263. to assign protection to the \KnownDlls object directory.
  4264. This descriptor grants the following access:
  4265. Grant: World: Execute (No Inherit)
  4266. Grant: Restricted: Execute (No Inherit)
  4267. Grant: Admin: All Access (Inherit)
  4268. Grant: World: Execute | Read | Write (Inherit Only)
  4269. Grant: Restricted: Execute | Read | Write (Inherit Only)
  4270. Note that System is an administrator, so granting Admin an
  4271. access also grants System that access.
  4272. Arguments:
  4273. InitialCall - Indicates whether this routine is being called for
  4274. the first time, or is being called to change the security
  4275. descriptors as a result of a protection mode change.
  4276. TRUE - being called for first time.
  4277. FALSE - being called a subsequent time.
  4278. (global variables: SmpBaseObjectsUnprotected)
  4279. Return Value:
  4280. STATUS_SUCCESS - The security descriptor(s) have been allocated
  4281. and initialized.
  4282. STATUS_NO_MEMORY - couldn't allocate memory for a security
  4283. descriptor.
  4284. --*/
  4285. {
  4286. NTSTATUS
  4287. Status;
  4288. PSID
  4289. WorldSid = NULL,
  4290. AdminSid = NULL,
  4291. LocalSystemSid = NULL,
  4292. RestrictedSid = NULL,
  4293. OwnerSid = NULL;
  4294. SID_IDENTIFIER_AUTHORITY
  4295. WorldAuthority = SECURITY_WORLD_SID_AUTHORITY,
  4296. NtAuthority = SECURITY_NT_AUTHORITY,
  4297. CreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  4298. ACCESS_MASK
  4299. AdminAccess = (GENERIC_ALL),
  4300. WorldAccess = (GENERIC_EXECUTE | GENERIC_READ),
  4301. OwnerAccess = (GENERIC_ALL),
  4302. RestrictedAccess = (GENERIC_EXECUTE | GENERIC_READ);
  4303. UCHAR
  4304. InheritOnlyFlags = (OBJECT_INHERIT_ACE |
  4305. CONTAINER_INHERIT_ACE |
  4306. INHERIT_ONLY_ACE);
  4307. ULONG
  4308. AceIndex,
  4309. AclLength;
  4310. PACL
  4311. Acl;
  4312. PACE_HEADER
  4313. Ace;
  4314. BOOLEAN
  4315. ProtectionRequired = FALSE;
  4316. if (InitialCall) {
  4317. //
  4318. // Now init the security descriptors for no protection.
  4319. // If told to, we will change these to have protection.
  4320. //
  4321. // Primary
  4322. SmpPrimarySecurityDescriptor = &SmpPrimarySDBody;
  4323. Status = RtlCreateSecurityDescriptor (
  4324. SmpPrimarySecurityDescriptor,
  4325. SECURITY_DESCRIPTOR_REVISION
  4326. );
  4327. ASSERT( NT_SUCCESS(Status) );
  4328. #pragma prefast(suppress: 248, "Protection enabled via registry")
  4329. Status = RtlSetDaclSecurityDescriptor (
  4330. SmpPrimarySecurityDescriptor,
  4331. TRUE, //DaclPresent,
  4332. NULL, //Dacl (no protection)
  4333. FALSE //DaclDefaulted OPTIONAL
  4334. );
  4335. ASSERT( NT_SUCCESS(Status) );
  4336. // Liberal
  4337. SmpLiberalSecurityDescriptor = &SmpLiberalSDBody;
  4338. Status = RtlCreateSecurityDescriptor (
  4339. SmpLiberalSecurityDescriptor,
  4340. SECURITY_DESCRIPTOR_REVISION
  4341. );
  4342. ASSERT( NT_SUCCESS(Status) );
  4343. #pragma prefast(suppress: 248, "Protection enabled via registry")
  4344. Status = RtlSetDaclSecurityDescriptor (
  4345. SmpLiberalSecurityDescriptor,
  4346. TRUE, //DaclPresent,
  4347. NULL, //Dacl (no protection)
  4348. FALSE //DaclDefaulted OPTIONAL
  4349. );
  4350. ASSERT( NT_SUCCESS(Status) );
  4351. // KnownDlls
  4352. SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody;
  4353. Status = RtlCreateSecurityDescriptor (
  4354. SmpKnownDllsSecurityDescriptor,
  4355. SECURITY_DESCRIPTOR_REVISION
  4356. );
  4357. ASSERT( NT_SUCCESS(Status) );
  4358. #pragma prefast(suppress: 248, "Protection enabled via registry")
  4359. Status = RtlSetDaclSecurityDescriptor (
  4360. SmpKnownDllsSecurityDescriptor,
  4361. TRUE, //DaclPresent,
  4362. NULL, //Dacl (no protection)
  4363. FALSE //DaclDefaulted OPTIONAL
  4364. );
  4365. ASSERT( NT_SUCCESS(Status) );
  4366. // ApiPort
  4367. SmpApiPortSecurityDescriptor = &SmpApiPortSDBody;
  4368. Status = RtlCreateSecurityDescriptor (
  4369. SmpApiPortSecurityDescriptor,
  4370. SECURITY_DESCRIPTOR_REVISION
  4371. );
  4372. ASSERT( NT_SUCCESS(Status) );
  4373. #pragma prefast(suppress: 248, "Protection enabled via registry")
  4374. Status = RtlSetDaclSecurityDescriptor (
  4375. SmpApiPortSecurityDescriptor,
  4376. TRUE, //DaclPresent,
  4377. NULL, //Dacl
  4378. FALSE //DaclDefaulted OPTIONAL
  4379. );
  4380. ASSERT( NT_SUCCESS(Status) );
  4381. }
  4382. if ((SmpProtectionMode & SMP_PROTECTION_REQUIRED) != 0) {
  4383. ProtectionRequired = TRUE;
  4384. }
  4385. if (!InitialCall && !ProtectionRequired) {
  4386. return(STATUS_SUCCESS);
  4387. }
  4388. if (InitialCall || ProtectionRequired) {
  4389. //
  4390. // We need to set up the ApiPort protection, and maybe
  4391. // others.
  4392. //
  4393. Status = RtlAllocateAndInitializeSid (&WorldAuthority,
  4394. 1,
  4395. SECURITY_WORLD_RID,
  4396. 0, 0, 0, 0, 0, 0, 0,
  4397. &WorldSid);
  4398. if (!NT_SUCCESS (Status)) {
  4399. WorldSid = NULL;
  4400. goto exit_and_free;
  4401. }
  4402. Status = RtlAllocateAndInitializeSid (&NtAuthority,
  4403. 2,
  4404. SECURITY_BUILTIN_DOMAIN_RID,
  4405. DOMAIN_ALIAS_RID_ADMINS,
  4406. 0, 0, 0, 0, 0, 0,
  4407. &AdminSid);
  4408. if (!NT_SUCCESS (Status)) {
  4409. AdminSid = NULL;
  4410. goto exit_and_free;
  4411. }
  4412. Status = RtlAllocateAndInitializeSid (&CreatorAuthority,
  4413. 1,
  4414. SECURITY_CREATOR_OWNER_RID,
  4415. 0, 0, 0, 0, 0, 0, 0,
  4416. &OwnerSid);
  4417. if (!NT_SUCCESS (Status)) {
  4418. OwnerSid = NULL;
  4419. goto exit_and_free;
  4420. }
  4421. Status = RtlAllocateAndInitializeSid (&NtAuthority,
  4422. 1,
  4423. SECURITY_RESTRICTED_CODE_RID,
  4424. 0, 0, 0, 0, 0, 0, 0,
  4425. &RestrictedSid);
  4426. if (!NT_SUCCESS (Status)) {
  4427. RestrictedSid = NULL;
  4428. goto exit_and_free;
  4429. }
  4430. Status = RtlAllocateAndInitializeSid (&NtAuthority,
  4431. 1,
  4432. SECURITY_LOCAL_SYSTEM_RID,
  4433. 0, 0, 0, 0, 0, 0, 0,
  4434. &LocalSystemSid);
  4435. if (!NT_SUCCESS (Status)) {
  4436. LocalSystemSid = NULL;
  4437. goto exit_and_free;
  4438. }
  4439. //
  4440. // Build the ApiPort security descriptor only
  4441. // if this is the initial call
  4442. //
  4443. if (InitialCall) {
  4444. AdminAccess = GENERIC_ALL;
  4445. AclLength = sizeof( ACL ) +
  4446. 2 * sizeof( ACCESS_ALLOWED_ACE ) +
  4447. RtlLengthSid( LocalSystemSid ) +
  4448. RtlLengthSid( AdminSid );
  4449. Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
  4450. if (Acl == NULL) {
  4451. Status = STATUS_NO_MEMORY;
  4452. }
  4453. if (NT_SUCCESS(Status)) {
  4454. //
  4455. // Create the ACL, then add each ACE
  4456. //
  4457. Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
  4458. ASSERT( NT_SUCCESS(Status) );
  4459. //
  4460. // Only Non-inheritable ACEs in this ACL
  4461. // Admin
  4462. //
  4463. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
  4464. ASSERT( NT_SUCCESS(Status) );
  4465. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, LocalSystemSid );
  4466. ASSERT( NT_SUCCESS(Status) );
  4467. Status = RtlSetDaclSecurityDescriptor (SmpApiPortSecurityDescriptor,
  4468. TRUE, //DaclPresent,
  4469. Acl, //Dacl
  4470. FALSE); //DaclDefaulted OPTIONAL
  4471. ASSERT( NT_SUCCESS(Status) );
  4472. }
  4473. //
  4474. // Build the KnownDlls security descriptor
  4475. //
  4476. AdminAccess = GENERIC_ALL;
  4477. AclLength = sizeof( ACL ) +
  4478. 6 * sizeof( ACCESS_ALLOWED_ACE ) +
  4479. (2*RtlLengthSid( WorldSid )) +
  4480. (2*RtlLengthSid( RestrictedSid ))+
  4481. (2*RtlLengthSid( AdminSid ));
  4482. Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
  4483. if (Acl == NULL) {
  4484. Status = STATUS_NO_MEMORY;
  4485. }
  4486. if (NT_SUCCESS(Status)) {
  4487. //
  4488. // Create the ACL
  4489. //
  4490. Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
  4491. ASSERT( NT_SUCCESS(Status) );
  4492. //
  4493. // Add the non-inheritable ACEs first
  4494. // World
  4495. // Restricted
  4496. // Admin
  4497. //
  4498. AceIndex = 0;
  4499. WorldAccess = GENERIC_EXECUTE;
  4500. RestrictedAccess = GENERIC_EXECUTE;
  4501. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
  4502. ASSERT( NT_SUCCESS(Status) );
  4503. AceIndex++;
  4504. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  4505. ASSERT( NT_SUCCESS(Status) );
  4506. AceIndex++;
  4507. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
  4508. ASSERT( NT_SUCCESS(Status) );
  4509. //
  4510. // Put the inherit only ACEs at at the end
  4511. // World
  4512. // Restricted
  4513. // Admin
  4514. //
  4515. AceIndex++;
  4516. WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
  4517. RestrictedAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
  4518. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
  4519. ASSERT( NT_SUCCESS(Status) );
  4520. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4521. ASSERT( NT_SUCCESS(Status) );
  4522. Ace->AceFlags = InheritOnlyFlags;
  4523. AceIndex++;
  4524. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  4525. ASSERT( NT_SUCCESS(Status) );
  4526. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4527. ASSERT( NT_SUCCESS(Status) );
  4528. Ace->AceFlags = InheritOnlyFlags;
  4529. AceIndex++;
  4530. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
  4531. ASSERT( NT_SUCCESS(Status) );
  4532. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4533. ASSERT( NT_SUCCESS(Status) );
  4534. Ace->AceFlags = InheritOnlyFlags;
  4535. //
  4536. // Put the Acl in the security descriptor
  4537. //
  4538. Status = RtlSetDaclSecurityDescriptor (SmpKnownDllsSecurityDescriptor,
  4539. TRUE, //DaclPresent,
  4540. Acl, //Dacl
  4541. FALSE); //DaclDefaulted OPTIONAL
  4542. ASSERT( NT_SUCCESS(Status) );
  4543. }
  4544. }
  4545. //
  4546. // The remaining security descriptors are only
  4547. // built if we are running with the correct in
  4548. // protection mode set. Notice that we only
  4549. // put protection on if standard protection is
  4550. // also specified. Otherwise, there is no protection
  4551. // on the objects, and nothing should fail.
  4552. //
  4553. if (SmpProtectionMode & SMP_STANDARD_PROTECTION) {
  4554. //
  4555. // Build the primary Security descriptor
  4556. //
  4557. WorldAccess = GENERIC_EXECUTE | GENERIC_READ;
  4558. RestrictedAccess = GENERIC_EXECUTE | GENERIC_READ;
  4559. AdminAccess = GENERIC_ALL;
  4560. OwnerAccess = GENERIC_ALL;
  4561. AclLength = sizeof( ACL ) +
  4562. 7 * sizeof( ACCESS_ALLOWED_ACE ) +
  4563. (2*RtlLengthSid( WorldSid )) +
  4564. (2*RtlLengthSid( RestrictedSid )) +
  4565. (2*RtlLengthSid( AdminSid )) +
  4566. RtlLengthSid( OwnerSid );
  4567. Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
  4568. if (Acl == NULL) {
  4569. Status = STATUS_NO_MEMORY;
  4570. }
  4571. if (NT_SUCCESS(Status)) {
  4572. //
  4573. // Create the ACL, then add each ACE
  4574. //
  4575. Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
  4576. ASSERT( NT_SUCCESS(Status) );
  4577. //
  4578. // Non-inheritable ACEs first
  4579. // World
  4580. // Restricted
  4581. // Admin
  4582. //
  4583. AceIndex = 0;
  4584. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
  4585. ASSERT( NT_SUCCESS(Status) );
  4586. AceIndex++;
  4587. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  4588. ASSERT( NT_SUCCESS(Status) );
  4589. AceIndex++;
  4590. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
  4591. ASSERT( NT_SUCCESS(Status) );
  4592. //
  4593. // Inheritable ACEs at end of ACE
  4594. // World
  4595. // Restricted
  4596. // Admin
  4597. // Owner
  4598. AceIndex++;
  4599. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
  4600. ASSERT( NT_SUCCESS(Status) );
  4601. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4602. ASSERT( NT_SUCCESS(Status) );
  4603. Ace->AceFlags = InheritOnlyFlags;
  4604. AceIndex++;
  4605. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  4606. ASSERT( NT_SUCCESS(Status) );
  4607. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4608. ASSERT( NT_SUCCESS(Status) );
  4609. Ace->AceFlags = InheritOnlyFlags;
  4610. AceIndex++;
  4611. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
  4612. ASSERT( NT_SUCCESS(Status) );
  4613. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4614. ASSERT( NT_SUCCESS(Status) );
  4615. Ace->AceFlags = InheritOnlyFlags;
  4616. AceIndex++;
  4617. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, OwnerAccess, OwnerSid );
  4618. ASSERT( NT_SUCCESS(Status) );
  4619. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4620. ASSERT( NT_SUCCESS(Status) );
  4621. Ace->AceFlags = InheritOnlyFlags;
  4622. Status = RtlSetDaclSecurityDescriptor (
  4623. SmpPrimarySecurityDescriptor,
  4624. TRUE, //DaclPresent,
  4625. Acl, //Dacl
  4626. FALSE //DaclDefaulted OPTIONAL
  4627. );
  4628. ASSERT( NT_SUCCESS(Status) );
  4629. }
  4630. //
  4631. // Build the liberal security descriptor
  4632. //
  4633. AdminAccess = GENERIC_ALL;
  4634. WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
  4635. RestrictedAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE;
  4636. AclLength = sizeof( ACL ) +
  4637. 7 * sizeof( ACCESS_ALLOWED_ACE ) +
  4638. (2*RtlLengthSid( WorldSid )) +
  4639. (2*RtlLengthSid( RestrictedSid ))+
  4640. (2*RtlLengthSid( AdminSid )) +
  4641. RtlLengthSid( OwnerSid );
  4642. Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength );
  4643. if (Acl == NULL) {
  4644. Status = STATUS_NO_MEMORY;
  4645. }
  4646. if (NT_SUCCESS(Status)) {
  4647. //
  4648. // Create the ACL
  4649. //
  4650. Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 );
  4651. ASSERT( NT_SUCCESS(Status) );
  4652. //
  4653. // Add the non-inheritable ACEs first
  4654. // World
  4655. // Restricted
  4656. // Admin
  4657. //
  4658. AceIndex = 0;
  4659. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
  4660. ASSERT( NT_SUCCESS(Status) );
  4661. AceIndex++;
  4662. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  4663. ASSERT( NT_SUCCESS(Status) );
  4664. AceIndex++;
  4665. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
  4666. ASSERT( NT_SUCCESS(Status) );
  4667. //
  4668. // Put the inherit only ACEs at at the end
  4669. // World
  4670. // Restricted
  4671. // Admin
  4672. // Owner
  4673. //
  4674. AceIndex++;
  4675. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid );
  4676. ASSERT( NT_SUCCESS(Status) );
  4677. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4678. ASSERT( NT_SUCCESS(Status) );
  4679. Ace->AceFlags = InheritOnlyFlags;
  4680. AceIndex++;
  4681. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, RestrictedAccess, RestrictedSid );
  4682. ASSERT( NT_SUCCESS(Status) );
  4683. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4684. ASSERT( NT_SUCCESS(Status) );
  4685. Ace->AceFlags = InheritOnlyFlags;
  4686. AceIndex++;
  4687. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid );
  4688. ASSERT( NT_SUCCESS(Status) );
  4689. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4690. ASSERT( NT_SUCCESS(Status) );
  4691. Ace->AceFlags = InheritOnlyFlags;
  4692. AceIndex++;
  4693. Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, OwnerAccess, OwnerSid );
  4694. ASSERT( NT_SUCCESS(Status) );
  4695. Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace );
  4696. ASSERT( NT_SUCCESS(Status) );
  4697. Ace->AceFlags = InheritOnlyFlags;
  4698. //
  4699. // Put the Acl in the security descriptor
  4700. //
  4701. Status = RtlSetDaclSecurityDescriptor (SmpLiberalSecurityDescriptor,
  4702. TRUE, //DaclPresent,
  4703. Acl, //Dacl
  4704. FALSE); //DaclDefaulted OPTIONAL
  4705. ASSERT( NT_SUCCESS(Status) );
  4706. }
  4707. }
  4708. }
  4709. exit_and_free:
  4710. if (OwnerSid != NULL) {
  4711. RtlFreeHeap( RtlProcessHeap(), 0, OwnerSid );
  4712. }
  4713. if (AdminSid != NULL) {
  4714. RtlFreeHeap( RtlProcessHeap(), 0, AdminSid );
  4715. }
  4716. if (WorldSid != NULL) {
  4717. RtlFreeHeap( RtlProcessHeap(), 0, WorldSid );
  4718. }
  4719. if (LocalSystemSid != NULL) {
  4720. RtlFreeHeap( RtlProcessHeap(), 0, LocalSystemSid );
  4721. }
  4722. if (RestrictedSid != NULL) {
  4723. RtlFreeHeap( RtlProcessHeap(), 0, RestrictedSid );
  4724. }
  4725. return( Status );
  4726. }
  4727. VOID
  4728. SmpTranslateSystemPartitionInformation( VOID )
  4729. /*++
  4730. Routine Description:
  4731. This routine translates the NT device path for the system partition (stored
  4732. during IoInitSystem) into a DOS path, and stores the resulting REG_SZ 'BootDir'
  4733. value under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup
  4734. Arguments:
  4735. None.
  4736. Return Value:
  4737. None.
  4738. --*/
  4739. {
  4740. NTSTATUS Status;
  4741. UNICODE_STRING UnicodeString;
  4742. OBJECT_ATTRIBUTES ObjectAttributes;
  4743. HANDLE Key;
  4744. UCHAR ValueBuffer[ VALUE_BUFFER_SIZE ];
  4745. ULONG ValueLength;
  4746. UNICODE_STRING SystemPartitionString;
  4747. POBJECT_DIRECTORY_INFORMATION DirInfo;
  4748. UCHAR DirInfoBuffer[ sizeof(OBJECT_DIRECTORY_INFORMATION) + (256 + sizeof("SymbolicLink")) * sizeof(WCHAR) ];
  4749. UNICODE_STRING LinkTypeName;
  4750. BOOLEAN RestartScan;
  4751. ULONG Context;
  4752. HANDLE SymbolicLinkHandle;
  4753. WCHAR UnicodeBuffer[ MAXIMUM_FILENAME_LENGTH ];
  4754. UNICODE_STRING LinkTarget;
  4755. //
  4756. // Retrieve 'SystemPartition' value stored under HKLM\SYSTEM\Setup
  4757. //
  4758. RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup");
  4759. InitializeObjectAttributes(&ObjectAttributes,
  4760. &UnicodeString,
  4761. OBJ_CASE_INSENSITIVE,
  4762. NULL,
  4763. NULL
  4764. );
  4765. Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes);
  4766. if (!NT_SUCCESS(Status)) {
  4767. KdPrintEx((DPFLTR_SMSS_ID,
  4768. DPFLTR_WARNING_LEVEL,
  4769. "SMSS: can't open system setup key for reading: 0x%x\n",
  4770. Status));
  4771. return;
  4772. }
  4773. RtlInitUnicodeString(&UnicodeString, L"SystemPartition");
  4774. Status = NtQueryValueKey(Key,
  4775. &UnicodeString,
  4776. KeyValuePartialInformation,
  4777. ValueBuffer,
  4778. sizeof(ValueBuffer),
  4779. &ValueLength
  4780. );
  4781. NtClose(Key);
  4782. if (!NT_SUCCESS(Status)) {
  4783. KdPrintEx((DPFLTR_SMSS_ID,
  4784. DPFLTR_WARNING_LEVEL,
  4785. "SMSS: can't query SystemPartition value: 0x%x\n",
  4786. Status));
  4787. return;
  4788. }
  4789. RtlInitUnicodeString(&SystemPartitionString,
  4790. (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer)->Data)
  4791. );
  4792. //
  4793. // Next, examine objects in the DosDevices directory, looking for one that's a symbolic link
  4794. // to the system partition.
  4795. //
  4796. LinkTarget.Buffer = UnicodeBuffer;
  4797. DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer;
  4798. RestartScan = TRUE;
  4799. RtlInitUnicodeString(&LinkTypeName, L"SymbolicLink");
  4800. while (TRUE) {
  4801. Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory,
  4802. DirInfo,
  4803. sizeof(DirInfoBuffer),
  4804. TRUE,
  4805. RestartScan,
  4806. &Context,
  4807. NULL
  4808. );
  4809. if (!NT_SUCCESS(Status)) {
  4810. break;
  4811. }
  4812. if (RtlEqualUnicodeString(&DirInfo->TypeName, &LinkTypeName, TRUE) &&
  4813. (DirInfo->Name.Length == 2 * sizeof(WCHAR)) &&
  4814. (DirInfo->Name.Buffer[1] == L':')) {
  4815. //
  4816. // We have a drive letter--check the NT device name it's linked to.
  4817. //
  4818. InitializeObjectAttributes(&ObjectAttributes,
  4819. &DirInfo->Name,
  4820. OBJ_CASE_INSENSITIVE,
  4821. SmpDosDevicesObjectDirectory,
  4822. NULL
  4823. );
  4824. Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle,
  4825. SYMBOLIC_LINK_ALL_ACCESS,
  4826. &ObjectAttributes
  4827. );
  4828. if (NT_SUCCESS(Status)) {
  4829. LinkTarget.Length = 0;
  4830. LinkTarget.MaximumLength = sizeof(UnicodeBuffer);
  4831. Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle,
  4832. &LinkTarget,
  4833. NULL
  4834. );
  4835. NtClose(SymbolicLinkHandle);
  4836. //
  4837. // The last part of the test below handles the remote boot case,
  4838. // where the system partition is on a redirected drive.
  4839. //
  4840. if (NT_SUCCESS(Status) &&
  4841. ( RtlEqualUnicodeString(&SystemPartitionString, &LinkTarget, TRUE)
  4842. || (RtlPrefixUnicodeString(&SystemPartitionString, &LinkTarget, TRUE)
  4843. && (LinkTarget.Buffer[SystemPartitionString.Length / sizeof(WCHAR)] == L'\\')) )
  4844. ) {
  4845. //
  4846. // We've found the drive letter corresponding to the system partition.
  4847. //
  4848. break;
  4849. }
  4850. }
  4851. }
  4852. RestartScan = FALSE;
  4853. }
  4854. if (!NT_SUCCESS(Status)) {
  4855. #if defined (_WIN64)
  4856. if (Status == STATUS_NO_MORE_ENTRIES) {
  4857. DirInfo->Name.Buffer = (PWCHAR)(DirInfo+1);
  4858. DirInfo->Name.Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0];
  4859. DirInfo->Name.Buffer[1] = USER_SHARED_DATA->NtSystemRoot[1];
  4860. } else {
  4861. #endif
  4862. KdPrintEx((DPFLTR_SMSS_ID,
  4863. DPFLTR_WARNING_LEVEL,
  4864. "SMSS: can't find drive letter for system partition\n"));
  4865. return;
  4866. #if defined (_WIN64)
  4867. }
  4868. #endif
  4869. }
  4870. //
  4871. // Now write out the DOS path for the system partition to
  4872. // HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup
  4873. //
  4874. RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup");
  4875. InitializeObjectAttributes(&ObjectAttributes,
  4876. &UnicodeString,
  4877. OBJ_CASE_INSENSITIVE,
  4878. NULL,
  4879. NULL
  4880. );
  4881. Status = NtOpenKey(&Key, KEY_ALL_ACCESS, &ObjectAttributes);
  4882. if (!NT_SUCCESS(Status)) {
  4883. KdPrintEx((DPFLTR_SMSS_ID,
  4884. DPFLTR_WARNING_LEVEL,
  4885. "SMSS: can't open software setup key for writing: 0x%x\n",
  4886. Status));
  4887. return;
  4888. }
  4889. wcsncpy(UnicodeBuffer, DirInfo->Name.Buffer, 2);
  4890. UnicodeBuffer[2] = L'\\';
  4891. UnicodeBuffer[3] = L'\0';
  4892. RtlInitUnicodeString(&UnicodeString, L"BootDir");
  4893. Status = NtSetValueKey(Key,
  4894. &UnicodeString,
  4895. 0,
  4896. REG_SZ,
  4897. UnicodeBuffer,
  4898. 4 * sizeof(WCHAR)
  4899. );
  4900. if (!NT_SUCCESS(Status)) {
  4901. KdPrintEx((DPFLTR_SMSS_ID,
  4902. DPFLTR_WARNING_LEVEL,
  4903. "SMSS: couldn't write BootDir value: 0x%x\n",
  4904. Status));
  4905. }
  4906. NtClose(Key);
  4907. }
  4908. #if defined(REMOTE_BOOT)
  4909. NTSTATUS
  4910. SmpExecuteCommandLineArguments( VOID )
  4911. /*++
  4912. Routine Description:
  4913. This routine processes any command line arguments that were passed to SMSS.exe.
  4914. Currently the only valid ones are netboot commands.
  4915. Arguments:
  4916. None.
  4917. Return Value:
  4918. Success or not.
  4919. --*/
  4920. {
  4921. UNICODE_STRING CfgFileName;
  4922. UNICODE_STRING MbrName;
  4923. UNICODE_STRING AutoFmtCmd;
  4924. UNICODE_STRING UnicodeString;
  4925. OBJECT_ATTRIBUTES ObjectAttributes;
  4926. OBJECT_ATTRIBUTES KeyObjectAttributes;
  4927. IO_STATUS_BLOCK IoStatusBlock;
  4928. HANDLE FileHandle;
  4929. HANDLE SourceHandle;
  4930. HANDLE TargetHandle;
  4931. NTSTATUS Status;
  4932. ULONG BootSerialNumber;
  4933. ULONG DiskSignature;
  4934. ULONG CmdFlags;
  4935. ULONG Length;
  4936. LARGE_INTEGER ByteOffset;
  4937. PUCHAR AlignedBuffer;
  4938. ON_DISK_MBR OnDiskMbr;
  4939. BOOLEAN WasEnabled;
  4940. HANDLE Key;
  4941. WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
  4942. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
  4943. ULONG ValueLength;
  4944. ULONG Repartition;
  4945. ULONG Disk;
  4946. ULONG Partition;
  4947. ULONG CSCPartition;
  4948. PWCHAR pWchar;
  4949. if (!SmpNetboot || SmpNetbootDisconnected) {
  4950. return STATUS_SUCCESS;
  4951. }
  4952. //
  4953. // Open the remoteboot.cfg file
  4954. //
  4955. RtlInitUnicodeString(&UnicodeString, L"\\SystemRoot");
  4956. InitializeObjectAttributes(
  4957. &ObjectAttributes,
  4958. &UnicodeString,
  4959. OBJ_CASE_INSENSITIVE,
  4960. NULL,
  4961. NULL
  4962. );
  4963. Status = NtOpenSymbolicLinkObject(&FileHandle,
  4964. (ACCESS_MASK)SYMBOLIC_LINK_QUERY,
  4965. &ObjectAttributes
  4966. );
  4967. if (!NT_SUCCESS(Status)) {
  4968. KdPrintEx((DPFLTR_SMSS_ID,
  4969. DPFLTR_WARNING_LEVEL,
  4970. "SMSS: Could not open symbolic link (Status 0x%x) -- quitting.\n",
  4971. Status));
  4972. Status = STATUS_SUCCESS;
  4973. goto CleanUp;
  4974. }
  4975. UnicodeString.Length = 0;
  4976. UnicodeString.MaximumLength = sizeof(TmpBuffer);
  4977. UnicodeString.Buffer = (PWCHAR)TmpBuffer;
  4978. Status = NtQuerySymbolicLinkObject(FileHandle,
  4979. &UnicodeString,
  4980. NULL
  4981. );
  4982. NtClose(FileHandle);
  4983. FileHandle = NULL;
  4984. if (!NT_SUCCESS(Status)) {
  4985. KdPrintEx((DPFLTR_SMSS_ID,
  4986. DPFLTR_WARNING_LEVEL,
  4987. "SMSS: Could not get symbolic link name (Status 0x%x) -- quitting.\n",
  4988. Status));
  4989. Status = STATUS_SUCCESS;
  4990. goto CleanUp;
  4991. }
  4992. ASSERT(((wcslen((PWCHAR)TmpBuffer) * sizeof(WCHAR)) - sizeof(L"BootDrive")) <
  4993. (sizeof(wszRemoteBootCfgFile) - sizeof(REMOTE_BOOT_CFG_FILE))
  4994. );
  4995. wcscpy(wszRemoteBootCfgFile, (PWCHAR)TmpBuffer);
  4996. pWchar = wcsstr(wszRemoteBootCfgFile, L"BootDrive");
  4997. ASSERT(pWchar != NULL);
  4998. *pWchar = UNICODE_NULL;
  4999. wcscat(wszRemoteBootCfgFile, REMOTE_BOOT_CFG_FILE);
  5000. CfgFileName.Length = wcslen(wszRemoteBootCfgFile) * sizeof(WCHAR);
  5001. CfgFileName.MaximumLength = sizeof(wszRemoteBootCfgFile);
  5002. CfgFileName.Buffer = wszRemoteBootCfgFile;
  5003. InitializeObjectAttributes(
  5004. &ObjectAttributes,
  5005. &CfgFileName,
  5006. OBJ_CASE_INSENSITIVE,
  5007. NULL,
  5008. NULL
  5009. );
  5010. Status = NtOpenFile( &FileHandle,
  5011. GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
  5012. &ObjectAttributes,
  5013. &IoStatusBlock,
  5014. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5015. FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS
  5016. );
  5017. //
  5018. // If it does not exist, then set the flags for reformatting and repinning.
  5019. //
  5020. if (!NT_SUCCESS(Status)) {
  5021. KdPrintEx((DPFLTR_SMSS_ID,
  5022. DPFLTR_WARNING_LEVEL,
  5023. "SMSS: Could not open file (status 0x%x) -- creating it.\n",
  5024. Status));
  5025. //
  5026. // Create the remoteboot.cfg in the system32\config directory if it does not exist.
  5027. //
  5028. CreateFile:
  5029. Status = NtCreateFile( &FileHandle,
  5030. GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
  5031. &ObjectAttributes,
  5032. &IoStatusBlock,
  5033. NULL,
  5034. FILE_ATTRIBUTE_HIDDEN,
  5035. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5036. FILE_OVERWRITE_IF,
  5037. FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS,
  5038. NULL,
  5039. 0
  5040. );
  5041. if (!NT_SUCCESS(Status)) {
  5042. //
  5043. // Something is really wrong, we will just exit and hope all is good.
  5044. // DEADISSUE, HISTORICAL CODE ONLY: This OK?
  5045. KdPrintEx((DPFLTR_SMSS_ID,
  5046. DPFLTR_WARNING_LEVEL,
  5047. "SMSS: Could not create file (Status 0x%x) -- quitting.\n",
  5048. Status));
  5049. Status = STATUS_SUCCESS;
  5050. goto CleanUp;
  5051. }
  5052. SmpAutoFormat = TRUE;
  5053. BootSerialNumber = 1;
  5054. } else {
  5055. Status = NtReadFile( FileHandle,
  5056. NULL,
  5057. NULL,
  5058. NULL,
  5059. &IoStatusBlock,
  5060. &BootSerialNumber,
  5061. sizeof(ULONG),
  5062. NULL,
  5063. NULL
  5064. );
  5065. if (!NT_SUCCESS(Status)) {
  5066. KdPrintEx((DPFLTR_SMSS_ID,
  5067. DPFLTR_WARNING_LEVEL,
  5068. "SMSS: Could not read file (Status 0x%x) -- creating it.\n",
  5069. Status));
  5070. NtClose( FileHandle );
  5071. goto CreateFile;
  5072. }
  5073. BootSerialNumber++;
  5074. }
  5075. //
  5076. // Process each command
  5077. //
  5078. if (SmpAutoFormat) {
  5079. //
  5080. // Read from the registry if it is ok to reformat, or just leave the disk alone.
  5081. //
  5082. Repartition = 1;
  5083. KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  5084. RtlInitUnicodeString(&UnicodeString,
  5085. L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\RemoteBoot");
  5086. InitializeObjectAttributes(&KeyObjectAttributes,
  5087. &UnicodeString,
  5088. OBJ_CASE_INSENSITIVE,
  5089. NULL,
  5090. NULL);
  5091. Status = NtOpenKey(&Key, KEY_READ, &KeyObjectAttributes);
  5092. if (NT_SUCCESS(Status)) {
  5093. //
  5094. // Query the key value.
  5095. //
  5096. RtlInitUnicodeString(&UnicodeString, L"Repartition");
  5097. Status = NtQueryValueKey(Key,
  5098. &UnicodeString,
  5099. KeyValuePartialInformation,
  5100. (PVOID)KeyValueInfo,
  5101. sizeof (ValueBuffer),
  5102. &ValueLength);
  5103. if (NT_SUCCESS(Status)) {
  5104. ASSERT(ValueLength <= VALUE_BUFFER_SIZE);
  5105. Repartition = *((PULONG)KeyValueInfo->Data);
  5106. }
  5107. NtClose(Key);
  5108. }
  5109. SmpGetHarddiskBootPartition(&Disk, &Partition);
  5110. if (Repartition) {
  5111. KdPrintEx((DPFLTR_SMSS_ID,
  5112. DPFLTR_INFO_LEVEL,
  5113. "SMSS: Autoformatting local disk.\n"));
  5114. NtClose(FileHandle);
  5115. //
  5116. // Repartition the disk.
  5117. //
  5118. SmpPartitionDisk(Disk, &Partition);
  5119. //
  5120. // Call autoformat on the partition
  5121. //
  5122. swprintf((PWSTR)TmpBuffer,
  5123. L"autoformat autofmt \\Device\\Harddisk%d\\Partition%d /Q /fs:ntfs",
  5124. Disk,
  5125. Partition
  5126. );
  5127. AutoFmtCmd.Buffer = (PWSTR)TmpBuffer;
  5128. AutoFmtCmd.MaximumLength = sizeof(TmpBuffer);
  5129. AutoFmtCmd.Length = wcslen((PWSTR)TmpBuffer) * sizeof(WCHAR);
  5130. CmdFlags = 0;
  5131. Status = SmpExecuteCommand(&AutoFmtCmd, 0, NULL, CmdFlags);
  5132. if (!NT_SUCCESS(Status)) {
  5133. //
  5134. // Big Trouble....
  5135. // CSC is disabled if we get here, so just keep on booting.
  5136. //
  5137. Status = STATUS_SUCCESS;
  5138. goto CleanUp;
  5139. }
  5140. } else {
  5141. SmpFindCSCPartition(Disk, &CSCPartition);
  5142. if (CSCPartition != 0) {
  5143. //
  5144. // Just blow away the CSC directory so we can refresh it
  5145. //
  5146. swprintf((PWSTR)TmpBuffer,
  5147. L"\\Device\\Harddisk%d\\Partition%d%ws",
  5148. Disk,
  5149. CSCPartition,
  5150. REMOTE_BOOT_IMIRROR_PATH_W REMOTE_BOOT_CSC_SUBDIR_W
  5151. );
  5152. SmpEnumFilesRecursive(
  5153. (PWSTR)TmpBuffer,
  5154. SmpDelEnumFile,
  5155. &Status,
  5156. NULL
  5157. );
  5158. if (!NT_SUCCESS(Status)) {
  5159. //
  5160. // Ignore this error, and hope that the next boot will fix. Just keep booting this
  5161. // time and hope.
  5162. //
  5163. Status = STATUS_SUCCESS;
  5164. goto CleanUp;
  5165. }
  5166. }
  5167. }
  5168. //
  5169. // Copy the NtLdr to the local disk
  5170. //
  5171. SourceHandle = SmpOpenDir( TRUE, TRUE, L"\\" );
  5172. if (SourceHandle == NULL) {
  5173. Status = STATUS_SUCCESS;
  5174. goto CleanUp;
  5175. }
  5176. swprintf((PWSTR)TmpBuffer,
  5177. L"\\Device\\Harddisk%d\\Partition%d",
  5178. Disk,
  5179. Partition
  5180. );
  5181. RtlInitUnicodeString(&UnicodeString, (PWSTR)TmpBuffer);
  5182. InitializeObjectAttributes(
  5183. &ObjectAttributes,
  5184. &UnicodeString,
  5185. OBJ_CASE_INSENSITIVE,
  5186. NULL,
  5187. NULL
  5188. );
  5189. Status = NtCreateFile( &TargetHandle,
  5190. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  5191. &ObjectAttributes,
  5192. &IoStatusBlock,
  5193. NULL,
  5194. FILE_ATTRIBUTE_NORMAL,
  5195. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5196. FILE_OPEN,
  5197. FILE_SYNCHRONOUS_IO_NONALERT,
  5198. NULL,
  5199. 0
  5200. );
  5201. if (!NT_SUCCESS(Status)) {
  5202. KdPrintEx((DPFLTR_SMSS_ID,
  5203. DPFLTR_WARNING_LEVEL,
  5204. "SMSS: Unable to open a handle to the (%ws) directory - Status == %lx\n",
  5205. UnicodeString.Buffer,
  5206. Status));
  5207. Status = STATUS_SUCCESS;
  5208. NtClose(SourceHandle);
  5209. goto CleanUp;
  5210. }
  5211. //
  5212. // If any of the copies fail, there is nothing we can really do.
  5213. //
  5214. RtlInitUnicodeString(&UnicodeString, L"ntldr");
  5215. Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
  5216. RtlInitUnicodeString(&UnicodeString, L"boot.ini");
  5217. Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
  5218. RtlInitUnicodeString(&UnicodeString, L"bootfont.bin");
  5219. Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
  5220. RtlInitUnicodeString(&UnicodeString, L"ntdetect.com");
  5221. Status = SmpCopyFile(SourceHandle, TargetHandle, &UnicodeString);
  5222. NtClose(SourceHandle);
  5223. NtClose(TargetHandle);
  5224. //
  5225. // Read Master Boot Record and get disk serial number.
  5226. //
  5227. swprintf((PWSTR)TmpBuffer,
  5228. L"\\Device\\Harddisk%d\\Partition0",
  5229. Disk
  5230. );
  5231. MbrName.Buffer = (PWSTR)TmpBuffer;
  5232. MbrName.MaximumLength = (wcslen((PWSTR)TmpBuffer) + 1) * sizeof(WCHAR);
  5233. MbrName.Length = MbrName.MaximumLength - sizeof(WCHAR);
  5234. InitializeObjectAttributes(
  5235. &ObjectAttributes,
  5236. &MbrName,
  5237. OBJ_CASE_INSENSITIVE,
  5238. NULL,
  5239. NULL
  5240. );
  5241. Status = NtCreateFile( &FileHandle,
  5242. GENERIC_READ | SYNCHRONIZE,
  5243. &ObjectAttributes,
  5244. &IoStatusBlock,
  5245. NULL,
  5246. FILE_ATTRIBUTE_NORMAL,
  5247. FILE_SHARE_READ,
  5248. FILE_OPEN,
  5249. FILE_SYNCHRONOUS_IO_NONALERT,
  5250. NULL,
  5251. 0
  5252. );
  5253. if (!NT_SUCCESS(Status)) {
  5254. //
  5255. // Something iswrong, but we are running w/o caching, so it should be ok.
  5256. //
  5257. KdPrintEx((DPFLTR_SMSS_ID,
  5258. DPFLTR_WARNING_LEVEL,
  5259. "SMSS: Could not create file (Status 0x%x).\n",
  5260. Status));
  5261. Status = STATUS_SUCCESS;
  5262. goto CleanUp;
  5263. }
  5264. ASSERT(sizeof(ON_DISK_MBR) == 512);
  5265. AlignedBuffer = ALIGN(TmpBuffer, 512);
  5266. Status = NtReadFile( FileHandle,
  5267. NULL,
  5268. NULL,
  5269. NULL,
  5270. &IoStatusBlock,
  5271. AlignedBuffer,
  5272. sizeof(ON_DISK_MBR),
  5273. NULL,
  5274. NULL
  5275. );
  5276. NtClose( FileHandle );
  5277. if (!NT_SUCCESS(Status)) {
  5278. KdPrintEx((DPFLTR_SMSS_ID,
  5279. DPFLTR_WARNING_LEVEL,
  5280. "SMSS: Could not read file (Status 0x%x) -- creating it.\n",
  5281. Status));
  5282. goto CreateFile;
  5283. }
  5284. RtlCopyMemory(&OnDiskMbr,AlignedBuffer,sizeof(ON_DISK_MBR));
  5285. ASSERT(U_USHORT(OnDiskMbr.AA55Signature) == 0xAA55);
  5286. DiskSignature = U_ULONG(OnDiskMbr.NTFTSignature);
  5287. InitializeObjectAttributes(
  5288. &ObjectAttributes,
  5289. &CfgFileName,
  5290. OBJ_CASE_INSENSITIVE,
  5291. NULL,
  5292. NULL
  5293. );
  5294. Status = NtOpenFile( &FileHandle,
  5295. GENERIC_WRITE | GENERIC_READ | SYNCHRONIZE,
  5296. &ObjectAttributes,
  5297. &IoStatusBlock,
  5298. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5299. FILE_SYNCHRONOUS_IO_NONALERT | FILE_RANDOM_ACCESS
  5300. );
  5301. if (!NT_SUCCESS(Status)) {
  5302. //
  5303. // Big Trouble....
  5304. // CSC is disabled if we get here, so just keep on booting.
  5305. //
  5306. Status = STATUS_SUCCESS;
  5307. goto CleanUp;
  5308. }
  5309. }
  5310. //
  5311. // Update the information
  5312. //
  5313. ByteOffset.LowPart = 0;
  5314. ByteOffset.HighPart = 0;
  5315. NtWriteFile( FileHandle,
  5316. NULL,
  5317. NULL,
  5318. NULL,
  5319. &IoStatusBlock,
  5320. &BootSerialNumber,
  5321. sizeof(ULONG),
  5322. &ByteOffset,
  5323. NULL
  5324. );
  5325. if (SmpAutoFormat) {
  5326. ByteOffset.LowPart = sizeof(ULONG);
  5327. NtWriteFile( FileHandle,
  5328. NULL,
  5329. NULL,
  5330. NULL,
  5331. &IoStatusBlock,
  5332. &DiskSignature,
  5333. sizeof(DiskSignature),
  5334. &ByteOffset,
  5335. NULL
  5336. );
  5337. }
  5338. ByteOffset.LowPart = sizeof(ULONG) + sizeof(ULONG);
  5339. NtWriteFile( FileHandle,
  5340. NULL,
  5341. NULL,
  5342. NULL,
  5343. &IoStatusBlock,
  5344. SmpHalName,
  5345. sizeof(SmpHalName),
  5346. &ByteOffset,
  5347. NULL
  5348. );
  5349. NtClose(FileHandle);
  5350. if (SmpAutoFormat) {
  5351. //
  5352. // Reboot the machine to start CSC
  5353. //
  5354. Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
  5355. (BOOLEAN)TRUE,
  5356. TRUE,
  5357. &WasEnabled
  5358. );
  5359. if (Status == STATUS_NO_TOKEN) {
  5360. //
  5361. // No thread token, use the process token
  5362. //
  5363. Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
  5364. (BOOLEAN)TRUE,
  5365. FALSE,
  5366. &WasEnabled
  5367. );
  5368. }
  5369. NtShutdownSystem(ShutdownReboot);
  5370. }
  5371. Status = STATUS_SUCCESS;
  5372. CleanUp:
  5373. return Status;
  5374. }
  5375. ENUMFILESRESULT
  5376. SmpEnumFilesRecursive (
  5377. IN PWSTR DirName,
  5378. IN ENUMFILESPROC EnumFilesProc,
  5379. OUT PULONG ReturnData,
  5380. IN PVOID p1 OPTIONAL
  5381. )
  5382. {
  5383. RECURSION_DATA RecursionData;
  5384. RecursionData.OptionalPtr = p1;
  5385. RecursionData.EnumProc = EnumFilesProc;
  5386. return SmpEnumFiles(
  5387. DirName,
  5388. SmppRecursiveEnumProc,
  5389. ReturnData,
  5390. &RecursionData
  5391. );
  5392. }
  5393. BOOLEAN
  5394. SmppRecursiveEnumProc (
  5395. IN PWSTR DirName,
  5396. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  5397. OUT PULONG ret,
  5398. IN PVOID Param
  5399. )
  5400. {
  5401. PWSTR FullPath;
  5402. PWSTR temp;
  5403. ULONG Len;
  5404. NTSTATUS Status;
  5405. ULONG ReturnData;
  5406. ENUMFILESRESULT EnumResult;
  5407. BOOLEAN b = FALSE;
  5408. PRECURSION_DATA RecursionData;
  5409. RecursionData = (PRECURSION_DATA) Param;
  5410. //
  5411. // Build the full file or dir path
  5412. //
  5413. temp = (PWSTR)(TmpBuffer + (sizeof(TmpBuffer)/2));
  5414. Len = FileInfo->FileNameLength/sizeof(WCHAR);
  5415. wcsncpy(temp, FileInfo->FileName, Len);
  5416. temp[Len] = 0;
  5417. wcscpy((PWSTR)TmpBuffer, DirName);
  5418. SmpConcatenatePaths((PWSTR)TmpBuffer, temp);
  5419. //
  5420. // For directories, recurse
  5421. //
  5422. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  5423. if( (wcscmp( temp, L"." ) == 0) ||
  5424. (wcscmp( temp, L".." ) == 0) ) {
  5425. //
  5426. // Skip past . and .. directories
  5427. //
  5428. b = TRUE;
  5429. } else {
  5430. //
  5431. // Recurse through subdirectory
  5432. //
  5433. FullPath = RtlAllocateHeap(RtlProcessHeap(),
  5434. MAKE_TAG( INIT_TAG ),
  5435. (wcslen((PWSTR)TmpBuffer)+1) * sizeof(WCHAR)
  5436. );
  5437. if (FullPath == NULL) {
  5438. *ret = EnumFileError;
  5439. return FALSE;
  5440. }
  5441. wcscpy(FullPath, (PWSTR)TmpBuffer);
  5442. EnumResult = SmpEnumFilesRecursive (
  5443. FullPath,
  5444. RecursionData->EnumProc,
  5445. &ReturnData,
  5446. RecursionData->OptionalPtr
  5447. );
  5448. RtlFreeHeap( RtlProcessHeap(), 0, FullPath );
  5449. if (EnumResult != NormalReturn) {
  5450. *ret = EnumResult;
  5451. return FALSE;
  5452. }
  5453. }
  5454. }
  5455. //
  5456. // Call normal enum proc for file or dir (except . or .. dirs)
  5457. //
  5458. if (!b) {
  5459. b = RecursionData->EnumProc (
  5460. DirName,
  5461. FileInfo,
  5462. ret,
  5463. RecursionData->OptionalPtr
  5464. );
  5465. }
  5466. return b;
  5467. }
  5468. VOID
  5469. SmpConcatenatePaths(
  5470. IN OUT LPWSTR Path1,
  5471. IN LPCWSTR Path2
  5472. )
  5473. {
  5474. BOOLEAN NeedBackslash = TRUE;
  5475. ULONG l = wcslen(Path1);
  5476. //
  5477. // Determine whether we need to stick a backslash
  5478. // between the components.
  5479. //
  5480. if(l && (Path1[l-1] == L'\\')) {
  5481. NeedBackslash = FALSE;
  5482. }
  5483. if(*Path2 == L'\\') {
  5484. if(NeedBackslash) {
  5485. NeedBackslash = FALSE;
  5486. } else {
  5487. //
  5488. // Not only do we not need a backslash, but we
  5489. // need to eliminate one before concatenating.
  5490. //
  5491. Path2++;
  5492. }
  5493. }
  5494. if(NeedBackslash) {
  5495. wcscat(Path1,L"\\");
  5496. }
  5497. wcscat(Path1,Path2);
  5498. }
  5499. BOOLEAN
  5500. SmpDelEnumFile(
  5501. IN PWSTR DirName,
  5502. IN PFILE_BOTH_DIR_INFORMATION FileInfo,
  5503. OUT PULONG ret,
  5504. IN PVOID Pointer
  5505. )
  5506. {
  5507. PWSTR FileName;
  5508. PWSTR p;
  5509. UNICODE_STRING UnicodeString;
  5510. //
  5511. // Ignore subdirectories
  5512. //
  5513. if(FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  5514. return TRUE; // continue processing
  5515. }
  5516. //
  5517. // We have to make a copy of the filename, because the info struct
  5518. // we get isn't NULL-terminated.
  5519. //
  5520. FileName = RtlAllocateHeap(RtlProcessHeap(),
  5521. MAKE_TAG( INIT_TAG ),
  5522. FileInfo->FileNameLength + sizeof(WCHAR)
  5523. );
  5524. if (FileName == NULL) {
  5525. *ret = EnumFileError;
  5526. return TRUE;
  5527. }
  5528. wcsncpy(FileName, FileInfo->FileName, FileInfo->FileNameLength);
  5529. FileName[FileInfo->FileNameLength / sizeof(WCHAR)] = UNICODE_NULL;
  5530. //
  5531. // Point to temporary buffer for pathname.
  5532. //
  5533. p = (PWSTR)TmpBuffer;
  5534. //
  5535. // Build up the full name of the file to delete.
  5536. //
  5537. wcscpy(p,DirName);
  5538. SmpConcatenatePaths(p,FileName);
  5539. //
  5540. // Prepare to open the file.
  5541. //
  5542. RtlInitUnicodeString(&UnicodeString, p);
  5543. //
  5544. // Ignore return status of delete
  5545. //
  5546. SmpDeleteFile(&UnicodeString);
  5547. RtlFreeHeap( RtlProcessHeap(), 0, FileName );
  5548. return TRUE; // continue processing
  5549. }
  5550. ENUMFILESRESULT
  5551. SmpEnumFiles(
  5552. IN PWSTR DirName,
  5553. IN ENUMFILESPROC EnumFilesProc,
  5554. OUT PULONG ReturnData,
  5555. IN PVOID p1 OPTIONAL
  5556. )
  5557. /*++
  5558. Routine Description:
  5559. This routine processes every file (and subdirectory) in the directory
  5560. specified by 'DirName'. Each entry is sent to the callback function
  5561. 'EnumFilesProc' for processing. If the callback returns TRUE, processing
  5562. continues, otherwise processing terminates.
  5563. Arguments:
  5564. DirName - Supplies the directory name containing the files/subdirectories
  5565. to be processed.
  5566. EnumFilesProc - Callback function to be called for each file/subdirectory.
  5567. The function must have the following prototype:
  5568. BOOLEAN EnumFilesProc(
  5569. IN PWSTR,
  5570. IN PFILE_BOTH_DIR_INFORMATION,
  5571. OUT PULONG
  5572. );
  5573. ReturnData - Pointer to the returned data. The contents stored here
  5574. depend on the reason for termination (See below).
  5575. p1 - Optional pointer, to be passed to the callback function.
  5576. Return Value:
  5577. This function can return one of three values. The data stored in
  5578. 'ReturnData' depends upon which value is returned:
  5579. NormalReturn - if the whole process completes uninterrupted
  5580. (ReturnData is not used)
  5581. EnumFileError - if an error occurs while enumerating files
  5582. (ReturnData contains the error code)
  5583. CallbackReturn - if the callback returns FALSE, causing termination
  5584. (ReturnData contains data defined by the callback)
  5585. --*/
  5586. {
  5587. HANDLE hFindFile;
  5588. NTSTATUS Status;
  5589. UNICODE_STRING PathName;
  5590. OBJECT_ATTRIBUTES Obja;
  5591. IO_STATUS_BLOCK IoStatusBlock;
  5592. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  5593. BOOLEAN bStartScan;
  5594. ENUMFILESRESULT ret;
  5595. //
  5596. // Prepare to open the directory
  5597. //
  5598. RtlInitUnicodeString(&PathName, DirName);
  5599. InitializeObjectAttributes(
  5600. &Obja,
  5601. &PathName,
  5602. OBJ_CASE_INSENSITIVE,
  5603. NULL,
  5604. NULL
  5605. );
  5606. //
  5607. // Open the specified directory for list access
  5608. //
  5609. Status = NtOpenFile(
  5610. &hFindFile,
  5611. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  5612. &Obja,
  5613. &IoStatusBlock,
  5614. FILE_SHARE_READ | FILE_SHARE_WRITE,
  5615. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  5616. );
  5617. if(!NT_SUCCESS(Status)) {
  5618. KdPrintEx((DPFLTR_SMSS_ID,
  5619. DPFLTR_WARNING_LEVEL,
  5620. "SMSS: Unable to open directory %ws for list (%lx)\n",
  5621. DirName,
  5622. Status));
  5623. *ReturnData = Status;
  5624. return EnumFileError;
  5625. }
  5626. DirectoryInfo = RtlAllocateHeap(RtlProcessHeap(),
  5627. MAKE_TAG( INIT_TAG ),
  5628. DOS_MAX_PATH_LENGTH * 2 + sizeof(FILE_BOTH_DIR_INFORMATION)
  5629. );
  5630. if(!DirectoryInfo) {
  5631. KdPrintEx((DPFLTR_SMSS_ID,
  5632. DPFLTR_WARNING_LEVEL,
  5633. "SMSS: Unable to allocate memory for SpEnumFiles()\n"));
  5634. *ReturnData = STATUS_INSUFFICIENT_RESOURCES;
  5635. return EnumFileError;
  5636. }
  5637. bStartScan = TRUE;
  5638. while(TRUE) {
  5639. Status = NtQueryDirectoryFile(
  5640. hFindFile,
  5641. NULL,
  5642. NULL,
  5643. NULL,
  5644. &IoStatusBlock,
  5645. DirectoryInfo,
  5646. (DOS_MAX_PATH_LENGTH * 2 + sizeof(FILE_BOTH_DIR_INFORMATION)),
  5647. FileBothDirectoryInformation,
  5648. TRUE,
  5649. NULL,
  5650. bStartScan
  5651. );
  5652. if(Status == STATUS_NO_MORE_FILES) {
  5653. ret = NormalReturn;
  5654. break;
  5655. } else if(!NT_SUCCESS(Status)) {
  5656. KdPrintEx((DPFLTR_SMSS_ID,
  5657. DPFLTR_WARNING_LEVEL,
  5658. "SMSS: Unable to query directory %ws (%lx)\n",
  5659. DirName,
  5660. Status));
  5661. *ReturnData = Status;
  5662. ret = EnumFileError;
  5663. break;
  5664. }
  5665. if(bStartScan) {
  5666. bStartScan = FALSE;
  5667. }
  5668. //
  5669. // Now pass this entry off to our callback function for processing
  5670. //
  5671. if(!EnumFilesProc(DirName, DirectoryInfo, ReturnData, p1)) {
  5672. ret = CallbackReturn;
  5673. break;
  5674. }
  5675. }
  5676. RtlFreeHeap( RtlProcessHeap(), 0, DirectoryInfo );
  5677. NtClose(hFindFile);
  5678. return ret;
  5679. }
  5680. #endif // defined(REMOTE_BOOT)
  5681. NTSTATUS
  5682. SmpDeleteFile(
  5683. IN PUNICODE_STRING pFile
  5684. )
  5685. {
  5686. NTSTATUS Status;
  5687. IO_STATUS_BLOCK IoStatusBlock;
  5688. OBJECT_ATTRIBUTES Obja;
  5689. HANDLE Handle;
  5690. FILE_DISPOSITION_INFORMATION Disposition;
  5691. FILE_BASIC_INFORMATION BasicInfo;
  5692. InitializeObjectAttributes(
  5693. &Obja,
  5694. pFile,
  5695. OBJ_CASE_INSENSITIVE,
  5696. NULL,
  5697. NULL
  5698. );
  5699. //
  5700. // Attempt to open the file.
  5701. //
  5702. Status = NtOpenFile(
  5703. &Handle,
  5704. (ACCESS_MASK)(DELETE | FILE_WRITE_ATTRIBUTES),
  5705. &Obja,
  5706. &IoStatusBlock,
  5707. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE ,
  5708. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  5709. );
  5710. if(!NT_SUCCESS(Status)) {
  5711. KdPrintEx((DPFLTR_SMSS_ID,
  5712. DPFLTR_WARNING_LEVEL,
  5713. "SMSS: Unable to open %ws for delete (%lx)\n",
  5714. pFile->Buffer,
  5715. Status));
  5716. return(Status);
  5717. }
  5718. //
  5719. // Change the file attribute to normal
  5720. //
  5721. RtlZeroMemory( &BasicInfo, sizeof( FILE_BASIC_INFORMATION ) );
  5722. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  5723. Status = NtSetInformationFile(Handle,
  5724. &IoStatusBlock,
  5725. &BasicInfo,
  5726. sizeof(BasicInfo),
  5727. FileBasicInformation
  5728. );
  5729. if(!NT_SUCCESS(Status)) {
  5730. KdPrintEx((DPFLTR_SMSS_ID,
  5731. DPFLTR_WARNING_LEVEL,
  5732. "SMSS: Unable to change attribute of %ls. Status = (%lx)\n",
  5733. pFile->Buffer,
  5734. Status));
  5735. return(Status);
  5736. }
  5737. //
  5738. // Set up for delete and call worker to do it.
  5739. //
  5740. #undef DeleteFile
  5741. Disposition.DeleteFile = TRUE;
  5742. Status = NtSetInformationFile(Handle,
  5743. &IoStatusBlock,
  5744. &Disposition,
  5745. sizeof(Disposition),
  5746. FileDispositionInformation
  5747. );
  5748. //
  5749. // Clean up and return.
  5750. //
  5751. NtClose(Handle);
  5752. return(Status);
  5753. }
  5754. NTSTATUS
  5755. SmpCallCsrCreateProcess(
  5756. IN OUT PSBAPIMSG m,
  5757. IN size_t ArgLength,
  5758. IN HANDLE CommunicationPort
  5759. )
  5760. /*++
  5761. Routine Description:
  5762. This function sends a message to CSR telling to start a process
  5763. Arguments:
  5764. m - message to send
  5765. ArgLength - length of argument struct inside message
  5766. CommunicationPort - LPC port to send to
  5767. Return Value:
  5768. NTSTATUS
  5769. --*/
  5770. {
  5771. NTSTATUS Status;
  5772. m->h.u1.s1.DataLength = ArgLength + 8;
  5773. m->h.u1.s1.TotalLength = sizeof(SBAPIMSG);
  5774. m->h.u2.ZeroInit = 0L;
  5775. m->ApiNumber = SbCreateProcessApi;
  5776. Status = NtRequestWaitReplyPort(CommunicationPort,
  5777. (PPORT_MESSAGE) m,
  5778. (PPORT_MESSAGE) m
  5779. );
  5780. if (NT_SUCCESS( Status )) {
  5781. Status = m->ReturnedStatus;
  5782. }
  5783. return Status;
  5784. }