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.

13162 lines
400 KiB

  1. /****************************************************************************/
  2. // wstrpc.c
  3. //
  4. // TermSrv API RPC server code.
  5. //
  6. // Copyright (C) 1997-2000 Microsoft Corporation
  7. /****************************************************************************/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #include <winuserp.h>
  11. #define SECURITY_WIN32
  12. #include <stdlib.h>
  13. #include <time.h>
  14. #include <tchar.h>
  15. #include <lmaccess.h>
  16. #include <lmerr.h>
  17. #include <allproc.h>
  18. #include <winsta.h>
  19. #include <rpc.h>
  20. #include <vdmdbg.h>
  21. #include <dsrole.h>
  22. #include <security.h>
  23. #include <ntsecapi.h>
  24. #include <lmapibuf.h>
  25. #include "..\rpcwire.h"
  26. #define INITGUID
  27. #include "objbase.h"
  28. #include "initguid.h"
  29. #include <netcfgx.h>
  30. #include "devguid.h"
  31. #include <malloc.h>
  32. #include <dsgetdc.h>
  33. #include <winsock2.h>
  34. #include <tdi.h>
  35. #include <reason.h>
  36. #include "tsremdsk.h"
  37. /*
  38. * Include the RPC generated common header
  39. */
  40. #include "tsrpc.h"
  41. #include "icaevent.h"
  42. #include "sessdir.h"
  43. #include "conntfy.h"
  44. #define REMOTE_DISCONNECT_TITLE_ID 23
  45. #define REMOTE_DISCONNECT_MESSAGE_ID 24
  46. #define MIN_GAP_DATABASE_SIZE 100
  47. #define MAX_IDS_LEN 256 // maximum length that the input parm can be
  48. #define MAX_BUF 256
  49. #define MAX_STRING_BYTES 512
  50. //
  51. // Winlogon defines
  52. //
  53. #define APPLICATION_NAME TEXT("Winlogon")
  54. #define WINSTATIONS_DISABLED TEXT("WinStationsDisabled")
  55. #ifdef NTSDDEBUG
  56. #define NTSDDBGPRINT(x) DbgPrint x
  57. #else
  58. #define NTSDDBGPRINT(x)
  59. #endif
  60. //
  61. // Value passed to RPC runtime libraries for the maximum number of
  62. // cached threads it will keep around. We can actually service more RPC
  63. // calls than this, but it will delete threads when they are done.
  64. //
  65. #define MAX_WINSTATION_RPC_THREADS 1000
  66. //
  67. //This value is to restrict the number
  68. //of concurrent calls to WinStationWaitSystemEvent(),
  69. //We should keep it lower than MAX_WINSTATION_RPC_THREADS
  70. //because this calls may block indefinitely, thus, if we don't do so,
  71. //it may render TS RPC service unresponsive for indefinite period of time.
  72. //
  73. #define MAX_SYSTEM_EVENTS 100
  74. #ifdef notdef
  75. // This validates the user pointer to be within the View memory region
  76. #define ISPOINTERVALID_SERVER(pContext, p, length) \
  77. (((ULONG)(p) >= (ULONG)(pContext)->ViewBase) && \
  78. ((char *)(p) + (length)) < (char *)((ULONG)(pContext)->ViewBase+pContext->ViewSize))
  79. #endif
  80. //
  81. // Extern funcs, these three are from acl.c
  82. extern VOID CleanUpSD(PSECURITY_DESCRIPTOR);
  83. extern BOOL IsCallerSystem( VOID );
  84. extern BOOL IsCallerAdmin( VOID );
  85. extern BOOL IsCallerAnonymous( VOID );
  86. extern BOOLEAN WinStationCheckConsoleSession(VOID);
  87. extern NTSTATUS CheckIdleWinstation(VOID);
  88. extern NTSTATUS WaitForConsoleConnectWorker( PWINSTATION pWinStation );
  89. extern WCHAR gpszServiceName[];
  90. extern BOOL g_fAppCompat;
  91. extern ULONG MaxOutStandingConnect;
  92. extern ULONG NumOutStandingConnect;
  93. extern HANDLE hConnectEvent;
  94. // TermSrv counter values
  95. extern DWORD g_TermSrvTotalSessions;
  96. extern DWORD g_TermSrvReconSessions;
  97. extern DWORD g_TermSrvDiscSessions;
  98. extern DWORD g_TermSrvSuccTotalLogons;
  99. extern DWORD g_TermSrvSuccRemoteLogons;
  100. extern DWORD g_TermSrvSuccLocalLogons;
  101. extern DWORD g_TermSrvSuccSession0Logons;
  102. extern PSID gSystemSid;
  103. extern PSID gAdminSid;
  104. extern HANDLE WinStationIdleControlEvent;
  105. extern HANDLE ConsoleLogoffEvent;
  106. extern RTL_CRITICAL_SECTION ConsoleLock;
  107. extern ULONG gConsoleCreationDisable;
  108. extern NTSTATUS
  109. WinStationEnableSessionIo(
  110. PWINSTATION pWinStation,
  111. BOOL bEnable
  112. );
  113. extern NTSTATUS
  114. _CheckShadowLoop(
  115. IN ULONG ClientLogonId,
  116. IN PWSTR pTargetServerName,
  117. IN ULONG TargetLogonId
  118. );
  119. extern BOOL
  120. Filter_RemoveOutstandingConnection(
  121. IN PBYTE pin_addr,
  122. IN UINT uAddrSize
  123. );
  124. extern NTSTATUS
  125. WinStationWinerrorToNtStatus(ULONG ulWinError);
  126. typedef struct _SID_CACHE_LIST_ENTRY {
  127. LIST_ENTRY ListEntry;
  128. HANDLE ProcId;
  129. LARGE_INTEGER CreateTime;
  130. PSID pSid;
  131. } SID_CACHE_LIST_ENTRY, *PSID_CACHE_LIST_ENTRY;
  132. #define MAX_SID_CACHE_ENTRIES 4000
  133. ULONG gMaxSidCacheEntries = 0;
  134. #define REG_GUID_TABLE REG_CONTROL_TSERVER L"\\lanatable\\"
  135. #define LANA_ID L"LanaId"
  136. /*=============================================================================
  137. == Functions Defined
  138. =============================================================================*/
  139. VOID NotifySystemEvent( ULONG );
  140. VOID CheckSidCacheSize();
  141. RPC_STATUS RegisterRPCInterface( BOOL bReregister );
  142. /*=============================================================================
  143. == External Functions used
  144. =============================================================================*/
  145. NTSTATUS WinStationEnumerateWorker( PULONG, PLOGONID, PULONG, PULONG );
  146. NTSTATUS WinStationRenameWorker( PWINSTATIONNAME, ULONG, PWINSTATIONNAME, ULONG );
  147. NTSTATUS xxxWinStationQueryInformation( ULONG, ULONG, PVOID, ULONG, PULONG );
  148. NTSTATUS xxxWinStationSetInformation( ULONG, WINSTATIONINFOCLASS, PVOID, ULONG );
  149. NTSTATUS LogonIdFromWinStationNameWorker( PWINSTATIONNAME, ULONG, PULONG );
  150. NTSTATUS IcaWinStationNameFromLogonId( ULONG, PWINSTATIONNAME );
  151. NTSTATUS WaitForConnectWorker( PWINSTATION pWinStation, HANDLE ClientProcessId );
  152. DWORD xxxWinStationGenerateLicense( PWCHAR, ULONG, PCHAR, ULONG );
  153. DWORD xxxWinStationInstallLicense( PCHAR, ULONG );
  154. DWORD xxxWinStationEnumerateLicenses( PULONG, PULONG, PCHAR, PULONG );
  155. DWORD xxxWinStationActivateLicense( PCHAR, ULONG, PWCHAR, ULONG );
  156. DWORD xxxWinStationRemoveLicense( PCHAR, ULONG );
  157. DWORD xxxWinStationSetPoolCount( PCHAR, ULONG );
  158. DWORD xxxWinStationQueryUpdateRequired( PULONG );
  159. NTSTATUS WinStationShadowWorker( ULONG, PWSTR, ULONG, ULONG, BYTE, USHORT );
  160. NTSTATUS WinStationShadowTargetSetupWorker( BOOL, ULONG );
  161. NTSTATUS WinStationShadowTargetWorker( BOOLEAN, BOOL, ULONG, PWINSTATIONCONFIG2, PICA_STACK_ADDRESS,
  162. PVOID, ULONG, PVOID, ULONG, PVOID );
  163. NTSTATUS WinStationStopAllShadows( PWINSTATION );
  164. VOID WinStationTerminate( PWINSTATION );
  165. VOID WinStationDeleteWorker( PWINSTATION );
  166. NTSTATUS WinStationDoDisconnect( PWINSTATION, PRECONNECT_INFO, BOOLEAN );
  167. NTSTATUS WinStationDoReconnect( PWINSTATION, PRECONNECT_INFO );
  168. VOID CleanupReconnect( PRECONNECT_INFO );
  169. NTSTATUS ShutdownLogoff( ULONG, ULONG );
  170. NTSTATUS SelfRelativeToAbsoluteSD( PSECURITY_DESCRIPTOR,
  171. PSECURITY_DESCRIPTOR *, PULONG );
  172. NTSTATUS QueueWinStationCreate( PWINSTATIONNAME );
  173. ULONG WinStationShutdownReset( PVOID );
  174. NTSTATUS DoForWinStationGroup( PULONG, ULONG, LPTHREAD_START_ROUTINE );
  175. NTSTATUS InitializeGAPPointersDatabase();
  176. NTSTATUS IncreaseGAPPointersDatabaseSize();
  177. NTSTATUS InsertPointerInGAPDatabase(PVOID Pointer);
  178. VOID ReleaseGAPPointersDatabase();
  179. BOOLEAN PointerIsInGAPDatabase(PVOID Pointer);
  180. VOID ValidateGAPPointersDatabase(ULONG n);
  181. VOID ResetAutoReconnectInfo( PWINSTATION );
  182. NTSTATUS
  183. GetSidFromProcessId(
  184. HANDLE UniqueProcessId,
  185. LARGE_INTEGER CreateTime,
  186. PSID *ppProcessSid,
  187. BOOLEAN ImpersonatingClient
  188. );
  189. PSECURITY_DESCRIPTOR
  190. WinStationGetSecurityDescriptor(
  191. PWINSTATION pWinStation
  192. );
  193. NTSTATUS
  194. WinStationConnectWorker(
  195. ULONG ClientLogonId,
  196. ULONG ConnectLogonId,
  197. ULONG TargetLogonId,
  198. PWCHAR pPassword,
  199. DWORD PasswordSize,
  200. BOOLEAN bWait,
  201. BOOLEAN bAutoReconnecting
  202. );
  203. NTSTATUS
  204. WinStationDisconnectWorker(
  205. ULONG LogonId,
  206. BOOLEAN bWait,
  207. BOOLEAN CallerIsRpc
  208. );
  209. NTSTATUS
  210. WinStationWaitSystemEventWorker(
  211. HANDLE hServer,
  212. ULONG EventMask,
  213. PULONG pEventFlags
  214. );
  215. NTSTATUS
  216. WinStationCallbackWorker(
  217. ULONG LogonId,
  218. PWCHAR pPhoneNumber
  219. );
  220. NTSTATUS
  221. WinStationBreakPointWorker(
  222. ULONG LogonId,
  223. BOOLEAN KernelFlag
  224. );
  225. NTSTATUS
  226. WinStationReadRegistryWorker(
  227. VOID
  228. );
  229. NTSTATUS
  230. ReInitializeSecurityWorker(
  231. VOID
  232. );
  233. NTSTATUS
  234. WinStationNotifyLogonWorker(
  235. DWORD ClientLogonId,
  236. DWORD ClientProcessId,
  237. BOOLEAN fUserIsAdmin,
  238. DWORD UserToken,
  239. PWCHAR pDomain,
  240. DWORD DomainSize,
  241. PWCHAR pUserName,
  242. DWORD UserNameSize,
  243. PWCHAR pPassword,
  244. DWORD PasswordSize,
  245. UCHAR Seed,
  246. PCHAR pUserConfig,
  247. DWORD ConfigSize,
  248. BOOLEAN *pfIsRedirected
  249. );
  250. NTSTATUS
  251. WinStationNotifyLogoffWorker(
  252. DWORD ClientLogonId,
  253. DWORD ClientProcessId
  254. );
  255. NTSTATUS
  256. WinStationNotifyNewSession(
  257. DWORD ClientLogonId
  258. );
  259. NTSTATUS
  260. WinStationShutdownSystemWorker(
  261. ULONG ClientLogonId,
  262. ULONG ShutdownFlags
  263. );
  264. NTSTATUS
  265. WinStationTerminateProcessWorker(
  266. ULONG ProcessId,
  267. ULONG ExitCode
  268. );
  269. PSECURITY_DESCRIPTOR
  270. BuildEveryOneAllowSD();
  271. NTSTATUS AddUserAce( PWINSTATION );
  272. NTSTATUS RemoveUserAce( PWINSTATION );
  273. NTSTATUS ApplyWinStaMapping( PWINSTATION pWinStation );
  274. NTSTATUS
  275. RpcCheckClientAccess(
  276. PWINSTATION pWinStation,
  277. ACCESS_MASK DesiredAccess,
  278. BOOLEAN AlreadyImpersonating
  279. );
  280. NTSTATUS
  281. RpcCheckClientAccessLocal(
  282. PWINSTATION pWinStation,
  283. ACCESS_MASK DesiredAccess,
  284. BOOLEAN AlreadyImpersonating
  285. );
  286. _CheckConnectAccess(
  287. PWINSTATION pSourceWinStation,
  288. PSID pClientSid,
  289. ULONG ClientLogonId,
  290. PWCHAR pPassword,
  291. DWORD PasswordSize
  292. );
  293. NTSTATUS
  294. RpcCheckSystemClient(
  295. ULONG LogonId
  296. );
  297. NTSTATUS
  298. RpcCheckSystemClientNoLogonId(
  299. PWINSTATION pWinStation
  300. );
  301. NTSTATUS
  302. RpcGetClientLogonId(
  303. PULONG pLogonId
  304. );
  305. BOOL
  306. ConfigurePerSessionSecurity(
  307. PWINSTATION pWinStation
  308. );
  309. BOOL
  310. IsCallerAdmin( VOID );
  311. BOOL
  312. IsCallerSystem( VOID );
  313. BOOL
  314. IsCallerAnonymous( VOID );
  315. BOOLEAN
  316. ValidWireBuffer(WINSTATIONINFOCLASS InfoClass,
  317. PVOID WireBuf,
  318. ULONG WireBufLen);
  319. NTSTATUS
  320. IsZeroterminateStringA(
  321. PBYTE pString,
  322. DWORD dwLength
  323. );
  324. NTSTATUS
  325. IsZeroterminateStringW(
  326. PWCHAR pwString,
  327. DWORD dwLength
  328. ) ;
  329. NTSTATUS
  330. IsConfigValid(
  331. PWINSTATIONCONFIG2 pConfig
  332. );
  333. NTSTATUS
  334. WinStationUpdateClientCachedCredentialsWorker(
  335. DWORD ClientLogonId,
  336. ULONG_PTR ClientProcessId,
  337. PWCHAR pDomain,
  338. DWORD DomainSize,
  339. PWCHAR pUserName,
  340. DWORD UserNameSize,
  341. BOOLEAN fSmartCard
  342. );
  343. NTSTATUS
  344. WinStationFUSCanRemoteUserDisconnectWorker(
  345. DWORD TargetLogonId,
  346. DWORD ClientLogonId,
  347. ULONG_PTR ClientProcessId,
  348. PWCHAR pDomain,
  349. DWORD DomainSize,
  350. PWCHAR pUserName,
  351. DWORD UserNameSize
  352. );
  353. NTSTATUS
  354. WinStationCheckLoopBackWorker(
  355. DWORD TargetLogonId,
  356. DWORD ClientLogonId,
  357. PWCHAR pTargetServerName,
  358. DWORD NameSize
  359. );
  360. NTSTATUS WinStationNotifyDisconnectPipeWorker(
  361. DWORD ClientLogonId,
  362. ULONG_PTR ClientProcessId
  363. );
  364. NTSTATUS WinStationSessionInitializedWorker(
  365. DWORD ClientLogonId,
  366. ULONG_PTR ClientProcessId
  367. );
  368. NTSTATUS WinStationCheckAccessWorker(
  369. ULONG ClientLogonId,
  370. DWORD UserToken,
  371. ULONG TargetLogonId,
  372. ULONG AccessMask
  373. );
  374. /*=============================================================================
  375. == Internal Functions used
  376. =============================================================================*/
  377. VOID AuditShutdownEvent(VOID);
  378. BOOL AuditingEnabled(VOID);
  379. NTSTATUS LogoffWinStation( PWINSTATION, ULONG );
  380. //
  381. //Used by IsGinaVersionCurrent()
  382. //
  383. #define WLX_NEGOTIATE_NAME "WlxNegotiate"
  384. typedef BOOL (WINAPI * PWLX_NEGOTIATE)(DWORD, DWORD *);
  385. BOOL IsGinaVersionCurrent();
  386. #if DBG
  387. void DumpOutLastErrorString()
  388. {
  389. LPVOID lpMsgBuf;
  390. DWORD error = GetLastError();
  391. DBGPRINT(("GetLastError() = 0x%lx \n", error ));
  392. FormatMessage(
  393. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  394. FORMAT_MESSAGE_FROM_SYSTEM |
  395. FORMAT_MESSAGE_IGNORE_INSERTS,
  396. NULL,
  397. error,
  398. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  399. (LPTSTR) &lpMsgBuf,
  400. 0,
  401. NULL
  402. );
  403. //
  404. // Process any inserts in lpMsgBuf.
  405. // ...
  406. // Display the string.
  407. //
  408. DBGPRINT(("%s\n", (LPCTSTR)lpMsgBuf ));
  409. //
  410. // Free the buffer.
  411. //
  412. LocalFree( lpMsgBuf );
  413. }
  414. #endif
  415. #if DBG
  416. #define DumpOutLastError DumpOutLastErrorString()
  417. #else
  418. #define DumpOutLastError
  419. #endif
  420. /*=============================================================================
  421. == Data
  422. =============================================================================*/
  423. BOOLEAN gbPointersDatabaseIsValid = FALSE;
  424. ULONG gPointersDatabaseSize;
  425. ULONG gNbProcesses;
  426. PVOID *gPointersDatabase = NULL;
  427. RTL_CRITICAL_SECTION gRpcGetAllProcessesLock;
  428. RTL_CRITICAL_SECTION gRpcPointersDatabaseLock;
  429. RTL_CRITICAL_SECTION gRpcSidCacheLock;
  430. BOOLEAN gbRpcGetAllProcessesOK;
  431. BOOLEAN gbRpcSidCacheOK;
  432. extern RTL_CRITICAL_SECTION WsxListLock;
  433. extern LIST_ENTRY WsxListHead;
  434. extern LIST_ENTRY WinStationListHead; // protected by WinStationListLock
  435. LIST_ENTRY gSidCacheHead;
  436. BOOLEAN bConsoleConnected=FALSE;
  437. extern POLICY_TS_MACHINE g_MachinePolicy; // declared in winsta.c
  438. /*****************************************************************************
  439. * WinStationInitRPC
  440. *
  441. * Setup the RPC bindings, and listen for incoming requests.
  442. ****************************************************************************/
  443. RPC_STATUS
  444. WinStationInitRPC( VOID
  445. )
  446. {
  447. RPC_STATUS Status;
  448. DWORD Result;
  449. RPC_BINDING_VECTOR *pBindingVector;
  450. TRACE((hTrace,TC_ICASRV,TT_API2,"RPC WinStationInitRPC\n"));
  451. //
  452. // Initialize the Critical Sections that are
  453. // necessary for RpcWinStationGetAllProcesses
  454. //
  455. gbRpcGetAllProcessesOK =
  456. ((NT_SUCCESS(RtlInitializeCriticalSection(&gRpcGetAllProcessesLock))
  457. && (NT_SUCCESS(RtlInitializeCriticalSection(&gRpcPointersDatabaseLock)))
  458. )? TRUE : FALSE);
  459. gbRpcSidCacheOK =
  460. NT_SUCCESS(RtlInitializeCriticalSection(&gRpcSidCacheLock)) ? TRUE :
  461. FALSE;
  462. InitializeListHead(&gSidCacheHead);
  463. // register the LPC (local only) interface
  464. Status = RpcServerUseProtseqEp(
  465. L"ncalrpc", // Protocol Sequence (LPC)
  466. MAX_WINSTATION_RPC_THREADS, // Maximum calls at one time
  467. L"IcaApi", // Endpoint
  468. NULL // Pass NULL for Security - RPC will take care of the correct Security based on Protocol Sequence used
  469. );
  470. if( Status != RPC_S_OK ) {
  471. TRACE((hTrace,TC_ICASRV,TT_ERROR,"IcaServ: Error %d RpcUseProtseqEp on ncalrpc\n",Status));
  472. return( Status );
  473. }
  474. //
  475. // register the Named pipes interface
  476. // (remote with NT domain authentication)
  477. //
  478. Status = RpcServerUseProtseqEp(
  479. L"ncacn_np", // Protocol Sequence
  480. MAX_WINSTATION_RPC_THREADS, // Maximum calls at one time
  481. L"\\pipe\\Ctx_WinStation_API_service", // Endpoint
  482. NULL // Security
  483. );
  484. if( Status != RPC_S_OK ) {
  485. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Error %d RpcUseProtseqEp on ncacn_np\n",Status));
  486. return( Status );
  487. }
  488. // Register our interface handle
  489. Status = RegisterRPCInterface( FALSE );
  490. if( Status != RPC_S_OK ) {
  491. return( Status );
  492. }
  493. // By default, rpc will serialize access to context handles. Since
  494. // the ICASRV needs to be able to have two threads access a context
  495. // handle at once, and it knows what it is doing, we will tell rpc
  496. // not to serialize access to context handles.
  497. // We cannot call this function as its effects are process wide, and since we are
  498. // part of SvcHost, other services also get affected with this call.
  499. // instead we will use context_handle_noserialize attribute in our acf files.
  500. //
  501. // I_RpcSsDontSerializeContext();
  502. // Now do the RPC listen to service calls
  503. Status = RpcServerListen(
  504. 1, // Min calls
  505. MAX_WINSTATION_RPC_THREADS,
  506. TRUE // fDontWait
  507. );
  508. if( Status != RPC_S_OK ) {
  509. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Error %d RpcServerListen\n",Status));
  510. return( Status );
  511. }
  512. return( 0 );
  513. }
  514. /*****************************************************************************
  515. * RpcWinStationOpenServer
  516. *
  517. * Function to open the server for WinStation API's.
  518. *
  519. * The purpose of this function is the allocation of the
  520. * RPC context handle for server side state information.
  521. ****************************************************************************/
  522. BOOLEAN
  523. RpcWinStationOpenServer(
  524. handle_t hBinding,
  525. DWORD *pResult,
  526. HANDLE *phContext
  527. )
  528. {
  529. PRPC_CLIENT_CONTEXT p;
  530. //
  531. // Allocate our open context structure
  532. //
  533. p = midl_user_allocate( sizeof(RPC_CLIENT_CONTEXT) );
  534. if( p == NULL ) {
  535. *pResult = (DWORD) STATUS_NO_MEMORY;
  536. return( FALSE );
  537. }
  538. //
  539. // zero it out
  540. //
  541. memset( p, 0, sizeof(RPC_CLIENT_CONTEXT) );
  542. //
  543. // Initialize it
  544. //
  545. p->pWaitEvent = NULL;
  546. //
  547. // Return the RPC context handle
  548. //
  549. *phContext = (PRPC_CLIENT_CONTEXT)p;
  550. // Return success
  551. *pResult = STATUS_SUCCESS;
  552. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  553. }
  554. /*****************************************************************************
  555. * RpcWinStationCloseServer
  556. *
  557. * Function to close the server for WinStation API's.
  558. * This function is obsolete. use RpcWinstationCloseServerEx instead.
  559. * Its kept here for compatibility with older (w2k) clients.
  560. ****************************************************************************/
  561. BOOLEAN
  562. RpcWinStationCloseServer(
  563. HANDLE hContext,
  564. DWORD *pResult
  565. )
  566. {
  567. PRPC_CLIENT_CONTEXT pContext = (PRPC_CLIENT_CONTEXT)hContext;
  568. ULONG EventFlags;
  569. NTSTATUS Status;
  570. if(!hContext)
  571. {
  572. *pResult = STATUS_UNSUCCESSFUL;
  573. return( FALSE );
  574. }
  575. // Free the wait event block if one was allocated
  576. if ( pContext->pWaitEvent ) {
  577. WinStationWaitSystemEventWorker( hContext, WEVENT_NONE, &EventFlags );
  578. }
  579. *pResult = STATUS_SUCCESS;
  580. return( TRUE );
  581. }
  582. /*****************************************************************************
  583. * RpcWinStationCloseServerEx
  584. *
  585. * Function to close the server for WinStation API's.
  586. * This function supersades the RpcWinStationCloseServer
  587. ****************************************************************************/
  588. BOOLEAN
  589. RpcWinStationCloseServerEx(
  590. HANDLE *phContext,
  591. DWORD *pResult
  592. )
  593. {
  594. PRPC_CLIENT_CONTEXT pContext = NULL;
  595. ULONG EventFlags;
  596. NTSTATUS Status;
  597. if(!phContext || !(*phContext))
  598. {
  599. *pResult = STATUS_UNSUCCESSFUL;
  600. return( FALSE );
  601. }
  602. pContext = (PRPC_CLIENT_CONTEXT)*phContext;
  603. // Free the wait event block if one was allocated
  604. if ( pContext->pWaitEvent ) {
  605. WinStationWaitSystemEventWorker( *phContext, WEVENT_NONE, &EventFlags );
  606. }
  607. Status = RpcSsContextLockExclusive(NULL, pContext);
  608. if (RPC_S_OK == Status)
  609. {
  610. midl_user_free(pContext);
  611. // This is required to signal the RPC that we are done with this context handle
  612. *phContext = NULL;
  613. *pResult = STATUS_SUCCESS;
  614. return( TRUE );
  615. }
  616. else
  617. {
  618. DbgPrint("-------------RpcWinStationCloseServerEx: failed to lock the Context exclusively, Status = 0x%X\n", Status);
  619. *pResult = Status;
  620. if (*pResult == STATUS_TIMEOUT) *pResult = STATUS_UNSUCCESSFUL;
  621. return (FALSE);
  622. }
  623. }
  624. /*****************************************************************************
  625. * RpcIcaServerPing
  626. *
  627. * Called on an external ping to this Terminal Server.
  628. ****************************************************************************/
  629. BOOLEAN
  630. RpcIcaServerPing(
  631. HANDLE hServer,
  632. DWORD *pResult
  633. )
  634. {
  635. if(!hServer)
  636. {
  637. *pResult = STATUS_UNSUCCESSFUL;
  638. return( FALSE );
  639. }
  640. TRACE((hTrace,TC_ICASRV,TT_API1,"PING Received!\n"));
  641. *pResult = STATUS_SUCCESS;
  642. return( TRUE );
  643. }
  644. /*****************************************************************************
  645. * RpcWinStationEnumerate
  646. *
  647. * WinStationEnumerate API
  648. ****************************************************************************/
  649. BOOLEAN
  650. RpcWinStationEnumerate(
  651. HANDLE hServer,
  652. DWORD *pResult,
  653. PULONG pEntries,
  654. PCHAR pLogonId,
  655. PULONG pByteCount,
  656. PULONG pIndex
  657. )
  658. {
  659. if(!hServer)
  660. {
  661. *pResult = STATUS_UNSUCCESSFUL;
  662. return( FALSE );
  663. }
  664. if (!pEntries || !pLogonId || !pByteCount || !pIndex) {
  665. *pResult = STATUS_INVALID_USER_BUFFER;
  666. return FALSE;
  667. }
  668. *pResult = WinStationEnumerateWorker(
  669. pEntries,
  670. (PLOGONID)pLogonId,
  671. pByteCount,
  672. pIndex
  673. );
  674. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  675. }
  676. /*****************************************************************************
  677. * RpcWinStationEnumerateProcesses
  678. *
  679. * WinStationEnumerateProcesses API
  680. ****************************************************************************/
  681. BOOLEAN
  682. RpcWinStationEnumerateProcesses(
  683. HANDLE hServer,
  684. DWORD *pResult,
  685. PBYTE pProcessBuffer,
  686. DWORD ByteCount
  687. )
  688. {
  689. PBYTE pSrcProcessBuffer = NULL;
  690. RPC_STATUS RpcStatus;
  691. NTSTATUS Status;
  692. if(!hServer)
  693. {
  694. *pResult = STATUS_UNSUCCESSFUL;
  695. return( FALSE );
  696. }
  697. #ifdef _X86_
  698. RtlEnterCriticalSection(&gRpcGetAllProcessesLock);
  699. // Check if SID cache hasn't grown too much
  700. CheckSidCacheSize();
  701. //
  702. // Allocate a temporary buffer
  703. //
  704. pSrcProcessBuffer = MemAlloc (ByteCount);
  705. if (pSrcProcessBuffer == NULL)
  706. {
  707. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  708. *pResult = STATUS_NO_MEMORY;
  709. return FALSE;
  710. }
  711. //
  712. // Impersonate client
  713. //
  714. RpcStatus = RpcImpersonateClient( NULL );
  715. if( RpcStatus != RPC_S_OK ) {
  716. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  717. *pResult = STATUS_ACCESS_DENIED;
  718. return FALSE;
  719. }
  720. /*
  721. * Perform process enumeration.
  722. */
  723. *pResult = NtQuerySystemInformation( SystemProcessInformation,
  724. (PVOID)pSrcProcessBuffer,
  725. ByteCount,
  726. NULL);
  727. if ( *pResult == STATUS_SUCCESS ) {
  728. PSYSTEM_PROCESS_INFORMATION pSrcProcessInfo;
  729. PSYSTEM_PROCESS_INFORMATION pDestProcessInfo;
  730. PCITRIX_PROCESS_INFORMATION pDestCitrixInfo;
  731. ULONG SessionId = INVALID_SESSIONID;
  732. PWINSTATION pWinStation = NULL;
  733. ULONG TotalOffset;
  734. PSID pSid;
  735. ULONG SizeOfSid;
  736. PBYTE pSrc, pDest;
  737. ULONG i;
  738. ULONG Size = 0;
  739. /*
  740. * Walk the returned buffer to calculate the required size.
  741. */
  742. pSrcProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pSrcProcessBuffer;
  743. TotalOffset = 0;
  744. do
  745. {
  746. Size += (SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION
  747. + (SIZEOF_TS4_SYSTEM_THREAD_INFORMATION * pSrcProcessInfo->NumberOfThreads)
  748. + pSrcProcessInfo->ImageName.Length
  749. );
  750. //
  751. // Get the Sid (will be remembered in the Sid cache)
  752. // Maybe it would be better to add here a "Sidmaximumlength" ??
  753. //
  754. Status = GetSidFromProcessId(
  755. pSrcProcessInfo->UniqueProcessId,
  756. pSrcProcessInfo->CreateTime,
  757. &pSid,
  758. TRUE
  759. );
  760. if (Status == STATUS_CANNOT_IMPERSONATE)
  761. {
  762. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  763. MemFree(pSrcProcessBuffer);
  764. *pResult = STATUS_ACCESS_DENIED;
  765. return FALSE;
  766. }
  767. if (NT_SUCCESS(Status))
  768. {
  769. Size += RtlLengthSid(pSid);
  770. }
  771. TotalOffset += pSrcProcessInfo->NextEntryOffset;
  772. pSrcProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pSrcProcessBuffer[TotalOffset];
  773. }
  774. while (pSrcProcessInfo->NextEntryOffset != 0);
  775. if (ByteCount < Size)
  776. {
  777. RevertToSelf();
  778. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  779. MemFree(pSrcProcessBuffer);
  780. *pResult = STATUS_INFO_LENGTH_MISMATCH;
  781. return FALSE;
  782. }
  783. /*
  784. * Walk the returned buffer (it's in new Win2000 SYSTEM_PROCESS_INFORMATION format),
  785. * copy it to the old TS4 SYSTEM_PROCESS_INFORMATION format, and fixup the addresses
  786. * (now containing pointers in our address space within pProcessBuffer) to offsets.
  787. */
  788. // back to the beginning
  789. pSrcProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pSrcProcessBuffer;
  790. pDestProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pProcessBuffer;
  791. // initialize current pointers
  792. pSrc = pSrcProcessBuffer;
  793. pDest = pProcessBuffer;
  794. TotalOffset = 0;
  795. for(;;) {
  796. //
  797. // Check winstation Query access first.
  798. //
  799. SessionId = pSrcProcessInfo->SessionId;
  800. if( SessionId == INVALID_SESSIONID )
  801. {
  802. //
  803. // Skip the process entry.
  804. //
  805. if( pSrcProcessInfo->NextEntryOffset == 0 )
  806. {
  807. pDestProcessInfo->NextEntryOffset = 0;
  808. break;
  809. }
  810. TotalOffset += pSrcProcessInfo->NextEntryOffset;
  811. pSrcProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pSrcProcessBuffer[TotalOffset];
  812. pSrc = (PBYTE)pSrcProcessInfo;
  813. continue;
  814. }
  815. /*
  816. * Find and lock client WinStation
  817. */
  818. pWinStation = FindWinStationById( SessionId, FALSE );
  819. if ( pWinStation == NULL )
  820. {
  821. //
  822. // The session this process belongs to, might already be gone.
  823. // Don't fail here, just skip the process entry.
  824. //
  825. if( pSrcProcessInfo->NextEntryOffset == 0 )
  826. {
  827. pDestProcessInfo->NextEntryOffset = 0;
  828. break;
  829. }
  830. TotalOffset += pSrcProcessInfo->NextEntryOffset;
  831. pSrcProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pSrcProcessBuffer[TotalOffset];
  832. pSrc = (PBYTE)pSrcProcessInfo;
  833. continue;
  834. }
  835. Status = RpcCheckClientAccess( pWinStation, WINSTATION_QUERY, TRUE );
  836. ReleaseWinStation( pWinStation );
  837. if ( !NT_SUCCESS( Status ) )
  838. {
  839. //
  840. // The client is not authorized to view this process entry. Skip it.
  841. //
  842. if( pSrcProcessInfo->NextEntryOffset == 0 )
  843. {
  844. pDestProcessInfo->NextEntryOffset = 0;
  845. break;
  846. }
  847. TotalOffset += pSrcProcessInfo->NextEntryOffset;
  848. pSrcProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pSrcProcessBuffer[TotalOffset];
  849. pSrc = (PBYTE)pSrcProcessInfo;
  850. continue;
  851. }
  852. //
  853. // Copy process information
  854. //
  855. memcpy(pDest,pSrc,SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION);
  856. pSrc += sizeof(SYSTEM_PROCESS_INFORMATION);
  857. pDest += SIZEOF_TS4_SYSTEM_PROCESS_INFORMATION;
  858. //
  859. // Copy all the threads info
  860. //
  861. for (i=0; i < pSrcProcessInfo->NumberOfThreads ; i++)
  862. {
  863. memcpy(pDest,pSrc,SIZEOF_TS4_SYSTEM_THREAD_INFORMATION);
  864. pSrc += sizeof(SYSTEM_THREAD_INFORMATION);
  865. pDest += SIZEOF_TS4_SYSTEM_THREAD_INFORMATION;
  866. }
  867. //
  868. // Set the old TS4 info
  869. //
  870. pDestCitrixInfo = (PCITRIX_PROCESS_INFORMATION) pDest;
  871. pDest += sizeof(CITRIX_PROCESS_INFORMATION);
  872. pDestCitrixInfo->MagicNumber = CITRIX_PROCESS_INFO_MAGIC;
  873. pDestCitrixInfo->LogonId = pSrcProcessInfo->SessionId;
  874. pDestCitrixInfo->ProcessSid = NULL;
  875. //
  876. // Get the Sid again (from the cache)
  877. //
  878. Status = GetSidFromProcessId(
  879. pDestProcessInfo->UniqueProcessId,
  880. pDestProcessInfo->CreateTime,
  881. &pSid,
  882. TRUE
  883. );
  884. if (Status == STATUS_CANNOT_IMPERSONATE)
  885. {
  886. *pResult = STATUS_ACCESS_DENIED;
  887. break;
  888. }
  889. if (NT_SUCCESS(Status))
  890. {
  891. //
  892. // Copy the Sid
  893. //
  894. SizeOfSid = RtlLengthSid(pSid);
  895. pDestCitrixInfo->ProcessSid = NULL;
  896. if ( NT_SUCCESS(RtlCopySid(SizeOfSid, pDest, pSid) ) )
  897. {
  898. pDestCitrixInfo->ProcessSid = (PSID)((ULONG_PTR)pDest - (ULONG_PTR)pProcessBuffer);
  899. pDest += SizeOfSid;
  900. }
  901. }
  902. pDestCitrixInfo->Pad = 0;
  903. //
  904. // Copy the image file name
  905. //
  906. if ((pSrcProcessInfo->ImageName.Buffer != NULL) && (pSrcProcessInfo->ImageName.Length != 0) )
  907. {
  908. memcpy(pDest, pSrcProcessInfo->ImageName.Buffer, pSrcProcessInfo->ImageName.Length);
  909. pDestProcessInfo->ImageName.Buffer = (PWSTR) ((ULONG_PTR)pDest - (ULONG_PTR)pProcessBuffer);
  910. pDestProcessInfo->ImageName.Length = pSrcProcessInfo->ImageName.Length;
  911. pDest += (pSrcProcessInfo->ImageName.Length);
  912. memcpy(pDest,L"\0",sizeof(WCHAR));
  913. pDest += sizeof(WCHAR);
  914. }
  915. else
  916. {
  917. pDestProcessInfo->ImageName.Buffer = NULL;
  918. pDestProcessInfo->ImageName.Length = 0;
  919. }
  920. //
  921. // loop...
  922. //
  923. if( pSrcProcessInfo->NextEntryOffset == 0 )
  924. {
  925. pDestProcessInfo->NextEntryOffset = 0;
  926. break;
  927. }
  928. pDestProcessInfo->NextEntryOffset =
  929. (ULONG)((ULONG_PTR)pDest - (ULONG_PTR)pDestProcessInfo);
  930. pDestProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pDest;
  931. TotalOffset += pSrcProcessInfo->NextEntryOffset;
  932. pSrcProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pSrcProcessBuffer[TotalOffset];
  933. pSrc = (PBYTE)pSrcProcessInfo;
  934. }
  935. }
  936. if (Status != STATUS_CANNOT_IMPERSONATE)
  937. RevertToSelf();
  938. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  939. MemFree(pSrcProcessBuffer);
  940. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  941. #else
  942. *pResult = STATUS_NOT_SUPPORTED;
  943. return FALSE;
  944. #endif
  945. }
  946. /*******************************************************************************
  947. * AllocateGAPPointer
  948. ******************************************************************************/
  949. void __RPC_FAR * __RPC_USER
  950. AllocateGAPPointer( size_t Size )
  951. {
  952. void __RPC_FAR * pMyPointer;
  953. pMyPointer = MIDL_user_allocate(Size);
  954. if (pMyPointer != NULL)
  955. {
  956. if (gbRpcGetAllProcessesOK == TRUE)
  957. {
  958. //
  959. // store the pointer in our database
  960. // so that the RPC server stub do not try to free them.
  961. //
  962. if (!NT_SUCCESS(InsertPointerInGAPDatabase(pMyPointer)))
  963. {
  964. MIDL_user_free(pMyPointer);
  965. pMyPointer = NULL;
  966. }
  967. }
  968. else // nothing can be done
  969. {
  970. MIDL_user_free(pMyPointer);
  971. pMyPointer = NULL;
  972. }
  973. }
  974. return pMyPointer;
  975. }
  976. //********************************************************************************
  977. //
  978. // Functions used to handle the memory allocations and de-allocations
  979. // in RpcWinStationGetAllProcesses (GAP = Get All Processes)
  980. //
  981. //********************************************************************************
  982. NTSTATUS
  983. InitializeGAPPointersDatabase()
  984. {
  985. NTSTATUS Status = STATUS_SUCCESS;
  986. RtlEnterCriticalSection(&gRpcPointersDatabaseLock);
  987. {
  988. gPointersDatabaseSize = MIN_GAP_DATABASE_SIZE;
  989. gPointersDatabase = MemAlloc(MIN_GAP_DATABASE_SIZE * sizeof(PVOID));
  990. if (gPointersDatabase == NULL)
  991. {
  992. Status = STATUS_NO_MEMORY;
  993. }
  994. else
  995. {
  996. RtlZeroMemory(gPointersDatabase,MIN_GAP_DATABASE_SIZE * sizeof(PVOID));
  997. }
  998. gNbProcesses = 0;
  999. gbPointersDatabaseIsValid = FALSE;
  1000. }
  1001. RtlLeaveCriticalSection(&gRpcPointersDatabaseLock);
  1002. return Status;
  1003. }
  1004. NTSTATUS
  1005. IncreaseGAPPointersDatabaseSize()
  1006. {
  1007. NTSTATUS Status = STATUS_SUCCESS;
  1008. PVOID *NewPointersDatabase;
  1009. NewPointersDatabase = MemAlloc(gPointersDatabaseSize * 2 * sizeof(PVOID));
  1010. if (NewPointersDatabase == NULL)
  1011. {
  1012. Status = STATUS_NO_MEMORY;
  1013. }
  1014. else
  1015. {
  1016. RtlCopyMemory(NewPointersDatabase,
  1017. gPointersDatabase,
  1018. gPointersDatabaseSize * sizeof(PVOID));
  1019. RtlZeroMemory(&NewPointersDatabase[gPointersDatabaseSize],
  1020. gPointersDatabaseSize * sizeof(PVOID));
  1021. MemFree(gPointersDatabase);
  1022. gPointersDatabase = NewPointersDatabase;
  1023. gPointersDatabaseSize = gPointersDatabaseSize * 2;
  1024. }
  1025. return Status;
  1026. }
  1027. NTSTATUS
  1028. InsertPointerInGAPDatabase(PVOID Pointer)
  1029. {
  1030. ULONG i;
  1031. NTSTATUS Status = STATUS_SUCCESS;
  1032. // DBGPRINT(("TERMSRV: InsertPointerInGAPDatabase 0x%x\n",Pointer));
  1033. RtlEnterCriticalSection(&gRpcPointersDatabaseLock);
  1034. {
  1035. for (i=0; i < gPointersDatabaseSize; i++)
  1036. {
  1037. if (gPointersDatabase[i] == NULL)
  1038. {
  1039. gPointersDatabase[i] = Pointer;
  1040. break;
  1041. }
  1042. }
  1043. if (i == gPointersDatabaseSize)
  1044. {
  1045. Status = IncreaseGAPPointersDatabaseSize();
  1046. if (NT_SUCCESS(Status))
  1047. {
  1048. gPointersDatabase[i] = Pointer;
  1049. }
  1050. }
  1051. }
  1052. RtlLeaveCriticalSection(&gRpcPointersDatabaseLock);
  1053. return Status;
  1054. }
  1055. VOID
  1056. ReleaseGAPPointersDatabase()
  1057. {
  1058. PTS_ALL_PROCESSES_INFO_NT6 pProcessArray;
  1059. ULONG i;
  1060. if (gPointersDatabase != NULL)
  1061. {
  1062. RtlEnterCriticalSection(&gRpcPointersDatabaseLock);
  1063. {
  1064. //
  1065. // free all the "autonomic" pointers
  1066. //
  1067. // the first one is ProcessArray
  1068. if ((gPointersDatabase[0] != NULL) && (gNbProcesses != 0))
  1069. {
  1070. pProcessArray = (PTS_ALL_PROCESSES_INFO_NT6) gPointersDatabase[0];
  1071. //
  1072. // free the Process Info buffer
  1073. //
  1074. if (pProcessArray[0].pTsProcessInfo != NULL)
  1075. {
  1076. LocalFree(pProcessArray[0].pTsProcessInfo);
  1077. }
  1078. //
  1079. // free all the SIDs
  1080. //
  1081. for (i=0; i < gNbProcesses ; i++)
  1082. {
  1083. if (pProcessArray[i].pSid != NULL)
  1084. {
  1085. LocalFree(pProcessArray[i].pSid);
  1086. }
  1087. }
  1088. //
  1089. // free the returned array
  1090. //
  1091. LocalFree(pProcessArray);
  1092. }
  1093. //
  1094. // free the database
  1095. //
  1096. MemFree(gPointersDatabase);
  1097. gPointersDatabase = NULL;
  1098. gNbProcesses = 0;
  1099. //
  1100. // disable the checking
  1101. //
  1102. gbPointersDatabaseIsValid = FALSE;
  1103. }
  1104. RtlLeaveCriticalSection(&gRpcPointersDatabaseLock);
  1105. }
  1106. }
  1107. BOOLEAN
  1108. PointerIsInGAPDatabase(PVOID Pointer)
  1109. {
  1110. ULONG i;
  1111. BOOLEAN bRet = FALSE;
  1112. // spend time only if necessary
  1113. if ((Pointer != NULL)
  1114. && (gbRpcGetAllProcessesOK == TRUE)
  1115. && (gbPointersDatabaseIsValid == TRUE)
  1116. )
  1117. {
  1118. RtlEnterCriticalSection(&gRpcPointersDatabaseLock);
  1119. {
  1120. // we need to check because the database may have been released
  1121. // while we were waiting for the lock
  1122. if (gPointersDatabase != NULL)
  1123. {
  1124. for (i=0; i < gPointersDatabaseSize; i++)
  1125. {
  1126. if (gPointersDatabase[i] == Pointer)
  1127. {
  1128. bRet = TRUE;
  1129. break;
  1130. }
  1131. }
  1132. }
  1133. }
  1134. RtlLeaveCriticalSection(&gRpcPointersDatabaseLock);
  1135. }
  1136. return bRet;
  1137. }
  1138. VOID
  1139. ValidateGAPPointersDatabase(ULONG n)
  1140. {
  1141. gbPointersDatabaseIsValid = TRUE;
  1142. gNbProcesses = n;
  1143. }
  1144. /*******************************************************************************
  1145. * SidCacheAdd
  1146. *
  1147. * NOTE: Do not call with GAP allocated, or otherwise controlled pointers.
  1148. ******************************************************************************/
  1149. VOID
  1150. SidCacheAdd(
  1151. HANDLE UniqueProcessId,
  1152. LARGE_INTEGER CreateTime,
  1153. PSID pNewSid
  1154. )
  1155. {
  1156. DWORD SidLength;
  1157. NTSTATUS Status;
  1158. PLIST_ENTRY pNewListEntry;
  1159. PSID_CACHE_LIST_ENTRY pNewCacheRecord;
  1160. PSID pSid;
  1161. //
  1162. // If the lock didn't initialize, bail.
  1163. //
  1164. if (!gbRpcSidCacheOK) {
  1165. return;
  1166. }
  1167. //
  1168. // Initialize memory for cache record. Failure is not a problem;
  1169. // the sid just won't be cached.
  1170. //
  1171. pNewCacheRecord = MemAlloc(sizeof(SID_CACHE_LIST_ENTRY));
  1172. if (pNewCacheRecord == NULL) {
  1173. return;
  1174. }
  1175. pNewCacheRecord->pSid = pNewSid;
  1176. pNewCacheRecord->ProcId = UniqueProcessId;
  1177. pNewCacheRecord->CreateTime = CreateTime;
  1178. pNewListEntry = &pNewCacheRecord->ListEntry;
  1179. //
  1180. // Lock the Sid Cache and add the new member.
  1181. //
  1182. RtlEnterCriticalSection(&gRpcSidCacheLock);
  1183. InsertTailList(&gSidCacheHead, pNewListEntry);
  1184. gMaxSidCacheEntries++;
  1185. RtlLeaveCriticalSection(&gRpcSidCacheLock);
  1186. }
  1187. /*******************************************************************************
  1188. *
  1189. * SidCacheFind
  1190. *
  1191. * NOTE: Use RtlLengthSid, alloc memory, and RtlCopySid for the return value!
  1192. * Otherwise, you may free memory being used by the Cache!!
  1193. *
  1194. ******************************************************************************/
  1195. PSID
  1196. SidCacheFind(
  1197. HANDLE UniqueProcessId,
  1198. LARGE_INTEGER CreateTime
  1199. )
  1200. {
  1201. PLIST_ENTRY pTempEntry;
  1202. PSID_CACHE_LIST_ENTRY pSidCacheEntry;
  1203. PSID pRetSid = NULL;
  1204. //
  1205. // If the lock didn't initialize, bail.
  1206. //
  1207. if (!gbRpcSidCacheOK) {
  1208. return(NULL);
  1209. }
  1210. //
  1211. // Lock the Sid Cache.
  1212. //
  1213. RtlEnterCriticalSection(&gRpcSidCacheLock);
  1214. //
  1215. // The list head is a place holder, start searching from the head's
  1216. // Flink. Stop when we reach the list head again.
  1217. //
  1218. pTempEntry = gSidCacheHead.Flink;
  1219. while(pTempEntry != &gSidCacheHead) {
  1220. pSidCacheEntry = CONTAINING_RECORD(
  1221. pTempEntry,
  1222. SID_CACHE_LIST_ENTRY,
  1223. ListEntry
  1224. );
  1225. if (pSidCacheEntry->ProcId != UniqueProcessId) {
  1226. pTempEntry = pTempEntry->Flink;
  1227. } else {
  1228. if (pSidCacheEntry->CreateTime.QuadPart == CreateTime.QuadPart) {
  1229. pRetSid = pSidCacheEntry->pSid;
  1230. } else {
  1231. //
  1232. // If the PID matches, but the create time doesn't, this record is
  1233. // stale. Remove it from the list and free the memory associated with
  1234. // it. There can only be one entry in the cache per PID, therefore,
  1235. // stop searching after freeing.
  1236. //
  1237. RemoveEntryList(pTempEntry);
  1238. if (pSidCacheEntry->pSid != NULL) {
  1239. MemFree(pSidCacheEntry->pSid);
  1240. }
  1241. MemFree(pSidCacheEntry);
  1242. }
  1243. break;
  1244. }
  1245. }
  1246. //
  1247. // Release the Sid Cache.
  1248. //
  1249. RtlLeaveCriticalSection(&gRpcSidCacheLock);
  1250. return(pRetSid);
  1251. }
  1252. /*******************************************************************************
  1253. *
  1254. * SidCacheFree
  1255. *
  1256. *
  1257. ******************************************************************************/
  1258. VOID
  1259. SidCacheFree(
  1260. PLIST_ENTRY pListHead
  1261. )
  1262. {
  1263. PLIST_ENTRY pTempEntry = pListHead->Flink;
  1264. //
  1265. // Lock the Sid Cache.
  1266. //
  1267. RtlEnterCriticalSection(&gRpcSidCacheLock);
  1268. //
  1269. // The list head is a place holder, start freeing from the head's
  1270. // Flink. Stop when we reach the list head again.
  1271. //
  1272. while (pTempEntry != pListHead) {
  1273. PSID_CACHE_LIST_ENTRY pSidCacheEntry;
  1274. pSidCacheEntry = CONTAINING_RECORD(
  1275. pTempEntry,
  1276. SID_CACHE_LIST_ENTRY,
  1277. ListEntry
  1278. );
  1279. if (pSidCacheEntry->pSid != NULL) {
  1280. MemFree(pSidCacheEntry->pSid);
  1281. }
  1282. RemoveEntryList(pTempEntry);
  1283. pTempEntry = pTempEntry->Flink;
  1284. MemFree(pSidCacheEntry);
  1285. }
  1286. //
  1287. // Release the Sid Cache.
  1288. //
  1289. RtlLeaveCriticalSection(&gRpcSidCacheLock);
  1290. }
  1291. /*******************************************************************************
  1292. *
  1293. * SidCacheUpdate
  1294. *
  1295. *
  1296. ******************************************************************************/
  1297. VOID
  1298. SidCacheUpdate(
  1299. VOID
  1300. )
  1301. {
  1302. //
  1303. // TODO: Figure out a way to get rid of stale cache entries!
  1304. //
  1305. }
  1306. /*******************************************************************************
  1307. *
  1308. * GetSidFromProcessId
  1309. *
  1310. * NOTE: GetSid returns a normal, local memory pointer. The caller should
  1311. * copy this sid based on its needs. For example, RpcWinStationGAP
  1312. * would copy this sid to a GAP pointer. The caller should NOT free
  1313. * the returned pointer, as it is also being cached!
  1314. *
  1315. ******************************************************************************/
  1316. NTSTATUS
  1317. GetSidFromProcessId(
  1318. HANDLE UniqueProcessId,
  1319. LARGE_INTEGER CreateTime,
  1320. PSID *ppProcessSid,
  1321. BOOLEAN ImpersonatingClient
  1322. )
  1323. {
  1324. BOOLEAN bResult = FALSE;
  1325. DWORD ReturnLength;
  1326. DWORD BufferLength;
  1327. DWORD SidLength;
  1328. PSID pSid;
  1329. NTSTATUS Status;
  1330. PTOKEN_USER pTokenUser = NULL;
  1331. HANDLE hProcess = NULL;
  1332. HANDLE hToken;
  1333. OBJECT_ATTRIBUTES ObjectAttributes;
  1334. CLIENT_ID ClientId;
  1335. KERNEL_USER_TIMES TimeInfo;
  1336. BOOLEAN ImpersonateAgain = FALSE;
  1337. RPC_STATUS RpcStatus;
  1338. //
  1339. // Look in sid cache first. Do it only for Admins.
  1340. //
  1341. if ( IsCallerAdmin() ) {
  1342. *ppProcessSid = SidCacheFind(UniqueProcessId, CreateTime);
  1343. if (*ppProcessSid != NULL) {
  1344. return(STATUS_SUCCESS);
  1345. }
  1346. }
  1347. //
  1348. // Take the long road...
  1349. // Get the Process Handle
  1350. //
  1351. InitializeObjectAttributes(
  1352. &ObjectAttributes,
  1353. NULL,
  1354. 0,
  1355. NULL,
  1356. NULL
  1357. );
  1358. ClientId.UniqueThread = (HANDLE)NULL;
  1359. ClientId.UniqueProcess = (HANDLE)UniqueProcessId;
  1360. // For Admins, we revert to system context before getting the SID.
  1361. // This is a hack. Ideally, process ACLs should have been set appropriately.
  1362. if ( ImpersonatingClient && IsCallerAdmin() ) {
  1363. RpcStatus = RpcRevertToSelf();
  1364. if (RpcStatus == RPC_S_OK) {
  1365. ImpersonateAgain = TRUE;
  1366. }
  1367. }
  1368. // This should now pass. If not, then this is not a permission issue.
  1369. Status = NtOpenProcess(
  1370. &hProcess,
  1371. PROCESS_QUERY_INFORMATION,
  1372. &ObjectAttributes,
  1373. &ClientId
  1374. );
  1375. if (NT_SUCCESS(Status)) {
  1376. //
  1377. // Get the Process CreateTime information
  1378. //
  1379. Status = NtQueryInformationProcess(
  1380. hProcess,
  1381. ProcessTimes,
  1382. (PVOID)&TimeInfo,
  1383. sizeof(TimeInfo),
  1384. NULL
  1385. );
  1386. //
  1387. // Verify that the passed in PID and CreateTime match
  1388. // the current environment (i.e. don't bother getting
  1389. // information on a stale PID).
  1390. //
  1391. if (NT_SUCCESS(Status)) {
  1392. if ((TimeInfo.CreateTime.LowPart != CreateTime.LowPart) ||
  1393. (TimeInfo.CreateTime.HighPart != CreateTime.HighPart)) {
  1394. CloseHandle(hProcess);
  1395. Status = STATUS_INVALID_HANDLE;
  1396. goto ReturnStatus;
  1397. }
  1398. } else {
  1399. CloseHandle(hProcess);
  1400. goto ReturnStatus;
  1401. }
  1402. //
  1403. // Get the Process Token
  1404. //
  1405. Status = NtOpenProcessToken(
  1406. hProcess,
  1407. TOKEN_QUERY,
  1408. &hToken
  1409. );
  1410. if (NT_SUCCESS(Status)) {
  1411. //
  1412. // Query the TokenUser size, then allocate space
  1413. // and re-query.
  1414. //
  1415. Status = NtQueryInformationToken(
  1416. hToken,
  1417. TokenUser,
  1418. NULL,
  1419. 0,
  1420. &ReturnLength
  1421. );
  1422. if (ReturnLength == 0) {
  1423. CloseHandle(hProcess);
  1424. CloseHandle(hToken);
  1425. goto ReturnStatus;
  1426. }
  1427. BufferLength = ReturnLength;
  1428. pTokenUser = MemAlloc(BufferLength);
  1429. if( pTokenUser == NULL ) {
  1430. CloseHandle(hProcess);
  1431. CloseHandle(hToken);
  1432. Status = STATUS_NO_MEMORY;
  1433. goto ReturnStatus;
  1434. }
  1435. Status = NtQueryInformationToken(
  1436. hToken,
  1437. TokenUser,
  1438. pTokenUser,
  1439. BufferLength,
  1440. &ReturnLength
  1441. );
  1442. CloseHandle(hToken);
  1443. if (NT_SUCCESS(Status)) {
  1444. //
  1445. // A valid Sid has been found; copy it and add it to
  1446. // the cache.
  1447. //
  1448. SidLength = RtlLengthSid(pTokenUser->User.Sid);
  1449. pSid = MemAlloc(SidLength);
  1450. if (pSid != NULL) {
  1451. Status = RtlCopySid(
  1452. SidLength,
  1453. pSid,
  1454. pTokenUser->User.Sid
  1455. );
  1456. if (NT_SUCCESS(Status)) {
  1457. *ppProcessSid = pSid;
  1458. bResult = TRUE;
  1459. SidCacheAdd(UniqueProcessId, CreateTime, pSid);
  1460. }
  1461. } else {
  1462. Status = STATUS_NO_MEMORY;
  1463. }
  1464. }
  1465. MemFree(pTokenUser);
  1466. }
  1467. CloseHandle(hProcess);
  1468. }
  1469. ReturnStatus:
  1470. if (ImpersonateAgain) {
  1471. RpcStatus = RpcImpersonateClient( NULL );
  1472. if ( RpcStatus != RPC_S_OK )
  1473. Status = STATUS_CANNOT_IMPERSONATE;
  1474. }
  1475. return(Status);
  1476. }
  1477. VOID
  1478. CheckSidCacheSize()
  1479. {
  1480. // if cache has grown over limit, free all the entries
  1481. // and reset the cache entries counter
  1482. if (gMaxSidCacheEntries >= MAX_SID_CACHE_ENTRIES) {
  1483. SidCacheFree(&gSidCacheHead);
  1484. InitializeListHead(&gSidCacheHead);
  1485. gMaxSidCacheEntries = 0;
  1486. }
  1487. }
  1488. //
  1489. // This function converts sys buffer to ts buffer. also counts the processes, and returns array procids.
  1490. // CALLER NEED TO LocalFree the *ppProcIds, thats allocaed.
  1491. NTSTATUS ConvertSysBufferToTSBuffer(PBYTE *ppSysProcessBuffer, DWORD ByteCount, ULONG *pProcesses, PHANDLE *ppProcIds)
  1492. {
  1493. PBYTE pTSProcessBuffer = NULL;
  1494. PSYSTEM_PROCESS_INFORMATION pSysProcessInfo = NULL;
  1495. PTS_SYS_PROCESS_INFORMATION_NT6 pTSProcessInfo = NULL;
  1496. ULONG TotalOffset = 0;
  1497. ULONG TotalTSOffset = 0;
  1498. ULONG TotalTmpOffset = 0;
  1499. ULONG CurrentOffset = 0;
  1500. ULONG CurrentSessionId = INVALID_SESSIONID;
  1501. HANDLE *pProcessIds = NULL;
  1502. UINT uiNumProcess = 0;
  1503. NTSTATUS Status;
  1504. PWINSTATION pWinStation = NULL;
  1505. ASSERT(ppSysProcessBuffer);
  1506. ASSERT(*ppSysProcessBuffer);
  1507. ASSERT(ByteCount);
  1508. ASSERT(pProcesses);
  1509. ASSERT(ppProcIds);
  1510. // allocate target buffer.
  1511. pTSProcessBuffer = MIDL_user_allocate(ByteCount);
  1512. if (pTSProcessBuffer == NULL)
  1513. {
  1514. *ppProcIds = NULL;
  1515. *pProcesses = 0;
  1516. return STATUS_NO_MEMORY;
  1517. }
  1518. uiNumProcess = 0;
  1519. TotalOffset = 0;
  1520. //count number of processes
  1521. do
  1522. {
  1523. ASSERT(TotalOffset < ByteCount);
  1524. pSysProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &((*ppSysProcessBuffer)[TotalOffset]);
  1525. TotalOffset += pSysProcessInfo->NextEntryOffset;
  1526. uiNumProcess++;
  1527. }
  1528. while (pSysProcessInfo->NextEntryOffset != 0);
  1529. // allocate memory for process ids.
  1530. pProcessIds = LocalAlloc(LMEM_FIXED, sizeof(HANDLE) * uiNumProcess);
  1531. if (!pProcessIds)
  1532. {
  1533. MIDL_user_free(pTSProcessBuffer);
  1534. *ppProcIds = NULL;
  1535. *pProcesses = 0;
  1536. return STATUS_NO_MEMORY;
  1537. }
  1538. uiNumProcess = 0;
  1539. TotalOffset = 0;
  1540. TotalTSOffset = 0;
  1541. do
  1542. {
  1543. ASSERT(TotalOffset < ByteCount);
  1544. pSysProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &((*ppSysProcessBuffer)[TotalOffset]);
  1545. CurrentSessionId = pSysProcessInfo->SessionId;
  1546. if(CurrentSessionId == INVALID_SESSIONID)
  1547. {
  1548. TotalOffset += pSysProcessInfo->NextEntryOffset;
  1549. CurrentOffset = pSysProcessInfo->NextEntryOffset;
  1550. continue;
  1551. }
  1552. /*
  1553. * Find and lock client WinStation
  1554. */
  1555. pWinStation = FindWinStationById( CurrentSessionId, FALSE );
  1556. if ( pWinStation == NULL )
  1557. {
  1558. //
  1559. //The session this process belongs to, might already be gone.
  1560. //Don't fail here, just skip the process.
  1561. //
  1562. pSysProcessInfo->SessionId = INVALID_SESSIONID;
  1563. TotalOffset += pSysProcessInfo->NextEntryOffset;
  1564. CurrentOffset = pSysProcessInfo->NextEntryOffset;
  1565. continue;
  1566. }
  1567. Status = RpcCheckClientAccess( pWinStation, WINSTATION_QUERY, TRUE );
  1568. ReleaseWinStation( pWinStation );
  1569. TotalTmpOffset = TotalOffset;
  1570. TotalOffset += pSysProcessInfo->NextEntryOffset;
  1571. CurrentOffset = pSysProcessInfo->NextEntryOffset;
  1572. do
  1573. {
  1574. pSysProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &((*ppSysProcessBuffer)[TotalTmpOffset]);
  1575. if(pSysProcessInfo->SessionId != CurrentSessionId)
  1576. {
  1577. TotalTmpOffset += pSysProcessInfo->NextEntryOffset;
  1578. continue;
  1579. }
  1580. if ( NT_SUCCESS( Status ) )
  1581. {
  1582. pTSProcessInfo = (PTS_SYS_PROCESS_INFORMATION_NT6)&(pTSProcessBuffer[TotalTSOffset]);
  1583. // now copy the information over.
  1584. /* ULONG */ pTSProcessInfo->NextEntryOffset = sizeof(TS_SYS_PROCESS_INFORMATION_NT6) +
  1585. pSysProcessInfo->ImageName.MaximumLength;//pSysProcessInfo->NextEntryOffset;
  1586. /* ULONG */ pTSProcessInfo->NumberOfThreads = pSysProcessInfo->NumberOfThreads;
  1587. /* LARGE_INTEGER */ pTSProcessInfo->SpareLi1 = pSysProcessInfo->SpareLi1;
  1588. /* LARGE_INTEGER */ pTSProcessInfo->SpareLi2 = pSysProcessInfo->SpareLi2;
  1589. /* LARGE_INTEGER */ pTSProcessInfo->SpareLi3 = pSysProcessInfo->SpareLi3;
  1590. /* LARGE_INTEGER */ pTSProcessInfo->CreateTime = pSysProcessInfo->CreateTime;
  1591. /* LARGE_INTEGER */ pTSProcessInfo->UserTime = pSysProcessInfo->UserTime;
  1592. /* LARGE_INTEGER */ pTSProcessInfo->KernelTime = pSysProcessInfo->KernelTime;
  1593. if (pSysProcessInfo->ImageName.Buffer != NULL && pSysProcessInfo->ImageName.Length != 0)
  1594. {
  1595. pTSProcessInfo->ImageName.Buffer = (PWSTR)((PBYTE)pTSProcessInfo + sizeof(TS_SYS_PROCESS_INFORMATION_NT6));
  1596. memcpy(pTSProcessInfo->ImageName.Buffer, pSysProcessInfo->ImageName.Buffer, pSysProcessInfo->ImageName.MaximumLength );
  1597. pTSProcessInfo->ImageName.Length = pSysProcessInfo->ImageName.Length;
  1598. pTSProcessInfo->ImageName.MaximumLength = pSysProcessInfo->ImageName.MaximumLength;
  1599. }
  1600. else
  1601. {
  1602. pTSProcessInfo->ImageName.Buffer = NULL;
  1603. pTSProcessInfo->ImageName.Length = 0;
  1604. }
  1605. /* KPRIORITY */ pTSProcessInfo->BasePriority = pSysProcessInfo->BasePriority;
  1606. /* HANDLE */ pTSProcessInfo->UniqueProcessId = HandleToULong(pSysProcessInfo->UniqueProcessId);
  1607. /* HANDLE */ pTSProcessInfo->InheritedFromUniqueProcessId = HandleToULong(pSysProcessInfo->InheritedFromUniqueProcessId);
  1608. /* ULONG */ pTSProcessInfo->HandleCount = pSysProcessInfo->HandleCount;
  1609. /* ULONG */ pTSProcessInfo->SessionId = pSysProcessInfo->SessionId;
  1610. // /* ULONG_PTR */ pTSProcessInfo->PageDirectoryBase = pSysProcessInfo->PageDirectoryBase;
  1611. /* SIZE_T */ pTSProcessInfo->PeakVirtualSize = pSysProcessInfo->PeakVirtualSize;
  1612. /* SIZE_T */ pTSProcessInfo->VirtualSize = pSysProcessInfo->VirtualSize;
  1613. /* ULONG */ pTSProcessInfo->PageFaultCount = pSysProcessInfo->PageFaultCount;
  1614. /* SIZE_T */ pTSProcessInfo->PeakWorkingSetSize = (ULONG)pSysProcessInfo->PeakWorkingSetSize;
  1615. /* SIZE_T */ pTSProcessInfo->WorkingSetSize = (ULONG)pSysProcessInfo->WorkingSetSize;
  1616. /* SIZE_T */ pTSProcessInfo->QuotaPeakPagedPoolUsage = (ULONG)pSysProcessInfo->QuotaPeakPagedPoolUsage;
  1617. /* SIZE_T */ pTSProcessInfo->QuotaPagedPoolUsage = (ULONG)pSysProcessInfo->QuotaPagedPoolUsage;
  1618. /* SIZE_T */ pTSProcessInfo->QuotaPeakNonPagedPoolUsage = (ULONG)pSysProcessInfo->QuotaPeakNonPagedPoolUsage;
  1619. /* SIZE_T */ pTSProcessInfo->QuotaNonPagedPoolUsage = (ULONG)pSysProcessInfo->QuotaNonPagedPoolUsage;
  1620. /* SIZE_T */ pTSProcessInfo->PagefileUsage = (ULONG)pSysProcessInfo->PagefileUsage;
  1621. /* SIZE_T */ pTSProcessInfo->PeakPagefileUsage = (ULONG)pSysProcessInfo->PeakPagefileUsage;
  1622. /* SIZE_T */ pTSProcessInfo->PrivatePageCount = (ULONG)pSysProcessInfo->PrivatePageCount;
  1623. //
  1624. // now keep the original pid form the original buffer,
  1625. //we have lost some data while converting it to ts format.
  1626. pProcessIds[uiNumProcess] = pSysProcessInfo->UniqueProcessId;
  1627. TotalTSOffset += pTSProcessInfo->NextEntryOffset;
  1628. uiNumProcess++;
  1629. }
  1630. pSysProcessInfo->SessionId = INVALID_SESSIONID;
  1631. TotalTmpOffset += pSysProcessInfo->NextEntryOffset;
  1632. }
  1633. while (pSysProcessInfo->NextEntryOffset != 0);
  1634. }
  1635. while (CurrentOffset != 0);
  1636. if ( !uiNumProcess )
  1637. {
  1638. LocalFree(pProcessIds);
  1639. MIDL_user_free(pTSProcessBuffer);
  1640. *ppProcIds = NULL;
  1641. *pProcesses = 0;
  1642. return STATUS_ACCESS_DENIED;
  1643. }
  1644. // now lets get rid of the original buffer, and replace it with our new TS process buffer
  1645. LocalFree(*ppSysProcessBuffer);
  1646. *ppProcIds = pProcessIds;
  1647. *pProcesses = uiNumProcess;
  1648. *ppSysProcessBuffer = pTSProcessBuffer;
  1649. return STATUS_SUCCESS;
  1650. }
  1651. /***********************************************************************************************************
  1652. * WinStationGetAllProcessesWorker
  1653. *
  1654. * Worker routine for RpcWinStationGetAllProcesses(Win2K) and RpcWinStationGetAllProcesses_NT6(Whistler).
  1655. *
  1656. * EXIT:
  1657. * TRUE -- The query succeeded, and the buffer contains the requested data.
  1658. * FALSE -- The operation failed. Extended error status is returned in pResult.
  1659. ***********************************************************************************************************/
  1660. BOOLEAN
  1661. WinStationGetAllProcessesWorker(
  1662. HANDLE hServer,
  1663. DWORD *pResult,
  1664. ULONG Level,
  1665. ULONG *pNumberOfProcesses,
  1666. PBYTE *ppTsAllProcessesInfo
  1667. )
  1668. {
  1669. PTS_SYS_PROCESS_INFORMATION_NT6 pProcessInfo = NULL;
  1670. PTS_ALL_PROCESSES_INFO_NT6 pProcessArray = NULL;
  1671. ULONG TotalOffset;
  1672. ULONG NumberOfProcesses = 1; // at least 1 process
  1673. ULONG i;
  1674. RPC_STATUS RpcStatus;
  1675. NTSTATUS Status = STATUS_INFO_LENGTH_MISMATCH; // Assume that this length is wrong. In fact it *is* wrong initially.
  1676. if (gbRpcGetAllProcessesOK == FALSE)
  1677. {
  1678. *pResult = STATUS_NO_MEMORY;
  1679. *pNumberOfProcesses = 0;
  1680. *ppTsAllProcessesInfo = NULL;
  1681. return FALSE;
  1682. }
  1683. //
  1684. // this critical section will be released in
  1685. // RpcWinStationGetAllProcesses_notify_flag
  1686. //
  1687. RtlEnterCriticalSection(&gRpcGetAllProcessesLock);
  1688. RpcStatus = RpcImpersonateClient( NULL );
  1689. if( RpcStatus != RPC_S_OK ) {
  1690. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: WinStationGetAllProcessesWorker RpcImpersonateClient failed! %d\n",RpcStatus));
  1691. *pResult = STATUS_ACCESS_DENIED;
  1692. *pNumberOfProcesses = 0;
  1693. *ppTsAllProcessesInfo = NULL;
  1694. return FALSE;
  1695. }
  1696. // Check if SID cache hasn't grown too much
  1697. CheckSidCacheSize();
  1698. if (!NT_SUCCESS(InitializeGAPPointersDatabase()))
  1699. {
  1700. RpcRevertToSelf();
  1701. *pResult = STATUS_NO_MEMORY;
  1702. *pNumberOfProcesses = 0;
  1703. *ppTsAllProcessesInfo = NULL;
  1704. return FALSE;
  1705. }
  1706. //
  1707. // make sure requested information level is known
  1708. //
  1709. if (Level != GAP_LEVEL_BASIC) // only info level known on this version
  1710. {
  1711. *pResult = STATUS_NOT_IMPLEMENTED;
  1712. }
  1713. else // OK
  1714. {
  1715. PBYTE pProcessBuffer = NULL;
  1716. PSID pSid;
  1717. DWORD RequiredByteCount = 0;
  1718. DWORD ByteCount = (MAX_PATH*sizeof(WCHAR)) + 1; // Give the minimum length first. We will get the correct on subsequent calls.
  1719. HANDLE *pProcessids = NULL;
  1720. while ( Status == STATUS_INFO_LENGTH_MISMATCH)
  1721. {
  1722. //
  1723. // Allocate a buffer
  1724. //
  1725. pProcessBuffer = MIDL_user_allocate(ByteCount);
  1726. if (pProcessBuffer == NULL)
  1727. {
  1728. Status = STATUS_NO_MEMORY;
  1729. *pResult = STATUS_NO_MEMORY;
  1730. *pNumberOfProcesses = 0;
  1731. *ppTsAllProcessesInfo = NULL;
  1732. break;
  1733. }
  1734. //
  1735. // Perform process enumeration.
  1736. // NOTE: We had a mismatch in the structure for the process information in Win2K and whistler from RPC point of view.
  1737. // Win2K RPC interpretes the size of the image name is twice of what whistler does. So, to take care of this problem,
  1738. // where Win2K client may call Whistler server, we will allocate more bytes than actually required. So, we will pass
  1739. // less number of bytes to the system call by the same amount.
  1740. //
  1741. Status = NtQuerySystemInformation( SystemProcessInformation,
  1742. (PVOID)pProcessBuffer,
  1743. ByteCount - (MAX_PATH*sizeof(WCHAR)),
  1744. &RequiredByteCount );
  1745. if (Status == STATUS_INFO_LENGTH_MISMATCH)
  1746. {
  1747. // Allocate little more bytes than required.
  1748. ByteCount = RequiredByteCount + (MAX_PATH*sizeof(WCHAR));
  1749. MIDL_user_free(pProcessBuffer);
  1750. }
  1751. }
  1752. if ( Status != STATUS_SUCCESS)
  1753. {
  1754. *pResult = STATUS_NO_MEMORY;
  1755. if (pProcessBuffer != NULL)
  1756. {
  1757. MIDL_user_free(pProcessBuffer);
  1758. pProcessBuffer = NULL;
  1759. }
  1760. }
  1761. else
  1762. {
  1763. Status = ConvertSysBufferToTSBuffer(&pProcessBuffer, ByteCount, &NumberOfProcesses, &pProcessids);
  1764. if (Status != STATUS_SUCCESS)
  1765. {
  1766. // failed to convert sysbuffer to ts buffer.
  1767. // lets bail out.
  1768. *pResult = Status;
  1769. if (pProcessBuffer != NULL)
  1770. {
  1771. MIDL_user_free(pProcessBuffer);
  1772. pProcessBuffer = NULL;
  1773. }
  1774. }
  1775. else // everything's fine
  1776. {
  1777. ASSERT(pProcessids);
  1778. ASSERT(pProcessBuffer);
  1779. ASSERT(NumberOfProcesses > 0);
  1780. pProcessArray = AllocateGAPPointer(NumberOfProcesses * sizeof(TS_ALL_PROCESSES_INFO_NT6));
  1781. if (pProcessArray == NULL)
  1782. {
  1783. *pResult = STATUS_NO_MEMORY;
  1784. MIDL_user_free(pProcessBuffer);
  1785. pProcessBuffer = NULL;
  1786. }
  1787. else
  1788. {
  1789. RtlZeroMemory(pProcessArray,
  1790. NumberOfProcesses * sizeof(TS_ALL_PROCESSES_INFO_NT6));
  1791. *pResult = STATUS_SUCCESS;
  1792. pProcessInfo = (PTS_SYS_PROCESS_INFORMATION_NT6)pProcessBuffer;
  1793. TotalOffset = 0;
  1794. //
  1795. // Walk the returned buffer again to set the correct pointers in pProcessArray
  1796. //
  1797. for (i=0; i < NumberOfProcesses; i++)
  1798. {
  1799. pProcessArray[i].pTsProcessInfo = (PTS_SYS_PROCESS_INFORMATION_NT6)pProcessInfo;
  1800. //
  1801. // keep some trace of the "internal" pointers
  1802. // so that the RPC server stub do not try to free them.
  1803. //
  1804. if (!NT_SUCCESS(InsertPointerInGAPDatabase(pProcessArray[i].pTsProcessInfo)))
  1805. {
  1806. *pResult = STATUS_NO_MEMORY;
  1807. break;
  1808. }
  1809. if ( pProcessInfo->ImageName.Buffer )
  1810. {
  1811. if (!NT_SUCCESS(InsertPointerInGAPDatabase(pProcessInfo->ImageName.Buffer)))
  1812. {
  1813. *pResult = STATUS_NO_MEMORY;
  1814. break;
  1815. }
  1816. }
  1817. //
  1818. // Get the Sid
  1819. //
  1820. Status = GetSidFromProcessId(
  1821. pProcessids[i],
  1822. pProcessInfo->CreateTime,
  1823. &pSid,
  1824. TRUE
  1825. );
  1826. if (Status == STATUS_CANNOT_IMPERSONATE)
  1827. {
  1828. *pResult = STATUS_ACCESS_DENIED;
  1829. break;
  1830. }
  1831. if (NT_SUCCESS(Status))
  1832. {
  1833. //
  1834. // set the length for the Sid
  1835. //
  1836. pProcessArray[i].SizeOfSid = RtlLengthSid(pSid);
  1837. // GAP allocate a pointer and copy!
  1838. pProcessArray[i].pSid = AllocateGAPPointer(
  1839. pProcessArray[i].SizeOfSid
  1840. );
  1841. if (pProcessArray[i].pSid == NULL) {
  1842. *pResult = STATUS_NO_MEMORY;
  1843. break;
  1844. }
  1845. *pResult = RtlCopySid(
  1846. pProcessArray[i].SizeOfSid,
  1847. pProcessArray[i].pSid,
  1848. pSid
  1849. );
  1850. if (!(NT_SUCCESS(*pResult))) {
  1851. break;
  1852. }
  1853. }
  1854. else
  1855. {
  1856. //
  1857. // set a NULL Sid
  1858. //
  1859. pProcessArray[i].pSid = NULL;
  1860. pProcessArray[i].SizeOfSid = 0;
  1861. }
  1862. //
  1863. // next entry
  1864. //
  1865. TotalOffset += pProcessInfo->NextEntryOffset;
  1866. pProcessInfo = (PTS_SYS_PROCESS_INFORMATION_NT6)&pProcessBuffer[TotalOffset];
  1867. }
  1868. if (*pResult != STATUS_SUCCESS) // we finally failed !
  1869. {
  1870. // DBGPRINT(( "TERMSRV: RpcWinStationGAP: ultimate failure\n"));
  1871. //
  1872. // free all SIDs
  1873. //
  1874. for (i=0; i < NumberOfProcesses; i++)
  1875. {
  1876. if (pProcessArray[i].pSid != NULL)
  1877. {
  1878. LocalFree(pProcessArray[i].pSid);
  1879. }
  1880. }
  1881. //
  1882. // free the array
  1883. //
  1884. LocalFree(pProcessArray);
  1885. pProcessArray = NULL;
  1886. //
  1887. // free the buffer
  1888. //
  1889. MIDL_user_free(pProcessBuffer);
  1890. pProcessBuffer = NULL;
  1891. }
  1892. }
  1893. if (pProcessids)
  1894. LocalFree(pProcessids);
  1895. }
  1896. }
  1897. }
  1898. if (NT_SUCCESS(*pResult))
  1899. {
  1900. // DBGPRINT(( "TERMSRV: RpcWinStationGAP: Everything went fine\n"));
  1901. //
  1902. // From that moment, we may receive some MIDL_user_free
  1903. // so enable the database checking
  1904. //
  1905. ValidateGAPPointersDatabase(NumberOfProcesses);
  1906. *pNumberOfProcesses = NumberOfProcesses;
  1907. *ppTsAllProcessesInfo = (PBYTE) pProcessArray;
  1908. }
  1909. else // error case
  1910. {
  1911. *pNumberOfProcesses = 0;
  1912. *ppTsAllProcessesInfo = NULL;
  1913. }
  1914. if (Status != STATUS_CANNOT_IMPERSONATE)
  1915. RpcRevertToSelf();
  1916. return ( (NT_SUCCESS(*pResult))? TRUE : FALSE);
  1917. }
  1918. /*******************************************************************************
  1919. * RpcWinStationGetAllProcesses_NT6
  1920. *
  1921. * Replaces RpcWinStationGetAllProcesses for Win2K servers.
  1922. *
  1923. * EXIT:
  1924. * TRUE -- The query succeeded, and the buffer contains the requested data.
  1925. * FALSE -- The operation failed. Extended error status is returned in pResult.
  1926. ******************************************************************************/
  1927. BOOLEAN
  1928. RpcWinStationGetAllProcesses_NT6(
  1929. HANDLE hServer,
  1930. DWORD *pResult,
  1931. ULONG Level,
  1932. ULONG *pNumberOfProcesses,
  1933. PTS_ALL_PROCESSES_INFO_NT6 *ppTsAllProcessesInfo
  1934. )
  1935. {
  1936. BOOLEAN Result;
  1937. PTS_ALL_PROCESSES_INFO_NT6 pProcessInfo;
  1938. if(!hServer)
  1939. {
  1940. *pResult = STATUS_UNSUCCESSFUL;
  1941. return( FALSE );
  1942. }
  1943. Result = WinStationGetAllProcessesWorker(
  1944. hServer,
  1945. pResult,
  1946. Level,
  1947. pNumberOfProcesses,
  1948. (PBYTE *)&pProcessInfo
  1949. );
  1950. *ppTsAllProcessesInfo = pProcessInfo;
  1951. return Result;
  1952. }
  1953. /*******************************************************************************
  1954. *
  1955. * RpcWinStationGetAllProcesses
  1956. *
  1957. * Replaces RpcWinStationEnumerateProcesses for NT5.0 servers.
  1958. * (Now used only by winsta client of Win2K)
  1959. *
  1960. * ENTRY:
  1961. *
  1962. * EXIT:
  1963. *
  1964. * TRUE -- The query succeeded, and the buffer contains the requested data.
  1965. *
  1966. * FALSE -- The operation failed. Extended error status is returned in pResult.
  1967. *
  1968. ******************************************************************************/
  1969. BOOLEAN
  1970. RpcWinStationGetAllProcesses(
  1971. HANDLE hServer,
  1972. DWORD *pResult,
  1973. ULONG Level,
  1974. ULONG *pNumberOfProcesses,
  1975. PTS_ALL_PROCESSES_INFO *ppTsAllProcessesInfo
  1976. )
  1977. {
  1978. BOOLEAN Result;
  1979. PTS_ALL_PROCESSES_INFO pProcessInfo;
  1980. if(!hServer)
  1981. {
  1982. *pResult = STATUS_UNSUCCESSFUL;
  1983. return( FALSE );
  1984. }
  1985. Result = WinStationGetAllProcessesWorker(
  1986. hServer,
  1987. pResult,
  1988. Level,
  1989. pNumberOfProcesses,
  1990. (PBYTE *)&pProcessInfo
  1991. );
  1992. *ppTsAllProcessesInfo = pProcessInfo;
  1993. return Result;
  1994. }
  1995. /*******************************************************************************
  1996. * RpcWinStationGetLanAdapterName
  1997. *
  1998. * EXIT:
  1999. * TRUE -- The query succeeded, and the buffer contains the requested data.
  2000. * FALSE -- The operation failed. Extended error status is returned in pResult.
  2001. ******************************************************************************/
  2002. #define RELEASEPTR(iPointer) \
  2003. if (iPointer) { \
  2004. iPointer->lpVtbl->Release(iPointer); \
  2005. iPointer = NULL; \
  2006. }
  2007. BOOLEAN RpcWinStationGetLanAdapterName(
  2008. HANDLE hServer,
  2009. DWORD *pResult,
  2010. DWORD PdNameSize,
  2011. PWCHAR pPdName,
  2012. ULONG LanAdapter,
  2013. ULONG *pLength,
  2014. PWCHAR *ppLanAdapterName)
  2015. {
  2016. HRESULT hResult = S_OK;
  2017. HRESULT hr = S_OK;
  2018. //Interface pointer declarations
  2019. WCHAR szProtocol[256];
  2020. INetCfg * pnetCfg = NULL;
  2021. INetCfgClass * pNetCfgClass = NULL;
  2022. INetCfgClass * pNetCfgClassAdapter = NULL;
  2023. INetCfgComponent * pNetCfgComponent = NULL;
  2024. INetCfgComponent * pNetCfgComponentprot = NULL;
  2025. IEnumNetCfgComponent * pEnumComponent = NULL;
  2026. INetCfgComponentBindings * pBinding = NULL;
  2027. LPWSTR pDisplayName = NULL;
  2028. DWORD dwCharacteristics;
  2029. ULONG count = 0;
  2030. RPC_STATUS RpcStatus;
  2031. PWCHAR pLanAdapter = NULL;
  2032. *ppLanAdapterName = NULL;
  2033. *pLength = 0;
  2034. *pResult = STATUS_SUCCESS;
  2035. if(!hServer)
  2036. {
  2037. *pResult = STATUS_UNSUCCESSFUL;
  2038. return( FALSE );
  2039. }
  2040. // Impersonate the client so that strings get localized
  2041. RpcStatus = RpcImpersonateClient(NULL);
  2042. if(RpcStatus != RPC_S_OK)
  2043. {
  2044. *pResult = STATUS_CANNOT_IMPERSONATE;
  2045. goto done;
  2046. }
  2047. // 0 corresponds to "All network adapters"
  2048. if (0 == LanAdapter) {
  2049. pLanAdapter = MIDL_user_allocate((DEVICENAME_LENGTH + 1) * sizeof(WCHAR));
  2050. if (pLanAdapter == NULL) {
  2051. *pResult = STATUS_NO_MEMORY;
  2052. RpcRevertToSelf();
  2053. goto done;
  2054. }
  2055. else {
  2056. if (!LoadString(hModuleWin, STR_ALL_LAN_ADAPTERS, pLanAdapter,
  2057. DEVICENAME_LENGTH + 1)) {
  2058. *pResult = STATUS_UNSUCCESSFUL;
  2059. MIDL_user_free(pLanAdapter);
  2060. RpcRevertToSelf();
  2061. goto done;
  2062. }
  2063. *ppLanAdapterName = pLanAdapter;
  2064. *pLength = (DEVICENAME_LENGTH + 1);
  2065. RpcRevertToSelf();
  2066. goto done;
  2067. }
  2068. }
  2069. RpcRevertToSelf();
  2070. try{
  2071. NTSTATUS StringStatus ;
  2072. // Do some buffer validation
  2073. // No of bytes (and not no of WCHARS) is sent from the Client, so send half the length got
  2074. StringStatus = IsZeroterminateStringW(pPdName, PdNameSize / sizeof(WCHAR) );
  2075. if (StringStatus != STATUS_SUCCESS) {
  2076. *pResult = STATUS_INVALID_PARAMETER;
  2077. goto done;
  2078. }
  2079. if (0 == _wcsnicmp( pPdName , L"tcp", PdNameSize/sizeof(WCHAR))) {
  2080. lstrcpy(szProtocol,NETCFG_TRANS_CID_MS_TCPIP);
  2081. }
  2082. else if( 0 == _wcsnicmp( pPdName , L"netbios", PdNameSize/sizeof(WCHAR)) ) {
  2083. lstrcpy(szProtocol,NETCFG_SERVICE_CID_MS_NETBIOS);
  2084. }
  2085. else if( 0 == _wcsnicmp( pPdName , L"ipx", PdNameSize/sizeof(WCHAR)) ) {
  2086. lstrcpy(szProtocol,NETCFG_TRANS_CID_MS_NWIPX);
  2087. }
  2088. else if( 0 == _wcsnicmp( pPdName , L"spx", PdNameSize/sizeof(WCHAR)) ) {
  2089. lstrcpy(szProtocol,NETCFG_TRANS_CID_MS_NWSPX);
  2090. }
  2091. else {
  2092. *pResult = STATUS_INVALID_PARAMETER;
  2093. goto done;
  2094. }
  2095. } except(EXCEPTION_EXECUTE_HANDLER){
  2096. *pResult = STATUS_INVALID_PARAMETER;
  2097. goto done;
  2098. }
  2099. hResult = CoCreateInstance(&CLSID_CNetCfg, NULL, CLSCTX_SERVER,
  2100. &IID_INetCfg, (LPVOID *)&pnetCfg);
  2101. if (FAILED(hResult)) {
  2102. *pResult = STATUS_UNSUCCESSFUL;
  2103. goto done;
  2104. }
  2105. if (pnetCfg != NULL) {
  2106. hResult = pnetCfg->lpVtbl->Initialize(pnetCfg,NULL );
  2107. if (FAILED(hResult) || pnetCfg == NULL) {
  2108. *pResult = STATUS_UNSUCCESSFUL;
  2109. goto done;
  2110. }
  2111. if (lstrcmpi(szProtocol, NETCFG_SERVICE_CID_MS_NETBIOS) == 0) {
  2112. hResult = pnetCfg->lpVtbl->QueryNetCfgClass(pnetCfg,
  2113. &GUID_DEVCLASS_NETSERVICE, &IID_INetCfgClass,
  2114. (void **)&pNetCfgClass);
  2115. if (FAILED(hResult) || pNetCfgClass == NULL) {
  2116. *pResult = STATUS_UNSUCCESSFUL;
  2117. goto done;
  2118. }
  2119. }
  2120. else {
  2121. hResult = pnetCfg->lpVtbl->QueryNetCfgClass(pnetCfg,
  2122. &GUID_DEVCLASS_NETTRANS, &IID_INetCfgClass,
  2123. (void **)&pNetCfgClass);
  2124. if (FAILED( hResult ) || pNetCfgClass == NULL) {
  2125. *pResult = STATUS_UNSUCCESSFUL;
  2126. goto done;
  2127. }
  2128. }
  2129. hResult = pnetCfg->lpVtbl->QueryNetCfgClass(pnetCfg,
  2130. &GUID_DEVCLASS_NET, &IID_INetCfgClass,
  2131. (void **)&pNetCfgClassAdapter);
  2132. if (FAILED( hResult ) || pNetCfgClassAdapter == NULL) {
  2133. *pResult = STATUS_UNSUCCESSFUL;
  2134. goto done;
  2135. }
  2136. hResult = pNetCfgClass->lpVtbl->FindComponent(pNetCfgClass,
  2137. szProtocol, &pNetCfgComponentprot);
  2138. if (FAILED( hResult ) || pNetCfgComponentprot == NULL) {
  2139. *pResult = STATUS_UNSUCCESSFUL;
  2140. goto done;
  2141. }
  2142. hResult = pNetCfgComponentprot->lpVtbl->QueryInterface(
  2143. pNetCfgComponentprot, &IID_INetCfgComponentBindings,
  2144. (void **)&pBinding);
  2145. if (FAILED( hResult ) || pBinding == NULL) {
  2146. *pResult = STATUS_UNSUCCESSFUL;
  2147. goto done;
  2148. }
  2149. hResult = pNetCfgClassAdapter->lpVtbl->EnumComponents(
  2150. pNetCfgClassAdapter, &pEnumComponent);
  2151. RELEASEPTR(pNetCfgClassAdapter);
  2152. if (FAILED( hResult ) || pEnumComponent == NULL) {
  2153. *pResult = STATUS_UNSUCCESSFUL;
  2154. goto done;
  2155. }
  2156. *pResult = STATUS_UNSUCCESSFUL;
  2157. while(TRUE) {
  2158. hr = pEnumComponent->lpVtbl->Next(pEnumComponent, 1,
  2159. &pNetCfgComponent,&count);
  2160. if (count == 0 || NULL == pNetCfgComponent)
  2161. break;
  2162. hr = pNetCfgComponent->lpVtbl->GetCharacteristics(
  2163. pNetCfgComponent,&dwCharacteristics);
  2164. if (FAILED(hr)) {
  2165. RELEASEPTR(pNetCfgComponent);
  2166. continue;
  2167. }
  2168. if (dwCharacteristics & NCF_PHYSICAL) {
  2169. if (S_OK == pBinding->lpVtbl->IsBoundTo(pBinding,
  2170. pNetCfgComponent)) {
  2171. GUID guidNIC;
  2172. /*index++;
  2173. if(index == LanAdapter)
  2174. {
  2175. hResult = pNetCfgComponent->lpVtbl->GetDisplayName(pNetCfgComponent,&pLanAdapter);
  2176. if( FAILED( hResult ) )
  2177. {
  2178. *pResult = STATUS_UNSUCCESSFUL;
  2179. }
  2180. else
  2181. {
  2182. *ppLanAdapterName = MIDL_user_allocate((lstrlen(pLanAdapter) + 1) * sizeof(WCHAR));
  2183. if (*ppLanAdapterName == NULL)
  2184. {
  2185. *pResult = STATUS_NO_MEMORY;
  2186. }
  2187. else
  2188. {
  2189. lstrcpy(*ppLanAdapterName,pLanAdapter);
  2190. *pLength = (lstrlen(pLanAdapter) + 1);
  2191. *pResult = STATUS_SUCCESS;
  2192. }
  2193. CoTaskMemFree(pLanAdapter);
  2194. break;
  2195. }
  2196. }
  2197. */
  2198. hResult = pNetCfgComponent->lpVtbl->GetInstanceGuid(
  2199. pNetCfgComponent , &guidNIC);
  2200. if (SUCCEEDED( hResult )) {
  2201. hResult = pNetCfgComponent->lpVtbl->GetDisplayName(
  2202. pNetCfgComponent, &pLanAdapter);
  2203. }
  2204. if (SUCCEEDED(hResult)) {
  2205. WCHAR wchRegKey[ MAX_PATH ];
  2206. WCHAR wchGUID[ 40 ];
  2207. HKEY hKey;
  2208. lstrcpy( wchRegKey , REG_GUID_TABLE );
  2209. // convert the 128bit value into a string
  2210. StringFromGUID2(&guidNIC, wchGUID,
  2211. sizeof( wchGUID ) / sizeof( WCHAR ));
  2212. // create the full regkey
  2213. lstrcat( wchRegKey , wchGUID );
  2214. // find guid in guid table
  2215. hResult = (HRESULT)RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2216. wchRegKey, 0, KEY_READ, &hKey);
  2217. if (hResult == ERROR_SUCCESS) {
  2218. DWORD dwSize = sizeof( DWORD );
  2219. DWORD dwLana = 0;
  2220. RegQueryValueEx(hKey, LANA_ID, NULL, NULL,
  2221. (LPBYTE)&dwLana, &dwSize);
  2222. RegCloseKey(hKey);
  2223. // if we have a match allocate space for the lanadapter name
  2224. // and then lets split
  2225. if (LanAdapter == dwLana) {
  2226. *ppLanAdapterName = MIDL_user_allocate(
  2227. (lstrlen(pLanAdapter) + 1) *
  2228. sizeof(WCHAR));
  2229. if ( *ppLanAdapterName == NULL ) {
  2230. *pResult = STATUS_NO_MEMORY;
  2231. }
  2232. else {
  2233. lstrcpy( *ppLanAdapterName , pLanAdapter );
  2234. *pLength = ( lstrlen( pLanAdapter ) + 1 );
  2235. *pResult = STATUS_SUCCESS;
  2236. }
  2237. MIDL_user_free(pLanAdapter);
  2238. break;
  2239. }
  2240. }
  2241. MIDL_user_free(pLanAdapter);
  2242. }
  2243. }
  2244. }
  2245. }
  2246. RELEASEPTR(pNetCfgComponent);
  2247. }
  2248. done:
  2249. RELEASEPTR(pBinding);
  2250. RELEASEPTR(pEnumComponent);
  2251. RELEASEPTR(pNetCfgComponentprot);
  2252. RELEASEPTR(pNetCfgComponent);
  2253. RELEASEPTR(pNetCfgClass);
  2254. if ( pnetCfg != NULL )
  2255. pnetCfg->lpVtbl->Uninitialize(pnetCfg);
  2256. RELEASEPTR(pnetCfg);
  2257. CoUninitialize();
  2258. return *pResult == STATUS_SUCCESS ? TRUE : FALSE;
  2259. }
  2260. /*******************************************************************************
  2261. *
  2262. * RpcWinStationGetAllProcesses_NT6_notify_flag
  2263. *
  2264. * This callback function is called by the RPC server stub at the very end
  2265. * (after all the calls to MIDL_user_free).
  2266. * This allows us to free the remaining pointers.
  2267. * We also release the lock so that a new RpcWinStationGetAllProcesses
  2268. * can be processed.
  2269. *
  2270. ******************************************************************************/
  2271. void RpcWinStationGetAllProcesses_NT6_notify_flag(boolean fServerCalled)
  2272. {
  2273. // DBGPRINT(( "TERMSRV: Entering RpcWinStationGAP_notify\n"));
  2274. if (!fServerCalled)
  2275. return;
  2276. if (gbRpcGetAllProcessesOK == TRUE)
  2277. {
  2278. //
  2279. // free our own pointers, free the database and disable the checking
  2280. //
  2281. ReleaseGAPPointersDatabase();
  2282. //
  2283. // release the lock that has been held since we entered
  2284. // RpcWinStationGetAllProcesses
  2285. //
  2286. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  2287. }
  2288. }
  2289. /*******************************************************************************
  2290. *
  2291. * RpcWinStationGetAllProcesses_notify_flag
  2292. *
  2293. * This callback function is called by the RPC server stub at the very end
  2294. * (after all the calls to MIDL_user_free).
  2295. * This allows us to free the remaining pointers.
  2296. * We also release the lock so that a new RpcWinStationGetAllProcesses
  2297. * can be processed.
  2298. *
  2299. ******************************************************************************/
  2300. void RpcWinStationGetAllProcesses_notify_flag(boolean fServerCalled)
  2301. {
  2302. // DBGPRINT(( "TERMSRV: Entering RpcWinStationGAP_notify\n"));
  2303. if (!fServerCalled)
  2304. return;
  2305. if (gbRpcGetAllProcessesOK == TRUE)
  2306. {
  2307. //
  2308. // free our own pointers, free the database and disable the checking
  2309. //
  2310. ReleaseGAPPointersDatabase();
  2311. //
  2312. // release the lock that has been held since we entered
  2313. // RpcWinStationGetAllProcesses
  2314. //
  2315. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  2316. }
  2317. }
  2318. /*****************************************************************************
  2319. *
  2320. * RpcWinStationGetProcessSid
  2321. *
  2322. * RpcWinStationGetProcessSid API
  2323. *
  2324. * ENTRY:
  2325. * hServer - input, The serrver handle to work on.
  2326. * dwUniqueProcessId - input, ProcessID (its not really unique)
  2327. * ProcessStartTime - input, ProcessStartTime combined with ProcessID
  2328. * identifies a unique process
  2329. * pResult - output, error code
  2330. * pProcessUserSid - output, process user sid
  2331. * dwSidSize - input, sid size allocated.
  2332. *
  2333. * EXIT:
  2334. * TRUE - Requested Sid is in pProcessUserSid.
  2335. * FALSE - The operation failed. Status code is in pResult.
  2336. *
  2337. ****************************************************************************/
  2338. BOOLEAN RpcWinStationGetProcessSid(
  2339. HANDLE hServer,
  2340. DWORD dwUniqueProcessId,
  2341. LARGE_INTEGER ProcessStartTime,
  2342. LONG *pResult, // Really an NTSTATUS
  2343. PBYTE pProcessUserSid,
  2344. DWORD dwSidSize,
  2345. DWORD *pdwSizeNeeded)
  2346. {
  2347. PSID pSid;
  2348. RPC_STATUS RpcStatus;
  2349. if(!hServer)
  2350. {
  2351. *pResult = STATUS_UNSUCCESSFUL;
  2352. return( FALSE );
  2353. }
  2354. RpcStatus = RpcImpersonateClient( NULL );
  2355. if( RpcStatus != RPC_S_OK ) {
  2356. *pResult = STATUS_ACCESS_DENIED;
  2357. return FALSE;
  2358. }
  2359. RtlEnterCriticalSection(&gRpcGetAllProcessesLock);
  2360. // Check if SID cache hasn't grown too much
  2361. CheckSidCacheSize();
  2362. *pResult = GetSidFromProcessId(
  2363. (HANDLE)(ULONG_PTR)dwUniqueProcessId,
  2364. ProcessStartTime,
  2365. &pSid,
  2366. TRUE
  2367. );
  2368. if (NT_SUCCESS(*pResult)) {
  2369. *pdwSizeNeeded = RtlLengthSid(pSid);
  2370. if (*pdwSizeNeeded <= dwSidSize) {
  2371. if (pProcessUserSid == NULL) {
  2372. *pResult = STATUS_INVALID_PARAMETER;
  2373. } else {
  2374. *pResult = RtlCopySid(
  2375. *pdwSizeNeeded,
  2376. pProcessUserSid,
  2377. pSid
  2378. );
  2379. }
  2380. } else {
  2381. *pResult = STATUS_BUFFER_TOO_SMALL;
  2382. }
  2383. } else {
  2384. *pdwSizeNeeded = 0;
  2385. }
  2386. RtlLeaveCriticalSection(&gRpcGetAllProcessesLock);
  2387. RpcRevertToSelf();
  2388. return(*pResult == STATUS_SUCCESS ? TRUE : FALSE);
  2389. }
  2390. /*******************************************************************************
  2391. *
  2392. * RpcWinStationRename
  2393. *
  2394. * Renames a window station object in the session manager.
  2395. *
  2396. * ENTRY:
  2397. *
  2398. * pWinStationNameOld (input)
  2399. * Old name of window station.
  2400. *
  2401. * pWinStationNameNew (input)
  2402. * New name of window station.
  2403. *
  2404. *
  2405. * EXIT:
  2406. *
  2407. * TRUE -- The rename operation succeeded.
  2408. *
  2409. * FALSE -- The operation failed. Extended error status is available
  2410. * using GetLastError.
  2411. *
  2412. ******************************************************************************/
  2413. BOOLEAN
  2414. RpcWinStationRename(
  2415. HANDLE hServer,
  2416. DWORD *pResult,
  2417. PWCHAR pWinStationNameOld,
  2418. DWORD NameOldSize,
  2419. PWCHAR pWinStationNameNew,
  2420. DWORD NameNewSize
  2421. )
  2422. {
  2423. if(!hServer)
  2424. {
  2425. *pResult = STATUS_UNSUCCESSFUL;
  2426. return( FALSE );
  2427. }
  2428. *pResult = WinStationRenameWorker(
  2429. pWinStationNameOld,
  2430. NameOldSize,
  2431. pWinStationNameNew,
  2432. NameNewSize
  2433. );
  2434. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  2435. }
  2436. /*******************************************************************************
  2437. *
  2438. * RpcWinStationQueryInformation
  2439. *
  2440. * Queries configuration information about a window station object.
  2441. *
  2442. * ENTRY:
  2443. *
  2444. * WinStationHandle (input)
  2445. * Identifies the window station object. The handle must have
  2446. * WINSTATION_QUERY access.
  2447. *
  2448. * WinStationInformationClass (input)
  2449. * Specifies the type of information to retrieve from the specified
  2450. * window station object.
  2451. *
  2452. * pWinStationInformation (output)
  2453. * A pointer to a buffer that will receive information about the
  2454. * specified window station. The format and contents of the buffer
  2455. * depend on the specified information class being queried.
  2456. *
  2457. * WinStationInformationLength (input)
  2458. * Specifies the length in bytes of the window station information
  2459. * buffer.
  2460. *
  2461. * pReturnLength (output)
  2462. * An optional parameter that if specified, receives the number of
  2463. * bytes placed in the window station information buffer.
  2464. *
  2465. * EXIT:
  2466. *
  2467. * TRUE -- The query succeeded, and the buffer contains the requested data.
  2468. *
  2469. * FALSE -- The operation failed. Extended error status is available
  2470. * using GetLastError.
  2471. *
  2472. ******************************************************************************/
  2473. BOOLEAN
  2474. RpcWinStationQueryInformation(
  2475. HANDLE hServer,
  2476. DWORD *pResult,
  2477. ULONG LogonId,
  2478. DWORD WinStationInformationClass,
  2479. PCHAR pWinStationInformation,
  2480. DWORD WinStationInformationLength,
  2481. DWORD *pReturnLength
  2482. )
  2483. {
  2484. if(!hServer)
  2485. {
  2486. *pResult = STATUS_UNSUCCESSFUL;
  2487. return( FALSE );
  2488. }
  2489. if (!pReturnLength) {
  2490. *pResult = STATUS_INVALID_USER_BUFFER;
  2491. return FALSE;
  2492. }
  2493. // Do minimal buffer validation
  2494. if ((pWinStationInformation == NULL ) && (WinStationInformationLength != 0)) {
  2495. *pResult = STATUS_INVALID_USER_BUFFER;
  2496. return FALSE;
  2497. }
  2498. *pResult = xxxWinStationQueryInformation(
  2499. LogonId,
  2500. WinStationInformationClass,
  2501. pWinStationInformation,
  2502. WinStationInformationLength,
  2503. pReturnLength
  2504. );
  2505. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  2506. }
  2507. /*******************************************************************************
  2508. *
  2509. * RpcWinStationSetInformation
  2510. *
  2511. * Sets configuration information for a window station object.
  2512. *
  2513. * ENTRY:
  2514. *
  2515. * WinStationHandle (input)
  2516. * Identifies the window station object. The handle must have
  2517. * WINSTATION_SET access.
  2518. *
  2519. * WinStationInformationClass (input)
  2520. * Specifies the type of information to retrieve from the specified
  2521. * window station object.
  2522. *
  2523. * pWinStationInformation (input)
  2524. * A pointer to a buffer that contains information to set for the
  2525. * specified window station. The format and contents of the buffer
  2526. * depend on the specified information class being set.
  2527. *
  2528. * WinStationInformationLength (input)
  2529. * Specifies the length in bytes of the window station information
  2530. * buffer.
  2531. *
  2532. * EXIT:
  2533. *
  2534. * TRUE -- The set operation succeeded.
  2535. *
  2536. * FALSE -- The operation failed. Extended error status is available
  2537. * using GetLastError.
  2538. *
  2539. ******************************************************************************/
  2540. BOOLEAN
  2541. RpcWinStationSetInformation(
  2542. HANDLE hServer,
  2543. DWORD *pResult,
  2544. ULONG LogonId,
  2545. DWORD WinStationInformationClass,
  2546. PCHAR pWinStationInformation,
  2547. ULONG WinStationInformationLength
  2548. )
  2549. {
  2550. if(!hServer)
  2551. {
  2552. *pResult = STATUS_UNSUCCESSFUL;
  2553. return( FALSE );
  2554. }
  2555. // Do minimal buffer validation
  2556. if ((pWinStationInformation == NULL ) && (WinStationInformationLength != 0)) {
  2557. *pResult = STATUS_INVALID_USER_BUFFER;
  2558. return FALSE;
  2559. }
  2560. *pResult = xxxWinStationSetInformation(
  2561. LogonId,
  2562. WinStationInformationClass,
  2563. pWinStationInformation,
  2564. WinStationInformationLength
  2565. );
  2566. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  2567. }
  2568. /*******************************************************************************
  2569. *
  2570. * RpcLogonIdFromWinStationName
  2571. *
  2572. * Returns the LogonId for the specified window station name.
  2573. *
  2574. * ENTRY:
  2575. *
  2576. * pWinStationName (input)
  2577. * Window station name.
  2578. *
  2579. * pLogonId (output)
  2580. * Pointer to where to place the LogonId if found
  2581. *
  2582. * EXIT:
  2583. *
  2584. * If the function succeeds, the return value is TRUE, otherwise, it is
  2585. * FALSE.
  2586. * To get extended error information, use the GetLastError function.
  2587. *
  2588. ******************************************************************************/
  2589. BOOLEAN
  2590. RpcLogonIdFromWinStationName(
  2591. HANDLE hServer,
  2592. DWORD *pResult,
  2593. PWCHAR pWinStationName,
  2594. DWORD NameSize,
  2595. PULONG pLogonId
  2596. )
  2597. {
  2598. if(!hServer)
  2599. {
  2600. *pResult = STATUS_UNSUCCESSFUL;
  2601. return( FALSE );
  2602. }
  2603. *pResult = LogonIdFromWinStationNameWorker(
  2604. pWinStationName,
  2605. NameSize,
  2606. pLogonId
  2607. );
  2608. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  2609. }
  2610. /*******************************************************************************
  2611. *
  2612. * RpcWinStationNameFromLogonId
  2613. *
  2614. * Returns the WinStation name for the specified LogonId.
  2615. *
  2616. * ENTRY:
  2617. *
  2618. * LogonId (output)
  2619. * LogonId to query
  2620. *
  2621. * pWinStationName (input)
  2622. * Location to return WinStation name
  2623. *
  2624. * EXIT:
  2625. *
  2626. * If the function succeeds, the return value is TRUE, otherwise, it is
  2627. * FALSE.
  2628. * To get extended error information, use the GetLastError function.
  2629. *
  2630. ******************************************************************************/
  2631. BOOLEAN
  2632. RpcWinStationNameFromLogonId(
  2633. HANDLE hServer,
  2634. DWORD *pResult,
  2635. ULONG LogonId,
  2636. PWCHAR pWinStationName,
  2637. DWORD NameSize
  2638. )
  2639. {
  2640. if(!hServer)
  2641. {
  2642. *pResult = STATUS_UNSUCCESSFUL;
  2643. return( FALSE );
  2644. }
  2645. if((NameSize < ((WINSTATIONNAME_LENGTH + 1) * sizeof(WCHAR))) ||
  2646. (IsBadWritePtr(pWinStationName, NameSize)))
  2647. {
  2648. *pResult = STATUS_INVALID_PARAMETER;
  2649. return FALSE;
  2650. }
  2651. *pResult = IcaWinStationNameFromLogonId(
  2652. LogonId,
  2653. pWinStationName
  2654. );
  2655. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  2656. }
  2657. /*******************************************************************************
  2658. *
  2659. * RpcWinStationDisconnect
  2660. *
  2661. * Disconects a window station object from the configured terminal and Pd.
  2662. * While disconnected all window station i/o is bit bucketed.
  2663. *
  2664. * ENTRY:
  2665. *
  2666. * LogonId (input)
  2667. * ID of window station object to disconnect.
  2668. * bWait (input)
  2669. * Specifies whether or not to wait for disconnect to complete
  2670. *
  2671. * EXIT:
  2672. *
  2673. * TRUE -- The disconnect operation succeeded.
  2674. *
  2675. * FALSE -- The operation failed. Extended error status is available
  2676. * using GetLastError.
  2677. *
  2678. ******************************************************************************/
  2679. BOOLEAN
  2680. RpcWinStationDisconnect(
  2681. HANDLE hServer,
  2682. DWORD *pResult,
  2683. ULONG LogonId,
  2684. BOOLEAN bWait
  2685. )
  2686. {
  2687. if(!hServer)
  2688. {
  2689. *pResult = STATUS_UNSUCCESSFUL;
  2690. return( FALSE );
  2691. }
  2692. *pResult = WinStationDisconnectWorker(
  2693. LogonId,
  2694. bWait,
  2695. TRUE
  2696. );
  2697. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  2698. }
  2699. /*******************************************************************************
  2700. *
  2701. * RpcWinStationConnect
  2702. *
  2703. * Connects a window station object to the configured terminal and Pd.
  2704. *
  2705. * ENTRY:
  2706. *
  2707. * LogonId (input)
  2708. * ID of window station object to connect.
  2709. *
  2710. * TargetLogonId (input)
  2711. * ID of target window station.
  2712. *
  2713. * pPassword (input)
  2714. * password of LogonId window station (not needed if same domain/username)
  2715. *
  2716. * bWait (input)
  2717. * Specifies whether or not to wait for connect to complete
  2718. *
  2719. * EXIT:
  2720. *
  2721. * TRUE -- The connect operation succeeded.
  2722. *
  2723. * FALSE -- The operation failed. Extended error status is available
  2724. * using GetLastError.
  2725. *
  2726. ******************************************************************************/
  2727. BOOLEAN
  2728. RpcWinStationConnect(
  2729. HANDLE hServer,
  2730. DWORD *pResult,
  2731. ULONG ClientLogonId,
  2732. ULONG ConnectLogonId,
  2733. ULONG TargetLogonId,
  2734. PWCHAR pPassword,
  2735. DWORD PasswordSize,
  2736. BOOLEAN bWait
  2737. )
  2738. {
  2739. if(!hServer)
  2740. {
  2741. *pResult = STATUS_UNSUCCESSFUL;
  2742. return( FALSE );
  2743. }
  2744. // Do some buffer Validation
  2745. *pResult = IsZeroterminateStringW(pPassword, PasswordSize );
  2746. if (*pResult != STATUS_SUCCESS) {
  2747. return FALSE;
  2748. }
  2749. *pResult = WinStationConnectWorker(
  2750. ClientLogonId,
  2751. ConnectLogonId,
  2752. TargetLogonId,
  2753. pPassword,
  2754. PasswordSize,
  2755. bWait,
  2756. FALSE
  2757. );
  2758. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  2759. }
  2760. /*****************************************************************************
  2761. * RpcWinStationVirtualOpen
  2762. *
  2763. * Open a virtual channel
  2764. ****************************************************************************/
  2765. BOOLEAN
  2766. RpcWinStationVirtualOpen(
  2767. HANDLE hServer,
  2768. DWORD *pResult,
  2769. ULONG LogonId,
  2770. DWORD Pid,
  2771. PCHAR pVirtualName, /* ascii name */
  2772. DWORD NameSize,
  2773. ULONG_PTR *pHandle
  2774. )
  2775. {
  2776. RPC_STATUS RpcStatus;
  2777. NTSTATUS Status = STATUS_SUCCESS;
  2778. PWINSTATION pWinStation;
  2779. HANDLE pidhandle = NULL;
  2780. HANDLE handle = NULL;
  2781. UINT LocalFlag = 0;
  2782. ULONG ulChannelNameLength = 0;
  2783. if(!hServer)
  2784. {
  2785. *pResult = STATUS_UNSUCCESSFUL;
  2786. return( FALSE );
  2787. }
  2788. //
  2789. // Only allow local access since virtual channels can't be accessed remotely
  2790. //
  2791. RpcStatus = I_RpcBindingIsClientLocal(
  2792. 0, // Active RPC call we are servicing
  2793. &LocalFlag
  2794. );
  2795. if( RpcStatus != RPC_S_OK ) {
  2796. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL,
  2797. "TERMSRV: RpcWinStationVirtualOpen: I_RpcBindingIsClientLocal() failed: 0x%x\n",RpcStatus));
  2798. Status = STATUS_UNSUCCESSFUL;
  2799. goto done;
  2800. }
  2801. //
  2802. // Check that the call came in locally
  2803. //
  2804. if (!LocalFlag) {
  2805. Status = (DWORD)STATUS_INVALID_PARAMETER;
  2806. goto done;
  2807. }
  2808. //
  2809. // Check channel name length.
  2810. //
  2811. if ( pVirtualName ) {
  2812. // Make sure if the virtual channel name is specified, the namelength if set to non-zero.
  2813. // Some bad client might intentionally have set it to 0, we don't want it to succeed.
  2814. if ( NameSize == 0 ) {
  2815. Status = (DWORD)STATUS_INVALID_PARAMETER;
  2816. goto done;
  2817. }
  2818. pVirtualName[NameSize-1] = '\0';
  2819. ulChannelNameLength = strlen( pVirtualName );
  2820. }
  2821. if ( !ulChannelNameLength ||
  2822. (ulChannelNameLength > VIRTUALCHANNELNAME_LENGTH)
  2823. ) {
  2824. Status = (DWORD)STATUS_INVALID_PARAMETER;
  2825. goto done;
  2826. }
  2827. /*
  2828. * Impersonate the client so that when the attempt is made to open the
  2829. * process, it will fail if the client does not have dup handle access.
  2830. */
  2831. RpcStatus = RpcImpersonateClient( NULL );
  2832. if( RpcStatus != RPC_S_OK ) {
  2833. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationVirtualOpen: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  2834. Status = (DWORD)STATUS_CANNOT_IMPERSONATE;
  2835. goto done;
  2836. }
  2837. pidhandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, Pid );
  2838. RpcRevertToSelf();
  2839. if ( !pidhandle ) {
  2840. Status = (DWORD)STATUS_ACCESS_DENIED;
  2841. goto done;
  2842. }
  2843. /*
  2844. * Find and lock client WinStation
  2845. */
  2846. pWinStation = FindWinStationById( LogonId, FALSE );
  2847. if ( pWinStation == NULL ) {
  2848. Status = (DWORD)STATUS_ACCESS_DENIED;
  2849. goto done;
  2850. }
  2851. /*
  2852. * If this winstation type does not allow opening virtual channel, then deny access.
  2853. */
  2854. if ( !_tcsicmp(VIRTUAL_THINWIRE, pVirtualName) &&
  2855. ( ( pWinStation->Client.ProtocolType == PROTOCOL_RDP ) ||
  2856. !(pWinStation->Config.Wd.WdFlag & WDF_USER_VCIOCTL) ) )
  2857. {
  2858. Status = STATUS_ACCESS_DENIED;
  2859. ReleaseWinStation( pWinStation );
  2860. goto done;
  2861. }
  2862. /*
  2863. * Make sure the caller has WINSTATION_VIRTUAL access
  2864. */
  2865. Status = RpcCheckClientAccess( pWinStation, WINSTATION_VIRTUAL, FALSE );
  2866. if ( !NT_SUCCESS( Status ) ) {
  2867. ReleaseWinStation( pWinStation );
  2868. goto done;
  2869. }
  2870. /*
  2871. * Don't allow VirtualChannel opens on listner or idle sessions
  2872. */
  2873. if( pWinStation->State == State_Listen ||
  2874. pWinStation->State == State_Idle )
  2875. {
  2876. ReleaseWinStation( pWinStation);
  2877. Status = (DWORD)STATUS_ACCESS_DENIED;
  2878. goto done;
  2879. }
  2880. /*
  2881. * we need to impersonate before calling IcaChannelOpen to
  2882. * make sure the handle gets marked as non system created
  2883. */
  2884. RpcStatus = RpcImpersonateClient( NULL );
  2885. if( RpcStatus != RPC_S_OK ) {
  2886. ReleaseWinStation( pWinStation);
  2887. DbgPrint("\n\n-----752354 - TERMSRV: RpcWinStationVirtualOpen: Not impersonating! RpcStatus 0x%x*----\n\n",RpcStatus);
  2888. Status = (DWORD)STATUS_CANNOT_IMPERSONATE;
  2889. goto done;
  2890. }
  2891. /*
  2892. * Duplicate the virtual channel.
  2893. */
  2894. Status = IcaChannelOpen( pWinStation->hIca,
  2895. Channel_Virtual,
  2896. pVirtualName,
  2897. &handle );
  2898. RevertToSelf();
  2899. ReleaseWinStation( pWinStation );
  2900. if ( !NT_SUCCESS( Status ) ) {
  2901. DbgPrint("**** 752354 - TERMSRV: IcaChannelOpen failed! Status 0x%x\n",Status);
  2902. goto done;
  2903. }
  2904. Status = NtDuplicateObject( NtCurrentProcess(),
  2905. handle,
  2906. pidhandle,
  2907. (PHANDLE)pHandle,
  2908. 0,
  2909. 0,
  2910. DUPLICATE_SAME_ACCESS |
  2911. DUPLICATE_SAME_ATTRIBUTES );
  2912. done:
  2913. if ( handle )
  2914. IcaChannelClose( handle );
  2915. if ( pidhandle )
  2916. CloseHandle( pidhandle );
  2917. *pResult = Status;
  2918. if ( NT_SUCCESS(Status) )
  2919. return( TRUE );
  2920. else
  2921. return( FALSE );
  2922. }
  2923. /*****************************************************************************
  2924. * RpcWinStationBeepOpen
  2925. *
  2926. * Open a beep channel
  2927. ****************************************************************************/
  2928. BOOLEAN
  2929. RpcWinStationBeepOpen(
  2930. HANDLE hServer,
  2931. DWORD *pResult,
  2932. ULONG LogonId,
  2933. DWORD Pid,
  2934. ULONG_PTR *pHandle
  2935. )
  2936. {
  2937. RPC_STATUS RpcStatus;
  2938. NTSTATUS Status = STATUS_SUCCESS;
  2939. PWINSTATION pWinStation;
  2940. HANDLE pidhandle = NULL;
  2941. HANDLE handle = NULL;
  2942. if(!hServer)
  2943. {
  2944. *pResult = STATUS_UNSUCCESSFUL;
  2945. return( FALSE );
  2946. }
  2947. /*
  2948. * Impersonate the client so that when the attempt is made to open the
  2949. * process, it will fail if the client does not have dup handle access.
  2950. */
  2951. RpcStatus = RpcImpersonateClient( NULL );
  2952. if( RpcStatus != RPC_S_OK ) {
  2953. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationBeepOpen: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  2954. Status = (DWORD)STATUS_CANNOT_IMPERSONATE;
  2955. goto done;
  2956. }
  2957. if ( !IsCallerSystem() ) {
  2958. *pResult = STATUS_ACCESS_DENIED;
  2959. RpcRevertToSelf();
  2960. return FALSE;
  2961. }
  2962. pidhandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, Pid );
  2963. RpcRevertToSelf();
  2964. if ( !pidhandle ) {
  2965. Status = (DWORD)STATUS_ACCESS_DENIED;
  2966. goto done;
  2967. }
  2968. /*
  2969. * Find and lock client WinStation
  2970. */
  2971. pWinStation = FindWinStationById( LogonId, FALSE );
  2972. if ( pWinStation == NULL ) {
  2973. Status = (DWORD)STATUS_ACCESS_DENIED;
  2974. goto done;
  2975. }
  2976. /*
  2977. * Make sure the caller has WINSTATION_VIRTUAL access
  2978. */
  2979. Status = RpcCheckClientAccess( pWinStation, WINSTATION_VIRTUAL, FALSE );
  2980. if ( !NT_SUCCESS( Status ) ) {
  2981. ReleaseWinStation( pWinStation );
  2982. goto done;
  2983. }
  2984. /*
  2985. * Duplicate the beep channel.
  2986. */
  2987. Status = IcaChannelOpen( pWinStation->hIca,
  2988. Channel_Beep,
  2989. NULL,
  2990. &handle );
  2991. ReleaseWinStation( pWinStation );
  2992. if ( !NT_SUCCESS( Status ) ) {
  2993. goto done;
  2994. }
  2995. Status = NtDuplicateObject( NtCurrentProcess(),
  2996. handle,
  2997. pidhandle,
  2998. (PHANDLE)pHandle,
  2999. 0,
  3000. 0,
  3001. DUPLICATE_SAME_ACCESS |
  3002. DUPLICATE_SAME_ATTRIBUTES );
  3003. done:
  3004. if ( handle )
  3005. IcaChannelClose( handle );
  3006. if ( pidhandle )
  3007. CloseHandle( pidhandle );
  3008. *pResult = Status;
  3009. if ( NT_SUCCESS(Status) )
  3010. return( TRUE );
  3011. else
  3012. return( FALSE );
  3013. }
  3014. /*******************************************************************************
  3015. * RpcWinStationReset
  3016. *
  3017. * Reset the specified window station.
  3018. *
  3019. * ENTRY:
  3020. * LogonId (input)
  3021. * Identifies the window station object to reset.
  3022. * bWait (input)
  3023. * Specifies whether or not to wait for reset to complete
  3024. *
  3025. * EXIT:
  3026. * TRUE -- The reset operation succeeded.
  3027. * FALSE -- The operation failed. Extended error status is available
  3028. * using GetLastError.
  3029. ******************************************************************************/
  3030. BOOLEAN
  3031. RpcWinStationReset(
  3032. HANDLE hServer,
  3033. DWORD *pResult,
  3034. ULONG LogonId,
  3035. BOOLEAN bWait
  3036. )
  3037. {
  3038. NTSTATUS Status;
  3039. if(!hServer)
  3040. {
  3041. *pResult = STATUS_UNSUCCESSFUL;
  3042. return( FALSE );
  3043. }
  3044. *pResult = WinStationResetWorker(
  3045. LogonId,
  3046. bWait,
  3047. TRUE, // Rpc caller, must check access
  3048. TRUE // By default, recreate the WinStation
  3049. );
  3050. //
  3051. // dont return STATUS_TIMEOUT.
  3052. //
  3053. if (*pResult == STATUS_TIMEOUT) *pResult = STATUS_UNSUCCESSFUL;
  3054. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3055. }
  3056. /*******************************************************************************
  3057. * RpcWinStationShadowStop
  3058. *
  3059. * Stop any shadow operation on the specified window station.
  3060. *
  3061. * ENTRY:
  3062. * LogonId (input)
  3063. * Identifies the window station object to reset.
  3064. * bWait (input)
  3065. * Specifies whether or not to wait for reset to complete
  3066. *
  3067. * EXIT:
  3068. * TRUE -- The stop shadow operation succeeded.
  3069. * FALSE -- The operation failed. Extended error status is available
  3070. * using GetLastError.
  3071. ******************************************************************************/
  3072. BOOLEAN
  3073. RpcWinStationShadowStop(
  3074. HANDLE hServer,
  3075. DWORD *pResult,
  3076. ULONG LogonId,
  3077. BOOLEAN bWait // unused - later?
  3078. )
  3079. {
  3080. PWINSTATION pWinStation;
  3081. ULONG ClientLogonId;
  3082. NTSTATUS Status;
  3083. RPC_STATUS RpcStatus;
  3084. UINT LocalFlag;
  3085. if(!hServer)
  3086. {
  3087. *pResult = STATUS_UNSUCCESSFUL;
  3088. return( FALSE );
  3089. }
  3090. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: RpcWinStationShadowStop, LogonId=%d\n", LogonId ));
  3091. /*
  3092. * Find and lock the WinStation struct for the specified LogonId
  3093. */
  3094. pWinStation = FindWinStationById( LogonId, FALSE );
  3095. if ( pWinStation == NULL ) {
  3096. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  3097. goto notfound;
  3098. }
  3099. //
  3100. // If the session is NOT being shadowed then bail out
  3101. //
  3102. if ( !( pWinStation->State == State_Active &&
  3103. !IsListEmpty(&pWinStation->ShadowHead) ) ) {
  3104. Status = STATUS_CTX_SHADOW_NOT_RUNNING;
  3105. goto done;
  3106. }
  3107. /*
  3108. * Impersonate the client
  3109. */
  3110. RpcStatus = RpcImpersonateClient( NULL );
  3111. if( RpcStatus != RPC_S_OK ) {
  3112. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationShadowStop: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3113. Status = STATUS_CANNOT_IMPERSONATE;
  3114. goto done;
  3115. }
  3116. //
  3117. // If its remote RPC call we should ignore ClientLogonId
  3118. //
  3119. RpcStatus = I_RpcBindingIsClientLocal(
  3120. 0, // Active RPC call we are servicing
  3121. &LocalFlag
  3122. );
  3123. if( RpcStatus != RPC_S_OK ) {
  3124. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "ERMSRV: RpcWinStationShadowStop: I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  3125. RpcRevertToSelf();
  3126. Status = STATUS_UNSUCCESSFUL;
  3127. goto done;
  3128. }
  3129. //
  3130. // Get the client session id if it's local
  3131. //
  3132. if (LocalFlag) {
  3133. Status = RpcGetClientLogonId( &ClientLogonId );
  3134. if ( !NT_SUCCESS( Status ) ) {
  3135. RpcRevertToSelf();
  3136. goto done;
  3137. }
  3138. }
  3139. //
  3140. // Check for Disconnect or Reset rights since these two operations
  3141. // would anyway terminate the shadow.
  3142. //
  3143. Status = RpcCheckClientAccess( pWinStation, WINSTATION_DISCONNECT | WINSTATION_RESET, TRUE );
  3144. //
  3145. // If the access is denied then see if the client is on the same session
  3146. // and check to see if the user has the veto right to being shadowed.
  3147. //
  3148. if( !NT_SUCCESS(Status) && LocalFlag && (ClientLogonId == LogonId ) ) {
  3149. switch ( pWinStation->Config.Config.User.Shadow ) {
  3150. case Shadow_EnableInputNotify :
  3151. case Shadow_EnableNoInputNotify :
  3152. Status = STATUS_SUCCESS;
  3153. break;
  3154. default :
  3155. // other cases : don't touch the Status
  3156. break;
  3157. }
  3158. } // else : The call comes from a remote machine or a different session.
  3159. RpcRevertToSelf();
  3160. if ( !NT_SUCCESS( Status ) ) {
  3161. goto done;
  3162. }
  3163. Status = WinStationStopAllShadows( pWinStation );
  3164. done:
  3165. ReleaseWinStation( pWinStation );
  3166. notfound:
  3167. *pResult = Status;
  3168. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3169. }
  3170. /*******************************************************************************
  3171. * RpcWinStationShutdownSystem
  3172. *
  3173. * Shutdown the system and optionally logoff all WinStations
  3174. * and/or reboot the system.
  3175. *
  3176. * ENTRY:
  3177. * ShutdownFlags (input)
  3178. * Flags which specify shutdown options.
  3179. *
  3180. * EXIT:
  3181. * TRUE -- The shutdown operation succeeded.
  3182. * FALSE -- The operation failed. Extended error status is available
  3183. * using GetLastError.
  3184. ******************************************************************************/
  3185. BOOLEAN
  3186. RpcWinStationShutdownSystem(
  3187. HANDLE hServer,
  3188. DWORD *pResult,
  3189. DWORD ClientLogonId,
  3190. ULONG ShutdownFlags
  3191. )
  3192. {
  3193. if(!hServer)
  3194. {
  3195. *pResult = STATUS_UNSUCCESSFUL;
  3196. return( FALSE );
  3197. }
  3198. *pResult = WinStationShutdownSystemWorker( ClientLogonId, ShutdownFlags );
  3199. if (AuditingEnabled() && (ShutdownFlags & WSD_LOGOFF)
  3200. && (*pResult == STATUS_SUCCESS))
  3201. AuditShutdownEvent();
  3202. //
  3203. // dont return STATUS_TIMEOUT.
  3204. //
  3205. if (*pResult == STATUS_TIMEOUT) *pResult = STATUS_UNSUCCESSFUL;
  3206. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3207. }
  3208. /*******************************************************************************
  3209. * RpcWinStationTerminateProcess
  3210. *
  3211. * Terminate the specified process
  3212. *
  3213. * ENTRY:
  3214. * hServer (input)
  3215. * handle to winframe server
  3216. * pResult (output)
  3217. * address to return error status
  3218. * ProcessId (input)
  3219. * process id of the process to terminate
  3220. * ExitCode (input)
  3221. * Termination status for each thread in the process
  3222. *
  3223. * EXIT:
  3224. * TRUE -- The terminate operation succeeded.
  3225. * FALSE -- The operation failed. Extended error status is available
  3226. * using GetLastError.
  3227. ******************************************************************************/
  3228. BOOLEAN
  3229. RpcWinStationTerminateProcess(
  3230. HANDLE hServer,
  3231. DWORD *pResult,
  3232. ULONG ProcessId,
  3233. ULONG ExitCode
  3234. )
  3235. {
  3236. RPC_STATUS RpcStatus;
  3237. if(!hServer)
  3238. {
  3239. *pResult = STATUS_UNSUCCESSFUL;
  3240. return( FALSE );
  3241. }
  3242. /*
  3243. * Impersonate the client so that when the attempt is made to terminate
  3244. * the process, it will fail if the account is not admin.
  3245. */
  3246. RpcStatus = RpcImpersonateClient( NULL );
  3247. if( RpcStatus != RPC_S_OK ) {
  3248. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationTerminateProcess: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3249. *pResult = (DWORD)STATUS_CANNOT_IMPERSONATE;
  3250. return( FALSE );
  3251. }
  3252. *pResult = WinStationTerminateProcessWorker( ProcessId, ExitCode );
  3253. RpcRevertToSelf();
  3254. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3255. }
  3256. /*******************************************************************************
  3257. * RpcWinStationWaitSystemEvent
  3258. *
  3259. * Waits for an event (WinStation create, delete, connect, etc) before
  3260. * returning to the caller.
  3261. *
  3262. * ENTRY:
  3263. * EventFlags (input)
  3264. * Bit mask that specifies which event(s) to wait for.
  3265. * pEventFlags (output)
  3266. * Bit mask of event(s) that occurred.
  3267. *
  3268. * EXIT:
  3269. * TRUE -- The wait event operation succeeded.
  3270. * FALSE -- The operation failed. Extended error status is available
  3271. * using GetLastError.
  3272. ******************************************************************************/
  3273. BOOLEAN
  3274. RpcWinStationWaitSystemEvent(
  3275. HANDLE hServer,
  3276. DWORD *pResult,
  3277. ULONG EventMask,
  3278. PULONG pEventFlags
  3279. )
  3280. {
  3281. if(!hServer)
  3282. {
  3283. *pResult = STATUS_UNSUCCESSFUL;
  3284. return( FALSE );
  3285. }
  3286. *pResult = WinStationWaitSystemEventWorker( hServer, EventMask, pEventFlags );
  3287. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3288. }
  3289. /*****************************************************************************
  3290. * RpcWinStationShadow
  3291. *
  3292. * Start a Winstation shadow operation
  3293. *
  3294. * ENTRY:
  3295. * hServer (input)
  3296. * shadow client server handle
  3297. * pResult (output)
  3298. * address to return status
  3299. * LogonId (input)
  3300. * shadow client logon id
  3301. * pTargetServerName (input)
  3302. * shadow target server name
  3303. * NameSize (input)
  3304. * size of pTargetServerName (input)
  3305. * TargetLogonId (input)
  3306. * shadow target login id (where the app is running)
  3307. * HotkeyVk (input)
  3308. * virtual key to press to stop shadow
  3309. * HotkeyModifiers (input)
  3310. * virtual modifer to press to stop shadow (i.e. shift, control)
  3311. ****************************************************************************/
  3312. BOOLEAN
  3313. RpcWinStationShadow(
  3314. HANDLE hServer,
  3315. DWORD *pResult,
  3316. ULONG LogonId,
  3317. PWSTR pTargetServerName,
  3318. ULONG NameSize,
  3319. ULONG TargetLogonId,
  3320. BYTE HotkeyVk,
  3321. USHORT HotkeyModifiers
  3322. )
  3323. {
  3324. RPC_STATUS RpcStatus;
  3325. ULONG ulLength = 0;
  3326. WCHAR TargetServerNameW[MAX_COMPUTERNAME_LENGTH+1];
  3327. char* pTargetServerNameA = NULL;
  3328. PWSTR pTargetServerNameW = pTargetServerName;
  3329. if(!hServer)
  3330. {
  3331. *pResult = STATUS_UNSUCCESSFUL;
  3332. return( FALSE );
  3333. }
  3334. // Do minimal buffer validation
  3335. if (pTargetServerName != NULL) {
  3336. // No of bytes is sent from the Client, so send half the length got
  3337. *pResult = (DWORD)IsZeroterminateStringW(pTargetServerName, NameSize / sizeof(WCHAR));
  3338. if (*pResult != STATUS_SUCCESS) {
  3339. return FALSE;
  3340. }
  3341. ulLength = wcslen(pTargetServerName);
  3342. if (ulLength > (MAX_COMPUTERNAME_LENGTH)) {
  3343. struct hostent *hostPtr;
  3344. ULONG ulRequiredLength = 0;
  3345. PUCHAR ipaddr = NULL;
  3346. int ipLength = 0;
  3347. *pResult = STATUS_INVALID_PARAMETER;
  3348. //
  3349. // Limit the target server name to MAX_COMPUTERNAME_LENGTH.
  3350. // We do this by converting the server name to ipaddress.
  3351. // First convert the name to ANSI
  3352. //
  3353. ulRequiredLength = WideCharToMultiByte(CP_ACP, 0,
  3354. pTargetServerName, -1,
  3355. NULL, 0, NULL, NULL);
  3356. ASSERT(ulRequiredLength > 0);
  3357. pTargetServerNameA = MemAlloc(ulRequiredLength);
  3358. if (pTargetServerNameA == NULL) {
  3359. *pResult = STATUS_NO_MEMORY;
  3360. goto EXIT;
  3361. }
  3362. if (ulRequiredLength == 0 ||
  3363. !WideCharToMultiByte(CP_ACP, 0,
  3364. pTargetServerName, -1,
  3365. pTargetServerNameA, ulRequiredLength,
  3366. NULL, NULL)) {
  3367. DBGPRINT(("RpcWinStationShadow: WideCharToMultiByte failed %ld\n",
  3368. GetLastError()));
  3369. goto EXIT;
  3370. }
  3371. //
  3372. // Get the ip address of the target server name
  3373. //
  3374. if ((hostPtr = gethostbyname(pTargetServerNameA)) == NULL) {
  3375. DBGPRINT(("RpcWinStationShadow: gethostbyname failed %ld\n",
  3376. WSAGetLastError()));
  3377. goto EXIT;
  3378. }
  3379. MemFree(pTargetServerNameA);
  3380. pTargetServerNameA = NULL;
  3381. ipaddr = (PUCHAR)*(hostPtr->h_addr_list);
  3382. // Sanity checks.
  3383. ASSERT(hostPtr->h_length >= 4);
  3384. ASSERT(ipaddr != NULL);
  3385. if (ipaddr == NULL) {
  3386. goto EXIT;
  3387. }
  3388. //
  3389. // Put the ip address in target server name.
  3390. // Use this for shadowing
  3391. //
  3392. ipLength =_snwprintf(TargetServerNameW, MAX_COMPUTERNAME_LENGTH,
  3393. L"%d.%d.%d.%d",
  3394. ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]);
  3395. if (ipLength < 0) {
  3396. DBGPRINT(("RpcWinStationShadow: _snwprintf failed\n"));
  3397. *pResult = STATUS_BUFFER_OVERFLOW;
  3398. goto EXIT;
  3399. }
  3400. ulLength = ipLength;
  3401. TargetServerNameW[MAX_COMPUTERNAME_LENGTH] = L'\0';
  3402. pTargetServerNameW = TargetServerNameW;
  3403. }
  3404. }
  3405. /*
  3406. * Impersonate the client so that when the shadow connection is
  3407. * created, it will have the correct security.
  3408. */
  3409. RpcStatus = RpcImpersonateClient( NULL );
  3410. if( RpcStatus != RPC_S_OK ) {
  3411. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationShadow: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3412. *pResult = (DWORD)STATUS_CANNOT_IMPERSONATE;
  3413. return( FALSE );
  3414. }
  3415. *pResult = (DWORD)WinStationShadowWorker( LogonId,
  3416. pTargetServerNameW,
  3417. ulLength,
  3418. TargetLogonId,
  3419. HotkeyVk,
  3420. HotkeyModifiers );
  3421. RpcRevertToSelf();
  3422. EXIT:
  3423. if (pTargetServerNameA != NULL) {
  3424. MemFree(pTargetServerNameA);
  3425. }
  3426. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3427. }
  3428. /*****************************************************************************
  3429. * RpcWinStationShadowTargetSetup
  3430. *
  3431. * Setup a Winstation shadow operation
  3432. *
  3433. * ENTRY:
  3434. * hServer (input)
  3435. * target server
  3436. * pResult (output)
  3437. * address to return status
  3438. * LogonId (input)
  3439. * target logon id
  3440. ****************************************************************************/
  3441. BOOLEAN
  3442. RpcWinStationShadowTargetSetup(
  3443. HANDLE hServer,
  3444. DWORD *pResult,
  3445. IN ULONG LogonId
  3446. )
  3447. {
  3448. RPC_STATUS RpcStatus;
  3449. if(!hServer)
  3450. {
  3451. *pResult = STATUS_UNSUCCESSFUL;
  3452. return( FALSE );
  3453. }
  3454. /*
  3455. * Impersonate the client so that the shadow connect request
  3456. * will be under the correct security context.
  3457. */
  3458. RpcStatus = RpcImpersonateClient( NULL );
  3459. if( RpcStatus != RPC_S_OK ) {
  3460. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationShadow: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3461. *pResult = (DWORD)STATUS_CANNOT_IMPERSONATE;
  3462. return( FALSE );
  3463. }
  3464. // remote caller can't RA session.
  3465. *pResult = (DWORD)WinStationShadowTargetSetupWorker( FALSE, LogonId );
  3466. RpcRevertToSelf();
  3467. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3468. }
  3469. /*****************************************************************************
  3470. * RpcWinStationShadowTarget
  3471. *
  3472. * Start a Winstation shadow operation
  3473. *
  3474. * ENTRY:
  3475. * hServer (input)
  3476. * target server
  3477. * pResult (output)
  3478. * address to return status
  3479. * LogonId (input)
  3480. * target logon id
  3481. * pConfig (input)
  3482. * pointer to WinStation config data
  3483. * NameSize (input)
  3484. * length of config data
  3485. * pAddress (input)
  3486. * address of shadow client
  3487. * AddressSize (input)
  3488. * length of address
  3489. * pModuleData (input)
  3490. * pointer to client module data
  3491. * ModuleDataLength (input)
  3492. * length of client module data
  3493. * pThinwireData (input)
  3494. * pointer to thinwire module data
  3495. * ThinwireDataLength (input)
  3496. * length of thinwire module data
  3497. * pClientName (input)
  3498. * pointer to client name string (domain/username)
  3499. * ClientNameLength (input)
  3500. * length of client name string
  3501. ****************************************************************************/
  3502. BOOLEAN
  3503. RpcWinStationShadowTarget(
  3504. HANDLE hServer,
  3505. DWORD *pResult,
  3506. IN ULONG LogonId,
  3507. IN PBYTE pConfig,
  3508. IN DWORD NameSize,
  3509. IN PBYTE pAddress,
  3510. IN DWORD AddressSize,
  3511. IN PBYTE pModuleData,
  3512. IN DWORD ModuleDataLength,
  3513. IN PBYTE pThinwireData,
  3514. IN DWORD ThinwireDataLength,
  3515. IN PBYTE pClientName,
  3516. IN DWORD ClientNameLength
  3517. )
  3518. {
  3519. RPC_STATUS RpcStatus;
  3520. if(!hServer)
  3521. {
  3522. *pResult = STATUS_UNSUCCESSFUL;
  3523. return( FALSE );
  3524. }
  3525. /*
  3526. * Validate buffers .
  3527. */
  3528. if (AddressSize < sizeof(ICA_STACK_ADDRESS) ||
  3529. pClientName == NULL ||
  3530. NameSize < sizeof(WINSTATIONCONFIG2)) {
  3531. *pResult = STATUS_INVALID_USER_BUFFER;
  3532. return FALSE;
  3533. }
  3534. // No of bytes is sent from the Client, so send half the length got
  3535. *pResult = (DWORD)IsZeroterminateStringW((PWCHAR)pClientName,ClientNameLength / sizeof(WCHAR));
  3536. if (*pResult != STATUS_SUCCESS) {
  3537. return FALSE;
  3538. }
  3539. *pResult = IsConfigValid((PWINSTATIONCONFIG2)pConfig);
  3540. if (*pResult != STATUS_SUCCESS) {
  3541. return FALSE;
  3542. }
  3543. /*
  3544. * Impersonate the client so that the shadow connect request
  3545. * will be under the correct security context.
  3546. */
  3547. RpcStatus = RpcImpersonateClient( NULL );
  3548. if( RpcStatus != RPC_S_OK ) {
  3549. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationShadow: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3550. *pResult = (DWORD)STATUS_CANNOT_IMPERSONATE;
  3551. return( FALSE );
  3552. }
  3553. *pResult = (DWORD)WinStationShadowTargetWorker(
  3554. FALSE, // Shadower not a Help Assistant session.
  3555. FALSE, // protocol shadow, can't be help assistant session
  3556. LogonId,
  3557. (PWINSTATIONCONFIG2) pConfig,
  3558. (PICA_STACK_ADDRESS) pAddress,
  3559. (PVOID) pModuleData,
  3560. ModuleDataLength,
  3561. (PVOID) pThinwireData,
  3562. ThinwireDataLength,
  3563. pClientName );
  3564. RpcRevertToSelf();
  3565. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  3566. }
  3567. /*******************************************************************************
  3568. * RpcWinStationGenerateLicense
  3569. *
  3570. * Called to generate a license from a given serial number string.
  3571. *
  3572. * ENTRY:
  3573. * hServer (input)
  3574. * Server handle
  3575. * pSerialNumberString (input)
  3576. * Pointer to a null-terminated, wide-character Serial Number string
  3577. * pLicense (output)
  3578. * Pointer to a License structure that will be filled in with
  3579. * information based on pSerialNumberString
  3580. * LicenseSize (input)
  3581. * Size in bytes of the structure pointed to by pLicense
  3582. *
  3583. * EXIT:
  3584. * TRUE -- The generate operation succeeded.
  3585. * FALSE -- The operation failed. Extended error status is available
  3586. * in pResult.
  3587. ******************************************************************************/
  3588. BOOLEAN
  3589. RpcWinStationGenerateLicense(
  3590. HANDLE hServer,
  3591. DWORD *pResult,
  3592. PWCHAR pSerialNumberString,
  3593. DWORD Length,
  3594. PCHAR pLicense,
  3595. DWORD LicenseSize
  3596. )
  3597. {
  3598. RPC_STATUS RpcStatus;
  3599. if(!hServer)
  3600. {
  3601. *pResult = STATUS_UNSUCCESSFUL;
  3602. return( FALSE );
  3603. }
  3604. //
  3605. // The WinFrame licensing API's load the Ulm DLL in the context
  3606. // of the ICASRV process, and then attempt to access the
  3607. // WinFrame licensing registry keys. By impersonating the caller,
  3608. // we can make sure that the license key operation is done under
  3609. // the callers subject context. This will fail for non-admin callers, as
  3610. // defined by the ACL placed on the licensing keys.
  3611. //
  3612. /*
  3613. * Impersonate the client
  3614. */
  3615. RpcStatus = RpcImpersonateClient( NULL );
  3616. if( RpcStatus != RPC_S_OK ) {
  3617. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationGenerateLicense: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3618. *pResult = ERROR_CANNOT_IMPERSONATE;
  3619. return( FALSE );
  3620. }
  3621. #ifdef not_hydrix
  3622. *pResult = xxxWinStationGenerateLicense(
  3623. pSerialNumberString,
  3624. Length,
  3625. pLicense,
  3626. LicenseSize
  3627. );
  3628. #else
  3629. {
  3630. PLIST_ENTRY Head, Next;
  3631. PWSEXTENSION pWsx;
  3632. ICASRVPROCADDR IcaSrvProcAddr;
  3633. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  3634. RtlEnterCriticalSection( &WsxListLock );
  3635. Head = &WsxListHead;
  3636. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  3637. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  3638. if ( pWsx->pWsxWinStationGenerateLicense ) {
  3639. *pResult = pWsx->pWsxWinStationGenerateLicense(
  3640. pSerialNumberString,
  3641. Length,
  3642. pLicense,
  3643. LicenseSize
  3644. );
  3645. break;
  3646. }
  3647. }
  3648. RtlLeaveCriticalSection( &WsxListLock );
  3649. }
  3650. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_TRACE_LEVEL, "WinStationGenerateLicense: 0x%x\n", *pResult ));
  3651. #endif
  3652. RpcRevertToSelf();
  3653. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  3654. }
  3655. /*******************************************************************************
  3656. * RpcWinStationInstallLicense
  3657. *
  3658. * Called to install a license.
  3659. *
  3660. * ENTRY:
  3661. * hServer (input)
  3662. * Server handle
  3663. * pLicense (input)
  3664. * Pointer to a License structure containing the license to
  3665. * be installed
  3666. * LicenseSize (input)
  3667. * Size in bytes of the structure pointed to by pLicense
  3668. *
  3669. * EXIT:
  3670. * TRUE -- The install operation succeeded.
  3671. * FALSE -- The operation failed. Extended error status is available
  3672. * in pResult.
  3673. ******************************************************************************/
  3674. BOOLEAN
  3675. RpcWinStationInstallLicense(
  3676. HANDLE hServer,
  3677. DWORD *pResult,
  3678. PCHAR pLicense,
  3679. DWORD LicenseSize
  3680. )
  3681. {
  3682. RPC_STATUS RpcStatus;
  3683. if(!hServer)
  3684. {
  3685. *pResult = STATUS_UNSUCCESSFUL;
  3686. return( FALSE );
  3687. }
  3688. /*
  3689. * Impersonate the client
  3690. */
  3691. RpcStatus = RpcImpersonateClient( NULL );
  3692. if( RpcStatus != RPC_S_OK ) {
  3693. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationInstallLicense: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3694. *pResult = ERROR_CANNOT_IMPERSONATE;
  3695. return( FALSE );
  3696. }
  3697. #ifdef not_hydrix
  3698. *pResult = xxxWinStationInstallLicense(
  3699. pLicense,
  3700. LicenseSize
  3701. );
  3702. #else
  3703. {
  3704. PLIST_ENTRY Head, Next;
  3705. PWSEXTENSION pWsx;
  3706. ICASRVPROCADDR IcaSrvProcAddr;
  3707. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  3708. RtlEnterCriticalSection( &WsxListLock );
  3709. Head = &WsxListHead;
  3710. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  3711. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  3712. if ( pWsx->pWsxWinStationInstallLicense ) {
  3713. *pResult = pWsx->pWsxWinStationInstallLicense(
  3714. pLicense,
  3715. LicenseSize
  3716. );
  3717. break;
  3718. }
  3719. }
  3720. RtlLeaveCriticalSection( &WsxListLock );
  3721. }
  3722. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationInstallLicense: 0x%x\n", *pResult ));
  3723. #endif
  3724. RpcRevertToSelf();
  3725. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  3726. }
  3727. /*******************************************************************************
  3728. * RpcWinStationEnumerateLicenses
  3729. *
  3730. * Called to return the list of valid licenses.
  3731. *
  3732. * ENTRY:
  3733. * hServer (input)
  3734. * Server handle
  3735. * pIndex (input/output)
  3736. * Specifies the subkey index for the \Citrix\WinStations subkeys in the
  3737. * registry. Should be set to 0 for the initial call, and supplied
  3738. * again (as modified by this function) for multi-call enumeration.
  3739. * pEntries (input/output)
  3740. * Points to a variable specifying the number of entries requested.
  3741. * If the number requested is 0xFFFFFFFF, the function returns as
  3742. * many entries as possible. When the function finishes successfully,
  3743. * the variable pointed to by the pEntries parameter contains the
  3744. * number of entries actually read.
  3745. * pLicense (input/output)
  3746. * Points to the buffer to receive the enumeration results, which are
  3747. * returned as an array of LICENSE structures. If this parameter
  3748. * is NULL, then no data will be copied, but just an enumeration count
  3749. * will be made.
  3750. * LicenseSize (input)
  3751. * Size in bytes of the structure pointed to by pLicense
  3752. * pByteCount (input/output)
  3753. * Points to a variable that specifies the size, in bytes, of the
  3754. * pWinStationName parameter. If the buffer is too small to receive even
  3755. * one entry, the function returns an error code (ERROR_OUTOFMEMORY)
  3756. * and this variable receives the required size of the buffer for a
  3757. * single subkey. When the function finishes sucessfully, the variable
  3758. * pointed to by the pByteCount parameter contains the number of bytes
  3759. * actually stored in pLicense.
  3760. *
  3761. * EXIT:
  3762. * TRUE -- The enumerate operation succeeded.
  3763. * FALSE -- The operation failed. Extended error status is available
  3764. * in pResult.
  3765. ******************************************************************************/
  3766. BOOLEAN
  3767. RpcWinStationEnumerateLicenses(
  3768. HANDLE hServer,
  3769. DWORD *pResult,
  3770. DWORD *pIndex,
  3771. DWORD *pEntries,
  3772. PCHAR pLicense,
  3773. DWORD LicenseSize,
  3774. DWORD *pByteCount
  3775. )
  3776. {
  3777. RPC_STATUS RpcStatus;
  3778. if(!hServer)
  3779. {
  3780. *pResult = STATUS_UNSUCCESSFUL;
  3781. return( FALSE );
  3782. }
  3783. /*
  3784. * Impersonate the client
  3785. */
  3786. RpcStatus = RpcImpersonateClient( NULL );
  3787. if( RpcStatus != RPC_S_OK ) {
  3788. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationEnumerateLicenses: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3789. *pResult = ERROR_CANNOT_IMPERSONATE;
  3790. return( FALSE );
  3791. }
  3792. #ifdef not_hydrix
  3793. *pResult = xxxWinStationEnumerateLicenses(
  3794. pIndex,
  3795. pEntries,
  3796. pLicense,
  3797. pByteCount
  3798. );
  3799. #else
  3800. {
  3801. PLIST_ENTRY Head, Next;
  3802. PWSEXTENSION pWsx;
  3803. ICASRVPROCADDR IcaSrvProcAddr;
  3804. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  3805. RtlEnterCriticalSection( &WsxListLock );
  3806. Head = &WsxListHead;
  3807. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  3808. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  3809. if ( pWsx->pWsxWinStationEnumerateLicenses ) {
  3810. *pResult = pWsx->pWsxWinStationEnumerateLicenses(
  3811. pIndex,
  3812. pEntries,
  3813. pLicense,
  3814. pByteCount
  3815. );
  3816. break;
  3817. }
  3818. }
  3819. RtlLeaveCriticalSection( &WsxListLock );
  3820. }
  3821. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationEnumerateLicense: 0x%x\n", *pResult ));
  3822. #endif
  3823. RpcRevertToSelf();
  3824. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  3825. }
  3826. /*******************************************************************************
  3827. * RpcWinStationActivateLicense
  3828. *
  3829. * Called to Activate a license for a License
  3830. *
  3831. * ENTRY:
  3832. * hServer (input)
  3833. * Server handle
  3834. * pLicense (output)
  3835. * Pointer to a License structure that will be filled in with
  3836. * information based on pSerialNumberString
  3837. * LicenseSize (input)
  3838. * Size in bytes of the structure pointed to by pLicense
  3839. * pActivationCode (input)
  3840. * Pointer to a null-terminated, wide-character Activation Code string
  3841. *
  3842. * EXIT:
  3843. * TRUE -- The activate operation succeeded.
  3844. * FALSE -- The operation failed. Extended error status is available
  3845. * in pResult.
  3846. ******************************************************************************/
  3847. BOOLEAN
  3848. RpcWinStationActivateLicense(
  3849. HANDLE hServer,
  3850. DWORD *pResult,
  3851. PCHAR pLicense,
  3852. DWORD LicenseSize,
  3853. PWCHAR pActivationCode,
  3854. DWORD StringSize
  3855. )
  3856. {
  3857. RPC_STATUS RpcStatus;
  3858. if(!hServer)
  3859. {
  3860. *pResult = STATUS_UNSUCCESSFUL;
  3861. return( FALSE );
  3862. }
  3863. /*
  3864. * Impersonate the client
  3865. */
  3866. RpcStatus = RpcImpersonateClient( NULL );
  3867. if( RpcStatus != RPC_S_OK ) {
  3868. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationActivateLicense: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3869. *pResult = ERROR_CANNOT_IMPERSONATE;
  3870. return( FALSE );
  3871. }
  3872. #ifdef not_hydrix
  3873. *pResult = xxxWinStationActivateLicense(
  3874. pLicense,
  3875. LicenseSize,
  3876. pActivationCode,
  3877. StringSize
  3878. );
  3879. #else
  3880. {
  3881. PLIST_ENTRY Head, Next;
  3882. PWSEXTENSION pWsx;
  3883. ICASRVPROCADDR IcaSrvProcAddr;
  3884. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  3885. RtlEnterCriticalSection( &WsxListLock );
  3886. Head = &WsxListHead;
  3887. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  3888. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  3889. if ( pWsx->pWsxWinStationActivateLicense ) {
  3890. *pResult = pWsx->pWsxWinStationActivateLicense(
  3891. pLicense,
  3892. LicenseSize,
  3893. pActivationCode,
  3894. StringSize
  3895. );
  3896. break;
  3897. }
  3898. }
  3899. RtlLeaveCriticalSection( &WsxListLock );
  3900. }
  3901. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationActivateLicense: 0x%x\n", *pResult ));
  3902. #endif
  3903. RpcRevertToSelf();
  3904. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  3905. }
  3906. /*****************************************************************************
  3907. * RpcWinStationQueryLicense
  3908. *
  3909. * Query the license(s) on the WinFrame server and the network
  3910. *
  3911. * ENTRY:
  3912. * hServer (input)
  3913. * Server handle
  3914. * pLicenseCounts (output)
  3915. * pointer to buffer to return license count structure
  3916. * ByteCount (input)
  3917. * length of buffer in bytes
  3918. *
  3919. * EXIT:
  3920. * TRUE -- The query operation succeeded.
  3921. * FALSE -- The operation failed. Extended error status is available
  3922. * in pResult.
  3923. ****************************************************************************/
  3924. BOOLEAN
  3925. RpcWinStationQueryLicense(
  3926. HANDLE hServer,
  3927. DWORD *pResult,
  3928. PCHAR pLicenseCounts,
  3929. ULONG ByteCount
  3930. )
  3931. {
  3932. RPC_STATUS RpcStatus;
  3933. if(!hServer)
  3934. {
  3935. *pResult = STATUS_UNSUCCESSFUL;
  3936. return( FALSE );
  3937. }
  3938. /*
  3939. * Impersonate the client
  3940. */
  3941. RpcStatus = RpcImpersonateClient( NULL );
  3942. if( RpcStatus != RPC_S_OK ) {
  3943. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationQueryLicense: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  3944. *pResult = ERROR_CANNOT_IMPERSONATE;
  3945. return( FALSE );
  3946. }
  3947. #ifdef not_hydrix
  3948. *pResult = QueryLicense(
  3949. (PLICENSE_COUNTS) pLicenseCounts,
  3950. ByteCount );
  3951. #else
  3952. {
  3953. PLIST_ENTRY Head, Next;
  3954. PWSEXTENSION pWsx;
  3955. ICASRVPROCADDR IcaSrvProcAddr;
  3956. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  3957. RtlEnterCriticalSection( &WsxListLock );
  3958. Head = &WsxListHead;
  3959. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  3960. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  3961. if ( pWsx->pWsxQueryLicense ) {
  3962. *pResult = pWsx->pWsxQueryLicense(
  3963. pLicenseCounts,
  3964. ByteCount );
  3965. break;
  3966. }
  3967. }
  3968. RtlLeaveCriticalSection( &WsxListLock );
  3969. }
  3970. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationQueryLicense: 0x%x\n", *pResult ));
  3971. #endif
  3972. RpcRevertToSelf();
  3973. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  3974. }
  3975. /*****************************************************************************
  3976. * RpcWinStationQueryUpdateRequired
  3977. *
  3978. * Query the license(s) on the WinFrame server and determine if an
  3979. * update is required.
  3980. *
  3981. * ENTRY:
  3982. * hServer (input)
  3983. * Server handle
  3984. * pUpdateFlag (output)
  3985. * Update flag, set if an update is required
  3986. *
  3987. * EXIT:
  3988. * TRUE -- The query operation succeeded.
  3989. * FALSE -- The operation failed. Extended error status is available
  3990. * in pResult.
  3991. ****************************************************************************/
  3992. BOOLEAN
  3993. RpcWinStationQueryUpdateRequired(
  3994. HANDLE hServer,
  3995. DWORD *pResult,
  3996. PULONG pUpdateFlag
  3997. )
  3998. {
  3999. RPC_STATUS RpcStatus;
  4000. if(!hServer)
  4001. {
  4002. *pResult = STATUS_UNSUCCESSFUL;
  4003. return( FALSE );
  4004. }
  4005. /*
  4006. * Impersonate the client
  4007. */
  4008. RpcStatus = RpcImpersonateClient( NULL );
  4009. if( RpcStatus != RPC_S_OK ) {
  4010. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationQueryUpdateRequired: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  4011. *pResult = ERROR_CANNOT_IMPERSONATE;
  4012. return( FALSE );
  4013. }
  4014. #ifdef not_hydrix
  4015. *pResult = xxxWinStationQueryUpdateRequired( pUpdateFlag );
  4016. #else
  4017. {
  4018. PLIST_ENTRY Head, Next;
  4019. PWSEXTENSION pWsx;
  4020. ICASRVPROCADDR IcaSrvProcAddr;
  4021. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  4022. RtlEnterCriticalSection( &WsxListLock );
  4023. Head = &WsxListHead;
  4024. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  4025. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  4026. if ( pWsx->pWsxWinStationQueryUpdateRequired ) {
  4027. *pResult = pWsx->pWsxWinStationQueryUpdateRequired( pUpdateFlag );
  4028. break;
  4029. }
  4030. }
  4031. RtlLeaveCriticalSection( &WsxListLock );
  4032. }
  4033. #endif
  4034. RpcRevertToSelf();
  4035. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  4036. }
  4037. /*******************************************************************************
  4038. * RpcWinStationRemoveLicense
  4039. *
  4040. * Called to remove a license diskette.
  4041. *
  4042. * ENTRY:
  4043. * hServer (input)
  4044. * Server handle
  4045. * pLicense (input)
  4046. * Pointer to a License structure containing the license to
  4047. * be removed
  4048. * LicenseSize (input)
  4049. * Size in bytes of the structure pointed to by pLicense
  4050. *
  4051. * EXIT:
  4052. * TRUE -- The remove operation succeeded.
  4053. * FALSE -- The operation failed. Extended error status is available
  4054. * in pResult.
  4055. ******************************************************************************/
  4056. BOOLEAN
  4057. RpcWinStationRemoveLicense(
  4058. HANDLE hServer,
  4059. DWORD *pResult,
  4060. PCHAR pLicense,
  4061. DWORD LicenseSize
  4062. )
  4063. {
  4064. RPC_STATUS RpcStatus;
  4065. if(!hServer)
  4066. {
  4067. *pResult = STATUS_UNSUCCESSFUL;
  4068. return( FALSE );
  4069. }
  4070. /*
  4071. * Impersonate the client
  4072. */
  4073. RpcStatus = RpcImpersonateClient( NULL );
  4074. if( RpcStatus != RPC_S_OK ) {
  4075. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationRemoveLicense: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  4076. *pResult = ERROR_CANNOT_IMPERSONATE;
  4077. return( FALSE );
  4078. }
  4079. #ifdef not_hydrix
  4080. *pResult = xxxWinStationRemoveLicense(
  4081. pLicense,
  4082. LicenseSize
  4083. );
  4084. #else
  4085. {
  4086. PLIST_ENTRY Head, Next;
  4087. PWSEXTENSION pWsx;
  4088. ICASRVPROCADDR IcaSrvProcAddr;
  4089. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  4090. RtlEnterCriticalSection( &WsxListLock );
  4091. Head = &WsxListHead;
  4092. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  4093. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  4094. if ( pWsx->pWsxWinStationRemoveLicense ) {
  4095. *pResult = pWsx->pWsxWinStationRemoveLicense(
  4096. pLicense,
  4097. LicenseSize
  4098. );
  4099. break;
  4100. }
  4101. }
  4102. RtlLeaveCriticalSection( &WsxListLock );
  4103. }
  4104. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationRemoveLicense: 0x%x\n", *pResult ));
  4105. #endif
  4106. RpcRevertToSelf();
  4107. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  4108. }
  4109. /*******************************************************************************
  4110. * RpcWinStationSetPoolCount
  4111. *
  4112. * Called to change the PoolCount for the given license
  4113. *
  4114. * ENTRY:
  4115. * hServer (input)
  4116. * Server handle
  4117. * pLicense (input)
  4118. * Pointer to a License structure containing the license to
  4119. * be removed
  4120. * LicenseSize (input)
  4121. * Size in bytes of the structure pointed to by pLicense
  4122. *
  4123. * EXIT:
  4124. * TRUE -- The change operation succeeded.
  4125. * FALSE -- The operation failed. Extended error status is available
  4126. * in pResult.
  4127. ******************************************************************************/
  4128. BOOLEAN
  4129. RpcWinStationSetPoolCount(
  4130. HANDLE hServer,
  4131. DWORD *pResult,
  4132. PCHAR pLicense,
  4133. DWORD LicenseSize
  4134. )
  4135. {
  4136. RPC_STATUS RpcStatus;
  4137. if(!hServer)
  4138. {
  4139. *pResult = STATUS_UNSUCCESSFUL;
  4140. return( FALSE );
  4141. }
  4142. /*
  4143. * Impersonate the client
  4144. */
  4145. RpcStatus = RpcImpersonateClient( NULL );
  4146. if( RpcStatus != RPC_S_OK ) {
  4147. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationSetPoolCount: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  4148. *pResult = ERROR_CANNOT_IMPERSONATE;
  4149. return( FALSE );
  4150. }
  4151. #ifdef not_hydrix
  4152. *pResult = xxxWinStationSetPoolCount(
  4153. pLicense,
  4154. LicenseSize
  4155. );
  4156. #else
  4157. {
  4158. PLIST_ENTRY Head, Next;
  4159. PWSEXTENSION pWsx;
  4160. ICASRVPROCADDR IcaSrvProcAddr;
  4161. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  4162. RtlEnterCriticalSection( &WsxListLock );
  4163. Head = &WsxListHead;
  4164. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  4165. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  4166. if ( pWsx->pWsxWinStationSetPoolCount ) {
  4167. *pResult = pWsx->pWsxWinStationSetPoolCount(
  4168. pLicense,
  4169. LicenseSize
  4170. );
  4171. break;
  4172. }
  4173. }
  4174. RtlLeaveCriticalSection( &WsxListLock );
  4175. }
  4176. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationSetPoolCount: 0x%x\n", *pResult ));
  4177. #endif
  4178. RpcRevertToSelf();
  4179. return( *pResult == ERROR_SUCCESS ? TRUE : FALSE );
  4180. }
  4181. /*****************************************************************************
  4182. * RpcWinStationAnnoyancePopup
  4183. ****************************************************************************/
  4184. BOOLEAN
  4185. RpcWinStationAnnoyancePopup(
  4186. HANDLE hServer,
  4187. DWORD *pResult,
  4188. ULONG LogonId
  4189. )
  4190. {
  4191. PWINSTATION pWinStation;
  4192. NTSTATUS Status;
  4193. if(!hServer)
  4194. {
  4195. *pResult = STATUS_UNSUCCESSFUL;
  4196. return( FALSE );
  4197. }
  4198. /*
  4199. * Make sure the caller is SYSTEM (WinLogon)
  4200. */
  4201. Status = RpcCheckSystemClient( LogonId );
  4202. if ( !NT_SUCCESS( Status ) ) {
  4203. *pResult = Status;
  4204. return( FALSE );
  4205. }
  4206. #ifdef not_hydrix
  4207. *pResult = WinStationLogonAnnoyance( LogonId );
  4208. #else
  4209. // Assume the worst
  4210. *pResult = (DWORD)STATUS_UNSUCCESSFUL;
  4211. // Check for compatibility
  4212. pWinStation = FindWinStationById( LogonId, FALSE );
  4213. if ( pWinStation != NULL ) {
  4214. if ( pWinStation->pWsx &&
  4215. pWinStation->pWsx->pWsxWinStationLogonAnnoyance ) {
  4216. UnlockWinStation( pWinStation );
  4217. *pResult = pWinStation->pWsx->pWsxWinStationLogonAnnoyance( LogonId );
  4218. RelockWinStation( pWinStation );
  4219. /*
  4220. * If WinStation has no Wsx structure, wen try to annoy it anyway.
  4221. * This will have the effect of sending annoy msgs to the console.
  4222. */
  4223. } else if ( pWinStation->pWsx == NULL ) {
  4224. PLIST_ENTRY Head, Next;
  4225. PWSEXTENSION pWsx;
  4226. ICASRVPROCADDR IcaSrvProcAddr;
  4227. RtlEnterCriticalSection( &WsxListLock );
  4228. Head = &WsxListHead;
  4229. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  4230. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  4231. if ( pWsx->pWsxWinStationLogonAnnoyance ) {
  4232. UnlockWinStation( pWinStation );
  4233. *pResult = pWsx->pWsxWinStationLogonAnnoyance( LogonId );
  4234. RelockWinStation( pWinStation );
  4235. break;
  4236. }
  4237. }
  4238. RtlLeaveCriticalSection( &WsxListLock );
  4239. }
  4240. ReleaseWinStation( pWinStation );
  4241. }
  4242. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationAnnoyancePopup: 0x%x\n", *pResult ));
  4243. #endif
  4244. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4245. }
  4246. /*****************************************************************************
  4247. * RpcWinStationCallback
  4248. ****************************************************************************/
  4249. BOOLEAN
  4250. RpcWinStationCallback(
  4251. HANDLE hServer,
  4252. DWORD *pResult,
  4253. ULONG LogonId,
  4254. PWCHAR pPhoneNumber,
  4255. DWORD PhoneNumberSize
  4256. )
  4257. {
  4258. NTSTATUS Status;
  4259. if(!hServer)
  4260. {
  4261. *pResult = STATUS_UNSUCCESSFUL;
  4262. return( FALSE );
  4263. }
  4264. /*
  4265. * Make sure the caller is SYSTEM (WinLogon)
  4266. */
  4267. Status = RpcCheckSystemClient( LogonId );
  4268. if ( !NT_SUCCESS( Status ) ) {
  4269. *pResult = Status;
  4270. return( FALSE );
  4271. }
  4272. *pResult = WinStationCallbackWorker( LogonId, pPhoneNumber );
  4273. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4274. }
  4275. /*****************************************************************************
  4276. * RpcWinStationBreakPoint
  4277. ****************************************************************************/
  4278. BOOLEAN
  4279. RpcWinStationBreakPoint(
  4280. HANDLE hServer,
  4281. DWORD *pResult,
  4282. ULONG LogonId,
  4283. BOOLEAN KernelFlag
  4284. )
  4285. {
  4286. /*
  4287. * This is obsolete and should be removed from the RPC code.
  4288. */
  4289. *pResult = STATUS_NOT_IMPLEMENTED;
  4290. RpcRaiseException(ERROR_INVALID_FUNCTION);
  4291. return FALSE;
  4292. }
  4293. /*****************************************************************************
  4294. * RpcWinStationReadRegistry
  4295. ****************************************************************************/
  4296. BOOLEAN
  4297. RpcWinStationReadRegistry(
  4298. HANDLE hServer,
  4299. DWORD *pResult
  4300. )
  4301. {
  4302. RPC_STATUS RpcStatus;
  4303. if(!hServer)
  4304. {
  4305. *pResult = STATUS_UNSUCCESSFUL;
  4306. return( FALSE );
  4307. }
  4308. RpcStatus = RpcImpersonateClient( NULL );
  4309. if( RpcStatus != RPC_S_OK ) {
  4310. *pResult = STATUS_ACCESS_DENIED;
  4311. return( FALSE );
  4312. }
  4313. if (!(IsCallerSystem() || IsCallerAdmin() )) {
  4314. *pResult = STATUS_ACCESS_DENIED;
  4315. RpcRevertToSelf();
  4316. return FALSE;
  4317. }
  4318. RpcRevertToSelf();
  4319. return RpcWinStationUpdateSettings(hServer, pResult, WINSTACFG_LEGACY, 0);
  4320. }
  4321. /*****************************************************************************
  4322. * RpcWinStationUpdateSettings
  4323. ****************************************************************************/
  4324. BOOLEAN
  4325. RpcWinStationUpdateSettings(
  4326. HANDLE hServer,
  4327. DWORD *pResult,
  4328. DWORD SettingsClass,
  4329. DWORD SettingsParameters
  4330. )
  4331. {
  4332. /*
  4333. * This API is not secured, since it is harmless. It tells the system
  4334. * to make sure all winstations are up to date with the registry. You
  4335. * must be system to write the keys, so the info would match for a normal
  4336. * user poking this call.
  4337. */
  4338. switch (SettingsClass) {
  4339. case WINSTACFG_SESSDIR:
  4340. {
  4341. if (!g_bPersonalTS && g_fAppCompat && g_bAdvancedServer) {
  4342. *pResult = UpdateSessionDirectory(SettingsParameters);
  4343. }
  4344. else {
  4345. // Do nothing in remote admin or on PTS
  4346. *pResult = STATUS_SUCCESS;
  4347. }
  4348. }
  4349. break;
  4350. case WINSTACFG_LEGACY:
  4351. {
  4352. *pResult = WinStationReadRegistryWorker();
  4353. }
  4354. break;
  4355. default:
  4356. {
  4357. *pResult = STATUS_INVALID_PARAMETER;
  4358. }
  4359. }
  4360. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4361. }
  4362. /*****************************************************************************
  4363. * RpcReInitializeSecurity
  4364. ****************************************************************************/
  4365. BOOLEAN
  4366. RpcWinStationReInitializeSecurity(
  4367. HANDLE hServer,
  4368. DWORD *pResult
  4369. )
  4370. {
  4371. RPC_STATUS RpcStatus;
  4372. if(!hServer)
  4373. {
  4374. *pResult = STATUS_UNSUCCESSFUL;
  4375. return( FALSE );
  4376. }
  4377. RpcStatus = RpcImpersonateClient( NULL );
  4378. if( RpcStatus != RPC_S_OK ) {
  4379. *pResult = STATUS_ACCESS_DENIED;
  4380. return( FALSE );
  4381. }
  4382. if (!(IsCallerSystem() || IsCallerAdmin() )) {
  4383. *pResult = STATUS_ACCESS_DENIED;
  4384. RpcRevertToSelf();
  4385. return FALSE;
  4386. }
  4387. RpcRevertToSelf();
  4388. *pResult = ReInitializeSecurityWorker();
  4389. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4390. }
  4391. /*****************************************************************************
  4392. * RpcWinStationWaitForConnect
  4393. ****************************************************************************/
  4394. BOOLEAN
  4395. RpcWinStationWaitForConnect(
  4396. HANDLE hServer,
  4397. DWORD *pResult,
  4398. DWORD ClientLogonId,
  4399. DWORD ClientProcessId
  4400. )
  4401. {
  4402. PWINSTATION pWinStation;
  4403. NTSTATUS Status = STATUS_SUCCESS;
  4404. HANDLE WinlogonStartHandle = NULL;
  4405. WCHAR szWinlogonStartEvent[MAX_PATH];
  4406. UNICODE_STRING WinlogonEventName;
  4407. OBJECT_ATTRIBUTES ObjA;
  4408. LARGE_INTEGER TimeOut ;
  4409. ULONG SleepDuration = 90 * 1000; // 90 seconds
  4410. if(!hServer)
  4411. {
  4412. *pResult = STATUS_UNSUCCESSFUL;
  4413. return( FALSE );
  4414. }
  4415. //
  4416. // Winlogon can call into Terminal Server, before we store the session id in its internal structure
  4417. // To prevent this, RpcWinStationWaitForConnect (which is called by Winlogon) will wait for a named event
  4418. // This is the same Named event (CsrStartEvent) which the Csr also waits for before calling into TermSrv
  4419. //
  4420. if (ClientLogonId != 0) {
  4421. wsprintf(szWinlogonStartEvent,
  4422. L"\\Sessions\\%d\\BaseNamedObjects\\CsrStartEvent",ClientLogonId);
  4423. RtlInitUnicodeString( &WinlogonEventName, szWinlogonStartEvent );
  4424. InitializeObjectAttributes( &ObjA, &WinlogonEventName, OBJ_OPENIF, NULL, NULL );
  4425. Status = NtCreateEvent( &WinlogonStartHandle,
  4426. EVENT_ALL_ACCESS,
  4427. &ObjA,
  4428. NotificationEvent,
  4429. FALSE );
  4430. if (!WinlogonStartHandle) {
  4431. Status = STATUS_INSUFFICIENT_RESOURCES;
  4432. goto error_exit;
  4433. } else {
  4434. TimeOut = RtlEnlargedIntegerMultiply( SleepDuration, -10000);
  4435. Status = NtWaitForSingleObject(WinlogonStartHandle, FALSE, &TimeOut);
  4436. NtClose(WinlogonStartHandle);
  4437. WinlogonStartHandle = NULL;
  4438. if (!NT_SUCCESS(Status) || (Status == STATUS_TIMEOUT)) {
  4439. // We timed out waiting for Session Creation to get complete - cant connect now, just exit
  4440. goto error_exit;
  4441. }
  4442. }
  4443. }
  4444. /*
  4445. * Make sure the caller is SYSTEM (WinLogon)
  4446. */
  4447. Status = RpcCheckSystemClient( ClientLogonId );
  4448. if ( !NT_SUCCESS( Status ) ) {
  4449. *pResult = Status;
  4450. return( FALSE );
  4451. }
  4452. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitForConnect, LogonId=%d\n",ClientLogonId ));
  4453. /*
  4454. * Find and lock client WinStation
  4455. */
  4456. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  4457. if ( pWinStation == NULL ) {
  4458. *pResult = (DWORD)STATUS_ACCESS_DENIED;
  4459. return( FALSE );
  4460. }
  4461. *pResult = (DWORD)WaitForConnectWorker( pWinStation, (HANDLE)(ULONG_PTR)ClientProcessId );
  4462. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4463. error_exit:
  4464. *pResult = Status;
  4465. //
  4466. // dont return STATUS_TIMEOUT.
  4467. //
  4468. if (*pResult == STATUS_TIMEOUT) *pResult = STATUS_UNSUCCESSFUL;
  4469. return FALSE;
  4470. }
  4471. /*****************************************************************************
  4472. * RpcWinStationNotifyLogon
  4473. ****************************************************************************/
  4474. BOOLEAN
  4475. RpcWinStationNotifyLogon(
  4476. HANDLE hServer,
  4477. DWORD *pResult,
  4478. DWORD ClientLogonId,
  4479. DWORD ClientProcessId,
  4480. BOOLEAN fUserIsAdmin,
  4481. DWORD UserToken,
  4482. PWCHAR pDomain,
  4483. DWORD DomainSize,
  4484. PWCHAR pUserName,
  4485. DWORD UserNameSize,
  4486. PWCHAR pPassword,
  4487. DWORD PasswordSize,
  4488. UCHAR Seed,
  4489. PCHAR pUserConfig,
  4490. DWORD ConfigSize,
  4491. BOOLEAN *pfIsRedirected
  4492. )
  4493. {
  4494. NTSTATUS Status;
  4495. if(!hServer)
  4496. {
  4497. *pResult = STATUS_UNSUCCESSFUL;
  4498. return( FALSE );
  4499. }
  4500. /*
  4501. * Do some buffer validation
  4502. * No of bytes is sent from the Client, so send half the length got
  4503. */
  4504. *pResult = IsZeroterminateStringW(pPassword, PasswordSize / sizeof(WCHAR) );
  4505. if (*pResult != STATUS_SUCCESS) {
  4506. return FALSE;
  4507. }
  4508. *pResult = IsZeroterminateStringW(pUserName, UserNameSize / sizeof(WCHAR) );
  4509. if (*pResult != STATUS_SUCCESS) {
  4510. return FALSE;
  4511. }
  4512. *pResult = IsZeroterminateStringW(pDomain, DomainSize / sizeof(WCHAR) );
  4513. if (*pResult != STATUS_SUCCESS) {
  4514. return FALSE;
  4515. }
  4516. /*
  4517. * Make sure the caller is SYSTEM (WinLogon)
  4518. */
  4519. Status = RpcCheckSystemClient( ClientLogonId );
  4520. if ( !NT_SUCCESS( Status ) ) {
  4521. *pResult = Status;
  4522. return( FALSE );
  4523. }
  4524. *pResult = WinStationNotifyLogonWorker(
  4525. ClientLogonId,
  4526. ClientProcessId,
  4527. fUserIsAdmin,
  4528. UserToken,
  4529. pDomain,
  4530. DomainSize,
  4531. pUserName,
  4532. UserNameSize,
  4533. pPassword,
  4534. PasswordSize,
  4535. Seed,
  4536. pUserConfig,
  4537. ConfigSize,
  4538. pfIsRedirected
  4539. );
  4540. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4541. }
  4542. /*****************************************************************************
  4543. * RpcWinStationNotifyLogoff
  4544. ****************************************************************************/
  4545. BOOLEAN
  4546. RpcWinStationNotifyLogoff(
  4547. HANDLE hServer,
  4548. DWORD ClientLogonId,
  4549. DWORD ClientProcessId,
  4550. DWORD *pResult
  4551. )
  4552. {
  4553. NTSTATUS Status;
  4554. if(!hServer)
  4555. {
  4556. *pResult = STATUS_UNSUCCESSFUL;
  4557. return( FALSE );
  4558. }
  4559. /*
  4560. * Make sure the caller is SYSTEM (WinLogon)
  4561. */
  4562. Status = RpcCheckSystemClient( ClientLogonId );
  4563. if ( !NT_SUCCESS( Status ) ) {
  4564. *pResult = Status;
  4565. return( FALSE );
  4566. }
  4567. *pResult = WinStationNotifyLogoffWorker(
  4568. ClientLogonId,
  4569. ClientProcessId
  4570. );
  4571. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4572. }
  4573. /*****************************************************************************
  4574. * RpcWinStationNotifyNewSession
  4575. *
  4576. * THIS FUNCTION IS OBSOLETE AND SHOULD BE REMOVED FROM FUTURE VERSIONS OF
  4577. * INTERFACE.
  4578. ****************************************************************************/
  4579. BOOLEAN
  4580. RpcWinStationNotifyNewSession(
  4581. HANDLE hServer,
  4582. DWORD *pResult,
  4583. DWORD ClientLogonId
  4584. )
  4585. {
  4586. *pResult = STATUS_SUCCESS;
  4587. return(TRUE);
  4588. }
  4589. /*******************************************************************************
  4590. * RpcWinStationSendMessage
  4591. *
  4592. * Sends a message to the specified window station object and optionally
  4593. * waits for a reply. The reply is returned to the caller of
  4594. * WinStationSendMessage.
  4595. *
  4596. * ENTRY:
  4597. * WinStationHandle (input)
  4598. * Specifies the window station object to send a message to.
  4599. * pTitle (input)
  4600. * Pointer to title for message box to display.
  4601. * TitleLength (input)
  4602. * Length of title to display in bytes.
  4603. * pMessage (input)
  4604. * Pointer to message to display.
  4605. * MessageLength (input)
  4606. * Length of message in bytes to display at the specified window station.
  4607. * Style (input)
  4608. * Standard Windows MessageBox() style parameter.
  4609. * Timeout (input)
  4610. * Response timeout in seconds. If message is not responded to in
  4611. * Timeout seconds then a response code of IDTIMEOUT (cwin.h) is
  4612. * returned to signify the message timed out.
  4613. * pResponse (output)
  4614. * Address to return selected response.
  4615. * DoNotWait (input)
  4616. * Do not wait for the response. Causes pResponse to be set to
  4617. * IDASYNC (cwin.h) if no errors queueing the message.
  4618. *
  4619. * EXIT:
  4620. * TRUE -- The send message operation succeeded.
  4621. * FALSE -- The operation failed. Extended error status is available
  4622. * using GetLastError.
  4623. ******************************************************************************/
  4624. BOOLEAN
  4625. RpcWinStationSendMessage(
  4626. HANDLE hServer,
  4627. DWORD *pResult,
  4628. ULONG LogonId,
  4629. PWCHAR pTitle,
  4630. ULONG TitleLength,
  4631. PWCHAR pMessage,
  4632. ULONG MessageLength,
  4633. ULONG Style,
  4634. ULONG Timeout,
  4635. PULONG pResponse,
  4636. BOOLEAN DoNotWait
  4637. )
  4638. {
  4639. PWINSTATION pWinStation;
  4640. WINSTATION_APIMSG WMsg;
  4641. OBJECT_ATTRIBUTES ObjA;
  4642. NTSTATUS Status;
  4643. NTSTATUS MessageDelieveryStatus;
  4644. if(!hServer)
  4645. {
  4646. *pResult = STATUS_UNSUCCESSFUL;
  4647. return( FALSE );
  4648. }
  4649. /*
  4650. * Make sure that the title and the message are NULL terminated.
  4651. */
  4652. pTitle[TitleLength-1] = L'\0';
  4653. pMessage[MessageLength-1] = L'\0';
  4654. /*
  4655. * Find and lock client WinStation
  4656. */
  4657. pWinStation = FindWinStationById( LogonId, FALSE );
  4658. if ( pWinStation == NULL ) {
  4659. *pResult = (DWORD)STATUS_CTX_WINSTATION_NOT_FOUND;
  4660. return( FALSE );
  4661. }
  4662. Status = RpcCheckClientAccess( pWinStation, WINSTATION_MSG, FALSE );
  4663. if ( !NT_SUCCESS( Status ) ) {
  4664. *pResult = Status;
  4665. ReleaseWinStation( pWinStation );
  4666. return( FALSE );
  4667. }
  4668. TRACE((hTrace,TC_ICASRV,TT_API1, "RpcWinStationSendMessage: pTitle %S\n", pTitle ));
  4669. TRACE((hTrace,TC_ICASRV,TT_API1, "RpcWinStationSendMessage: pMessage %S\n", pMessage ));
  4670. /*
  4671. * Marshall in the [in] parameters
  4672. *
  4673. * pTitle and pMessage will be mapped into client
  4674. * view at apropriate time and place
  4675. */
  4676. WMsg.u.SendMessage.pTitle = pTitle;
  4677. WMsg.u.SendMessage.TitleLength = TitleLength;
  4678. WMsg.u.SendMessage.pMessage = pMessage;
  4679. WMsg.u.SendMessage.MessageLength = MessageLength;
  4680. WMsg.u.SendMessage.Style = Style;
  4681. WMsg.u.SendMessage.Timeout = Timeout;
  4682. WMsg.u.SendMessage.DoNotWait = DoNotWait;
  4683. WMsg.u.SendMessage.DoNotWaitForCorrectDesktop = FALSE;
  4684. if( !DoNotWait ) {
  4685. WMsg.u.SendMessage.pStatus = &MessageDelieveryStatus;
  4686. WMsg.u.SendMessage.pResponse = pResponse;
  4687. } else {
  4688. WMsg.u.SendMessage.pStatus = NULL;
  4689. WMsg.u.SendMessage.pResponse = NULL;
  4690. }
  4691. WMsg.ApiNumber = SMWinStationDoMessage;
  4692. /*
  4693. * Create wait event
  4694. */
  4695. if( !DoNotWait ) {
  4696. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  4697. Status = NtCreateEvent( &WMsg.u.SendMessage.hEvent, EVENT_ALL_ACCESS, &ObjA,
  4698. NotificationEvent, FALSE );
  4699. if ( !NT_SUCCESS(Status) ) {
  4700. *pResult = Status;
  4701. goto done;
  4702. }
  4703. }
  4704. else
  4705. {
  4706. WMsg.u.SendMessage.hEvent = NULL;
  4707. }
  4708. /*
  4709. * Initialize response to IDTIMEOUT or IDASYNC
  4710. */
  4711. if (DoNotWait) {
  4712. *pResponse = IDASYNC;
  4713. } else {
  4714. *pResponse = IDTIMEOUT;
  4715. }
  4716. /*
  4717. * Tell the WinStation to display the message box
  4718. */
  4719. *pResult = SendWinStationCommand( pWinStation, &WMsg, 0 );
  4720. /*
  4721. * Wait for response, pResponse & MessageDelieveryStatus are filled in WinStationIcaReplyMessage
  4722. */
  4723. if( !DoNotWait ) {
  4724. if (*pResult == STATUS_SUCCESS) {
  4725. TRACE((hTrace,TC_ICASRV,TT_API1, "RpcWinStationSendMessage: wait for response\n" ));
  4726. UnlockWinStation( pWinStation );
  4727. Status = NtWaitForSingleObject( WMsg.u.SendMessage.hEvent, FALSE, NULL );
  4728. if ( !RelockWinStation( pWinStation ) ) {
  4729. Status = STATUS_CTX_CLOSE_PENDING;
  4730. }
  4731. else {
  4732. Status = MessageDelieveryStatus;
  4733. }
  4734. *pResult = Status;
  4735. TRACE((hTrace,TC_ICASRV,TT_API1, "RpcWinStationSendMessage: got response %u\n", *pResponse ));
  4736. }
  4737. NtClose( WMsg.u.SendMessage.hEvent );
  4738. }
  4739. done:
  4740. ReleaseWinStation( pWinStation );
  4741. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  4742. }
  4743. /*****************************************************************************
  4744. * SERVER_HANDLE_rundown
  4745. *
  4746. * Required RPC context run down routine.
  4747. *
  4748. * This gets called when the RPC client drops or closes
  4749. * the connection and allows us to cleanup any state
  4750. * information.
  4751. *
  4752. * ENTRY:
  4753. * phContext (input)
  4754. * Context handle being rundown
  4755. ****************************************************************************/
  4756. VOID
  4757. SERVER_HANDLE_rundown(
  4758. HANDLE hContext
  4759. )
  4760. {
  4761. DWORD Result;
  4762. PRPC_CLIENT_CONTEXT pContext = (PRPC_CLIENT_CONTEXT)hContext;
  4763. ULONG EventFlags;
  4764. TRACE((hTrace,TC_ICASRV,TT_API1,"TERMSRV: Context rundown, %p\n", hContext));
  4765. if(!pContext)
  4766. {
  4767. return;
  4768. }
  4769. //RpcWinStationCloseServerEx( &hContext, &Result );
  4770. //ASSERT(hContext == NULL);
  4771. // Free the wait event block if one was allocated
  4772. if ( pContext->pWaitEvent ) {
  4773. WinStationWaitSystemEventWorker( pContext, WEVENT_NONE, &EventFlags );
  4774. }
  4775. midl_user_free(hContext);
  4776. hContext = NULL;
  4777. return;
  4778. }
  4779. /*
  4780. * The following functions allow us to control the
  4781. * memory allocation and free functions of the RPC.
  4782. */
  4783. void __RPC_FAR * __RPC_USER
  4784. MIDL_user_allocate( size_t Size )
  4785. {
  4786. return( LocalAlloc(LMEM_FIXED,Size) );
  4787. }
  4788. void __RPC_USER
  4789. MIDL_user_free( void __RPC_FAR *p )
  4790. {
  4791. if (!PointerIsInGAPDatabase(p))
  4792. {
  4793. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: MIDL_user_free for 0x%x....FREE it\n",p));
  4794. LocalFree( p );
  4795. }
  4796. else
  4797. {
  4798. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: MIDL_user_free for 0x%x..................DON'T FREE IT\n",p));
  4799. }
  4800. }
  4801. /*******************************************************************************
  4802. * NotifySystemEvent
  4803. *
  4804. * Notify clients that a system event occured.
  4805. *
  4806. * ENTRY:
  4807. * EventMask (input)
  4808. * mask of event(s) that have occured
  4809. ******************************************************************************/
  4810. VOID
  4811. NotifySystemEvent( ULONG EventMask )
  4812. {
  4813. PLIST_ENTRY Head, Next;
  4814. PEVENT pWaitEvent;
  4815. NTSTATUS Status;
  4816. if ( IsListEmpty( &SystemEventHead ) ) {
  4817. return;
  4818. }
  4819. TRACE((hTrace,TC_ICAAPI,TT_API3, "TERMSRV: NotifySystemEvent, Event=0x%08x\n", EventMask ));
  4820. RtlEnterCriticalSection( &WinStationListLock );
  4821. Head = &SystemEventHead;
  4822. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  4823. pWaitEvent = CONTAINING_RECORD( Next, EVENT, EventListEntry );
  4824. if ( pWaitEvent->EventMask & EventMask ) {
  4825. pWaitEvent->EventFlags |= EventMask;
  4826. if ( pWaitEvent->fWaiter ) {
  4827. pWaitEvent->WaitResult = STATUS_SUCCESS;
  4828. NtSetEvent( pWaitEvent->Event, NULL );
  4829. }
  4830. }
  4831. }
  4832. RtlLeaveCriticalSection( &WinStationListLock );
  4833. }
  4834. /*****************************************************************************
  4835. * WinStationDisconnectWorker
  4836. *
  4837. * Function to disconnect a Winstation based on an RPC API request.
  4838. *
  4839. * ENTRY:
  4840. * pContext (input)
  4841. * Pointer to our context structure describing the connection.
  4842. * pMsg (input/output)
  4843. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  4844. ****************************************************************************/
  4845. NTSTATUS
  4846. WinStationDisconnectWorker(
  4847. ULONG LogonId,
  4848. BOOLEAN bWait,
  4849. BOOLEAN CallerIsRpc
  4850. )
  4851. {
  4852. PWINSTATION pWinStation;
  4853. ULONG ClientLogonId;
  4854. ULONG PdFlag;
  4855. WINSTATIONNAME WinStationName;
  4856. WINSTATIONNAME ListenName;
  4857. NTSTATUS Status;
  4858. BOOLEAN bConsoleSession = FALSE;
  4859. UINT LocalFlag = FALSE;
  4860. BOOLEAN bRelock;
  4861. BOOLEAN bIncrementFlag = FALSE;
  4862. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationDisconnect, LogonId=%d\n", LogonId ));
  4863. //
  4864. //There are some bad ginas that break
  4865. //console disconnection bug 345286
  4866. //
  4867. if(LogonId == 0 && !IsGinaVersionCurrent()) {
  4868. Status = STATUS_CTX_CONSOLE_DISCONNECT;
  4869. goto done;
  4870. }
  4871. /*
  4872. * Find and lock the WinStation struct for the specified LogonId
  4873. */
  4874. pWinStation = FindWinStationById( LogonId, FALSE );
  4875. if ( pWinStation == NULL ) {
  4876. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  4877. goto done;
  4878. }
  4879. if (LogonId == 0 && !bConsoleConnected){
  4880. Status = WaitForConsoleConnectWorker( pWinStation );
  4881. if (NT_SUCCESS(Status)) {
  4882. bConsoleConnected=TRUE;
  4883. } else {
  4884. ReleaseWinStation( pWinStation );
  4885. goto done;
  4886. }
  4887. }
  4888. /*
  4889. * Note if we are disconnecting a session that is connected to the console terminal.
  4890. */
  4891. bConsoleSession = pWinStation->fOwnsConsoleTerminal;
  4892. /*
  4893. * Verify that client has DISCONNECT access if its an RPC (external) caller.
  4894. *
  4895. * When ICASRV calls this function internally, it is not impersonating
  4896. * and fails the RpcCheckClientAccess() call. Internal calls are
  4897. * not a security problem since they come in as LPC messages on a secured
  4898. * port.
  4899. */
  4900. if ( CallerIsRpc ) {
  4901. RPC_STATUS RpcStatus;
  4902. /*
  4903. * Impersonate the client
  4904. */
  4905. RpcStatus = RpcImpersonateClient( NULL );
  4906. if ( RpcStatus != RPC_S_OK ) {
  4907. ReleaseWinStation( pWinStation );
  4908. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationDisconnectWorker: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  4909. Status = STATUS_CANNOT_IMPERSONATE;
  4910. goto done;
  4911. }
  4912. Status = RpcCheckClientAccess( pWinStation, WINSTATION_DISCONNECT, TRUE );
  4913. if ( !NT_SUCCESS( Status ) ) {
  4914. RpcRevertToSelf();
  4915. ReleaseWinStation( pWinStation );
  4916. goto done;
  4917. }
  4918. //
  4919. // If its remote RPC call we should ignore ClientLogonId
  4920. //
  4921. RpcStatus = I_RpcBindingIsClientLocal(
  4922. 0, // Active RPC call we are servicing
  4923. &LocalFlag
  4924. );
  4925. if( RpcStatus != RPC_S_OK ) {
  4926. RpcRevertToSelf();
  4927. ReleaseWinStation( pWinStation );
  4928. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationDisconnectWorker: IsClientLocal failed! RpcStatus 0x%x\n",RpcStatus));
  4929. Status = STATUS_UNSUCCESSFUL;
  4930. goto done;
  4931. }
  4932. if ( LocalFlag ) {
  4933. Status = RpcGetClientLogonId( &ClientLogonId );
  4934. if ( !NT_SUCCESS( Status ) ) {
  4935. RpcRevertToSelf();
  4936. ReleaseWinStation( pWinStation );
  4937. goto done;
  4938. }
  4939. }
  4940. RpcRevertToSelf();
  4941. }
  4942. /*
  4943. * If WinStation is already disconnected, then we're done
  4944. */
  4945. if ( !pWinStation->WinStationName[0] ) {
  4946. ReleaseWinStation( pWinStation );
  4947. return (STATUS_SUCCESS);
  4948. }
  4949. /*
  4950. * If we are disconnecting the console session, we want to make sure
  4951. * that we can precreate a session that would become the console session.
  4952. */
  4953. if (bConsoleSession && !ShutdownInProgress) {
  4954. UnlockWinStation(pWinStation);
  4955. Status = CheckIdleWinstation();
  4956. bRelock = RelockWinStation(pWinStation);
  4957. if (!NT_SUCCESS(Status) || !bRelock) {
  4958. if (NT_SUCCESS(Status)) {
  4959. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  4960. }
  4961. ReleaseWinStation( pWinStation );
  4962. goto done;
  4963. }
  4964. }
  4965. /*
  4966. * If busy with something already, don't do this
  4967. */
  4968. if ( pWinStation->NeverConnected || pWinStation->Flags ) {
  4969. ReleaseWinStation( pWinStation );
  4970. Status = STATUS_CTX_WINSTATION_BUSY;
  4971. goto done;
  4972. }
  4973. if (bConsoleSession) {
  4974. InterlockedIncrement(&gConsoleCreationDisable);
  4975. bIncrementFlag = TRUE;
  4976. }
  4977. /*
  4978. * If no broken reason/source have been set, then set them here.
  4979. *
  4980. * BrokenReason is Disconnect. BrokenSource is User if we are
  4981. * called via RPC and caller is disconnecting his own LogonId.
  4982. */
  4983. if ( pWinStation->BrokenReason == 0 ) {
  4984. pWinStation->BrokenReason = Broken_Disconnect;
  4985. if ( CallerIsRpc && LocalFlag && ClientLogonId == pWinStation->LogonId ) {
  4986. pWinStation->BrokenSource = BrokenSource_User;
  4987. } else {
  4988. pWinStation->BrokenSource = BrokenSource_Server;
  4989. }
  4990. }
  4991. /*
  4992. * If it's an external request (RPC) then set the last error
  4993. * state to the client to indicate what the reason for the
  4994. * disconnection was.
  4995. */
  4996. if ( CallerIsRpc && pWinStation)
  4997. {
  4998. if(pWinStation->pWsx &&
  4999. pWinStation->pWsx->pWsxSetErrorInfo &&
  5000. pWinStation->pWsxContext)
  5001. {
  5002. pWinStation->pWsx->pWsxSetErrorInfo(
  5003. pWinStation->pWsxContext,
  5004. TS_ERRINFO_RPC_INITIATED_DISCONNECT,
  5005. FALSE); //stack lock not held
  5006. }
  5007. }
  5008. /*
  5009. * If the RPC caller did not wish to wait for this disconnect,
  5010. * then queue an internal call for this to be done.
  5011. * This is safe now that we have done all of the above checks
  5012. * to determine that the caller has access to perform the
  5013. * disconnect and have set BrokenSource/Reason above.
  5014. */
  5015. if ( CallerIsRpc && !bWait ) {
  5016. ReleaseWinStation( pWinStation );
  5017. QueueWinStationDisconnect( LogonId );
  5018. Status = STATUS_SUCCESS;
  5019. goto done;
  5020. }
  5021. /*
  5022. * Preserve some of this WinStation's state in case it's
  5023. * needed after we disconnect and release it.
  5024. */
  5025. PdFlag = pWinStation->Config.Pd[0].Create.PdFlag;
  5026. wcscpy( WinStationName, pWinStation->WinStationName );
  5027. if ( gbListenerOff ) {
  5028. wcscpy( ListenName, pWinStation->ListenName );
  5029. }
  5030. /*
  5031. * Notify the licensing core of the disconnect. Failures are ignored.
  5032. */
  5033. (VOID)LCProcessConnectionDisconnect(pWinStation);
  5034. /*
  5035. * Disconnect the WinStation
  5036. */
  5037. pWinStation->Flags |= WSF_DISCONNECT;
  5038. Status = WinStationDoDisconnect( pWinStation, NULL, FALSE );
  5039. pWinStation->Flags &= ~WSF_DISCONNECT;
  5040. /*
  5041. * If there is no user logged on (logon time is 0),
  5042. * then queue a reset for this WinStation.
  5043. *
  5044. * We don't want to do this here directly since the RPC client may
  5045. * NOT have reset access. However, the behavior we want is that if
  5046. * a WinStation with no user logged on is disconnected, it gets reset.
  5047. * This is consistent with how we handle broken connections
  5048. * (see WinStationBrokenConnection() in wstlpc.c).
  5049. */
  5050. if ( RtlLargeIntegerEqualToZero( pWinStation->LogonTime ) ) {
  5051. QueueWinStationReset( pWinStation->LogonId);
  5052. }
  5053. ReleaseWinStation( pWinStation );
  5054. // Increment the total number of disconnected sessions
  5055. if (Status == STATUS_SUCCESS) {
  5056. InterlockedIncrement(&g_TermSrvDiscSessions);
  5057. }
  5058. /*
  5059. * For single-instance transports a listener must be re-created
  5060. * upon disconnection
  5061. */
  5062. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WinStationDisconnect: after disconnecting\n" ));
  5063. if ( PdFlag & PD_SINGLE_INST ) {
  5064. Status = QueueWinStationCreate( WinStationName );
  5065. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WinStationDisconnect: QueueWinStationCreate returned 0x%x\n", Status ));
  5066. if ( !NT_SUCCESS( Status ) ) {
  5067. goto done;
  5068. }
  5069. }
  5070. if ( gbListenerOff && ListenName[0]) {
  5071. StartStopListeners( ListenName, FALSE );
  5072. }
  5073. /*
  5074. * Determine return status and cleanup
  5075. */
  5076. done:
  5077. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationDisconnect, Status=0x%x\n", Status ));
  5078. if (bIncrementFlag) {
  5079. InterlockedDecrement(&gConsoleCreationDisable);
  5080. bIncrementFlag = FALSE;
  5081. }
  5082. // If we disconnected a Session owning the console terminal, go an create a new one
  5083. // to own it.
  5084. if (bConsoleSession) {
  5085. ENTERCRIT(&ConsoleLock);
  5086. if (!WinStationCheckConsoleSession()) {
  5087. /*
  5088. * Wake up the WinStationIdleControlThread
  5089. */
  5090. NtSetEvent(WinStationIdleControlEvent, NULL);
  5091. }
  5092. LEAVECRIT(&ConsoleLock);
  5093. }
  5094. return( Status );
  5095. }
  5096. /*****************************************************************************
  5097. * RpcGetUserSID
  5098. *
  5099. * Helper function to get the SID of the caller
  5100. *
  5101. * ENTRY:
  5102. * - BOOLEAN AlreadyImpersonating TRUE if the caller is already impersonating
  5103. * the client
  5104. * - PSID* ppSid : pointer to receive the SID pointer
  5105. *
  5106. * RETURN:
  5107. * - nt Status, the pointer to the Sid in ppSid if success, NULL otherwise.
  5108. ****************************************************************************/
  5109. NTSTATUS
  5110. RpcGetUserSID(
  5111. BOOLEAN AlreadyImpersonating,
  5112. PSID* ppSid
  5113. )
  5114. {
  5115. PSID pClientSid = NULL;
  5116. PTOKEN_USER TokenInfo = NULL;
  5117. HANDLE CurrentThreadToken = NULL;
  5118. ULONG SidLength;
  5119. ULONG Length;
  5120. RPC_STATUS RpcStatus;
  5121. NTSTATUS Status;
  5122. if (ppSid == NULL) {
  5123. return STATUS_INVALID_PARAMETER;
  5124. }
  5125. *ppSid = NULL;
  5126. /*
  5127. * Impersonate the client
  5128. */
  5129. if (!AlreadyImpersonating) {
  5130. RpcStatus = RpcImpersonateClient( NULL );
  5131. if (RpcStatus != RPC_S_OK) {
  5132. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcGetUserSID: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  5133. return STATUS_CANNOT_IMPERSONATE;
  5134. }
  5135. }
  5136. Status = NtOpenThreadToken(
  5137. NtCurrentThread(),
  5138. TOKEN_QUERY,
  5139. TRUE, // Use service's security context to open thread token
  5140. &CurrentThreadToken
  5141. );
  5142. if (!NT_SUCCESS(Status)) {
  5143. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcGetUserSID: Cannot open the current thread token %08lx\n",
  5144. Status));
  5145. goto done;
  5146. }
  5147. /*
  5148. * Determine size needed for token info buffer and allocate it
  5149. */
  5150. Status = NtQueryInformationToken( CurrentThreadToken, TokenUser,
  5151. NULL, 0, &Length );
  5152. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  5153. goto done;
  5154. }
  5155. TokenInfo = MemAlloc( Length );
  5156. if (TokenInfo == NULL) {
  5157. Status = STATUS_NO_MEMORY;
  5158. goto done;
  5159. }
  5160. /*
  5161. * Query token information to get client user's SID
  5162. */
  5163. Status = NtQueryInformationToken( CurrentThreadToken, TokenUser,
  5164. TokenInfo, Length, &Length );
  5165. if (!NT_SUCCESS( Status )) {
  5166. goto done;
  5167. }
  5168. SidLength = RtlLengthSid( TokenInfo->User.Sid );
  5169. pClientSid = (PSID) MemAlloc( SidLength );
  5170. if (pClientSid == NULL) {
  5171. Status = STATUS_NO_MEMORY;
  5172. goto done;
  5173. }
  5174. Status = RtlCopySid(SidLength, pClientSid, TokenInfo->User.Sid);
  5175. done:
  5176. if ( !AlreadyImpersonating ) {
  5177. RpcRevertToSelf();
  5178. }
  5179. if (CurrentThreadToken) {
  5180. NtClose( CurrentThreadToken );
  5181. }
  5182. if (TokenInfo) {
  5183. MemFree( TokenInfo );
  5184. }
  5185. if (!NT_SUCCESS(Status)) {
  5186. if (pClientSid) {
  5187. MemFree( pClientSid );
  5188. }
  5189. } else {
  5190. *ppSid = pClientSid;
  5191. }
  5192. return Status;
  5193. }
  5194. /*****************************************************************************
  5195. * WinStationConnectWorker
  5196. *
  5197. * Worker for handling WinStation connection called from RPC server.
  5198. *
  5199. * ENTRY:
  5200. * pContext (input)
  5201. * Pointer to our context structure describing the connection.
  5202. * bAutoReconnecting (input)
  5203. * Boolean set to TRUE to indicate that this is a connection for the
  5204. * purposes of autoreconnection. This is important to allow an atomic
  5205. * autoreconnection by properly handling the WSF_AUTORECONNECTING flag
  5206. * that otherwise guards against race conditions while autoreconnecting.
  5207. *
  5208. * pMsg (input/output)
  5209. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  5210. ****************************************************************************/
  5211. NTSTATUS
  5212. WinStationConnectWorker(
  5213. ULONG ClientLogonId,
  5214. ULONG ConnectLogonId,
  5215. ULONG TargetLogonId,
  5216. PWCHAR pPassword,
  5217. DWORD PasswordSize,
  5218. BOOLEAN bWait,
  5219. BOOLEAN bAutoReconnecting
  5220. )
  5221. {
  5222. PWINSTATION pClientWinStation;
  5223. PWINSTATION pSourceWinStation;
  5224. PWINSTATION pTargetWinStation;
  5225. PWINSTATION pWinStation;
  5226. PSID pClientSid;
  5227. UNICODE_STRING PasswordString;
  5228. BOOLEAN fWrongPassword;
  5229. PRECONNECT_INFO pTargetReconnectInfo = NULL;
  5230. PRECONNECT_INFO pSourceReconnectInfo = NULL;
  5231. BOOLEAN SourceConnected = FALSE;
  5232. WINSTATIONNAME SourceWinStationName;
  5233. NTSTATUS Status;
  5234. BOOLEAN bConsoleSession = FALSE;
  5235. ULONG ulIndex;
  5236. LONG lActiveCount = 0;
  5237. PLIST_ENTRY Head, Next;
  5238. BOOLEAN fSourceAutoReconnecting = FALSE;
  5239. BOOLEAN fTargetAutoReconnecting = FALSE;
  5240. //------------------------------------------------------------
  5241. /*
  5242. * Target winstation might still have user password
  5243. * used for auto-logon. Let's clear it here.
  5244. */
  5245. pTargetWinStation = FindWinStationById( TargetLogonId, FALSE );
  5246. if ( pTargetWinStation == NULL ) {
  5247. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5248. return Status;
  5249. }
  5250. //Since we don't need the password anymore, clean it up
  5251. if (pTargetWinStation->pNewClientCredentials != NULL) {
  5252. RtlSecureZeroMemory(pTargetWinStation->pNewClientCredentials->Password,
  5253. sizeof(pTargetWinStation->pNewClientCredentials->Password));
  5254. }
  5255. RtlSecureZeroMemory(pTargetWinStation->Config.Config.User.Password,
  5256. sizeof(pTargetWinStation->Config.Config.User.Password));
  5257. ReleaseWinStation( pTargetWinStation );
  5258. //------------------------------------------------------------
  5259. // Do not allow reconnection to the same session, for any session.
  5260. // BUG 506808
  5261. // This problem was only happening on a non-logged in console (bConsoleConnected=FALSE), when from
  5262. // some other session, TsCon was used to connection session0 to console session:
  5263. // tscon 0 /dest:console
  5264. //
  5265. if (TargetLogonId == ConnectLogonId)
  5266. {
  5267. Status = STATUS_CTX_WINSTATION_ACCESS_DENIED;
  5268. return Status;
  5269. }
  5270. //
  5271. //On session 0 it might happen that user already logged on,
  5272. //but termsrv is not notified yet.
  5273. //in this case "Local\\WinlogonTSSynchronizeEvent" event will be in
  5274. //nonsignaled state. We need to refuse all attempts to connect to
  5275. //session 0 untill this event is signaled.
  5276. //
  5277. if (ConnectLogonId == 0) {
  5278. HANDLE hSyncEvent;
  5279. DWORD dwWaitResult;
  5280. hSyncEvent = OpenEventW(SYNCHRONIZE, FALSE, L"Local\\WinlogonTSSynchronizeEvent");
  5281. if ( !hSyncEvent){
  5282. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL,
  5283. "TERMSRV: Cannot open WinlogonTSSynchronizeEvent event. ERROR: %d\n",GetLastError()));
  5284. return STATUS_OBJECT_NAME_NOT_FOUND;
  5285. }
  5286. dwWaitResult = WaitForSingleObject(hSyncEvent,0);
  5287. CloseHandle(hSyncEvent);
  5288. if(dwWaitResult != WAIT_OBJECT_0) {
  5289. TRACE((hTrace,TC_ICASRV,TT_API1,
  5290. "TERMSRV: WinStationConnectWorker. WinlogonTSSynchronizeEvent is not signaled.\n"));
  5291. return STATUS_CTX_WINSTATION_BUSY;
  5292. }
  5293. }
  5294. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationConnect, LogonId=%u, Target LogonId=%u, (%S)\n",
  5295. ConnectLogonId, TargetLogonId, pPassword ));
  5296. /*
  5297. * Allocate RECONNECT_INFO structures
  5298. */
  5299. if ((pTargetReconnectInfo = MemAlloc(sizeof(*pTargetReconnectInfo))) == NULL) {
  5300. return STATUS_NO_MEMORY;
  5301. }
  5302. if ((pSourceReconnectInfo = MemAlloc(sizeof(*pSourceReconnectInfo))) == NULL) {
  5303. MemFree(pTargetReconnectInfo);
  5304. return STATUS_NO_MEMORY;
  5305. }
  5306. Status = RpcGetUserSID( FALSE, &pClientSid);
  5307. if(!NT_SUCCESS(Status)) {
  5308. goto done;
  5309. }
  5310. /*
  5311. * on non server make sure to fail reconnect if it is going to endup in more than one active session.
  5312. */
  5313. if (!gbServer) {
  5314. Head = &WinStationListHead;
  5315. ENTERCRIT( &WinStationListLock );
  5316. for ( Next = Head->Flink; Next != Head; Next = Next->Flink) {
  5317. pWinStation = CONTAINING_RECORD( Next, WINSTATION, Links );
  5318. if ( (pWinStation->State == State_Active) || (pWinStation->State == State_Shadow) ){
  5319. if (pWinStation->LogonId != ConnectLogonId && pWinStation->LogonId != TargetLogonId ) {
  5320. if (!TSIsSessionHelpSession(pWinStation, NULL)) {
  5321. lActiveCount ++;
  5322. }
  5323. }
  5324. }
  5325. }
  5326. LEAVECRIT( &WinStationListLock );
  5327. if (lActiveCount != 0) {
  5328. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5329. MemFree( pClientSid );
  5330. goto done;
  5331. }
  5332. }
  5333. /*
  5334. * Find and lock the WinStation (source) for the specified LogonId
  5335. */
  5336. pSourceWinStation = FindWinStationById( ConnectLogonId, FALSE );
  5337. if ( pSourceWinStation == NULL ) {
  5338. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5339. MemFree( pClientSid );
  5340. goto done;
  5341. }
  5342. if (ConnectLogonId == 0 && !bConsoleConnected ){
  5343. Status = WaitForConsoleConnectWorker( pSourceWinStation );
  5344. if (NT_SUCCESS(Status)) {
  5345. bConsoleConnected=TRUE;
  5346. } else{
  5347. ReleaseWinStation( pSourceWinStation );
  5348. MemFree( pClientSid );
  5349. goto done;
  5350. }
  5351. }
  5352. /*
  5353. * Verify that there is someone logged on (SALIMC)
  5354. */
  5355. if ( (ConnectLogonId != 0) && !pSourceWinStation->pUserSid ) {
  5356. Status = STATUS_CTX_WINSTATION_ACCESS_DENIED;
  5357. ReleaseWinStation( pSourceWinStation );
  5358. MemFree( pClientSid );
  5359. goto done;
  5360. }
  5361. /*
  5362. * Verify that client has CONNECT access
  5363. *
  5364. * NOTE: This function clears pPassword whether successful or not
  5365. * to prevent its being paged out as clear text.
  5366. */
  5367. Status = _CheckConnectAccess(
  5368. pSourceWinStation,
  5369. pClientSid,
  5370. ClientLogonId,
  5371. pPassword,
  5372. PasswordSize
  5373. );
  5374. MemFree( pClientSid );
  5375. if ( !NT_SUCCESS( Status ) ) {
  5376. ReleaseWinStation( pSourceWinStation );
  5377. goto done;
  5378. }
  5379. //
  5380. // Deterime if source is part of an autoreconnection
  5381. //
  5382. fSourceAutoReconnecting = bAutoReconnecting &&
  5383. (pSourceWinStation->Flags & WSF_AUTORECONNECTING);
  5384. /*
  5385. * Mark the winstation as being connected. (SALIMC)
  5386. * If any operation (create/delete/reset/...) is already in progress
  5387. * on this winstation, then don't proceed with the connect.
  5388. * unless that operation is an autoreconnect and we are autoreconnecting
  5389. */
  5390. if (pSourceWinStation->LogonId == 0) {
  5391. if (pSourceWinStation->Flags && !fSourceAutoReconnecting) {
  5392. if ((pSourceWinStation->Flags & WSF_DISCONNECT) && (pSourceWinStation->UserName[0] == L'\0')) {
  5393. /* Let us wait for sometime here before setting Busy flag and exiting */
  5394. for (ulIndex=0; ulIndex < WINSTATION_WAIT_RETRIES; ulIndex++) {
  5395. if ( pSourceWinStation->Flags ) {
  5396. LARGE_INTEGER Timeout;
  5397. Timeout = RtlEnlargedIntegerMultiply( WINSTATION_WAIT_DURATION, -10000 );
  5398. UnlockWinStation( pSourceWinStation );
  5399. NtDelayExecution( FALSE, &Timeout );
  5400. if ( !RelockWinStation( pSourceWinStation ) ) {
  5401. ReleaseWinStation( pSourceWinStation );
  5402. Status = STATUS_CTX_WINSTATION_BUSY;
  5403. goto done;
  5404. }
  5405. } else {
  5406. break;
  5407. }
  5408. }
  5409. }
  5410. if (pSourceWinStation->Flags && !fSourceAutoReconnecting) {
  5411. #if DBG
  5412. DbgPrint("WinstationConnectWorker : Even after waiting for 2 mins,Winstation flag is not clear. Sending STATUS_CTX_WINSTATION_BUSY.\n");
  5413. #endif
  5414. Status = STATUS_CTX_WINSTATION_BUSY;
  5415. ReleaseWinStation( pSourceWinStation );
  5416. goto done;
  5417. }
  5418. }
  5419. } else if ( pSourceWinStation->NeverConnected ||
  5420. (pSourceWinStation->Flags && !fSourceAutoReconnecting) ||
  5421. (pSourceWinStation->State != State_Active &&
  5422. pSourceWinStation->State != State_Disconnected) ) {
  5423. Status = STATUS_CTX_WINSTATION_BUSY;
  5424. ReleaseWinStation( pSourceWinStation );
  5425. goto done;
  5426. }
  5427. pSourceWinStation->Flags |= WSF_CONNECT;
  5428. /*
  5429. * Unlock the source WinStation but keep a reference to it.
  5430. */
  5431. UnlockWinStation( pSourceWinStation );
  5432. /*
  5433. * Now find and lock the target WinStation
  5434. */
  5435. pTargetWinStation = FindWinStationById( TargetLogonId, FALSE );
  5436. if ( pTargetWinStation == NULL ) {
  5437. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5438. goto badname;
  5439. }
  5440. /*
  5441. * If this is a re-connection to Session 0 where no one is logged on, then it must be a request from the Client or should be a from a temp session attached to console
  5442. */
  5443. if ( (gbServer) && (ConnectLogonId == 0) && (!pSourceWinStation->pUserSid) ) {
  5444. BOOLEAN Check1 = FALSE, Check2 = FALSE ;
  5445. Check1 = pTargetWinStation->bRequestedSessionIDFieldValid && (pTargetWinStation->RequestedSessionID == 0);
  5446. Check2 = pTargetWinStation->fOwnsConsoleTerminal;
  5447. if ( !(Check1 || Check2) ) {
  5448. Status = STATUS_CTX_WINSTATION_ACCESS_DENIED;
  5449. ReleaseWinStation( pTargetWinStation );
  5450. goto badname;
  5451. }
  5452. }
  5453. if (TargetLogonId == 0 && !bConsoleConnected){
  5454. Status = WaitForConsoleConnectWorker( pTargetWinStation );
  5455. if (NT_SUCCESS(Status)) {
  5456. bConsoleConnected=TRUE;
  5457. } else {
  5458. ReleaseWinStation( pTargetWinStation );
  5459. goto badname;
  5460. }
  5461. }
  5462. /*
  5463. * Verify that client has DISCONNECT access
  5464. */
  5465. Status = RpcCheckClientAccess( pTargetWinStation, WINSTATION_DISCONNECT, FALSE );
  5466. if ( !NT_SUCCESS( Status ) )
  5467. goto targetnoaccess;
  5468. #if 0
  5469. BUG 495195
  5470. http://liveraid/?id=495195
  5471. /*
  5472. * Do not allow a client running on the same machine to reconnect a the console session to its own session.
  5473. */
  5474. if (IsValidLoopBack(pTargetWinStation, ConnectLogonId, ClientLogonId)) {
  5475. Status = STATUS_CTX_CONSOLE_CONNECT;
  5476. goto targetnoconsole;
  5477. }
  5478. #endif
  5479. /*
  5480. * On server do not allow reconnecting a non zero session to the iconsole.
  5481. */
  5482. if (pTargetWinStation->fOwnsConsoleTerminal && gbServer && (ConnectLogonId != 0)) {
  5483. Status = STATUS_CTX_CONSOLE_DISCONNECT;
  5484. goto targetnoconsole;
  5485. }
  5486. // Whistler supports reconnecting a session from Console to a given Remote Protocol
  5487. // But Whistler does not support direct reconnect from one remote protocol to a different remote protocol
  5488. // Check for the above condition and block this scenario
  5489. if ( (pSourceWinStation->Client.ProtocolType != PROTOCOL_CONSOLE) && (pTargetWinStation->Client.ProtocolType != PROTOCOL_CONSOLE) ) {
  5490. // This is not a Direct Console Disconnect/Reconnect Scenario
  5491. if (pSourceWinStation->Client.ProtocolType != pTargetWinStation->Client.ProtocolType) {
  5492. Status = STATUS_CTX_BAD_VIDEO_MODE ;
  5493. goto targetnoaccess;
  5494. }
  5495. }
  5496. /*
  5497. * Make sure the reconnected session is licensed.
  5498. */
  5499. Status = LCProcessConnectionReconnect(pSourceWinStation, pTargetWinStation);
  5500. if (!NT_SUCCESS(Status))
  5501. {
  5502. goto badlicense;
  5503. }
  5504. fTargetAutoReconnecting = bAutoReconnecting &&
  5505. (pTargetWinStation->Flags & WSF_AUTORECONNECTING);
  5506. /*
  5507. * Mark the winstation as being disconnected.
  5508. * If any operation (create/delete/reset/...) is already in progress
  5509. * on this winstation, then don't proceed with the connect.
  5510. */
  5511. if ( pTargetWinStation->NeverConnected ||
  5512. (pTargetWinStation->Flags && !fTargetAutoReconnecting)) {
  5513. Status = STATUS_CTX_WINSTATION_BUSY;
  5514. goto targetbusy;
  5515. }
  5516. pTargetWinStation->Flags |= WSF_DISCONNECT;
  5517. /*
  5518. * Disconnect the target WinStation
  5519. */
  5520. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationConnectWorker Disconnecting target!\n"));
  5521. /*
  5522. * Note if we are disconnecting the session that owns the console
  5523. */
  5524. if (pTargetWinStation->fOwnsConsoleTerminal) {
  5525. bConsoleSession = TRUE;
  5526. UnlockWinStation( pTargetWinStation );
  5527. ENTERCRIT(&ConsoleLock);
  5528. InterlockedIncrement(&gConsoleCreationDisable);
  5529. LEAVECRIT(&ConsoleLock);
  5530. if (!RelockWinStation( pTargetWinStation )) {
  5531. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5532. goto baddisconnecttarget;
  5533. }
  5534. }
  5535. Status = WinStationDoDisconnect( pTargetWinStation, pTargetReconnectInfo, FALSE );
  5536. if ( !NT_SUCCESS( Status ) ) {
  5537. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "WinStationConnectWorker Disconnecting target failed Status = %x!\n", Status));
  5538. goto baddisconnecttarget;
  5539. }
  5540. /*
  5541. * Unlock target WinStation but leave it referenced
  5542. */
  5543. UnlockWinStation( pTargetWinStation );
  5544. /*
  5545. * Relock the source WinStation
  5546. */
  5547. if ( !RelockWinStation( pSourceWinStation ) )
  5548. goto sourcedeleted;
  5549. /*
  5550. * The source Winstation might have been deleted while it was unlocked.
  5551. * Let's check this didn't happen because we don't want to reconnect to a
  5552. * going away session (Bug#206614).
  5553. */
  5554. if (pSourceWinStation->Terminating || pSourceWinStation->StateFlags & WSF_ST_WINSTATIONTERMINATE)
  5555. goto sourcedeleted;
  5556. /*
  5557. * If the source WinStation is currently connected, then disconnect it.
  5558. */
  5559. if ( pSourceWinStation->WinStationName[0] ) {
  5560. SourceConnected = TRUE;
  5561. /*
  5562. * For single-instance transports a listener must be re-created upon disconnection
  5563. * so we remember the source WinStation name.
  5564. */
  5565. if ( pSourceWinStation->Config.Pd[0].Create.PdFlag & PD_SINGLE_INST ) {
  5566. wcscpy( SourceWinStationName, pSourceWinStation->WinStationName );
  5567. }
  5568. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "WinStationConnectWorker Disconnecting Source!\n"));
  5569. /*
  5570. * Note if we are disconnecting the session that owns the console
  5571. */
  5572. if (pSourceWinStation->fOwnsConsoleTerminal) {
  5573. /*
  5574. * If we are disconnecting the console session, we want to make sure
  5575. * that we can precreate a session that would become the console session.
  5576. */
  5577. UnlockWinStation( pSourceWinStation );
  5578. if ( !ShutdownInProgress) {
  5579. Status = CheckIdleWinstation();
  5580. if (!NT_SUCCESS(Status)) {
  5581. RelockWinStation(pSourceWinStation);
  5582. goto baddisconnectsource;
  5583. }
  5584. }
  5585. bConsoleSession = TRUE;
  5586. ENTERCRIT(&ConsoleLock);
  5587. InterlockedIncrement(&gConsoleCreationDisable);
  5588. LEAVECRIT(&ConsoleLock);
  5589. if (!RelockWinStation( pSourceWinStation )) {
  5590. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5591. goto baddisconnectsource;
  5592. }
  5593. }
  5594. if(pSourceWinStation->pWsx &&
  5595. pSourceWinStation->pWsx->pWsxSetErrorInfo &&
  5596. pSourceWinStation->pWsxContext)
  5597. {
  5598. //
  5599. // Extended error reporting, set status to client.
  5600. //
  5601. pSourceWinStation->pWsx->pWsxSetErrorInfo(
  5602. pSourceWinStation->pWsxContext,
  5603. TS_ERRINFO_DISCONNECTED_BY_OTHERCONNECTION,
  5604. FALSE); //stack lock not held
  5605. }
  5606. Status = WinStationDoDisconnect( pSourceWinStation, pSourceReconnectInfo, TRUE );
  5607. if ( !NT_SUCCESS( Status ) ) {
  5608. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "WinStationConnectWorker Disconnecting source failed Status = %x!\n", Status));
  5609. goto baddisconnectsource;
  5610. }
  5611. }
  5612. /*
  5613. * Cause the source WinStation to connect using the stack state
  5614. * obtained from the target WinStation.
  5615. */
  5616. Status = WinStationDoReconnect( pSourceWinStation, pTargetReconnectInfo );
  5617. if ( !NT_SUCCESS( Status ) )
  5618. goto badconnectsource;
  5619. /*
  5620. * Indicate source WinStation connect is complete and unlock it.
  5621. */
  5622. pSourceWinStation->Flags &= ~WSF_CONNECT;
  5623. /*
  5624. * Set Last Reconnect Type for the Source WinStation
  5625. */
  5626. if (bAutoReconnecting) {
  5627. pSourceWinStation->LastReconnectType = AutoReconnect;
  5628. } else {
  5629. pSourceWinStation->LastReconnectType = ManualReconnect;
  5630. }
  5631. ReleaseWinStation( pSourceWinStation );
  5632. /*
  5633. * Indicate target WinStation disconnect is complete and unlock it.
  5634. */
  5635. if ( RelockWinStation( pTargetWinStation ) ) {
  5636. pTargetWinStation->Flags &= ~WSF_DISCONNECT;
  5637. /*
  5638. * Clear all client license data and indicate
  5639. * this WinStaion no longer holds a license.
  5640. */
  5641. if ( pTargetWinStation->pWsx &&
  5642. pTargetWinStation->pWsx->pWsxClearContext ) {
  5643. pTargetWinStation->pWsx->pWsxClearContext( pTargetWinStation->pWsxContext );
  5644. }
  5645. }
  5646. ReleaseWinStation( pTargetWinStation );
  5647. /*
  5648. * If the source WinStation was connected and we disconnected it above,
  5649. * then make sure we cleanup the reconnect structure.
  5650. * (This will also complete the disconnect by closing the endpoint
  5651. * that was connected to the source WinStation).
  5652. * Also, if the source WinStation was a single-instance transport,
  5653. * then we must re-create the listener.
  5654. */
  5655. if ( SourceConnected ) {
  5656. CleanupReconnect( pSourceReconnectInfo );
  5657. if ( (pSourceReconnectInfo->Config.Pd[0].Create.PdFlag & PD_SINGLE_INST) ) {
  5658. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinstationConnectWorker create new winstation: %S \n ", SourceWinStationName));
  5659. QueueWinStationCreate( SourceWinStationName );
  5660. }
  5661. }
  5662. // Stop the listener if the target was the last WinStation.
  5663. if ( gbListenerOff ) {
  5664. StartStopListeners( NULL, FALSE );
  5665. }
  5666. goto done;
  5667. /*=============================================================================
  5668. == Error returns
  5669. =============================================================================*/
  5670. /*
  5671. * Could not connect source WinStation
  5672. */
  5673. badconnectsource:
  5674. /*
  5675. * If source WinStation was connected, try to reconnect if it is
  5676. * NOT currently terminating. If the reconnect does not succeed,
  5677. * there's nothing else we can do.
  5678. */
  5679. if ( SourceConnected ) {
  5680. CleanupReconnect( pSourceReconnectInfo );
  5681. if ( !pSourceWinStation->Terminating &&
  5682. !pSourceWinStation->WinStationName[0] ) {
  5683. if ( pSourceReconnectInfo->Config.Pd[0].Create.PdFlag & PD_SINGLE_INST ) {
  5684. QueueWinStationCreate( pSourceReconnectInfo->WinStationName );
  5685. }
  5686. }
  5687. }
  5688. /*
  5689. * Could not disconnect source WinStation
  5690. */
  5691. baddisconnectsource:
  5692. /*
  5693. * Source WinStation was deleted
  5694. */
  5695. sourcedeleted:
  5696. pSourceWinStation->Flags &= ~WSF_CONNECT;
  5697. ReleaseWinStation( pSourceWinStation );
  5698. pSourceWinStation = NULL; // indicate source WinStation is released
  5699. /*
  5700. * Try to relock and reconnect the target WinStation.
  5701. */
  5702. if ( RelockWinStation( pTargetWinStation ) &&
  5703. !pTargetWinStation->Terminating &&
  5704. !pTargetWinStation->WinStationName[0] ) {
  5705. NTSTATUS st;
  5706. st = WinStationDoReconnect( pTargetWinStation, pTargetReconnectInfo );
  5707. if ( !NT_SUCCESS( st ) ) {
  5708. CleanupReconnect( pTargetReconnectInfo );
  5709. if ( pTargetReconnectInfo->Config.Pd[0].Create.PdFlag & PD_SINGLE_INST ) {
  5710. QueueWinStationCreate( pTargetReconnectInfo->WinStationName );
  5711. }
  5712. }
  5713. } else {
  5714. CleanupReconnect( pTargetReconnectInfo );
  5715. }
  5716. /*
  5717. * Could not disconnect target WinStation
  5718. * Could not query target WinStation stack state
  5719. */
  5720. baddisconnecttarget:
  5721. /* clear disconnect flag, unlock/derererence target WinStation */
  5722. pTargetWinStation->Flags &= ~WSF_DISCONNECT;
  5723. /*
  5724. * Target WinStation is busy or is the console
  5725. */
  5726. targetbusy:
  5727. badlicense:
  5728. targetnoconsole:
  5729. targetnoaccess:
  5730. ReleaseWinStation( pTargetWinStation );
  5731. badname:
  5732. /* clear connect flag, unlock/derererence source WinStation */
  5733. if ( pSourceWinStation ) {
  5734. if ( RelockWinStation( pSourceWinStation ) )
  5735. pSourceWinStation->Flags &= ~WSF_CONNECT;
  5736. ReleaseWinStation( pSourceWinStation );
  5737. }
  5738. done:
  5739. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationConnect, Status=0x%x\n", Status ));
  5740. // If we disconnected a Session owning the console terminal, go an create a new one
  5741. // to own it.
  5742. if (bConsoleSession) {
  5743. ENTERCRIT(&ConsoleLock);
  5744. InterlockedDecrement(&gConsoleCreationDisable);
  5745. if (!WinStationCheckConsoleSession()) {
  5746. /*
  5747. * Wake up the WinStationIdleControlThread
  5748. */
  5749. NtSetEvent(WinStationIdleControlEvent, NULL);
  5750. }
  5751. LEAVECRIT(&ConsoleLock);
  5752. }
  5753. // Increment total number of reconnected sessions
  5754. if (Status == STATUS_SUCCESS) {
  5755. InterlockedIncrement(&g_TermSrvReconSessions);
  5756. }
  5757. // free RECONNECT_INFO structures
  5758. MemFree(pTargetReconnectInfo);
  5759. MemFree(pSourceReconnectInfo);
  5760. return( Status );
  5761. }
  5762. /*****************************************************************************
  5763. * WinStationResetWorker
  5764. *
  5765. * Function to reset a Winstation based on an RPC API request.
  5766. *
  5767. * ENTRY:
  5768. * pContext (input)
  5769. * Pointer to our context structure describing the connection.
  5770. * pMsg (input/output)
  5771. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  5772. ****************************************************************************/
  5773. NTSTATUS
  5774. WinStationResetWorker(
  5775. ULONG LogonId,
  5776. BOOLEAN bWait,
  5777. BOOLEAN CallerIsRpc,
  5778. BOOLEAN bRecreate
  5779. )
  5780. {
  5781. PWINSTATION pWinStation;
  5782. ULONG ClientLogonId;
  5783. WINSTATIONNAME ListenName;
  5784. NTSTATUS Status;
  5785. ULONG ulIndex;
  5786. BOOL bConnectDisconnectPending = TRUE;
  5787. BOOL bConsoleSession = FALSE;
  5788. BOOL bListener = FALSE;
  5789. UINT LocalFlag = 0;
  5790. BOOLEAN bRelock;
  5791. DWORD dwWaitStatus ;
  5792. DWORD dwTimeOut ;
  5793. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationReset, LogonId=%d\n", LogonId ));
  5794. /*
  5795. * Find and lock the WinStation struct for the specified LogonId
  5796. */
  5797. pWinStation = FindWinStationById( LogonId, FALSE );
  5798. if ( pWinStation == NULL ) {
  5799. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5800. goto done;
  5801. }
  5802. /*
  5803. * For non zero sessions which are connected and has not yet been initialized, wait for it to be initialized (for max 10 mins)
  5804. */
  5805. if ((pWinStation->LogonId != 0) && (pWinStation->State == State_Connected)) {
  5806. dwTimeOut = 10 * 60 * 1000 ; // 10 mins
  5807. UnlockWinStation( pWinStation );
  5808. dwWaitStatus = WaitForSingleObject(pWinStation->SessionInitializedEvent, dwTimeOut);
  5809. RelockWinStation( pWinStation );
  5810. if (dwWaitStatus != WAIT_OBJECT_0) {
  5811. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationResetWorker: Timed out waiting for the Session to be initialized before Resetting. \n"));
  5812. Status = STATUS_TIMEOUT;
  5813. ReleaseWinStation( pWinStation );
  5814. goto done ;
  5815. }
  5816. }
  5817. /*
  5818. * Note if we are disconnecting a session that is connected to the console terminal.
  5819. */
  5820. bConsoleSession = pWinStation->fOwnsConsoleTerminal;
  5821. /*
  5822. * If we are Resetting a non-zero console session, we want to make sure
  5823. * that we can precreate a session that would become the console session.
  5824. */
  5825. if (bConsoleSession && !ShutdownInProgress && (pWinStation->LogonId != 0)) {
  5826. UnlockWinStation(pWinStation);
  5827. Status = CheckIdleWinstation();
  5828. bRelock = RelockWinStation(pWinStation);
  5829. if (!NT_SUCCESS(Status) || !bRelock) {
  5830. if (NT_SUCCESS(Status)) {
  5831. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  5832. }
  5833. ReleaseWinStation( pWinStation );
  5834. goto done;
  5835. }
  5836. }
  5837. /*
  5838. * Save off the listen name if needed later.
  5839. */
  5840. if ( pWinStation->Flags & WSF_LISTEN ) {
  5841. wcscpy(ListenName, pWinStation->WinStationName);
  5842. bListener = TRUE;
  5843. } else if (gbListenerOff) {
  5844. wcscpy(ListenName, pWinStation->ListenName);
  5845. }
  5846. /*
  5847. * Verify that client has RESET access if its an RPC (external) caller.
  5848. *
  5849. * When ICASRV calls this function internally, it is not impersonating
  5850. * and fails the RpcCheckClientAccess() call. Internal calls are
  5851. * not a security problem since they come in as LPC messages on a secured
  5852. * port.
  5853. */
  5854. if ( CallerIsRpc ) {
  5855. RPC_STATUS RpcStatus;
  5856. /*
  5857. * Impersonate the client
  5858. */
  5859. RpcStatus = RpcImpersonateClient( NULL );
  5860. if ( RpcStatus != RPC_S_OK ) {
  5861. ReleaseWinStation( pWinStation );
  5862. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationResetWorker: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  5863. Status = STATUS_CANNOT_IMPERSONATE;
  5864. goto done;
  5865. }
  5866. Status = RpcCheckClientAccess( pWinStation, WINSTATION_RESET, TRUE );
  5867. if ( !NT_SUCCESS( Status ) ) {
  5868. RpcRevertToSelf();
  5869. ReleaseWinStation( pWinStation );
  5870. goto done;
  5871. }
  5872. //
  5873. // If its remote RPC call we should ignore ClientLogonId
  5874. //
  5875. RpcStatus = I_RpcBindingIsClientLocal(
  5876. 0, // Active RPC call we are servicing
  5877. &LocalFlag
  5878. );
  5879. if( RpcStatus != RPC_S_OK ) {
  5880. RpcRevertToSelf();
  5881. ReleaseWinStation( pWinStation );
  5882. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationResetWorker: IsClientLocal failed! RpcStatus 0x%x\n",RpcStatus));
  5883. Status = STATUS_UNSUCCESSFUL;
  5884. goto done;
  5885. }
  5886. if ( LocalFlag ) {
  5887. Status = RpcGetClientLogonId( &ClientLogonId );
  5888. if ( !NT_SUCCESS( Status ) ) {
  5889. RpcRevertToSelf();
  5890. ReleaseWinStation( pWinStation );
  5891. goto done;
  5892. }
  5893. }
  5894. RpcRevertToSelf();
  5895. if(pWinStation->WinStationName[0] &&
  5896. pWinStation->pWsx &&
  5897. pWinStation->pWsx->pWsxSetErrorInfo &&
  5898. pWinStation->pWsxContext)
  5899. {
  5900. pWinStation->pWsx->pWsxSetErrorInfo(
  5901. pWinStation->pWsxContext,
  5902. TS_ERRINFO_RPC_INITIATED_LOGOFF,
  5903. FALSE); //stack lock not held
  5904. }
  5905. }
  5906. /*
  5907. * For console reset, logoff (SALIMC)
  5908. */
  5909. if ( LogonId == 0 ) {
  5910. Status = LogoffWinStation( pWinStation,EWX_FORCE | EWX_LOGOFF);
  5911. ReleaseWinStation( pWinStation );
  5912. if (NT_SUCCESS(Status) && bWait) {
  5913. DWORD dwRet;
  5914. dwRet = WaitForSingleObject(ConsoleLogoffEvent,120*1000);
  5915. if (dwRet == WAIT_TIMEOUT)
  5916. {
  5917. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: TimedOut wait for ConsoleLogoffEvent\n"));
  5918. Status = STATUS_TIMEOUT;
  5919. }
  5920. }
  5921. goto done;
  5922. }
  5923. /*
  5924. * Mark the winstation as being reset.
  5925. * If a reset/delete operation is already in progress
  5926. * on this winstation, then don't proceed with the delete.
  5927. * If the WinStation is currently in the process of connecting or
  5928. * disconnecting, then give it some time to complete before we continue.
  5929. * If connect/disconnect doesn't complete whithin timeout duration
  5930. * do not proceed with termination (bug#204614).
  5931. */
  5932. for (ulIndex=0; ulIndex < WINSTATION_WAIT_COMPLETE_RETRIES; ulIndex++) {
  5933. if ( pWinStation->Flags & (WSF_RESET | WSF_DELETE) ) {
  5934. ReleaseWinStation( pWinStation );
  5935. Status = STATUS_CTX_WINSTATION_BUSY;
  5936. goto done;
  5937. }
  5938. if ( pWinStation->Flags & (WSF_CONNECT | WSF_DISCONNECT |
  5939. WSF_AUTORECONNECTING) ) {
  5940. LARGE_INTEGER Timeout;
  5941. Timeout = RtlEnlargedIntegerMultiply( WINSTATION_WAIT_COMPLETE_DURATION, -10000 );
  5942. UnlockWinStation( pWinStation );
  5943. NtDelayExecution( FALSE, &Timeout );
  5944. if ( !RelockWinStation( pWinStation ) ) {
  5945. ReleaseWinStation( pWinStation );
  5946. Status = STATUS_SUCCESS;
  5947. goto done;
  5948. }
  5949. } else {
  5950. bConnectDisconnectPending = FALSE;
  5951. break;
  5952. }
  5953. }
  5954. if ( bConnectDisconnectPending ) {
  5955. ReleaseWinStation( pWinStation );
  5956. Status = STATUS_CTX_WINSTATION_BUSY;
  5957. goto done;
  5958. }
  5959. pWinStation->Flags |= WSF_RESET;
  5960. /*
  5961. * If no broken reason/source have been set, then set them here.
  5962. *
  5963. * BrokenReason is Terminate. BrokenSource is User if we are
  5964. * called via RPC and caller is resetting his own LogonId, or if
  5965. * the "Terminating" field is already set, then this is a reset
  5966. * from the WinStationTerminateThread after seeing WinLogon/CSR exit.
  5967. * Otherwise, this reset is the result of a call from another
  5968. * WinStation or a QueueWinStationReset call from within ICASRV.
  5969. */
  5970. if ( pWinStation->BrokenReason == 0 ) {
  5971. pWinStation->BrokenReason = Broken_Terminate;
  5972. if ( CallerIsRpc && LocalFlag && ClientLogonId == pWinStation->LogonId
  5973. || pWinStation->Terminating ) {
  5974. pWinStation->BrokenSource = BrokenSource_User;
  5975. } else {
  5976. pWinStation->BrokenSource = BrokenSource_Server;
  5977. }
  5978. }
  5979. /*
  5980. * If the RPC caller did not wish to wait for this reset,
  5981. * then queue an internal call for this to be done.
  5982. * This is safe now that we have done all of the above checks
  5983. * to determine that the caller has access to perform the
  5984. * reset and have set BrokenSource/Reason above.
  5985. */
  5986. if ( CallerIsRpc && !bWait ) {
  5987. // clear reset flag so the internal reset will proceed
  5988. pWinStation->Flags &= ~WSF_RESET;
  5989. ReleaseWinStation( pWinStation );
  5990. QueueWinStationReset( LogonId);
  5991. Status = STATUS_SUCCESS;
  5992. goto done;
  5993. }
  5994. /*
  5995. * Make sure this WinStation is ready to reset
  5996. */
  5997. WinStationTerminate( pWinStation );
  5998. /*
  5999. * If it's a listener, reset all active winstations of the same type
  6000. */
  6001. if ((pWinStation->Flags & WSF_LISTEN) && ListenName[0] && bRecreate) {
  6002. ResetGroupByListener(ListenName);
  6003. }
  6004. /*
  6005. * If WinStation is marked DownPending (and is not disconnected),
  6006. * then set it to the Down state, clear the DownPending and Reset flags,
  6007. * and release the WinStation.
  6008. */
  6009. if ( (pWinStation->Flags & WSF_DOWNPENDING) && pWinStation->WinStationName[0] ) {
  6010. pWinStation->State = State_Down;
  6011. pWinStation->Flags &= ~(WSF_DOWNPENDING | WSF_RESET);
  6012. ReleaseWinStation( pWinStation );
  6013. Status = STATUS_SUCCESS;
  6014. /*
  6015. * The WinStation is not DownPending so complete deleting it
  6016. * and then recreate it.
  6017. */
  6018. } else {
  6019. ULONG PdFlag;
  6020. ULONG WinStationFlags;
  6021. WINSTATIONNAME WinStationName;
  6022. /*
  6023. * Save WinStation name for later create call
  6024. */
  6025. WinStationFlags = pWinStation->Flags;
  6026. PdFlag = pWinStation->Config.Pd[0].Create.PdFlag;
  6027. wcscpy( WinStationName, pWinStation->WinStationName );
  6028. /*
  6029. * Call the WinStationDelete worker
  6030. */
  6031. WinStationDeleteWorker( pWinStation );
  6032. /*
  6033. * Now recreate the WinStation
  6034. */
  6035. if ( WinStationName[0] &&
  6036. bRecreate &&
  6037. ((WinStationFlags & WSF_LISTEN) || (PdFlag & PD_SINGLE_INST)) ) {
  6038. Status = WinStationCreateWorker( WinStationName, NULL, TRUE );
  6039. } else if ( WinStationFlags & WSF_IDLE ) {
  6040. // wake up WinStationIdleControlThread so that it recreates an idle session
  6041. NtSetEvent(WinStationIdleControlEvent, NULL);
  6042. } else {
  6043. Status = STATUS_SUCCESS;
  6044. }
  6045. }
  6046. // If we disconnected a Session owning the console terminal, go an create a new one
  6047. // to own it.
  6048. if (bConsoleSession) {
  6049. ENTERCRIT(&ConsoleLock);
  6050. if (!WinStationCheckConsoleSession()) {
  6051. /*
  6052. * Wake up the WinStationIdleControlThread
  6053. */
  6054. NtSetEvent(WinStationIdleControlEvent, NULL);
  6055. }
  6056. LEAVECRIT(&ConsoleLock);
  6057. }
  6058. if ( gbListenerOff && !bListener && ListenName[0] ) {
  6059. StartStopListeners( ListenName, FALSE );
  6060. }
  6061. /*
  6062. * Save return status
  6063. */
  6064. done:
  6065. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationReset, Status=0x%x\n", Status ));
  6066. return( Status );
  6067. }
  6068. /*****************************************************************************
  6069. * WinStationShutdownSystemWorker
  6070. *
  6071. * Function to shutdown the system from an RPC API request
  6072. *
  6073. * ENTRY:
  6074. * pContext (input)
  6075. * Pointer to our context structure describing the connection.
  6076. * pMsg (input/output)
  6077. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  6078. ****************************************************************************/
  6079. NTSTATUS
  6080. WinStationShutdownSystemWorker(
  6081. ULONG ClientLogonId,
  6082. ULONG ShutdownFlags
  6083. )
  6084. {
  6085. BOOL rc;
  6086. BOOLEAN WasEnabled;
  6087. NTSTATUS Status = 0;
  6088. NTSTATUS Status2;
  6089. PWINSTATION pWinStation;
  6090. UINT ExitWindowsFlags;
  6091. RPC_STATUS RpcStatus;
  6092. UINT LocalFlag;
  6093. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationShutdownSystem, Flags=%d\n", ShutdownFlags ));
  6094. /*
  6095. * Impersonate the client so that when the attempt is made to enable
  6096. * the SE_SHUTDOWN_PRIVILEGE, it will fail if the account is not admin.
  6097. */
  6098. RpcStatus = RpcImpersonateClient( NULL );
  6099. if( RpcStatus != RPC_S_OK ) {
  6100. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationShutdownSystemWorker: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  6101. Status = STATUS_CANNOT_IMPERSONATE;
  6102. goto done;
  6103. }
  6104. //
  6105. // If its remote RPC call we should ignore ClientLogonId
  6106. //
  6107. RpcStatus = I_RpcBindingIsClientLocal(
  6108. 0, // Active RPC call we are servicing
  6109. &LocalFlag
  6110. );
  6111. if( RpcStatus != RPC_S_OK ) {
  6112. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, " I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  6113. RpcRevertToSelf();
  6114. Status = STATUS_UNSUCCESSFUL;
  6115. goto done;
  6116. }
  6117. //
  6118. // we dont care about client logon id if this is called from remote machine.
  6119. // so lets set it zero. So its treated as shutdown from session 0.
  6120. //
  6121. if (!LocalFlag) {
  6122. ClientLogonId = 0;
  6123. }
  6124. /*
  6125. * We are called under RPC impersonation so that the current
  6126. * thread token represents the RPC client. If the RPC client
  6127. * does not have SE_SHUTDOWN_PRIVILEGE, the RtlAdjustPrivilege()
  6128. * will fail.
  6129. */
  6130. Status = RtlAdjustPrivilege(
  6131. SE_SHUTDOWN_PRIVILEGE,
  6132. TRUE, // Enable the PRIVILEGE
  6133. TRUE, // Use Thread token (under impersonation)
  6134. &WasEnabled
  6135. );
  6136. if( NT_SUCCESS( Status ) && !WasEnabled ) {
  6137. /*
  6138. * Principle of least rights says to not go around with privileges
  6139. * held you do not need. So we must disable the shutdown privilege
  6140. * if it was just a logoff force.
  6141. */
  6142. Status2 = RtlAdjustPrivilege(
  6143. SE_SHUTDOWN_PRIVILEGE,
  6144. FALSE, // Disable the PRIVILEGE
  6145. TRUE, // Use Thread token (under impersonation)
  6146. &WasEnabled
  6147. );
  6148. ASSERT( NT_SUCCESS(Status2) );
  6149. }
  6150. RpcRevertToSelf();
  6151. if ( Status == STATUS_NO_TOKEN ) {
  6152. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationShutdownSystemWorker: No Thread token!\n"));
  6153. goto done;
  6154. }
  6155. if ( !NT_SUCCESS( Status ) ) {
  6156. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationShutdownSystemWorker: RtlAdjustPrivilege failure 0x%x\n",Status));
  6157. goto done;
  6158. }
  6159. if ( ShutdownFlags == 0 )
  6160. goto done;
  6161. //
  6162. // At this point we know that the client has access to shutdown the machine.
  6163. // Now enable Shutdown privilege for the termsrv.exe process. This is done
  6164. // because winlogon only allow system processes to shutdown the machine if
  6165. // if no one is logged on the console session. If we just enable privilige
  6166. // for the impersonating thread winlogon will not consider it as a system
  6167. // process
  6168. //
  6169. Status = RtlAdjustPrivilege(
  6170. SE_SHUTDOWN_PRIVILEGE,
  6171. TRUE, // Enable the PRIVILEGE
  6172. FALSE, // Use Process Token
  6173. &WasEnabled
  6174. );
  6175. if ( !NT_SUCCESS( Status ) ) {
  6176. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationShutdownSystemWorker: RtlAdjustPrivilege failure 0x%x\n",Status));
  6177. goto done;
  6178. }
  6179. /*
  6180. * Set global shutdown flag
  6181. */
  6182. ShutdownInProgress = TRUE;
  6183. // Let TS leave SD in case of shutdown
  6184. if (!g_bPersonalTS && g_fAppCompat && g_bAdvancedServer) {
  6185. DestroySessionDirectory();
  6186. }
  6187. /*
  6188. * If logoff option is specified, then cause all WinStations
  6189. * to logoff now and don't restart them.
  6190. */
  6191. if ( ShutdownFlags & (WSD_SHUTDOWN | WSD_LOGOFF) ) {
  6192. Status = ShutdownLogoff( ClientLogonId, ShutdownFlags );
  6193. }
  6194. if ( ShutdownFlags & (WSD_SHUTDOWN | WSD_REBOOT | WSD_POWEROFF) ) {
  6195. /*
  6196. * If system will be rebooted or powered off, then cause
  6197. * the client WinStation that called us to logoff now.
  6198. * If shutdown from non-console, close the connection (self) here.
  6199. */
  6200. if ( (ShutdownFlags & (WSD_REBOOT | WSD_POWEROFF)) || ClientLogonId != 0) {
  6201. if (!ShutDownFromSessionID)
  6202. ShutDownFromSessionID = ClientLogonId;
  6203. // ShutdownTerminateNoWait = TRUE;
  6204. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: Start reset of last WinStation\n" ));
  6205. (VOID) DoForWinStationGroup( &ClientLogonId, 1,
  6206. (LPTHREAD_START_ROUTINE) WinStationShutdownReset );
  6207. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: Last WinStation reset\n" ));
  6208. if ( ClientLogonId == 0 ) {
  6209. DWORD dwRet;
  6210. dwRet = WaitForSingleObject(ConsoleLogoffEvent,120*1000);
  6211. if (dwRet == WAIT_TIMEOUT)
  6212. {
  6213. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationShutdownSystemWorker: Timedout waiting for ConsoleLogoffEvent\n"));
  6214. Status = STATUS_TIMEOUT;
  6215. }
  6216. }
  6217. }
  6218. /*
  6219. * Now complete system shutdown.
  6220. *
  6221. * Use ExitWindowsEx() so that console winlogon completes
  6222. * our shutdown. This is so that services get shutdown
  6223. * properly.
  6224. */
  6225. if (ClientLogonId == (USER_SHARED_DATA->ActiveConsoleId) ) {
  6226. ExitWindowsFlags = 0;
  6227. } else {
  6228. ExitWindowsFlags = EWX_FORCE;
  6229. }
  6230. if ( ShutdownFlags & WSD_REBOOT )
  6231. ExitWindowsFlags |= EWX_REBOOT;
  6232. else if ( ShutdownFlags & WSD_POWEROFF )
  6233. ExitWindowsFlags |= EWX_POWEROFF;
  6234. else
  6235. ExitWindowsFlags |= EWX_SHUTDOWN;
  6236. /*
  6237. * Need to pass the EWX_TERMSRV_INITIATED to let winlogon know
  6238. * that the shutdown was initiated by termsrv.
  6239. */
  6240. rc = ExitWindowsEx( ExitWindowsFlags | EWX_TERMSRV_INITIATED,SHTDN_REASON_LEGACY_API|SHTDN_REASON_MINOR_TERMSRV );
  6241. if( !rc ) {
  6242. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: ExitWindowsEx failed %d\n",GetLastError() ));
  6243. }
  6244. }
  6245. if( !WasEnabled ) {
  6246. /*
  6247. * Principle of least rights says to not go around with privileges
  6248. * held you do not need. So we must disable the shutdown privilege
  6249. * if it was just a logoff force.
  6250. */
  6251. Status2 = RtlAdjustPrivilege(
  6252. SE_SHUTDOWN_PRIVILEGE,
  6253. FALSE, // Disable the PRIVILEGE
  6254. FALSE, // Use Process Token
  6255. &WasEnabled
  6256. );
  6257. ASSERT( NT_SUCCESS(Status2) );
  6258. }
  6259. /*
  6260. * Save return status in API message
  6261. */
  6262. done:
  6263. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationShutdownSystem, Status=0x%x\n", Status ));
  6264. return( Status );
  6265. }
  6266. /*****************************************************************************
  6267. * WinStationTerminateProcessWorker
  6268. *
  6269. * Terminate the specified process
  6270. *
  6271. * ENTRY:
  6272. * ProcessId (input)
  6273. * process id of the process to terminate
  6274. * ExitCode (input)
  6275. * Termination status for each thread in the process
  6276. ****************************************************************************/
  6277. NTSTATUS
  6278. WinStationTerminateProcessWorker(
  6279. ULONG ProcessId,
  6280. ULONG ExitCode
  6281. )
  6282. {
  6283. OBJECT_ATTRIBUTES Obja;
  6284. CLIENT_ID ClientId;
  6285. BOOLEAN fWasEnabled = FALSE;
  6286. NTSTATUS Status;
  6287. NTSTATUS Status2;
  6288. SID_IDENTIFIER_AUTHORITY NtSidAuthority = SECURITY_NT_AUTHORITY;
  6289. HANDLE ProcHandle = NULL;
  6290. HANDLE TokenHandle = NULL;
  6291. PTOKEN_USER pTokenInfo = NULL;
  6292. ULONG TokenInfoLength;
  6293. ULONG ReturnLength;
  6294. int rc;
  6295. TRACE(( hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationTerminateProcess, PID=%d, ExitCode %u\n",
  6296. ProcessId, ExitCode ));
  6297. /*
  6298. * If possible, enable the debug privilege
  6299. */
  6300. (void) RtlAdjustPrivilege( SE_DEBUG_PRIVILEGE,
  6301. TRUE, // Enable the PRIVILEGE
  6302. TRUE, // Use Thread token (under impersonation)
  6303. &fWasEnabled );
  6304. /*
  6305. * Attempt to open the process for query and terminate access.
  6306. */
  6307. ClientId.UniqueThread = (HANDLE) NULL;
  6308. ClientId.UniqueProcess = (HANDLE) LongToHandle( ProcessId );
  6309. InitializeObjectAttributes( &Obja, NULL, 0, NULL, NULL );
  6310. Status = NtOpenProcess( &ProcHandle,
  6311. PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE,
  6312. &Obja,
  6313. &ClientId );
  6314. if ( !NT_SUCCESS(Status) )
  6315. goto restore;
  6316. /*
  6317. * Open the process token so we can query the user SID. If the user
  6318. * SID for this process is the SYSTEM SID, we will deny access to it.
  6319. * This is to prevent ADMINs from killing system processes.
  6320. */
  6321. Status = NtOpenProcessToken( ProcHandle, TOKEN_QUERY, &TokenHandle );
  6322. /*
  6323. * Its possible for OpenProcess above to succeed and NtOpenProcessToken
  6324. * to fail. One scenario is an ADMIN user trying to kill a USER process.
  6325. * Standard security allows ADMIN terminate access to the process but
  6326. * does not allow any access to the process token. In this case we
  6327. * will just skip the SID check and do the terminate below.
  6328. */
  6329. if ( NT_SUCCESS( Status ) ) {
  6330. /*
  6331. * Allocate buffer for reading user SID
  6332. */
  6333. TokenInfoLength = sizeof(TOKEN_USER) +
  6334. RtlLengthRequiredSid( SID_MAX_SUB_AUTHORITIES );
  6335. pTokenInfo = MemAlloc( TokenInfoLength );
  6336. if ( pTokenInfo == NULL ) {
  6337. Status = STATUS_NO_MEMORY;
  6338. goto freeit;
  6339. }
  6340. /*
  6341. * Query the user SID in the token
  6342. */
  6343. Status = NtQueryInformationToken( TokenHandle, TokenUser, pTokenInfo,
  6344. TokenInfoLength, &ReturnLength );
  6345. if ( !NT_SUCCESS( Status ) )
  6346. goto freeit;
  6347. /*
  6348. * If user SID for this process is the SYSTEM SID,
  6349. * then we don't allow it to be terminated.
  6350. */
  6351. if ( RtlEqualSid( gSystemSid, pTokenInfo->User.Sid ) ) {
  6352. Status = STATUS_ACCESS_DENIED;
  6353. goto freeit;
  6354. }
  6355. }
  6356. /*
  6357. * Now try to terminate the process
  6358. */
  6359. Status = NtTerminateProcess( ProcHandle, (NTSTATUS)ExitCode );
  6360. freeit:
  6361. if ( pTokenInfo )
  6362. MemFree( pTokenInfo );
  6363. if ( TokenHandle )
  6364. CloseHandle( TokenHandle );
  6365. if ( ProcHandle )
  6366. CloseHandle( ProcHandle );
  6367. restore:
  6368. if( !fWasEnabled ) {
  6369. /*
  6370. * Principle of least rights says to not go around with privileges
  6371. * held you do not need. So we must disable the debug privilege
  6372. * if it was not enabled on entry to this routine.
  6373. */
  6374. Status2 = RtlAdjustPrivilege(
  6375. SE_DEBUG_PRIVILEGE,
  6376. FALSE, // Disable the PRIVILEGE
  6377. TRUE, // Use Thread token (under impersonation)
  6378. &fWasEnabled
  6379. );
  6380. ASSERT( NT_SUCCESS(Status2) );
  6381. }
  6382. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationTerminateProcess, Status=0x%x\n", Status ));
  6383. return( Status );
  6384. }
  6385. /*****************************************************************************
  6386. * WinStationWaitSystemEventWorker
  6387. *
  6388. * Function to wait for a system event from an RPC API request.
  6389. *
  6390. * Only one event wait may be posted per server handle at a time. The
  6391. * code protects itself from misuse by returning STATUS_PIPE_BUSY if
  6392. * an eventwait is already outstanding, and the request is not a cancel.
  6393. *
  6394. * ENTRY:
  6395. * pContext (input)
  6396. * Pointer to our context structure describing the connection.
  6397. * pMsg (input/output)
  6398. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  6399. ****************************************************************************/
  6400. NTSTATUS
  6401. WinStationWaitSystemEventWorker(
  6402. HANDLE hServer,
  6403. ULONG EventMask,
  6404. PULONG pEventFlags
  6405. )
  6406. {
  6407. NTSTATUS Status;
  6408. PEVENT pWaitEvent;
  6409. OBJECT_ATTRIBUTES ObjA;
  6410. PRPC_CLIENT_CONTEXT pContext = (PRPC_CLIENT_CONTEXT)hServer;
  6411. static long s_cEvents = 0; //Used to count events in SystemEvent list.
  6412. //Protected by "WinStationListLock" Critical Section.
  6413. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEventWorker, Mask=0x%08x\n", EventMask ));
  6414. ASSERT( MAX_WINSTATION_RPC_THREADS > MAX_SYSTEM_EVENTS);
  6415. /*
  6416. * Protect ourselves from multiple threads calling in at once
  6417. */
  6418. RtlEnterCriticalSection( &WinStationListLock );
  6419. /*
  6420. * If client doesn't already have an event block,
  6421. * then allocate and initialize one now.
  6422. */
  6423. if ( pContext->pWaitEvent == NULL ) {
  6424. // If event mask is null or flush specified, then nothing to do
  6425. if ( EventMask == WEVENT_NONE || (EventMask & WEVENT_FLUSH) ) {
  6426. Status = STATUS_SUCCESS;
  6427. RtlLeaveCriticalSection( &WinStationListLock );
  6428. goto done;
  6429. }
  6430. if(s_cEvents == MAX_SYSTEM_EVENTS)
  6431. {
  6432. Status = STATUS_PIPE_BUSY;
  6433. RtlLeaveCriticalSection( &WinStationListLock );
  6434. goto done;
  6435. }
  6436. /*
  6437. * Allocate event block and initialize it
  6438. */
  6439. if ( (pWaitEvent = MemAlloc( sizeof(EVENT) )) == NULL ) {
  6440. Status = STATUS_NO_MEMORY;
  6441. RtlLeaveCriticalSection( &WinStationListLock );
  6442. goto done;
  6443. }
  6444. RtlZeroMemory( pWaitEvent, sizeof(EVENT) );
  6445. pWaitEvent->fWaiter = FALSE;
  6446. pWaitEvent->EventMask = EventMask;
  6447. pWaitEvent->EventFlags = 0;
  6448. /*
  6449. * Create an event to wait on
  6450. */
  6451. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  6452. Status = NtCreateEvent( &pWaitEvent->Event, EVENT_ALL_ACCESS, &ObjA,
  6453. NotificationEvent, FALSE );
  6454. if( !NT_SUCCESS(Status) ) {
  6455. MemFree( pWaitEvent );
  6456. RtlLeaveCriticalSection( &WinStationListLock );
  6457. goto done;
  6458. }
  6459. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEvent, Event=%p\n", pWaitEvent->Event ));
  6460. TRACE((hTrace,TC_ICAAPI,TT_API3, "TERMSRV: WinStationWaitSystemEvent, Event block=%p\n", pWaitEvent ));
  6461. /*
  6462. * Save event block pointer in RPC client context structure
  6463. * and insert in system event list.
  6464. */
  6465. pContext->pWaitEvent = pWaitEvent;
  6466. InsertTailList( &SystemEventHead, &pWaitEvent->EventListEntry );
  6467. s_cEvents++;
  6468. ASSERT(s_cEvents <= MAX_SYSTEM_EVENTS);
  6469. /*
  6470. * Wait for the event to be signaled
  6471. */
  6472. pWaitEvent->fWaiter = TRUE;
  6473. RtlLeaveCriticalSection( &WinStationListLock );
  6474. Status = WaitForSingleObject( pWaitEvent->Event, (DWORD)-1 );
  6475. RtlEnterCriticalSection( &WinStationListLock );
  6476. pWaitEvent->fWaiter = FALSE;
  6477. if ( NT_SUCCESS(Status) ) {
  6478. Status = pWaitEvent->WaitResult;
  6479. if( NT_SUCCESS(Status) ) {
  6480. *pEventFlags = pWaitEvent->EventFlags;
  6481. /*
  6482. * makarp - Fix For . (#21929)
  6483. */
  6484. pWaitEvent->EventFlags = 0;
  6485. }
  6486. }
  6487. /*
  6488. * If fClosing is set, then cleanup the eventwait entry and free it.
  6489. */
  6490. if ( pWaitEvent->fClosing ) {
  6491. pContext->pWaitEvent = NULL;
  6492. RemoveEntryList( &pWaitEvent->EventListEntry );
  6493. s_cEvents--;
  6494. ASSERT(s_cEvents >= 0);
  6495. RtlLeaveCriticalSection( &WinStationListLock );
  6496. NtClose( pWaitEvent->Event );
  6497. pWaitEvent->Event = NULL;
  6498. MemFree( pWaitEvent );
  6499. } else {
  6500. RtlLeaveCriticalSection( &WinStationListLock );
  6501. }
  6502. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEvent, Status=0x%x\n", Status ));
  6503. return( Status );
  6504. /*
  6505. * Client has an event block but wants to remove it
  6506. */
  6507. } else if ( EventMask == WEVENT_NONE ) {
  6508. pWaitEvent = pContext->pWaitEvent;
  6509. // If we have a waiter, mark the eventwait struct as closing
  6510. // and let the waiter clean up.
  6511. if ( pWaitEvent->fWaiter ) {
  6512. pWaitEvent->fClosing = TRUE;
  6513. pWaitEvent->WaitResult = STATUS_CANCELLED;
  6514. NtSetEvent( pWaitEvent->Event, NULL );
  6515. RtlLeaveCriticalSection( &WinStationListLock );
  6516. Status = STATUS_SUCCESS;
  6517. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WinStationWaitSystemEvent, Status=0x%x\n", Status ));
  6518. return( Status );
  6519. }
  6520. pContext->pWaitEvent = NULL;
  6521. RemoveEntryList( &pWaitEvent->EventListEntry );
  6522. s_cEvents--;
  6523. ASSERT(s_cEvents >= 0);
  6524. RtlLeaveCriticalSection( &WinStationListLock );
  6525. NtClose( pWaitEvent->Event );
  6526. pWaitEvent->Event = NULL;
  6527. MemFree( pWaitEvent );
  6528. Status = STATUS_SUCCESS;
  6529. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEvent, Status=0x%x\n", Status ));
  6530. return( Status );
  6531. /*
  6532. * Flush specified so we must release waiting client
  6533. */
  6534. } else if ( EventMask & WEVENT_FLUSH ) {
  6535. pWaitEvent = pContext->pWaitEvent;
  6536. if ( pWaitEvent->fWaiter ) {
  6537. pWaitEvent->WaitResult = STATUS_CANCELLED;
  6538. NtSetEvent( pWaitEvent->Event, NULL );
  6539. TRACE((hTrace,TC_ICAAPI,TT_API3, "TERMSRV: WinStationWaitSystemEvent, event wait cancelled\n" ));
  6540. }
  6541. RtlLeaveCriticalSection( &WinStationListLock );
  6542. Status = STATUS_SUCCESS;
  6543. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEvent, Status=0x%x\n", Status ));
  6544. return( Status );
  6545. /*
  6546. * Client already has an event block and is calling again
  6547. * to wait for another event. Update the EventMask in case it
  6548. * changed from the original call.
  6549. */
  6550. } else {
  6551. pWaitEvent = pContext->pWaitEvent;
  6552. // Only allow one waiter
  6553. if ( pWaitEvent->fWaiter ) {
  6554. RtlLeaveCriticalSection( &WinStationListLock );
  6555. Status = STATUS_PIPE_BUSY;
  6556. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WinStationWaitSystemEvent, Status=0x%x\n", Status ));
  6557. return( Status );
  6558. }
  6559. pWaitEvent->EventMask = EventMask;
  6560. /*
  6561. * If additional events occured while client was processing
  6562. * previous events, then just return to the client now.
  6563. */
  6564. if ( pWaitEvent->EventFlags &= EventMask ) {
  6565. *pEventFlags = pWaitEvent->EventFlags;
  6566. pWaitEvent->EventFlags = 0;
  6567. Status = STATUS_SUCCESS;
  6568. RtlLeaveCriticalSection( &WinStationListLock );
  6569. TRACE((hTrace,TC_ICAAPI,TT_API3, "TERMSRV: WinStationWaitSystemEvent, returning immediately\n" ));
  6570. return( Status );
  6571. } else {
  6572. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEvent, waiting for event\n" ));
  6573. // Reset the event
  6574. NtResetEvent( pWaitEvent->Event, NULL );
  6575. /*
  6576. * Wait for the event to be signaled
  6577. */
  6578. pWaitEvent->fWaiter = TRUE;
  6579. RtlLeaveCriticalSection( &WinStationListLock );
  6580. Status = WaitForSingleObject( pWaitEvent->Event, (DWORD)-1 );
  6581. RtlEnterCriticalSection( &WinStationListLock );
  6582. pWaitEvent->fWaiter = FALSE;
  6583. if( NT_SUCCESS(Status) ) {
  6584. Status = pWaitEvent->WaitResult;
  6585. if( NT_SUCCESS(Status) ) {
  6586. *pEventFlags = pWaitEvent->EventFlags;
  6587. /*
  6588. * makarp - Fix For . (#21929)
  6589. */
  6590. pWaitEvent->EventFlags = 0;
  6591. }
  6592. }
  6593. /*
  6594. * If fClosing is set, then cleanup the eventwait entry and free it.
  6595. */
  6596. if ( pWaitEvent->fClosing ) {
  6597. pContext->pWaitEvent = NULL;
  6598. RemoveEntryList( &pWaitEvent->EventListEntry );
  6599. s_cEvents--;
  6600. ASSERT(s_cEvents >= 0);
  6601. RtlLeaveCriticalSection( &WinStationListLock );
  6602. NtClose( pWaitEvent->Event );
  6603. pWaitEvent->Event = NULL;
  6604. MemFree( pWaitEvent );
  6605. } else {
  6606. RtlLeaveCriticalSection( &WinStationListLock );
  6607. }
  6608. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEvent, Status=0x%x\n", Status ));
  6609. return( Status );
  6610. }
  6611. }
  6612. done:
  6613. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationWaitSystemEvent, Status=0x%x\n", Status ));
  6614. return( Status );
  6615. }
  6616. /*****************************************************************************
  6617. * WinStationCallbackWorker
  6618. *
  6619. * Perform callback processing for the specified WinStation.
  6620. *
  6621. * ENTRY:
  6622. * LogonId (input)
  6623. * Logon Id of WinStation
  6624. * pPhoneNumber (input)
  6625. * Phone number string suitable for processing by TAPI
  6626. ****************************************************************************/
  6627. NTSTATUS
  6628. WinStationCallbackWorker(
  6629. ULONG LogonId,
  6630. PWCHAR pPhoneNumber
  6631. )
  6632. {
  6633. PWINSTATION pWinStation;
  6634. NTSTATUS Status;
  6635. /*
  6636. * Find and lock client WinStation
  6637. */
  6638. pWinStation = FindWinStationById( LogonId, FALSE );
  6639. if ( pWinStation == NULL ) {
  6640. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  6641. return( Status );
  6642. }
  6643. /*
  6644. * Unlock WinStation while Callback is in progress
  6645. */
  6646. UnlockWinStation( pWinStation );
  6647. if (pWinStation->hStack != NULL) {
  6648. Status = IcaStackCallback( pWinStation->hStack,
  6649. &pWinStation->Config,
  6650. pPhoneNumber,
  6651. pWinStation->pEndpoint,
  6652. pWinStation->EndpointLength,
  6653. &pWinStation->EndpointLength );
  6654. } else {
  6655. Status = STATUS_INVALID_PARAMETER;
  6656. }
  6657. return( Status );
  6658. }
  6659. /*****************************************************************************
  6660. * WinStationBreakPointWorker
  6661. *
  6662. * Message parameter unmarshalling function for WinStation API.
  6663. *
  6664. * ENTRY:
  6665. * pContext (input)
  6666. * Pointer to our context structure describing the connection.
  6667. *
  6668. * pMsg (input/output)
  6669. * Pointer to the API message, a superset of NT LPC PORT_MESSAGE.
  6670. ****************************************************************************/
  6671. NTSTATUS
  6672. WinStationBreakPointWorker(
  6673. ULONG LogonId,
  6674. BOOLEAN KernelFlag
  6675. )
  6676. {
  6677. NTSTATUS Status;
  6678. NTSTATUS Status2;
  6679. BOOLEAN WasEnabled;
  6680. WINSTATION_APIMSG WMsg;
  6681. PWINSTATION pWinStation;
  6682. /*
  6683. * We are called under RPC impersonation so that the current
  6684. * thread token represents the RPC client. If the RPC client
  6685. * does not have SE_SHUTDOWN_PRIVILEGE, the RtlAdjustPrivilege()
  6686. * will fail.
  6687. *
  6688. * SE_SHUTDOWN_PRIVILEGE is used for breakpoints because that is
  6689. * effectively what a break point does to the system.
  6690. */
  6691. Status = RtlAdjustPrivilege(
  6692. SE_SHUTDOWN_PRIVILEGE,
  6693. TRUE, // Enable the PRIVILEGE
  6694. TRUE, // Use Thread token (under impersonation)
  6695. &WasEnabled
  6696. );
  6697. if ( Status == STATUS_NO_TOKEN ) {
  6698. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationBreakPointWorker: No Thread token!\n"));
  6699. return( Status );
  6700. }
  6701. if ( !NT_SUCCESS( Status ) ) {
  6702. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationBreakPointWorker: RtlAdjustPrivilege failure 0x%x\n",Status));
  6703. return( Status );
  6704. }
  6705. /*
  6706. * Stop here if that's what was requested
  6707. */
  6708. if ( LogonId == (ULONG)-2 ) {
  6709. DbgBreakPoint();
  6710. Status = STATUS_SUCCESS;
  6711. goto Done;
  6712. }
  6713. /*
  6714. * Find and lock client WinStation
  6715. */
  6716. pWinStation = FindWinStationById( LogonId, FALSE );
  6717. if ( pWinStation == NULL ) {
  6718. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  6719. goto Done;
  6720. }
  6721. /*
  6722. * Tell the WinStation to breakpoint
  6723. */
  6724. WMsg.ApiNumber = SMWinStationDoBreakPoint;
  6725. WMsg.u.BreakPoint.KernelFlag = KernelFlag;
  6726. Status = SendWinStationCommand( pWinStation, &WMsg, 0 );
  6727. ReleaseWinStation( pWinStation );
  6728. Done:
  6729. if( !WasEnabled ) {
  6730. /*
  6731. * Principle of least rights says to not go around with privileges
  6732. * held you do not need.
  6733. */
  6734. Status2 = RtlAdjustPrivilege(
  6735. SE_SHUTDOWN_PRIVILEGE,
  6736. FALSE, // Disable the PRIVILEGE
  6737. TRUE, // Use Thread token (under impersonation)
  6738. &WasEnabled
  6739. );
  6740. ASSERT( NT_SUCCESS(Status2) );
  6741. }
  6742. return( Status );
  6743. }
  6744. NTSTATUS
  6745. WinStationEnableSessionIo(
  6746. PWINSTATION pWinStation,
  6747. BOOL bEnable
  6748. )
  6749. /*++
  6750. Description:
  6751. Funtion to disable keyboard and mouse input from session, this is to prevent
  6752. security hole that a hacker can send keystrock to bring up utility manager
  6753. before shadowing.
  6754. Parameters:
  6755. pWinStation (INPUT) : Pointer to winstation, function will ignore if session is
  6756. not a help session.
  6757. bEnable (INPUT) : TRUE to enable keyboard/mouse, FALSE otherwise.
  6758. Returns:
  6759. ...
  6760. Note:
  6761. WINSTATION structure must be locked. Two new IOCTL code so we don't introduce any regression.
  6762. --*/
  6763. {
  6764. HANDLE ChannelHandle;
  6765. NTSTATUS Status;
  6766. if( pWinStation->fOwnsConsoleTerminal )
  6767. {
  6768. //
  6769. // Don't want to disable mouse/keyboard input on active console session,
  6770. //
  6771. Status = STATUS_SUCCESS;
  6772. }
  6773. else
  6774. {
  6775. Status = IcaChannelOpen(
  6776. pWinStation->hIca,
  6777. Channel_Keyboard,
  6778. NULL,
  6779. &ChannelHandle
  6780. );
  6781. if ( NT_SUCCESS( Status ) ) {
  6782. Status = IcaChannelIoControl(
  6783. ChannelHandle,
  6784. (bEnable) ? IOCTL_ICA_CHANNEL_ENABLE_SESSION_IO : IOCTL_ICA_CHANNEL_DISABLE_SESSION_IO,
  6785. NULL, 0, NULL, 0, NULL
  6786. );
  6787. IcaChannelClose( ChannelHandle );
  6788. }
  6789. Status = IcaChannelOpen(
  6790. pWinStation->hIca,
  6791. Channel_Mouse,
  6792. NULL,
  6793. &ChannelHandle
  6794. );
  6795. if ( NT_SUCCESS( Status ) ) {
  6796. Status = IcaChannelIoControl( ChannelHandle,
  6797. (bEnable) ? IOCTL_ICA_CHANNEL_ENABLE_SESSION_IO : IOCTL_ICA_CHANNEL_DISABLE_SESSION_IO,
  6798. NULL, 0, NULL, 0, NULL );
  6799. IcaChannelClose( ChannelHandle );
  6800. }
  6801. }
  6802. return Status;
  6803. }
  6804. /*****************************************************************************
  6805. * WinStationNotifyLogonWorker
  6806. *
  6807. * Message parameter unmarshalling function for WinStation API.
  6808. ****************************************************************************/
  6809. NTSTATUS WinStationNotifyLogonWorker(
  6810. DWORD ClientLogonId,
  6811. DWORD ClientProcessId,
  6812. BOOLEAN fUserIsAdmin,
  6813. DWORD UserToken,
  6814. PWCHAR pDomain,
  6815. DWORD DomainSize,
  6816. PWCHAR pUserName,
  6817. DWORD UserNameSize,
  6818. PWCHAR pPassword,
  6819. DWORD PasswordSize,
  6820. UCHAR Seed,
  6821. PCHAR pUserConfig,
  6822. DWORD ConfigSize,
  6823. BOOLEAN *pfIsRedirected
  6824. )
  6825. {
  6826. extern GENERIC_MAPPING WinStaMapping;
  6827. extern LPCWSTR szTermsrv;
  6828. extern LPCWSTR szTermsrvSession;
  6829. PWINSTATION pWinStation;
  6830. HANDLE ClientToken, NewToken;
  6831. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  6832. OBJECT_ATTRIBUTES ObjA;
  6833. HANDLE ImpersonationToken;
  6834. PTOKEN_USER TokenInfo;
  6835. ULONG Length;
  6836. NTSTATUS Status = STATUS_SUCCESS;
  6837. ULONG UserNameLength = USERNAME_LENGTH;
  6838. ULONG DomainLength = DOMAIN_LENGTH;
  6839. BOOL bAccessCheckOk = FALSE;
  6840. DWORD GrantedAccess;
  6841. BOOL AccessStatus;
  6842. BOOL fGenerateOnClose;
  6843. PTSSD_CreateSessionInfo pCreateInfo = NULL;
  6844. BOOL bHaveCreateInfo = FALSE;
  6845. BOOL bQueueReset = FALSE;
  6846. BOOL bRedirect = FALSE; // TRUE: redirect this connection
  6847. BOOL bValidHelpSession;
  6848. BOOL bNoAccessCheck = FALSE;
  6849. BOOL fReconnectingToConsole = FALSE;
  6850. BOOL RetValue = FALSE;
  6851. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationNotifyLogon, LogonId=%d\n", ClientLogonId ));
  6852. *pfIsRedirected = FALSE;
  6853. /*
  6854. * Find and lock client WinStation
  6855. */
  6856. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  6857. if ( pWinStation == NULL ) {
  6858. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  6859. return Status;
  6860. }
  6861. //Since we don't need the password anymore, clean it up
  6862. if (pWinStation->pNewClientCredentials != NULL) {
  6863. RtlSecureZeroMemory(pWinStation->pNewClientCredentials->Password,
  6864. sizeof(pWinStation->pNewClientCredentials->Password));
  6865. }
  6866. RtlSecureZeroMemory(pWinStation->Config.Config.User.Password,
  6867. sizeof(pWinStation->Config.Config.User.Password));
  6868. if( sizeof( USERCONFIGW ) > ConfigSize ) {
  6869. ReleaseWinStation( pWinStation );
  6870. return( STATUS_ACCESS_VIOLATION );
  6871. }
  6872. //
  6873. // If this is a notification from Session 0, then clear the Mpr notification information
  6874. // Termsrv already erases this after query, but since this is critical information, lets Erase everything again
  6875. // This is to take care of the case where reconnect to Session 0 failed for some reason and we do not Erase these after Query
  6876. //
  6877. if (ClientLogonId == 0) {
  6878. RtlSecureZeroMemory( g_MprNotifyInfo.Domain, wcslen(g_MprNotifyInfo.Domain) * sizeof(WCHAR) );
  6879. RtlSecureZeroMemory( g_MprNotifyInfo.UserName, wcslen(g_MprNotifyInfo.UserName) * sizeof(WCHAR) );
  6880. RtlSecureZeroMemory( g_MprNotifyInfo.Password, wcslen(g_MprNotifyInfo.Password) * sizeof(WCHAR) );
  6881. }
  6882. if ( ShutdownInProgress ) {
  6883. ReleaseWinStation( pWinStation );
  6884. return ( STATUS_CTX_WINSTATION_ACCESS_DENIED );
  6885. }
  6886. pCreateInfo = MemAlloc(sizeof(TSSD_CreateSessionInfo));
  6887. if (NULL == pCreateInfo) {
  6888. ReleaseWinStation( pWinStation );
  6889. return ( STATUS_NO_MEMORY );
  6890. }
  6891. //
  6892. // Release filtered address
  6893. //
  6894. if (pWinStation->pRememberedAddress != NULL) {
  6895. Filter_RemoveOutstandingConnection( &pWinStation->pRememberedAddress->addr[0], pWinStation->pRememberedAddress->length );
  6896. MemFree(pWinStation->pRememberedAddress);
  6897. pWinStation->pRememberedAddress = NULL;
  6898. if( (ULONG)InterlockedDecrement( &NumOutStandingConnect ) == MaxOutStandingConnect )
  6899. {
  6900. if (hConnectEvent != NULL)
  6901. {
  6902. SetEvent(hConnectEvent);
  6903. }
  6904. }
  6905. }
  6906. // The client has communicated its initial configuration
  6907. // information. Check if we need to redirect the client for
  6908. // load balancing. Ignore the console!
  6909. // Note: Only go through this if SD is enabled, i.e. GetTSSD() returns valid value
  6910. if (ClientLogonId != 0 && !g_bPersonalTS && g_fAppCompat && g_bAdvancedServer && GetTSSD()) {
  6911. PTS_LOAD_BALANCE_INFO pLBInfo = NULL;
  6912. PWINSTATION pTargetWinStation = pWinStation;
  6913. ULONG ReturnLength;
  6914. BOOL bSuccess = FALSE;
  6915. pLBInfo = MemAlloc(sizeof(TS_LOAD_BALANCE_INFO));
  6916. if (NULL == pLBInfo) {
  6917. Status = STATUS_NO_MEMORY;
  6918. if (pWinStation->pNewNotificationCredentials != NULL) {
  6919. MemFree(pWinStation->pNewNotificationCredentials);
  6920. pWinStation->pNewNotificationCredentials = NULL;
  6921. }
  6922. ReleaseWinStation( pWinStation );
  6923. goto done;
  6924. }
  6925. // need to release it
  6926. ReleaseTSSD();
  6927. // Get the client load balance capability info. We continue onward
  6928. // to do a session directory query only when the client supports
  6929. // redirection and has not already been redirected to this server.
  6930. memset(pLBInfo, 0, sizeof(TS_LOAD_BALANCE_INFO));
  6931. Status = IcaStackIoControl(pTargetWinStation->hStack,
  6932. IOCTL_TS_STACK_QUERY_LOAD_BALANCE_INFO,
  6933. NULL, 0,
  6934. pLBInfo, sizeof(TS_LOAD_BALANCE_INFO),
  6935. &ReturnLength);
  6936. // Only check for possible redirection if this is the initial request
  6937. if (NT_SUCCESS(Status) && !pLBInfo->bRequestedSessionIDFieldValid) {
  6938. // On non-success, we'll have FALSE for all of our entries, on
  6939. // success valid values. So, save off the cluster info into the
  6940. // WinStation struct now.
  6941. pTargetWinStation->bClientSupportsRedirection =
  6942. pLBInfo->bClientSupportsRedirection;
  6943. pTargetWinStation->bRequestedSessionIDFieldValid =
  6944. pLBInfo->bRequestedSessionIDFieldValid;
  6945. pTargetWinStation->bClientRequireServerAddr =
  6946. pLBInfo->bClientRequireServerAddr;
  6947. pTargetWinStation->RequestedSessionID = pLBInfo->RequestedSessionID;
  6948. // Use the name & domain they used to actually log on
  6949. memset(pLBInfo->Domain, 0, sizeof(pLBInfo->Domain));
  6950. memset(pLBInfo->UserName, 0, sizeof(pLBInfo->UserName));
  6951. wcsncpy(pLBInfo->Domain, pDomain, DomainLength);
  6952. wcsncpy(pLBInfo->UserName, pUserName, UserNameLength);
  6953. TRACE((hTrace,TC_LOAD,TT_API1,
  6954. "Client LBInfo: Supports Redirect [%lx], "
  6955. "Session Id valid [%lx]:%lx, "
  6956. "Creds [%S\\%S]\n",
  6957. pLBInfo->bClientSupportsRedirection,
  6958. pLBInfo->bRequestedSessionIDFieldValid,
  6959. pLBInfo->RequestedSessionID,
  6960. pLBInfo->UserName, pLBInfo->Domain));
  6961. wcsncpy(pLBInfo->Password, pPassword, PasswordSize);
  6962. bSuccess = SessDirCheckRedirectClient(pTargetWinStation, pLBInfo);
  6963. // Clear password
  6964. if (0 != PasswordSize)
  6965. SecureZeroMemory(pLBInfo->Password, PasswordSize);
  6966. if (bSuccess) {
  6967. // The client should drop the socket, and we'll
  6968. // go ahead and drop this ongoing connection.
  6969. // Set an error status.
  6970. Status = STATUS_UNSUCCESSFUL;
  6971. *pfIsRedirected = TRUE;
  6972. bRedirect = TRUE;
  6973. TRACE((hTrace,TC_LOAD,TT_API1,
  6974. "Disconnected session found: redirecting client!\n"));
  6975. if (pLBInfo != NULL) {
  6976. MemFree(pLBInfo);
  6977. pLBInfo = NULL;
  6978. }
  6979. goto release;
  6980. }
  6981. else {
  6982. TRACE((hTrace,TC_LOAD,TT_API1,
  6983. "Disconnected session not found: status [%lx], pers [%ld], appcompat [%ld]\n",
  6984. Status, g_bPersonalTS, g_fAppCompat));
  6985. }
  6986. }
  6987. if (pLBInfo != NULL) {
  6988. MemFree(pLBInfo);
  6989. pLBInfo = NULL;
  6990. }
  6991. }
  6992. if (ClientLogonId == 0) {
  6993. //
  6994. //ReSet the Console Logon Event
  6995. //
  6996. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_INFO_LEVEL, "TERMSRV: WinStationNotifyLogon, ReSetting ConsoleLogoffEvent\n"));
  6997. NtResetEvent(ConsoleLogoffEvent, NULL);
  6998. }
  6999. /*
  7000. * Do not do anything if the session is not connected. The processing in this API assumes we are connected and have a
  7001. * valid stack.
  7002. */
  7003. if ((ClientLogonId != 0) && ((pWinStation->State != State_Connected) || pWinStation->StateFlags & WSF_ST_IN_DISCONNECT)) {
  7004. Status = STATUS_CTX_CLOSE_PENDING;
  7005. if (pWinStation->pNewNotificationCredentials != NULL) {
  7006. MemFree(pWinStation->pNewNotificationCredentials);
  7007. pWinStation->pNewNotificationCredentials = NULL;
  7008. }
  7009. ReleaseWinStation( pWinStation );
  7010. goto done;
  7011. }
  7012. if (ClientLogonId == 0 && !bConsoleConnected ){
  7013. Status = WaitForConsoleConnectWorker( pWinStation );
  7014. if (NT_SUCCESS(Status)) {
  7015. bConsoleConnected=TRUE;
  7016. } else {
  7017. if (pWinStation->pNewNotificationCredentials != NULL) {
  7018. MemFree(pWinStation->pNewNotificationCredentials);
  7019. pWinStation->pNewNotificationCredentials = NULL;
  7020. }
  7021. ReleaseWinStation( pWinStation );
  7022. goto done;
  7023. }
  7024. }
  7025. /*
  7026. * Upper level code has verified that this RPC
  7027. * is coming from a local client with SYSTEM access.
  7028. *
  7029. * We should be able to trust the ClientProcessId from
  7030. * SYSTEM code.
  7031. */
  7032. /*
  7033. * Ensure this is WinLogon calling
  7034. */
  7035. if ( (HANDLE)(ULONG_PTR)ClientProcessId != pWinStation->InitialCommandProcessId ) {
  7036. /*
  7037. * The console has a special problem with NTSD starting winlogon.
  7038. * It doesn't get notified until now what the PID if winlogon.exe
  7039. * instead of ntsd.exe is.
  7040. */
  7041. if ( !pWinStation->LogonId && !pWinStation->InitialProcessSet ) {
  7042. pWinStation->InitialCommandProcess = OpenProcess(
  7043. PROCESS_ALL_ACCESS,
  7044. FALSE,
  7045. (DWORD) ClientProcessId );
  7046. if ( pWinStation->InitialCommandProcess == NULL ) {
  7047. Status = STATUS_ACCESS_DENIED;
  7048. if (pWinStation->pNewNotificationCredentials != NULL) {
  7049. MemFree(pWinStation->pNewNotificationCredentials);
  7050. pWinStation->pNewNotificationCredentials = NULL;
  7051. }
  7052. ReleaseWinStation( pWinStation );
  7053. goto done;
  7054. }
  7055. pWinStation->InitialCommandProcessId = (HANDLE)(ULONG_PTR)ClientProcessId;
  7056. pWinStation->InitialProcessSet = TRUE;
  7057. }
  7058. else {
  7059. //Set flag saying that WinStationNotifyLogonWorker
  7060. //was successfully completed
  7061. pWinStation->StateFlags |= WSF_ST_LOGON_NOTIFIED;
  7062. if (pWinStation->pNewNotificationCredentials != NULL) {
  7063. MemFree(pWinStation->pNewNotificationCredentials);
  7064. pWinStation->pNewNotificationCredentials = NULL;
  7065. }
  7066. ReleaseWinStation( pWinStation );
  7067. Status = STATUS_SUCCESS;
  7068. goto done;
  7069. }
  7070. }
  7071. /*
  7072. * Verify the client license if appropriate
  7073. */
  7074. if ( pWinStation->pWsx && pWinStation->pWsx->pWsxVerifyClientLicense ) {
  7075. Status = pWinStation->pWsx->pWsxVerifyClientLicense(
  7076. pWinStation->pWsxContext,
  7077. pWinStation->Config.Pd[0].Create.SdClass);
  7078. }
  7079. if ( Status != STATUS_SUCCESS) {
  7080. if (pWinStation->pNewNotificationCredentials != NULL) {
  7081. MemFree(pWinStation->pNewNotificationCredentials);
  7082. pWinStation->pNewNotificationCredentials = NULL;
  7083. }
  7084. ReleaseWinStation( pWinStation );
  7085. goto done;
  7086. }
  7087. //
  7088. // DON'T CHECK RpcClientAccess. The client is always winlogon (verified
  7089. // before the call to this function) so this call does not check against
  7090. // the actual user logging in. This is done further down from here.
  7091. //
  7092. #if 0
  7093. if (ClientLogonId != 0)
  7094. {
  7095. Status = RpcCheckClientAccess( pWinStation, WINSTATION_LOGON, FALSE );
  7096. if ( !NT_SUCCESS( Status ) ) {
  7097. if (pWinStation->pNewNotificationCredentials != NULL) {
  7098. MemFree(pWinStation->pNewNotificationCredentials);
  7099. pWinStation->pNewNotificationCredentials = NULL;
  7100. }
  7101. ReleaseWinStation( pWinStation );
  7102. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationNotifyLogon, RpcCheckClientAccess failed=%x\n", Status ));
  7103. goto done;
  7104. }
  7105. }
  7106. #endif
  7107. /*
  7108. * Save user status
  7109. *
  7110. * NOTE: This flag should only be used by the annoyance thread,
  7111. * and not for any security sensitive operations. All
  7112. * security sensitive operations need to go through the
  7113. * NT SeAccessCheck so that auditing is done properly.
  7114. */
  7115. pWinStation->fUserIsAdmin = fUserIsAdmin;
  7116. if (!ClientLogonId && !pWinStation->pWsx) {
  7117. PLIST_ENTRY Head, Next;
  7118. PWSEXTENSION pWsx;
  7119. ICASRVPROCADDR IcaSrvProcAddr;
  7120. RtlEnterCriticalSection( &WsxListLock );
  7121. Head = &WsxListHead;
  7122. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  7123. pWsx = CONTAINING_RECORD( Next, WSEXTENSION, Links );
  7124. if ( pWsx->pWsxGetLicense ) {
  7125. if (!pWinStation->pWsxContext && pWsx->pWsxWinStationInitialize) {
  7126. Status = pWsx->pWsxWinStationInitialize(&pWinStation->pWsxContext);
  7127. }
  7128. Status = pWsx->pWsxGetLicense(pWinStation->pWsxContext,
  7129. pWinStation->hStack,
  7130. pWinStation->LogonId,
  7131. fUserIsAdmin);
  7132. break;
  7133. }
  7134. }
  7135. RtlLeaveCriticalSection( &WsxListLock );
  7136. } else {
  7137. if ( pWinStation->pWsx && pWinStation->pWsx->pWsxGetLicense ) {
  7138. Status = pWinStation->pWsx->pWsxGetLicense( pWinStation->pWsxContext,
  7139. pWinStation->hStack,
  7140. pWinStation->LogonId,
  7141. fUserIsAdmin );
  7142. }
  7143. }
  7144. if ( Status != STATUS_SUCCESS) {
  7145. HANDLE h;
  7146. PWSTR Strings[2];
  7147. /*
  7148. * Send event to event log
  7149. */
  7150. h = RegisterEventSource(NULL, gpszServiceName);
  7151. if (h) {
  7152. //
  7153. // Would have used UserName and Domain in this error message,
  7154. // but they aren't set yet.
  7155. //
  7156. Strings[0] = pUserName;
  7157. Strings[1] = pDomain;
  7158. ReportEvent(h, EVENTLOG_WARNING_TYPE, 0, EVENT_NO_LICENSES, NULL, 2, 0, Strings, NULL);
  7159. DeregisterEventSource(h);
  7160. }
  7161. if (pWinStation->pNewNotificationCredentials != NULL) {
  7162. MemFree(pWinStation->pNewNotificationCredentials);
  7163. pWinStation->pNewNotificationCredentials = NULL;
  7164. }
  7165. ReleaseWinStation( pWinStation );
  7166. goto done;
  7167. }
  7168. /*
  7169. * Get a valid copy of the clients token handle
  7170. */
  7171. Status = NtDuplicateObject( pWinStation->InitialCommandProcess,
  7172. (HANDLE)LongToHandle( UserToken ),
  7173. NtCurrentProcess(),
  7174. &ClientToken,
  7175. 0, 0,
  7176. DUPLICATE_SAME_ACCESS |
  7177. DUPLICATE_SAME_ATTRIBUTES );
  7178. if ( !NT_SUCCESS( Status ) )
  7179. goto baddupobject;
  7180. /*
  7181. * ClientToken is a primary token - create an impersonation token
  7182. * version of it so we can set it on our thread
  7183. */
  7184. InitializeObjectAttributes( &ObjA, NULL, 0L, NULL, NULL );
  7185. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  7186. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  7187. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  7188. SecurityQualityOfService.EffectiveOnly = FALSE;
  7189. ObjA.SecurityQualityOfService = &SecurityQualityOfService;
  7190. Status = NtDuplicateToken( ClientToken,
  7191. TOKEN_IMPERSONATE,
  7192. &ObjA,
  7193. FALSE,
  7194. TokenImpersonation,
  7195. &ImpersonationToken );
  7196. if ( !NT_SUCCESS( Status ) )
  7197. goto badduptoken;
  7198. /*
  7199. * Impersonate the client
  7200. */
  7201. Status = NtSetInformationThread( NtCurrentThread(),
  7202. ThreadImpersonationToken,
  7203. (PVOID)&ImpersonationToken,
  7204. (ULONG)sizeof(HANDLE) );
  7205. if ( !NT_SUCCESS( Status ) )
  7206. goto badimpersonate;
  7207. //
  7208. // security check
  7209. //
  7210. Status = ApplyWinStaMapping( pWinStation );
  7211. if( !NT_SUCCESS( Status ) )
  7212. {
  7213. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationNotifyLogon, ApplyWinStaMapping failed=%x\n", Status ));
  7214. goto noaccess;
  7215. }
  7216. // There is a race condition between this function and Reconnect - we may reach here when Reconnect is still pending
  7217. // In that case the ActiveConsoleId is -1 and we do access check for a non-admin user - this leads to access check failure
  7218. // Check for this special case and dont call AccessCheck for this Special case
  7219. fReconnectingToConsole = pWinStation->fReconnectingToConsole;
  7220. if ( (ClientLogonId == 0) && (USER_SHARED_DATA->ActiveConsoleId == -1) && (pWinStation->fReconnectPending) && (pWinStation->fReconnectingToConsole) ) {
  7221. bNoAccessCheck = TRUE ;
  7222. }
  7223. if (bNoAccessCheck == FALSE) {
  7224. if (ClientLogonId != (USER_SHARED_DATA->ActiveConsoleId))
  7225. //
  7226. // Since for PTS the remote session could have an ID of 0 or (1),
  7227. // we check for access only if session is not on console.
  7228. //
  7229. {
  7230. bAccessCheckOk = AccessCheckAndAuditAlarm(szTermsrv,
  7231. NULL,
  7232. (LPWSTR)szTermsrvSession,
  7233. (LPWSTR)szTermsrvSession,
  7234. WinStationGetSecurityDescriptor(pWinStation),
  7235. WINSTATION_LOGON,
  7236. &WinStaMapping,
  7237. FALSE,
  7238. &GrantedAccess,
  7239. &AccessStatus,
  7240. &fGenerateOnClose);
  7241. if (bAccessCheckOk)
  7242. {
  7243. if (AccessStatus == FALSE)
  7244. {
  7245. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WinStationNotifyLogon, AccessCheckAndAuditAlarm(%u) returned error 0x%x\n",
  7246. pWinStation->LogonId, GetLastError() ));
  7247. Status = STATUS_CTX_WINSTATION_ACCESS_DENIED;
  7248. goto noaccess;
  7249. }
  7250. else
  7251. {
  7252. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WinStationNotifyLogon, AccessCheckAndAuditAlarm(%u) returned no error \n",
  7253. pWinStation->LogonId));
  7254. }
  7255. }
  7256. else
  7257. {
  7258. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WinStationNotifyLogon, AccessCheckAndAuditAlarm(%u) failed 0x%x\n",
  7259. pWinStation->LogonId, GetLastError() ));
  7260. goto noaccess;
  7261. }
  7262. }
  7263. } // if ( !bNoAccessCheck)
  7264. /*
  7265. * Revert back to our threads default token.
  7266. */
  7267. NewToken = NULL;
  7268. NtSetInformationThread( NtCurrentThread(),
  7269. ThreadImpersonationToken,
  7270. (PVOID)&NewToken,
  7271. (ULONG)sizeof(HANDLE) );
  7272. /*
  7273. * See if OpenWinStation was successful
  7274. */
  7275. if ( !NT_SUCCESS( Status ) ) {
  7276. TRACE((hTrace,TC_ICASRV,TT_ERROR, "TERMSRV: WinStationNotifyLogon, OpenWinStation(%u) failed 0x%x\n",
  7277. pWinStation->LogonId, Status ));
  7278. goto noaccess;
  7279. }
  7280. /*
  7281. * Save User Name and Domain Name. Do this before the call into the
  7282. * license core so that the core knows who is calling.
  7283. */
  7284. wcsncpy( pWinStation->Domain, pDomain, DomainLength );
  7285. wcsncpy( pWinStation->UserName, pUserName, UserNameLength );
  7286. /*
  7287. * Call into the licensing core.
  7288. */
  7289. Status = LCProcessConnectionPostLogon(pWinStation);
  7290. if (Status != STATUS_SUCCESS)
  7291. {
  7292. goto nolicense;
  7293. }
  7294. /*
  7295. * note that post logon licensing happened
  7296. */
  7297. pWinStation->StateFlags |= WSF_ST_LICENSING;
  7298. if (pWinStation->pWsx &&
  7299. pWinStation->pWsx->pWsxLogonNotify) {
  7300. if ((ClientLogonId != 0) && (pWinStation->State != State_Connected || pWinStation->StateFlags & WSF_ST_IN_DISCONNECT)) {
  7301. Status = STATUS_CTX_CLOSE_PENDING;
  7302. } else {
  7303. PWCHAR pDomainToSend, pUserNameToSend ;
  7304. // Use the Notification given by GINA (WinStationUpdateClientCachedCredentials) if they are available
  7305. // This is because the credentials got in this call are not UPN names
  7306. if (pWinStation->pNewNotificationCredentials) {
  7307. pDomainToSend = pWinStation->pNewNotificationCredentials->Domain;
  7308. pUserNameToSend = pWinStation->pNewNotificationCredentials->UserName;
  7309. } else {
  7310. pDomainToSend = pDomain;
  7311. pUserNameToSend = pUserName;
  7312. }
  7313. /*
  7314. * Reset any autoreconnect information prior to reconnection
  7315. * as it is stale. New information will be generated by the stack
  7316. * when login completes.
  7317. */
  7318. ResetAutoReconnectInfo(pWinStation);
  7319. Status = pWinStation->pWsx->pWsxLogonNotify(pWinStation->pWsxContext,
  7320. pWinStation->LogonId,
  7321. ClientToken,
  7322. pDomainToSend,
  7323. pUserNameToSend);
  7324. if (pWinStation->pNewNotificationCredentials != NULL) {
  7325. MemFree(pWinStation->pNewNotificationCredentials);
  7326. pWinStation->pNewNotificationCredentials = NULL;
  7327. }
  7328. }
  7329. }
  7330. if( !NT_SUCCESS(Status) ) {
  7331. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: pWsxLogonNotify rejected logon status 0x%x\n",Status));
  7332. goto badwsxnotify;
  7333. }
  7334. /*
  7335. * Determine size needed for token info buffer and allocate it
  7336. */
  7337. Status = NtQueryInformationToken( ClientToken, TokenUser,
  7338. NULL, 0, &Length );
  7339. if ( Status != STATUS_BUFFER_TOO_SMALL )
  7340. goto badquerytoken;
  7341. TokenInfo = MemAlloc( Length );
  7342. if ( TokenInfo == NULL ) {
  7343. Status = STATUS_NO_MEMORY;
  7344. goto badquerytoken;
  7345. }
  7346. /*
  7347. * Query token information to get user's SID
  7348. */
  7349. Status = NtQueryInformationToken( ClientToken, TokenUser,
  7350. TokenInfo, Length, &Length );
  7351. if ( !NT_SUCCESS( Status ) ) {
  7352. MemFree( TokenInfo );
  7353. goto badquerytoken;
  7354. }
  7355. /*
  7356. * Save copy of user's SID and password in WinStation
  7357. */
  7358. Length = RtlLengthSid( TokenInfo->User.Sid );
  7359. if (pWinStation->pUserSid) {
  7360. MemFree(pWinStation->pUserSid);
  7361. }
  7362. // clean up usertoken
  7363. if ( pWinStation->UserToken ) {
  7364. NtClose( pWinStation->UserToken );
  7365. pWinStation->UserToken = NULL;
  7366. }
  7367. pWinStation->pUserSid = MemAlloc( Length );
  7368. /* makarp; check for allocation failure. #182624 */
  7369. if (!pWinStation->pUserSid) {
  7370. Status = STATUS_NO_MEMORY;
  7371. goto badusersid;
  7372. }
  7373. RtlCopySid( Length, pWinStation->pUserSid, TokenInfo->User.Sid );
  7374. MemFree( TokenInfo );
  7375. NtClose( ImpersonationToken );
  7376. //For console session profile cleanup is done at next
  7377. //logon because the session is never unloaded.
  7378. if (pWinStation->pProfileSid != NULL) {
  7379. ASSERT(pWinStation->LogonId == 0);
  7380. if (pWinStation->LogonId == 0) {
  7381. if (!RtlEqualSid(pWinStation->pProfileSid, pWinStation->pUserSid )) {
  7382. WinstationUnloadProfile(pWinStation);
  7383. }
  7384. }
  7385. MemFree(pWinStation->pProfileSid);
  7386. pWinStation->pProfileSid = NULL;
  7387. }
  7388. /*
  7389. * Save copy of Client token in WinStation
  7390. */
  7391. pWinStation->UserToken = ClientToken;
  7392. #if 0
  7393. //
  7394. // C2 WARNING - WARNING - WARNING
  7395. //
  7396. // This is no longer done, or needed. See comments in acl.c
  7397. //
  7398. // C2 WARNING - WARNING - WARNING
  7399. //
  7400. RtlCopyMemory( pWinStation->Password, pPassword,
  7401. sizeof(pWinStation->Password) );
  7402. pWinStation->Seed = Seed;
  7403. #endif
  7404. /*
  7405. * Fixup the security descriptors for the session
  7406. * so this user has access to their named WIN32
  7407. * object directory's.
  7408. */
  7409. RetValue = ConfigurePerSessionSecurity( pWinStation );
  7410. if (RetValue != TRUE) {
  7411. // Set WinStation's UserToken to NULL here as the error path closes the ClientToken
  7412. pWinStation->UserToken = NULL;
  7413. goto badduptoken;
  7414. }
  7415. /*
  7416. * Add ACE for logged on user to the WinStation object SD
  7417. */
  7418. Status = AddUserAce( pWinStation );
  7419. if (Status != STATUS_SUCCESS) {
  7420. // Set WinStation's UserToken to NULL here as the error path closes the ClientToken
  7421. pWinStation->UserToken = NULL;
  7422. goto badduptoken;
  7423. }
  7424. /*
  7425. * Notify clients of WinStation logon
  7426. */
  7427. NotifySystemEvent( WEVENT_LOGON );
  7428. NotifyLogon(pWinStation);
  7429. /*
  7430. * State is now active
  7431. */
  7432. if ( pWinStation->State != (ULONG) State_Active ) {
  7433. // make sure repopulating thread don't include this winstation
  7434. // in the list reporting to SD and let this thread do its
  7435. // own reporting.
  7436. if (!g_bPersonalTS && g_fAppCompat && g_bAdvancedServer) {
  7437. SessDirWaitForRepopulate();
  7438. }
  7439. pWinStation->State = State_Active;
  7440. NotifySystemEvent( WEVENT_STATECHANGE );
  7441. }
  7442. (VOID) NtQuerySystemTime( &(pWinStation->LogonTime) );
  7443. // 2nd and 3rd parama are NULL, since we don't yet have policy data.
  7444. // policy data will be aquired when user hive is loaded and winlogin fires
  7445. // a shell-startup notify.
  7446. MergeUserConfigData(pWinStation, NULL, NULL, (PUSERCONFIGW)pUserConfig ) ;
  7447. /*
  7448. * Save User Name and Domain Name into the USERCONFIG of the WINSTATION
  7449. */
  7450. wcsncpy( pWinStation->Config.Config.User.UserName, pUserName, UserNameLength );
  7451. wcsncpy( pWinStation->Config.Config.User.Domain, pDomain, DomainLength );
  7452. /*
  7453. * Convert any "published app" to absolute path. This will also return
  7454. * failure if a non-published app is trying to run on a WinStation that
  7455. * is configured to only run published apps.
  7456. */
  7457. if ( pWinStation->pWsx &&
  7458. pWinStation->pWsx->pWsxConvertPublishedApp ) {
  7459. if ((Status = pWinStation->pWsx->pWsxConvertPublishedApp(
  7460. pWinStation->pWsxContext, &pWinStation->Config.Config.User)) !=
  7461. STATUS_SUCCESS)
  7462. goto release;
  7463. }
  7464. // Now that we have all the WinStation data, notify the session directory.
  7465. // Copy off the pertinent info, which we will send to the directory after
  7466. // we release the WinStation lock.
  7467. wcsncpy(pCreateInfo->UserName, pWinStation->UserName,
  7468. sizeof(pCreateInfo->UserName) / sizeof(WCHAR) - 1);
  7469. wcsncpy(pCreateInfo->Domain, pWinStation->Domain,
  7470. sizeof(pCreateInfo->Domain) / sizeof(WCHAR) - 1);
  7471. pCreateInfo->SessionID = pWinStation->LogonId;
  7472. pCreateInfo->TSProtocol = pWinStation->Client.ProtocolType;
  7473. // If InitialProgram is set on the server side, use it for the Applicationtype
  7474. if (!pWinStation->Config.Config.User.fInheritInitialProgram) {
  7475. wcsncpy(pCreateInfo->ApplicationType, pWinStation->Config.Config.User.InitialProgram,
  7476. sizeof(pCreateInfo->ApplicationType) / sizeof(WCHAR) - 1);
  7477. }
  7478. else {
  7479. wcsncpy(pCreateInfo->ApplicationType, pWinStation->Client.InitialProgram,
  7480. sizeof(pCreateInfo->ApplicationType) / sizeof(WCHAR) - 1);
  7481. }
  7482. pCreateInfo->ResolutionWidth = pWinStation->Client.HRes;
  7483. pCreateInfo->ResolutionHeight = pWinStation->Client.VRes;
  7484. pCreateInfo->ColorDepth = pWinStation->Client.ColorDepth;
  7485. memcpy(&(pCreateInfo->CreateTime), &pWinStation->LogonTime,
  7486. sizeof(pCreateInfo->CreateTime));
  7487. bHaveCreateInfo = TRUE;
  7488. if(Status == STATUS_SUCCESS)
  7489. {
  7490. //Set flag saying that WinStationNotifyLogonWorker
  7491. //was successfully completed
  7492. pWinStation->StateFlags |= WSF_ST_LOGON_NOTIFIED;
  7493. }
  7494. if( TSIsSessionHelpSession(pWinStation, &bValidHelpSession) )
  7495. {
  7496. WINSTATION_APIMSG msg;
  7497. // we disconnect RA if ticket is invalid at conntion time so assert
  7498. // if we ever come to this.
  7499. ASSERT( TRUE == bValidHelpSession );
  7500. //
  7501. // Disable IO from Help Session
  7502. //
  7503. WinStationEnableSessionIo( pWinStation, FALSE );
  7504. msg.ApiNumber = SMWinStationNotify;
  7505. msg.WaitForReply = FALSE;
  7506. msg.u.DoNotify.NotifyEvent = WinStation_Notify_DisableScrnSaver;
  7507. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  7508. ASSERT( NT_SUCCESS(Status) );
  7509. // ignore this error, help can still proceed.
  7510. Status = STATUS_SUCCESS;
  7511. }
  7512. /*
  7513. * Release the winstation lock
  7514. */
  7515. release:
  7516. if (pWinStation != NULL) {
  7517. if (pWinStation->pNewNotificationCredentials != NULL) {
  7518. MemFree(pWinStation->pNewNotificationCredentials);
  7519. pWinStation->pNewNotificationCredentials = NULL;
  7520. }
  7521. }
  7522. ReleaseWinStation( pWinStation );
  7523. // Now inform the session directory while we're not holding the lock.
  7524. if (!bQueueReset && bHaveCreateInfo && !g_bPersonalTS && g_fAppCompat && g_bAdvancedServer && !bRedirect)
  7525. SessDirNotifyLogon(pCreateInfo);
  7526. /*
  7527. * Save return status in API message
  7528. */
  7529. done:
  7530. // Clear password
  7531. if (0 != PasswordSize)
  7532. SecureZeroMemory(pPassword, PasswordSize);
  7533. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationNotifyLogon, Status=0x%x\n", Status ));
  7534. if (pCreateInfo != NULL) {
  7535. MemFree(pCreateInfo);
  7536. pCreateInfo = NULL;
  7537. }
  7538. // Update the counters for successful logons.
  7539. if (Status == STATUS_SUCCESS) {
  7540. InterlockedIncrement(&g_TermSrvSuccTotalLogons);
  7541. if (ClientLogonId == 0) {
  7542. // Connecting to console.
  7543. InterlockedIncrement(&g_TermSrvSuccSession0Logons);
  7544. }
  7545. if (fReconnectingToConsole) {
  7546. // Reconnecting locally to console.
  7547. InterlockedIncrement(&g_TermSrvSuccLocalLogons);
  7548. }
  7549. else {
  7550. if ( (ClientLogonId == 0) && (USER_SHARED_DATA->ActiveConsoleId == 0) ) {
  7551. // Logging on to console locally (When no one is connected to console).
  7552. InterlockedIncrement(&g_TermSrvSuccLocalLogons);
  7553. }
  7554. else {
  7555. // Connecting remotely. (if ClientLogonId is 0, then connecting remotely to console, else connecting to non-console).
  7556. InterlockedIncrement(&g_TermSrvSuccRemoteLogons);
  7557. }
  7558. }
  7559. }
  7560. return Status;
  7561. /*=============================================================================
  7562. == Error returns
  7563. =============================================================================*/
  7564. /* Could not allocate for pWinStation->pUserSid, makarp #182624 */
  7565. badusersid:
  7566. MemFree( TokenInfo );
  7567. /*
  7568. * Could not query token info
  7569. * WinStation Open failed (no access)
  7570. * Could not impersonate client token
  7571. * Could not duplicate client token
  7572. */
  7573. badquerytoken:
  7574. badwsxnotify:
  7575. nolicense:
  7576. noaccess:
  7577. badimpersonate:
  7578. NtClose( ImpersonationToken );
  7579. badduptoken:
  7580. NtClose( ClientToken );
  7581. /*
  7582. * Could not duplicate client token handle
  7583. */
  7584. baddupobject:
  7585. #ifdef not_hydrix
  7586. pWinStation->HasLicense = FALSE;
  7587. RtlZeroMemory( pWinStation->ClientLicense,
  7588. sizeof(pWinStation->ClientLicense) );
  7589. #else
  7590. if ( pWinStation->pWsx &&
  7591. pWinStation->pWsx->pWsxClearContext ) {
  7592. pWinStation->pWsx->pWsxClearContext( pWinStation->pWsxContext );
  7593. }
  7594. #endif
  7595. if (pWinStation->pNewNotificationCredentials != NULL) {
  7596. MemFree(pWinStation->pNewNotificationCredentials);
  7597. pWinStation->pNewNotificationCredentials = NULL;
  7598. }
  7599. ReleaseWinStation( pWinStation );
  7600. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationNotifyLogon, Status=0x%x\n", Status ));
  7601. // Clear password
  7602. if (0 != PasswordSize)
  7603. memset(pPassword, 0, PasswordSize);
  7604. if (pCreateInfo != NULL) {
  7605. MemFree(pCreateInfo);
  7606. pCreateInfo = NULL;
  7607. }
  7608. return Status;
  7609. }
  7610. /*****************************************************************************
  7611. * WinStationNotifyLogoffWorker
  7612. *
  7613. * Message parameter unmarshalling function for WinStation API.
  7614. ****************************************************************************/
  7615. NTSTATUS WinStationNotifyLogoffWorker(
  7616. DWORD ClientLogonId,
  7617. DWORD ClientProcessId)
  7618. {
  7619. NTSTATUS Status;
  7620. PWINSTATION pWinStation;
  7621. DWORD SessionID = 0;
  7622. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationNotifyLogoff, LogonId=%d\n", ClientLogonId ));
  7623. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationNotifyLogoff, LogonId=%d\n", ClientLogonId ));
  7624. Status = STATUS_SUCCESS;
  7625. /*
  7626. * Find and lock client WinStation
  7627. */
  7628. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  7629. if ( pWinStation == NULL ) {
  7630. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  7631. goto done;
  7632. }
  7633. //See if WinStation was notified of logon
  7634. if(pWinStation->StateFlags & WSF_ST_LOGON_NOTIFIED)
  7635. {
  7636. //Clear the flag
  7637. pWinStation->StateFlags &= ~WSF_ST_LOGON_NOTIFIED;
  7638. }
  7639. else
  7640. {
  7641. //WinStation was not notified of logon.
  7642. //do nothing; return error. However if postlogon licensing happened, do post logoff licensing.
  7643. if (pWinStation->StateFlags & WSF_ST_LICENSING) {
  7644. (VOID)LCProcessConnectionLogoff(pWinStation);
  7645. pWinStation->StateFlags &= ~WSF_ST_LICENSING;
  7646. }
  7647. KdPrint(("TERMSRV: WinStationNotifyLogoff FAILED, WinStation was not notified of logon!\n"));
  7648. ReleaseWinStation( pWinStation );
  7649. Status = STATUS_INVALID_PARAMETER; //probably need some special error code
  7650. goto done;
  7651. }
  7652. /*
  7653. * The upper level has verified the client caller
  7654. * is local and has SYSTEM access. So we can trust
  7655. * the parameters passed.
  7656. */
  7657. /*
  7658. * Ensure this is WinLogon calling
  7659. */
  7660. if ( (HANDLE)(ULONG_PTR)ClientProcessId != pWinStation->InitialCommandProcessId ) {
  7661. ReleaseWinStation( pWinStation );
  7662. goto done;
  7663. }
  7664. /*
  7665. * Stop the shadow on console if needed.
  7666. */
  7667. if ( pWinStation->fOwnsConsoleTerminal ) {
  7668. WinStationStopAllShadows( pWinStation );
  7669. }
  7670. /*
  7671. * Remove ACE for logged on user to the WinStation object SD
  7672. */
  7673. if (pWinStation->pSecurityDescriptor != NULL) {
  7674. RemoveUserAce( pWinStation );
  7675. }
  7676. if ( pWinStation->pUserSid ) {
  7677. ASSERT(pWinStation->pProfileSid == NULL);
  7678. pWinStation->pProfileSid = pWinStation->pUserSid;
  7679. pWinStation->pUserSid = NULL;
  7680. }
  7681. /*
  7682. * Cleanup UserToken
  7683. */
  7684. if ( pWinStation->UserToken ) {
  7685. NtClose( pWinStation->UserToken );
  7686. pWinStation->UserToken = NULL;
  7687. }
  7688. /*
  7689. * Indicate this WinStation no longer has a license
  7690. */
  7691. #ifdef not_hydrix
  7692. pWinStation->HasLicense = FALSE;
  7693. RtlZeroMemory( pWinStation->ClientLicense,
  7694. sizeof(pWinStation->ClientLicense) );
  7695. #else
  7696. if ( pWinStation->pWsx &&
  7697. pWinStation->pWsx->pWsxClearContext ) {
  7698. pWinStation->pWsx->pWsxClearContext( pWinStation->pWsxContext );
  7699. }
  7700. #endif
  7701. if (!g_bPersonalTS && g_fAppCompat && g_bAdvancedServer) {
  7702. // TS only reset the Flag not the the winstation state for logoff session
  7703. // so we wait and let repopulating thread has enough time to pick up this
  7704. // winstation/report to SD then this thread can continue to notify SD
  7705. // about logoff
  7706. SessDirWaitForRepopulate();
  7707. }
  7708. /*
  7709. * do needed data cleanup.
  7710. */
  7711. RtlZeroMemory( pWinStation->Domain,
  7712. sizeof( pWinStation->Domain ) );
  7713. RtlZeroMemory( pWinStation->UserName,
  7714. sizeof( pWinStation->UserName ) );
  7715. RtlZeroMemory( &pWinStation->LogonTime,
  7716. sizeof( pWinStation->LogonTime ) );
  7717. ResetUserConfigData( pWinStation );
  7718. pWinStation->Config.Config.User.UserName[0] = L'\0';
  7719. pWinStation->Config.Config.User.Domain[0] = L'\0';
  7720. pWinStation->Config.Config.User.Password[0] = L'\0';
  7721. if ( pWinStation->LogonId == 0 ) {
  7722. /*
  7723. * No need to do anything else for console state change.
  7724. */
  7725. if ( pWinStation->State != (ULONG) State_Connected &&
  7726. pWinStation->State != (ULONG) State_Disconnected) {
  7727. pWinStation->State = State_Connected;
  7728. NotifySystemEvent( WEVENT_STATECHANGE );
  7729. }
  7730. //
  7731. //Set the Console Logon Event
  7732. //
  7733. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: WinStationNotifyLogoff, Setting ConsoleLogoffEvent\n"));
  7734. NtSetEvent(ConsoleLogoffEvent, NULL);
  7735. /*
  7736. * For non-Console WinStations, mark this WinStation as terminating
  7737. * and set the broken reason and source for later use.
  7738. */
  7739. } else {
  7740. //pWinStation->Terminating = TRUE;
  7741. pWinStation->BrokenReason = Broken_Terminate;
  7742. pWinStation->BrokenSource = BrokenSource_User;
  7743. // Save off the session dir for sending to the session directory
  7744. // below.
  7745. SessionID = pWinStation->LogonId;
  7746. }
  7747. // Clean up the New Client Credentials struct for Long UserName
  7748. if (pWinStation->pNewClientCredentials != NULL) {
  7749. MemFree(pWinStation->pNewClientCredentials);
  7750. pWinStation->pNewClientCredentials = NULL;
  7751. }
  7752. /*
  7753. * Call into licensing core for logoff. Ignore errors.
  7754. */
  7755. if (pWinStation->StateFlags & WSF_ST_LICENSING) {
  7756. (VOID)LCProcessConnectionLogoff(pWinStation);
  7757. pWinStation->StateFlags &= ~WSF_ST_LICENSING;
  7758. }
  7759. NotifyLogoff(pWinStation);
  7760. ReleaseWinStation( pWinStation );
  7761. // Notify the session directory.
  7762. if (!g_bPersonalTS && g_fAppCompat && g_bAdvancedServer) {
  7763. SessDirNotifyLogoff(SessionID);
  7764. }
  7765. /*
  7766. * Notify clients of WinStation logoff
  7767. */
  7768. NotifySystemEvent(WEVENT_LOGOFF);
  7769. done:
  7770. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationNotifyLogoff, Status=0x%x\n", Status ));
  7771. return Status;
  7772. }
  7773. /*****************************************************************************
  7774. * OldRpcWinStationEnumerateProcesses
  7775. *
  7776. * WinStationEnumerateProcesses API for Beta servers
  7777. *
  7778. * The format changed after Beta. New winsta.dll's were trapping when talking
  7779. * to old hosts.
  7780. ****************************************************************************/
  7781. BOOLEAN
  7782. OldRpcWinStationEnumerateProcesses(
  7783. HANDLE hServer,
  7784. DWORD *pResult,
  7785. PBYTE pProcessBuffer,
  7786. DWORD ByteCount
  7787. )
  7788. {
  7789. return ( RpcWinStationEnumerateProcesses( hServer, pResult, pProcessBuffer, ByteCount ) );
  7790. }
  7791. /*******************************************************************************
  7792. * RpcWinStationCheckForApplicationName
  7793. *
  7794. * Handles published applications.
  7795. *
  7796. * EXIT:
  7797. * TRUE -- The query succeeded, and the buffer contains the requested data.
  7798. * FALSE -- The operation failed. Extended error status is available
  7799. * using GetLastError.
  7800. ******************************************************************************/
  7801. BOOLEAN
  7802. RpcWinStationCheckForApplicationName(
  7803. HANDLE hServer,
  7804. DWORD *pResult,
  7805. ULONG LogonId,
  7806. PWCHAR pUserName,
  7807. DWORD UserNameSize,
  7808. PWCHAR pDomain,
  7809. DWORD DomainSize,
  7810. PWCHAR pPassword,
  7811. DWORD *pPasswordSize,
  7812. DWORD MaxPasswordSize,
  7813. PCHAR pSeed,
  7814. PBOOLEAN pfPublished,
  7815. PBOOLEAN pfAnonymous
  7816. )
  7817. {
  7818. /*
  7819. * This is obsolete and should be removed from the RPC
  7820. */
  7821. *pResult = STATUS_NOT_IMPLEMENTED;
  7822. RpcRaiseException(ERROR_INVALID_FUNCTION);
  7823. return FALSE;
  7824. }
  7825. /*******************************************************************************
  7826. *
  7827. * RpcWinStationGetApplicationInfo
  7828. *
  7829. * Gets info about published applications.
  7830. *
  7831. * ENTRY:
  7832. *
  7833. * EXIT:
  7834. *
  7835. * TRUE -- The query succeeded, and the buffer contains the requested data.
  7836. *
  7837. * FALSE -- The operation failed. Extended error status is available
  7838. * using GetLastError.
  7839. *
  7840. ******************************************************************************/
  7841. BOOLEAN
  7842. RpcWinStationGetApplicationInfo(
  7843. HANDLE hServer,
  7844. DWORD *pResult,
  7845. ULONG LogonId,
  7846. PBOOLEAN pfPublished,
  7847. PBOOLEAN pfAnonymous
  7848. )
  7849. {
  7850. /*
  7851. * This is obsolete and should be removed from the RPC code.
  7852. */
  7853. *pResult = STATUS_NOT_IMPLEMENTED;
  7854. RpcRaiseException(ERROR_INVALID_FUNCTION);
  7855. return FALSE;
  7856. }
  7857. /*******************************************************************************
  7858. *
  7859. * RpcWinStationNtsdDebug
  7860. *
  7861. * Sets up connection for Ntsd to debug processes belonging to another
  7862. * CSR.
  7863. *
  7864. * ENTRY:
  7865. *
  7866. * EXIT:
  7867. *
  7868. * TRUE -- The query succeeded, and the buffer contains the requested data.
  7869. *
  7870. * FALSE -- The operation failed. Extended error status is available
  7871. * using GetLastError.
  7872. *
  7873. ******************************************************************************/
  7874. BOOLEAN
  7875. RpcWinStationNtsdDebug(
  7876. HANDLE hServer,
  7877. DWORD *pResult,
  7878. ULONG LogonId,
  7879. LONG ProcessId,
  7880. ULONG DbgProcessId,
  7881. ULONG DbgThreadId,
  7882. DWORD_PTR AttachCompletionRoutine
  7883. )
  7884. {
  7885. *pResult = STATUS_NOT_IMPLEMENTED;
  7886. RpcRaiseException(ERROR_INVALID_FUNCTION);
  7887. return FALSE;
  7888. }
  7889. /*******************************************************************************
  7890. *
  7891. * RpcWinStationGetTermSrvCountersValue
  7892. *
  7893. * Gets TermSrv Counters value
  7894. *
  7895. * ENTRY:
  7896. *
  7897. * EXIT:
  7898. *
  7899. * TRUE -- The query succeeded, and the buffer contains the requested data.
  7900. *
  7901. * FALSE -- The operation failed. Extended error status is available
  7902. * using GetLastError.
  7903. *
  7904. ******************************************************************************/
  7905. BOOLEAN
  7906. RpcWinStationGetTermSrvCountersValue(
  7907. HANDLE hServer,
  7908. DWORD *pResult,
  7909. DWORD dwEntries,
  7910. PTS_COUNTER pCounter
  7911. )
  7912. {
  7913. UINT i;
  7914. PLIST_ENTRY Head, Next;
  7915. PWINSTATION pWinStation;
  7916. BOOLEAN bWalkedList = FALSE;
  7917. ULONG cActive, cDisconnected;
  7918. if(!hServer)
  7919. {
  7920. *pResult = STATUS_UNSUCCESSFUL;
  7921. return( FALSE );
  7922. }
  7923. *pResult = STATUS_UNSUCCESSFUL;
  7924. if (pCounter != NULL) {
  7925. for (i = 0; i < dwEntries; i++) {
  7926. // set the TermSrv counter value. Currently, startTime is always
  7927. // set to 0 because we don't support time stamp.
  7928. pCounter[i].startTime.QuadPart = 0;
  7929. switch (pCounter[i].counterHead.dwCounterID) {
  7930. case TERMSRV_TOTAL_SESSIONS:
  7931. {
  7932. pCounter[i].counterHead.bResult = TRUE;
  7933. pCounter[i].dwValue = g_TermSrvTotalSessions;
  7934. *pResult = STATUS_SUCCESS;
  7935. }
  7936. break;
  7937. case TERMSRV_DISC_SESSIONS:
  7938. {
  7939. pCounter[i].counterHead.bResult = TRUE;
  7940. pCounter[i].dwValue = g_TermSrvDiscSessions;
  7941. *pResult = STATUS_SUCCESS;
  7942. }
  7943. break;
  7944. case TERMSRV_RECON_SESSIONS:
  7945. {
  7946. pCounter[i].counterHead.bResult = TRUE;
  7947. pCounter[i].dwValue = g_TermSrvReconSessions;
  7948. *pResult = STATUS_SUCCESS;
  7949. }
  7950. break;
  7951. case TERMSRV_CURRENT_ACTIVE_SESSIONS:
  7952. case TERMSRV_CURRENT_DISC_SESSIONS:
  7953. {
  7954. if ( !bWalkedList ) {
  7955. cActive = cDisconnected = 0;
  7956. Head = &WinStationListHead;
  7957. ENTERCRIT( &WinStationListLock );
  7958. for ( Next = Head->Flink; Next != Head; Next = Next->Flink ) {
  7959. pWinStation = CONTAINING_RECORD( Next, WINSTATION, Links );
  7960. if ( (pWinStation->State == State_Active) ||
  7961. (pWinStation->State == State_Shadow) )
  7962. cActive ++;
  7963. if ( pWinStation->State == State_Disconnected )
  7964. if ( pWinStation->LogonId != 0 )
  7965. cDisconnected ++;
  7966. else if ( pWinStation->UserName[0] )
  7967. // For session 0, test if a user is logged on.
  7968. cDisconnected ++;
  7969. }
  7970. LEAVECRIT( &WinStationListLock );
  7971. bWalkedList = TRUE;
  7972. }
  7973. pCounter[i].counterHead.bResult = TRUE;
  7974. if ( pCounter[i].counterHead.dwCounterID == TERMSRV_CURRENT_ACTIVE_SESSIONS )
  7975. pCounter[i].dwValue = cActive;
  7976. else
  7977. pCounter[i].dwValue = cDisconnected;
  7978. *pResult = STATUS_SUCCESS;
  7979. }
  7980. break;
  7981. case TERMSRV_PENDING_SESSIONS:
  7982. {
  7983. pCounter[i].counterHead.bResult = TRUE;
  7984. pCounter[i].dwValue = NumOutStandingConnect;
  7985. *pResult = STATUS_SUCCESS;
  7986. }
  7987. break;
  7988. case TERMSRV_SUCC_TOTAL_LOGONS:
  7989. {
  7990. pCounter[i].counterHead.bResult = TRUE;
  7991. pCounter[i].dwValue = g_TermSrvSuccTotalLogons;
  7992. *pResult = STATUS_SUCCESS;
  7993. }
  7994. break;
  7995. case TERMSRV_SUCC_LOCAL_LOGONS:
  7996. {
  7997. pCounter[i].counterHead.bResult = TRUE;
  7998. pCounter[i].dwValue = g_TermSrvSuccLocalLogons;
  7999. *pResult = STATUS_SUCCESS;
  8000. }
  8001. break;
  8002. case TERMSRV_SUCC_REMOTE_LOGONS:
  8003. {
  8004. pCounter[i].counterHead.bResult = TRUE;
  8005. pCounter[i].dwValue = g_TermSrvSuccRemoteLogons;
  8006. *pResult = STATUS_SUCCESS;
  8007. }
  8008. break;
  8009. case TERMSRV_SUCC_SESSION0_LOGONS:
  8010. {
  8011. pCounter[i].counterHead.bResult = TRUE;
  8012. pCounter[i].dwValue = g_TermSrvSuccSession0Logons;
  8013. *pResult = STATUS_SUCCESS;
  8014. }
  8015. break;
  8016. default:
  8017. {
  8018. pCounter[i].counterHead.bResult = FALSE;
  8019. pCounter[i].dwValue = 0;
  8020. }
  8021. }
  8022. }
  8023. }
  8024. return ( *pResult == STATUS_SUCCESS );
  8025. }
  8026. /******************************************************************************
  8027. *
  8028. * RpcServerGetInternetConnectorStatus
  8029. *
  8030. * Returns whether Internet Connector licensing is being used
  8031. *
  8032. * ENTRY:
  8033. *
  8034. * EXIT:
  8035. *
  8036. * TRUE -- The query succeeded, and pfEnabled contains the requested data.
  8037. *
  8038. * FALSE -- The operation failed. Extended error status is in pResult
  8039. *
  8040. *****************************************************************************/
  8041. BOOLEAN
  8042. RpcServerGetInternetConnectorStatus(
  8043. HANDLE hServer,
  8044. DWORD *pResult,
  8045. PBOOLEAN pfEnabled
  8046. )
  8047. {
  8048. #if 0
  8049. if (pResult != NULL)
  8050. {
  8051. *pResult = STATUS_NOT_IMPLEMENTED;
  8052. }
  8053. if (pfEnabled != NULL)
  8054. {
  8055. *pfEnabled = FALSE;
  8056. }
  8057. return(FALSE);
  8058. #else
  8059. //
  8060. // TEMPORARY FUNCTION! THIS WILL GET NUKED ONCE THE LCRPC
  8061. // INTERFACE IS UP AND RUNNING AND TSCC CHANGES HAVE BEEN
  8062. // MADE!
  8063. //
  8064. if (pResult == NULL)
  8065. {
  8066. return(FALSE);
  8067. }
  8068. if(!hServer)
  8069. {
  8070. *pResult = STATUS_UNSUCCESSFUL;
  8071. return( FALSE );
  8072. }
  8073. if (pfEnabled == NULL)
  8074. {
  8075. *pResult = STATUS_INVALID_PARAMETER;
  8076. return(FALSE);
  8077. }
  8078. *pfEnabled = (LCGetPolicy() == (ULONG)3);
  8079. *pResult = STATUS_SUCCESS;
  8080. return(TRUE);
  8081. #endif
  8082. }
  8083. /******************************************************************************
  8084. *
  8085. * RpcServerSetInternetConnectorStatus
  8086. *
  8087. * This function will (if fEnabled has changed from its previous setting):
  8088. * Check that the caller has administrative privileges,
  8089. * Modify the corresponding value in the registry,
  8090. * Change licensing mode (between normal per-seat and Internet Connector.
  8091. * Enable/Disable the TsInternetUser account appropriately
  8092. *
  8093. * ENTRY:
  8094. *
  8095. * EXIT:
  8096. *
  8097. * TRUE -- The operation succeeded.
  8098. *
  8099. * FALSE -- The operation failed. Extended error status is in pResult
  8100. *
  8101. ******************************************************************************/
  8102. BOOLEAN
  8103. RpcServerSetInternetConnectorStatus(
  8104. HANDLE hServer,
  8105. DWORD *pResult,
  8106. BOOLEAN fEnabled
  8107. )
  8108. {
  8109. #if 0
  8110. if (pResult != NULL)
  8111. {
  8112. *pResult = STATUS_NOT_IMPLEMENTED;
  8113. }
  8114. return(FALSE);
  8115. #else
  8116. //
  8117. // TEMPORARY FUNCTION! THIS WILL GET NUKED ONCE THE LCRPC
  8118. // INTERFACE IS UP AND RUNNING AND TSCC CHANGES HAVE BEEN
  8119. // MADE!
  8120. //
  8121. NTSTATUS NewStatus;
  8122. RPC_STATUS RpcStatus;
  8123. if (pResult == NULL)
  8124. {
  8125. return FALSE;
  8126. }
  8127. if(!hServer)
  8128. {
  8129. *pResult = STATUS_UNSUCCESSFUL;
  8130. return( FALSE );
  8131. }
  8132. RpcStatus = RpcImpersonateClient( NULL );
  8133. if( RpcStatus != RPC_S_OK ) {
  8134. *pResult = STATUS_CANNOT_IMPERSONATE;
  8135. return( FALSE );
  8136. }
  8137. if (!IsCallerAdmin())
  8138. {
  8139. RpcRevertToSelf();
  8140. *pResult = STATUS_PRIVILEGE_NOT_HELD;
  8141. return FALSE;
  8142. }
  8143. RpcRevertToSelf();
  8144. *pResult = LCSetPolicy(fEnabled ? 3 : 2, &NewStatus);
  8145. if ((*pResult == STATUS_SUCCESS) && (NewStatus == STATUS_SUCCESS))
  8146. {
  8147. return(TRUE);
  8148. }
  8149. //
  8150. // If there was an error, it was either in the core or the new policy.
  8151. // If its in the core, NewStatus will be success. If its in the new
  8152. // policy, *pResult will be unsuccessful, and the real error will be in
  8153. // NewStatus. Return the real error.
  8154. //
  8155. if (NewStatus != STATUS_SUCCESS)
  8156. {
  8157. *pResult = NewStatus;
  8158. }
  8159. return(FALSE);
  8160. #endif
  8161. }
  8162. /******************************************************************************
  8163. *
  8164. * RpcServerQueryInetConnectorInformation
  8165. *
  8166. * Queries configuration information about a Internet Connector licensing.
  8167. *
  8168. * ENTRY:
  8169. *
  8170. * pWinStationInformation (output)
  8171. * A pointer to a buffer that will receive information about the
  8172. * specified window station. The format and contents of the buffer
  8173. * depend on the specified information class being queried.
  8174. *
  8175. * WinStationInformationLength (input)
  8176. * Specifies the length in bytes of the window station information
  8177. * buffer.
  8178. *
  8179. * pReturnLength (output)
  8180. * An optional parameter that if specified, receives the number of
  8181. * bytes placed in the window station information buffer.
  8182. *
  8183. * EXIT:
  8184. *
  8185. * TRUE -- The query succeeded, and the buffer contains the requested data.
  8186. *
  8187. * False -- The operation failed or Internet Connector licensing isn't
  8188. * turned on. Extended error status is in pResult
  8189. *
  8190. *****************************************************************************/
  8191. BOOLEAN
  8192. RpcServerQueryInetConnectorInformation(
  8193. HANDLE hServer,
  8194. DWORD *pResult,
  8195. PCHAR pWinStationInformation,
  8196. DWORD WinStationInformationLength,
  8197. DWORD *pReturnLength
  8198. )
  8199. {
  8200. // doesn't return
  8201. RpcRaiseException(RPC_S_CANNOT_SUPPORT);
  8202. return FALSE;
  8203. }
  8204. /******************************************************************************
  8205. *
  8206. * RpcWinStationQueryLogonCredentials
  8207. *
  8208. * Queries autologon credentials for use in Winlogon/GINA.
  8209. *
  8210. *****************************************************************************/
  8211. BOOLEAN
  8212. RpcWinStationQueryLogonCredentials(
  8213. HANDLE hServer,
  8214. ULONG LogonId,
  8215. PCHAR *ppWire,
  8216. PULONG pcbWire
  8217. )
  8218. {
  8219. BOOL fRet;
  8220. BOOL fUseLcCredentials;
  8221. LCCREDENTIALS LcCredentials;
  8222. NTSTATUS Status;
  8223. PWINSTATION pWinStation;
  8224. RPC_STATUS RpcStatus;
  8225. WLX_CLIENT_CREDENTIALS_INFO_V2_0 WlxCredentials;
  8226. BOOL fHelpAssistant = FALSE;
  8227. BOOL bValidHelpSession;
  8228. pExtendedClientCredentials pHelpAssistantCredential = NULL;
  8229. if(!hServer)
  8230. {
  8231. return( FALSE );
  8232. }
  8233. //
  8234. // Impersonate client.
  8235. //
  8236. RpcStatus = RpcImpersonateClient(NULL);
  8237. if (RpcStatus != RPC_S_OK)
  8238. {
  8239. return(FALSE);
  8240. }
  8241. //
  8242. // Check for administration privileges.
  8243. //
  8244. if (!IsCallerSystem())
  8245. {
  8246. RpcRevertToSelf();
  8247. return(FALSE);
  8248. }
  8249. RpcRevertToSelf();
  8250. pWinStation = FindWinStationById(LogonId, FALSE);
  8251. if (pWinStation == NULL)
  8252. {
  8253. return(FALSE);
  8254. }
  8255. pHelpAssistantCredential = MemAlloc(sizeof(ExtendedClientCredentials));
  8256. if (pHelpAssistantCredential == NULL) {
  8257. ReleaseWinStation(pWinStation);
  8258. return FALSE;
  8259. }
  8260. ZeroMemory(&WlxCredentials, sizeof(WLX_CLIENT_CREDENTIALS_INFO_V2_0));
  8261. WlxCredentials.dwType = WLX_CREDENTIAL_TYPE_V2_0;
  8262. if( TSIsSessionHelpSession( pWinStation, &bValidHelpSession ) )
  8263. {
  8264. //
  8265. // We should not hit this since we will disconnect at winstation transfer time
  8266. //
  8267. ASSERT( TRUE == bValidHelpSession );
  8268. Status = TSHelpAssistantQueryLogonCredentials(pHelpAssistantCredential);
  8269. if( STATUS_SUCCESS == Status )
  8270. {
  8271. WlxCredentials.fDisconnectOnLogonFailure = TRUE;
  8272. WlxCredentials.fPromptForPassword = FALSE;
  8273. WlxCredentials.pszUserName = pHelpAssistantCredential->UserName;
  8274. WlxCredentials.pszDomain = pHelpAssistantCredential->Domain;
  8275. WlxCredentials.pszPassword = pHelpAssistantCredential->Password;
  8276. fUseLcCredentials = FALSE;
  8277. fHelpAssistant = TRUE;
  8278. }
  8279. }
  8280. if( FALSE == fHelpAssistant )
  8281. {
  8282. //
  8283. // Not Help Assistant, use whatever send in from client.
  8284. //
  8285. ZeroMemory(&LcCredentials, sizeof(LCCREDENTIALS));
  8286. Status = LCProvideAutoLogonCredentials(
  8287. pWinStation,
  8288. &fUseLcCredentials,
  8289. &LcCredentials
  8290. );
  8291. if (Status == STATUS_SUCCESS)
  8292. {
  8293. if (fUseLcCredentials)
  8294. {
  8295. WlxCredentials.fDisconnectOnLogonFailure = TRUE;
  8296. WlxCredentials.fPromptForPassword = FALSE;
  8297. WlxCredentials.pszUserName = LcCredentials.pUserName;
  8298. WlxCredentials.pszDomain = LcCredentials.pDomain;
  8299. WlxCredentials.pszPassword = LcCredentials.pPassword;
  8300. }
  8301. else
  8302. {
  8303. WlxCredentials.fDisconnectOnLogonFailure = FALSE;
  8304. WlxCredentials.fPromptForPassword = pWinStation->Config.Config.User.fPromptForPassword;
  8305. // If it's an app server, check if it's a SD redirected connection
  8306. // If yes, ignore fPromptForPassword setting and allow auto-logon
  8307. // Note: Only do it if SD is enabled, i.e. GetTSSD() returns a valide value
  8308. if (!g_bPersonalTS && g_fAppCompat && g_bAdvancedServer && GetTSSD()) {
  8309. TS_LOAD_BALANCE_INFO LBInfo;
  8310. ULONG ReturnLength;
  8311. // need to release it
  8312. ReleaseTSSD();
  8313. memset(&LBInfo, 0, sizeof(LBInfo));
  8314. Status = IcaStackIoControl(pWinStation->hStack,
  8315. IOCTL_TS_STACK_QUERY_LOAD_BALANCE_INFO,
  8316. NULL, 0,
  8317. &LBInfo, sizeof(LBInfo),
  8318. &ReturnLength);
  8319. if (NT_SUCCESS(Status)) {
  8320. if (LBInfo.RequestedSessionID &&
  8321. (LBInfo.ClientRedirectionVersion >= TS_CLUSTER_REDIRECTION_VERSION3)) {
  8322. WlxCredentials.fPromptForPassword = FALSE;
  8323. if (LBInfo.bUseSmartcardLogon) {
  8324. pWinStation->fSDRedirectedSmartCardLogon = TRUE;
  8325. }
  8326. }
  8327. }
  8328. }
  8329. // Check if we have to use New Credentials for long UserName and copy accordingly
  8330. if (pWinStation->pNewClientCredentials != NULL) {
  8331. WlxCredentials.pszUserName = pWinStation->pNewClientCredentials->UserName;
  8332. WlxCredentials.pszDomain = pWinStation->pNewClientCredentials->Domain;
  8333. WlxCredentials.pszPassword = pWinStation->pNewClientCredentials->Password;
  8334. } else {
  8335. WlxCredentials.pszUserName = pWinStation->Config.Config.User.UserName ;
  8336. WlxCredentials.pszDomain = pWinStation->Config.Config.User.Domain ;
  8337. WlxCredentials.pszPassword = pWinStation->Config.Config.User.Password ;
  8338. }
  8339. }
  8340. }
  8341. else
  8342. {
  8343. fRet = FALSE;
  8344. goto exit;
  8345. }
  8346. }
  8347. ASSERT(WlxCredentials.pszUserName != NULL);
  8348. ASSERT(WlxCredentials.pszDomain != NULL);
  8349. ASSERT(WlxCredentials.pszPassword != NULL);
  8350. *pcbWire = AllocateAndCopyCredToWire((PWLXCLIENTCREDWIREW*)ppWire, &WlxCredentials);
  8351. fRet = *pcbWire > 0;
  8352. //
  8353. // The values in LcCredentials are LocalAlloc-ed by the core.
  8354. //
  8355. if (fUseLcCredentials)
  8356. {
  8357. if (LcCredentials.pUserName != NULL)
  8358. {
  8359. LocalFree(LcCredentials.pUserName);
  8360. }
  8361. if (LcCredentials.pDomain != NULL)
  8362. {
  8363. LocalFree(LcCredentials.pDomain);
  8364. }
  8365. if (LcCredentials.pPassword != NULL)
  8366. {
  8367. //This code is never executed, but once it does we should call the below function.
  8368. //RtlSecureZeroMemory(LcCredentials.pPassword,
  8369. //lstrlenW(LcCredentials.pPassword)*sizeof(WCHAR));
  8370. LocalFree(LcCredentials.pPassword);
  8371. }
  8372. }
  8373. if( TRUE == fHelpAssistant )
  8374. {
  8375. // Zero out memory that contains password
  8376. RtlSecureZeroMemory( pHelpAssistantCredential, sizeof(ExtendedClientCredentials));
  8377. }
  8378. exit:
  8379. ReleaseWinStation(pWinStation);
  8380. if (pHelpAssistantCredential != NULL) {
  8381. MemFree(pHelpAssistantCredential);
  8382. pHelpAssistantCredential = NULL;
  8383. }
  8384. return((BOOLEAN)fRet);
  8385. }
  8386. /*****************************************************************************
  8387. * RPcWinStationBroadcastSystemMessage
  8388. * This is the server side for cleint's WinStationBroadcastSystemMessage
  8389. *
  8390. * Perform the the equivalent to BroadcastSystemMessage to each specified sessions
  8391. *
  8392. * Limittations:
  8393. * Caller must be system or Admin, and lparam can not be zero unless
  8394. * msg is WM_DEVICECHANGE
  8395. * Error checking is done on the clinet side (winsta\client\winsta.c)
  8396. *
  8397. * ENTRY:
  8398. * hServer
  8399. * this is a handle which identifies a Hydra server. For the local server, hServer
  8400. * should be set to SERVERNAME_CURRENT
  8401. * sessionID
  8402. * this idefntifies the hydra session to which message is being sent
  8403. * timeOut
  8404. * set this to the amount of time you are willing to wait to get a response
  8405. * from the specified winstation. Even though Window's SendMessage API
  8406. * is blocking, the call from this side MUST choose how long it is willing to
  8407. * wait for a response.
  8408. * dwFlags
  8409. * Option flags. Can be a combination of the following values: Value Meaning
  8410. * BSF_ALLOWSFW Windows NT 5.0 and later: Enables the recipient to set the foreground window while
  8411. * processing the message.
  8412. * BSF_FLUSHDISK Flush the disk after each recipient processes the message.
  8413. * BSF_FORCEIFHUNG Continue to broadcast the message, even if the time-out period elapses or one of
  8414. * the recipients is hung..
  8415. * BSF_IGNORECURRENTTASK Do not send the message to windows that belong to the current task.
  8416. * This prevents an application from receiving its own message.
  8417. * BSF_NOHANG Force a hung application to time out. If one of the recipients times out, do not continue
  8418. * broadcasting the message.
  8419. * BSF_NOTIMEOUTIFNOTHUNG Wait for a response to the message, as long as the recipient is not hung.
  8420. * Do not time out.
  8421. * ***
  8422. * *** DO NOT USE *** BSF_POSTMESSAGE Post the message. Do not use in combination with BSF_QUERY.
  8423. * ***
  8424. * BSF_QUERY Send the message to one recipient at a time, sending to a subsequent recipient only if the
  8425. * current recipient returns TRUE.
  8426. * lpdwRecipients
  8427. * Pointer to a variable that contains and receives information about the recipients of the message. The variable can be a combination of the following values: Value Meaning
  8428. * BSM_ALLCOMPONENTS Broadcast to all system components.
  8429. * BSM_ALLDESKTOPS Windows NT: Broadcast to all desktops. Requires the SE_TCB_NAME privilege.
  8430. * BSM_APPLICATIONS Broadcast to applications.
  8431. * BSM_INSTALLABLEDRIVERS Windows 95 and Windows 98: Broadcast to installable drivers.
  8432. * BSM_NETDRIVER Windows 95 and Windows 98: Broadcast to network drivers.
  8433. * BSM_VXDS Windows 95 and Windows 98: Broadcast to all system-level device drivers.
  8434. * When the function returns, this variable receives a combination of these values identifying which recipients actually received the message.
  8435. * If this parameter is NULL, the function broadcasts to all components.
  8436. * uiMessage
  8437. * the window's message to send
  8438. * wParam
  8439. * first message param
  8440. * lParam
  8441. * second message parameter
  8442. *
  8443. * pResponse
  8444. * This is the response to the broadcasted message
  8445. * If the function succeeds, the value is a positive value.
  8446. * If the function is unable to broadcast the message, the value is ?1.
  8447. * If the dwFlags parameter is BSF_QUERY and at least one recipient returned
  8448. * BROADCAST_QUERY_DENY to the corresponding message, the return value is zero
  8449. *
  8450. * EXIT:
  8451. * TRUE if all went well or
  8452. * FALSE if something went wrong.
  8453. *
  8454. * WARNING:
  8455. * Do not use flag BSF_POSTMESSAGE, since an app/window on a winstation is not setup to send back
  8456. * a response to the query in an asynchronous fashion. You must wait for the response (until the time out period).
  8457. *
  8458. * Comments:
  8459. * For more info, please see MSDN for BroadcastSystemMessage()
  8460. *
  8461. ****************************************************************************/
  8462. LONG RpcWinStationBroadcastSystemMessage(
  8463. HANDLE hServer,
  8464. ULONG sessionID,
  8465. ULONG waitTime,
  8466. DWORD dwFlags,
  8467. DWORD *lpdwRecipients,
  8468. ULONG uiMessage,
  8469. WPARAM wParam,
  8470. LPARAM lParam,
  8471. PBYTE rpcBuffer,
  8472. ULONG bufferSize,
  8473. BOOLEAN fBufferHasValidData,
  8474. LONG *pResponse
  8475. )
  8476. {
  8477. // Broadcast system message to all winstations.
  8478. PWINSTATION pWinStation=NULL;
  8479. WINSTATION_APIMSG WMsg;
  8480. OBJECT_ATTRIBUTES ObjA;
  8481. NTSTATUS Status;
  8482. LONG rc;
  8483. int i;
  8484. RPC_STATUS RpcStatus;
  8485. UINT LocalFlag;
  8486. if(!hServer)
  8487. {
  8488. return( FALSE );
  8489. }
  8490. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "in RpcWinStationBroadcastSystemMessage()\n"));
  8491. //
  8492. //
  8493. //
  8494. RpcStatus = RpcImpersonateClient( NULL );
  8495. if( RpcStatus != RPC_S_OK ) {
  8496. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, " RpcImpersonateClient() failed : 0x%x\n",RpcStatus));
  8497. SetLastError(ERROR_CANNOT_IMPERSONATE );
  8498. return( FALSE );
  8499. }
  8500. //
  8501. // Inquire if local RPC call
  8502. //
  8503. RpcStatus = I_RpcBindingIsClientLocal(
  8504. 0, // Active RPC call we are servicing
  8505. &LocalFlag
  8506. );
  8507. if( RpcStatus != RPC_S_OK ) {
  8508. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, " I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  8509. RpcRevertToSelf();
  8510. SetLastError(ERROR_ACCESS_DENIED);
  8511. return( FALSE );
  8512. }
  8513. if( !LocalFlag ) {
  8514. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, " Not a local client call\n"));
  8515. RpcRevertToSelf();
  8516. return( FALSE );
  8517. }
  8518. // if the caller is system or admin, then let it thru, else, return
  8519. if( !(IsCallerSystem() | IsCallerAdmin() ) )
  8520. {
  8521. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, " Caller must be system or admin \n"));
  8522. SetLastError(ERROR_ACCESS_DENIED);
  8523. RpcRevertToSelf();
  8524. return( FALSE );
  8525. }
  8526. //
  8527. // if we got this far, then client is admin or system
  8528. //
  8529. //
  8530. // done with the impersonation, we must have succeeded, otherwise, we would have exited above
  8531. //
  8532. RpcRevertToSelf();
  8533. /*
  8534. * Marshall in the [in] parameters
  8535. *
  8536. */
  8537. WMsg.WaitForReply=TRUE;
  8538. WMsg.u.bMsg.dwFlags = dwFlags;
  8539. WMsg.u.bMsg.dwRecipients= *lpdwRecipients; //note that we are passing the value, and we will get a new value back
  8540. WMsg.u.bMsg.uiMessage = uiMessage;
  8541. WMsg.u.bMsg.wParam = wParam;
  8542. WMsg.u.bMsg.lParam = lParam;
  8543. WMsg.u.bMsg.dataBuffer = NULL;
  8544. WMsg.u.bMsg.bufferSize = 0;
  8545. WMsg.u.bMsg.Response = *pResponse;
  8546. WMsg.ApiNumber = SMWinStationBroadcastSystemMessage ;
  8547. /*
  8548. * Find and lock client WinStation
  8549. */
  8550. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "in RpcWinStationBroadcastSystemMessage() for sessionID = %d \n", sessionID ));
  8551. pWinStation = FindWinStationById( sessionID, FALSE );
  8552. if ( pWinStation == NULL )
  8553. {
  8554. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "Winstation not found \n"));
  8555. return( FALSE );
  8556. }
  8557. if ( pWinStation->Flags & WSF_LISTEN )
  8558. {
  8559. // this is a "listen" winstation, not an interactive one, so return an empty response.
  8560. *pResponse = 0;
  8561. ReleaseWinStation( pWinStation );
  8562. return( TRUE );
  8563. }
  8564. if ( !((pWinStation->State == State_Active) ||
  8565. (pWinStation->State == State_Disconnected) ) )
  8566. {
  8567. // This is something that winsta.C checks for, but it's possibele that from the time it
  8568. // took to get here, a winstation was logged out from.
  8569. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "\t request aborted, winstation State should be Active or Disconnected, neither in this case. \n"));
  8570. *pResponse = 0;
  8571. ReleaseWinStation( pWinStation );
  8572. return( TRUE );
  8573. }
  8574. // if we have valid data, then set the msg dataBuffer to point to it
  8575. if ( fBufferHasValidData )
  8576. {
  8577. WMsg.u.bMsg.dataBuffer = rpcBuffer;
  8578. WMsg.u.bMsg.bufferSize = bufferSize;
  8579. }
  8580. /*
  8581. * send message to winstation
  8582. */
  8583. rc = SendWinStationCommand( pWinStation, &WMsg, waitTime );
  8584. ReleaseWinStation( pWinStation );
  8585. if ( NT_SUCCESS( rc ) )
  8586. {
  8587. *pResponse = WMsg.u.bMsg.Response;
  8588. *lpdwRecipients = WMsg.u.bMsg.dwRecipients;
  8589. return (TRUE);
  8590. }
  8591. else
  8592. return ( FALSE );
  8593. }
  8594. /*****************************************************************************
  8595. *
  8596. * RpcWinStationSendWindowMessage
  8597. *
  8598. * Perform the the equivalent to SendMessage to a specific winstation as
  8599. * identified by the session ID. This is an exported function, at least used
  8600. * by the PNP manager to send a device change message (or any other window's message)
  8601. *
  8602. * Limitations:
  8603. * Caller must be system or Admin, and lparam can not be zero unless
  8604. * msg is WM_DEVICECHANGE
  8605. * Error checking is done on the clinet side (winsta\client\winsta.c)
  8606. *
  8607. * ENTRY:
  8608. * hServer
  8609. * this is a handle which identifies a Hydra server. For the local server, hServer
  8610. * should be set to SERVERNAME_CURRENT
  8611. * sessionID
  8612. * this idefntifies the hydra session to which message is being sent
  8613. * timeOut
  8614. * set this to the amount of time you are willing to wait to get a response
  8615. * from the specified winstation. Even though Window's SendMessage API
  8616. * is blocking, the call from this side MUST choose how long it is willing to
  8617. * wait for a response.
  8618. * hWnd
  8619. * This is the HWND of the target window in the specified session that
  8620. * a message will be sent to.
  8621. * Msg
  8622. * the window's message to send
  8623. * wParam
  8624. * first message param
  8625. * lParam
  8626. * second message parameter
  8627. * pResponse
  8628. * this is the response to the message sent, it depends on the type of message sent, see MSDN
  8629. *
  8630. *
  8631. * EXIT:
  8632. * TRUE if all went well , check presponse for the actual response to the send message
  8633. * FALSE if something went wrong, the value of pResponse is not altered.
  8634. *
  8635. * WARNINGs:
  8636. * since the RPC call never blocks, you need to specify a reasonable timeOut if you want to wait for
  8637. * a response. Please remember that since this message is being sent to all winstations, the timeOut value
  8638. * will be on per-winstation.
  8639. *
  8640. *
  8641. * Comments:
  8642. * For more info, please see MSDN for SendMessage()
  8643. *
  8644. ****************************************************************************/
  8645. LONG
  8646. RpcWinStationSendWindowMessage(
  8647. HANDLE hServer,
  8648. ULONG sessionID,
  8649. ULONG waitTime,
  8650. ULONG hWnd, // handle of destination window
  8651. ULONG Msg, // message to send
  8652. WPARAM wParam, // first message parameter
  8653. LPARAM lParam, // second message parameter
  8654. PBYTE rpcBuffer,
  8655. ULONG bufferSize,
  8656. BOOLEAN fBufferHasValidData,
  8657. LONG *pResponse // reply to the message sent
  8658. )
  8659. {
  8660. PWINSTATION pWinStation=NULL;
  8661. WINSTATION_APIMSG WMsg;
  8662. OBJECT_ATTRIBUTES ObjA;
  8663. NTSTATUS Status;
  8664. LONG rc;
  8665. int i;
  8666. PVOID pData;
  8667. RPC_STATUS RpcStatus;
  8668. UINT LocalFlag;
  8669. if(!hServer)
  8670. {
  8671. return( FALSE );
  8672. }
  8673. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "in RpcWinStationSendWindowMessage()\n"));
  8674. /*
  8675. * Impersonate the client
  8676. */
  8677. RpcStatus = RpcImpersonateClient( NULL );
  8678. if( RpcStatus != RPC_S_OK ) {
  8679. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "\tNot impersonating! RpcStatus 0x%x\n",RpcStatus));
  8680. SetLastError(ERROR_CANNOT_IMPERSONATE );
  8681. return( FALSE );
  8682. }
  8683. //
  8684. // Inquire if local RPC call
  8685. //
  8686. RpcStatus = I_RpcBindingIsClientLocal(
  8687. 0, // Active RPC call we are servicing
  8688. &LocalFlag
  8689. );
  8690. if( RpcStatus != RPC_S_OK ) {
  8691. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "\tI_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  8692. RpcRevertToSelf();
  8693. SetLastError(ERROR_ACCESS_DENIED);
  8694. return( FALSE );
  8695. }
  8696. if( !LocalFlag ) {
  8697. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "\tNot a local client call\n"));
  8698. RpcRevertToSelf();
  8699. return( FALSE );
  8700. }
  8701. // if the caller is system or admin, then let it thru, else, return
  8702. if( !(IsCallerSystem() | IsCallerAdmin() ) )
  8703. {
  8704. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "\tCaller must be system or admin \n"));
  8705. SetLastError(ERROR_ACCESS_DENIED);
  8706. RpcRevertToSelf();
  8707. return( FALSE );
  8708. }
  8709. //
  8710. // if we got this far, then client is admin or system
  8711. //
  8712. //
  8713. // done with the impersonation, we must have succeeded, otherwise, we would have exited above
  8714. //
  8715. RpcRevertToSelf();
  8716. /*
  8717. * Marshall in the [in] parameters
  8718. *
  8719. */
  8720. WMsg.WaitForReply=TRUE;
  8721. WMsg.u.sMsg.hWnd = (HWND)LongToHandle( hWnd );
  8722. WMsg.u.sMsg.Msg = Msg;
  8723. WMsg.u.sMsg.wParam = wParam;
  8724. WMsg.u.sMsg.lParam = lParam;
  8725. WMsg.u.sMsg.dataBuffer = NULL;
  8726. WMsg.u.sMsg.bufferSize = 0;
  8727. WMsg.u.sMsg.Response = *pResponse;
  8728. WMsg.ApiNumber = SMWinStationSendWindowMessage ;
  8729. /*
  8730. * Find and lock client WinStation
  8731. */
  8732. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "in RpcWinStationSendWindowMessage() for essionID = %d \n", sessionID ));
  8733. pWinStation = FindWinStationById( sessionID, FALSE );
  8734. if ( pWinStation == NULL )
  8735. {
  8736. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "Winstation not found \n"));
  8737. return( FALSE );
  8738. }
  8739. if ( pWinStation->Flags & WSF_LISTEN )
  8740. {
  8741. // this is a "listen" winstation, not an interactive one
  8742. ReleaseWinStation( pWinStation );
  8743. return( FALSE ); // this is normal situation, not an error, but no caller of this func should send a message to this w/s
  8744. }
  8745. if ( !((pWinStation->State == State_Active) ||
  8746. (pWinStation->State == State_Disconnected) ) )
  8747. {
  8748. // This is something that winsta.C checks for, but it's possibele that from the time it
  8749. // took to get here, a winstation was logged out from.
  8750. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "\t request aborted, winstation State should be Active or Disconnected, neither in this case. \n"));
  8751. *pResponse = 0;
  8752. ReleaseWinStation( pWinStation );
  8753. return( TRUE );
  8754. }
  8755. // if we have valid data, then set the msg dataBuffer to point to it
  8756. if ( fBufferHasValidData )
  8757. {
  8758. WMsg.u.sMsg.dataBuffer = rpcBuffer;
  8759. WMsg.u.sMsg.bufferSize = bufferSize;
  8760. }
  8761. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, " dataBuffer = 0x%lx \n", WMsg.u.sMsg.dataBuffer ));
  8762. // KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, " bufferSize = %d \n", WMsg.u.sMsg.bufferSize ));
  8763. /*
  8764. * send message to winstation
  8765. */
  8766. rc = SendWinStationCommand( pWinStation, &WMsg, waitTime );
  8767. ReleaseWinStation( pWinStation );
  8768. if ( NT_SUCCESS( rc ) )
  8769. {
  8770. *pResponse = WMsg.u.sMsg.Response;
  8771. return (TRUE);
  8772. }
  8773. else
  8774. return ( FALSE );
  8775. }
  8776. NTSTATUS
  8777. IsZeroterminateStringA(
  8778. PBYTE pString,
  8779. DWORD dwLength
  8780. )
  8781. {
  8782. NTSTATUS Status = STATUS_SUCCESS;
  8783. if ( (pString == NULL) || (memchr(pString, '\0', dwLength) == NULL)) {
  8784. Status = STATUS_INVALID_PARAMETER;
  8785. }
  8786. return Status;
  8787. }
  8788. NTSTATUS
  8789. IsZeroterminateStringW(
  8790. PWCHAR pwString,
  8791. DWORD dwLength
  8792. )
  8793. {
  8794. if (pwString == NULL) {
  8795. return STATUS_INVALID_PARAMETER;
  8796. }
  8797. for (; 0 < dwLength; ++pwString, --dwLength ) {
  8798. if (*pwString == (WCHAR)0) {
  8799. return STATUS_SUCCESS;
  8800. }
  8801. }
  8802. return STATUS_INVALID_PARAMETER;
  8803. }
  8804. /*****************************************************************************
  8805. * GetTextualSid()
  8806. * given a sid, return the text of that sid
  8807. *
  8808. * Params:
  8809. * [in] user sid binary
  8810. * [out] text of user sid stuffed in the buffer which was passed in by the caller
  8811. * [in] the size of buffer passed in.
  8812. *
  8813. * Return:
  8814. * TRUE if no errors.
  8815. *
  8816. ******************************************************************************/
  8817. BOOL
  8818. GetTextualSid(
  8819. PSID pSid, // binary Sid
  8820. LPTSTR TextualSid, // buffer for Textual representaion of Sid
  8821. LPDWORD cchSidSize // required/provided TextualSid buffersize
  8822. )
  8823. {
  8824. PSID_IDENTIFIER_AUTHORITY psia;
  8825. DWORD dwSubAuthorities;
  8826. DWORD dwCounter;
  8827. DWORD cchSidCopy;
  8828. //
  8829. // test if Sid passed in is valid
  8830. //
  8831. if(!IsValidSid(pSid)) return FALSE;
  8832. // obtain SidIdentifierAuthority
  8833. psia = GetSidIdentifierAuthority(pSid);
  8834. // obtain sidsubauthority count
  8835. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  8836. //
  8837. // compute approximate buffer length
  8838. // S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
  8839. //
  8840. cchSidCopy = (15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
  8841. //
  8842. // check provided buffer length.
  8843. // If not large enough, indicate proper size and setlasterror
  8844. //
  8845. if(*cchSidSize < cchSidCopy) {
  8846. *cchSidSize = cchSidCopy;
  8847. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  8848. return FALSE;
  8849. }
  8850. //
  8851. // prepare S-SID_REVISION-
  8852. //
  8853. cchSidCopy = wsprintf(TextualSid, TEXT("S-%lu-"), SID_REVISION );
  8854. //
  8855. // prepare SidIdentifierAuthority
  8856. //
  8857. if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) {
  8858. cchSidCopy += wsprintf(TextualSid + cchSidCopy,
  8859. TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
  8860. (USHORT)psia->Value[0],
  8861. (USHORT)psia->Value[1],
  8862. (USHORT)psia->Value[2],
  8863. (USHORT)psia->Value[3],
  8864. (USHORT)psia->Value[4],
  8865. (USHORT)psia->Value[5]);
  8866. } else {
  8867. cchSidCopy += wsprintf(TextualSid + cchSidCopy,
  8868. TEXT("%lu"),
  8869. (ULONG)(psia->Value[5] ) +
  8870. (ULONG)(psia->Value[4] << 8) +
  8871. (ULONG)(psia->Value[3] << 16) +
  8872. (ULONG)(psia->Value[2] << 24) );
  8873. }
  8874. //
  8875. // loop through SidSubAuthorities
  8876. //
  8877. for(dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++) {
  8878. cchSidCopy += wsprintf(TextualSid + cchSidCopy, TEXT("-%lu"),
  8879. *GetSidSubAuthority(pSid, dwCounter) );
  8880. }
  8881. //
  8882. // tell the caller how many chars we provided, not including NULL
  8883. //
  8884. *cchSidSize = cchSidCopy;
  8885. return TRUE;
  8886. }
  8887. /*****************************************************************************
  8888. * RpcWinStationUpdateUserConfig()
  8889. * Called by notify when winlogon tells notify that shell startup is about to happen
  8890. * We open the user profile and get the policy data, and then override any data found
  8891. * in user's sessions's USERCONFIGW
  8892. *
  8893. * Params:
  8894. * [in] hServer,
  8895. * [in] ClientLogonId,
  8896. * [in] ClientProcessId,
  8897. * [in] UserToken,
  8898. * [in] pDomain,
  8899. * [in] DomainSize,
  8900. * [in] pUserName,
  8901. * [in] UserNameSize,
  8902. * [out] *pResult
  8903. *
  8904. * Return:
  8905. * TRUE if no errors, FALSE otherwise, see pResult for the NTSTATUS of the error
  8906. *
  8907. *
  8908. *
  8909. * *****************************************************************************/
  8910. BOOLEAN
  8911. RpcWinStationUpdateUserConfig(
  8912. HANDLE hServer,
  8913. DWORD ClientLogonId,
  8914. DWORD ClientProcessId,
  8915. DWORD UserToken,
  8916. DWORD *pResult
  8917. )
  8918. {
  8919. NTSTATUS Status = STATUS_SUCCESS;
  8920. ULONG Length;
  8921. DWORD rc = ERROR_SUCCESS;
  8922. ULONG Error;
  8923. USERCONFIGW *pTmpUserConfig;
  8924. POLICY_TS_USER userPolicy;
  8925. USERCONFIGW userPolicyData;
  8926. HANDLE NewToken;
  8927. PWINSTATION pWinStation;
  8928. OBJECT_ATTRIBUTES ObjA;
  8929. PTOKEN_USER pTokenInfo = NULL;
  8930. HANDLE hClientToken=NULL;
  8931. // @@@ make these dynamic later
  8932. TCHAR szSidText [MAX_PATH ];
  8933. DWORD sidTextSize = MAX_PATH;
  8934. if(!hServer)
  8935. {
  8936. *pResult = STATUS_UNSUCCESSFUL;
  8937. return( FALSE );
  8938. }
  8939. *pResult=0;
  8940. /*
  8941. * Make sure the caller is SYSTEM (WinLogon)
  8942. */
  8943. Status = RpcCheckSystemClient( ClientLogonId );
  8944. if ( !NT_SUCCESS( Status ) ) {
  8945. *pResult = Status;
  8946. return( FALSE );
  8947. }
  8948. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationUpdateUserConfig, LogonId=%d\n", ClientLogonId ));
  8949. /*
  8950. * Find and lock client WinStation
  8951. */
  8952. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  8953. if ( pWinStation == NULL )
  8954. {
  8955. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  8956. *pResult = Status;
  8957. return( FALSE );
  8958. }
  8959. /*
  8960. * Get a valid copy of the clients token handle
  8961. */
  8962. Status = NtDuplicateObject( pWinStation->InitialCommandProcess,
  8963. (HANDLE)LongToHandle( UserToken ),
  8964. NtCurrentProcess(),
  8965. &hClientToken,
  8966. 0, 0,
  8967. DUPLICATE_SAME_ACCESS |
  8968. DUPLICATE_SAME_ATTRIBUTES );
  8969. if ( !NT_SUCCESS( Status ) )
  8970. goto done;
  8971. /*
  8972. * Determine size needed for token info buffer and allocate it
  8973. */
  8974. Status = NtQueryInformationToken ( hClientToken, TokenUser,
  8975. NULL, 0, &Length );
  8976. if ( Status != STATUS_BUFFER_TOO_SMALL )
  8977. {
  8978. goto done;
  8979. }
  8980. pTokenInfo = MemAlloc( Length );
  8981. if ( pTokenInfo == NULL )
  8982. {
  8983. Status = STATUS_NO_MEMORY;
  8984. goto done;
  8985. }
  8986. /*
  8987. * Query token information to get client user's SID
  8988. */
  8989. Status = NtQueryInformationToken ( hClientToken, TokenUser,
  8990. pTokenInfo, Length, &Length );
  8991. if ( NT_SUCCESS( Status ) )
  8992. {
  8993. if ( GetTextualSid( pTokenInfo->User.Sid , szSidText, &sidTextSize ) )
  8994. {
  8995. // We now have the user SID
  8996. /*
  8997. * Get User policy from HKCU
  8998. */
  8999. if ( RegGetUserPolicy( szSidText, &userPolicy, & userPolicyData ) )
  9000. {
  9001. // 4th param is NULL, since config data is already part of pWinstation
  9002. // due to the call into NotifyLogonWorker from Winlogon. We are now
  9003. // going to override data by any/all user group policy data.
  9004. MergeUserConfigData( pWinStation, &userPolicy, &userPolicyData, NULL );
  9005. }
  9006. // else we were not able to get user policy, so no merge was done.
  9007. }
  9008. }
  9009. done:
  9010. if (pTokenInfo )
  9011. {
  9012. MemFree( pTokenInfo );
  9013. }
  9014. if (hClientToken)
  9015. {
  9016. NtClose( hClientToken );
  9017. }
  9018. /*
  9019. * Start logon timers anyway, in case of any errors, we should still start the timers since
  9020. * some machine policy might have set them up.
  9021. */
  9022. StartLogonTimers( pWinStation );
  9023. ReleaseWinStation( pWinStation );
  9024. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: RpcWinStationUpdateUserConfig, Status=0x%x\n", Status ));
  9025. *pResult = Status ;
  9026. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  9027. }
  9028. BOOLEAN RpcWinStationUnRegisterNotificationEvent (
  9029. HANDLE hServer,
  9030. DWORD *pResult,
  9031. ULONG_PTR NotificationId,
  9032. ULONG SessionId
  9033. )
  9034. {
  9035. RPC_STATUS RpcStatus;
  9036. UINT LocalFlag;
  9037. if (pResult == NULL) {
  9038. return FALSE;
  9039. }
  9040. if(!hServer)
  9041. {
  9042. *pResult = STATUS_UNSUCCESSFUL;
  9043. return( FALSE );
  9044. }
  9045. //
  9046. // Calling this function from the remote machine, does not make sense, and
  9047. // we should not allow it.
  9048. //
  9049. RpcStatus = RpcImpersonateClient( NULL );
  9050. if( RpcStatus != RPC_S_OK ) {
  9051. DBGPRINT((" RpcImpersonateClient() failed : 0x%x\n",RpcStatus));
  9052. *pResult = STATUS_CANNOT_IMPERSONATE;
  9053. return( FALSE );
  9054. }
  9055. //
  9056. // Inquire if local RPC call
  9057. //
  9058. RpcStatus = I_RpcBindingIsClientLocal(
  9059. 0, // Active RPC call we are servicing
  9060. &LocalFlag
  9061. );
  9062. if( RpcStatus != RPC_S_OK ) {
  9063. DBGPRINT((" I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  9064. RpcRevertToSelf();
  9065. *pResult = STATUS_ACCESS_DENIED;
  9066. return( FALSE );
  9067. }
  9068. if( !LocalFlag ) {
  9069. DBGPRINT((" Not a local client call\n"));
  9070. *pResult = STATUS_ACCESS_DENIED;
  9071. RpcRevertToSelf();
  9072. return( FALSE );
  9073. }
  9074. else
  9075. {
  9076. ULONG ClientLogonId;
  9077. *pResult = RpcGetClientLogonId( &ClientLogonId );
  9078. if ( !NT_SUCCESS( *pResult ) ) {
  9079. RpcRevertToSelf();
  9080. return( FALSE );
  9081. }
  9082. if (ClientLogonId != SessionId)
  9083. {
  9084. RpcRevertToSelf();
  9085. *pResult = STATUS_INVALID_PARAMETER;
  9086. return FALSE;
  9087. }
  9088. }
  9089. //
  9090. // done with the impersonation, we must have succeeded, otherwise, we would have exited above
  9091. //
  9092. RpcRevertToSelf();
  9093. *pResult = UnRegisterConsoleNotification ( NotificationId, SessionId, WTS_EVENT_NOTIFICATION);
  9094. return (*pResult == STATUS_SUCCESS);
  9095. }
  9096. BOOLEAN RpcWinStationRegisterNotificationEvent (
  9097. HANDLE hServer,
  9098. DWORD *pResult,
  9099. ULONG_PTR *pNotificationId,
  9100. ULONG_PTR EventHandle, // handle of destination window
  9101. DWORD dwFlags,
  9102. DWORD dwMask,
  9103. ULONG SessionId,
  9104. ULONG ProcessId
  9105. )
  9106. {
  9107. RPC_STATUS RpcStatus;
  9108. UINT LocalFlag;
  9109. ULONG_PTR dupHandle;
  9110. HANDLE ClientProcessHandle = NULL;
  9111. OBJECT_ATTRIBUTES ObjectAttributes;
  9112. CLIENT_ID ClientId;
  9113. if (pResult == NULL) {
  9114. return FALSE;
  9115. }
  9116. if(!hServer)
  9117. {
  9118. *pResult = STATUS_UNSUCCESSFUL;
  9119. return( FALSE );
  9120. }
  9121. if (pNotificationId == NULL) {
  9122. *pResult = STATUS_INVALID_PARAMETER;
  9123. return FALSE;
  9124. }
  9125. if (!dwMask) {
  9126. *pResult = STATUS_INVALID_PARAMETER;
  9127. return FALSE;
  9128. }
  9129. //
  9130. // Calling this function from the remote machine, does not make sense, and
  9131. // we should not allow it.
  9132. //
  9133. RpcStatus = RpcImpersonateClient( NULL );
  9134. if( RpcStatus != RPC_S_OK ) {
  9135. DBGPRINT((" RpcImpersonateClient() failed : 0x%x\n",RpcStatus));
  9136. *pResult = STATUS_CANNOT_IMPERSONATE;
  9137. return( FALSE );
  9138. }
  9139. //
  9140. // Inquire if local RPC call
  9141. //
  9142. RpcStatus = I_RpcBindingIsClientLocal(
  9143. 0, // Active RPC call we are servicing
  9144. &LocalFlag
  9145. );
  9146. if( RpcStatus != RPC_S_OK ) {
  9147. DBGPRINT((" I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  9148. RpcRevertToSelf();
  9149. *pResult = STATUS_ACCESS_DENIED;
  9150. return( FALSE );
  9151. }
  9152. if( !LocalFlag ) {
  9153. DBGPRINT((" Not a local client call\n"));
  9154. *pResult = STATUS_ACCESS_DENIED;
  9155. RpcRevertToSelf();
  9156. return( FALSE );
  9157. }
  9158. else
  9159. {
  9160. ULONG ClientLogonId;
  9161. *pResult = RpcGetClientLogonId( &ClientLogonId );
  9162. if ( !NT_SUCCESS( *pResult ) ) {
  9163. RpcRevertToSelf();
  9164. return( FALSE );
  9165. }
  9166. if (ClientLogonId != SessionId)
  9167. {
  9168. RpcRevertToSelf();
  9169. *pResult = STATUS_INVALID_PARAMETER;
  9170. return( FALSE );
  9171. }
  9172. }
  9173. //
  9174. // get the client process handle.
  9175. // do this while client is impersonated, so that if client doesnt have access to the
  9176. // said process, we will fail the call.
  9177. //
  9178. ClientProcessHandle = OpenProcess( PROCESS_DUP_HANDLE, FALSE, ProcessId );
  9179. if (!ClientProcessHandle) {
  9180. *pResult = STATUS_ACCESS_DENIED;
  9181. RpcRevertToSelf();
  9182. return (FALSE);
  9183. }
  9184. //
  9185. // done with the impersonation, we must have succeeded, otherwise, we would have exited above
  9186. //
  9187. RpcRevertToSelf();
  9188. if (DuplicateHandle(
  9189. ClientProcessHandle,
  9190. (HANDLE)EventHandle,
  9191. GetCurrentProcess(),
  9192. (PHANDLE)&dupHandle,
  9193. 0,
  9194. 0,
  9195. DUPLICATE_SAME_ACCESS
  9196. )) {
  9197. *pResult = STATUS_SUCCESS;
  9198. } else {
  9199. *pResult = STATUS_INVALID_PARAMETER;
  9200. }
  9201. CloseHandle(ClientProcessHandle);
  9202. if ( NT_SUCCESS( *pResult ) ) {
  9203. dwFlags |= WTS_EVENT_NOTIFICATION;
  9204. dwFlags &= ~WTS_WINDOW_NOTIFICATION;
  9205. *pResult = RegisterConsoleNotification ( dupHandle, SessionId, dwFlags, dwMask );
  9206. if ( NT_SUCCESS( *pResult ) ) {
  9207. *pNotificationId = dupHandle;
  9208. } else {
  9209. CloseHandle((HANDLE)dupHandle);
  9210. }
  9211. }
  9212. return (*pResult == STATUS_SUCCESS);
  9213. }
  9214. BOOLEAN RpcWinStationRegisterConsoleNotification (
  9215. HANDLE hServer,
  9216. DWORD *pResult,
  9217. ULONG SessionId,
  9218. ULONG_PTR handle, // handle of destination window
  9219. DWORD dwFlags,
  9220. DWORD dwMask
  9221. )
  9222. {
  9223. RPC_STATUS RpcStatus;
  9224. UINT LocalFlag;
  9225. if (pResult == NULL) {
  9226. return FALSE;
  9227. }
  9228. if(!hServer)
  9229. {
  9230. *pResult = STATUS_UNSUCCESSFUL;
  9231. return( FALSE );
  9232. }
  9233. //
  9234. // Calling this function from the remote machine, does not make sense, and
  9235. // we should not allow it.
  9236. //
  9237. RpcStatus = RpcImpersonateClient( NULL );
  9238. if( RpcStatus != RPC_S_OK ) {
  9239. DBGPRINT((" RpcImpersonateClient() failed : 0x%x\n",RpcStatus));
  9240. *pResult = STATUS_CANNOT_IMPERSONATE;
  9241. return( FALSE );
  9242. }
  9243. //
  9244. // Inquire if local RPC call
  9245. //
  9246. RpcStatus = I_RpcBindingIsClientLocal(
  9247. 0, // Active RPC call we are servicing
  9248. &LocalFlag
  9249. );
  9250. if( RpcStatus != RPC_S_OK ) {
  9251. DBGPRINT((" I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  9252. RpcRevertToSelf();
  9253. *pResult = STATUS_ACCESS_DENIED;
  9254. return( FALSE );
  9255. }
  9256. if( !LocalFlag ) {
  9257. DBGPRINT((" Not a local client call\n"));
  9258. *pResult = STATUS_ACCESS_DENIED;
  9259. RpcRevertToSelf();
  9260. return( FALSE );
  9261. }
  9262. {
  9263. ULONG ClientLogonId;
  9264. *pResult = RpcGetClientLogonId( &ClientLogonId );
  9265. if ( !NT_SUCCESS( *pResult ) ) {
  9266. RpcRevertToSelf();
  9267. return( FALSE );
  9268. }
  9269. if (ClientLogonId != SessionId)
  9270. {
  9271. RpcRevertToSelf();
  9272. *pResult = STATUS_INVALID_PARAMETER;
  9273. return( FALSE );
  9274. }
  9275. }
  9276. //
  9277. // done with the impersonation, we must have succeeded, otherwise, we would have exited above
  9278. //
  9279. RpcRevertToSelf();
  9280. // BUGBUG : MakarP, can we check if the calling process owns this hWnd ?
  9281. // using GetWindowThreadProcessId ? Does it work across the sessions ?
  9282. dwFlags &= ~WTS_EVENT_NOTIFICATION;
  9283. dwFlags |= WTS_WINDOW_NOTIFICATION;
  9284. *pResult = RegisterConsoleNotification ( handle, SessionId, dwFlags, dwMask );
  9285. return (*pResult == STATUS_SUCCESS);
  9286. }
  9287. BOOLEAN RpcWinStationUnRegisterConsoleNotification (
  9288. HANDLE hServer,
  9289. DWORD *pResult,
  9290. ULONG SessionId,
  9291. ULONG hWnd // handle of destination window
  9292. )
  9293. {
  9294. RPC_STATUS RpcStatus;
  9295. UINT LocalFlag;
  9296. if (pResult == NULL) {
  9297. return FALSE;
  9298. }
  9299. if(!hServer)
  9300. {
  9301. *pResult = STATUS_UNSUCCESSFUL;
  9302. return( FALSE );
  9303. }
  9304. //
  9305. // Calling this function from the remote machine, does not make sense, and
  9306. // we should not allow it.
  9307. //
  9308. RpcStatus = RpcImpersonateClient( NULL );
  9309. if( RpcStatus != RPC_S_OK ) {
  9310. DBGPRINT((" RpcImpersonateClient() failed : 0x%x\n",RpcStatus));
  9311. *pResult = STATUS_CANNOT_IMPERSONATE;
  9312. return( FALSE );
  9313. }
  9314. //
  9315. // Inquire if local RPC call
  9316. //
  9317. RpcStatus = I_RpcBindingIsClientLocal(
  9318. 0, // Active RPC call we are servicing
  9319. &LocalFlag
  9320. );
  9321. if( RpcStatus != RPC_S_OK ) {
  9322. DBGPRINT((" I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  9323. RpcRevertToSelf();
  9324. *pResult = STATUS_ACCESS_DENIED;
  9325. return( FALSE );
  9326. }
  9327. if( !LocalFlag ) {
  9328. DBGPRINT((" Not a local client call\n"));
  9329. *pResult = STATUS_ACCESS_DENIED;
  9330. RpcRevertToSelf();
  9331. return( FALSE );
  9332. }
  9333. {
  9334. ULONG ClientLogonId;
  9335. *pResult = RpcGetClientLogonId( &ClientLogonId );
  9336. if ( !NT_SUCCESS( *pResult ) ) {
  9337. RpcRevertToSelf();
  9338. return( FALSE );
  9339. }
  9340. if (ClientLogonId != SessionId)
  9341. {
  9342. RpcRevertToSelf();
  9343. *pResult = STATUS_INVALID_PARAMETER;
  9344. return( FALSE );
  9345. }
  9346. }
  9347. //
  9348. // done with the impersonation, we must have succeeded, otherwise, we would have exited above
  9349. //
  9350. RpcRevertToSelf();
  9351. // BUGBUG : MakarP, can we check if the calling process owns this hWnd ?
  9352. // using GetWindowThreadProcessId ? Does it work across the sessions ?
  9353. *pResult = UnRegisterConsoleNotification ( hWnd, SessionId, WTS_WINDOW_NOTIFICATION);
  9354. return (*pResult == STATUS_SUCCESS);
  9355. }
  9356. BOOLEAN RpcWinStationIsHelpAssistantSession (
  9357. HANDLE hServer,
  9358. DWORD *pResult, // function status
  9359. ULONG SessionId // user logon id
  9360. )
  9361. /*++
  9362. RpcWinStationIsSessionHelpAssistantSession returns if a
  9363. given session is created by Salem HelpAssistant account.
  9364. Parameters:
  9365. hServer : Handle to server, unused, just to match all
  9366. other RPC function.
  9367. SessionId : User session ID.
  9368. Returns:
  9369. TRUE/FALSE
  9370. --*/
  9371. {
  9372. RPC_STATUS RpcStatus;
  9373. UINT LocalFlag;
  9374. PWINSTATION pWinStation=NULL;
  9375. BOOLEAN bReturn;
  9376. BOOL bValidHelpSession;
  9377. if(!hServer)
  9378. {
  9379. *pResult = STATUS_UNSUCCESSFUL;
  9380. return( FALSE );
  9381. }
  9382. *pResult=0;
  9383. //
  9384. // Do we need to check system or only LPC call?
  9385. //
  9386. //
  9387. // Find and lock client WinStation
  9388. //
  9389. pWinStation = FindWinStationById( SessionId, FALSE );
  9390. if ( pWinStation == NULL )
  9391. {
  9392. *pResult = STATUS_CTX_WINSTATION_NOT_FOUND;
  9393. return( FALSE );
  9394. }
  9395. bReturn = (BOOLEAN)TSIsSessionHelpSession( pWinStation, &bValidHelpSession );
  9396. if( TRUE == bReturn )
  9397. {
  9398. if( FALSE == bValidHelpSession )
  9399. {
  9400. *pResult = STATUS_WRONG_PASSWORD;
  9401. }
  9402. }
  9403. ReleaseWinStation( pWinStation );
  9404. return bReturn;
  9405. }
  9406. BOOLEAN RpcRemoteAssistancePrepareSystemRestore (
  9407. HANDLE hServer,
  9408. DWORD *pResult // function status
  9409. )
  9410. /*++
  9411. Prepare TermSrv/Salem for system restore.
  9412. Parameters:
  9413. hServer : Handle to server, unused, just to match all
  9414. other RPC function.
  9415. pResult : Pointer to DWORD to receive status of function.
  9416. Returns:
  9417. TRUE/FALSE
  9418. --*/
  9419. {
  9420. BOOLEAN bReturn = TRUE;
  9421. RPC_STATUS RpcStatus;
  9422. BOOL LocalFlag;
  9423. HRESULT hRes;
  9424. if (pResult == NULL) {
  9425. return FALSE;
  9426. }
  9427. if(!hServer)
  9428. {
  9429. *pResult = STATUS_UNSUCCESSFUL;
  9430. return( FALSE );
  9431. }
  9432. //
  9433. // Calling this function from the remote machine, does not make sense, and
  9434. // we should not allow it.
  9435. //
  9436. RpcStatus = RpcImpersonateClient( NULL );
  9437. if( RpcStatus != RPC_S_OK ) {
  9438. DBGPRINT((" RpcImpersonateClient() failed : 0x%x\n",RpcStatus));
  9439. *pResult = ERROR_CANNOT_IMPERSONATE;
  9440. return( FALSE );
  9441. }
  9442. //
  9443. // Allow ony local admin to invoke this call.
  9444. //
  9445. if( !IsCallerAdmin() ) {
  9446. RpcRevertToSelf();
  9447. *pResult = ERROR_ACCESS_DENIED;
  9448. return (FALSE);
  9449. }
  9450. //
  9451. // Inquire if local RPC call
  9452. //
  9453. RpcStatus = I_RpcBindingIsClientLocal(
  9454. 0, // Active RPC call we are servicing
  9455. &LocalFlag
  9456. );
  9457. if( RpcStatus != RPC_S_OK ) {
  9458. DBGPRINT((" I_RpcBindingIsClientLocal() failed : 0x%x\n",RpcStatus));
  9459. RpcRevertToSelf();
  9460. *pResult = ERROR_ACCESS_DENIED;
  9461. return( FALSE );
  9462. }
  9463. if( !LocalFlag ) {
  9464. DBGPRINT((" Not a local client call\n"));
  9465. *pResult = ERROR_ACCESS_DENIED;
  9466. RpcRevertToSelf();
  9467. return( FALSE );
  9468. }
  9469. //
  9470. // done with the impersonation, we must have succeeded, otherwise, we would have exited above
  9471. //
  9472. RpcRevertToSelf();
  9473. *pResult=0;
  9474. hRes = TSRemoteAssistancePrepareSystemRestore();
  9475. if( S_OK != hRes ) {
  9476. bReturn = FALSE;
  9477. *pResult = hRes;
  9478. }
  9479. return bReturn;
  9480. }
  9481. /*
  9482. * RpcWinStationGetMachinePolicy
  9483. *
  9484. * Return (a copye of ) the machine policy to the caller
  9485. *
  9486. * Parameters:
  9487. *
  9488. * hServer : Handle to server, unused, just to match all
  9489. * other RPC function.
  9490. *
  9491. * pointer to the policy struct
  9492. *
  9493. * size of the policy struct.
  9494. *
  9495. */
  9496. BOOLEAN
  9497. RpcWinStationGetMachinePolicy(
  9498. SERVER_HANDLE hServer,
  9499. PBYTE pPolicy,
  9500. ULONG bufferSize )
  9501. {
  9502. if(!hServer)
  9503. {
  9504. return( FALSE );
  9505. }
  9506. if (pPolicy == NULL) {
  9507. return FALSE;
  9508. }
  9509. // Check if BufferSize if big enough
  9510. if (bufferSize < sizeof(POLICY_TS_MACHINE)) {
  9511. return FALSE;
  9512. }
  9513. RtlCopyMemory( pPolicy , & g_MachinePolicy, sizeof( POLICY_TS_MACHINE ) );
  9514. return TRUE;
  9515. }
  9516. /*++
  9517. RpcWinStationUpdateClientCachedCredentials is used to store the ACTUAL credentials
  9518. used to log on by a client. This is stored in WINSTATION struct which is later
  9519. on used to notify the client about the logon credentials. This API is called
  9520. from MSGINA.
  9521. Parameters:
  9522. ClientLogonId : Logon Id of the new session opened by the client
  9523. pDomian, pUserName : Credentials used by the client to log on
  9524. Returns:
  9525. TRUE if the call succeeded in updating the credentials.
  9526. --*/
  9527. BOOLEAN
  9528. RpcWinStationUpdateClientCachedCredentials(
  9529. HANDLE hServer,
  9530. DWORD *pResult,
  9531. DWORD ClientLogonId,
  9532. ULONG_PTR ClientProcessId,
  9533. PWCHAR pDomain,
  9534. DWORD DomainSize,
  9535. PWCHAR pUserName,
  9536. DWORD UserNameSize,
  9537. BOOLEAN fSmartCard
  9538. )
  9539. {
  9540. NTSTATUS Status;
  9541. if(!hServer)
  9542. {
  9543. *pResult = STATUS_UNSUCCESSFUL;
  9544. return( FALSE );
  9545. }
  9546. /*
  9547. * Do some buffer validation
  9548. */
  9549. *pResult = IsZeroterminateStringW(pUserName, UserNameSize );
  9550. if (*pResult != STATUS_SUCCESS) {
  9551. return FALSE;
  9552. }
  9553. *pResult = IsZeroterminateStringW(pDomain, DomainSize );
  9554. if (*pResult != STATUS_SUCCESS) {
  9555. return FALSE;
  9556. }
  9557. /*
  9558. * Make sure the caller is SYSTEM (WinLogon)
  9559. */
  9560. Status = RpcCheckSystemClient( ClientLogonId );
  9561. if ( !NT_SUCCESS( Status ) ) {
  9562. *pResult = Status;
  9563. return( FALSE );
  9564. }
  9565. *pResult = WinStationUpdateClientCachedCredentialsWorker(
  9566. ClientLogonId,
  9567. ClientProcessId,
  9568. pDomain,
  9569. DomainSize,
  9570. pUserName,
  9571. UserNameSize,
  9572. fSmartCard
  9573. );
  9574. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  9575. }
  9576. /*****************************************************************************
  9577. * WinStationUpdateClientCachedCredentialsWorker
  9578. *
  9579. * Worker function for RPCWinStationUpdateClientCachedCredentials
  9580. ****************************************************************************/
  9581. NTSTATUS WinStationUpdateClientCachedCredentialsWorker(
  9582. DWORD ClientLogonId,
  9583. ULONG_PTR ClientProcessId,
  9584. PWCHAR pDomain,
  9585. DWORD DomainSize,
  9586. PWCHAR pUserName,
  9587. DWORD UserNameSize,
  9588. BOOLEAN fSmartCard)
  9589. {
  9590. PWINSTATION pWinStation;
  9591. ULONG Length;
  9592. NTSTATUS Status = STATUS_SUCCESS;
  9593. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationUpdateClientCachedCredentialsWorker, LogonId=%d\n", ClientLogonId ));
  9594. if ( ShutdownInProgress ) {
  9595. return ( STATUS_CTX_WINSTATION_ACCESS_DENIED );
  9596. }
  9597. /*
  9598. * Find and lock client WinStation
  9599. */
  9600. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  9601. if ( pWinStation == NULL ) {
  9602. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  9603. goto done;
  9604. }
  9605. /*
  9606. * Do not do anything if the session is not connected. The processing in this API assumes we are connected and have a
  9607. * valid stack.
  9608. */
  9609. if ((ClientLogonId != 0) && ((pWinStation->State != State_Connected) || pWinStation->StateFlags & WSF_ST_IN_DISCONNECT)) {
  9610. Status = STATUS_CTX_CLOSE_PENDING;
  9611. ReleaseWinStation( pWinStation );
  9612. goto done;
  9613. }
  9614. /*
  9615. * Upper level code has verified that this RPC
  9616. * is coming from a local client with SYSTEM access.
  9617. *
  9618. * We should be able to trust the ClientProcessId from
  9619. * SYSTEM code.
  9620. */
  9621. /*
  9622. * Ensure this is WinLogon calling
  9623. */
  9624. if ( (HANDLE)(ULONG_PTR)ClientProcessId != pWinStation->InitialCommandProcessId ) {
  9625. ReleaseWinStation( pWinStation );
  9626. goto done;
  9627. }
  9628. /*
  9629. * Save User Name and Domain Name which we will later use to send Notification to the Client
  9630. */
  9631. pWinStation->pNewNotificationCredentials = MemAlloc(sizeof(CLIENTNOTIFICATIONCREDENTIALS));
  9632. if (pWinStation->pNewNotificationCredentials == NULL) {
  9633. Status = STATUS_NO_MEMORY ;
  9634. ReleaseWinStation( pWinStation );
  9635. goto done ;
  9636. }
  9637. // pDomain and pUserName are sent from Winlogon - these cannot exceed the size of the pWinstation buffers
  9638. // because of the restrictions in the credentials lengths imposed by winlogon
  9639. // But anyway check for their length and truncate them if they are more than the length of pWinstation buffers
  9640. if ( wcslen(pDomain) > EXTENDED_DOMAIN_LEN ) {
  9641. pDomain[EXTENDED_DOMAIN_LEN] = L'\0';
  9642. }
  9643. if ( wcslen(pUserName) > EXTENDED_USERNAME_LEN ) {
  9644. pUserName[EXTENDED_USERNAME_LEN] = L'\0';
  9645. }
  9646. wcscpy( pWinStation->pNewNotificationCredentials->Domain, pDomain);
  9647. wcscpy( pWinStation->pNewNotificationCredentials->UserName, pUserName);
  9648. pWinStation->fSmartCardLogon = fSmartCard;
  9649. /*
  9650. * Release the winstation lock
  9651. */
  9652. ReleaseWinStation( pWinStation );
  9653. done:
  9654. /*
  9655. * Save return status in API message
  9656. */
  9657. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationUpdateClientCachedCredentialsWorker, Status=0x%x\n", Status ));
  9658. return Status;
  9659. }
  9660. /*++
  9661. RpcWinStationFUSCanRemoteUserDisconnect - this API is used in a FUS Scenario
  9662. when there is someone at the console and another user tries to open a remote
  9663. session. This API askes the local user if it is ok to disconnect his/her session
  9664. and allow the remote user to connect.
  9665. Parameters:
  9666. TargetLogonId : Session ID which is being requested for connection
  9667. ClientLogonId : Session ID of the temperory new session
  9668. pDomain : Domain Name of the user who is trying to connect from remote
  9669. pUserName : UserName of the user who is trying to connect from remote
  9670. Returns:
  9671. TRUE - The local user has agreed to connect the remote user - so this user's session
  9672. will be disconnected
  9673. FALSE - Local user does not allow the remote user to connect
  9674. --*/
  9675. BOOLEAN
  9676. RpcWinStationFUSCanRemoteUserDisconnect(
  9677. HANDLE hServer,
  9678. DWORD *pResult,
  9679. DWORD TargetLogonId,
  9680. DWORD ClientLogonId,
  9681. ULONG_PTR ClientProcessId,
  9682. PWCHAR pDomain,
  9683. DWORD DomainSize,
  9684. PWCHAR pUserName,
  9685. DWORD UserNameSize
  9686. )
  9687. {
  9688. NTSTATUS Status;
  9689. if(!hServer)
  9690. {
  9691. *pResult = STATUS_UNSUCCESSFUL;
  9692. return( FALSE );
  9693. }
  9694. /*
  9695. * Do some buffer validation
  9696. */
  9697. *pResult = IsZeroterminateStringW(pUserName, UserNameSize );
  9698. if (*pResult != STATUS_SUCCESS) {
  9699. return FALSE;
  9700. }
  9701. *pResult = IsZeroterminateStringW(pDomain, DomainSize );
  9702. if (*pResult != STATUS_SUCCESS) {
  9703. return FALSE;
  9704. }
  9705. /*
  9706. * Make sure the caller is SYSTEM (WinLogon)
  9707. */
  9708. Status = RpcCheckSystemClient( ClientLogonId );
  9709. if ( !NT_SUCCESS( Status ) ) {
  9710. *pResult = Status;
  9711. return( FALSE );
  9712. }
  9713. *pResult = WinStationFUSCanRemoteUserDisconnectWorker(
  9714. TargetLogonId,
  9715. ClientLogonId,
  9716. ClientProcessId,
  9717. pDomain,
  9718. DomainSize,
  9719. pUserName,
  9720. UserNameSize
  9721. );
  9722. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  9723. }
  9724. /*****************************************************************************
  9725. * WinStationFUSCanRemoteUserDisconnectWorker
  9726. *
  9727. * Worker function for WinStationFUSCanRemoteUserDisconnect
  9728. ****************************************************************************/
  9729. NTSTATUS WinStationFUSCanRemoteUserDisconnectWorker(
  9730. DWORD TargetLogonId,
  9731. DWORD ClientLogonId,
  9732. ULONG_PTR ClientProcessId,
  9733. PWCHAR pDomain,
  9734. DWORD DomainSize,
  9735. PWCHAR pUserName,
  9736. DWORD UserNameSize)
  9737. {
  9738. PWINSTATION pTargetWinStation, pClientWinStation;
  9739. ULONG Length;
  9740. NTSTATUS Status = STATUS_SUCCESS;
  9741. NTSTATUS MessageDelieveryStatus;
  9742. WINSTATION_APIMSG msg;
  9743. ULONG DisconnectResponse;
  9744. OBJECT_ATTRIBUTES ObjA;
  9745. WCHAR *szDomain = NULL;
  9746. WCHAR *szUserName = NULL;
  9747. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationFUSCanRemoteUserDisconnect, LogonId=%d\n", ClientLogonId ));
  9748. if ( ShutdownInProgress ) {
  9749. return ( STATUS_CTX_WINSTATION_ACCESS_DENIED );
  9750. }
  9751. /*
  9752. * Find and lock client WinStation
  9753. */
  9754. pClientWinStation = FindWinStationById( ClientLogonId, FALSE );
  9755. if ( pClientWinStation == NULL ) {
  9756. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  9757. goto done;
  9758. }
  9759. /*
  9760. * Do not do anything if the session is not connected. The processing in this API assumes we are connected and have a
  9761. * valid stack.
  9762. */
  9763. if ((ClientLogonId != 0) && ((pClientWinStation->State != State_Connected) || pClientWinStation->StateFlags & WSF_ST_IN_DISCONNECT)) {
  9764. Status = STATUS_CTX_CLOSE_PENDING;
  9765. ReleaseWinStation(pClientWinStation);
  9766. goto done;
  9767. }
  9768. /*
  9769. * Upper level code has verified that this RPC
  9770. * is coming from a local client with SYSTEM access.
  9771. *
  9772. * We should be able to trust the ClientProcessId from
  9773. * SYSTEM code.
  9774. */
  9775. /*
  9776. * Ensure this is WinLogon calling
  9777. */
  9778. if ( (HANDLE)(ULONG_PTR)ClientProcessId != pClientWinStation->InitialCommandProcessId ) {
  9779. ReleaseWinStation(pClientWinStation);
  9780. goto done;
  9781. }
  9782. /*
  9783. * Client WinStation is not needed anymore, so release that lock
  9784. */
  9785. ReleaseWinStation(pClientWinStation);
  9786. /*
  9787. * Find and lock target WinStation
  9788. */
  9789. pTargetWinStation = FindWinStationById( TargetLogonId, FALSE );
  9790. if ( pTargetWinStation == NULL ) {
  9791. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  9792. goto done;
  9793. }
  9794. // Allocate the strings needed to display the Popup MessageBox
  9795. if ((szDomain = LocalAlloc(LMEM_FIXED, MAX_STRING_BYTES * sizeof(WCHAR))) == NULL) {
  9796. Status = STATUS_NO_MEMORY ;
  9797. goto done;
  9798. }
  9799. if ((szUserName = LocalAlloc(LMEM_FIXED, MAX_STRING_BYTES * sizeof(WCHAR))) == NULL) {
  9800. Status = STATUS_NO_MEMORY ;
  9801. goto done;
  9802. }
  9803. memcpy(szDomain, pDomain, (DomainSize) * sizeof(WCHAR));
  9804. szDomain[DomainSize] = L'\0';
  9805. memcpy(szUserName, pUserName, (UserNameSize) * sizeof(WCHAR));
  9806. szUserName[UserNameSize] = L'\0';
  9807. /*
  9808. * Create wait event
  9809. */
  9810. InitializeObjectAttributes( &ObjA, NULL, 0, NULL, NULL );
  9811. Status = NtCreateEvent( &msg.u.LoadStringMessage.hEvent, EVENT_ALL_ACCESS, &ObjA,
  9812. NotificationEvent, FALSE );
  9813. if ( !NT_SUCCESS(Status) ) {
  9814. ReleaseWinStation(pTargetWinStation);
  9815. goto done;
  9816. }
  9817. /*
  9818. * Send message and wait for reply
  9819. */
  9820. msg.u.LoadStringMessage.TitleId = REMOTE_DISCONNECT_TITLE_ID;
  9821. msg.u.LoadStringMessage.MessageId = REMOTE_DISCONNECT_MESSAGE_ID;
  9822. msg.u.LoadStringMessage.Style = MB_YESNO | MB_DEFBUTTON1 | MB_ICONQUESTION;
  9823. msg.u.LoadStringMessage.Timeout = 20;
  9824. msg.u.LoadStringMessage.DoNotWait = FALSE;
  9825. msg.u.LoadStringMessage.pResponse = &DisconnectResponse;
  9826. msg.u.LoadStringMessage.pDomain = szDomain;
  9827. msg.u.LoadStringMessage.DomainSize = (ULONG) (DomainSize * sizeof(WCHAR));
  9828. msg.u.LoadStringMessage.pUserName = szUserName;
  9829. msg.u.LoadStringMessage.UserNameSize = (ULONG)(UserNameSize * sizeof(WCHAR));
  9830. msg.u.LoadStringMessage.pStatus = &MessageDelieveryStatus;
  9831. msg.ApiNumber = SMWinStationDoLoadStringNMessage;
  9832. /*
  9833. * Initialize response to IDTIMEOUT
  9834. */
  9835. DisconnectResponse = IDTIMEOUT;
  9836. /*
  9837. * Tell the WinStation to display the message box
  9838. */
  9839. Status = SendWinStationCommand( pTargetWinStation, &msg, 0 );
  9840. /*
  9841. * Wait for response
  9842. */
  9843. if ( Status == STATUS_SUCCESS ) {
  9844. TRACE((hTrace,TC_ICASRV,TT_API1, "WinStationSendMessage: wait for response\n" ));
  9845. UnlockWinStation( pTargetWinStation );
  9846. Status = NtWaitForSingleObject( msg.u.LoadStringMessage.hEvent, FALSE, NULL );
  9847. if ( !RelockWinStation( pTargetWinStation ) ) {
  9848. Status = STATUS_CTX_CLOSE_PENDING;
  9849. }
  9850. else {
  9851. Status = MessageDelieveryStatus;
  9852. }
  9853. TRACE((hTrace,TC_ICASRV,TT_API1, "WinStationSendMessage: got response %u\n", DisconnectResponse ));
  9854. NtClose( msg.u.LoadStringMessage.hEvent );
  9855. } else {
  9856. /* close the event in case of SendWinStationCommand failure */
  9857. NtClose( msg.u.LoadStringMessage.hEvent );
  9858. }
  9859. if (Status == STATUS_SUCCESS && DisconnectResponse == IDNO) {
  9860. Status = STATUS_CTX_WINSTATION_ACCESS_DENIED;
  9861. }
  9862. /*
  9863. * Release the target winstation lock
  9864. */
  9865. ReleaseWinStation( pTargetWinStation );
  9866. done:
  9867. /*
  9868. * Do some memory cleanup
  9869. */
  9870. if (szDomain != NULL) {
  9871. LocalFree(szDomain);
  9872. szDomain = NULL;
  9873. }
  9874. if (szUserName != NULL) {
  9875. LocalFree(szUserName);
  9876. szUserName = NULL;
  9877. }
  9878. /*
  9879. * Save return status in API message
  9880. */
  9881. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationFUSCanRemoteUserDisconnectWorker, Status=0x%x\n", Status ));
  9882. return Status;
  9883. }
  9884. /*++
  9885. RPCWinStationCheckLoopBack checks for loopback during connections. This API
  9886. is called from Winlogon.
  9887. Parameters:
  9888. ClientSessionId : Session ID from where the TS Client was started
  9889. TargetLogonId : Session ID to which we are trying to connect
  9890. pTargetServerName : Name of the Server we are trying to connect to
  9891. Returns:
  9892. TRUE if there is a loopBack, FALSE otherwise
  9893. --*/
  9894. BOOLEAN
  9895. RpcWinStationCheckLoopBack(
  9896. HANDLE hServer,
  9897. DWORD *pResult,
  9898. DWORD ClientSessionId,
  9899. DWORD TargetLogonId,
  9900. PWCHAR pTargetServerName,
  9901. DWORD NameSize
  9902. )
  9903. {
  9904. NTSTATUS Status;
  9905. if(!hServer)
  9906. {
  9907. *pResult = STATUS_UNSUCCESSFUL;
  9908. return( FALSE );
  9909. }
  9910. /*
  9911. * Do some buffer validation
  9912. */
  9913. *pResult = IsZeroterminateStringW(pTargetServerName, NameSize );
  9914. if (*pResult != STATUS_SUCCESS) {
  9915. return FALSE;
  9916. }
  9917. *pResult = WinStationCheckLoopBackWorker(
  9918. TargetLogonId,
  9919. ClientSessionId,
  9920. pTargetServerName,
  9921. NameSize
  9922. );
  9923. // NOTE - If Worker function returns STATUS_SUCCESS that means there is no loopback, so return FALSE
  9924. return( *pResult == STATUS_SUCCESS ? FALSE : TRUE );
  9925. }
  9926. /*****************************************************************************
  9927. * WinStationCheckLoopBackWorker
  9928. *
  9929. * Worker function for RPCWinStationCheckLoopBack
  9930. ****************************************************************************/
  9931. NTSTATUS WinStationCheckLoopBackWorker(
  9932. DWORD TargetLogonId,
  9933. DWORD ClientSessionId,
  9934. PWCHAR pTargetServerName,
  9935. DWORD NameSize)
  9936. {
  9937. PWINSTATION pWinStation;
  9938. ULONG Length;
  9939. NTSTATUS Status = STATUS_SUCCESS;
  9940. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationCheckLoopBackWorker, ClientSessionId=%d, TargetLogonId = %d\n", ClientSessionId, TargetLogonId ));
  9941. if ( ShutdownInProgress ) {
  9942. return ( STATUS_CTX_WINSTATION_ACCESS_DENIED );
  9943. }
  9944. // Do the actual processing to call the CheckLoopBack routine here
  9945. // Use the _CheckShadowLoop function which already detects for a loop during Shadowing
  9946. Status = _CheckShadowLoop(ClientSessionId, pTargetServerName, TargetLogonId);
  9947. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationCheckLoopBackWorker, Status=0x%x\n", Status ));
  9948. return Status;
  9949. }
  9950. /*******************************************************************************
  9951. * RpcConnectCallBack
  9952. *
  9953. * Initiate connect back to TS client. For Whistler, this is Salem only call.
  9954. *
  9955. *
  9956. * Returns :
  9957. * TRUE --
  9958. * FALSE -- The operation failed. Extended error status is available
  9959. * using GetLastError.
  9960. ******************************************************************************/
  9961. BOOLEAN
  9962. RpcConnectCallback(
  9963. HANDLE hServer, // needed?
  9964. DWORD *pResult,
  9965. DWORD Timeout,
  9966. ULONG AddressType, // should be one of the TDI_ADDRESS_TYPE_XXX
  9967. PBYTE pAddress, // should be one of the TDI_ADDRESS_XXX
  9968. ULONG AddressLength
  9969. )
  9970. {
  9971. NTSTATUS Status;
  9972. RPC_STATUS RpcStatus;
  9973. ICA_STACK_ADDRESS StackAddress;
  9974. PICA_STACK_ADDRESS pStackAddress = &StackAddress;
  9975. PTDI_ADDRESS_IP pTargetIpAddress;
  9976. if(!hServer)
  9977. {
  9978. *pResult = STATUS_UNSUCCESSFUL;
  9979. return( FALSE );
  9980. }
  9981. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: RpcConnectCallBack" ));
  9982. if( ShutdownInProgress )
  9983. {
  9984. *pResult = STATUS_SYSTEM_SHUTDOWN;
  9985. return FALSE;
  9986. }
  9987. //
  9988. // We only support IPV4 address, Need to modify tdtcp.sys to support IPv6
  9989. //
  9990. if( AddressType != TDI_ADDRESS_TYPE_IP )
  9991. {
  9992. *pResult = STATUS_NOT_SUPPORTED;
  9993. return FALSE;
  9994. }
  9995. //
  9996. // Extra checking, making sure we gets everything.
  9997. //
  9998. if( AddressLength != TDI_ADDRESS_LENGTH_IP )
  9999. {
  10000. *pResult = STATUS_INVALID_PARAMETER;
  10001. return FALSE;
  10002. }
  10003. ZeroMemory( &StackAddress , sizeof( ICA_STACK_ADDRESS ) );
  10004. //
  10005. // ??? What other security we want to apply here
  10006. //
  10007. /*
  10008. * Impersonate the client
  10009. */
  10010. RpcStatus = RpcImpersonateClient( NULL );
  10011. if( RpcStatus != RPC_S_OK ) {
  10012. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL, "TERMSRV: RpcWinStationShadowStop: Not impersonating! RpcStatus 0x%x\n",RpcStatus));
  10013. Status = STATUS_CANNOT_IMPERSONATE;
  10014. goto done;
  10015. }
  10016. //
  10017. // For Whistler, this call is Salem rdshost.exe only, rdshost.exe is kick off by helpctr
  10018. // running under system context.
  10019. //
  10020. if( !IsCallerSystem() ) {
  10021. #if DISABLESECURITYCHECKS
  10022. //
  10023. // Private testing only, allowing administrator to make this call.
  10024. //
  10025. if( !IsCallerAdmin() ) {
  10026. RpcRevertToSelf();
  10027. Status = STATUS_ACCESS_DENIED;
  10028. goto done;
  10029. }
  10030. #else
  10031. RpcRevertToSelf();
  10032. Status = STATUS_ACCESS_DENIED;
  10033. goto done;
  10034. #endif
  10035. }
  10036. RpcRevertToSelf();
  10037. //
  10038. // winsta.h, byte 0, 1, family, 2-n address.
  10039. //
  10040. *(PUSHORT)pStackAddress = (USHORT)AddressType;
  10041. if ( AddressLength <= (sizeof(ICA_STACK_ADDRESS) - 2) ) {
  10042. //
  10043. // Refer to TDI_ADDRESS_IP, last 8 char is not use.
  10044. // Adding a timeout to pass into TD will require changes to ICA_STACK_ADDRESS
  10045. // too risky for Whister but needed on next.
  10046. //
  10047. pTargetIpAddress = (PTDI_ADDRESS_IP)pAddress;
  10048. RtlCopyMemory( &(pTargetIpAddress->sin_zero[0]), &Timeout, sizeof(Timeout) );
  10049. RtlCopyMemory( &((PCHAR)pStackAddress)[2], pAddress, AddressLength );
  10050. } else {
  10051. Status = STATUS_INVALID_PARAMETER;
  10052. goto done;
  10053. }
  10054. #if DBG
  10055. {
  10056. PULONG pData = (PULONG)pStackAddress;
  10057. PTDI_ADDRESS_IP pIpAddress = (PTDI_ADDRESS_IP)&((PCHAR)pStackAddress)[2];
  10058. DbgPrint(
  10059. "TERMSRV: Connect API: address port %u address 0x%x (%u.%u.%u.%u)\n",
  10060. ntohs(pIpAddress->sin_port),
  10061. pIpAddress->in_addr,
  10062. (pIpAddress->in_addr & 0xff000000) >> 24,
  10063. (pIpAddress->in_addr & 0x00ff0000) >> 16,
  10064. (pIpAddress->in_addr & 0x0000ff00) >> 8,
  10065. (pIpAddress->in_addr & 0x000000ff)
  10066. );
  10067. }
  10068. #endif
  10069. Status = TransferConnectionToIdleWinStation( NULL, // no listen winstation
  10070. NULL, // no Endpoint,
  10071. 0, // EndpointLength,
  10072. &StackAddress );
  10073. done:
  10074. *pResult = Status;
  10075. return( NT_SUCCESS(*pResult) ? TRUE : FALSE );
  10076. }
  10077. //*************************************************************
  10078. //
  10079. // IsGinaVersionCurrent()
  10080. //
  10081. // Purpose: Loads the gina DLL and negotiates the version number
  10082. //
  10083. // Parameters: NONE
  10084. //
  10085. // Return: TRUE if gina is of current version
  10086. // FALSE if version of gina is not current
  10087. // or in case of any error
  10088. //
  10089. //*************************************************************
  10090. BOOL
  10091. IsGinaVersionCurrent()
  10092. {
  10093. HMODULE hGina = NULL;
  10094. LPWSTR wszGinaName = NULL;
  10095. PWLX_NEGOTIATE pWlxNegotiate = NULL;
  10096. DWORD dwGinaLevel = 0;
  10097. BOOL bResult = FALSE;
  10098. wszGinaName = (LPWSTR) LocalAlloc(LPTR,(MAX_PATH+1)*sizeof(WCHAR));
  10099. if(!wszGinaName)
  10100. {
  10101. //
  10102. //Not enough memory
  10103. //
  10104. return FALSE;
  10105. }
  10106. GetProfileStringW(
  10107. L"WINLOGON",
  10108. L"GinaDll",
  10109. L"msgina.dll",
  10110. wszGinaName,
  10111. MAX_PATH);
  10112. if(!_wcsicmp(L"msgina.dll",wszGinaName))
  10113. {
  10114. //
  10115. //If it is "msgina.dll",
  10116. //assume that it is a Windows native gina.
  10117. //
  10118. LocalFree(wszGinaName);
  10119. return TRUE;
  10120. }
  10121. //
  10122. //Load gina
  10123. //if we cannot load gina, assume that it is incompatible
  10124. //with TS
  10125. //
  10126. hGina = LoadLibraryW(wszGinaName);
  10127. if (hGina)
  10128. {
  10129. //
  10130. // Get the "WlxNegotiate" function pointer
  10131. //
  10132. pWlxNegotiate = (PWLX_NEGOTIATE) GetProcAddress(hGina, WLX_NEGOTIATE_NAME);
  10133. if (pWlxNegotiate)
  10134. {
  10135. //
  10136. // Negotiate a version number with the gina
  10137. //
  10138. if ( pWlxNegotiate(WLX_CURRENT_VERSION, &dwGinaLevel) &&
  10139. (dwGinaLevel == WLX_CURRENT_VERSION) )
  10140. {
  10141. bResult = TRUE;
  10142. }
  10143. }
  10144. FreeLibrary(hGina);
  10145. }
  10146. LocalFree(wszGinaName);
  10147. return bResult;
  10148. }
  10149. /*++
  10150. RPCWinStationNotifyDisconnectPipe notifies session 0 Winlogon to disconnect from the autologon named pipe
  10151. Parameters:
  10152. ClientSessionId : Session ID of the calling process
  10153. ClientProcessId : Process ID of the calling process
  10154. Returns:
  10155. TRUE if notification is successful, FALSE otherwise
  10156. --*/
  10157. BOOLEAN
  10158. RpcWinStationNotifyDisconnectPipe(
  10159. HANDLE hServer,
  10160. DWORD *pResult,
  10161. DWORD ClientLogonId,
  10162. ULONG_PTR ClientProcessId
  10163. )
  10164. {
  10165. NTSTATUS Status;
  10166. if(!hServer)
  10167. {
  10168. *pResult = STATUS_UNSUCCESSFUL;
  10169. return( FALSE );
  10170. }
  10171. /*
  10172. * Make sure the caller is SYSTEM (WinLogon)
  10173. */
  10174. Status = RpcCheckSystemClient( ClientLogonId );
  10175. if ( !NT_SUCCESS( Status ) ) {
  10176. *pResult = Status;
  10177. return( FALSE );
  10178. }
  10179. *pResult = WinStationNotifyDisconnectPipeWorker(
  10180. ClientLogonId,
  10181. ClientProcessId
  10182. );
  10183. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  10184. }
  10185. /*****************************************************************************
  10186. * WinStationNotifyDisconnectPipeWorker
  10187. *
  10188. * Worker function for RpcWinstationNotifyDisconnectPipe
  10189. ****************************************************************************/
  10190. NTSTATUS WinStationNotifyDisconnectPipeWorker(
  10191. DWORD ClientLogonId,
  10192. ULONG_PTR ClientProcessId
  10193. )
  10194. {
  10195. PWINSTATION pWinStation, pTargetWinStation;
  10196. ULONG Length;
  10197. NTSTATUS Status = STATUS_SUCCESS;
  10198. WINSTATION_APIMSG DisconnectPipeMsg;
  10199. DWORD SessionZeroLogonId = 0;
  10200. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationNotifyDisconnectPipeWorker, ClientLogonId=%d \n", ClientLogonId));
  10201. if ( ShutdownInProgress ) {
  10202. return ( STATUS_CTX_WINSTATION_ACCESS_DENIED );
  10203. }
  10204. /*
  10205. * Find and lock client WinStation
  10206. */
  10207. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  10208. if ( pWinStation == NULL ) {
  10209. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  10210. goto done;
  10211. }
  10212. /*
  10213. * Upper level code has verified that this RPC
  10214. * is coming from a local client with SYSTEM access.
  10215. *
  10216. * We should be able to trust the ClientProcessId from
  10217. * SYSTEM code.
  10218. */
  10219. /*
  10220. * Ensure this is WinLogon calling
  10221. */
  10222. if ( (HANDLE)(ULONG_PTR)ClientProcessId != pWinStation->InitialCommandProcessId ) {
  10223. Status = STATUS_ACCESS_DENIED;
  10224. ReleaseWinStation( pWinStation );
  10225. goto done;
  10226. }
  10227. ReleaseWinStation(pWinStation);
  10228. /*
  10229. * Send the Notification to disconnect the autologon Pipe to Winlogon in session 0
  10230. */
  10231. pTargetWinStation = FindWinStationById( SessionZeroLogonId, FALSE );
  10232. if ( pTargetWinStation == NULL ) {
  10233. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  10234. goto done;
  10235. }
  10236. DisconnectPipeMsg.ApiNumber = SMWinStationNotify;
  10237. DisconnectPipeMsg.WaitForReply = FALSE;
  10238. DisconnectPipeMsg.u.DoNotify.NotifyEvent = WinStation_Notify_DisconnectPipe;
  10239. Status = SendWinStationCommand( pTargetWinStation, &DisconnectPipeMsg, 0 );
  10240. /*
  10241. * Release the winstation lock
  10242. */
  10243. ReleaseWinStation( pTargetWinStation );
  10244. done:
  10245. /*
  10246. * Save return status in API message
  10247. */
  10248. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinstationNotifyDisconnectPipeWorker, Status=0x%x\n", Status ));
  10249. return Status;
  10250. }
  10251. /*++
  10252. RpcWinstationSessionInitialized informs termsrv that winlogon has created the window station and desktop for this session
  10253. Parameters:
  10254. ClientSessionId : Session ID of the calling process
  10255. ClientProcessId : Process ID of the calling process
  10256. Returns:
  10257. TRUE if everything went well. FALSE otherwise
  10258. --*/
  10259. BOOLEAN
  10260. RpcWinStationSessionInitialized(
  10261. HANDLE hServer,
  10262. DWORD *pResult,
  10263. DWORD ClientLogonId,
  10264. ULONG_PTR ClientProcessId
  10265. )
  10266. {
  10267. NTSTATUS Status;
  10268. if(!hServer)
  10269. {
  10270. *pResult = STATUS_UNSUCCESSFUL;
  10271. return( FALSE );
  10272. }
  10273. /*
  10274. * Make sure the caller is SYSTEM (WinLogon)
  10275. */
  10276. Status = RpcCheckSystemClient( ClientLogonId );
  10277. if ( !NT_SUCCESS( Status ) ) {
  10278. *pResult = Status;
  10279. return( FALSE );
  10280. }
  10281. *pResult = WinStationSessionInitializedWorker(
  10282. ClientLogonId,
  10283. ClientProcessId
  10284. );
  10285. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  10286. }
  10287. /*****************************************************************************
  10288. * WinStationSessionInitializedWorker
  10289. *
  10290. * Worker function for RpcWinstationSessionInitialized
  10291. ****************************************************************************/
  10292. NTSTATUS WinStationSessionInitializedWorker(
  10293. DWORD ClientLogonId,
  10294. ULONG_PTR ClientProcessId
  10295. )
  10296. {
  10297. PWINSTATION pWinStation;
  10298. NTSTATUS Status = STATUS_SUCCESS;
  10299. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationSessionInitializedWorker, ClientLogonId=%d \n", ClientLogonId));
  10300. if ( ShutdownInProgress ) {
  10301. return ( STATUS_CTX_WINSTATION_ACCESS_DENIED );
  10302. }
  10303. /*
  10304. * Find and lock client WinStation
  10305. */
  10306. pWinStation = FindWinStationById( ClientLogonId, FALSE );
  10307. if ( pWinStation == NULL ) {
  10308. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  10309. goto done;
  10310. }
  10311. /*
  10312. * Ensure this is WinLogon calling
  10313. */
  10314. if ( (HANDLE)(ULONG_PTR)ClientProcessId != pWinStation->InitialCommandProcessId ) {
  10315. Status = STATUS_ACCESS_DENIED;
  10316. ReleaseWinStation( pWinStation );
  10317. goto done;
  10318. }
  10319. // Set the Event to indicate Session is initialized
  10320. if (pWinStation->SessionInitializedEvent) {
  10321. SetEvent(pWinStation->SessionInitializedEvent);
  10322. }
  10323. ReleaseWinStation(pWinStation);
  10324. done:
  10325. /*
  10326. * Save return status in API message
  10327. */
  10328. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinstationSessionInitializedWorker, Status=0x%x\n", Status ));
  10329. return Status;
  10330. }
  10331. /*******************************************************************************
  10332. * RpcWinStationAutoReconnect
  10333. *
  10334. * Does atomic autoreconnection policy work
  10335. *
  10336. * ENTRY:
  10337. * IN hServer - RPC caller handle - API restricted to local use
  10338. * OUT pResult - Result code in NTSTATUS format with information class set
  10339. * IN LogonId - Session to autoreconnect
  10340. * IN flags - extra options (currently unused)
  10341. *
  10342. * EXIT:
  10343. * STATUS_SUCCESS - if we successfully autoreconnected
  10344. * STATUS_CTX_WINSTATION_BUSY - if session is already disconnected, or busy
  10345. * STATUS_ACCESS_DENIED - if the target winstation was not found
  10346. * or if the autoreconnection check failed
  10347. * STATUS_NOT_FOUND - autoreconnect info was not specified
  10348. ******************************************************************************/
  10349. BOOLEAN
  10350. RpcWinStationAutoReconnect(
  10351. SERVER_HANDLE hServer,
  10352. DWORD *pResult,
  10353. DWORD LogonId,
  10354. DWORD flags
  10355. )
  10356. {
  10357. RPC_STATUS RpcStatus;
  10358. UINT LocalFlag = 0;
  10359. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  10360. PWINSTATION pSourceWinStation = NULL;
  10361. PWINSTATION pTargetWinStation = NULL;
  10362. TS_AUTORECONNECTINFO autoReconnectInfo;
  10363. BYTE abClientRandom[512];
  10364. LONG cbClientRandomLen = 0;
  10365. ULONG BytesGot = 0;
  10366. DWORD SourceID;
  10367. DWORD TargetID;
  10368. if(!hServer)
  10369. {
  10370. *pResult = STATUS_UNSUCCESSFUL;
  10371. return( FALSE );
  10372. }
  10373. TRACE((hTrace,TC_ICASRV,TT_API2,"RPC RpcWinStationAutoReconnect for %d\n",
  10374. LogonId));
  10375. //
  10376. // Only allow system caller for security reasons
  10377. //
  10378. RpcStatus = RpcImpersonateClient(NULL);
  10379. if (RpcStatus != RPC_S_OK) {
  10380. Status = STATUS_UNSUCCESSFUL;
  10381. goto rpcaccessdenied;
  10382. }
  10383. //
  10384. // Check for System caller
  10385. //
  10386. if (!IsCallerSystem()) {
  10387. RpcRevertToSelf();
  10388. Status = STATUS_ACCESS_DENIED;
  10389. goto rpcaccessdenied;
  10390. }
  10391. RpcRevertToSelf();
  10392. //
  10393. // Only allow local access for security reasons
  10394. //
  10395. RpcStatus = I_RpcBindingIsClientLocal(
  10396. 0, // Active RPC call we are servicing
  10397. &LocalFlag
  10398. );
  10399. if( RpcStatus != RPC_S_OK ) {
  10400. KdPrintEx((DPFLTR_TERMSRV_ID, DPFLTR_ERROR_LEVEL,
  10401. "TERMSRV: RpcWinStationAutoReconnect:" \
  10402. "I_RpcBindingIsClientLocal() failed: 0x%x\n", RpcStatus));
  10403. Status = STATUS_UNSUCCESSFUL;
  10404. goto rpcaccessdenied;
  10405. }
  10406. //
  10407. // Do the check for local access
  10408. //
  10409. if (!LocalFlag) {
  10410. Status = (DWORD)STATUS_INVALID_PARAMETER;
  10411. goto rpcaccessdenied;
  10412. }
  10413. pSourceWinStation = FindWinStationById( LogonId, FALSE);
  10414. if (pSourceWinStation == NULL) {
  10415. TRACE((hTrace,TC_ICASRV,TT_ERROR,
  10416. "RpcWinStationAutoReconnect source session not found: %d\n",
  10417. LogonId));
  10418. Status = STATUS_ACCESS_DENIED;
  10419. goto badconnectsource;
  10420. }
  10421. if (pSourceWinStation->Terminating ||
  10422. pSourceWinStation->StateFlags & WSF_ST_WINSTATIONTERMINATE ||
  10423. !pSourceWinStation->WinStationName[0]) {
  10424. TRACE((hTrace,TC_ICASRV,TT_ERROR,
  10425. "RpcWinStationAutoReconnect source session disconnected %d\n",
  10426. LogonId));
  10427. Status = STATUS_ACCESS_DENIED;
  10428. goto badconnectsource;
  10429. }
  10430. if (pSourceWinStation->Flags) {
  10431. Status = STATUS_CTX_WINSTATION_BUSY;
  10432. goto badconnectsource;
  10433. }
  10434. //
  10435. // Check if Winstation logons are disabled and prevent ARC from
  10436. // happening in this case. Bug#532238
  10437. //
  10438. if (GetProfileInt(APPLICATION_NAME, WINSTATIONS_DISABLED, 0) == 1) {
  10439. //
  10440. // Fail the ARC and tell the client
  10441. //
  10442. Status = STATUS_ACCESS_DENIED;
  10443. pSourceWinStation->pWsx->pWsxSendAutoReconnectStatus(
  10444. pSourceWinStation->pWsxContext,
  10445. 0,
  10446. FALSE); //stack lock held
  10447. ReleaseWinStation(pSourceWinStation);
  10448. pSourceWinStation = NULL;
  10449. goto done;
  10450. }
  10451. //
  10452. // Get the client autoreconnect info
  10453. //
  10454. if (pSourceWinStation->pWsx &&
  10455. pSourceWinStation->pWsx->pWsxEscape) {
  10456. Status = pSourceWinStation->pWsx->pWsxEscape(
  10457. pSourceWinStation->pWsxContext,
  10458. GET_CS_AUTORECONNECT_INFO,
  10459. NULL,
  10460. 0,
  10461. &autoReconnectInfo,
  10462. sizeof(autoReconnectInfo),
  10463. &BytesGot);
  10464. }
  10465. TRACE((hTrace,TC_ICASRV,TT_API3,
  10466. "RpcWinStationAutoReconnect get GET_CS_AUTORECONNECT_INFO: 0x%x\n",
  10467. Status));
  10468. if (0 == BytesGot ) {
  10469. //
  10470. // Skip the rest of the processing if we didn't get any arc info
  10471. //
  10472. //
  10473. // This is not strictly an error condition, the client could have
  10474. // just not sent up any autoreconnect info
  10475. //
  10476. Status = STATUS_NOT_FOUND;
  10477. goto badconnectsource;
  10478. }
  10479. //
  10480. // Get the client random
  10481. //
  10482. if (NT_SUCCESS(Status)) {
  10483. if (pSourceWinStation->pWsx &&
  10484. pSourceWinStation->pWsx->pWsxEscape) {
  10485. Status = pSourceWinStation->pWsx->pWsxEscape(
  10486. pSourceWinStation->pWsxContext,
  10487. GET_CLIENT_RANDOM,
  10488. NULL,
  10489. 0,
  10490. &abClientRandom,
  10491. sizeof(abClientRandom),
  10492. &BytesGot);
  10493. TRACE((hTrace,TC_ICASRV,TT_API3,
  10494. "RpcWinStationAutoReconnect get GET_CLIENT_RANDOM: 0x%x\n",
  10495. Status));
  10496. }
  10497. }
  10498. //
  10499. // Source winstation locked here
  10500. // Target not set yet
  10501. //
  10502. if (NT_SUCCESS(Status)) {
  10503. cbClientRandomLen = BytesGot;
  10504. //
  10505. // Flag the winstation as part of the autoreconnection
  10506. // to prevent a race where it might be reconnected somewhere
  10507. // else while we unlock it
  10508. //
  10509. pSourceWinStation->Flags |= WSF_AUTORECONNECTING;
  10510. SourceID = pSourceWinStation->LogonId;
  10511. //
  10512. // Unlock the winstation because we are about to try to
  10513. // lock the target winstation
  10514. //
  10515. UnlockWinStation(pSourceWinStation);
  10516. //
  10517. // Use the autoreconnect info to find the target winstation
  10518. // Returns a LOCKED winstation on success
  10519. //
  10520. pTargetWinStation = GetWinStationFromArcInfo(
  10521. (PBYTE)abClientRandom,
  10522. cbClientRandomLen,
  10523. (PTS_AUTORECONNECTINFO)&autoReconnectInfo
  10524. );
  10525. if (pTargetWinStation) {
  10526. //
  10527. // Check if the target is busy or if AutoReconnect is disallowed
  10528. //
  10529. if (pTargetWinStation->Flags || pTargetWinStation->fDisallowAutoReconnect) {
  10530. if (pTargetWinStation->fDisallowAutoReconnect) {
  10531. Status = STATUS_ACCESS_DENIED;
  10532. } else {
  10533. Status = STATUS_CTX_WINSTATION_BUSY;
  10534. }
  10535. ReleaseWinStation(pTargetWinStation);
  10536. pTargetWinStation = NULL;
  10537. RelockWinStation(pSourceWinStation);
  10538. //
  10539. // Tell the client that ARC failed
  10540. //
  10541. if (pSourceWinStation->pWsx &&
  10542. pSourceWinStation->pWsx->pWsxSendAutoReconnectStatus) {
  10543. pSourceWinStation->pWsx->pWsxSendAutoReconnectStatus(
  10544. pSourceWinStation->pWsxContext,
  10545. 0,
  10546. FALSE); //stack lock held
  10547. }
  10548. pSourceWinStation->Flags &= ~WSF_AUTORECONNECTING;
  10549. ReleaseWinStation(pSourceWinStation);
  10550. goto done;
  10551. }
  10552. //
  10553. // Success! We found a winstation to autoreconnect to
  10554. // flag it and unlock it so we can make the connect call
  10555. //
  10556. TargetID = pTargetWinStation->LogonId;
  10557. pTargetWinStation->Flags |= WSF_AUTORECONNECTING;
  10558. UnlockWinStation(pTargetWinStation);
  10559. }
  10560. else {
  10561. TRACE((hTrace,TC_ICASRV,TT_ERROR,
  10562. "TERMSRV: GetWinStationFromArcInfo failed\n"));
  10563. //
  10564. // Relock the source and cancel the autoreconnect flag
  10565. //
  10566. if (RelockWinStation(pSourceWinStation)) {
  10567. //
  10568. // Tell the client that ARC failed
  10569. //
  10570. if (pSourceWinStation->pWsx &&
  10571. pSourceWinStation->pWsx->pWsxSendAutoReconnectStatus) {
  10572. Status = pSourceWinStation->pWsx->pWsxSendAutoReconnectStatus(
  10573. pSourceWinStation->pWsxContext,
  10574. 0,
  10575. FALSE); //stack lock held
  10576. }
  10577. }
  10578. else {
  10579. //
  10580. // This is a failure path anyway so it doesn't
  10581. // matter if the winstation was deleted. It just means
  10582. // we can't send status to the client
  10583. //
  10584. }
  10585. pSourceWinStation->Flags &= ~WSF_AUTORECONNECTING;
  10586. ReleaseWinStation(pSourceWinStation);
  10587. pSourceWinStation = NULL;
  10588. Status = STATUS_ACCESS_DENIED;
  10589. goto done;
  10590. }
  10591. }
  10592. else {
  10593. goto badconnectsource;
  10594. }
  10595. //
  10596. // At this point neither winstation is locked
  10597. //
  10598. if (NT_SUCCESS(Status)) {
  10599. ASSERT(pTargetWinStation);
  10600. //
  10601. // Trigger an autoreconnection from Source->Target
  10602. //
  10603. TRACE((hTrace,TC_ICASRV,TT_API1,
  10604. "RpcWinStationAutoReconnect doing ARC from %d to %d\n",
  10605. SourceID, TargetID));
  10606. //
  10607. // Do the reconnection
  10608. //
  10609. // The autoreconnect flag allows the connect worker to properly
  10610. // handle the WSF_AUTORECONNECTING flag whose purpose is to
  10611. // prevent a race where the sessions could be reconnected while
  10612. // the winstations are unlocked
  10613. //
  10614. Status = WinStationConnectWorker(
  10615. LOGONID_CURRENT,
  10616. TargetID,
  10617. SourceID,
  10618. NULL,
  10619. 0,
  10620. TRUE,
  10621. TRUE //flag that this is an autoreconnection
  10622. );
  10623. //
  10624. // Relock and then release the source
  10625. //
  10626. if (!RelockWinStation(pSourceWinStation)) {
  10627. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  10628. }
  10629. pSourceWinStation->Flags &= ~WSF_AUTORECONNECTING;
  10630. ReleaseWinStation(pSourceWinStation);
  10631. pSourceWinStation = NULL;
  10632. //
  10633. // Relock and then release the target
  10634. //
  10635. if (!RelockWinStation(pTargetWinStation)) {
  10636. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  10637. }
  10638. pTargetWinStation->Flags &= ~WSF_AUTORECONNECTING;
  10639. ReleaseWinStation(pTargetWinStation);
  10640. pTargetWinStation = NULL;
  10641. TRACE((hTrace,TC_ICASRV,TT_API1,
  10642. "RpcWinStationAutoReconnect ARC ConnectWorker result: 0x%x\n",
  10643. Status));
  10644. if (NT_SUCCESS(Status)) {
  10645. //
  10646. // Call succeeded AND we autoreconnected
  10647. //
  10648. TRACE((hTrace,TC_ICASRV,TT_API1,
  10649. "RpcWinStationAutoReconnect ARC Succeeded\n"));
  10650. }
  10651. }
  10652. goto done;
  10653. badconnectsource:
  10654. if (pSourceWinStation) {
  10655. ReleaseWinStation(pSourceWinStation);
  10656. }
  10657. rpcaccessdenied:
  10658. done:
  10659. *pResult = Status;
  10660. return NT_SUCCESS(Status);
  10661. }
  10662. #ifdef DBG
  10663. void PrintClientInfo()
  10664. {
  10665. RPC_STATUS status;
  10666. RPC_CALL_ATTRIBUTES CallAttributes;
  10667. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: -|--------------------------------------------|-\n"));
  10668. memset(&CallAttributes, 0, sizeof(CallAttributes));
  10669. CallAttributes.Version = RPC_CALL_ATTRIBUTES_VERSION;
  10670. CallAttributes.Flags = RPC_QUERY_SERVER_PRINCIPAL_NAME | RPC_QUERY_CLIENT_PRINCIPAL_NAME;
  10671. RpcServerInqCallAttributes(NULL, &CallAttributes);
  10672. if(CallAttributes.ServerPrincipalNameBufferLength)
  10673. {
  10674. CallAttributes.ServerPrincipalName = (WCHAR*)LocalAlloc(LPTR,
  10675. CallAttributes.ServerPrincipalNameBufferLength);
  10676. if(!CallAttributes.ServerPrincipalName)
  10677. {
  10678. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: PrintClientInfo failed - no memory\n"));
  10679. goto done;
  10680. }
  10681. }
  10682. if(CallAttributes.ClientPrincipalNameBufferLength)
  10683. {
  10684. CallAttributes.ClientPrincipalName = (WCHAR*)LocalAlloc(LPTR,
  10685. CallAttributes.ClientPrincipalNameBufferLength);
  10686. if(!CallAttributes.ClientPrincipalName)
  10687. {
  10688. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: PrintClientInfo failed - no memory\n"));
  10689. goto done;
  10690. }
  10691. }
  10692. status = RpcServerInqCallAttributes(NULL, &CallAttributes);
  10693. if(status != RPC_S_OK)
  10694. {
  10695. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: RpcServerInqCallAttributes failed - %d\n", status));
  10696. return ;
  10697. }
  10698. if(CallAttributes.ServerPrincipalName)
  10699. {
  10700. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Server SPN: %ws\n", CallAttributes.ServerPrincipalName));
  10701. }
  10702. if(CallAttributes.ClientPrincipalName)
  10703. {
  10704. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Client SPN: %ws\n", CallAttributes.ClientPrincipalName));
  10705. }
  10706. switch(CallAttributes.AuthenticationLevel)
  10707. {
  10708. case RPC_C_AUTHN_LEVEL_DEFAULT:
  10709. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: RPC_C_AUTHN_LEVEL_DEFAULT\n"));
  10710. break;
  10711. case RPC_C_AUTHN_LEVEL_NONE:
  10712. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: RPC_C_AUTHN_LEVEL_NONE\n"));
  10713. break;
  10714. case RPC_C_AUTHN_LEVEL_CONNECT:
  10715. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: RPC_C_AUTHN_LEVEL_CONNECT\n"));
  10716. break;
  10717. case RPC_C_AUTHN_LEVEL_CALL:
  10718. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: RPC_C_AUTHN_LEVEL_CALL\n"));
  10719. break;
  10720. case RPC_C_AUTHN_LEVEL_PKT:
  10721. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: RPC_C_AUTHN_LEVEL_PKT\n"));
  10722. break;
  10723. case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
  10724. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: RPC_C_AUTHN_LEVEL_PKT_INTEGRITY\n"));
  10725. break;
  10726. case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
  10727. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: RPC_C_AUTHN_LEVEL_PKT_PRIVACY\n"));
  10728. break;
  10729. default:
  10730. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication level: UNKNOWN!!!\n"));
  10731. break;
  10732. }
  10733. switch(CallAttributes.AuthenticationService)
  10734. {
  10735. case RPC_C_AUTHN_NONE:
  10736. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_NONE\n"));
  10737. break;
  10738. case RPC_C_AUTHN_DCE_PRIVATE:
  10739. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_DCE_PRIVATE\n"));
  10740. break;
  10741. case RPC_C_AUTHN_DCE_PUBLIC:
  10742. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_DCE_PUBLIC\n"));
  10743. break;
  10744. case RPC_C_AUTHN_DEC_PUBLIC:
  10745. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_DEC_PUBLIC\n"));
  10746. break;
  10747. case RPC_C_AUTHN_GSS_NEGOTIATE:
  10748. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_GSS_NEGOTIATE\n"));
  10749. break;
  10750. case RPC_C_AUTHN_WINNT:
  10751. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_WINNT\n"));
  10752. break;
  10753. case RPC_C_AUTHN_GSS_SCHANNEL:
  10754. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_GSS_SCHANNEL\n"));
  10755. break;
  10756. case RPC_C_AUTHN_GSS_KERBEROS:
  10757. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_GSS_KERBEROS\n"));
  10758. break;
  10759. case RPC_C_AUTHN_DPA:
  10760. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_DPA\n"));
  10761. break;
  10762. case RPC_C_AUTHN_MSN:
  10763. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_MSN\n"));
  10764. break;
  10765. case RPC_C_AUTHN_DIGEST:
  10766. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_DIGEST\n"));
  10767. break;
  10768. case RPC_C_AUTHN_MQ:
  10769. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_MQ\n"));
  10770. break;
  10771. case RPC_C_AUTHN_DEFAULT:
  10772. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: RPC_C_AUTHN_DEFAULT\n"));
  10773. break;
  10774. default:
  10775. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: Authentication service: UNKNOWN!!!\n"));
  10776. break;
  10777. }
  10778. done:
  10779. if(CallAttributes.ServerPrincipalName)
  10780. {
  10781. LocalFree(CallAttributes.ServerPrincipalName);
  10782. }
  10783. if(CallAttributes.ClientPrincipalName)
  10784. {
  10785. LocalFree(CallAttributes.ClientPrincipalName);
  10786. }
  10787. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: -|--------------------------------------------|-\n"));
  10788. }
  10789. #endif //DBG
  10790. RPC_STATUS __stdcall
  10791. RpcSecurityCallback(
  10792. IN RPC_IF_HANDLE Interface,
  10793. IN void *Context)
  10794. {
  10795. RPC_STATUS status;
  10796. WCHAR *szStringBinding = NULL;
  10797. WCHAR *szProtSeq = NULL;
  10798. RPC_CALL_ATTRIBUTES CallAttributes; // this maps to RPC_CALL_ATTRIBUTES_V1
  10799. BOOL bUsingLPC;
  10800. BOOL bUsingNP;
  10801. #ifdef DBG
  10802. //To enable tracing, set these registry values:
  10803. //HKLM\System\CurrentControlSet\Control\TerminalServer:
  10804. //TraceEnable=(dword)0x8
  10805. //TraceClass=(dword)0x1
  10806. //TraceDebugger=(dword)0x1
  10807. PrintClientInfo();
  10808. #endif //DBG
  10809. status = RpcBindingToStringBinding(Context, &szStringBinding);
  10810. if(status != RPC_S_OK)
  10811. {
  10812. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: RpcBindingToStringBinding failed - %d\n", status));
  10813. return ERROR_ACCESS_DENIED;
  10814. }
  10815. status = RpcStringBindingParse(szStringBinding,
  10816. NULL, &szProtSeq, NULL, NULL, NULL);
  10817. if(status != RPC_S_OK)
  10818. {
  10819. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: RpcStringBindingParse failed - %d\n", status));
  10820. RpcStringFree(&szStringBinding);
  10821. return ERROR_ACCESS_DENIED;
  10822. }
  10823. RpcStringFree(&szStringBinding);
  10824. bUsingLPC = (!_wcsicmp(szProtSeq, L"ncalrpc"));
  10825. bUsingNP = (!_wcsicmp(szProtSeq, L"ncacn_np"));
  10826. if(!bUsingLPC && !bUsingNP)
  10827. {
  10828. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Client is neither using named pipe nor LPC!\n"));
  10829. RpcStringFree(&szProtSeq);
  10830. return ERROR_ACCESS_DENIED;
  10831. }
  10832. RpcStringFree(&szProtSeq);
  10833. memset(&CallAttributes, 0, sizeof(CallAttributes));
  10834. CallAttributes.Version = RPC_CALL_ATTRIBUTES_VERSION;
  10835. CallAttributes.Flags = 0;
  10836. status = RpcServerInqCallAttributes(Context, &CallAttributes);
  10837. if(status == RPC_S_BINDING_HAS_NO_AUTH && !g_MachinePolicy.fEncryptRPCTraffic)
  10838. {
  10839. //User must be authenticated at least on a transport level,
  10840. //even when we are not in "Secure" mode.
  10841. status = RpcImpersonateClient(NULL);
  10842. if(status != RPC_S_OK)
  10843. {
  10844. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Cannot impersonate client: %d\n",status));
  10845. return ERROR_ACCESS_DENIED;
  10846. }
  10847. //No anonymous calls are allowed.
  10848. if(IsCallerAnonymous())
  10849. {
  10850. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Caller is ANONYMOUS!\n"));
  10851. RpcRevertToSelf();
  10852. return ERROR_ACCESS_DENIED;
  10853. }
  10854. RpcRevertToSelf();
  10855. //We are not in "Secure" mode. Nothing more to check out.
  10856. return RPC_S_OK;
  10857. }
  10858. if(status != RPC_S_OK)
  10859. {
  10860. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: RpcServerInqCallAttributes failed - %d\n", status));
  10861. return ERROR_ACCESS_DENIED;
  10862. }
  10863. if(g_MachinePolicy.fEncryptRPCTraffic)
  10864. {
  10865. //Check authentication level only when we in "Secure" mode.
  10866. if(CallAttributes.AuthenticationLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
  10867. {
  10868. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: AuthLevel != RPC_C_AUTHN_LEVEL_PKT_PRIVACY\n"));
  10869. return ERROR_ACCESS_DENIED;
  10870. }
  10871. }
  10872. if(CallAttributes.NullSession != 0)
  10873. {
  10874. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: NULL SESSION!\n"));
  10875. return ERROR_ACCESS_DENIED;
  10876. }
  10877. return RPC_S_OK;
  10878. }
  10879. RPC_STATUS
  10880. RegisterRPCInterface(
  10881. BOOL bReregister)
  10882. {
  10883. RPC_STATUS Status;
  10884. static BOOL bRunSecure = FALSE;
  10885. WCHAR *szDefaultSPN = NULL;
  10886. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: IN RegisterRPCInterface Reregister=%d OldSecure= %d Secure=%d\n",bReregister, bRunSecure, g_MachinePolicy.fEncryptRPCTraffic));
  10887. if(bReregister)
  10888. {
  10889. if( bRunSecure == g_MachinePolicy.fEncryptRPCTraffic )
  10890. {
  10891. return RPC_S_OK;
  10892. }
  10893. }
  10894. else
  10895. {
  10896. Status = RpcServerInqDefaultPrincName(RPC_C_AUTHN_GSS_NEGOTIATE, &szDefaultSPN);
  10897. if( Status != RPC_S_OK )
  10898. {
  10899. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Error %d RpcServerInqDefaultPrincName\n",Status));
  10900. return( Status );
  10901. }
  10902. Status = RpcServerRegisterAuthInfo(
  10903. szDefaultSPN, // service SPN,
  10904. RPC_C_AUTHN_GSS_NEGOTIATE,
  10905. NULL,
  10906. NULL );
  10907. if (szDefaultSPN) {
  10908. RpcStringFree(&szDefaultSPN);
  10909. }
  10910. if( Status != RPC_S_OK )
  10911. {
  10912. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Error %d RpcServerRegisterAuthInfo\n",Status));
  10913. return( Status );
  10914. }
  10915. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: RpcServerRegisterAuthInfo OK!\n"));
  10916. }
  10917. bRunSecure = g_MachinePolicy.fEncryptRPCTraffic;
  10918. // Register our interface handle
  10919. Status = RpcServerRegisterIfEx(
  10920. IcaApi_ServerIfHandle,
  10921. NULL,
  10922. NULL,
  10923. bRunSecure ? RPC_IF_ALLOW_SECURE_ONLY : RPC_IF_ALLOW_CALLBACKS_WITH_NO_AUTH,
  10924. RPC_C_LISTEN_MAX_CALLS_DEFAULT,
  10925. &RpcSecurityCallback);
  10926. if( Status != RPC_S_OK )
  10927. {
  10928. TRACE((hTrace,TC_ICASRV,TT_ERROR,"TERMSRV: Error %d RpcServerRegisterIf\n",Status));
  10929. return( Status );
  10930. }
  10931. TRACE((hTrace,TC_ICASRV,TT_API4,"TERMSRV: RpcServerRegisterIfEx OK!\n"));
  10932. return( Status );
  10933. }
  10934. /*++
  10935. RpcWinStationCheckAccess - find out if a User has a specific access to a WinStation
  10936. Parameters:
  10937. ClientLogonId : Session ID of the calling process
  10938. UserToken : Token of the User whose access needs to be determined
  10939. TargetLogonId : Target Session Id against whom we should verify Access
  10940. AccessMask : Desired Access - eg. WINSTATION_LOGON
  10941. Returns:
  10942. TRUE if User has required Access. FALSE otherwise
  10943. --*/
  10944. BOOLEAN
  10945. RpcWinStationCheckAccess(
  10946. HANDLE hServer,
  10947. DWORD *pResult,
  10948. ULONG ClientLogonId,
  10949. DWORD UserToken,
  10950. ULONG TargetLogonId,
  10951. ULONG AccessMask
  10952. )
  10953. {
  10954. NTSTATUS Status;
  10955. if(!hServer) {
  10956. *pResult = STATUS_UNSUCCESSFUL;
  10957. return( FALSE );
  10958. }
  10959. /*
  10960. * Make sure the caller is SYSTEM
  10961. */
  10962. Status = RpcCheckSystemClient( ClientLogonId );
  10963. if ( !NT_SUCCESS( Status ) ) {
  10964. *pResult = Status;
  10965. return( FALSE );
  10966. }
  10967. *pResult = WinStationCheckAccessWorker(
  10968. ClientLogonId,
  10969. UserToken,
  10970. TargetLogonId,
  10971. AccessMask
  10972. );
  10973. return( *pResult == STATUS_SUCCESS ? TRUE : FALSE );
  10974. }
  10975. /*****************************************************************************
  10976. * WinStationCheckAccessWorker
  10977. *
  10978. * Worker function for RpcWinStationCheckAccess
  10979. ****************************************************************************/
  10980. NTSTATUS WinStationCheckAccessWorker(
  10981. ULONG ClientLogonId,
  10982. DWORD UserToken,
  10983. ULONG TargetLogonId,
  10984. ULONG AccessMask
  10985. )
  10986. {
  10987. PWINSTATION pWinStation, pClientWinStation;
  10988. NTSTATUS Status = STATUS_SUCCESS;
  10989. HANDLE ClientToken, NewToken, ImpersonationToken;
  10990. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  10991. OBJECT_ATTRIBUTES ObjA;
  10992. BOOL bAccessCheckOk = FALSE;
  10993. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationCheckAccessWorker, ClientLogonId=%d \n", ClientLogonId));
  10994. if ( ShutdownInProgress ) {
  10995. return ( STATUS_CTX_WINSTATION_ACCESS_DENIED );
  10996. }
  10997. pClientWinStation = FindWinStationById( ClientLogonId, FALSE );
  10998. if ( pClientWinStation == NULL ) {
  10999. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  11000. goto done;
  11001. }
  11002. /*
  11003. * Get a valid copy of the clients token handle
  11004. */
  11005. Status = NtDuplicateObject( pClientWinStation->InitialCommandProcess,
  11006. (HANDLE)LongToHandle( UserToken ),
  11007. NtCurrentProcess(),
  11008. &ClientToken,
  11009. 0, 0,
  11010. DUPLICATE_SAME_ACCESS |
  11011. DUPLICATE_SAME_ATTRIBUTES );
  11012. if (Status != STATUS_SUCCESS) {
  11013. ReleaseWinStation(pClientWinStation);
  11014. goto done;
  11015. }
  11016. ReleaseWinStation(pClientWinStation);
  11017. /*
  11018. * ClientToken is a primary token - create an impersonation token
  11019. * version of it so we can set it on our thread
  11020. */
  11021. InitializeObjectAttributes( &ObjA, NULL, 0L, NULL, NULL );
  11022. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  11023. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  11024. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  11025. SecurityQualityOfService.EffectiveOnly = FALSE;
  11026. ObjA.SecurityQualityOfService = &SecurityQualityOfService;
  11027. Status = NtDuplicateToken( ClientToken,
  11028. TOKEN_IMPERSONATE,
  11029. &ObjA,
  11030. FALSE,
  11031. TokenImpersonation,
  11032. &ImpersonationToken );
  11033. if (Status != STATUS_SUCCESS) {
  11034. NtClose(ClientToken);
  11035. goto done;
  11036. }
  11037. /*
  11038. * Impersonate the client
  11039. */
  11040. Status = NtSetInformationThread( NtCurrentThread(),
  11041. ThreadImpersonationToken,
  11042. (PVOID)&ImpersonationToken,
  11043. (ULONG)sizeof(HANDLE) );
  11044. if ( Status != STATUS_SUCCESS ) {
  11045. goto CloseTokens;
  11046. }
  11047. /*
  11048. * Find and lock Target WinStation
  11049. */
  11050. pWinStation = FindWinStationById( TargetLogonId, FALSE );
  11051. if ( pWinStation == NULL ) {
  11052. Status = STATUS_CTX_WINSTATION_NOT_FOUND;
  11053. goto CloseTokens;
  11054. }
  11055. Status = RpcCheckClientAccess(pWinStation, AccessMask, TRUE);
  11056. /*
  11057. * Revert back to our threads default token.
  11058. */
  11059. NewToken = NULL;
  11060. NtSetInformationThread( NtCurrentThread(),
  11061. ThreadImpersonationToken,
  11062. (PVOID)&NewToken,
  11063. (ULONG)sizeof(HANDLE) );
  11064. ReleaseWinStation(pWinStation);
  11065. CloseTokens:
  11066. NtClose(ImpersonationToken);
  11067. NtClose(ClientToken);
  11068. done:
  11069. /*
  11070. * Save return status in API message
  11071. */
  11072. TRACE((hTrace,TC_ICASRV,TT_API1, "TERMSRV: WinStationCheckAccess, Status=0x%x\n", Status ));
  11073. return Status;
  11074. }
  11075. /*****************************************************************************
  11076. * RpcWinStationOpenSessionDirectory
  11077. Ping SD to see if it can accept RPC call
  11078. Params:
  11079. hServer: not used
  11080. pszServerName: SD server name
  11081. Return:
  11082. ERROR_SUCCESS if SD can accept RPC call
  11083. otherwise NT error code is returned
  11084. ****************************************************************************/
  11085. BOOLEAN RpcWinStationOpenSessionDirectory(
  11086. HANDLE hServer,
  11087. DWORD *pResult,
  11088. PWCHAR pszServerName)
  11089. {
  11090. RPC_STATUS RpcStatus;
  11091. DWORD SessDirError;
  11092. if(!hServer || !pszServerName || !*pszServerName)
  11093. {
  11094. *pResult = STATUS_INVALID_PARAMETER;
  11095. goto Exit;
  11096. }
  11097. if ( ShutdownInProgress )
  11098. {
  11099. *pResult = STATUS_CTX_WINSTATION_ACCESS_DENIED;
  11100. goto Exit;
  11101. }
  11102. // TS can only participate in session directory if it is in
  11103. // app. server mode and is ADS SKU
  11104. if( g_bPersonalTS || !g_fAppCompat || !g_bAdvancedServer )
  11105. {
  11106. *pResult = STATUS_UNSUCCESSFUL;
  11107. goto Exit;
  11108. }
  11109. // Impersonate client and only allow service and admin to call
  11110. RpcStatus = RpcImpersonateClient( NULL );
  11111. if( RpcStatus != RPC_S_OK )
  11112. {
  11113. *pResult = STATUS_CANNOT_IMPERSONATE;
  11114. goto Exit;
  11115. }
  11116. if ( !(IsCallerSystem() || IsCallerAdmin()) )
  11117. {
  11118. *pResult = STATUS_ACCESS_DENIED;
  11119. RpcRevertToSelf();
  11120. goto Exit;
  11121. }
  11122. RpcRevertToSelf();
  11123. SessDirError = SessDirOpenSessionDirectory( pszServerName );
  11124. *pResult = WinStationWinerrorToNtStatus( SessDirError );
  11125. Exit:
  11126. return(*pResult == STATUS_SUCCESS ? TRUE : FALSE);
  11127. }