Source code of Windows XP (NT5)
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.

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