Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1748 lines
54 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. srvinit.c
  5. Abstract:
  6. This is the main initialization module for the Server side of the Client
  7. Server Runtime Subsystem (CSRSS)
  8. Author:
  9. Steve Wood (stevewo) 08-Oct-1990
  10. Environment:
  11. User Mode Only
  12. Revision History:
  13. --*/
  14. #include "csrsrv.h"
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <wow64reg.h>
  18. CONST PCSR_API_ROUTINE CsrServerApiDispatchTable[CsrpMaxApiNumber] = {
  19. (PCSR_API_ROUTINE)CsrSrvClientConnect,
  20. (PCSR_API_ROUTINE)CsrSrvUnusedFunction,
  21. (PCSR_API_ROUTINE)CsrSrvUnusedFunction,
  22. (PCSR_API_ROUTINE)CsrSrvUnusedFunction,
  23. (PCSR_API_ROUTINE)CsrSrvUnusedFunction
  24. };
  25. BOOLEAN CsrServerApiServerValidTable[CsrpMaxApiNumber] = {
  26. TRUE, // CsrSrvClientConnect,
  27. FALSE, // CsrSrvUnusedFunction,
  28. FALSE, // CsrSrvUnusedFunction,
  29. FALSE, // CsrSrvUnusedFunction,
  30. FALSE // CsrSrvUnusedFunction,
  31. };
  32. #if DBG
  33. CONST PSZ CsrServerApiNameTable[CsrpMaxApiNumber] = {
  34. "ClientConnect",
  35. "CsrSrvUnusedFunction",
  36. "CsrSrvUnusedFunction",
  37. "CsrSrvUnusedFunction",
  38. "CsrSrvUnusedFunction",
  39. };
  40. #endif
  41. NTSTATUS
  42. CsrSetProcessSecurity(
  43. VOID
  44. );
  45. NTSTATUS
  46. CsrSetDirectorySecurity(
  47. IN HANDLE DirectoryHandle
  48. );
  49. NTSTATUS
  50. GetDosDevicesProtection (
  51. PSECURITY_DESCRIPTOR SecurityDescriptor
  52. );
  53. VOID
  54. FreeDosDevicesProtection (
  55. PSECURITY_DESCRIPTOR SecurityDescriptor
  56. );
  57. NTSTATUS
  58. CsrPopulateDosDevicesDirectory(
  59. HANDLE NewDirectoryHandle,
  60. PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo
  61. );
  62. // Though this function does not seem to cleanup on failure, failure
  63. // will cause CSRSS to exit, so any allocated memory will be freed and
  64. // any open handle will be closed.
  65. NTSTATUS
  66. CsrServerInitialization(
  67. IN ULONG argc,
  68. IN PCH argv[]
  69. )
  70. {
  71. NTSTATUS Status;
  72. ULONG i;
  73. PVOID ProcessDataPtr;
  74. PCSR_SERVER_DLL LoadedServerDll;
  75. #if DBG
  76. BOOLEAN bIsRemoteSession = NtCurrentPeb()->SessionId != 0;
  77. #endif
  78. //
  79. // Initialize Wow64 stuffs
  80. //
  81. #ifdef _WIN64
  82. InitializeWow64OnBoot(1);
  83. #endif
  84. //
  85. // Save away system information in a global variable
  86. //
  87. Status = NtQuerySystemInformation( SystemBasicInformation,
  88. &CsrNtSysInfo,
  89. sizeof( CsrNtSysInfo ),
  90. NULL
  91. );
  92. ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession );
  93. if (!NT_SUCCESS( Status )) {
  94. return Status;
  95. }
  96. //
  97. // Use the process heap for memory allocation.
  98. //
  99. CsrHeap = RtlProcessHeap();
  100. CsrBaseTag = RtlCreateTagHeap( CsrHeap,
  101. 0,
  102. L"CSRSS!",
  103. L"TMP\0"
  104. L"INIT\0"
  105. L"CAPTURE\0"
  106. L"PROCESS\0"
  107. L"THREAD\0"
  108. L"SECURITY\0"
  109. L"SESSION\0"
  110. L"WAIT\0"
  111. );
  112. //
  113. // Set up CSRSS process security
  114. //
  115. Status = CsrSetProcessSecurity();
  116. ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
  117. if (!NT_SUCCESS(Status)) {
  118. return Status;
  119. }
  120. //
  121. // Initialize the Session List
  122. //
  123. Status = CsrInitializeNtSessionList();
  124. ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
  125. if (!NT_SUCCESS(Status)) {
  126. return Status;
  127. }
  128. //
  129. // Initialize the Process List
  130. //
  131. Status = CsrInitializeProcessStructure();
  132. ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
  133. if (!NT_SUCCESS(Status)) {
  134. return Status;
  135. }
  136. //
  137. // Process the command line arguments
  138. //
  139. Status = CsrParseServerCommandLine(argc, argv);
  140. ASSERT(NT_SUCCESS(Status) || bIsRemoteSession);
  141. if (!NT_SUCCESS(Status)) {
  142. return Status;
  143. }
  144. #if DBG
  145. Status = RtlInitializeCriticalSection(&CsrTrackLpcLock);
  146. if (!NT_SUCCESS(Status)) {
  147. return Status;
  148. }
  149. LpcTrackIndex = 0;
  150. #endif
  151. //
  152. // Fix up per-process data for root process
  153. //
  154. ProcessDataPtr = (PCSR_PROCESS)RtlAllocateHeap( CsrHeap,
  155. MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY,
  156. CsrTotalPerProcessDataLength
  157. );
  158. if (ProcessDataPtr == NULL) {
  159. return STATUS_NO_MEMORY;
  160. }
  161. for (i=0; i<CSR_MAX_SERVER_DLL; i++) {
  162. LoadedServerDll = CsrLoadedServerDll[ i ];
  163. if (LoadedServerDll && LoadedServerDll->PerProcessDataLength) {
  164. CsrRootProcess->ServerDllPerProcessData[i] = ProcessDataPtr;
  165. ProcessDataPtr = (PVOID)QUAD_ALIGN((PCHAR)ProcessDataPtr + LoadedServerDll->PerProcessDataLength);
  166. }
  167. else {
  168. CsrRootProcess->ServerDllPerProcessData[i] = NULL;
  169. }
  170. }
  171. //
  172. // Let server dlls know about the root process.
  173. //
  174. for (i=0; i<CSR_MAX_SERVER_DLL; i++) {
  175. LoadedServerDll = CsrLoadedServerDll[ i ];
  176. if (LoadedServerDll && LoadedServerDll->AddProcessRoutine) {
  177. (*LoadedServerDll->AddProcessRoutine)( NULL, CsrRootProcess );
  178. }
  179. }
  180. //
  181. // Initialize the Windows Server API Port, and one or more
  182. // request threads.
  183. //
  184. Status = CsrApiPortInitialize();
  185. ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession );
  186. if (!NT_SUCCESS( Status )) {
  187. return Status;
  188. }
  189. //
  190. // Initialize the Server Session Manager API Port and one
  191. // request thread.
  192. //
  193. Status = CsrSbApiPortInitialize();
  194. ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession);
  195. if (!NT_SUCCESS( Status )) {
  196. return Status;
  197. }
  198. //
  199. // Connect to the session manager so we can start foreign sessions
  200. //
  201. Status = SmConnectToSm( &CsrSbApiPortName,
  202. CsrSbApiPort,
  203. IMAGE_SUBSYSTEM_WINDOWS_GUI,
  204. &CsrSmApiPort
  205. );
  206. ASSERT( NT_SUCCESS( Status ) || bIsRemoteSession );
  207. if (!NT_SUCCESS( Status )) {
  208. return Status;
  209. }
  210. //
  211. // Only on Console (HYDRA)
  212. //
  213. if (NtCurrentPeb()->SessionId == 0) {
  214. Status = NtSetDefaultHardErrorPort(CsrApiPort);
  215. }
  216. return( Status );
  217. }
  218. NTSTATUS
  219. CsrParseServerCommandLine(
  220. IN ULONG argc,
  221. IN PCH argv[]
  222. )
  223. {
  224. NTSTATUS Status;
  225. OBJECT_ATTRIBUTES ObjectAttributes;
  226. ULONG i, ServerDllIndex;
  227. PCH KeyName, KeyValue, s;
  228. PCH InitRoutine;
  229. CsrTotalPerProcessDataLength = 0;
  230. CsrObjectDirectory = NULL;
  231. CsrMaxApiRequestThreads = CSR_MAX_THREADS;
  232. SessionId = NtCurrentPeb()->SessionId;
  233. //
  234. // Create session specific object directories
  235. //
  236. Status = CsrCreateSessionObjectDirectory ( SessionId );
  237. if (!NT_SUCCESS(Status)) {
  238. if (SessionId == 0) {
  239. ASSERT( NT_SUCCESS( Status ) );
  240. DbgPrint("CSRSS: CsrCreateSessionObjectDirectory failed status = %lx\n", Status);
  241. } else {
  242. DbgPrint("CSRSS: CsrCreateSessionObjectDirectory failed status = %lx\n", Status);
  243. return Status;
  244. }
  245. }
  246. for (i=1; i<argc ; i++) {
  247. KeyName = argv[ i ];
  248. KeyValue = NULL;
  249. while (*KeyName) {
  250. if (*KeyName == '=') {
  251. *KeyName++ = '\0';
  252. KeyValue = KeyName;
  253. break;
  254. }
  255. KeyName++;
  256. }
  257. KeyName = argv[ i ];
  258. if (!_stricmp( KeyName, "ObjectDirectory" )) {
  259. ANSI_STRING AnsiString;
  260. ULONG attributes;
  261. CHAR SessionDirectory[MAX_SESSION_PATH];
  262. if (SessionId != 0) {
  263. //
  264. // Non-Console session
  265. //
  266. _snprintf(SessionDirectory, sizeof (SessionDirectory), "%ws\\%ld%s", SESSION_ROOT, SessionId, KeyValue);
  267. SessionDirectory[MAX_SESSION_PATH-1] = '\0';
  268. }
  269. //
  270. // Create an object directory in the object name space with the
  271. // name specified. It will be the root for all object names
  272. // created by the Server side of the Client Server Runtime
  273. // SubSystem.
  274. //
  275. attributes = OBJ_OPENIF | OBJ_CASE_INSENSITIVE;
  276. if (SessionId == 0) {
  277. attributes |= OBJ_PERMANENT;
  278. RtlInitString( &AnsiString, KeyValue );
  279. } else {
  280. RtlInitString( &AnsiString, SessionDirectory );
  281. }
  282. Status = RtlAnsiStringToUnicodeString( &CsrDirectoryName, &AnsiString, TRUE );
  283. ASSERT(NT_SUCCESS(Status) || SessionId != 0);
  284. if (!NT_SUCCESS( Status )) {
  285. break;
  286. }
  287. InitializeObjectAttributes( &ObjectAttributes,
  288. &CsrDirectoryName,
  289. attributes,
  290. NULL,
  291. NULL
  292. );
  293. Status = NtCreateDirectoryObject( &CsrObjectDirectory,
  294. DIRECTORY_ALL_ACCESS,
  295. &ObjectAttributes
  296. );
  297. if (!NT_SUCCESS( Status )) {
  298. break;
  299. }
  300. Status = CsrSetDirectorySecurity( CsrObjectDirectory );
  301. if (!NT_SUCCESS( Status )) {
  302. break;
  303. }
  304. }
  305. else
  306. if (!_stricmp( KeyName, "SubSystemType" )) {
  307. }
  308. else
  309. if (!_stricmp( KeyName, "MaxRequestThreads" )) {
  310. Status = RtlCharToInteger( KeyValue,
  311. 0,
  312. &CsrMaxApiRequestThreads
  313. );
  314. }
  315. else
  316. if (!_stricmp( KeyName, "RequestThreads" )) {
  317. #if 0
  318. Status = RtlCharToInteger( KeyValue,
  319. 0,
  320. &CsrNumberApiRequestThreads
  321. );
  322. #else
  323. //
  324. // wait until hive change !
  325. //
  326. Status = STATUS_SUCCESS;
  327. #endif
  328. }
  329. else
  330. if (!_stricmp( KeyName, "ProfileControl" )) {
  331. }
  332. else
  333. if (!_stricmp( KeyName, "SharedSection" )) {
  334. Status = CsrSrvCreateSharedSection( KeyValue );
  335. if (!NT_SUCCESS( Status )) {
  336. IF_DEBUG {
  337. DbgPrint( "CSRSS: *** Invalid syntax for %s=%s (Status == %X)\n",
  338. KeyName,
  339. KeyValue,
  340. Status
  341. );
  342. }
  343. return Status;
  344. }
  345. Status = CsrLoadServerDll( "CSRSS", NULL, CSRSRV_SERVERDLL_INDEX );
  346. }
  347. else
  348. if (!_stricmp( KeyName, "ServerDLL" )) {
  349. s = KeyValue;
  350. InitRoutine = NULL;
  351. Status = STATUS_INVALID_PARAMETER;
  352. while (*s) {
  353. if ((*s == ':') && (InitRoutine == NULL)) {
  354. *s++ = '\0';
  355. InitRoutine = s;
  356. }
  357. if (*s++ == ',') {
  358. Status = RtlCharToInteger ( s, 10, &ServerDllIndex );
  359. if (NT_SUCCESS( Status )) {
  360. s[ -1 ] = '\0';
  361. }
  362. break;
  363. }
  364. }
  365. if (!NT_SUCCESS( Status )) {
  366. IF_DEBUG {
  367. DbgPrint( "CSRSS: *** Invalid syntax for ServerDll=%s (Status == %X)\n",
  368. KeyValue,
  369. Status
  370. );
  371. }
  372. }
  373. else {
  374. IF_CSR_DEBUG( INIT) {
  375. DbgPrint( "CSRSS: Loading ServerDll=%s:%s\n", KeyValue, InitRoutine );
  376. }
  377. Status = CsrLoadServerDll( KeyValue, InitRoutine, ServerDllIndex);
  378. if (!NT_SUCCESS( Status )) {
  379. IF_DEBUG {
  380. DbgPrint( "CSRSS: *** Failed loading ServerDll=%s (Status == 0x%x)\n",
  381. KeyValue,
  382. Status
  383. );
  384. }
  385. return Status;
  386. }
  387. }
  388. }
  389. else
  390. //
  391. // This is a temporary hack until Windows & Console are friends.
  392. //
  393. if (!_stricmp( KeyName, "Windows" )) {
  394. }
  395. else {
  396. Status = STATUS_INVALID_PARAMETER;
  397. }
  398. }
  399. return( Status );
  400. }
  401. NTSTATUS
  402. CsrServerDllInitialization(
  403. IN PCSR_SERVER_DLL LoadedServerDll
  404. )
  405. {
  406. LoadedServerDll->ApiNumberBase = CSRSRV_FIRST_API_NUMBER;
  407. LoadedServerDll->MaxApiNumber = CsrpMaxApiNumber;
  408. LoadedServerDll->ApiDispatchTable = CsrServerApiDispatchTable;
  409. LoadedServerDll->ApiServerValidTable = CsrServerApiServerValidTable;
  410. #if DBG
  411. LoadedServerDll->ApiNameTable = CsrServerApiNameTable;
  412. #endif
  413. LoadedServerDll->PerProcessDataLength = 0;
  414. LoadedServerDll->ConnectRoutine = NULL;
  415. LoadedServerDll->DisconnectRoutine = NULL;
  416. return( STATUS_SUCCESS );
  417. }
  418. NTSTATUS
  419. CsrSrvUnusedFunction(
  420. IN OUT PCSR_API_MSG m,
  421. IN OUT PCSR_REPLY_STATUS ReplyStatus
  422. )
  423. {
  424. IF_DEBUG {
  425. DbgPrint("CSRSS: Calling obsolete function %x\n", m->ApiNumber);
  426. }
  427. return STATUS_INVALID_PARAMETER;
  428. }
  429. NTSTATUS
  430. CsrSetProcessSecurity(
  431. VOID
  432. )
  433. {
  434. HANDLE Token;
  435. NTSTATUS Status;
  436. PTOKEN_USER User = NULL;
  437. ULONG LengthSid, Length;
  438. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  439. PACL Dacl;
  440. //
  441. // Open the token and get the system sid
  442. //
  443. Status = NtOpenProcessToken( NtCurrentProcess(),
  444. TOKEN_QUERY,
  445. &Token);
  446. if (!NT_SUCCESS(Status)) {
  447. return Status;
  448. }
  449. Status = NtQueryInformationToken (Token,
  450. TokenUser,
  451. NULL,
  452. 0,
  453. &Length);
  454. User = (PTOKEN_USER)RtlAllocateHeap (CsrHeap,
  455. MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY,
  456. Length);
  457. if (User == NULL) {
  458. NtClose( Token );
  459. Status = STATUS_NO_MEMORY;
  460. goto error_cleanup;
  461. }
  462. Status = NtQueryInformationToken( Token,
  463. TokenUser,
  464. User,
  465. Length,
  466. &Length
  467. );
  468. NtClose( Token );
  469. if (!NT_SUCCESS(Status)) {
  470. goto error_cleanup;
  471. }
  472. LengthSid = RtlLengthSid( User->User.Sid );
  473. //
  474. // Allocate a buffer to hold the SD
  475. //
  476. SecurityDescriptor = RtlAllocateHeap (CsrHeap,
  477. MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY,
  478. SECURITY_DESCRIPTOR_MIN_LENGTH +
  479. sizeof(ACL) + LengthSid +
  480. sizeof(ACCESS_ALLOWED_ACE));
  481. if (SecurityDescriptor == NULL) {
  482. Status = STATUS_NO_MEMORY;
  483. goto error_cleanup;
  484. }
  485. Dacl = (PACL)((PCHAR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
  486. //
  487. // Create the SD
  488. //
  489. Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
  490. SECURITY_DESCRIPTOR_REVISION);
  491. if (!NT_SUCCESS(Status)) {
  492. IF_DEBUG {
  493. DbgPrint("CSRSS: SD creation failed - status = %lx\n", Status);
  494. }
  495. goto error_cleanup;
  496. }
  497. Status = RtlCreateAcl( Dacl,
  498. sizeof(ACL) + LengthSid + sizeof(ACCESS_ALLOWED_ACE),
  499. ACL_REVISION2);
  500. if (!NT_SUCCESS(Status)) {
  501. IF_DEBUG {
  502. DbgPrint("CSRSS: DACL creation failed - status = %lx\n", Status);
  503. }
  504. goto error_cleanup;
  505. }
  506. Status = RtlAddAccessAllowedAce( Dacl,
  507. ACL_REVISION,
  508. ( PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION |
  509. PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_SET_PORT |
  510. READ_CONTROL | PROCESS_QUERY_INFORMATION ),
  511. User->User.Sid);
  512. if (!NT_SUCCESS(Status)) {
  513. IF_DEBUG {
  514. DbgPrint("CSRSS: ACE creation failed - status = %lx\n", Status);
  515. }
  516. goto error_cleanup;
  517. }
  518. //
  519. // Set DACL to NULL to deny all access
  520. //
  521. Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
  522. TRUE,
  523. Dacl,
  524. FALSE);
  525. if (!NT_SUCCESS(Status)) {
  526. IF_DEBUG {
  527. DbgPrint("CSRSS: set DACL failed - status = %lx\n", Status);
  528. }
  529. goto error_cleanup;
  530. }
  531. //
  532. // Put the DACL onto the process
  533. //
  534. Status = NtSetSecurityObject(NtCurrentProcess(),
  535. DACL_SECURITY_INFORMATION,
  536. SecurityDescriptor);
  537. if (!NT_SUCCESS(Status)) {
  538. IF_DEBUG {
  539. DbgPrint("CSRSS: set process DACL failed - status = %lx\n", Status);
  540. }
  541. }
  542. //
  543. // Cleanup
  544. //
  545. error_cleanup:
  546. if (SecurityDescriptor != NULL) {
  547. RtlFreeHeap( CsrHeap, 0, SecurityDescriptor );
  548. }
  549. if (User != NULL) {
  550. RtlFreeHeap( CsrHeap, 0, User );
  551. }
  552. return Status;
  553. }
  554. NTSTATUS
  555. CsrSetDirectorySecurity(
  556. IN HANDLE DirectoryHandle
  557. )
  558. {
  559. PSID WorldSid = NULL;
  560. PSID SystemSid = NULL;
  561. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  562. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  563. NTSTATUS Status;
  564. ULONG AclLength;
  565. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  566. PACL Dacl;
  567. //
  568. // Get the SIDs for world and system
  569. //
  570. Status = RtlAllocateAndInitializeSid( &WorldAuthority,
  571. 1,
  572. SECURITY_WORLD_RID,
  573. 0, 0, 0, 0, 0, 0, 0,
  574. &WorldSid
  575. );
  576. if (!NT_SUCCESS(Status)) {
  577. WorldSid = NULL;
  578. goto error_cleanup;
  579. }
  580. Status = RtlAllocateAndInitializeSid( &NtAuthority,
  581. 1,
  582. SECURITY_LOCAL_SYSTEM_RID,
  583. 0, 0, 0, 0, 0, 0, 0,
  584. &SystemSid
  585. );
  586. if (!NT_SUCCESS(Status)) {
  587. SystemSid = NULL;
  588. goto error_cleanup;
  589. }
  590. //
  591. // Allocate a buffer to hold the SD
  592. //
  593. AclLength = sizeof(ACL) +
  594. RtlLengthSid( WorldSid ) +
  595. RtlLengthSid( SystemSid ) +
  596. 2 * sizeof(ACCESS_ALLOWED_ACE);
  597. SecurityDescriptor = RtlAllocateHeap( CsrHeap,
  598. MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY,
  599. SECURITY_DESCRIPTOR_MIN_LENGTH +
  600. AclLength
  601. );
  602. if (SecurityDescriptor == NULL) {
  603. Status = STATUS_NO_MEMORY;
  604. goto error_cleanup;
  605. }
  606. //
  607. // Create the SD
  608. //
  609. Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
  610. SECURITY_DESCRIPTOR_REVISION);
  611. if (!NT_SUCCESS(Status)) {
  612. IF_DEBUG {
  613. DbgPrint("CSRSS: SD creation failed - status = %lx\n", Status);
  614. }
  615. goto error_cleanup;
  616. }
  617. //
  618. // Create the DACL
  619. //
  620. Dacl = (PACL)((PCHAR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
  621. RtlCreateAcl( Dacl,
  622. AclLength,
  623. ACL_REVISION
  624. );
  625. Status = RtlAddAccessAllowedAce( Dacl,
  626. ACL_REVISION,
  627. STANDARD_RIGHTS_READ | DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
  628. WorldSid
  629. );
  630. if (!NT_SUCCESS(Status)) {
  631. IF_DEBUG {
  632. DbgPrint("CSRSS: ACE creation failed - status = %lx\n", Status);
  633. }
  634. goto error_cleanup;
  635. }
  636. Status = RtlAddAccessAllowedAce( Dacl,
  637. ACL_REVISION,
  638. DIRECTORY_ALL_ACCESS,
  639. SystemSid
  640. );
  641. if (!NT_SUCCESS(Status)) {
  642. IF_DEBUG {
  643. DbgPrint("CSRSS: ACE creation failed - status = %lx\n", Status);
  644. }
  645. goto error_cleanup;
  646. }
  647. //
  648. // Set DACL into the SD
  649. //
  650. Status = RtlSetDaclSecurityDescriptor(SecurityDescriptor,
  651. TRUE,
  652. Dacl,
  653. FALSE);
  654. if (!NT_SUCCESS(Status)) {
  655. IF_DEBUG {
  656. DbgPrint("CSRSS: set DACL failed - status = %lx\n", Status);
  657. }
  658. goto error_cleanup;
  659. }
  660. //
  661. // Put the DACL onto the direcory
  662. //
  663. Status = NtSetSecurityObject(DirectoryHandle,
  664. DACL_SECURITY_INFORMATION,
  665. SecurityDescriptor);
  666. if (!NT_SUCCESS(Status)) {
  667. IF_DEBUG {
  668. DbgPrint("CSRSS: set directory DACL failed - status = %lx\n", Status);
  669. }
  670. }
  671. //
  672. // Cleanup
  673. //
  674. error_cleanup:
  675. if (SecurityDescriptor != NULL) {
  676. RtlFreeHeap( CsrHeap, 0, SecurityDescriptor );
  677. }
  678. if (WorldSid != NULL) {
  679. RtlFreeSid( WorldSid );
  680. }
  681. if (SystemSid != NULL) {
  682. RtlFreeSid( SystemSid );
  683. }
  684. return Status;
  685. }
  686. /*******************************************************************************
  687. *
  688. * CsrPopulateDosDevices
  689. *
  690. * Populate the new session specific DosDevices Directory. This is an
  691. * export called by ntuser\server when a connection is completed.
  692. *
  693. * The security descriptor on the sessions \DosDevices should already
  694. * have been set.
  695. *
  696. * ENTRY:
  697. * HANDLE NewDosDevicesDirectory - Session specific DosDevices Directory
  698. * PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo
  699. *
  700. * EXIT:
  701. * STATUS_SUCCESS
  702. *
  703. ******************************************************************************/
  704. NTSTATUS
  705. CsrPopulateDosDevices(
  706. VOID
  707. )
  708. {
  709. NTSTATUS Status = STATUS_SUCCESS;
  710. PROCESS_DEVICEMAP_INFORMATION ProcessDeviceMapInfo;
  711. PROCESS_DEVICEMAP_INFORMATION GlobalProcessDeviceMapInfo;
  712. //
  713. // Get the global ProcessDeviceMap. We will use this to only add
  714. // non-network drive letters to the session specific dos devices
  715. // directory
  716. //
  717. Status = NtQueryInformationProcess( NtCurrentProcess(),
  718. ProcessDeviceMap,
  719. &GlobalProcessDeviceMapInfo.Query,
  720. sizeof( GlobalProcessDeviceMapInfo.Query ),
  721. NULL
  722. );
  723. if (!NT_SUCCESS( Status )) {
  724. DbgPrint("CSRSS: NtQueryInformationProcess failed in CsrPopulateDosDevices - status = %lx\n", Status);
  725. return Status;
  726. }
  727. //
  728. // Set the CSRSS's ProcessDeviceMap to the newly created DosDevices Directory
  729. //
  730. ProcessDeviceMapInfo.Set.DirectoryHandle = DosDevicesDirectory;
  731. Status = NtSetInformationProcess( NtCurrentProcess(),
  732. ProcessDeviceMap,
  733. &ProcessDeviceMapInfo.Set,
  734. sizeof( ProcessDeviceMapInfo.Set )
  735. );
  736. if (!NT_SUCCESS( Status )) {
  737. DbgPrint("CSRSS: NtSetInformationProcess failed in CsrPopulateDosDevices - status = %lx\n", Status);
  738. return Status;
  739. }
  740. //
  741. // Populate the session specfic DosDevices Directory
  742. //
  743. Status = CsrPopulateDosDevicesDirectory( DosDevicesDirectory, &GlobalProcessDeviceMapInfo );
  744. return Status;
  745. }
  746. /*******************************************************************************
  747. *
  748. * CsrPopulateDosDevicesDirectory
  749. *
  750. * Populate the new session specific DosDevices Direcotory
  751. *
  752. * ENTRY:
  753. * HANDLE NewDosDevicesDirectory - Session specific DosDevices Directory
  754. * PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo
  755. *
  756. * EXIT:
  757. * STATUS_SUCCESS
  758. *
  759. ******************************************************************************/
  760. NTSTATUS
  761. CsrPopulateDosDevicesDirectory( HANDLE NewDirectoryHandle,
  762. PPROCESS_DEVICEMAP_INFORMATION pGlobalProcessDeviceMapInfo )
  763. {
  764. NTSTATUS Status;
  765. UNICODE_STRING UnicodeString;
  766. UNICODE_STRING Target;
  767. OBJECT_ATTRIBUTES Attributes;
  768. HANDLE DirectoryHandle = NULL;
  769. HANDLE LinkHandle;
  770. POBJECT_DIRECTORY_INFORMATION DirInfo;
  771. ULONG DirInfoBufferLength = 16384; //16K
  772. PVOID DirInfoBuffer = NULL;
  773. WCHAR lpTargetPath[ 4096 ];
  774. ULONG Context;
  775. ULONG ReturnedLength = 0;
  776. ULONG DosDeviceDriveIndex = 0;
  777. WCHAR DosDeviceDriveLetter;
  778. //
  779. // Open the global DosDevices Directory. This used to populate the
  780. // the session specific DosDevices Directory
  781. //
  782. RtlInitUnicodeString( &UnicodeString, L"\\GLOBAL??" );
  783. InitializeObjectAttributes( &Attributes,
  784. &UnicodeString,
  785. OBJ_CASE_INSENSITIVE,
  786. NULL,
  787. NULL
  788. );
  789. Status = NtOpenDirectoryObject( &DirectoryHandle,
  790. DIRECTORY_QUERY,
  791. &Attributes
  792. );
  793. if (!NT_SUCCESS( Status )) {
  794. DbgPrint("CSRSS: NtOpenDirectoryObject failed in CsrPopulateDosDevicesDirectory - status = %lx\n", Status);
  795. return Status;
  796. }
  797. Restart:
  798. Context = 0;
  799. DirInfoBuffer = RtlAllocateHeap( CsrHeap,
  800. MAKE_TAG( PROCESS_TAG ) | HEAP_ZERO_MEMORY,
  801. DirInfoBufferLength
  802. );
  803. if (DirInfoBuffer == NULL) {
  804. Status = STATUS_NO_MEMORY;
  805. goto cleanup;
  806. }
  807. while (TRUE) {
  808. DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer;
  809. Status = NtQueryDirectoryObject( DirectoryHandle,
  810. (PVOID)DirInfo,
  811. DirInfoBufferLength,
  812. FALSE,
  813. FALSE,
  814. &Context,
  815. &ReturnedLength
  816. );
  817. //
  818. // Check the status of the operation.
  819. //
  820. if (!NT_SUCCESS( Status )) {
  821. if (Status == STATUS_BUFFER_TOO_SMALL) {
  822. DirInfoBufferLength = ReturnedLength;
  823. RtlFreeHeap( CsrHeap, 0, DirInfoBuffer );
  824. goto Restart;
  825. }
  826. if (Status == STATUS_NO_MORE_ENTRIES) {
  827. Status = STATUS_SUCCESS;
  828. }
  829. break;
  830. }
  831. while (DirInfo->Name.Length != 0) {
  832. if (!wcscmp( DirInfo->TypeName.Buffer, L"SymbolicLink" )) {
  833. InitializeObjectAttributes( &Attributes,
  834. &DirInfo->Name,
  835. OBJ_CASE_INSENSITIVE,
  836. DirectoryHandle,
  837. NULL
  838. );
  839. Status = NtOpenSymbolicLinkObject( &LinkHandle,
  840. SYMBOLIC_LINK_QUERY,
  841. &Attributes
  842. );
  843. if (NT_SUCCESS( Status )) {
  844. Target.Buffer = lpTargetPath;
  845. Target.Length = 0;
  846. Target.MaximumLength = 4096;
  847. ReturnedLength = 0;
  848. Status = NtQuerySymbolicLinkObject( LinkHandle,
  849. &Target,
  850. &ReturnedLength
  851. );
  852. NtClose( LinkHandle );
  853. if (NT_SUCCESS( Status )) {
  854. //
  855. // We only want to add Non-DOSDEVICE_DRIVE_REMOTE symbolic
  856. // links to the session specific directory
  857. //
  858. if ((DirInfo->Name.Length == 2 * sizeof( WCHAR )) &&
  859. (DirInfo->Name.Buffer[ 1 ] == L':')) {
  860. DosDeviceDriveLetter = RtlUpcaseUnicodeChar( DirInfo->Name.Buffer[ 0 ] );
  861. if ((DosDeviceDriveLetter >= L'A') && (DosDeviceDriveLetter <= L'Z')) {
  862. DosDeviceDriveIndex = DosDeviceDriveLetter - L'A';
  863. if ( (
  864. (pGlobalProcessDeviceMapInfo->Query.DriveType[DosDeviceDriveIndex] == DOSDEVICE_DRIVE_REMOTE)
  865. &&
  866. !(
  867. //Need to populate the Netware gateway drive
  868. ((Target.Length >= 13) && ((_wcsnicmp(Target.Buffer,L"\\Device\\NwRdr",13)==0)))
  869. &&
  870. ((Target.Length >= 16) && (Target.Buffer[15] != L':'))
  871. )
  872. )
  873. ||
  874. (
  875. (pGlobalProcessDeviceMapInfo->Query.DriveType[DosDeviceDriveIndex] == DOSDEVICE_DRIVE_CALCULATE)
  876. &&
  877. (
  878. ((Target.Length > 4) && (!_wcsnicmp(Target.Buffer,L"\\??\\",4)))
  879. ||
  880. ((Target.Length >= 14) && (!_wcsnicmp(Target.Buffer,L"\\Device\\WinDfs",14)))
  881. )
  882. )
  883. )
  884. {
  885. //Skip remote drives and virtual drives (subst)
  886. DirInfo = (POBJECT_DIRECTORY_INFORMATION)(((PUCHAR) DirInfo) + sizeof(OBJECT_DIRECTORY_INFORMATION));
  887. continue;
  888. }
  889. }
  890. }
  891. //
  892. // Create the new Symbolic Link
  893. //
  894. // The security on the new link is inherited
  895. // from the parent directory, which is setup
  896. // at create time.
  897. //
  898. InitializeObjectAttributes( &Attributes,
  899. &DirInfo->Name,
  900. 0,
  901. NewDirectoryHandle,
  902. NULL // Default security
  903. );
  904. Target.MaximumLength = Target.Length + sizeof( WCHAR );
  905. Attributes.Attributes |= OBJ_PERMANENT;
  906. Status = NtCreateSymbolicLinkObject( &LinkHandle,
  907. SYMBOLIC_LINK_ALL_ACCESS,
  908. &Attributes,
  909. &Target
  910. );
  911. Target.MaximumLength = 4096;
  912. // Don't close the handles. Cleaned up when CSRSS goes away
  913. if (!NT_SUCCESS( Status )) {
  914. #if DBG
  915. DbgPrint("CSRSS: Symbolic link creation failed in CsrPopulateDosDevicesDirectory for Name %ws and Target %ws- status = %lx for Session %ld\n", DirInfo->Name.Buffer, Target.Buffer, Status,NtCurrentPeb()->SessionId);
  916. #endif
  917. ASSERT(FALSE);
  918. }
  919. else {
  920. NtClose( LinkHandle );
  921. }
  922. }
  923. }
  924. }
  925. DirInfo = (POBJECT_DIRECTORY_INFORMATION)(((PUCHAR) DirInfo) + sizeof(OBJECT_DIRECTORY_INFORMATION));
  926. }
  927. }
  928. cleanup:
  929. if (DirectoryHandle) {
  930. NtClose(DirectoryHandle);
  931. }
  932. if (DirInfoBuffer) {
  933. RtlFreeHeap( CsrHeap, 0, DirInfoBuffer );
  934. }
  935. return Status;
  936. }
  937. /*******************************************************************************
  938. *
  939. * CsrCreateSessionObjectDirectory
  940. *
  941. * Creates \Sessions\<SessionId> and \Sessions\<SessionId>\DosDevices
  942. * Object Directories
  943. *
  944. * ENTRY:
  945. * ULONG SessionId
  946. *
  947. * EXIT:
  948. * STATUS_SUCCESS
  949. *
  950. ******************************************************************************/
  951. NTSTATUS
  952. CsrCreateSessionObjectDirectory( ULONG SessionId )
  953. {
  954. NTSTATUS Status = STATUS_SUCCESS;
  955. WCHAR szString[MAX_SESSION_PATH];
  956. WCHAR szTargetString[MAX_SESSION_PATH];
  957. UNICODE_STRING UnicodeString, LinkTarget;
  958. OBJECT_ATTRIBUTES Obja;
  959. HANDLE SymbolicLinkHandle;
  960. SECURITY_DESCRIPTOR DosDevicesSD;
  961. /*
  962. * \Sessions\BNOLINKS\0 -> \BaseNamedObjects
  963. * \Sessions\BNOLINKS\6 -> \Sessions\6\BaseNamedObjects
  964. * \Sessions\BNOLINKS\7 -> \Sessions\7\BaseNamedObjects
  965. */
  966. //
  967. //Create/Open the \\Sessions\BNOLINKS directory
  968. //
  969. swprintf(szString,L"%ws\\BNOLINKS",SESSION_ROOT);
  970. RtlInitUnicodeString( &UnicodeString, szString );
  971. InitializeObjectAttributes( &Obja,
  972. &UnicodeString,
  973. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  974. NULL,
  975. NULL
  976. );
  977. Status = NtCreateDirectoryObject( &BNOLinksDirectory,
  978. DIRECTORY_ALL_ACCESS,
  979. &Obja
  980. );
  981. if (!NT_SUCCESS( Status )) {
  982. DbgPrint("CSRSS: NtCreateDirectoryObject failed in CsrCreateSessionObjectDirectory - status = %lx\n", Status);
  983. return Status;
  984. }
  985. //
  986. // Create a symbolic link \\Sessions\BNOLINKS\<sessionid> pointing
  987. // to the session specific BaseNamedObjects directory
  988. // This symbolic link will be used by proccesses that want to e.g. access a
  989. // event in another session. This will be done by using the following
  990. // naming convention : Session\\<sessionid>\\ObjectName
  991. //
  992. swprintf(szString,L"%ld",SessionId);
  993. RtlInitUnicodeString( &UnicodeString, szString );
  994. if (SessionId == 0) {
  995. RtlInitUnicodeString( &LinkTarget, L"\\BaseNamedObjects" );
  996. } else {
  997. swprintf(szTargetString,L"%ws\\%ld\\BaseNamedObjects",SESSION_ROOT,SessionId);
  998. RtlInitUnicodeString(&LinkTarget, szTargetString);
  999. }
  1000. InitializeObjectAttributes( &Obja,
  1001. &UnicodeString,
  1002. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  1003. (HANDLE)BNOLinksDirectory,
  1004. NULL);
  1005. Status = NtCreateSymbolicLinkObject( &SymbolicLinkHandle,
  1006. SYMBOLIC_LINK_ALL_ACCESS,
  1007. &Obja,
  1008. &LinkTarget );
  1009. if (!NT_SUCCESS( Status )) {
  1010. DbgPrint("CSRSS: NtCreateSymbolicLinkObject failed in CsrCreateSessionObjectDirectory - status = %lx\n", Status);
  1011. return Status;
  1012. }
  1013. //
  1014. // Create the security descriptor to use for the object directories
  1015. //
  1016. Status = GetDosDevicesProtection( &DosDevicesSD );
  1017. if (!NT_SUCCESS( Status )) {
  1018. return Status;
  1019. }
  1020. //
  1021. // Create the Sessions\\<sessionid directory
  1022. //
  1023. swprintf(szString,L"%ws\\%ld",SESSION_ROOT,SessionId);
  1024. RtlInitUnicodeString( &UnicodeString, szString );
  1025. InitializeObjectAttributes( &Obja,
  1026. &UnicodeString,
  1027. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  1028. NULL,
  1029. &DosDevicesSD
  1030. );
  1031. Status = NtCreateDirectoryObject( &SessionObjectDirectory,
  1032. DIRECTORY_ALL_ACCESS,
  1033. &Obja
  1034. );
  1035. if (!NT_SUCCESS( Status )) {
  1036. DbgPrint("CSRSS: NtCreateDirectoryObject failed in CsrCreateSessionObjectDirectory - status = %lx\n", Status);
  1037. FreeDosDevicesProtection( &DosDevicesSD );
  1038. return Status;
  1039. }
  1040. RtlInitUnicodeString( &UnicodeString, L"DosDevices" );
  1041. InitializeObjectAttributes( &Obja,
  1042. &UnicodeString,
  1043. OBJ_CASE_INSENSITIVE,
  1044. SessionObjectDirectory,
  1045. &DosDevicesSD
  1046. );
  1047. //
  1048. // Create the Session specific DosDevices Directory
  1049. //
  1050. Status = NtCreateDirectoryObject( &DosDevicesDirectory,
  1051. DIRECTORY_ALL_ACCESS,
  1052. &Obja
  1053. );
  1054. if (!NT_SUCCESS( Status )) {
  1055. DbgPrint("CSRSS: NtCreateDirectoryObject failed in CsrCreateSessionObjectDirectory - status = %lx\n", Status);
  1056. FreeDosDevicesProtection( &DosDevicesSD );
  1057. return Status;
  1058. }
  1059. FreeDosDevicesProtection( &DosDevicesSD );
  1060. return Status;
  1061. }
  1062. NTSTATUS
  1063. GetDosDevicesProtection (
  1064. PSECURITY_DESCRIPTOR SecurityDescriptor
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. This routine builds a security descriptor for use in creating
  1069. the \DosDevices object directory. The protection of \DosDevices
  1070. must establish inheritable protection which will dictate how
  1071. dos devices created via the DefineDosDevice() and
  1072. IoCreateUnprotectedSymbolicLink() apis can be managed.
  1073. The protection assigned is dependent upon an administrable registry
  1074. key:
  1075. Key: \hkey_local_machine\System\CurrentControlSet\Control\Session Manager
  1076. Value: [REG_DWORD] ProtectionMode
  1077. If this value is 0x1, then
  1078. Administrators may control all Dos devices,
  1079. Anyone may create new Dos devices (such as net drives
  1080. or additional printers),
  1081. Anyone may use any Dos device,
  1082. The creator of a Dos device may delete it.
  1083. Note that this protects system-defined LPTs and COMs so that only
  1084. administrators may redirect them. However, anyone may add
  1085. additional printers and direct them to wherever they would
  1086. like.
  1087. This is achieved with the following protection for the DosDevices
  1088. Directory object:
  1089. Grant: World: Execute | Read | Write (No Inherit)
  1090. Grant: System: All Access (No Inherit)
  1091. Grant: World: Execute (Inherit Only)
  1092. Grant: Admins: All Access (Inherit Only)
  1093. Grant: System: All Access (Inherit Only)
  1094. Grant: Owner: All Access (Inherit Only)
  1095. If this value is 0x0, or not present, then
  1096. Administrators may control all Dos devices,
  1097. Anyone may create new Dos devices (such as net drives
  1098. or additional printers),
  1099. Anyone may use any Dos device,
  1100. Anyone may delete Dos devices created with either DefineDosDevice()
  1101. or IoCreateUnprotectedSymbolicLink(). This is how network drives
  1102. and LPTs are created (but not COMs).
  1103. This is achieved with the following protection for the DosDevices
  1104. Directory object:
  1105. Grant: World: Execute | Read | Write (No Inherit)
  1106. Grant: System: All Access (No Inherit)
  1107. Grant: World: All Access (Inherit Only)
  1108. Arguments:
  1109. SecurityDescriptor - The address of a security descriptor to be
  1110. initialized and filled in. When this security descriptor is no
  1111. longer needed, you should call FreeDosDevicesProtection() to
  1112. free the protection information.
  1113. Return Value:
  1114. Returns one of the following status codes:
  1115. STATUS_SUCCESS - normal, successful completion.
  1116. --*/
  1117. {
  1118. NTSTATUS Status = STATUS_SUCCESS;
  1119. ULONG aceIndex, aclLength;
  1120. PACL dacl = NULL;
  1121. PACE_HEADER ace;
  1122. ACCESS_MASK accessMask;
  1123. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1124. SID_IDENTIFIER_AUTHORITY WorldAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1125. SID_IDENTIFIER_AUTHORITY CreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  1126. PSID LocalSystemSid;
  1127. PSID WorldSid;
  1128. PSID CreatorOwnerSid;
  1129. PSID AliasAdminsSid;
  1130. UNICODE_STRING NameString;
  1131. OBJECT_ATTRIBUTES Obja;
  1132. ULONG ProtectionMode = 0;
  1133. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  1134. WCHAR ValueBuffer[ 32 ];
  1135. ULONG ResultLength;
  1136. HANDLE KeyHandle;
  1137. UCHAR inheritOnlyFlags = (OBJECT_INHERIT_ACE |
  1138. CONTAINER_INHERIT_ACE |
  1139. INHERIT_ONLY_ACE
  1140. );
  1141. UCHAR inheritFlags = (OBJECT_INHERIT_ACE |
  1142. CONTAINER_INHERIT_ACE
  1143. );
  1144. Status = RtlCreateSecurityDescriptor( SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  1145. if (!NT_SUCCESS( Status )) {
  1146. ASSERT( NT_SUCCESS( Status ) );
  1147. return( Status );
  1148. }
  1149. Status = RtlAllocateAndInitializeSid(
  1150. &NtAuthority,
  1151. 1,
  1152. SECURITY_LOCAL_SYSTEM_RID,
  1153. 0, 0, 0, 0, 0, 0, 0,
  1154. &LocalSystemSid
  1155. );
  1156. if (!NT_SUCCESS( Status )) {
  1157. ASSERT( NT_SUCCESS( Status ) );
  1158. return( Status );
  1159. }
  1160. Status = RtlAllocateAndInitializeSid(
  1161. &WorldAuthority,
  1162. 1,
  1163. SECURITY_WORLD_RID,
  1164. 0, 0, 0, 0, 0, 0, 0,
  1165. &WorldSid
  1166. );
  1167. if (!NT_SUCCESS( Status )) {
  1168. RtlFreeSid( LocalSystemSid );
  1169. ASSERT( NT_SUCCESS( Status ) );
  1170. return( Status );
  1171. }
  1172. Status = RtlAllocateAndInitializeSid(
  1173. &NtAuthority,
  1174. 2,
  1175. SECURITY_BUILTIN_DOMAIN_RID,
  1176. DOMAIN_ALIAS_RID_ADMINS,
  1177. 0, 0, 0, 0, 0, 0,
  1178. &AliasAdminsSid
  1179. );
  1180. if (!NT_SUCCESS( Status )) {
  1181. RtlFreeSid( LocalSystemSid );
  1182. RtlFreeSid( WorldSid );
  1183. ASSERT( NT_SUCCESS( Status ) );
  1184. return( Status );
  1185. }
  1186. Status = RtlAllocateAndInitializeSid(
  1187. &CreatorAuthority,
  1188. 1,
  1189. SECURITY_CREATOR_OWNER_RID,
  1190. 0, 0, 0, 0, 0, 0, 0,
  1191. &CreatorOwnerSid
  1192. );
  1193. if (!NT_SUCCESS( Status )) {
  1194. RtlFreeSid( LocalSystemSid );
  1195. RtlFreeSid( WorldSid );
  1196. RtlFreeSid( AliasAdminsSid );
  1197. ASSERT( NT_SUCCESS( Status ) );
  1198. return( Status );
  1199. }
  1200. RtlInitUnicodeString( &NameString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
  1201. InitializeObjectAttributes( &Obja,
  1202. &NameString,
  1203. OBJ_CASE_INSENSITIVE,
  1204. NULL,
  1205. NULL );
  1206. Status = NtOpenKey( &KeyHandle,
  1207. KEY_READ,
  1208. &Obja
  1209. );
  1210. if (NT_SUCCESS(Status)) {
  1211. RtlInitUnicodeString( &NameString, L"ProtectionMode" );
  1212. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  1213. Status = NtQueryValueKey( KeyHandle,
  1214. &NameString,
  1215. KeyValuePartialInformation,
  1216. KeyValueInformation,
  1217. sizeof( ValueBuffer ),
  1218. &ResultLength
  1219. );
  1220. if (NT_SUCCESS(Status)) {
  1221. if (KeyValueInformation->Type == REG_DWORD &&
  1222. *(PULONG)KeyValueInformation->Data) {
  1223. ProtectionMode = *(PULONG)KeyValueInformation->Data;
  1224. }
  1225. }
  1226. NtClose( KeyHandle );
  1227. }
  1228. if (ProtectionMode & 0x00000003) {
  1229. //
  1230. // If ProtectionMode is set to 1 or 2 Terminal Server
  1231. // locks down sessions tight.
  1232. //
  1233. // Dacl:
  1234. // Grant: System: All Access (With Inherit)
  1235. // Grant: Admins: All Access (With Inherit)
  1236. // Grant: Owner: All Access (Inherit Only)
  1237. // Grant: World: No Access
  1238. //
  1239. aclLength = sizeof( ACL ) +
  1240. 3 * sizeof( ACCESS_ALLOWED_ACE ) +
  1241. RtlLengthSid( LocalSystemSid ) +
  1242. RtlLengthSid( AliasAdminsSid ) +
  1243. RtlLengthSid( CreatorOwnerSid );
  1244. dacl = (PACL)RtlAllocateHeap( CsrHeap,
  1245. MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY,
  1246. aclLength );
  1247. if (dacl == NULL) {
  1248. Status = STATUS_NO_MEMORY;
  1249. ASSERT( NT_SUCCESS( Status ) );
  1250. goto cleanup;
  1251. }
  1252. Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2);
  1253. if (!NT_SUCCESS( Status )) {
  1254. ASSERT( NT_SUCCESS( Status ) );
  1255. goto cleanup;
  1256. }
  1257. aceIndex = 0;
  1258. accessMask = (GENERIC_ALL);
  1259. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, LocalSystemSid );
  1260. if (!NT_SUCCESS( Status )) {
  1261. ASSERT( NT_SUCCESS( Status ) );
  1262. goto cleanup;
  1263. }
  1264. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1265. if (!NT_SUCCESS( Status )) {
  1266. ASSERT( NT_SUCCESS( Status ) );
  1267. goto cleanup;
  1268. }
  1269. ace->AceFlags |= inheritFlags;
  1270. aceIndex++;
  1271. accessMask = (GENERIC_ALL);
  1272. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, AliasAdminsSid );
  1273. if (!NT_SUCCESS( Status )) {
  1274. ASSERT( NT_SUCCESS( Status ) );
  1275. goto cleanup;
  1276. }
  1277. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1278. if (!NT_SUCCESS( Status )) {
  1279. ASSERT( NT_SUCCESS( Status ) );
  1280. goto cleanup;
  1281. }
  1282. ace->AceFlags |= inheritFlags;
  1283. //
  1284. // Inherit only ACE at the end of the ACL
  1285. // Owner
  1286. //
  1287. aceIndex++;
  1288. accessMask = (GENERIC_ALL);
  1289. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, CreatorOwnerSid );
  1290. if (!NT_SUCCESS( Status )) {
  1291. ASSERT( NT_SUCCESS( Status ) );
  1292. goto cleanup;
  1293. }
  1294. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1295. if (!NT_SUCCESS( Status )) {
  1296. ASSERT( NT_SUCCESS( Status ) );
  1297. goto cleanup;
  1298. }
  1299. ace->AceFlags |= inheritOnlyFlags;
  1300. Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor,
  1301. TRUE, //DaclPresent,
  1302. dacl, //Dacl
  1303. FALSE ); //!DaclDefaulted
  1304. if (!NT_SUCCESS( Status )) {
  1305. ASSERT( NT_SUCCESS( Status ) );
  1306. goto cleanup;
  1307. }
  1308. } else {
  1309. //
  1310. // DACL:
  1311. // Grant: World: Execute | Read | Write (No Inherit)
  1312. // Grant: System: All Access (No Inherit)
  1313. // Grant: World: All Access (Inherit Only)
  1314. //
  1315. aclLength = sizeof( ACL ) +
  1316. 3 * sizeof( ACCESS_ALLOWED_ACE ) +
  1317. (2*RtlLengthSid( WorldSid )) +
  1318. RtlLengthSid( LocalSystemSid );
  1319. dacl = (PACL)RtlAllocateHeap( CsrHeap,
  1320. MAKE_TAG( SECURITY_TAG ) | HEAP_ZERO_MEMORY,
  1321. aclLength );
  1322. if (dacl == NULL) {
  1323. ASSERT( NT_SUCCESS( Status ) );
  1324. Status = STATUS_NO_MEMORY;
  1325. goto cleanup;
  1326. }
  1327. Status = RtlCreateAcl( dacl, aclLength, ACL_REVISION2);
  1328. if (!NT_SUCCESS( Status )) {
  1329. ASSERT( NT_SUCCESS( Status ) );
  1330. goto cleanup;
  1331. }
  1332. //
  1333. // Non-inheritable ACEs first
  1334. // World
  1335. // System
  1336. //
  1337. aceIndex = 0;
  1338. accessMask = (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE);
  1339. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, WorldSid );
  1340. if (!NT_SUCCESS( Status )) {
  1341. ASSERT( NT_SUCCESS( Status ) );
  1342. goto cleanup;
  1343. }
  1344. aceIndex++;
  1345. accessMask = (GENERIC_ALL);
  1346. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, LocalSystemSid );
  1347. if (!NT_SUCCESS( Status )) {
  1348. ASSERT( NT_SUCCESS( Status ) );
  1349. goto cleanup;
  1350. }
  1351. //
  1352. // Inheritable ACEs at the end of the ACL
  1353. // World
  1354. //
  1355. aceIndex++;
  1356. accessMask = (GENERIC_ALL);
  1357. Status = RtlAddAccessAllowedAce ( dacl, ACL_REVISION2, accessMask, WorldSid );
  1358. if (!NT_SUCCESS( Status )) {
  1359. ASSERT( NT_SUCCESS( Status ) );
  1360. goto cleanup;
  1361. }
  1362. Status = RtlGetAce( dacl, aceIndex, (PVOID)&ace );
  1363. if (!NT_SUCCESS( Status )) {
  1364. ASSERT( NT_SUCCESS( Status ) );
  1365. goto cleanup;
  1366. }
  1367. ace->AceFlags |= inheritOnlyFlags;
  1368. Status = RtlSetDaclSecurityDescriptor( SecurityDescriptor,
  1369. TRUE, //DaclPresent,
  1370. dacl, //Dacl
  1371. FALSE ); //!DaclDefaulted
  1372. if (!NT_SUCCESS( Status )) {
  1373. ASSERT( NT_SUCCESS( Status ) );
  1374. goto cleanup;
  1375. }
  1376. }
  1377. cleanup:
  1378. if (!NT_SUCCESS( Status ) && (dacl != NULL)) {
  1379. RtlFreeHeap( CsrHeap, 0, dacl);
  1380. }
  1381. RtlFreeSid( LocalSystemSid );
  1382. RtlFreeSid( WorldSid );
  1383. RtlFreeSid( AliasAdminsSid );
  1384. RtlFreeSid( CreatorOwnerSid );
  1385. if (!NT_SUCCESS( Status )) {
  1386. DbgPrint("CSRSS: GetDosDevicesProtection failed - status = %lx\n", Status);
  1387. ASSERT( NT_SUCCESS( Status ) );
  1388. }
  1389. return Status;
  1390. }
  1391. VOID
  1392. FreeDosDevicesProtection (
  1393. PSECURITY_DESCRIPTOR SecurityDescriptor
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. This routine frees memory allocated via GetDosDevicesProtection().
  1398. Arguments:
  1399. SecurityDescriptor - The address of a security descriptor initialized by
  1400. GetDosDevicesProtection().
  1401. Return Value:
  1402. None.
  1403. --*/
  1404. {
  1405. NTSTATUS Status;
  1406. PACL Dacl = NULL;
  1407. BOOLEAN DaclPresent, Defaulted;
  1408. Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
  1409. &DaclPresent,
  1410. &Dacl,
  1411. &Defaulted);
  1412. ASSERT(NT_SUCCESS(Status));
  1413. ASSERT(DaclPresent);
  1414. ASSERT(Dacl != NULL);
  1415. if (NT_SUCCESS(Status) && Dacl != NULL) {
  1416. RtlFreeHeap(CsrHeap, 0, Dacl);
  1417. }
  1418. }