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

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