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.

3563 lines
92 KiB

  1. /*************************************************************************
  2. *
  3. * acl.c
  4. *
  5. * Routines to manage Window Station Security.
  6. *
  7. *
  8. * Copyright Microsoft Corporation, 1998
  9. *
  10. *************************************************************************/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. #include <winsta.h>
  14. #include <rpc.h>
  15. #include <seopaque.h>
  16. /*
  17. * NOTE: Please keep all security code for ICASRV and CITRIX WINSTATIONS
  18. * in this file. This helps to compartmentilize the security routines
  19. * to make it easier to update/debug our policies.
  20. *
  21. */
  22. #if DBG
  23. ULONG
  24. DbgPrint(
  25. PCH Format,
  26. ...
  27. );
  28. #define DBGPRINT(x) DbgPrint x
  29. #if DBGTRACE
  30. #define TRACE0(x) DbgPrint x
  31. #define TRACE1(x) DbgPrint x
  32. #else
  33. #define TRACE0(x)
  34. #define TRACE1(x)
  35. #endif
  36. #else
  37. #define DBGPRINT(x)
  38. #define TRACE0(x)
  39. #define TRACE1(x)
  40. #endif
  41. /*
  42. * Forward references
  43. */
  44. VOID
  45. CleanUpSD(
  46. PSECURITY_DESCRIPTOR pSD
  47. );
  48. NTSTATUS IcaRegWinStationEnumerate( PULONG, PWINSTATIONNAME, PULONG );
  49. NTSTATUS
  50. ConfigureSecurity(
  51. IN PWSTR ValueName,
  52. IN ULONG ValueType,
  53. IN PVOID ValueData,
  54. IN ULONG ValueLength,
  55. IN PVOID Context,
  56. IN PVOID EntryContext
  57. );
  58. NTSTATUS
  59. ConfigureConsoleSecurity(
  60. IN PWSTR ValueName,
  61. IN ULONG ValueType,
  62. IN PVOID ValueData,
  63. IN ULONG ValueLength,
  64. IN PVOID Context,
  65. IN PVOID EntryContext
  66. );
  67. PSECURITY_DESCRIPTOR
  68. CreateWinStationDefaultSecurityDescriptor();
  69. NTSTATUS
  70. RpcGetClientLogonId(
  71. PULONG pLogonId
  72. );
  73. NTSTATUS
  74. RpcCheckSystemClientEx(
  75. PWINSTATION pWinStation
  76. );
  77. BOOL
  78. IsCallerSystem( VOID );
  79. BOOL
  80. IsCallerAdmin( VOID );
  81. BOOL
  82. IsServiceLoggedAsSystem( VOID );
  83. BOOL
  84. IsSystemToken( HANDLE TokenHandle );
  85. NTSTATUS
  86. RpcCheckSystemClientNoLogonId(
  87. PWINSTATION pWinStation
  88. );
  89. NTSTATUS
  90. RpcCheckClientAccessLocal(
  91. PWINSTATION pWinStation,
  92. ACCESS_MASK DesiredAccess,
  93. BOOLEAN AlreadyImpersonating
  94. );
  95. BOOL
  96. AddAccessToDirectory(
  97. PWCHAR pPath,
  98. DWORD NewAccess,
  99. PSID pSid
  100. );
  101. NTSTATUS
  102. AddAccessToDirectoryObjects(
  103. HANDLE DirectoryHandle,
  104. DWORD NewAccess,
  105. PSID pSid
  106. );
  107. BOOL
  108. AddAceToSecurityDescriptor(
  109. PSECURITY_DESCRIPTOR *ppSd,
  110. PACL *ppDacl,
  111. DWORD Access,
  112. PSID pSid,
  113. BOOLEAN InheritOnly
  114. );
  115. BOOL
  116. SelfRelativeToAbsoluteSD(
  117. PSECURITY_DESCRIPTOR SecurityDescriptorIn,
  118. PSECURITY_DESCRIPTOR *SecurityDescriptorOut,
  119. PULONG ReturnedLength
  120. );
  121. BOOL
  122. AbsoluteToSelfRelativeSD(
  123. PSECURITY_DESCRIPTOR SecurityDescriptorIn,
  124. PSECURITY_DESCRIPTOR *SecurityDescriptorOut,
  125. PULONG ReturnedLength
  126. );
  127. NTSTATUS ApplyWinStaMappingToSD(
  128. PSECURITY_DESCRIPTOR pSecurityDescriptor
  129. );
  130. /*
  131. * Global data
  132. */
  133. PSECURITY_DESCRIPTOR DefaultWinStationSecurityDescriptor = NULL;
  134. PSECURITY_DESCRIPTOR DefaultConsoleSecurityDescriptor = NULL;
  135. /*
  136. * Structure to lookup the default security descriptor
  137. * for WINSTATIONS.
  138. */
  139. RTL_QUERY_REGISTRY_TABLE DefaultSecurityTable[] = {
  140. {NULL, RTL_QUERY_REGISTRY_SUBKEY,
  141. REG_WINSTATIONS, NULL,
  142. REG_NONE, NULL, 0},
  143. {ConfigureSecurity, RTL_QUERY_REGISTRY_REQUIRED,
  144. REG_DEFAULTSECURITY, NULL,
  145. REG_NONE, NULL, 0},
  146. {NULL, 0,
  147. NULL, NULL,
  148. REG_NONE, NULL, 0}
  149. };
  150. /*
  151. * Structure to lookup the default console security descriptor
  152. */
  153. RTL_QUERY_REGISTRY_TABLE ConsoleSecurityTable[] = {
  154. {NULL, RTL_QUERY_REGISTRY_SUBKEY,
  155. REG_WINSTATIONS, NULL,
  156. REG_NONE, NULL, 0},
  157. {ConfigureConsoleSecurity, RTL_QUERY_REGISTRY_REQUIRED,
  158. REG_CONSOLESECURITY, NULL,
  159. REG_NONE, NULL, 0},
  160. {NULL, 0,
  161. NULL, NULL,
  162. REG_NONE, NULL, 0}
  163. };
  164. extern PSID gSystemSid;
  165. extern PSID gAdminSid;
  166. extern RTL_RESOURCE WinStationSecurityLock;
  167. /*
  168. * Structure to lookup the security on a specific WINSTATION
  169. * type name in the registry.
  170. *
  171. * This is control\Terminal Server\WinStations\<name>\Security
  172. *
  173. * <name> is the transport type. IE: TCP, IPX, etc.
  174. */
  175. RTL_QUERY_REGISTRY_TABLE WinStationSecurityTable[] = {
  176. {ConfigureSecurity, RTL_QUERY_REGISTRY_REQUIRED,
  177. REG_SECURITY, NULL,
  178. REG_NONE, NULL, 0},
  179. {NULL, 0,
  180. NULL, NULL,
  181. REG_NONE, NULL, 0}
  182. };
  183. LPCWSTR szTermsrv = L"Termsrv";
  184. LPCWSTR szTermsrvSession = L"Termsrv Session";
  185. //
  186. // Structure that describes the mapping of generic access rights to object
  187. // specific access rights for Window Station objects.
  188. //
  189. GENERIC_MAPPING WinStaMapping = {
  190. STANDARD_RIGHTS_READ |
  191. WINSTATION_QUERY,
  192. STANDARD_RIGHTS_WRITE |
  193. WINSTATION_SET,
  194. STANDARD_RIGHTS_EXECUTE,
  195. WINSTATION_ALL_ACCESS
  196. };
  197. /*******************************************************************************
  198. *
  199. * WinStationSecurityInit
  200. *
  201. * Initialize the WinStation security.
  202. *
  203. * ENTRY:
  204. * nothing
  205. *
  206. * EXIT:
  207. * STATUS_SUCCESS
  208. *
  209. ******************************************************************************/
  210. NTSTATUS
  211. WinStationSecurityInit( VOID )
  212. {
  213. NTSTATUS Status;
  214. /*
  215. * Get the default security descriptor from the registry
  216. *
  217. * This is placed on WinStations that do not have specific
  218. * security placed on them by WinAdmin.
  219. *
  220. * This key is in CurrentControlSet\Control\Terminal Server\WinStations\DefaultSecurity
  221. */
  222. Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
  223. REG_TSERVER,
  224. DefaultSecurityTable,
  225. NULL,
  226. DefaultEnvironment
  227. );
  228. /*
  229. * If the key does not exist, create a default security descriptor.
  230. *
  231. * NOTE: This is now created by default always by SM manager. The
  232. * SM default must match the default here.
  233. * This is so that the console is created with the right SD.
  234. */
  235. if ( ( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  236. || ( DefaultWinStationSecurityDescriptor == NULL ) ) {
  237. PSECURITY_DESCRIPTOR Default;
  238. ULONG Length;
  239. Default = CreateWinStationDefaultSecurityDescriptor();
  240. ASSERT( Default != NULL );
  241. if (Default == NULL) {
  242. return STATUS_NO_MEMORY;
  243. }
  244. Length = RtlLengthSecurityDescriptor(Default);
  245. // Ensure the complete path exists
  246. RtlCreateRegistryKey( RTL_REGISTRY_CONTROL, REG_TSERVER );
  247. RtlCreateRegistryKey( RTL_REGISTRY_CONTROL, REG_TSERVER_WINSTATIONS );
  248. Status = RtlWriteRegistryValue( RTL_REGISTRY_CONTROL,
  249. REG_TSERVER_WINSTATIONS,
  250. REG_DEFAULTSECURITY, REG_BINARY,
  251. Default, Length );
  252. DefaultWinStationSecurityDescriptor = Default;
  253. }
  254. if (!NT_SUCCESS( Status )) {
  255. DBGPRINT(( "TERMSRV: RtlQueryRegistryValues(Terminal Server) failed - Status == %lx\n", Status ));
  256. }
  257. ASSERT( DefaultWinStationSecurityDescriptor != NULL );
  258. //Just do the same for default console security descriptor
  259. //--------------------------------------------------------------------------------------
  260. /*
  261. * Get the default console security descriptor from the registry
  262. *
  263. * This is placed on WinStations that do not have specific
  264. * security placed on them by WinAdmin.
  265. *
  266. * This key is in CurrentControlSet\Control\Terminal Server\WinStations\ConsoleSecurity
  267. */
  268. Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
  269. REG_TSERVER,
  270. ConsoleSecurityTable,
  271. NULL,
  272. DefaultEnvironment
  273. );
  274. /*
  275. * If the key does not exist, set default console SD to be equal to
  276. * default SD
  277. */
  278. if ( ( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  279. || ( DefaultConsoleSecurityDescriptor == NULL ) ) {
  280. DefaultConsoleSecurityDescriptor = DefaultWinStationSecurityDescriptor;
  281. }
  282. ASSERT( DefaultConsoleSecurityDescriptor != NULL );
  283. //--------------------------------------------------------------------------------------
  284. return( STATUS_SUCCESS );
  285. }
  286. /*****************************************************************************
  287. *
  288. * ReadWinStationSecurityDescriptor
  289. *
  290. * Read the security descriptor from the registry for the
  291. * WINSTATION name.
  292. *
  293. * The WINSTATION name is the base protocol name, or the one shot name.
  294. * IE: "TCP", or "COM3". It is not an instance name such as "TCP#4".
  295. *
  296. * This is called by the WSF_LISTEN thread to get any specific ACL's
  297. * for the WINSTATION protocol type.
  298. *
  299. * ENTRY:
  300. * Param1 (input/output)
  301. * Comments
  302. *
  303. * EXIT:
  304. * STATUS_SUCCESS - no error
  305. *
  306. ****************************************************************************/
  307. NTSTATUS
  308. ReadWinStationSecurityDescriptor(
  309. PWINSTATION pWinStation
  310. )
  311. {
  312. LONG cb;
  313. LPWSTR PathBuf;
  314. NTSTATUS Status;
  315. ULONG Length;
  316. PACL Dacl, NewDacl = NULL;
  317. BOOLEAN DaclPresent, DaclDefaulted;
  318. ACL_SIZE_INFORMATION AclInfo;
  319. PACE_HEADER CurrentAce;
  320. ULONG i;
  321. /*
  322. * If no name, we can not lookup the security descriptor.
  323. */
  324. if( pWinStation->WinStationName[0] == UNICODE_NULL ) {
  325. TRACE0(("TERMSRV: ReadWinStationSecurityDescriptor: No name on WinStation LogonId %d\n",pWinStation->LogonId));
  326. return( STATUS_NO_SECURITY_ON_OBJECT );
  327. }
  328. TRACE0(("TERMSRV: ReadWinStationSecurityDescriptor: Name %ws\n",&pWinStation->WinStationName));
  329. cb = sizeof( REG_TSERVER_WINSTATIONS ) +
  330. sizeof( L"\\" ) +
  331. sizeof(WINSTATIONNAME) +
  332. sizeof(UNICODE_NULL);
  333. PathBuf = MemAlloc( cb );
  334. if ( PathBuf == NULL )
  335. return( STATUS_NO_MEMORY );
  336. wcscpy( PathBuf, REG_TSERVER_WINSTATIONS );
  337. wcscat( PathBuf, L"\\" );
  338. wcscat( PathBuf, pWinStation->WinStationName );
  339. Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
  340. PathBuf,
  341. WinStationSecurityTable,
  342. pWinStation,
  343. DefaultEnvironment
  344. );
  345. /*
  346. * Do not let a Winstation with no security descriptor
  347. */
  348. if ( ( ( Status == STATUS_OBJECT_NAME_NOT_FOUND )
  349. || ( pWinStation->pSecurityDescriptor == NULL) )
  350. && (DefaultWinStationSecurityDescriptor != NULL) )
  351. {
  352. //
  353. // Free the old one if allocated
  354. //
  355. if ( pWinStation->pSecurityDescriptor ) {
  356. // must break up into absolute format and self-relative
  357. CleanUpSD(pWinStation->pSecurityDescriptor);
  358. pWinStation->pSecurityDescriptor = NULL;
  359. }
  360. if(_wcsicmp( pWinStation->WinStationName, L"Console" ))
  361. {
  362. // RtlCopySecurityDescriptor only works with self-relative format
  363. Status = RtlCopySecurityDescriptor(DefaultWinStationSecurityDescriptor,
  364. &(pWinStation->pSecurityDescriptor));
  365. }
  366. else
  367. {
  368. //It is a console winstation
  369. Status = RtlCopySecurityDescriptor(DefaultConsoleSecurityDescriptor,
  370. &(pWinStation->pSecurityDescriptor));
  371. }
  372. }
  373. TRACE0(("TERMSRV: ReadWinStationSecurityDescriptor: Status 0x%x\n",Status));
  374. MemFree( PathBuf );
  375. return( Status );
  376. }
  377. /*****************************************************************************
  378. *
  379. * ConfigureSecurity
  380. *
  381. * Processing function called by RtlQueryRegistryValues() to process the
  382. * WINSTATION security descriptor read from the registry.
  383. *
  384. * ENTRY:
  385. * Param1 (input/output)
  386. * Comments
  387. *
  388. * EXIT:
  389. * STATUS_SUCCESS - no error
  390. *
  391. ****************************************************************************/
  392. NTSTATUS
  393. ConfigureSecurity(
  394. IN PWSTR ValueName,
  395. IN ULONG ValueType,
  396. IN PVOID ValueData,
  397. IN ULONG ValueLength,
  398. IN PVOID Context,
  399. IN PVOID EntryContext
  400. )
  401. {
  402. NTSTATUS Status;
  403. PSECURITY_DESCRIPTOR * ppSD;
  404. PWINSTATION pWinStation = (PWINSTATION)Context;
  405. PSID pOwnerSid = NULL;
  406. BOOLEAN bOD;
  407. PSID pGroupSid = NULL;
  408. BOOLEAN bGD;
  409. PSID SystemSid;
  410. SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY;
  411. /*
  412. * Ensure value type is REG_BINARY and length of value data
  413. * is at least the length of a minimum security descriptor
  414. * and not unreasonably large.
  415. */
  416. if ( ValueType != REG_BINARY ||
  417. ValueLength < SECURITY_DESCRIPTOR_MIN_LENGTH ||
  418. ValueLength > MAXUSHORT ) {
  419. DBGPRINT(( "TERMSRV: ConfigureSecurity, ValueType=0x%x\n", ValueType ));
  420. return( STATUS_INVALID_SECURITY_DESCR );
  421. }
  422. if( !IsValidSecurityDescriptor( ValueData )) {
  423. DBGPRINT(( "TERMSRV: ConfigureSecurity, Invalid Security Descriptor in registry\n"));
  424. return( STATUS_INVALID_SECURITY_DESCR );
  425. }
  426. //
  427. // HACK needed for TS 4.0 security descriptors conversion
  428. //
  429. if (!NT_SUCCESS(RtlGetOwnerSecurityDescriptor( ValueData, &pOwnerSid, &bOD))
  430. || (pOwnerSid == NULL))
  431. {
  432. DBGPRINT(( "TERMSRV: ConfigureSecurity, Invalid Security Descriptor in registry: Can't get owner\n"));
  433. return( STATUS_INVALID_SECURITY_DESCR );
  434. }
  435. if (!NT_SUCCESS(RtlGetGroupSecurityDescriptor( ValueData, &pGroupSid, &bGD)))
  436. {
  437. DBGPRINT(( "TERMSRV: ConfigureSecurity, Invalid Security Descriptor in registry: Can't get group\n"));
  438. return( STATUS_INVALID_SECURITY_DESCR );
  439. }
  440. if( pWinStation ) {
  441. /*
  442. * WinStation specific security descriptor
  443. */
  444. ppSD = &(pWinStation->pSecurityDescriptor);
  445. }
  446. else {
  447. /*
  448. * Update the global default security descriptor
  449. */
  450. ppSD = &DefaultWinStationSecurityDescriptor;
  451. }
  452. //
  453. // Free old one if allocated
  454. //
  455. if (*ppSD != NULL) {
  456. CleanUpSD(*ppSD);
  457. //RtlDeleteSecurityObject( ppSD );
  458. *ppSD = NULL;
  459. }
  460. if (pGroupSid != NULL)
  461. {
  462. //
  463. // Regular case:
  464. // Copy the value read in registry
  465. //
  466. // RtlCopySecurityDescriptor only works with self-relative format
  467. RtlCopySecurityDescriptor((PSECURITY_DESCRIPTOR)ValueData, ppSD);
  468. }
  469. else
  470. {
  471. //
  472. // Conversion for TS 4 descriptors
  473. //
  474. PSECURITY_DESCRIPTOR AbsoluteSD = NULL;
  475. if (SelfRelativeToAbsoluteSD ( (PSECURITY_DESCRIPTOR)ValueData, &AbsoluteSD, NULL))
  476. {
  477. // set the owner as group (both should be system sid)
  478. Status = RtlSetGroupSecurityDescriptor(AbsoluteSD, pOwnerSid, FALSE);
  479. if (NT_SUCCESS(Status))
  480. {
  481. // need also to force the mapping. Sigh !
  482. Status = ApplyWinStaMappingToSD(AbsoluteSD);
  483. if ((!NT_SUCCESS(Status)) || ( !AbsoluteToSelfRelativeSD (AbsoluteSD, ppSD, NULL)))
  484. {
  485. Status = STATUS_INVALID_SECURITY_DESCR;
  486. }
  487. }
  488. // Absolute SD was only needed temporarily
  489. CleanUpSD( AbsoluteSD );
  490. }
  491. else
  492. {
  493. Status = STATUS_INVALID_SECURITY_DESCR;
  494. }
  495. if (!NT_SUCCESS(Status))
  496. {
  497. DBGPRINT(( "TERMSRV: ConfigureSecurity, Invalid Security Descriptor in registry\n"));
  498. return( STATUS_INVALID_SECURITY_DESCR );
  499. }
  500. }
  501. return( STATUS_SUCCESS );
  502. }
  503. /*****************************************************************************
  504. *
  505. * ConfigureConsoleSecurity
  506. *
  507. * Processing function called by RtlQueryRegistryValues() to process the
  508. * default console security descriptor read from the registry.
  509. *
  510. * ENTRY:
  511. * Param1 (input/output)
  512. * Comments
  513. *
  514. * EXIT:
  515. * STATUS_SUCCESS - no error
  516. *
  517. ****************************************************************************/
  518. NTSTATUS
  519. ConfigureConsoleSecurity(
  520. IN PWSTR ValueName,
  521. IN ULONG ValueType,
  522. IN PVOID ValueData,
  523. IN ULONG ValueLength,
  524. IN PVOID Context,
  525. IN PVOID EntryContext
  526. )
  527. {
  528. NTSTATUS Status;
  529. PSECURITY_DESCRIPTOR * ppSD;
  530. PSID pOwnerSid = NULL;
  531. BOOLEAN bOD;
  532. PSID pGroupSid = NULL;
  533. BOOLEAN bGD;
  534. /*
  535. * Ensure value type is REG_BINARY and length of value data
  536. * is at least the length of a minimum security descriptor
  537. * and not unreasonably large.
  538. */
  539. if ( ValueType != REG_BINARY ||
  540. ValueLength < SECURITY_DESCRIPTOR_MIN_LENGTH ||
  541. ValueLength > MAXUSHORT ) {
  542. DBGPRINT(( "TERMSRV: ConfigureConsoleSecurity, ValueType=0x%x\n", ValueType ));
  543. return( STATUS_INVALID_SECURITY_DESCR );
  544. }
  545. if( !IsValidSecurityDescriptor( ValueData )) {
  546. DBGPRINT(( "TERMSRV: ConfigureConsoleSecurity, Invalid Security Descriptor in registry\n"));
  547. return( STATUS_INVALID_SECURITY_DESCR );
  548. }
  549. //
  550. // HACK needed for TS 4.0 security descriptors conversion
  551. //
  552. if (!NT_SUCCESS(RtlGetOwnerSecurityDescriptor( ValueData, &pOwnerSid, &bOD))
  553. || (pOwnerSid == NULL))
  554. {
  555. DBGPRINT(( "TERMSRV: ConfigureConsoleSecurity, Invalid Security Descriptor in registry: Can't get owner\n"));
  556. return( STATUS_INVALID_SECURITY_DESCR );
  557. }
  558. if (!NT_SUCCESS(RtlGetGroupSecurityDescriptor( ValueData, &pGroupSid, &bGD))
  559. ||(pGroupSid == NULL))
  560. {
  561. DBGPRINT(( "TERMSRV: ConfigureConsoleSecurity, Invalid Security Descriptor in registry: Can't get group\n"));
  562. return( STATUS_INVALID_SECURITY_DESCR );
  563. }
  564. /*
  565. * Update the global default security descriptor
  566. */
  567. ppSD = &DefaultConsoleSecurityDescriptor;
  568. //
  569. // Free old one if allocated
  570. //
  571. if (*ppSD != NULL) {
  572. CleanUpSD(*ppSD);
  573. //RtlDeleteSecurityObject( ppSD );
  574. *ppSD = NULL;
  575. }
  576. //
  577. // Regular case:
  578. // Copy the value read in registry
  579. //
  580. // RtlCopySecurityDescriptor only works with self-relative format
  581. RtlCopySecurityDescriptor((PSECURITY_DESCRIPTOR)ValueData, ppSD);
  582. return( STATUS_SUCCESS );
  583. }
  584. /*****************************************************************************
  585. *
  586. * WinStationGetSecurityDescriptor
  587. *
  588. * Return a pointer to the security descriptor that should be enforced
  589. * on this winstation. This could be a specific, or a global
  590. * default security descriptor.
  591. *
  592. * ENTRY: pWinStation the aimed winstation
  593. *
  594. * EXIT: the SD of this winstation,
  595. * or the default SD if this winstation hs no SD (it should not happen !)
  596. *
  597. ****************************************************************************/
  598. PSECURITY_DESCRIPTOR
  599. WinStationGetSecurityDescriptor(
  600. PWINSTATION pWinStation
  601. )
  602. {
  603. PSECURITY_DESCRIPTOR SecurityDescriptor;
  604. SecurityDescriptor = pWinStation->pSecurityDescriptor ?
  605. pWinStation->pSecurityDescriptor :
  606. DefaultWinStationSecurityDescriptor;
  607. return( SecurityDescriptor );
  608. }
  609. /*****************************************************************************
  610. *
  611. * WinStationFreeSecurityDescriptor
  612. *
  613. * Release the winstation security descriptor.
  614. *
  615. * If its the global default, it is not free'd.
  616. *
  617. * ENTRY: the winstation
  618. *
  619. * EXIT: nothing
  620. *
  621. ****************************************************************************/
  622. VOID
  623. WinStationFreeSecurityDescriptor(
  624. PWINSTATION pWinStation
  625. )
  626. {
  627. // console disconnect
  628. if ( pWinStation->pSecurityDescriptor == DefaultWinStationSecurityDescriptor && pWinStation->LogonId != 0) {
  629. pWinStation->pSecurityDescriptor = NULL;
  630. }
  631. // Catch callers mis-managing the security descriptor
  632. ASSERT( pWinStation->pSecurityDescriptor != DefaultWinStationSecurityDescriptor );
  633. if (pWinStation->pSecurityDescriptor) {
  634. //RtlDeleteSecurityObject( &(pWinStation->pSecurityDescriptor) );
  635. CleanUpSD(pWinStation->pSecurityDescriptor);
  636. pWinStation->pSecurityDescriptor = NULL;
  637. }
  638. return;
  639. }
  640. /*****************************************************************************
  641. *
  642. * WinStationInheritSecurityDescriptor
  643. *
  644. * Copy the security descriptor to the target WinStation and set it
  645. * on the kernel object.
  646. *
  647. * ENTRY:
  648. * pSecurityDescriptor (input)
  649. * pointer to SD to be inherited
  650. * pTargetWinStation (input)
  651. * pointer to WinStation to inherit the SD
  652. *
  653. * EXIT:
  654. * STATUS_SUCCESS - no error
  655. *
  656. ****************************************************************************/
  657. NTSTATUS
  658. WinStationInheritSecurityDescriptor(
  659. PVOID pSecurityDescriptor,
  660. PWINSTATION pTargetWinStation
  661. )
  662. {
  663. NTSTATUS Status;
  664. //
  665. // If the listen WinStation has a security descriptor, this means
  666. // that all WinStations of this protocol (TD) type will inherit
  667. // the security descriptor set by WinCfg.
  668. //
  669. if ( pSecurityDescriptor ) {
  670. ASSERT( IsValidSecurityDescriptor( pSecurityDescriptor ) );
  671. if ( pTargetWinStation->pSecurityDescriptor ) {
  672. //RtlDeleteSecurityObject( &(pTargetWinStation->pSecurityDescriptor) );
  673. CleanUpSD(pTargetWinStation->pSecurityDescriptor);
  674. pTargetWinStation->pSecurityDescriptor = NULL;
  675. }
  676. // RtlCopySecurityDescriptor only works with self-relative format
  677. Status = RtlCopySecurityDescriptor(pSecurityDescriptor,
  678. &(pTargetWinStation->pSecurityDescriptor) );
  679. return (Status);
  680. }
  681. //
  682. // If no specific security descriptor on the listen WinStation,
  683. // the default was set on the object when it was created for the pool.
  684. //
  685. return( STATUS_SUCCESS );
  686. }
  687. /*****************************************************************************
  688. *
  689. * RpcCheckClientAccess
  690. *
  691. * Verify whether client has the desired access to a WinStation.
  692. *
  693. * NOTE: This is called under an RPC context.
  694. *
  695. * ENTRY:
  696. * pWinStation (input)
  697. * Pointer to WinStation to query access to
  698. *
  699. * DesiredAccess (input)
  700. * Access mask of desired client access
  701. *
  702. * AlreadyImpersonating (input)
  703. * BOOLEAN that specifies caller is already impersonating client
  704. *
  705. * EXIT:
  706. * STATUS_SUCCESS - no error
  707. *
  708. ****************************************************************************/
  709. NTSTATUS
  710. RpcCheckClientAccess(
  711. PWINSTATION pWinStation,
  712. ACCESS_MASK DesiredAccess,
  713. BOOLEAN AlreadyImpersonating
  714. )
  715. {
  716. NTSTATUS Status;
  717. RPC_STATUS RpcStatus;
  718. BOOL bAccessCheckOk = FALSE;
  719. DWORD GrantedAccess;
  720. BOOL AccessStatus;
  721. BOOL fGenerateOnClose;
  722. /*
  723. * Impersonate the client
  724. */
  725. if ( !AlreadyImpersonating ) {
  726. RpcStatus = RpcImpersonateClient( NULL );
  727. if ( RpcStatus != RPC_S_OK ) {
  728. DBGPRINT(("TERMSRV: CheckClientAccess: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  729. return( STATUS_CANNOT_IMPERSONATE );
  730. }
  731. }
  732. bAccessCheckOk = AccessCheckAndAuditAlarm(szTermsrv,
  733. NULL,
  734. (LPWSTR)szTermsrvSession,
  735. (LPWSTR)szTermsrvSession,
  736. WinStationGetSecurityDescriptor(pWinStation),
  737. DesiredAccess,
  738. &WinStaMapping,
  739. FALSE,
  740. &GrantedAccess,
  741. &AccessStatus,
  742. &fGenerateOnClose);
  743. if ( !AlreadyImpersonating ) {
  744. RpcRevertToSelf();
  745. }
  746. if (bAccessCheckOk)
  747. {
  748. if (AccessStatus == FALSE)
  749. {
  750. Status = NtCurrentTeb()->LastStatusValue;
  751. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: RpcCheckClientAccess, AccessCheckAndAuditAlarm(%u) returned error 0x%x\n",
  752. pWinStation->LogonId, Status ));
  753. }
  754. else
  755. {
  756. TRACE((hTrace,TC_ICASRV,TT_API3, "TERMSRV: RpcCheckClientAccess, AccessCheckAndAuditAlarm(%u) returned no error \n",
  757. pWinStation->LogonId));
  758. Status = STATUS_SUCCESS;
  759. }
  760. }
  761. else
  762. {
  763. Status = NtCurrentTeb()->LastStatusValue;
  764. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: RpcCheckClientAccess, AccessCheckAndAuditAlarm(%u) failed 0x%x\n",
  765. pWinStation->LogonId, Status ));
  766. }
  767. return (Status);
  768. }
  769. /*****************************************************************************
  770. *
  771. * _CheckConnectAccess
  772. *
  773. * Check for connect access to the WINSTATION.
  774. *
  775. * This is called under RPC context.
  776. *
  777. * ENTRY:
  778. * Param1 (input/output)
  779. * Comments
  780. *
  781. * EXIT:
  782. * STATUS_SUCCESS - no error
  783. *
  784. ****************************************************************************/
  785. _CheckConnectAccess(
  786. PWINSTATION pSourceWinStation,
  787. PSID pClientSid,
  788. ULONG ClientLogonId,
  789. PWCHAR pPassword,
  790. DWORD PasswordSize
  791. )
  792. {
  793. NTSTATUS Status;
  794. BOOLEAN fWrongPassword;
  795. UNICODE_STRING PasswordString;
  796. /*
  797. * First check that the current RPC caller has WINSTATION_CONNECT access
  798. * to the target WINSTATIONS object. This is controlled by either the
  799. * default, or per WINSTATION ACL setup from the registry.
  800. */
  801. Status = RpcCheckClientAccess( pSourceWinStation, WINSTATION_CONNECT, FALSE );
  802. if ( !NT_SUCCESS( Status ) ) {
  803. /*
  804. * clear the password parameter to prevent it being paged cleartext
  805. */
  806. RtlZeroMemory( pPassword, wcslen(pPassword) * sizeof(WCHAR) );
  807. return( Status );
  808. }
  809. //
  810. // C2 WARNING - WARNING - WARNING
  811. //
  812. // Comments by JohnR 01/21/97 - The design of this feature was redone.
  813. //
  814. // There was legacy code which has WinLogon store the users password
  815. // scrambled in the PWINSTATION structure for all users to support
  816. // the feature in which a user logged on as account User1 may type the
  817. // "connect <winstation>" command, in which the disconnected winstation
  818. // logged in as account User2 may be connected to, if the proper account
  819. // password is supplied from the command line. The password verification
  820. // was a simple string compare between the winstations stored password,
  821. // and the password supplied by the caller.
  822. //
  823. // The problems with this are many:
  824. //
  825. // - LSA should do all authentication. The password may have
  826. // been changed, or the account disabled. Also all authentication
  827. // code must be in a centralized location.
  828. //
  829. // - The Logon Hours may have expired on the account. Another violation
  830. // of policy.
  831. //
  832. // - No auditing is performed on failure, in violation of
  833. // security policy.
  834. //
  835. // - The users password, though scrambled, is passed around the
  836. // system in code not explicitly designed to handle user authentication.
  837. // This code is not known, or registered with LSA as an authentication
  838. // provider. Network redirectors, WinLogon, etc. do this registration.
  839. //
  840. //
  841. // FIX that was be done:
  842. //
  843. // The users password is no longer set in the PWINSTATION
  844. // by WinLogon. When a user wants to do a "connect <winstation>",
  845. // the account name and password of the winstation to connect to
  846. // is passed to LSA as a normal authentication. This means that
  847. // ICASRV.EXE is properly registered as a logon provider. If the
  848. // account and password is valid, a token is returned. This token
  849. // can then be closed, and the user connected to the winstation.
  850. // If failure, return the access denied error. The benefits are:
  851. //
  852. // - LSA authentication
  853. // - ICASRV registration as a logon provider
  854. // - Auditing
  855. // - Password change, account disable handling
  856. // - Logon hours enforcement
  857. // - Password no longer passed around the system
  858. //
  859. //
  860. // C2 WARNING
  861. //
  862. // Even with this routine using LSA, the WinFrame connect.exe command
  863. // could be trojan horsed. It is not in the trusted path. At least it is
  864. // a system utility that users should not allow writing to. Though a user
  865. // has to watch their %PATH%. A better design would be for the connect
  866. // commands function to be part of the WinLogon's GINA screen like our
  867. // current Disconnect... option. This will keep the password gathering
  868. // in the trusted path. But this is no worse than "net.exe", WinFile, etc.,
  869. // or anything else that asks for a network resource password.
  870. //
  871. // C2 WARNING - WARNING - WARNING
  872. //
  873. /*
  874. * If different username/domain check the password by calling LogonUser()
  875. */
  876. // SALIMC CHANGE
  877. if ( pSourceWinStation->pUserSid && !RtlEqualSid( pClientSid, pSourceWinStation->pUserSid ) &&
  878. !RtlEqualSid( pClientSid, gSystemSid ) ) {
  879. HANDLE hToken;
  880. BOOL Result;
  881. Result = LogonUser(
  882. pSourceWinStation->UserName,
  883. pSourceWinStation->Domain,
  884. pPassword,
  885. LOGON32_LOGON_INTERACTIVE, // Logon Type
  886. LOGON32_PROVIDER_DEFAULT, // Logon Provider
  887. &hToken // Token that represents the account
  888. );
  889. /*
  890. * clear the password parameter to prevent it being paged cleartext
  891. */
  892. RtlZeroMemory( pPassword, wcslen(pPassword) * sizeof(WCHAR) );
  893. /*
  894. * check for account restriction which indicates a blank password
  895. * on the account that is correct though - allow this thru on console
  896. */
  897. if( !Result && (PasswordSize == sizeof(WCHAR)) && (GetLastError() == ERROR_ACCOUNT_RESTRICTION) && (USER_SHARED_DATA->ActiveConsoleId == ClientLogonId)) {
  898. return( STATUS_SUCCESS );
  899. }
  900. if( !Result) {
  901. DBGPRINT(("TERMSRV: _CheckConnectAccess: User Account %ws\\%ws not valid %d\n",pSourceWinStation->Domain,pSourceWinStation->UserName,GetLastError()));
  902. return( STATUS_LOGON_FAILURE );
  903. }
  904. /*
  905. * Close the token handle since we only needed to determine
  906. * if the account and password is still valid.
  907. */
  908. CloseHandle( hToken );
  909. return( STATUS_SUCCESS );
  910. }
  911. else {
  912. return( STATUS_SUCCESS );
  913. }
  914. // NOTREACHED
  915. }
  916. /*****************************************************************************
  917. *
  918. * RpcCheckSystemClient
  919. *
  920. * Inquire in the current RPC call context whether we were
  921. * called by a local SYSTEM mode caller.
  922. *
  923. * WinStation API's that are only to be called by the WinLogon
  924. * process call this function.
  925. *
  926. * ENTRY:
  927. * Param1 (input/output)
  928. * Comments
  929. *
  930. * EXIT:
  931. * STATUS_SUCCESS - no error
  932. *
  933. ****************************************************************************/
  934. NTSTATUS
  935. RpcCheckSystemClient(
  936. ULONG TargetLogonId
  937. )
  938. {
  939. NTSTATUS Status;
  940. PWINSTATION pWinStation;
  941. pWinStation = FindWinStationById( TargetLogonId, FALSE );
  942. if ( pWinStation == NULL ) {
  943. return( STATUS_CTX_WINSTATION_NOT_FOUND );
  944. }
  945. Status = RpcCheckSystemClientEx( pWinStation );
  946. ReleaseWinStation( pWinStation );
  947. return( Status );
  948. }
  949. /*****************************************************************************
  950. *
  951. * RpcCheckSystemClientEx
  952. *
  953. * Inquire in the current RPC call context whether we were
  954. * called by a local SYSTEM mode caller.
  955. *
  956. * WinStation API's that are only to be called by the WinLogon
  957. * process call this function.
  958. *
  959. * ENTRY:
  960. * Param1 (input/output)
  961. * Comments
  962. *
  963. * EXIT:
  964. * STATUS_SUCCESS - no error
  965. *
  966. ****************************************************************************/
  967. NTSTATUS
  968. RpcCheckSystemClientEx(
  969. PWINSTATION pWinStation
  970. )
  971. {
  972. ULONG ClientLogonId;
  973. RPC_STATUS RpcStatus;
  974. NTSTATUS Status = STATUS_SUCCESS;
  975. Status = RpcCheckSystemClientNoLogonId( pWinStation );
  976. if( !NT_SUCCESS(Status) ) {
  977. return( Status);
  978. }
  979. /*
  980. * Impersonate the client
  981. */
  982. RpcStatus = RpcImpersonateClient( NULL );
  983. if( RpcStatus != RPC_S_OK ) {
  984. TRACE0(("TERMSRV: RpcCheckSystemClient: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  985. return( STATUS_CANNOT_IMPERSONATE );
  986. }
  987. /*
  988. * Check that the LogonId of the client is the same
  989. * as the LogonId of the WINSTATION being targeted.
  990. */
  991. Status = RpcGetClientLogonId( &ClientLogonId );
  992. if( !NT_SUCCESS(Status) ) {
  993. TRACE0(("TERMSRV: RpcCheckSystemClient: Could not get clients LogonId 0x%x\n",Status));
  994. RpcRevertToSelf();
  995. return( STATUS_ACCESS_DENIED );
  996. }
  997. if( ClientLogonId != pWinStation->LogonId ) {
  998. TRACE0(("TERMSRV: RpcCheckSystemClient: Caller LogonId %d does not match target %d\n",ClientLogonId,pWinStation->LogonId));
  999. RpcRevertToSelf();
  1000. return( STATUS_ACCESS_DENIED );
  1001. }
  1002. RpcRevertToSelf();
  1003. return( STATUS_SUCCESS );
  1004. }
  1005. /*****************************************************************************
  1006. *
  1007. * RpcCheckSystemClientNoLogonId
  1008. *
  1009. * Inquire in the current RPC call context whether we were
  1010. * called by a local SYSTEM mode caller.
  1011. *
  1012. * WinStation API's that are only to be called by the WinLogon
  1013. * process call this function.
  1014. *
  1015. * ENTRY:
  1016. * Param1 (input/output)
  1017. * Comments
  1018. *
  1019. * EXIT:
  1020. * STATUS_SUCCESS - no error
  1021. *
  1022. ****************************************************************************/
  1023. NTSTATUS
  1024. RpcCheckSystemClientNoLogonId(
  1025. PWINSTATION pWinStation
  1026. )
  1027. {
  1028. UINT LocalFlag;
  1029. RPC_STATUS RpcStatus;
  1030. RPC_AUTHZ_HANDLE Privs;
  1031. PWCHAR pServerPrincName;
  1032. ULONG AuthnLevel, AuthnSvc, AuthzSvc;
  1033. NTSTATUS Status = STATUS_SUCCESS;
  1034. /*
  1035. * The following checking is to keep from screwing up
  1036. * the state due to attempts to invoke this local
  1037. * only API remotely, across LogonId's, or from an application.
  1038. */
  1039. /*
  1040. * Impersonate the client
  1041. */
  1042. RpcStatus = RpcImpersonateClient( NULL );
  1043. if( RpcStatus != RPC_S_OK ) {
  1044. TRACE0(("TERMSRV: RpcCheckSystemClient: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  1045. return( STATUS_CANNOT_IMPERSONATE );
  1046. }
  1047. /*
  1048. * Inquire if local RPC call
  1049. */
  1050. RpcStatus = I_RpcBindingIsClientLocal(
  1051. 0, // Active RPC call we are servicing
  1052. &LocalFlag
  1053. );
  1054. if( RpcStatus != RPC_S_OK ) {
  1055. TRACE0(("TERMSRV: RpcCheckSystemClient: Could not query local client RpcStatus 0x%x\n",RpcStatus));
  1056. RpcRevertToSelf();
  1057. return( STATUS_ACCESS_DENIED );
  1058. }
  1059. if( !LocalFlag ) {
  1060. TRACE0(("TERMSRV: RpcCheckSystemClient: Not a local client call\n"));
  1061. RpcRevertToSelf();
  1062. return( STATUS_ACCESS_DENIED );
  1063. }
  1064. #ifdef notdef
  1065. // This is not working in 4.0. Its not returning
  1066. // the principle name on the LPC transport.
  1067. // So we resort to looking into the thread token.
  1068. /*
  1069. * Get the principle name, and see if its the built in LSA
  1070. * local account "SYSTEM".
  1071. */
  1072. RpcStatus = RpcBindingInqAuthClientW(
  1073. 0, // Active RPC call we are servicing
  1074. &Privs,
  1075. &pServerPrincName,
  1076. &AuthnLevel,
  1077. &AuthnSvc,
  1078. &AuthzSvc
  1079. );
  1080. if( RpcStatus != RPC_S_OK ) {
  1081. DBGPRINT(("TERMSRV: RpcCheckSystemClient RpcAuthorizaton query failed! RpcStatus 0x%x\n",RpcStatus));
  1082. RpcRevertToSelf();
  1083. return( STATUS_ACCESS_DENIED );
  1084. }
  1085. TRACE0(("TERMSRV: AuthnLevel %d, AuthnSvc %d, AuthzSvc %d pServerPrincName 0x%x, Privs 0x%x\n",AuthnLevel,AuthnSvc,AuthzSvc,pServerPrincName,Privs));
  1086. if( AuthnSvc != RPC_C_AUTHN_WINNT ) {
  1087. DBGPRINT(("TERMSRV: RpcCheckSystemClient RpcAuthorizaton Type not NT! 0x%x\n",AuthnSvc));
  1088. RpcRevertToSelf();
  1089. Status = STATUS_ACCESS_DENIED;
  1090. }
  1091. if( pServerPrincName ) {
  1092. TRACE0(("TERMSRV: RpcCheckSystemClient: Principle Name :%ws:\n",pServerPrincName));
  1093. // Compare with "SYSTEM"
  1094. if( wcsicmp( L"SYSTEM", pServerPrincName ) ) {
  1095. DBGPRINT(("TERMSRV: RpcCheckSystemClient: Principle Name :%ws: not SYSTEM\n",pServerPrincName));
  1096. Status = STATUS_ACCESS_DENIED;
  1097. }
  1098. RpcStringFreeW( &pServerPrincName );
  1099. }
  1100. #else
  1101. /*
  1102. * Validate that the thread token is SYSTEM
  1103. */
  1104. if( !IsCallerSystem() ) {
  1105. Status = STATUS_ACCESS_DENIED;
  1106. }
  1107. #endif
  1108. RpcRevertToSelf();
  1109. return( Status );
  1110. }
  1111. /*****************************************************************************
  1112. *
  1113. * RpcCheckClientAccessLocal
  1114. *
  1115. * Inquire in the current RPC call context whether we were
  1116. * called by a local caller.
  1117. *
  1118. * ENTRY:
  1119. * Param1 (input/output)
  1120. * Comments
  1121. *
  1122. * EXIT:
  1123. * STATUS_SUCCESS - no error
  1124. *
  1125. ****************************************************************************/
  1126. NTSTATUS
  1127. RpcCheckClientAccessLocal(
  1128. PWINSTATION pWinStation,
  1129. ACCESS_MASK DesiredAccess,
  1130. BOOLEAN AlreadyImpersonating
  1131. )
  1132. {
  1133. UINT LocalFlag;
  1134. RPC_STATUS RpcStatus;
  1135. RPC_AUTHZ_HANDLE Privs;
  1136. PWCHAR pServerPrincName;
  1137. ULONG AuthnLevel, AuthnSvc, AuthzSvc;
  1138. NTSTATUS Status;
  1139. /*
  1140. * Impersonate the client, if not already
  1141. */
  1142. if ( !AlreadyImpersonating ) {
  1143. RpcStatus = RpcImpersonateClient( NULL );
  1144. if ( RpcStatus != RPC_S_OK ) {
  1145. DBGPRINT(("TERMSRV: RpcCheckClientAccessLocal: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  1146. return( STATUS_CANNOT_IMPERSONATE );
  1147. }
  1148. }
  1149. /*
  1150. * Check for desired access. This will generate an access audit if on.
  1151. */
  1152. Status = RpcCheckClientAccess( pWinStation, DesiredAccess, TRUE );
  1153. if ( !NT_SUCCESS( Status ) ) {
  1154. if ( !AlreadyImpersonating ) {
  1155. RpcRevertToSelf();
  1156. }
  1157. return( Status );
  1158. }
  1159. /*
  1160. * We have now checked security on the WINSTATION, the
  1161. * rest of the checking is to keep from screwing up
  1162. * the state due to attempts to invoke this local
  1163. * only API remotely.
  1164. */
  1165. /*
  1166. * Inquire if local RPC call
  1167. */
  1168. RpcStatus = I_RpcBindingIsClientLocal(
  1169. 0, // Active RPC call we are servicing
  1170. &LocalFlag
  1171. );
  1172. if ( !AlreadyImpersonating ) {
  1173. RpcRevertToSelf();
  1174. }
  1175. if ( RpcStatus != RPC_S_OK ) {
  1176. DBGPRINT(("TERMSRV: RpcCheckClientAccessLocal: Could not query local client RpcStatus 0x%x\n",RpcStatus));
  1177. return( STATUS_ACCESS_DENIED );
  1178. }
  1179. if ( !LocalFlag ) {
  1180. DBGPRINT(("TERMSRV: RpcCheckClientAccessLocal: Not a local client call\n"));
  1181. return( STATUS_ACCESS_DENIED );
  1182. }
  1183. return( STATUS_SUCCESS );
  1184. }
  1185. /*******************************************************************************
  1186. *
  1187. * AddUserAce
  1188. *
  1189. * Add an ACE for the currently logged on user to the WinStation object.
  1190. *
  1191. * ENTRY:
  1192. * pWinStation (input)
  1193. * Pointer to WinStation to update
  1194. *
  1195. * EXIT:
  1196. * nothing
  1197. *
  1198. ******************************************************************************/
  1199. NTSTATUS
  1200. AddUserAce( PWINSTATION pWinStation )
  1201. {
  1202. PACL Dacl = NULL;
  1203. BOOLEAN DaclPresent, DaclDefaulted;
  1204. ACL_SIZE_INFORMATION AclInfo;
  1205. ULONG Length;
  1206. NTSTATUS Status;
  1207. /*
  1208. * Get a pointer to the DACL from the security descriptor.
  1209. */
  1210. Status = RtlGetDaclSecurityDescriptor( pWinStation->pSecurityDescriptor, &DaclPresent,
  1211. &Dacl, &DaclDefaulted );
  1212. if ( !NT_SUCCESS( Status ) || !DaclPresent || !Dacl ) {
  1213. return( Status );
  1214. }
  1215. Status = RtlAddAccessAllowedAce( Dacl, ACL_REVISION,
  1216. (WINSTATION_ALL_ACCESS) & ~(STANDARD_RIGHTS_ALL),
  1217. pWinStation->pUserSid );
  1218. if ( (Status == STATUS_ALLOTTED_SPACE_EXCEEDED) || (Status == STATUS_REVISION_MISMATCH) )
  1219. {
  1220. //
  1221. // We need to copy the security data into a new descriptor
  1222. //
  1223. Status = RtlQueryInformationAcl( Dacl, &AclInfo, sizeof(AclInfo),
  1224. AclSizeInformation );
  1225. if ( NT_SUCCESS( Status ) )
  1226. {
  1227. ULONG AceCount;
  1228. PRTL_ACE_DATA pAceData;
  1229. PACE_HEADER pAce;
  1230. ULONG i;
  1231. PSECURITY_DESCRIPTOR pSD;
  1232. PSID Owner, Group;
  1233. PSID * pSidList;
  1234. BOOLEAN OwnerDefaulted, GroupDefaulted;
  1235. AceCount = AclInfo.AceCount;
  1236. AceCount++;
  1237. //
  1238. // allocate a RTL_ACE_DATA structure and a list of pPSIDs
  1239. //
  1240. Length = AceCount * sizeof(RTL_ACE_DATA);
  1241. pAceData = MemAlloc(Length);
  1242. if (!pAceData)
  1243. {
  1244. return (STATUS_NO_MEMORY);
  1245. }
  1246. Length = AceCount * sizeof(PSID *);
  1247. pSidList = MemAlloc(Length);
  1248. if (!pSidList)
  1249. {
  1250. MemFree(pAceData);
  1251. return (STATUS_NO_MEMORY);
  1252. }
  1253. for ( i = 0; i < AclInfo.AceCount; i++ )
  1254. {
  1255. Status = RtlGetAce( Dacl, i, &pAce );
  1256. ASSERT( NT_SUCCESS( Status ) );
  1257. if (!NT_SUCCESS( Status ))
  1258. {
  1259. MemFree(pAceData);
  1260. MemFree(pSidList);
  1261. return STATUS_INVALID_SECURITY_DESCR;
  1262. }
  1263. pAceData[i].AceType = pAce->AceType;
  1264. pAceData[i].InheritFlags = 0;
  1265. pAceData[i].AceFlags = 0;
  1266. switch (pAce->AceType)
  1267. {
  1268. case ACCESS_ALLOWED_ACE_TYPE:
  1269. pAceData[i].Mask = ((PACCESS_ALLOWED_ACE)pAce)->Mask;
  1270. pSidList[i] = (PSID)(&(((PACCESS_ALLOWED_ACE)pAce)->SidStart));
  1271. break;
  1272. case ACCESS_DENIED_ACE_TYPE:
  1273. pAceData[i].Mask = ((PACCESS_DENIED_ACE)pAce)->Mask;
  1274. pSidList[i] = (PSID)(&(((PACCESS_DENIED_ACE)pAce)->SidStart));
  1275. pAceData[i].Sid = (PSID *)(&(pSidList[i]));
  1276. break;
  1277. default: // we do not expect anything else
  1278. MemFree(pAceData);
  1279. MemFree(pSidList);
  1280. return STATUS_INVALID_SECURITY_DESCR;
  1281. }
  1282. pAceData[i].Sid = (PSID *)(&(pSidList[i]));
  1283. }
  1284. //
  1285. // add the new ACE
  1286. //
  1287. pAceData[i].AceType = ACCESS_ALLOWED_ACE_TYPE;
  1288. pAceData[i].InheritFlags = 0;
  1289. pAceData[i].AceFlags = 0;
  1290. pAceData[i].Mask = (WINSTATION_ALL_ACCESS) & ~(STANDARD_RIGHTS_ALL);
  1291. pAceData[i].Sid = &(pWinStation->pUserSid);
  1292. //
  1293. // get the owner and the group
  1294. //
  1295. Status = RtlGetOwnerSecurityDescriptor(pWinStation->pSecurityDescriptor,
  1296. &Owner,
  1297. &OwnerDefaulted);
  1298. Status = RtlGetOwnerSecurityDescriptor(pWinStation->pSecurityDescriptor,
  1299. &Group,
  1300. &GroupDefaulted);
  1301. //
  1302. // save the old security descriptor
  1303. //
  1304. pSD = pWinStation->pSecurityDescriptor;
  1305. //
  1306. // create the new security descriptor
  1307. //
  1308. Status = RtlCreateUserSecurityObject(pAceData,
  1309. AceCount,
  1310. Owner,
  1311. Group,
  1312. FALSE,
  1313. &WinStaMapping,
  1314. &(pWinStation->pSecurityDescriptor) );
  1315. //
  1316. // delete the old security descriptor
  1317. //
  1318. //RtlDeleteSecurityObject( &pSD );
  1319. // must break up into absolute format and self-relative
  1320. if (pSD) {
  1321. CleanUpSD(pSD);
  1322. }
  1323. //
  1324. // free the RTL_ACE_DATA
  1325. //
  1326. MemFree(pAceData);
  1327. MemFree(pSidList);
  1328. }
  1329. }
  1330. return( Status );
  1331. }
  1332. /*******************************************************************************
  1333. *
  1334. * RemoveUserAce
  1335. *
  1336. * Remove the ACE for the currently logged on user from the WinStation object.
  1337. *
  1338. * ENTRY:
  1339. * pWinStation (input)
  1340. * Pointer to WinStation to update
  1341. *
  1342. * EXIT:
  1343. * nothing
  1344. *
  1345. ******************************************************************************/
  1346. NTSTATUS
  1347. RemoveUserAce( PWINSTATION pWinStation )
  1348. {
  1349. SECURITY_INFORMATION SecInfo = DACL_SECURITY_INFORMATION;
  1350. PACL Dacl;
  1351. BOOLEAN DaclPresent, DaclDefaulted;
  1352. ACL_SIZE_INFORMATION AclInfo;
  1353. PACE_HEADER Ace;
  1354. ULONG i, Length;
  1355. NTSTATUS Status;
  1356. /*
  1357. * This is probably the console if ICASRV wasn't started soon enough
  1358. *
  1359. */
  1360. if ( !pWinStation->pUserSid ) {
  1361. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  1362. }
  1363. else
  1364. {
  1365. Status = RtlGetDaclSecurityDescriptor( pWinStation->pSecurityDescriptor, &DaclPresent,
  1366. &Dacl, &DaclDefaulted );
  1367. if ( !NT_SUCCESS( Status ) || !DaclPresent || !Dacl ) {
  1368. return( Status );
  1369. }
  1370. Status = RtlQueryInformationAcl( Dacl, &AclInfo, sizeof(AclInfo),
  1371. AclSizeInformation );
  1372. if ( !NT_SUCCESS( Status ) ) {
  1373. return( Status );
  1374. }
  1375. /*
  1376. * Scan the DACL looking for the ACE that contains the UserSid (it should
  1377. * be first), delete the ACE, and set the new security for the WinStation.
  1378. */
  1379. for ( i = 0; i < AclInfo.AceCount; i++ ) {
  1380. RtlGetAce( Dacl, i, &Ace );
  1381. if ( RtlEqualSid( pWinStation->pUserSid,
  1382. &((PACCESS_ALLOWED_ACE)Ace)->SidStart ) ) {
  1383. RtlDeleteAce( Dacl, i );
  1384. break;
  1385. }
  1386. }
  1387. }
  1388. return( Status );
  1389. }
  1390. /*******************************************************************************
  1391. *
  1392. * ApplyWinStaMappingToSD
  1393. *
  1394. * Apply the generic mapping on the security descriptor.
  1395. *
  1396. * ENTRY:
  1397. * pSecurityDescriptor
  1398. * Pointer to security descriptor to update
  1399. *
  1400. * EXIT:
  1401. * nothing
  1402. *
  1403. ******************************************************************************/
  1404. NTSTATUS
  1405. ApplyWinStaMappingToSD( PSECURITY_DESCRIPTOR pSecurityDescriptor )
  1406. {
  1407. PACL Dacl;
  1408. BOOLEAN DaclPresent, DaclDefaulted;
  1409. ACL_SIZE_INFORMATION AclInfo;
  1410. PACE_HEADER Ace;
  1411. ULONG i;
  1412. NTSTATUS Status;
  1413. Status = RtlGetDaclSecurityDescriptor( pSecurityDescriptor, &DaclPresent,
  1414. &Dacl, &DaclDefaulted );
  1415. if ( !NT_SUCCESS( Status ) || !DaclPresent || !Dacl ) {
  1416. return( Status );
  1417. }
  1418. Status = RtlQueryInformationAcl( Dacl, &AclInfo, sizeof(AclInfo),
  1419. AclSizeInformation );
  1420. if ( !NT_SUCCESS( Status ) ) {
  1421. return( Status );
  1422. }
  1423. /*
  1424. * Scan the DACL applying the generic mapping to each ACE
  1425. */
  1426. for ( i = 0; i < AclInfo.AceCount; i++ ) {
  1427. RtlGetAce( Dacl, i, &Ace );
  1428. RtlApplyAceToObject( Ace, &WinStaMapping );
  1429. }
  1430. return( Status );
  1431. }
  1432. /*******************************************************************************
  1433. *
  1434. * ApplyWinStaMapping
  1435. *
  1436. * Apply the generic mapping on the security descriptor of the WinStation object.
  1437. *
  1438. * ENTRY:
  1439. * pWinStation (input)
  1440. * Pointer to WinStation to update
  1441. *
  1442. * EXIT:
  1443. * nothing
  1444. *
  1445. ******************************************************************************/
  1446. NTSTATUS
  1447. ApplyWinStaMapping( PWINSTATION pWinStation )
  1448. {
  1449. return (ApplyWinStaMappingToSD(pWinStation->pSecurityDescriptor));
  1450. }
  1451. /*****************************************************************************
  1452. *
  1453. * BuildEveryOneAllowSD
  1454. *
  1455. * Build and return an EveryOne (WORLD) allow Security descriptor.
  1456. *
  1457. * ENTRY:
  1458. * Param1 (input/output)
  1459. * Comments
  1460. *
  1461. * EXIT:
  1462. * STATUS_SUCCESS - no error
  1463. *
  1464. ****************************************************************************/
  1465. PSECURITY_DESCRIPTOR
  1466. BuildEveryOneAllowSD()
  1467. {
  1468. BOOL rc;
  1469. DWORD Error;
  1470. DWORD AclSize;
  1471. PACL pAcl = NULL;
  1472. PACCESS_ALLOWED_ACE pAce = NULL;
  1473. PSECURITY_DESCRIPTOR pSd = NULL;
  1474. PSID SeWorldSid = NULL;
  1475. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1476. pSd = LocalAlloc(LMEM_FIXED, sizeof(SECURITY_DESCRIPTOR) );
  1477. if( pSd == NULL ) {
  1478. return( NULL );
  1479. }
  1480. rc = InitializeSecurityDescriptor( pSd, SECURITY_DESCRIPTOR_REVISION );
  1481. if( !rc ) {
  1482. TRACE((hTrace,TC_ICASRV,TT_ERROR,"Error initing security descriptor %d\n",GetLastError()));
  1483. LocalFree( pSd );
  1484. return( NULL );
  1485. }
  1486. SeWorldSid = (PSID)LocalAlloc(LMEM_FIXED, RtlLengthRequiredSid(1) );
  1487. if( SeWorldSid == NULL ) {
  1488. LocalFree( pSd );
  1489. return( NULL );
  1490. }
  1491. RtlInitializeSid( SeWorldSid, &WorldSidAuthority, 1 );
  1492. *(RtlSubAuthoritySid( SeWorldSid, 0 )) = SECURITY_WORLD_RID;
  1493. /*
  1494. * Calculate the ACL size
  1495. */
  1496. AclSize = sizeof(ACL);
  1497. AclSize += sizeof(ACCESS_ALLOWED_ACE);
  1498. AclSize += (GetLengthSid( SeWorldSid ) - sizeof(DWORD));
  1499. pAcl = LocalAlloc( LMEM_FIXED, AclSize );
  1500. if( pAcl == NULL ) {
  1501. TRACE((hTrace,TC_ICASRV,TT_ERROR,"Could not allocate memory\n"));
  1502. LocalFree( SeWorldSid );
  1503. LocalFree( pSd );
  1504. return( NULL );
  1505. }
  1506. rc = InitializeAcl(
  1507. pAcl,
  1508. AclSize,
  1509. ACL_REVISION
  1510. );
  1511. if( !rc ) {
  1512. TRACE((hTrace,TC_ICASRV,TT_ERROR,"Error %d InitializeAcl\n",GetLastError()));
  1513. LocalFree( pAcl );
  1514. LocalFree( SeWorldSid );
  1515. LocalFree( pSd );
  1516. return( NULL );
  1517. }
  1518. /*
  1519. * Add the access allowed ACE
  1520. */
  1521. rc = AddAccessAllowedAce(
  1522. pAcl,
  1523. ACL_REVISION,
  1524. FILE_ALL_ACCESS,
  1525. SeWorldSid
  1526. );
  1527. if( !rc ) {
  1528. Error = GetLastError();
  1529. TRACE((hTrace,TC_ICASRV,TT_ERROR,"***ERROR*** adding allow ACE %d for SeWorldSid\n",Error));
  1530. LocalFree( pAcl );
  1531. LocalFree( SeWorldSid );
  1532. LocalFree( pSd );
  1533. return( NULL );
  1534. }
  1535. rc = SetSecurityDescriptorDacl(
  1536. pSd,
  1537. TRUE,
  1538. pAcl,
  1539. FALSE
  1540. );
  1541. if( !rc ) {
  1542. TRACE((hTrace,TC_ICASRV,TT_ERROR,"Error %d SetSecurityDescriptorDacl\n",GetLastError()));
  1543. LocalFree( pAcl );
  1544. LocalFree( SeWorldSid );
  1545. LocalFree( pSd );
  1546. return( NULL );
  1547. }
  1548. // These are contained in the SD
  1549. // LocalFree( pAcl );
  1550. // LocalFree( SeWorldSid );
  1551. // Caller can free SD
  1552. return( pSd );
  1553. }
  1554. /*****************************************************************************
  1555. *
  1556. * CreateWinStationDefaultSecurityDescriptor
  1557. *
  1558. * Create the default security descriptor for WinStation for
  1559. * when we do not find one in the registry.
  1560. *
  1561. * ENTRY: nothing
  1562. *
  1563. * EXIT: a self-relative SD, or NULL
  1564. *
  1565. ****************************************************************************/
  1566. PSECURITY_DESCRIPTOR
  1567. CreateWinStationDefaultSecurityDescriptor()
  1568. {
  1569. PSECURITY_DESCRIPTOR SecurityDescriptor;
  1570. #define DEFAULT_ACE_COUNT 2
  1571. RTL_ACE_DATA AceData[DEFAULT_ACE_COUNT] =
  1572. {
  1573. { ACCESS_ALLOWED_ACE_TYPE, 0, 0, WINSTATION_ALL_ACCESS, &gSystemSid },
  1574. { ACCESS_ALLOWED_ACE_TYPE, 0, 0, WINSTATION_ALL_ACCESS, &gAdminSid }
  1575. };
  1576. SecurityDescriptor = NULL;
  1577. RtlCreateUserSecurityObject(AceData, DEFAULT_ACE_COUNT, gSystemSid,
  1578. gSystemSid, FALSE, &WinStaMapping, &SecurityDescriptor);
  1579. return( SecurityDescriptor );
  1580. }
  1581. /*****************************************************************************
  1582. *
  1583. * BuildSystemOnlySecurityDescriptor
  1584. *
  1585. * Create a security descriptor for system access only.
  1586. *
  1587. * ENTRY:
  1588. * Param1 (input/output)
  1589. * Comments
  1590. *
  1591. * EXIT:
  1592. * STATUS_SUCCESS - no error
  1593. *
  1594. ****************************************************************************/
  1595. PSECURITY_DESCRIPTOR
  1596. BuildSystemOnlySecurityDescriptor()
  1597. {
  1598. PACL Dacl;
  1599. ULONG Length;
  1600. NTSTATUS Status;
  1601. PSECURITY_DESCRIPTOR SecurityDescriptor;
  1602. SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY;
  1603. Length = SECURITY_DESCRIPTOR_MIN_LENGTH +
  1604. (ULONG)sizeof(ACL) +
  1605. (ULONG)sizeof(ACCESS_ALLOWED_ACE) +
  1606. RtlLengthSid( gSystemSid );
  1607. SecurityDescriptor = MemAlloc(Length);
  1608. if (SecurityDescriptor == NULL) {
  1609. goto bsosderror;
  1610. }
  1611. Dacl = (PACL)((PCHAR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
  1612. Status = RtlCreateSecurityDescriptor(SecurityDescriptor,
  1613. SECURITY_DESCRIPTOR_REVISION);
  1614. if (Status != STATUS_SUCCESS) {
  1615. goto bsosderror;
  1616. }
  1617. Status = RtlCreateAcl( Dacl, Length - SECURITY_DESCRIPTOR_MIN_LENGTH,
  1618. ACL_REVISION2);
  1619. if (Status != STATUS_SUCCESS) {
  1620. goto bsosderror;
  1621. }
  1622. Status = RtlAddAccessAllowedAce (
  1623. Dacl,
  1624. ACL_REVISION2,
  1625. PORT_ALL_ACCESS,
  1626. gSystemSid
  1627. );
  1628. if (Status != STATUS_SUCCESS) {
  1629. goto bsosderror;
  1630. }
  1631. Status = RtlSetDaclSecurityDescriptor (
  1632. SecurityDescriptor,
  1633. TRUE,
  1634. Dacl,
  1635. FALSE
  1636. );
  1637. if (Status != STATUS_SUCCESS) {
  1638. goto bsosderror;
  1639. }
  1640. return( SecurityDescriptor );
  1641. bsosderror:
  1642. if (SecurityDescriptor) {
  1643. MemFree(SecurityDescriptor);
  1644. }
  1645. return(NULL);
  1646. }
  1647. /*****************************************************************************
  1648. *
  1649. * RpcGetClientLogonId
  1650. *
  1651. * Get the logonid from the client who we should be impersonating.
  1652. *
  1653. * ENTRY:
  1654. *
  1655. * EXIT:
  1656. * STATUS_SUCCESS - no error
  1657. *
  1658. ****************************************************************************/
  1659. NTSTATUS
  1660. RpcGetClientLogonId(
  1661. PULONG pLogonId
  1662. )
  1663. {
  1664. BOOL Result;
  1665. HANDLE TokenHandle;
  1666. ULONG LogonId, ReturnLength;
  1667. NTSTATUS Status = STATUS_SUCCESS;
  1668. //
  1669. // We should be impersonating the client, so we will get the
  1670. // LogonId from out token.
  1671. //
  1672. Result = OpenThreadToken(
  1673. GetCurrentThread(),
  1674. TOKEN_QUERY,
  1675. FALSE, // Use impersonation
  1676. &TokenHandle
  1677. );
  1678. if( Result ) {
  1679. //
  1680. // Use the CITRIX extension to GetTokenInformation to
  1681. // return the LogonId from the token.
  1682. //
  1683. // This identifies which WinStation is making this request.
  1684. //
  1685. Result = GetTokenInformation(
  1686. TokenHandle,
  1687. (TOKEN_INFORMATION_CLASS)TokenSessionId,
  1688. &LogonId,
  1689. sizeof(LogonId),
  1690. &ReturnLength
  1691. );
  1692. if( Result ) {
  1693. #if DBG
  1694. if( ReturnLength != sizeof(LogonId) ) {
  1695. DbgPrint("TERMSRV: RpcGetClientLogonId GetTokenInformation: ReturnLength %d != sizeof(LogonId)\n", ReturnLength );
  1696. }
  1697. #endif
  1698. *pLogonId = LogonId;
  1699. }
  1700. else {
  1701. DBGPRINT(("TERMSRV: Error getting token LogonId information %d\n", GetLastError()));
  1702. Status = STATUS_NO_IMPERSONATION_TOKEN;
  1703. }
  1704. CloseHandle( TokenHandle );
  1705. }
  1706. else {
  1707. TRACE0(("SYSLIB: Error opening token %d\n", GetLastError()));
  1708. Status = STATUS_NO_IMPERSONATION_TOKEN;
  1709. }
  1710. return( Status );
  1711. }
  1712. /*****************************************************************************
  1713. *
  1714. * IsServiceLoggedAsSystem
  1715. *
  1716. * Returns whether the termsrv process is running under SYSTEM
  1717. * security.
  1718. *
  1719. * ENTRY:
  1720. * None
  1721. * Comments
  1722. *
  1723. * EXIT:
  1724. * TRUE if running under system account. FALSE otherwise
  1725. *
  1726. ****************************************************************************/
  1727. BOOL
  1728. IsServiceLoggedAsSystem( VOID )
  1729. {
  1730. BOOL Result;
  1731. HANDLE TokenHandle;
  1732. //
  1733. // Open the process token and check if System token.
  1734. //
  1735. Result = OpenProcessToken(
  1736. GetCurrentProcess(),
  1737. TOKEN_QUERY,
  1738. &TokenHandle
  1739. );
  1740. if (!Result) {
  1741. DBGPRINT(("TERMSRV: IsServiceLoggedAsSystem : Could not open process token %d\n",GetLastError()));
  1742. return( FALSE );
  1743. }
  1744. Result = IsSystemToken(TokenHandle);
  1745. return Result;
  1746. }
  1747. /*****************************************************************************
  1748. *
  1749. * IsCallerSystem
  1750. *
  1751. * Returns whether the current thread is running under SYSTEM
  1752. * security.
  1753. *
  1754. * ENTRY:
  1755. * Param1 (input/output)
  1756. * Comments
  1757. *
  1758. * EXIT:
  1759. * STATUS_SUCCESS - no error
  1760. *
  1761. ****************************************************************************/
  1762. BOOL
  1763. IsCallerSystem( VOID )
  1764. {
  1765. BOOL Result;
  1766. HANDLE TokenHandle;
  1767. //
  1768. // Open the thread token and check if System token.
  1769. //
  1770. Result = OpenThreadToken(
  1771. GetCurrentThread(),
  1772. TOKEN_QUERY,
  1773. FALSE, // Use impersonation
  1774. &TokenHandle
  1775. );
  1776. if( !Result ) {
  1777. TRACE0(("TERMSRV: IsCallerSystem: Could not open thread token %d\n",GetLastError()));
  1778. return( FALSE );
  1779. }
  1780. Result = IsSystemToken(TokenHandle);
  1781. return Result;
  1782. }
  1783. /*****************************************************************************
  1784. *
  1785. * IsSystemToken
  1786. *
  1787. * Returns whether the current token is running under SYSTEM
  1788. * security.
  1789. *
  1790. * ENTRY:
  1791. * Param1 Thread or process token
  1792. * Comments
  1793. *
  1794. * EXIT:
  1795. * TRUE if System token. FALSE otherwise.
  1796. *
  1797. ****************************************************************************/
  1798. BOOL
  1799. IsSystemToken( HANDLE TokenHandle )
  1800. {
  1801. BOOL Result;
  1802. ULONG ReturnLength, BufferLength;
  1803. NTSTATUS Status;
  1804. PTOKEN_USER pTokenUser = NULL;
  1805. //Get primary account SID from token and test if local system SID.
  1806. if (gSystemSid == NULL) {
  1807. return FALSE;
  1808. }
  1809. ReturnLength = 0;
  1810. Result = GetTokenInformation(
  1811. TokenHandle,
  1812. TokenUser,
  1813. NULL,
  1814. 0,
  1815. &ReturnLength
  1816. );
  1817. if( ReturnLength == 0 ) {
  1818. TRACE0(("TERMSRV: IsCallerSystem: Error %d Getting TokenInformation\n",GetLastError()));
  1819. CloseHandle( TokenHandle );
  1820. return( FALSE );
  1821. }
  1822. BufferLength = ReturnLength;
  1823. pTokenUser = MemAlloc( BufferLength );
  1824. if( pTokenUser == NULL ) {
  1825. TRACE0(("TERMSRV: IsCallerSystem: Error allocating %d bytes memory\n",BufferLength));
  1826. CloseHandle( TokenHandle );
  1827. return( FALSE );
  1828. }
  1829. Result = GetTokenInformation(
  1830. TokenHandle,
  1831. TokenUser,
  1832. pTokenUser,
  1833. BufferLength,
  1834. &ReturnLength
  1835. );
  1836. CloseHandle( TokenHandle );
  1837. if( !Result ) {
  1838. TRACE0(("TERMSRV: IsCallerSystem: Error %d Getting TokenInformation on buffer\n",GetLastError()));
  1839. MemFree( pTokenUser );
  1840. return( FALSE );
  1841. }
  1842. if( RtlEqualSid( pTokenUser->User.Sid, gSystemSid) ) {
  1843. MemFree( pTokenUser );
  1844. return( TRUE );
  1845. }
  1846. else {
  1847. #if DBGTRACE
  1848. BOOL OK;
  1849. DWORD cDomain;
  1850. DWORD cUserName;
  1851. WCHAR Domain[256];
  1852. WCHAR UserName[256];
  1853. SID_NAME_USE UserSidType;
  1854. cUserName = sizeof(UserName)/sizeof(WCHAR);
  1855. cDomain = sizeof(Domain)/sizeof(WCHAR);
  1856. // Now print its account
  1857. OK = LookupAccountSidW(
  1858. NULL, // Computer Name
  1859. pTokenUser->User.Sid,
  1860. UserName,
  1861. &cUserName,
  1862. Domain,
  1863. &cDomain,
  1864. &UserSidType
  1865. );
  1866. DBGPRINT(("TERMSRV: IsCallerSystem: Caller SID is not SYSTEM\n"));
  1867. if( OK ) {
  1868. DBGPRINT(("TERMSRV: IsCallerSystem: CallerAccount Name %ws, Domain %ws, Type %d, SidSize %d\n",UserName,Domain,UserSidType));
  1869. }
  1870. else {
  1871. extern void CtxDumpSid( PSID, PCHAR, PULONG ); // syslib:dumpsd.c
  1872. DBGPRINT(("TERMSRV: Could not lookup callers account Error %d\n",GetLastError()));
  1873. CtxDumpSid( pTokenUser->User.Sid, NULL, NULL );
  1874. }
  1875. #else
  1876. TRACE0(("TERMSRV: IsCallerSystem: Caller SID is not SYSTEM\n"));
  1877. #endif
  1878. MemFree( pTokenUser );
  1879. return( FALSE );
  1880. }
  1881. // NOTREACHED
  1882. }
  1883. /*****************************************************************************
  1884. *
  1885. * IsCallerAdmin
  1886. *
  1887. * Returns whether the current thread is running under SYSTEM
  1888. * security.
  1889. *
  1890. * ENTRY:
  1891. * Param1 (input/output)
  1892. * Comments
  1893. *
  1894. * EXIT:
  1895. * STATUS_SUCCESS - no error
  1896. *
  1897. ****************************************************************************/
  1898. BOOL
  1899. IsCallerAdmin( VOID )
  1900. {
  1901. BOOL FoundAdmin;
  1902. NTSTATUS Status;
  1903. //
  1904. // If the admin sid didn't initialize, the service would not have started.
  1905. //
  1906. ASSERT(gAdminSid != NULL);
  1907. if (!CheckTokenMembership(NULL, gAdminSid, &FoundAdmin)) {
  1908. FoundAdmin = FALSE;
  1909. }
  1910. #if DBG
  1911. if (!FoundAdmin)
  1912. {
  1913. DBGPRINT(("TERMSRV: IsCallerAdmin: Caller SID is not ADMINISTRATOR\n"));
  1914. }
  1915. #endif
  1916. return(FoundAdmin);
  1917. }
  1918. /*******************************************************************************
  1919. *
  1920. * IsCallerAllowedPasswordAccess
  1921. *
  1922. * Is the calling process allowed to view the password field?
  1923. *
  1924. * The caller must be SYSTEM context, IE: WinLogon.
  1925. *
  1926. * ENTRY:
  1927. *
  1928. * EXIT:
  1929. * nothing
  1930. *
  1931. ******************************************************************************/
  1932. BOOLEAN
  1933. IsCallerAllowedPasswordAccess()
  1934. {
  1935. UINT LocalFlag;
  1936. RPC_STATUS RpcStatus;
  1937. //
  1938. // Only a SYSTEM mode caller (IE: Winlogon) is allowed
  1939. // to query this value.
  1940. //
  1941. RpcStatus = RpcImpersonateClient( NULL );
  1942. if( RpcStatus != RPC_S_OK ) {
  1943. return( FALSE );
  1944. }
  1945. //
  1946. // Inquire if local RPC call
  1947. //
  1948. RpcStatus = I_RpcBindingIsClientLocal(
  1949. 0, // Active RPC call we are servicing
  1950. &LocalFlag
  1951. );
  1952. if( RpcStatus != RPC_S_OK ) {
  1953. RpcRevertToSelf();
  1954. return( FALSE );
  1955. }
  1956. if( !LocalFlag ) {
  1957. RpcRevertToSelf();
  1958. return( FALSE );
  1959. }
  1960. if( !IsCallerSystem() ) {
  1961. RpcRevertToSelf();
  1962. return( FALSE );
  1963. }
  1964. RpcRevertToSelf();
  1965. return( TRUE );
  1966. }
  1967. BOOL
  1968. ConfigurePerSessionSecurity(
  1969. PWINSTATION pWinStation
  1970. )
  1971. /*++
  1972. Routine Description:
  1973. Configure security for the new session. This sets the
  1974. per session \Sessions\<x>\BasedNamedObjects and
  1975. \Sessions\<x>\DosDevices with an ACE that allows the
  1976. currently logged on user to be able to create objects
  1977. in their sessions directories.
  1978. This is called by WinStationNotifyLogon() after the user
  1979. has been authenticated. This must be called before the
  1980. newly logged on user can create any WIN32 objects
  1981. (events, semaphores, etc.), or DosDevices.
  1982. Arguments:
  1983. Arg - desc
  1984. Return Value:
  1985. NTSTATUS - STATUS_SUCCESS no error
  1986. !STATUS_SUCCESS NT Status code
  1987. --*/
  1988. {
  1989. BOOL Result;
  1990. BOOL bRet = TRUE;
  1991. DWORD Len;
  1992. PWCHAR pBuf;
  1993. WCHAR IdBuf[MAX_PATH];
  1994. static ProtectionMode = 0;
  1995. static GotProtectionMode = FALSE;
  1996. PSID CreatorOwnerSid;
  1997. PSID LocalSystemSid;
  1998. SID_IDENTIFIER_AUTHORITY CreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  1999. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  2000. #define SESSIONS_ROOT L"\\Sessions\\"
  2001. #define BNO_PATH L"\\BaseNamedObjects"
  2002. #define DD_PATH L"\\DosDevices"
  2003. //
  2004. // We leave the consoles default NT permissions
  2005. // alone.
  2006. //
  2007. if( pWinStation->LogonId == 0 ) {
  2008. return TRUE;
  2009. }
  2010. // Get the Protection mode from Session Manager\ProtectionMode
  2011. if( !GotProtectionMode ) {
  2012. HANDLE KeyHandle;
  2013. NTSTATUS Status;
  2014. ULONG ResultLength;
  2015. WCHAR ValueBuffer[ 32 ];
  2016. UNICODE_STRING NameString;
  2017. OBJECT_ATTRIBUTES ObjectAttributes;
  2018. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
  2019. GotProtectionMode = TRUE;
  2020. RtlInitUnicodeString( &NameString, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
  2021. InitializeObjectAttributes(
  2022. &ObjectAttributes,
  2023. &NameString,
  2024. OBJ_CASE_INSENSITIVE,
  2025. NULL,
  2026. NULL
  2027. );
  2028. Status = NtOpenKey(
  2029. &KeyHandle,
  2030. KEY_READ,
  2031. &ObjectAttributes
  2032. );
  2033. if (NT_SUCCESS(Status)) {
  2034. RtlInitUnicodeString( &NameString, L"ProtectionMode" );
  2035. KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  2036. Status = NtQueryValueKey(
  2037. KeyHandle,
  2038. &NameString,
  2039. KeyValuePartialInformation,
  2040. KeyValueInformation,
  2041. sizeof( ValueBuffer ),
  2042. &ResultLength
  2043. );
  2044. if (NT_SUCCESS(Status)) {
  2045. if (KeyValueInformation->Type == REG_DWORD &&
  2046. *(PULONG)KeyValueInformation->Data) {
  2047. ProtectionMode = *(PULONG)KeyValueInformation->Data;
  2048. }
  2049. }
  2050. NtClose( KeyHandle );
  2051. }
  2052. }
  2053. // Nothing locked down
  2054. if( (ProtectionMode & 0x00000003) == 0 ) {
  2055. return TRUE;
  2056. }
  2057. wsprintf( IdBuf, L"%d", pWinStation->LogonId );
  2058. Len = wcslen( IdBuf ) + wcslen( SESSIONS_ROOT ) + wcslen( BNO_PATH ) + 2;
  2059. pBuf = LocalAlloc( LMEM_FIXED, Len*sizeof(WCHAR) );
  2060. if( pBuf == NULL ) {
  2061. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2062. return FALSE;
  2063. }
  2064. wsprintf( pBuf, L"%s%s%s", SESSIONS_ROOT, IdBuf, BNO_PATH );
  2065. Result = AddAccessToDirectory(
  2066. pBuf,
  2067. GENERIC_ALL,
  2068. pWinStation->pUserSid
  2069. );
  2070. if( !Result ) bRet = FALSE;
  2071. if (NT_SUCCESS(RtlAllocateAndInitializeSid(
  2072. &CreatorAuthority,
  2073. 1,
  2074. SECURITY_CREATOR_OWNER_RID,
  2075. 0, 0, 0, 0, 0, 0, 0,
  2076. &CreatorOwnerSid
  2077. ))) {
  2078. Result = AddAccessToDirectory(
  2079. pBuf,
  2080. GENERIC_ALL,
  2081. CreatorOwnerSid
  2082. );
  2083. if( !Result ) {
  2084. bRet = FALSE;
  2085. }
  2086. RtlFreeSid( CreatorOwnerSid );
  2087. }
  2088. if (NT_SUCCESS(RtlAllocateAndInitializeSid(
  2089. &NtAuthority,
  2090. 1,
  2091. SECURITY_LOCAL_SYSTEM_RID,
  2092. 0, 0, 0, 0, 0, 0, 0,
  2093. &LocalSystemSid
  2094. ))) {
  2095. Result = AddAccessToDirectory(
  2096. pBuf,
  2097. GENERIC_ALL,
  2098. LocalSystemSid
  2099. );
  2100. if( !Result ) {
  2101. bRet = FALSE;
  2102. }
  2103. RtlFreeSid( LocalSystemSid );
  2104. }
  2105. LocalFree( pBuf );
  2106. Len = wcslen( IdBuf ) + wcslen( SESSIONS_ROOT ) + wcslen( DD_PATH ) + 2;
  2107. pBuf = LocalAlloc( LMEM_FIXED, Len*sizeof(WCHAR) );
  2108. if( pBuf == NULL ) {
  2109. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2110. return FALSE;
  2111. }
  2112. wsprintf( pBuf, L"%s%s%s", SESSIONS_ROOT, IdBuf, DD_PATH );
  2113. Result = AddAccessToDirectory(
  2114. pBuf,
  2115. GENERIC_READ | GENERIC_EXECUTE,
  2116. pWinStation->pUserSid
  2117. );
  2118. if( !Result ) bRet = FALSE;
  2119. LocalFree( pBuf );
  2120. return bRet;
  2121. }
  2122. BOOL
  2123. AddAccessToDirectory(
  2124. PWCHAR pPath,
  2125. DWORD NewAccess,
  2126. PSID pSid
  2127. )
  2128. /*++
  2129. Routine Description:
  2130. Add Access to the given NT object directory path for
  2131. the supplied SID.
  2132. This is done by adding a new AccessAllowedAce to
  2133. the DACL on the object directory.
  2134. Arguments:
  2135. Arg - desc
  2136. Return Value:
  2137. TRUE - Success
  2138. FALSE - Error in GetLastError()
  2139. --*/
  2140. {
  2141. BOOL Result;
  2142. HANDLE hDir;
  2143. NTSTATUS Status;
  2144. ULONG LengthNeeded;
  2145. OBJECT_ATTRIBUTES Obja;
  2146. PSECURITY_DESCRIPTOR pSd,pSelfSD;
  2147. PACL pDacl;
  2148. UNICODE_STRING UnicodeString;
  2149. RtlInitUnicodeString( &UnicodeString, pPath );
  2150. InitializeObjectAttributes(
  2151. &Obja,
  2152. &UnicodeString,
  2153. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  2154. NULL,
  2155. NULL // Sd
  2156. );
  2157. Status = NtCreateDirectoryObject(
  2158. &hDir,
  2159. DIRECTORY_ALL_ACCESS,
  2160. &Obja
  2161. );
  2162. if( !NT_SUCCESS(Status) ) {
  2163. DBGPRINT(("AddAccessToDirectory: NtCreateDirectoryObject 0x%x :%ws:\n",Status,pPath));
  2164. SetLastError(RtlNtStatusToDosError(Status));
  2165. return FALSE;
  2166. }
  2167. // Get SD from sessions directory
  2168. Status = NtQuerySecurityObject(
  2169. hDir,
  2170. OWNER_SECURITY_INFORMATION |
  2171. GROUP_SECURITY_INFORMATION |
  2172. DACL_SECURITY_INFORMATION,
  2173. NULL, // pSd
  2174. 0, // Length
  2175. &LengthNeeded
  2176. );
  2177. // ? bad handle
  2178. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  2179. DBGPRINT(("AddAccessToDirectory: NtQuerySecurityObject 0x%x :%ws:\n",Status,pPath));
  2180. SetLastError(RtlNtStatusToDosError(Status));
  2181. NtClose( hDir );
  2182. return FALSE;
  2183. }
  2184. pSd = LocalAlloc(LMEM_FIXED, LengthNeeded );
  2185. if( pSd == NULL ) {
  2186. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2187. NtClose( hDir );
  2188. return FALSE;
  2189. }
  2190. Status = NtQuerySecurityObject(
  2191. hDir,
  2192. OWNER_SECURITY_INFORMATION |
  2193. GROUP_SECURITY_INFORMATION |
  2194. DACL_SECURITY_INFORMATION,
  2195. pSd,
  2196. LengthNeeded,
  2197. &LengthNeeded
  2198. );
  2199. if( !NT_SUCCESS(Status) ) {
  2200. DBGPRINT(("AddAccessToDirectory: NtQuerySecurityObject 0x%x :%ws:\n",Status,pPath));
  2201. SetLastError(RtlNtStatusToDosError(Status));
  2202. LocalFree( pSd );
  2203. NtClose( hDir );
  2204. return FALSE;
  2205. }
  2206. Result = AddAceToSecurityDescriptor(
  2207. &pSd,
  2208. &pDacl,
  2209. NewAccess,
  2210. pSid,
  2211. TRUE
  2212. );
  2213. if( !Result ) {
  2214. DBGPRINT(("AddAccessToDirectory: AddAceToSecurityDescriptor failure :%ws:\n",pPath));
  2215. CleanUpSD(pSd);
  2216. NtClose( hDir );
  2217. return FALSE;
  2218. }
  2219. Result = AddAceToSecurityDescriptor(
  2220. &pSd,
  2221. &pDacl,
  2222. NewAccess,
  2223. pSid,
  2224. FALSE
  2225. );
  2226. if( !Result ) {
  2227. DBGPRINT(("AddAccessToDirectory: AddAceToSecurityDescriptor failure :%ws:\n",pPath));
  2228. CleanUpSD(pSd);
  2229. NtClose( hDir );
  2230. return FALSE;
  2231. }
  2232. Result = FALSE;
  2233. // make sure that pSd is not self-relative already
  2234. if (!(((PISECURITY_DESCRIPTOR)pSd)->Control & SE_SELF_RELATIVE)) {
  2235. Result = AbsoluteToSelfRelativeSD (pSd, &pSelfSD, NULL);
  2236. CleanUpSD(pSd);
  2237. if ( !Result ) {
  2238. NtClose( hDir);
  2239. return FALSE;
  2240. }
  2241. }
  2242. // Put a self-relative SD on session directory (note only self-relative sd are allowed)
  2243. Status = NtSetSecurityObject(
  2244. hDir,
  2245. DACL_SECURITY_INFORMATION,
  2246. pSelfSD
  2247. );
  2248. if( !NT_SUCCESS(Status) ) {
  2249. DBGPRINT(("AddAccessToDirectory: NtSetSecurityObject 0x%x :%ws:\n",Status,pPath));
  2250. SetLastError(RtlNtStatusToDosError(Status));
  2251. CleanUpSD(pSelfSD);
  2252. NtClose( hDir );
  2253. return FALSE;
  2254. }
  2255. // Result could only be false if the sd is already self-relative
  2256. if (Result) {
  2257. CleanUpSD(pSelfSD);
  2258. }
  2259. // Now update any objects in the directory already
  2260. Status = AddAccessToDirectoryObjects(
  2261. hDir,
  2262. NewAccess,
  2263. pSid
  2264. );
  2265. NtClose( hDir );
  2266. // AddAccessToDirectoryObjects() may return out of memory.
  2267. if ( !NT_SUCCESS( Status ) )
  2268. {
  2269. return FALSE;
  2270. }
  2271. return TRUE;
  2272. }
  2273. BOOL
  2274. AddAceToSecurityDescriptor(
  2275. PSECURITY_DESCRIPTOR *ppSd,
  2276. PACL *ppDacl,
  2277. DWORD Access,
  2278. PSID pSid,
  2279. BOOLEAN InheritOnly
  2280. )
  2281. /*++
  2282. Routine Description:
  2283. Adds the given ACE/SID to the security descriptor. It will
  2284. re-allocate the security descriptor if more room is needed.
  2285. Arguments:
  2286. ppSD - Pointer to PSECURITY_DESCRIPTOR
  2287. ppDacl - Pointer to PACL, returns the newly created DACL for freeing
  2288. after the security has been set.
  2289. Access - Access mask for ACE
  2290. pSid - Pointer to Sid this ACE is representing
  2291. Return Value:
  2292. TRUE - Success
  2293. FALSE - Error
  2294. --*/
  2295. {
  2296. ULONG i;
  2297. BOOL Result;
  2298. BOOL DaclPresent;
  2299. BOOL DaclDefaulted;
  2300. DWORD Length;
  2301. DWORD NewAceLength, NewAclLength;
  2302. PACE_HEADER OldAce;
  2303. PACE_HEADER NewAce;
  2304. ACL_SIZE_INFORMATION AclInfo;
  2305. PACL Dacl = NULL;
  2306. PACL NewDacl = NULL;
  2307. PACL NewAceDacl = NULL;
  2308. PSECURITY_DESCRIPTOR NewSD = NULL;
  2309. PSECURITY_DESCRIPTOR OldSD = NULL;
  2310. BOOL SDAllocated = FALSE;
  2311. OldSD = *ppSd;
  2312. *ppDacl = NULL;
  2313. /*
  2314. * Convert SecurityDescriptor to absolute format. It generates
  2315. * a new SecurityDescriptor for its output which we must free.
  2316. */
  2317. if (((PISECURITY_DESCRIPTOR)OldSD)->Control & SE_SELF_RELATIVE) {
  2318. Result = SelfRelativeToAbsoluteSD( OldSD, &NewSD, NULL );
  2319. if ( !Result ) {
  2320. DBGPRINT(("Could not convert to AbsoluteSD %d\n",GetLastError()));
  2321. return( FALSE );
  2322. }
  2323. SDAllocated = TRUE;
  2324. } else {
  2325. NewSD = OldSD;
  2326. }
  2327. // Must get DACL pointer again from new (absolute) SD
  2328. Result = GetSecurityDescriptorDacl(
  2329. NewSD,
  2330. &DaclPresent,
  2331. &Dacl,
  2332. &DaclDefaulted
  2333. );
  2334. if( !Result ) {
  2335. DBGPRINT(("Could not get Dacl %d\n",GetLastError()));
  2336. goto ErrorCleanup;
  2337. }
  2338. //
  2339. // If no DACL, no need to add the user since no DACL
  2340. // means all accesss
  2341. //
  2342. if( !DaclPresent ) {
  2343. DBGPRINT(("SD has no DACL, Present %d, Defaulted %d\n",DaclPresent,DaclDefaulted));
  2344. if (SDAllocated && NewSD) {
  2345. CleanUpSD(NewSD);
  2346. }
  2347. return( TRUE );
  2348. }
  2349. //
  2350. // Code can return DaclPresent, but a NULL which means
  2351. // a NULL Dacl is present. This allows no access to the object.
  2352. //
  2353. if( Dacl == NULL ) {
  2354. DBGPRINT(("SD has NULL DACL, Present %d, Defaulted %d\n",DaclPresent,DaclDefaulted));
  2355. goto ErrorCleanup;
  2356. }
  2357. // Get the current ACL's size
  2358. Result = GetAclInformation(
  2359. Dacl,
  2360. &AclInfo,
  2361. sizeof(AclInfo),
  2362. AclSizeInformation
  2363. );
  2364. if( !Result ) {
  2365. DBGPRINT(("Error GetAclInformation %d\n",GetLastError()));
  2366. goto ErrorCleanup;
  2367. }
  2368. //
  2369. // Create a new ACL to put the new access allowed ACE on
  2370. // to get the right structures and sizes.
  2371. //
  2372. NewAclLength = sizeof(ACL) +
  2373. sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) +
  2374. GetLengthSid( pSid );
  2375. NewAceDacl = LocalAlloc( LMEM_FIXED, NewAclLength );
  2376. if ( NewAceDacl == NULL ) {
  2377. DBGPRINT(("Error LocalAlloc %d bytes\n",NewAclLength));
  2378. goto ErrorCleanup;
  2379. }
  2380. Result = InitializeAcl( NewAceDacl, NewAclLength, ACL_REVISION );
  2381. if( !Result ) {
  2382. DBGPRINT(("Error Initializing Acl %d\n",GetLastError()));
  2383. goto ErrorCleanup;
  2384. }
  2385. Result = AddAccessAllowedAce(
  2386. NewAceDacl,
  2387. ACL_REVISION,
  2388. Access,
  2389. pSid
  2390. );
  2391. if( !Result ) {
  2392. DBGPRINT(("Error adding Ace %d\n",GetLastError()));
  2393. goto ErrorCleanup;
  2394. }
  2395. TRACE0(("Added 0x%x Access to ACL\n",Access));
  2396. Result = GetAce( NewAceDacl, 0, &NewAce );
  2397. if( !Result ) {
  2398. DBGPRINT(("Error getting Ace %d\n",GetLastError()));
  2399. goto ErrorCleanup;
  2400. }
  2401. /*
  2402. * Allocate new DACL and copy existing ACE list
  2403. */
  2404. Length = AclInfo.AclBytesInUse + NewAce->AceSize;
  2405. NewDacl = LocalAlloc( LMEM_FIXED, Length );
  2406. if( NewDacl == NULL ) {
  2407. DBGPRINT(("Error LocalAlloc %d bytes\n",Length));
  2408. goto ErrorCleanup;
  2409. }
  2410. Result = InitializeAcl( NewDacl, Length, ACL_REVISION );
  2411. if( !Result ) {
  2412. DBGPRINT(("Error Initializing Acl %d\n",GetLastError()));
  2413. goto ErrorCleanup;
  2414. }
  2415. if (InheritOnly) {
  2416. /*
  2417. * Make this an inherit ACE
  2418. */
  2419. NewAce->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE);
  2420. }
  2421. /*
  2422. * Insert new ACE at the front of the DACL
  2423. */
  2424. Result = AddAce( NewDacl, ACL_REVISION, 0, NewAce, NewAce->AceSize );
  2425. if( !Result ) {
  2426. DBGPRINT(("Error Adding New Ace to Acl %d\n",GetLastError()));
  2427. goto ErrorCleanup;
  2428. }
  2429. /*
  2430. * Now put the ACE's on the old Dacl to the new Dacl
  2431. */
  2432. for ( i = 0; i < AclInfo.AceCount; i++ ) {
  2433. Result = GetAce( Dacl, i, &OldAce );
  2434. if( !Result ) {
  2435. DBGPRINT(("Error getting old Ace from Acl %d\n",GetLastError()));
  2436. goto ErrorCleanup;
  2437. }
  2438. Result = AddAce( NewDacl, ACL_REVISION, i+1, OldAce, OldAce->AceSize );
  2439. if( !Result ) {
  2440. DBGPRINT(("Error setting old Ace to Acl %d\n",GetLastError()));
  2441. goto ErrorCleanup;
  2442. }
  2443. }
  2444. /*
  2445. * Set new DACL for Security Descriptor
  2446. */
  2447. Result = SetSecurityDescriptorDacl(
  2448. NewSD,
  2449. TRUE,
  2450. NewDacl,
  2451. FALSE
  2452. );
  2453. if( !Result ) {
  2454. DBGPRINT(("Error setting New Dacl to SD %d\n",GetLastError()));
  2455. goto ErrorCleanup;
  2456. }
  2457. // NewSD is in absolute format and it's dacl is being replaced by NewDacl
  2458. // thus it makes perfect sense to delete the old dacl
  2459. if (Dacl) {
  2460. LocalFree( Dacl );
  2461. }
  2462. // If we allocated the SD, release the callers old security descriptor,
  2463. // otherwise, release the old SDs DACL.
  2464. if (SDAllocated) {
  2465. CleanUpSD(OldSD);
  2466. }
  2467. // Release the template Ace Dacl
  2468. LocalFree( NewAceDacl );
  2469. *ppSd = NewSD;
  2470. *ppDacl = NewDacl;
  2471. return( TRUE );
  2472. ErrorCleanup:
  2473. if (NewDacl) {
  2474. LocalFree( NewDacl );
  2475. }
  2476. if (NewAceDacl) {
  2477. LocalFree( NewAceDacl );
  2478. }
  2479. if (SDAllocated && NewSD) {
  2480. CleanUpSD( NewSD );
  2481. }
  2482. // If the SD wasn't allocated, and we got far enough to get a valid
  2483. // DACL, free the DACL.
  2484. if (Dacl) {
  2485. LocalFree( Dacl );
  2486. }
  2487. return( FALSE );
  2488. }
  2489. BOOL
  2490. AbsoluteToSelfRelativeSD(
  2491. PSECURITY_DESCRIPTOR SecurityDescriptorIn,
  2492. PSECURITY_DESCRIPTOR *SecurityDescriptorOut,
  2493. PULONG ReturnedLength
  2494. )
  2495. /*++
  2496. Routine Description:
  2497. Make a security descriptor self-relative
  2498. Return Value:
  2499. TRUE - Success
  2500. FALSE - Failure
  2501. --*/
  2502. {
  2503. BOOL Result;
  2504. PSECURITY_DESCRIPTOR pSD;
  2505. DWORD dwLength = 0;
  2506. /*
  2507. * Determine buffer size needed to convert absolute to self-relative SD .
  2508. * We use try-except here since if the input security descriptor value
  2509. * is sufficiently messed up, it is possible for this call to trap.
  2510. */
  2511. try {
  2512. Result = MakeSelfRelativeSD(
  2513. SecurityDescriptorIn,
  2514. NULL,
  2515. &dwLength);
  2516. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2517. SetLastError( ERROR_INVALID_SECURITY_DESCR );
  2518. Result = FALSE;
  2519. }
  2520. if ( Result || (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ) {
  2521. DBGPRINT(("SUSERVER: AbsoluteToSelfRelativeSD, Error %d\n",GetLastError()));
  2522. return( FALSE );
  2523. }
  2524. /*
  2525. * Allocate memory for the self-relative SD
  2526. */
  2527. pSD = LocalAlloc( LMEM_FIXED, dwLength );
  2528. if ( pSD == NULL )
  2529. return( FALSE );
  2530. /*
  2531. * Now convert absolute SD to self-relative format.
  2532. * We use try-except here since if the input security descriptor value
  2533. * is sufficiently messed up, it is possible for this call to trap.
  2534. */
  2535. try {
  2536. Result = MakeSelfRelativeSD(SecurityDescriptorIn,
  2537. pSD,
  2538. &dwLength);
  2539. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2540. SetLastError( ERROR_INVALID_SECURITY_DESCR );
  2541. Result = FALSE;
  2542. }
  2543. if ( !Result ) {
  2544. DBGPRINT(("SUSERVER: SelfRelativeToAbsoluteSD, Error %d\n",GetLastError()));
  2545. LocalFree( pSD );
  2546. return( FALSE );
  2547. }
  2548. *SecurityDescriptorOut = pSD;
  2549. if ( ReturnedLength )
  2550. *ReturnedLength = dwLength;
  2551. return( TRUE );
  2552. }
  2553. BOOL
  2554. SelfRelativeToAbsoluteSD(
  2555. PSECURITY_DESCRIPTOR SecurityDescriptorIn,
  2556. PSECURITY_DESCRIPTOR *SecurityDescriptorOut,
  2557. PULONG ReturnedLength
  2558. )
  2559. /*++
  2560. Routine Description:
  2561. Make a security descriptor absolute
  2562. Arguments:
  2563. Arg - desc
  2564. Return Value:
  2565. TRUE - Success
  2566. FALSE - Failure
  2567. --*/
  2568. {
  2569. BOOL Result;
  2570. PACL pDacl, pSacl;
  2571. PSID pOwner, pGroup;
  2572. PSECURITY_DESCRIPTOR pSD;
  2573. ULONG SdSize, DaclSize, SaclSize, OwnerSize, GroupSize;
  2574. /*
  2575. * Determine buffer size needed to convert self-relative SD to absolute.
  2576. * We use try-except here since if the input security descriptor value
  2577. * is sufficiently messed up, it is possible for this call to trap.
  2578. */
  2579. try {
  2580. SdSize = DaclSize = SaclSize = OwnerSize = GroupSize = 0;
  2581. Result = MakeAbsoluteSD(
  2582. SecurityDescriptorIn,
  2583. NULL, &SdSize,
  2584. NULL, &DaclSize,
  2585. NULL, &SaclSize,
  2586. NULL, &OwnerSize,
  2587. NULL, &GroupSize
  2588. );
  2589. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2590. SetLastError( ERROR_INVALID_SECURITY_DESCR );
  2591. Result = FALSE;
  2592. }
  2593. if ( Result || (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ) {
  2594. DBGPRINT(("SUSERVER: SelfRelativeToAbsoluteSD, Error %d\n",GetLastError()));
  2595. return( FALSE );
  2596. }
  2597. /*
  2598. * Allocate memory for the absolute SD and setup various pointers
  2599. */
  2600. pSD = NULL;
  2601. pDacl = NULL;
  2602. pSacl = NULL;
  2603. pOwner = NULL;
  2604. pGroup = NULL;
  2605. if (SdSize>0) {
  2606. pSD = LocalAlloc( LMEM_FIXED, SdSize);
  2607. if ( pSD == NULL )
  2608. goto error;
  2609. }
  2610. if (DaclSize>0) {
  2611. pDacl = LocalAlloc( LMEM_FIXED, DaclSize);
  2612. if ( pDacl == NULL ){
  2613. goto error;
  2614. }
  2615. }
  2616. if (SaclSize>0) {
  2617. pSacl = LocalAlloc( LMEM_FIXED, SaclSize);
  2618. if ( pSacl == NULL ){
  2619. goto error;
  2620. }
  2621. }
  2622. if (OwnerSize>0) {
  2623. pOwner = LocalAlloc( LMEM_FIXED, OwnerSize);
  2624. if ( pOwner == NULL ){
  2625. goto error;
  2626. }
  2627. }
  2628. if (GroupSize>0) {
  2629. pGroup = LocalAlloc( LMEM_FIXED, GroupSize);
  2630. if ( pGroup == NULL ){
  2631. goto error;
  2632. }
  2633. }
  2634. //pDacl = (PACL)((PCHAR)pSD + SdSize);
  2635. ///pSacl = (PACL)((PCHAR)pDacl + DaclSize);
  2636. //pOwner = (PSID)((PCHAR)pSacl + SaclSize);
  2637. //pGroup = (PSID)((PCHAR)pOwner + OwnerSize);
  2638. /*
  2639. * Now convert self-relative SD to absolute format.
  2640. * We use try-except here since if the input security descriptor value
  2641. * is sufficiently messed up, it is possible for this call to trap.
  2642. */
  2643. try {
  2644. Result = MakeAbsoluteSD(
  2645. SecurityDescriptorIn,
  2646. pSD, &SdSize,
  2647. pDacl, &DaclSize,
  2648. pSacl, &SaclSize,
  2649. pOwner, &OwnerSize,
  2650. pGroup, &GroupSize
  2651. );
  2652. } except( EXCEPTION_EXECUTE_HANDLER ) {
  2653. SetLastError( ERROR_INVALID_SECURITY_DESCR );
  2654. Result = FALSE;
  2655. }
  2656. if ( !Result ) {
  2657. DBGPRINT(("SUSERVER: SelfRelativeToAbsoluteSD, Error %d\n",GetLastError()));
  2658. goto error;
  2659. }
  2660. *SecurityDescriptorOut = pSD;
  2661. if ( ReturnedLength )
  2662. *ReturnedLength = SdSize + DaclSize + SaclSize + OwnerSize + GroupSize;
  2663. return( TRUE );
  2664. error:
  2665. if (pSD) {
  2666. LocalFree(pSD);
  2667. }
  2668. if (pDacl) {
  2669. LocalFree(pDacl);
  2670. }
  2671. if (pSacl) {
  2672. LocalFree(pSacl);
  2673. }
  2674. if (pOwner) {
  2675. LocalFree(pOwner);
  2676. }
  2677. if (pGroup) {
  2678. LocalFree(pGroup);
  2679. }
  2680. return( FALSE );
  2681. }
  2682. VOID
  2683. CleanUpSD(
  2684. PSECURITY_DESCRIPTOR pSD
  2685. )
  2686. /*++
  2687. Routine Description:
  2688. delete the security descriptor
  2689. Arguments:
  2690. Arg - desc
  2691. Return Value:
  2692. TRUE - Success
  2693. FALSE - Error in GetLastError()
  2694. --*/
  2695. {
  2696. if (pSD) {
  2697. if (((PISECURITY_DESCRIPTOR)pSD)->Control & SE_SELF_RELATIVE){
  2698. LocalFree( pSD );
  2699. }else{
  2700. ULONG_PTR Dacl,Owner,Group,Sacl;
  2701. ULONG_PTR SDTop = (ULONG_PTR)pSD;
  2702. ULONG_PTR SDBottom = LocalSize(pSD)+SDTop;
  2703. Dacl = (ULONG_PTR)((PISECURITY_DESCRIPTOR)pSD)->Dacl;
  2704. Owner = (ULONG_PTR)((PISECURITY_DESCRIPTOR)pSD)->Owner;
  2705. Group = (ULONG_PTR)((PISECURITY_DESCRIPTOR)pSD)->Group;
  2706. Sacl = (ULONG_PTR)((PISECURITY_DESCRIPTOR)pSD)->Sacl;
  2707. // make sure that the dacl, owner, group, sacl are not within the SD boundary
  2708. if (Dacl) {
  2709. if (Dacl>=SDBottom|| Dacl<SDTop) {
  2710. LocalFree(((PISECURITY_DESCRIPTOR)pSD)->Dacl);
  2711. }
  2712. }
  2713. if (Owner) {
  2714. if (Owner>=SDBottom || Owner<SDTop) {
  2715. LocalFree(((PISECURITY_DESCRIPTOR)pSD)->Owner);
  2716. }
  2717. }
  2718. if (Group) {
  2719. if (Group>=SDBottom || Group<SDTop) {
  2720. LocalFree(((PISECURITY_DESCRIPTOR)pSD)->Group);
  2721. }
  2722. }
  2723. if (Sacl) {
  2724. if (Sacl>=SDBottom || Sacl<SDTop) {
  2725. LocalFree(((PISECURITY_DESCRIPTOR)pSD)->Sacl);
  2726. }
  2727. }
  2728. LocalFree(pSD);
  2729. }
  2730. }
  2731. }
  2732. NTSTATUS
  2733. AddAccessToDirectoryObjects(
  2734. HANDLE DirectoryHandle,
  2735. DWORD NewAccess,
  2736. PSID pSid
  2737. )
  2738. /*++
  2739. Routine Description:
  2740. Add Access to the objects in the given NT object directory
  2741. for the supplied SID.
  2742. This is done by adding a new AccessAllowedAce to the DACL's
  2743. on the objects in the directory.
  2744. Arguments:
  2745. Arg - desc
  2746. Return Value:
  2747. TRUE - Success
  2748. FALSE - Error in GetLastError()
  2749. --*/
  2750. {
  2751. BOOL Result;
  2752. ULONG Context;
  2753. HANDLE LinkHandle;
  2754. NTSTATUS Status;
  2755. BOOLEAN RestartScan;
  2756. ULONG ReturnedLength;
  2757. ULONG LengthNeeded;
  2758. OBJECT_ATTRIBUTES Attributes;
  2759. PSECURITY_DESCRIPTOR pSd,pSelfSD;
  2760. PACL pDacl;
  2761. POBJECT_DIRECTORY_INFORMATION pDirInfo;
  2762. RestartScan = TRUE;
  2763. Context = 0;
  2764. pDirInfo = (POBJECT_DIRECTORY_INFORMATION) LocalAlloc(LMEM_FIXED, 4096 );
  2765. if ( !pDirInfo)
  2766. {
  2767. return STATUS_NO_MEMORY;
  2768. }
  2769. while (TRUE) {
  2770. Status = NtQueryDirectoryObject( DirectoryHandle,
  2771. pDirInfo,
  2772. 4096 ,
  2773. TRUE,
  2774. RestartScan,
  2775. &Context,
  2776. &ReturnedLength
  2777. );
  2778. RestartScan = FALSE;
  2779. //
  2780. // Check the status of the operation.
  2781. //
  2782. if (!NT_SUCCESS( Status )) {
  2783. if (Status == STATUS_NO_MORE_ENTRIES) {
  2784. Status = STATUS_SUCCESS;
  2785. }
  2786. break;
  2787. }
  2788. // SymbolicLink
  2789. if (!wcscmp( pDirInfo->TypeName.Buffer, L"SymbolicLink" )) {
  2790. InitializeObjectAttributes(
  2791. &Attributes,
  2792. &pDirInfo->Name,
  2793. OBJ_CASE_INSENSITIVE,
  2794. DirectoryHandle,
  2795. NULL
  2796. );
  2797. Status = NtOpenSymbolicLinkObject(
  2798. &LinkHandle,
  2799. SYMBOLIC_LINK_ALL_ACCESS,
  2800. &Attributes
  2801. );
  2802. }
  2803. else {
  2804. continue;
  2805. }
  2806. if (!NT_SUCCESS( Status )) {
  2807. continue;
  2808. }
  2809. // GetSecurity
  2810. Status = NtQuerySecurityObject(
  2811. LinkHandle,
  2812. OWNER_SECURITY_INFORMATION |
  2813. GROUP_SECURITY_INFORMATION |
  2814. DACL_SECURITY_INFORMATION,
  2815. NULL, // pSd
  2816. 0, // Length
  2817. &LengthNeeded
  2818. );
  2819. if( Status != STATUS_BUFFER_TOO_SMALL ) {
  2820. DBGPRINT(("NtQuerySecurityObject 0x%x\n",Status));
  2821. NtClose( LinkHandle );
  2822. continue;
  2823. }
  2824. pSd = LocalAlloc(LMEM_FIXED, LengthNeeded );
  2825. if( pSd == NULL ) {
  2826. NtClose( LinkHandle );
  2827. continue;
  2828. }
  2829. Status = NtQuerySecurityObject(
  2830. LinkHandle,
  2831. OWNER_SECURITY_INFORMATION |
  2832. GROUP_SECURITY_INFORMATION |
  2833. DACL_SECURITY_INFORMATION,
  2834. pSd, // pSd
  2835. LengthNeeded, // Length
  2836. &LengthNeeded
  2837. );
  2838. if( !NT_SUCCESS(Status) ) {
  2839. DBGPRINT(("NtQuerySecurityObject 0x%x\n",Status));
  2840. NtClose( LinkHandle );
  2841. LocalFree( pSd );
  2842. continue;
  2843. }
  2844. // Mung ACL
  2845. Result = AddAceToSecurityDescriptor(
  2846. &pSd,
  2847. &pDacl,
  2848. NewAccess,
  2849. pSid,
  2850. FALSE
  2851. );
  2852. if( !Result ) {
  2853. NtClose( LinkHandle );
  2854. CleanUpSD(pSd);
  2855. continue;
  2856. }
  2857. // make sure that pSd is not self-relative already.
  2858. if (!(((PISECURITY_DESCRIPTOR)pSd)->Control & SE_SELF_RELATIVE)) {
  2859. if (!AbsoluteToSelfRelativeSD (pSd, &pSelfSD, NULL)){
  2860. NtClose( LinkHandle );
  2861. CleanUpSD(pSd);
  2862. continue;
  2863. }
  2864. }
  2865. // SetSecurity only accepts self-relative formats
  2866. Status = NtSetSecurityObject(
  2867. LinkHandle,
  2868. DACL_SECURITY_INFORMATION,
  2869. pSelfSD
  2870. );
  2871. NtClose( LinkHandle );
  2872. //
  2873. // These must be freed regardless of the success of
  2874. // NtSetSecurityObject
  2875. //
  2876. // pDacl lives inside of pSd
  2877. CleanUpSD(pSd);
  2878. CleanUpSD(pSelfSD);
  2879. } // end while
  2880. LocalFree( pDirInfo );
  2881. return STATUS_SUCCESS;
  2882. }
  2883. /*******************************************************************************
  2884. *
  2885. * ReInitializeSecurityWorker
  2886. *
  2887. * ReInitialize the default WinStation security descriptor and force all active
  2888. * sessions to update their security descirptors
  2889. *
  2890. * ENTRY:
  2891. * nothing
  2892. *
  2893. * EXIT:
  2894. * STATUS_SUCCESS
  2895. *
  2896. ******************************************************************************/
  2897. NTSTATUS
  2898. ReInitializeSecurityWorker( VOID )
  2899. {
  2900. NTSTATUS Status;
  2901. ULONG WinStationCount;
  2902. ULONG ByteCount;
  2903. WINSTATIONNAME * pWinStationName;
  2904. ULONG i;
  2905. PWINSTATION pWinStation;
  2906. /*
  2907. * Update Default Security Descriptor
  2908. */
  2909. RtlAcquireResourceExclusive(&WinStationSecurityLock, TRUE);
  2910. WinStationSecurityInit();
  2911. RtlReleaseResource(&WinStationSecurityLock);
  2912. /*
  2913. * Get the number of WinStations in the registry
  2914. */
  2915. WinStationCount = 0;
  2916. Status = IcaRegWinStationEnumerate( &WinStationCount, NULL, &ByteCount );
  2917. if ( !NT_SUCCESS(Status) )
  2918. return Status;
  2919. /*
  2920. * Allocate a buffer for the WinStation names
  2921. */
  2922. pWinStationName = MemAlloc( ByteCount );
  2923. if ( pWinStationName == NULL ) {
  2924. return STATUS_NO_MEMORY;
  2925. }
  2926. /*
  2927. * Get list of WinStation names from registry
  2928. */
  2929. WinStationCount = (ULONG) -1;
  2930. Status = IcaRegWinStationEnumerate( &WinStationCount,
  2931. (PWINSTATIONNAME)pWinStationName,
  2932. &ByteCount );
  2933. if ( !NT_SUCCESS(Status) ) {
  2934. MemFree( pWinStationName );
  2935. return Status;
  2936. }
  2937. /*
  2938. * Check if any WinStations need to be created or reset
  2939. */
  2940. for ( i = 0; i < WinStationCount; i++ ) {
  2941. /*
  2942. * Ignore console WinStation
  2943. */
  2944. if ( _wcsicmp( pWinStationName[i], L"Console" ) ) {
  2945. /*
  2946. * If this WinStation exists, then see if the Registry data
  2947. * has changed. If so, then reset the WinStation.
  2948. */
  2949. if ( pWinStation = FindWinStationByName( pWinStationName[i], FALSE ) ) {
  2950. /*
  2951. * Winstations should update their security
  2952. * descriptors.
  2953. */
  2954. RtlAcquireResourceExclusive(&WinStationSecurityLock, TRUE);
  2955. ReadWinStationSecurityDescriptor( pWinStation );
  2956. RtlReleaseResource(&WinStationSecurityLock);
  2957. ReleaseWinStation( pWinStation );
  2958. }
  2959. }
  2960. }
  2961. /*
  2962. * Free buffers
  2963. */
  2964. MemFree( pWinStationName );
  2965. return( STATUS_SUCCESS );
  2966. }