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.

836 lines
26 KiB

  1. /*************************************************************************
  2. *
  3. * winset.c
  4. *
  5. * Window station set APS
  6. *
  7. * Copyright Microsoft Corporation, 1998
  8. *
  9. *
  10. *************************************************************************/
  11. /*
  12. * Includes
  13. */
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include "conntfy.h" // for SetLockedState
  17. /*
  18. * External Procedures
  19. */
  20. NTSTATUS xxxWinStationSetInformation( ULONG, WINSTATIONINFOCLASS,
  21. PVOID, ULONG );
  22. VOID _ReadUserProfile( PWCHAR, PWCHAR, PUSERCONFIG );
  23. extern BOOL IsCallerSystem( VOID );
  24. extern BOOL IsCallerAdmin( VOID );
  25. /*
  26. * Internal Procedures used
  27. */
  28. NTSTATUS _SetConfig( PWINSTATION, PWINSTATIONCONFIG, ULONG );
  29. NTSTATUS _SetPdParams( PWINSTATION, PPDPARAMS, ULONG );
  30. NTSTATUS _SetBeep( PWINSTATION, PBEEPINPUT, ULONG );
  31. NTSTATUS WinStationShadowChangeMode( PWINSTATION, PWINSTATIONSHADOW, ULONG );
  32. NTSTATUS FlushVirtualInput( PWINSTATION, VIRTUALCHANNELCLASS, ULONG );
  33. NTSTATUS
  34. RpcCheckClientAccess(
  35. PWINSTATION pWinStation,
  36. ACCESS_MASK DesiredAccess,
  37. BOOLEAN AlreadyImpersonating
  38. );
  39. NTSTATUS
  40. CheckWireBuffer(WINSTATIONINFOCLASS InfoClass,
  41. PVOID WireBuf,
  42. ULONG WireBufLen,
  43. PVOID *ppLocalBuf,
  44. PULONG pLocalBufLen);
  45. /*
  46. * Global data
  47. */
  48. typedef ULONG_PTR (*PFN)();
  49. HMODULE ghNetApiDll = NULL;
  50. PFN pNetGetAnyDCName = NULL;
  51. PFN pNetApiBufferFree = NULL;
  52. /*
  53. * External data
  54. */
  55. NTSTATUS
  56. _CheckCallerLocalAndSystem()
  57. /*++
  58. Checking caller is calling from local and also is running
  59. under system context
  60. --*/
  61. {
  62. NTSTATUS Status;
  63. BOOL bRevert = FALSE;
  64. UINT LocalFlag;
  65. Status = RpcImpersonateClient( NULL );
  66. if( Status != RPC_S_OK ) {
  67. DBGPRINT((" RpcImpersonateClient() failed : 0x%x\n",Status));
  68. Status = STATUS_CANNOT_IMPERSONATE;
  69. goto CLEANUPANDEXIT;
  70. }
  71. bRevert = TRUE;
  72. //
  73. // Inquire if local RPC call
  74. //
  75. Status = I_RpcBindingIsClientLocal(
  76. 0, // Active RPC call we are servicing
  77. &LocalFlag
  78. );
  79. if( Status != RPC_S_OK ) {
  80. DBGPRINT((" I_RpcBindingIsClientLocal() failed : 0x%x\n",Status));
  81. Status = STATUS_ACCESS_DENIED;
  82. goto CLEANUPANDEXIT;
  83. }
  84. if( !LocalFlag ) {
  85. DBGPRINT((" Not a local client call\n"));
  86. Status = STATUS_ACCESS_DENIED;
  87. goto CLEANUPANDEXIT;
  88. }
  89. Status = (IsCallerSystem()) ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
  90. CLEANUPANDEXIT:
  91. if( TRUE == bRevert ) {
  92. RpcRevertToSelf();
  93. }
  94. return Status;
  95. }
  96. /*******************************************************************************
  97. *
  98. * xxxWinStationSetInformation
  99. *
  100. * set window station information (worker routine)
  101. *
  102. * ENTRY:
  103. * pWinStation (input)
  104. * pointer to citrix window station structure
  105. * WinStationInformationClass (input)
  106. * Specifies the type of information to set at the specified window
  107. * station object.
  108. * pWinStationInformation (input)
  109. * A pointer to a buffer that contains information to set for the
  110. * specified window station. The format and contents of the buffer
  111. * depend on the specified information class being set.
  112. * WinStationInformationLength (input)
  113. * Specifies the length in bytes of the window station information
  114. * buffer.
  115. *
  116. * EXIT:
  117. * STATUS_SUCCESS - no error
  118. *
  119. ******************************************************************************/
  120. NTSTATUS
  121. xxxWinStationSetInformation( ULONG LogonId,
  122. WINSTATIONINFOCLASS WinStationInformationClass,
  123. PVOID pWinStationInformation,
  124. ULONG WinStationInformationLength )
  125. {
  126. NTSTATUS Status = STATUS_SUCCESS;
  127. PWINSTATION pWinStation;
  128. ULONG cbReturned;
  129. WINSTATION_APIMSG msg;
  130. PWINSTATIONCONFIG pConfig;
  131. ULONG ConfigLength;
  132. PPDPARAMS pPdParams;
  133. ULONG PdParamsLength;
  134. RPC_STATUS RpcStatus;
  135. TRACE((hTrace,TC_ICASRV,TT_API2,"TERMSRV: WinStationSetInformation LogonId=%d, Class=%d\n",
  136. LogonId, (ULONG)WinStationInformationClass ));
  137. /*
  138. * Find the WinStation
  139. * Return error if not found or currently terminating.
  140. */
  141. pWinStation = FindWinStationById( LogonId, FALSE );
  142. if ( !pWinStation )
  143. return( STATUS_CTX_WINSTATION_NOT_FOUND );
  144. if ( pWinStation->Terminating ) {
  145. ReleaseWinStation( pWinStation );
  146. return( STATUS_CTX_CLOSE_PENDING );
  147. }
  148. /*
  149. * Verify that client has SET access
  150. */
  151. Status = RpcCheckClientAccess( pWinStation, WINSTATION_SET, FALSE );
  152. if ( !NT_SUCCESS( Status ) ) {
  153. ReleaseWinStation( pWinStation );
  154. return( Status );
  155. }
  156. switch ( WinStationInformationClass ) {
  157. case WinStationPdParams :
  158. Status = CheckWireBuffer(WinStationInformationClass,
  159. pWinStationInformation,
  160. WinStationInformationLength,
  161. &pPdParams,
  162. &PdParamsLength);
  163. if ( !NT_SUCCESS(Status) ) {
  164. break;
  165. }
  166. if ( pWinStation->hStack ) {
  167. // Check for availability
  168. if ( pWinStation->pWsx &&
  169. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  170. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  171. pWinStation->pWsxContext,
  172. pWinStation->hIca,
  173. pWinStation->hStack,
  174. IOCTL_ICA_STACK_SET_PARAMS,
  175. pPdParams,
  176. PdParamsLength,
  177. NULL,
  178. 0,
  179. NULL );
  180. }
  181. else {
  182. Status = STATUS_INVALID_INFO_CLASS;
  183. }
  184. }
  185. LocalFree((PVOID)pPdParams);
  186. break;
  187. case WinStationConfiguration :
  188. Status = CheckWireBuffer(WinStationInformationClass,
  189. pWinStationInformation,
  190. WinStationInformationLength,
  191. &pConfig,
  192. &ConfigLength);
  193. if ( !NT_SUCCESS(Status) ) {
  194. break;
  195. }
  196. Status = _SetConfig( pWinStation,
  197. pConfig,
  198. ConfigLength );
  199. LocalFree((PVOID)pConfig);
  200. break;
  201. case WinStationTrace :
  202. RpcStatus = RpcImpersonateClient( NULL );
  203. if( RpcStatus != RPC_S_OK ) {
  204. Status = STATUS_CANNOT_IMPERSONATE;
  205. break;
  206. }
  207. if (!IsCallerAdmin() && !IsCallerSystem()) {
  208. Status = STATUS_ACCESS_DENIED;
  209. }
  210. RpcRevertToSelf();
  211. if (!NT_SUCCESS(Status)) {
  212. break;
  213. }
  214. if ( WinStationInformationLength < sizeof(ICA_TRACE) ) {
  215. Status = STATUS_BUFFER_TOO_SMALL;
  216. break;
  217. }
  218. if ( pWinStation->hIca ) {
  219. Status = IcaIoControl( pWinStation->hIca,
  220. IOCTL_ICA_SET_TRACE,
  221. pWinStationInformation,
  222. WinStationInformationLength,
  223. NULL,
  224. 0,
  225. NULL );
  226. }
  227. break;
  228. case WinStationSystemTrace :
  229. RpcStatus = RpcImpersonateClient( NULL );
  230. if( RpcStatus != RPC_S_OK ) {
  231. Status = STATUS_CANNOT_IMPERSONATE;
  232. break;
  233. }
  234. if (!IsCallerAdmin() && !IsCallerSystem()) {
  235. Status = STATUS_ACCESS_DENIED;
  236. }
  237. RpcRevertToSelf();
  238. if (!NT_SUCCESS(Status)) {
  239. break;
  240. }
  241. if ( WinStationInformationLength < sizeof(ICA_TRACE) ) {
  242. Status = STATUS_BUFFER_TOO_SMALL;
  243. break;
  244. }
  245. /*
  246. * Open ICA device driver
  247. */
  248. if ( hTrace == NULL ) {
  249. Status = IcaOpen( &hTrace );
  250. if ( !NT_SUCCESS(Status) )
  251. hTrace = NULL;
  252. }
  253. if ( hTrace ) {
  254. Status = IcaIoControl( hTrace,
  255. IOCTL_ICA_SET_SYSTEM_TRACE,
  256. pWinStationInformation,
  257. WinStationInformationLength,
  258. NULL,
  259. 0,
  260. NULL );
  261. }
  262. break;
  263. case WinStationPrinter :
  264. break;
  265. case WinStationBeep :
  266. if (WinStationInformationLength < sizeof(BEEPINPUT)) {
  267. Status = STATUS_BUFFER_TOO_SMALL ;
  268. break;
  269. }
  270. Status = _SetBeep( pWinStation,
  271. (PBEEPINPUT) pWinStationInformation,
  272. WinStationInformationLength );
  273. break;
  274. case WinStationEncryptionOff :
  275. if ( pWinStation->hStack ) {
  276. // Check for availability
  277. if ( pWinStation->pWsx &&
  278. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  279. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  280. pWinStation->pWsxContext,
  281. pWinStation->hIca,
  282. pWinStation->hStack,
  283. IOCTL_ICA_STACK_ENCRYPTION_OFF,
  284. pWinStationInformation,
  285. WinStationInformationLength,
  286. NULL,
  287. 0,
  288. NULL );
  289. }
  290. else {
  291. Status = STATUS_INVALID_INFO_CLASS;
  292. }
  293. }
  294. break;
  295. case WinStationEncryptionPerm :
  296. if ( pWinStation->hStack ) {
  297. // Check for availability
  298. if ( pWinStation->pWsx &&
  299. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  300. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  301. pWinStation->pWsxContext,
  302. pWinStation->hIca,
  303. pWinStation->hStack,
  304. IOCTL_ICA_STACK_ENCRYPTION_PERM,
  305. pWinStationInformation,
  306. WinStationInformationLength,
  307. NULL,
  308. 0,
  309. NULL );
  310. }
  311. else {
  312. Status = STATUS_INVALID_INFO_CLASS;
  313. }
  314. }
  315. break;
  316. case WinStationSecureDesktopEnter :
  317. if ( pWinStation->hStack ) {
  318. // Check for availability
  319. if ( pWinStation->pWsx &&
  320. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  321. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  322. pWinStation->pWsxContext,
  323. pWinStation->hIca,
  324. pWinStation->hStack,
  325. IOCTL_ICA_STACK_ENCRYPTION_ENTER,
  326. pWinStationInformation,
  327. WinStationInformationLength,
  328. NULL,
  329. 0,
  330. NULL );
  331. }
  332. else {
  333. Status = STATUS_INVALID_INFO_CLASS;
  334. }
  335. }
  336. break;
  337. case WinStationSecureDesktopExit :
  338. if ( pWinStation->hStack ) {
  339. // Check for availability
  340. if ( pWinStation->pWsx &&
  341. pWinStation->pWsx->pWsxIcaStackIoControl ) {
  342. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  343. pWinStation->pWsxContext,
  344. pWinStation->hIca,
  345. pWinStation->hStack,
  346. IOCTL_ICA_STACK_ENCRYPTION_EXIT,
  347. pWinStationInformation,
  348. WinStationInformationLength,
  349. NULL,
  350. 0,
  351. NULL );
  352. }
  353. else {
  354. Status = STATUS_INVALID_INFO_CLASS;
  355. }
  356. }
  357. break;
  358. /*
  359. * Give focus to winlogon security desktop
  360. * -- used by progman.exe
  361. */
  362. case WinStationNtSecurity :
  363. /*
  364. * Tell the WinStation to Send Winlogon the CTR-ALT-DEL message
  365. */
  366. msg.ApiNumber = SMWinStationNtSecurity;
  367. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  368. break;
  369. case WinStationClientData :
  370. //
  371. // Handles multiple client data items. The data buffer
  372. // format is:
  373. // ULONG // Length of next data item
  374. // WINSTATIONCLIENTDATA // Including variable length part
  375. // ULONG // Length of next data item
  376. // WINSTATIONCLIENTDATA // Including variable length part
  377. // etc
  378. //
  379. // WinStationInformationLength is the length of the entire
  380. // data buffer. Keep processing client data items until
  381. // the buffer is exhausted.
  382. //
  383. if ( WinStationInformationLength < sizeof(ULONG) +
  384. sizeof(WINSTATIONCLIENTDATA) )
  385. {
  386. Status = STATUS_INFO_LENGTH_MISMATCH;
  387. break;
  388. }
  389. if ( pWinStation->hStack )
  390. {
  391. // Check for availability
  392. if ( pWinStation->pWsx &&
  393. pWinStation->pWsx->pWsxIcaStackIoControl )
  394. {
  395. ULONG CurLen;
  396. ULONG LenUsed =0;
  397. PBYTE CurPtr = (PBYTE)pWinStationInformation;
  398. while (LenUsed + sizeof(ULONG) < WinStationInformationLength)
  399. {
  400. CurLen = *(ULONG UNALIGNED *)CurPtr;
  401. LenUsed += sizeof(ULONG);
  402. CurPtr += sizeof(ULONG);
  403. if ( (LenUsed + CurLen >= LenUsed) &&
  404. (LenUsed + CurLen <= WinStationInformationLength))
  405. {
  406. Status = pWinStation->pWsx->pWsxIcaStackIoControl(
  407. pWinStation->pWsxContext,
  408. pWinStation->hIca,
  409. pWinStation->hStack,
  410. IOCTL_ICA_STACK_SET_CLIENT_DATA,
  411. CurPtr,
  412. CurLen,
  413. NULL,
  414. 0,
  415. NULL );
  416. LenUsed += CurLen;
  417. CurPtr += CurLen;
  418. }else
  419. {
  420. Status = STATUS_INVALID_USER_BUFFER;
  421. break;
  422. }
  423. }
  424. }
  425. else
  426. {
  427. Status = STATUS_INVALID_INFO_CLASS;
  428. }
  429. }
  430. break;
  431. case WinStationInitialProgram :
  432. /*
  433. * Identify first program, non-consoles only
  434. */
  435. if ( LogonId != 0 ) {
  436. /*
  437. * Tell the WinStation this is the initial program
  438. */
  439. msg.ApiNumber = SMWinStationInitialProgram;
  440. Status = SendWinStationCommand( pWinStation, &msg, 0 );
  441. }
  442. break;
  443. case WinStationShadowInfo:
  444. Status = _CheckCallerLocalAndSystem();
  445. if( NT_SUCCESS(Status) ) {
  446. Status = WinStationShadowChangeMode( pWinStation,
  447. (PWINSTATIONSHADOW) pWinStationInformation,
  448. WinStationInformationLength );
  449. }
  450. break;
  451. case WinStationLockedState:
  452. {
  453. BOOL bLockedState;
  454. if (WinStationInformationLength == sizeof(bLockedState))
  455. {
  456. bLockedState = * (LPBOOL) pWinStationInformation;
  457. Status = SetLockedState (pWinStation, bLockedState);
  458. }
  459. else
  460. {
  461. Status = STATUS_INFO_LENGTH_MISMATCH;
  462. }
  463. break;
  464. }
  465. case WinStationDisallowAutoReconnect:
  466. {
  467. RpcStatus = RpcImpersonateClient( NULL );
  468. if( RpcStatus != RPC_S_OK ) {
  469. Status = STATUS_CANNOT_IMPERSONATE;
  470. break;
  471. }
  472. if (!IsCallerSystem()) {
  473. Status = STATUS_ACCESS_DENIED;
  474. }
  475. RpcRevertToSelf();
  476. if (Status != STATUS_SUCCESS) {
  477. break;
  478. }
  479. if (WinStationInformationLength == sizeof(BOOLEAN)) {
  480. pWinStation->fDisallowAutoReconnect = * (PBOOLEAN) pWinStationInformation;
  481. } else {
  482. Status = STATUS_INFO_LENGTH_MISMATCH;
  483. }
  484. break;
  485. }
  486. case WinStationMprNotifyInfo:
  487. {
  488. Status = _CheckCallerLocalAndSystem();
  489. if (Status != STATUS_SUCCESS) {
  490. break;
  491. }
  492. if (WinStationInformationLength == sizeof(ExtendedClientCredentials)) {
  493. pExtendedClientCredentials pMprInfo ;
  494. pMprInfo = (pExtendedClientCredentials) pWinStationInformation;
  495. wcsncpy(g_MprNotifyInfo.Domain, pMprInfo->Domain, EXTENDED_DOMAIN_LEN);
  496. g_MprNotifyInfo.Domain[EXTENDED_DOMAIN_LEN] = L'\0';
  497. wcsncpy(g_MprNotifyInfo.UserName, pMprInfo->UserName, EXTENDED_USERNAME_LEN);
  498. g_MprNotifyInfo.UserName[EXTENDED_USERNAME_LEN] = L'\0';
  499. wcsncpy(g_MprNotifyInfo.Password, pMprInfo->Password, EXTENDED_PASSWORD_LEN);
  500. g_MprNotifyInfo.Password[EXTENDED_PASSWORD_LEN] = L'\0';
  501. } else {
  502. Status = STATUS_INFO_LENGTH_MISMATCH;
  503. }
  504. break;
  505. }
  506. default:
  507. /*
  508. * Fail the call
  509. */
  510. Status = STATUS_INVALID_INFO_CLASS;
  511. break;
  512. }
  513. ReleaseWinStation( pWinStation );
  514. TRACE((hTrace,TC_ICASRV,TT_API2,"TERMSRV: WinStationSetInformation LogonId=%d, Class=%d, Status=0x%x\n",
  515. LogonId, (ULONG)WinStationInformationClass, Status));
  516. return( Status );
  517. }
  518. /*******************************************************************************
  519. *
  520. * _SetConfig
  521. *
  522. * set window station configuration
  523. *
  524. * ENTRY:
  525. * pWinStation (input)
  526. * pointer to citrix window station structure
  527. * pConfig (input)
  528. * pointer to configuration structure
  529. * Length (input)
  530. * length of configuration structure
  531. *
  532. * EXIT:
  533. * STATUS_SUCCESS - no error
  534. *
  535. ******************************************************************************/
  536. NTSTATUS
  537. _SetConfig( PWINSTATION pWinStation,
  538. PWINSTATIONCONFIG pConfig,
  539. ULONG Length )
  540. {
  541. USERCONFIG UserConfig;
  542. /*
  543. * Validate length
  544. */
  545. if ( Length < sizeof(WINSTATIONCONFIG) )
  546. return( STATUS_BUFFER_TOO_SMALL );
  547. /*
  548. * Copy structure
  549. */
  550. pWinStation->Config.Config = *pConfig;
  551. /*
  552. * Merge client data into winstation structure
  553. */
  554. if ( pWinStation->pWsx &&
  555. pWinStation->pWsx->pWsxInitializeUserConfig ) {
  556. pWinStation->pWsx->pWsxInitializeUserConfig( pWinStation->pWsxContext,
  557. pWinStation->hStack,
  558. pWinStation->hIcaThinwireChannel,
  559. &pWinStation->Config.Config.User,
  560. &pWinStation->Client.HRes,
  561. &pWinStation->Client.VRes,
  562. &pWinStation->Client.ColorDepth);
  563. }
  564. /*
  565. * If user is logged on -> merge user profile data
  566. */
  567. if ( pWinStation->UserName[0] ) {
  568. /*
  569. * Read user profile data
  570. */
  571. _ReadUserProfile( pWinStation->Domain,
  572. pWinStation->UserName,
  573. &UserConfig );
  574. #if NT2195
  575. /*
  576. * Merge user config data into the winstation
  577. */
  578. MergeUserConfigData( pWinStation, &UserConfig );
  579. #else
  580. // @@@
  581. DbgPrint(("WARNING: _SetConfig is if-def'd out \n" ) );
  582. #endif
  583. }
  584. /*
  585. * Convert any "published app" to absolute path
  586. */
  587. if ( pWinStation->pWsx &&
  588. pWinStation->pWsx->pWsxConvertPublishedApp ) {
  589. (void) pWinStation->pWsx->pWsxConvertPublishedApp( pWinStation->pWsxContext,
  590. &pWinStation->Config.Config.User);
  591. }
  592. return( STATUS_SUCCESS );
  593. }
  594. /*******************************************************************************
  595. *
  596. * _ReadUserProfile
  597. *
  598. * This routine reads the user profile data from the registry
  599. *
  600. * ENTRY:
  601. * pDomain (input)
  602. * domain of user
  603. * pUserName (input)
  604. * user name to read
  605. * pUserConfig (output)
  606. * address to return user profile data
  607. *
  608. * EXIT:
  609. * None.
  610. *
  611. ******************************************************************************/
  612. VOID
  613. _ReadUserProfile( PWCHAR pDomain, PWCHAR pUserName, PUSERCONFIG pUserConfig )
  614. {
  615. PWCHAR pServerName;
  616. ULONG Length;
  617. LONG Error;
  618. /*
  619. * Get Domain Controller name and userconfig data.
  620. * If no userconfig data for user then get default values.
  621. */
  622. if ( ghNetApiDll == NULL ) {
  623. ghNetApiDll = LoadLibrary( L"NETAPI32" );
  624. if ( ghNetApiDll ) {
  625. pNetGetAnyDCName = GetProcAddress( ghNetApiDll, "NetGetAnyDCName" );
  626. pNetApiBufferFree = GetProcAddress( ghNetApiDll, "NetApiBufferFree" );
  627. }
  628. }
  629. /*
  630. * Check to make sure we got a server name
  631. */
  632. if ( pNetGetAnyDCName == NULL ||
  633. pNetGetAnyDCName( NULL, pDomain, (LPBYTE *)&pServerName ) != ERROR_SUCCESS )
  634. pServerName = NULL;
  635. /*
  636. * Read user profile data
  637. */
  638. Error = RegUserConfigQuery( pServerName,
  639. pUserName,
  640. pUserConfig,
  641. sizeof(USERCONFIG),
  642. &Length );
  643. TRACE((hTrace,TC_ICASRV,TT_API1, "RegUserConfigQuery: \\\\%S\\%S, server %S, Error=%u\n",
  644. pDomain, pUserName, pServerName, Error ));
  645. if ( Error != ERROR_SUCCESS ) {
  646. Error = RegDefaultUserConfigQuery( pServerName, pUserConfig,
  647. sizeof(USERCONFIG), &Length );
  648. TRACE((hTrace,TC_ICASRV,TT_ERROR, "RegDefaultUserConfigQuery, Error=%u\n", Error ));
  649. }
  650. /*
  651. * Free memory
  652. */
  653. if ( pServerName && pNetApiBufferFree )
  654. pNetApiBufferFree( pServerName );
  655. }
  656. /*******************************************************************************
  657. *
  658. * _SetBeep
  659. *
  660. * Beep the WinStation
  661. *
  662. * ENTRY:
  663. * pWinStation (input)
  664. * pointer to citrix window station structure
  665. * pBeepInput (input)
  666. * pointer to Beep input structure
  667. * Length (input)
  668. * length of Beep input structure
  669. *
  670. * EXIT:
  671. * STATUS_SUCCESS - no error
  672. *
  673. ******************************************************************************/
  674. NTSTATUS
  675. _SetBeep( PWINSTATION pWinStation,
  676. PBEEPINPUT pBeepInput,
  677. ULONG Length)
  678. {
  679. NTSTATUS Status = STATUS_SUCCESS;
  680. BEEP_SET_PARAMETERS BeepParameters;
  681. IO_STATUS_BLOCK IoStatus;
  682. /*
  683. * Do the regular Beep, so you can support fancy Beeps from
  684. * sound cards.
  685. */
  686. if ( pWinStation->LogonId == 0 ) {
  687. if ( MessageBeep( pBeepInput->uType ) )
  688. return( STATUS_SUCCESS );
  689. else
  690. return( STATUS_UNSUCCESSFUL );
  691. }
  692. BeepParameters.Frequency = 440;
  693. BeepParameters.Duration = 125;
  694. if ( pWinStation->hIcaBeepChannel ) {
  695. Status = NtDeviceIoControlFile( pWinStation->hIcaBeepChannel,
  696. NULL,
  697. NULL,
  698. NULL,
  699. &IoStatus,
  700. IOCTL_BEEP_SET,
  701. &BeepParameters,
  702. sizeof( BeepParameters ),
  703. NULL,
  704. 0
  705. );
  706. }
  707. return( STATUS_SUCCESS );
  708. }