Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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