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

1407 lines
39 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. wksta.c
  5. Abstract:
  6. This module contains the worker routines for the NetWksta APIs
  7. implemented in the Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 20-Feb-1991
  10. Revision History:
  11. 14-May-1992 JohnRo
  12. Implemented "sticky set info" and registry watch.
  13. Corrected an info level: 1015 should be 1013.
  14. --*/
  15. #include "wsutil.h"
  16. #include "wsdevice.h"
  17. #include "wssec.h"
  18. #include "wslsa.h"
  19. #include "wsconfig.h"
  20. #include "wswksta.h"
  21. #include <config.h>
  22. #include <confname.h>
  23. #include <prefix.h>
  24. #include "wsregcfg.h" // Registry helpers
  25. //-------------------------------------------------------------------//
  26. // //
  27. // Local function prototypes //
  28. // //
  29. //-------------------------------------------------------------------//
  30. STATIC
  31. NET_API_STATUS
  32. WsValidateAndSetWksta(
  33. IN DWORD Level,
  34. IN LPBYTE Buffer,
  35. OUT LPDWORD ErrorParameter OPTIONAL,
  36. OUT LPDWORD Parmnum
  37. );
  38. STATIC
  39. NET_API_STATUS
  40. WsGetSystemInfo(
  41. IN DWORD Level,
  42. OUT LPBYTE *BufferPointer
  43. );
  44. STATIC
  45. NET_API_STATUS
  46. WsGetPlatformInfo(
  47. IN DWORD Level,
  48. OUT LPBYTE *BufferPointer
  49. );
  50. STATIC
  51. NET_API_STATUS
  52. WsFillSystemBufferInfo(
  53. IN DWORD Level,
  54. IN DWORD NumberOfLoggedOnUsers,
  55. OUT LPBYTE *OutputBuffer
  56. );
  57. STATIC
  58. VOID
  59. WsUpdateRegistryToMatchWksta(
  60. IN DWORD Level,
  61. IN LPBYTE Buffer,
  62. OUT LPDWORD ErrorParameter OPTIONAL
  63. );
  64. NET_API_STATUS NET_API_FUNCTION
  65. NetrWkstaGetInfo(
  66. IN LPTSTR ServerName OPTIONAL,
  67. IN DWORD Level,
  68. OUT LPWKSTA_INFO WkstaInfo
  69. )
  70. /*++
  71. Routine Description:
  72. This function is the NetWkstaGetInfo entry point in the Workstation
  73. service. It checks the security access of the caller before returning
  74. one the information requested which is either system-wide, or redirector
  75. specific.
  76. Arguments:
  77. ServerName - Supplies the name of server to execute this function
  78. Level - Supplies the requested level of information.
  79. WkstaInfo - Returns a pointer to a buffer which contains the requested
  80. workstation information.
  81. Return Value:
  82. NET_API_STATUS - NERR_Success or reason for failure.
  83. --*/
  84. {
  85. NET_API_STATUS status = NERR_Success;
  86. LPBYTE Buffer;
  87. ACCESS_MASK DesiredAccess;
  88. UNREFERENCED_PARAMETER(ServerName);
  89. //
  90. // Determine the desired access based on the specified info level.
  91. //
  92. switch (Level) {
  93. //
  94. // Guest access
  95. //
  96. case 100:
  97. DesiredAccess = WKSTA_CONFIG_GUEST_INFO_GET;
  98. break;
  99. //
  100. // User access
  101. //
  102. case 101:
  103. DesiredAccess = WKSTA_CONFIG_USER_INFO_GET;
  104. break;
  105. //
  106. // Admin or operator access
  107. //
  108. case 102:
  109. case 502:
  110. DesiredAccess = WKSTA_CONFIG_ADMIN_INFO_GET;
  111. break;
  112. default:
  113. return ERROR_INVALID_LEVEL;
  114. }
  115. //
  116. // Perform access validation on the caller.
  117. //
  118. if (NetpAccessCheckAndAudit(
  119. WORKSTATION_DISPLAY_NAME, // Subsystem name
  120. (LPTSTR) CONFIG_INFO_OBJECT, // Object type name
  121. ConfigurationInfoSd, // Security descriptor
  122. DesiredAccess, // Desired access
  123. &WsConfigInfoMapping // Generic mapping
  124. ) != NERR_Success) {
  125. return ERROR_ACCESS_DENIED;
  126. }
  127. //
  128. // Only allowed to proceed with get info if no one else is setting
  129. //
  130. if (! RtlAcquireResourceShared(&WsInfo.ConfigResource, TRUE)) {
  131. return NERR_InternalError;
  132. }
  133. try {
  134. switch (Level) {
  135. //
  136. // System-wide information
  137. //
  138. case 100:
  139. case 101:
  140. case 102:
  141. status = WsGetSystemInfo(Level, &Buffer);
  142. if (status == NERR_Success) {
  143. SET_SYSTEM_INFO_POINTER(WkstaInfo, Buffer);
  144. }
  145. break;
  146. //
  147. // Platform specific information
  148. //
  149. case 502:
  150. status = WsGetPlatformInfo(
  151. Level,
  152. (LPBYTE *) &(WkstaInfo->WkstaInfo502)
  153. );
  154. break;
  155. //
  156. // This should have been caught earlier.
  157. //
  158. default:
  159. NetpAssert(FALSE);
  160. status = ERROR_INVALID_LEVEL;
  161. }
  162. } except(EXCEPTION_EXECUTE_HANDLER) {
  163. RtlReleaseResource(&WsInfo.ConfigResource);
  164. return RtlNtStatusToDosError(GetExceptionCode());
  165. }
  166. RtlReleaseResource(&WsInfo.ConfigResource);
  167. return status;
  168. }
  169. NET_API_STATUS NET_API_FUNCTION
  170. NetrWkstaSetInfo(
  171. IN LPTSTR ServerName OPTIONAL,
  172. IN DWORD Level,
  173. IN LPWKSTA_INFO WkstaInfo,
  174. OUT LPDWORD ErrorParameter OPTIONAL
  175. )
  176. /*++
  177. Routine Description:
  178. This function is the NetWkstaSetInfo entry point in the Workstation
  179. service. It checks the security access of the caller to make sure
  180. that the caller is allowed to set specific workstation information.
  181. Arguments:
  182. ServerName - Supplies the name of server to execute this function
  183. Level - Supplies the level of information.
  184. WkstaInfo - Supplies a pointer to union structure of pointers to
  185. buffer of fields to set. The level denotes the fields supplied in
  186. this buffer.
  187. ErrorParameter - Returns the identifier to the invalid parameter if
  188. this function returns ERROR_INVALID_PARAMETER.
  189. Return Value:
  190. NET_API_STATUS - NERR_Success or reason for failure.
  191. --*/
  192. {
  193. WKSTA_INFO_502 OriginalWksta = WSBUF;
  194. NET_API_STATUS status = NERR_Success;
  195. DWORD Parmnum;
  196. UNREFERENCED_PARAMETER(ServerName);
  197. //
  198. // Check for NULL input buffer
  199. //
  200. if (WkstaInfo->WkstaInfo502 == NULL) {
  201. RETURN_INVALID_PARAMETER(ErrorParameter, PARM_ERROR_UNKNOWN);
  202. }
  203. //
  204. // Only admins can set redirector configurable fields. Validate access.
  205. //
  206. if (NetpAccessCheckAndAudit(
  207. WORKSTATION_DISPLAY_NAME, // Subsystem name
  208. (LPTSTR) CONFIG_INFO_OBJECT, // Object type name
  209. ConfigurationInfoSd, // Security descriptor
  210. WKSTA_CONFIG_INFO_SET, // Desired access
  211. &WsConfigInfoMapping // Generic mapping
  212. ) != NERR_Success) {
  213. return ERROR_ACCESS_DENIED;
  214. }
  215. //
  216. // Serialize write access
  217. //
  218. if (! RtlAcquireResourceExclusive(&WsInfo.ConfigResource, TRUE)) {
  219. return NERR_InternalError;
  220. }
  221. status = WsValidateAndSetWksta(
  222. Level,
  223. (LPBYTE) WkstaInfo->WkstaInfo502,
  224. ErrorParameter,
  225. &Parmnum
  226. );
  227. if (status != NERR_Success) {
  228. goto CleanExit;
  229. }
  230. //
  231. // Set NT redirector specific fields
  232. //
  233. status = WsUpdateRedirToMatchWksta(
  234. Parmnum,
  235. ErrorParameter
  236. );
  237. if (status != NERR_Success) {
  238. goto CleanExit;
  239. }
  240. //
  241. // Make updates "sticky" (update registry to match wksta).
  242. //
  243. WsUpdateRegistryToMatchWksta(
  244. Level,
  245. (LPBYTE) WkstaInfo->WkstaInfo502,
  246. ErrorParameter
  247. );
  248. CleanExit:
  249. if (status != NERR_Success) {
  250. WSBUF = OriginalWksta;
  251. }
  252. RtlReleaseResource(&WsInfo.ConfigResource);
  253. return status;
  254. }
  255. NET_API_STATUS NET_API_FUNCTION
  256. NetrWkstaTransportEnum(
  257. IN LPTSTR ServerName OPTIONAL,
  258. IN OUT LPWKSTA_TRANSPORT_ENUM_STRUCT TransportInfo,
  259. IN DWORD PreferedMaximumLength,
  260. OUT LPDWORD TotalEntries,
  261. IN OUT LPDWORD ResumeHandle OPTIONAL
  262. )
  263. /*++
  264. Routine Description:
  265. This function is the NetWkstaTransportEnum entry point in the
  266. Workstation service.
  267. Arguments:
  268. ServerName - Supplies the name of server to execute this function
  269. TransportInfo - This structure supplies the level of information requested,
  270. returns a pointer to the buffer allocated by the Workstation service
  271. which contains a sequence of information structure of the specified
  272. information level, and returns the number of entries read. The buffer
  273. pointer is set to NULL if return code is not NERR_Success or
  274. ERROR_MORE_DATA, or if EntriesRead returned is 0. The EntriesRead
  275. value is only valid if the return code is NERR_Success or
  276. ERROR_MORE_DATA.
  277. PreferedMaximumLength - Supplies the number of bytes of information
  278. to return in the buffer. If this value is MAXULONG, all available
  279. information will be returned.
  280. TotalEntries - Returns the total number of entries available. This value
  281. is only valid if the return code is NERR_Success or ERROR_MORE_DATA.
  282. ResumeHandle - Supplies a handle to resume the enumeration from where it
  283. left off the last time through. Returns the resume handle if return
  284. code is ERROR_MORE_DATA.
  285. Return Value:
  286. NET_API_STATUS - NERR_Success or reason for failure.
  287. --*/
  288. {
  289. NET_API_STATUS status;
  290. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  291. DWORD EnumTransportHintSize = 0; // Hint size from redirector
  292. LPBYTE Buffer;
  293. UNREFERENCED_PARAMETER(ServerName);
  294. //
  295. // Only level 0 is valid
  296. //
  297. if (TransportInfo->Level != 0) {
  298. return ERROR_INVALID_LEVEL;
  299. }
  300. //
  301. // Set up request packet. Output buffer structure is of enumerate
  302. // transport type.
  303. //
  304. Rrp.Version = REQUEST_PACKET_VERSION;
  305. Rrp.Type = EnumerateTransports;
  306. Rrp.Level = TransportInfo->Level;
  307. Rrp.Parameters.Get.ResumeHandle = (ARGUMENT_PRESENT(ResumeHandle)) ?
  308. *ResumeHandle : 0;
  309. //
  310. // Get the requested information from the redirector.
  311. //
  312. status = WsDeviceControlGetInfo(
  313. Redirector,
  314. WsRedirDeviceHandle,
  315. FSCTL_LMR_ENUMERATE_TRANSPORTS,
  316. &Rrp,
  317. sizeof(LMR_REQUEST_PACKET),
  318. &Buffer,
  319. PreferedMaximumLength,
  320. EnumTransportHintSize,
  321. NULL
  322. );
  323. //
  324. // Return output parameters
  325. //
  326. if (status == NERR_Success || status == ERROR_MORE_DATA) {
  327. SET_TRANSPORT_ENUM_POINTER(
  328. TransportInfo,
  329. Buffer,
  330. Rrp.Parameters.Get.EntriesRead
  331. );
  332. if (TransportInfo->WkstaTransportInfo.Level0 == NULL)
  333. {
  334. LocalFree(Buffer);
  335. }
  336. *TotalEntries = Rrp.Parameters.Get.TotalEntries;
  337. if (status == ERROR_MORE_DATA && ARGUMENT_PRESENT(ResumeHandle)) {
  338. *ResumeHandle = Rrp.Parameters.Get.ResumeHandle;
  339. }
  340. }
  341. return status;
  342. }
  343. NET_API_STATUS NET_API_FUNCTION
  344. NetrWkstaTransportAdd (
  345. IN LPTSTR ServerName OPTIONAL,
  346. IN DWORD Level,
  347. IN LPWKSTA_TRANSPORT_INFO_0 TransportInfo,
  348. OUT LPDWORD ErrorParameter OPTIONAL
  349. )
  350. /*++
  351. Routine Description:
  352. This function is the NetWkstaTransportAdd entry point in the
  353. Workstation service.
  354. Arguments:
  355. ServerName - Supplies the name of server to execute this function
  356. Level - Supplies the requested level of information.
  357. TransportInfo - Supplies the information structure to add a new transport.
  358. ErrorParameter - Returns the identifier to the invalid parameter if this
  359. function returns ERROR_INVALID_PARAMETER.
  360. Return Value:
  361. NET_API_STATUS - NERR_Success or reason for failure.
  362. --*/
  363. {
  364. UNREFERENCED_PARAMETER(ServerName);
  365. //
  366. // Only admins can add a transport. Validate access.
  367. //
  368. if (NetpAccessCheckAndAudit(
  369. WORKSTATION_DISPLAY_NAME, // Subsystem name
  370. (LPTSTR) CONFIG_INFO_OBJECT, // Object type name
  371. ConfigurationInfoSd, // Security descriptor
  372. WKSTA_CONFIG_INFO_SET, // Desired access
  373. &WsConfigInfoMapping // Generic mapping
  374. ) != NERR_Success) {
  375. return ERROR_ACCESS_DENIED;
  376. }
  377. //
  378. // 0 is the only valid level
  379. //
  380. if (Level != 0) {
  381. return ERROR_INVALID_LEVEL;
  382. }
  383. if (TransportInfo->wkti0_transport_name == NULL) {
  384. RETURN_INVALID_PARAMETER(ErrorParameter, TRANSPORT_NAME_PARMNUM);
  385. }
  386. return WsBindTransport(
  387. TransportInfo->wkti0_transport_name,
  388. TransportInfo->wkti0_quality_of_service,
  389. ErrorParameter
  390. );
  391. }
  392. NET_API_STATUS NET_API_FUNCTION
  393. NetrWkstaTransportDel (
  394. IN LPTSTR ServerName OPTIONAL,
  395. IN LPTSTR TransportName,
  396. IN DWORD ForceLevel
  397. )
  398. /*++
  399. Routine Description:
  400. This function is the NetWkstaTransportDel entry point in the
  401. Workstation service.
  402. Arguments:
  403. ServerName - Supplies the name of server to execute this function
  404. TransportName - Supplies the name of the transport to delete.
  405. ForceLevel - Supplies the level of force to delete the tree connections on
  406. the transport we are unbinding from.
  407. Return Value:
  408. NET_API_STATUS - NERR_Success or reason for failure.
  409. --*/
  410. {
  411. UNREFERENCED_PARAMETER(ServerName);
  412. //
  413. // Only admins can delete a transport. Validate access.
  414. //
  415. if (NetpAccessCheckAndAudit(
  416. WORKSTATION_DISPLAY_NAME, // Subsystem name
  417. (LPTSTR) CONFIG_INFO_OBJECT, // Object type name
  418. ConfigurationInfoSd, // Security descriptor
  419. WKSTA_CONFIG_INFO_SET, // Desired access
  420. &WsConfigInfoMapping // Generic mapping
  421. ) != NERR_Success) {
  422. return ERROR_ACCESS_DENIED;
  423. }
  424. if (TransportName == NULL) {
  425. return ERROR_INVALID_PARAMETER;
  426. }
  427. //
  428. // Check that ForceLevel parameter is valid, which the redirector and
  429. // browser use to delete the connections on the transport we are
  430. // unbinding from.
  431. //
  432. switch (ForceLevel) {
  433. case USE_FORCE:
  434. ForceLevel = USE_NOFORCE;
  435. break;
  436. case USE_NOFORCE:
  437. case USE_LOTS_OF_FORCE:
  438. break;
  439. default:
  440. return ERROR_INVALID_PARAMETER;
  441. }
  442. return WsUnbindTransport(TransportName, ForceLevel);
  443. }
  444. STATIC
  445. NET_API_STATUS
  446. WsGetSystemInfo(
  447. IN DWORD Level,
  448. OUT LPBYTE *BufferPointer
  449. )
  450. /*++
  451. Routine Description:
  452. This function calls the Redirector FSD, the LSA subsystem and the
  453. MSV1_0 authentication package, and the Datagram Receiver DD to get
  454. the system wide information returned by NetWkstaGetInfo API.
  455. Arguments:
  456. Level - Supplies the requested level of information.
  457. BufferPointer - Returns a pointer to a buffer which contains the
  458. requested workstation information.
  459. Return Value:
  460. NET_API_STATUS - NERR_Success or reason for failure.
  461. --*/
  462. {
  463. NET_API_STATUS status;
  464. DWORD NumberOfLoggedOnUsers = 1;
  465. //
  466. // Get number of logged on users from the MSV1_0 authentication package
  467. // if Level == 102.
  468. //
  469. if (Level == 102) {
  470. PMSV1_0_ENUMUSERS_RESPONSE EnumUsersResponse = NULL;
  471. //
  472. // Ask authentication package to enumerate users who are physically
  473. // logged to the local machine.
  474. //
  475. if ((status = WsLsaEnumUsers(
  476. (LPBYTE *) &EnumUsersResponse
  477. )) != NERR_Success) {
  478. return status;
  479. }
  480. if (EnumUsersResponse == NULL) {
  481. return ERROR_GEN_FAILURE;
  482. }
  483. NumberOfLoggedOnUsers = EnumUsersResponse->NumberOfLoggedOnUsers;
  484. (VOID) LsaFreeReturnBuffer(EnumUsersResponse);
  485. }
  486. //
  487. // Put all the data collected into output buffer allocated by this routine.
  488. //
  489. return WsFillSystemBufferInfo(
  490. Level,
  491. NumberOfLoggedOnUsers,
  492. BufferPointer
  493. );
  494. }
  495. STATIC
  496. NET_API_STATUS
  497. WsGetPlatformInfo(
  498. IN DWORD Level,
  499. OUT LPBYTE *BufferPointer
  500. )
  501. /*++
  502. Routine Description:
  503. This function calls the Redirector FSD to get the Redirector platform
  504. specific information returned by NetWkstaGetInfo API.
  505. Arguments:
  506. Level - Supplies the requested level of information.
  507. BufferPointer - Returns the pointer a buffer which contains the requested
  508. redirector specific information.
  509. Return Value:
  510. NET_API_STATUS - NERR_Success or reason for failure.
  511. --*/
  512. {
  513. NET_API_STATUS status;
  514. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  515. PWKSTA_INFO_502 Info;
  516. //
  517. // There is only one redirector info level: 502.
  518. //
  519. NetpAssert(Level == 502);
  520. //
  521. // Set up request packet. Output buffer structure is of configuration
  522. // information type.
  523. //
  524. Rrp.Version = REQUEST_PACKET_VERSION;
  525. Rrp.Level = Level;
  526. Rrp.Type = ConfigInformation;
  527. //
  528. // Get the requested information from the Redirector. This routine
  529. // allocates the returned buffer.
  530. //
  531. status = WsDeviceControlGetInfo(
  532. Redirector,
  533. WsRedirDeviceHandle,
  534. FSCTL_LMR_GET_CONFIG_INFO,
  535. &Rrp,
  536. sizeof(LMR_REQUEST_PACKET),
  537. BufferPointer,
  538. sizeof(WKSTA_INFO_502),
  539. 0,
  540. NULL
  541. );
  542. if (status == NERR_Success) {
  543. Info = (PWKSTA_INFO_502) *BufferPointer;
  544. //
  545. // Fill datagram receiver fields in level 502 structure from global
  546. // Workstation buffer (WSBUF). There are no FSCtl APIs to get or
  547. // set them in the datagram receiver.
  548. //
  549. Info->wki502_num_mailslot_buffers =
  550. WSBUF.wki502_num_mailslot_buffers;
  551. Info->wki502_num_srv_announce_buffers =
  552. WSBUF.wki502_num_srv_announce_buffers;
  553. Info->wki502_max_illegal_datagram_events =
  554. WSBUF.wki502_max_illegal_datagram_events;
  555. Info->wki502_illegal_datagram_event_reset_frequency =
  556. WSBUF.wki502_illegal_datagram_event_reset_frequency;
  557. Info->wki502_log_election_packets =
  558. WSBUF.wki502_log_election_packets;;
  559. }
  560. return status;
  561. }
  562. NET_API_STATUS
  563. WsValidateAndSetWksta(
  564. IN DWORD Level,
  565. IN LPBYTE Buffer,
  566. OUT LPDWORD ErrorParameter OPTIONAL,
  567. OUT LPDWORD Parmnum
  568. )
  569. /*++
  570. Routine Description:
  571. This function sets the user specified config fields into the global
  572. WsInfo.WsConfigBuf (WSBUF) buffer and validates that the fields
  573. are valid.
  574. It returns the associated parmnum value so that the caller can
  575. specify it to the redirector.
  576. Arguments:
  577. Level - Supplies the requested level of information.
  578. Buffer - Supplies a buffer which contains the user specified config
  579. fields.
  580. ErrorParameter - Receives the parmnum value of the field that is
  581. invalid if ERROR_INVALID_PARAMETER is returned.
  582. Parmnum - Receives the parmnum for the field(s) being set.
  583. Return Value:
  584. NET_API_STATUS - NERR_Success or reason for failure.
  585. --*/
  586. {
  587. DWORD i;
  588. //
  589. // Perform range checking
  590. //
  591. switch (Level) {
  592. case 502: // Set all fields
  593. WSBUF = *((PWKSTA_INFO_502) Buffer);
  594. *Parmnum = PARMNUM_ALL;
  595. break;
  596. case 1010: // char_wait
  597. WSBUF.wki502_char_wait = *((LPDWORD) Buffer);
  598. *Parmnum = WKSTA_CHARWAIT_PARMNUM;
  599. break;
  600. case 1011: // collection_time
  601. WSBUF.wki502_collection_time = *((LPDWORD) Buffer);
  602. *Parmnum = WKSTA_CHARTIME_PARMNUM;
  603. break;
  604. case 1012: // maximum_collection_count
  605. WSBUF.wki502_maximum_collection_count = *((LPDWORD) Buffer);
  606. *Parmnum = WKSTA_CHARCOUNT_PARMNUM;
  607. break;
  608. case 1013: // keep_conn
  609. WSBUF.wki502_keep_conn = *((LPDWORD) Buffer);
  610. *Parmnum = WKSTA_KEEPCONN_PARMNUM;
  611. break;
  612. case 1018: // sess_timeout
  613. WSBUF.wki502_sess_timeout = *((LPDWORD) Buffer);
  614. *Parmnum = WKSTA_SESSTIMEOUT_PARMNUM;
  615. break;
  616. case 1023: // siz_char_buf
  617. WSBUF.wki502_siz_char_buf = *((LPDWORD) Buffer);
  618. *Parmnum = WKSTA_SIZCHARBUF_PARMNUM;
  619. break;
  620. case 1033: // max_threads
  621. WSBUF.wki502_max_threads = *((LPDWORD) Buffer);
  622. *Parmnum = WKSTA_MAXTHREADS_PARMNUM;
  623. break;
  624. case 1041: // lock_quota
  625. WSBUF.wki502_lock_quota = *((LPDWORD) Buffer);
  626. *Parmnum = WKSTA_LOCKQUOTA_PARMNUM;
  627. break;
  628. case 1042: // lock_increment
  629. WSBUF.wki502_lock_increment = *((LPDWORD) Buffer);
  630. *Parmnum = WKSTA_LOCKINCREMENT_PARMNUM;
  631. break;
  632. case 1043: // lock_maximum
  633. WSBUF.wki502_lock_maximum = *((LPDWORD) Buffer);
  634. *Parmnum = WKSTA_LOCKMAXIMUM_PARMNUM;
  635. break;
  636. case 1044: // pipe_increment
  637. WSBUF.wki502_pipe_increment = *((LPDWORD) Buffer);
  638. *Parmnum = WKSTA_PIPEINCREMENT_PARMNUM;
  639. break;
  640. case 1045: // pipe_maximum
  641. WSBUF.wki502_pipe_maximum = *((LPDWORD) Buffer);
  642. *Parmnum = WKSTA_PIPEMAXIMUM_PARMNUM;
  643. break;
  644. case 1046: // dormant_file_limit
  645. WSBUF.wki502_dormant_file_limit = *((LPDWORD) Buffer);
  646. *Parmnum = WKSTA_DORMANTFILELIMIT_PARMNUM;
  647. break;
  648. case 1047: // cache_file_timeout
  649. WSBUF.wki502_cache_file_timeout = *((LPDWORD) Buffer);
  650. *Parmnum = WKSTA_CACHEFILETIMEOUT_PARMNUM;
  651. break;
  652. case 1048: // use_opportunistic_locking
  653. WSBUF.wki502_use_opportunistic_locking = *((LPBOOL) Buffer);
  654. *Parmnum = WKSTA_USEOPPORTUNISTICLOCKING_PARMNUM;
  655. break;
  656. case 1049: // use_unlock_behind
  657. WSBUF.wki502_use_unlock_behind = *((LPBOOL) Buffer);
  658. *Parmnum = WKSTA_USEUNLOCKBEHIND_PARMNUM;
  659. break;
  660. case 1050: // use_close_behind
  661. WSBUF.wki502_use_close_behind = *((LPBOOL) Buffer);
  662. *Parmnum = WKSTA_USECLOSEBEHIND_PARMNUM;
  663. break;
  664. case 1051: // buf_named_pipes
  665. WSBUF.wki502_buf_named_pipes = *((LPBOOL) Buffer);
  666. *Parmnum = WKSTA_BUFFERNAMEDPIPES_PARMNUM;
  667. break;
  668. case 1052: // use_lock_read_unlock
  669. WSBUF.wki502_use_lock_read_unlock = *((LPBOOL) Buffer);
  670. *Parmnum = WKSTA_USELOCKANDREADANDUNLOCK_PARMNUM;
  671. break;
  672. case 1053: // utilize_nt_caching
  673. WSBUF.wki502_utilize_nt_caching = *((LPBOOL) Buffer);
  674. *Parmnum = WKSTA_UTILIZENTCACHING_PARMNUM;
  675. break;
  676. case 1054: // use_raw_read
  677. WSBUF.wki502_use_raw_read = *((LPBOOL) Buffer);
  678. *Parmnum = WKSTA_USERAWREAD_PARMNUM;
  679. break;
  680. case 1055: // use_raw_write
  681. WSBUF.wki502_use_raw_write = *((LPBOOL) Buffer);
  682. *Parmnum = WKSTA_USERAWWRITE_PARMNUM;
  683. break;
  684. case 1056: // use_write_raw_data
  685. WSBUF.wki502_use_write_raw_data = *((LPBOOL) Buffer);
  686. *Parmnum = WKSTA_USEWRITERAWWITHDATA_PARMNUM;
  687. break;
  688. case 1057: // use_encryption
  689. WSBUF.wki502_use_encryption = *((LPBOOL) Buffer);
  690. *Parmnum = WKSTA_USEENCRYPTION_PARMNUM;
  691. break;
  692. case 1058: // buf_files_deny_write
  693. WSBUF.wki502_buf_files_deny_write = *((LPBOOL) Buffer);
  694. *Parmnum = WKSTA_BUFFILESWITHDENYWRITE_PARMNUM;
  695. break;
  696. case 1059: // buf_read_only_files
  697. WSBUF.wki502_buf_read_only_files = *((LPBOOL) Buffer);
  698. *Parmnum = WKSTA_BUFFERREADONLYFILES_PARMNUM;
  699. break;
  700. case 1060: // force_core_create_mode
  701. WSBUF.wki502_force_core_create_mode = *((LPBOOL) Buffer);
  702. *Parmnum = WKSTA_FORCECORECREATEMODE_PARMNUM;
  703. break;
  704. case 1061: // use_512_byte_max_transfer
  705. WSBUF.wki502_use_512_byte_max_transfer = *((LPBOOL) Buffer);
  706. *Parmnum = WKSTA_USE512BYTESMAXTRANSFER_PARMNUM;
  707. break;
  708. case 1062: // read_ahead_throughput
  709. WSBUF.wki502_read_ahead_throughput = *((LPDWORD) Buffer);
  710. *Parmnum = WKSTA_READAHEADTHRUPUT_PARMNUM;
  711. break;
  712. default:
  713. if (ErrorParameter != NULL) {
  714. *ErrorParameter = PARM_ERROR_UNKNOWN;
  715. }
  716. return ERROR_INVALID_LEVEL;
  717. }
  718. for (i = 0; WsInfo.WsConfigFields[i].Keyword != NULL; i++) {
  719. //
  720. // Check the range of all fields. If any fail, we return
  721. // ERROR_INVALID_PARAMETER.
  722. //
  723. if (((WsInfo.WsConfigFields[i].DataType == DWordType) &&
  724. (*(WsInfo.WsConfigFields[i].FieldPtr) <
  725. WsInfo.WsConfigFields[i].Minimum ||
  726. *(WsInfo.WsConfigFields[i].FieldPtr) >
  727. WsInfo.WsConfigFields[i].Maximum))
  728. ||
  729. ((WsInfo.WsConfigFields[i].DataType == BooleanType) &&
  730. (*(WsInfo.WsConfigFields[i].FieldPtr) != TRUE &&
  731. *(WsInfo.WsConfigFields[i].FieldPtr) != FALSE))) {
  732. //
  733. // We have a problem if this is not a field we want
  734. // to set, and we still happen to find a bad value.
  735. //
  736. NetpAssert((*Parmnum == PARMNUM_ALL) ||
  737. (*Parmnum == WsInfo.WsConfigFields[i].Parmnum));
  738. IF_DEBUG(INFO) {
  739. NetpKdPrint((
  740. PREFIX_WKSTA "Parameter %s has bad value %u, parmnum %u\n",
  741. WsInfo.WsConfigFields[i].Keyword,
  742. *(WsInfo.WsConfigFields[i].FieldPtr),
  743. WsInfo.WsConfigFields[i].Parmnum
  744. ));
  745. }
  746. RETURN_INVALID_PARAMETER(
  747. ErrorParameter,
  748. WsInfo.WsConfigFields[i].Parmnum
  749. );
  750. }
  751. }
  752. return NERR_Success;
  753. }
  754. NET_API_STATUS
  755. WsUpdateRedirToMatchWksta(
  756. IN DWORD Parmnum,
  757. OUT LPDWORD ErrorParameter OPTIONAL
  758. )
  759. /*++
  760. Routine Description:
  761. This function calls the redirector to set the redirector platform specific
  762. information with the values found in the global WsInfo.WsConfigBuf (WSBUF)
  763. buffer.
  764. Arguments:
  765. Parmnum - Supplies the parameter number of the field if a single field
  766. is being set. If all fields are being set, this value is PARMNUM_ALL.
  767. ErrorParameter - Returns the identifier to the invalid parameter in Buffer
  768. if this function returns ERROR_INVALID_PARAMETER.
  769. Return Value:
  770. NET_API_STATUS - NERR_Success or reason for failure.
  771. --*/
  772. {
  773. NET_API_STATUS ApiStatus;
  774. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  775. //
  776. // Set up request packet. Input buffer structure is of configuration
  777. // information type.
  778. //
  779. Rrp.Version = REQUEST_PACKET_VERSION;
  780. Rrp.Level = 502;
  781. Rrp.Type = ConfigInformation;
  782. Rrp.Parameters.Set.WkstaParameter = Parmnum;
  783. //
  784. // Set the information in the Redirector.
  785. //
  786. ApiStatus = WsRedirFsControl(
  787. WsRedirDeviceHandle,
  788. FSCTL_LMR_SET_CONFIG_INFO,
  789. &Rrp,
  790. sizeof(LMR_REQUEST_PACKET),
  791. (PVOID) &WSBUF,
  792. sizeof(WSBUF),
  793. NULL
  794. );
  795. if (ApiStatus == ERROR_INVALID_PARAMETER && ARGUMENT_PRESENT(ErrorParameter)) {
  796. IF_DEBUG(INFO) {
  797. NetpKdPrint((
  798. PREFIX_WKSTA "NetrWkstaSetInfo: invalid parameter is %lu\n",
  799. Rrp.Parameters.Set.WkstaParameter));
  800. }
  801. *ErrorParameter = Rrp.Parameters.Set.WkstaParameter;
  802. }
  803. return ApiStatus;
  804. }
  805. VOID
  806. WsUpdateRegistryToMatchWksta(
  807. IN DWORD Level,
  808. IN LPBYTE Buffer,
  809. OUT LPDWORD ErrorParameter OPTIONAL
  810. )
  811. /*++
  812. Routine Description:
  813. This function calls the registry to update the platform specific
  814. information in the registry.
  815. If any write operation to the registry fails, there is nothing we can
  816. do about it because chances are good that we will not be able to back
  817. out the changes since that requires more writes to the registry. When
  818. this happens, the discrepancy between the registry and the redirector
  819. will be straightened out when next key change notify occurs.
  820. Arguments:
  821. Level - Supplies the level of information.
  822. Buffer - Supplies a buffer which contains the information structure
  823. to set.
  824. ErrorParameter - Returns the identifier to the invalid parameter in Buffer
  825. if this function returns ERROR_INVALID_PARAMETER.
  826. Return Value:
  827. None.
  828. --*/
  829. {
  830. NET_API_STATUS ApiStatus;
  831. LPNET_CONFIG_HANDLE SectionHandle = NULL;
  832. DWORD i;
  833. //
  834. // Open section of config data.
  835. //
  836. ApiStatus = NetpOpenConfigData(
  837. &SectionHandle,
  838. NULL, // Local server.
  839. SECT_NT_WKSTA, // Section name.
  840. FALSE // Don't want read-only access.
  841. );
  842. if (ApiStatus != NERR_Success) {
  843. return;
  844. }
  845. //
  846. // Macro to update one value in the registry.
  847. // Assumes that Buffer starts with the new value for this field.
  848. //
  849. #define WRITE_ONE_PARM_TO_REGISTRY( KeyNamePart, TypeFlag ) \
  850. { \
  851. if (TypeFlag == BooleanType) { \
  852. (void) WsSetConfigBool( \
  853. SectionHandle, \
  854. WKSTA_KEYWORD_ ## KeyNamePart, \
  855. * ((LPBOOL) Buffer) ); \
  856. } else { \
  857. NetpAssert( TypeFlag == DWordType ); \
  858. (void) WsSetConfigDword( \
  859. SectionHandle, \
  860. WKSTA_KEYWORD_ ## KeyNamePart, \
  861. * ((LPDWORD) Buffer) ); \
  862. } \
  863. }
  864. //
  865. // Update field based on the info level.
  866. //
  867. switch (Level) {
  868. case 502: // Set all fields
  869. for (i = 0; WsInfo.WsConfigFields[i].Keyword != NULL; i++) {
  870. //
  871. // Write this field to the registry.
  872. //
  873. if (WsInfo.WsConfigFields[i].DataType == DWordType) {
  874. (void) WsSetConfigDword(
  875. SectionHandle,
  876. WsInfo.WsConfigFields[i].Keyword,
  877. * ((LPDWORD) WsInfo.WsConfigFields[i].FieldPtr)
  878. );
  879. } else {
  880. NetpAssert(WsInfo.WsConfigFields[i].DataType == BooleanType);
  881. (void) WsSetConfigBool(
  882. SectionHandle,
  883. WsInfo.WsConfigFields[i].Keyword,
  884. * ((LPBOOL) WsInfo.WsConfigFields[i].FieldPtr)
  885. );
  886. }
  887. }
  888. break;
  889. case 1010: // char_wait
  890. WRITE_ONE_PARM_TO_REGISTRY( CHARWAIT, DWordType );
  891. break;
  892. case 1011: // collection_time
  893. WRITE_ONE_PARM_TO_REGISTRY( COLLECTIONTIME, DWordType );
  894. break;
  895. case 1012: // maximum_collection_count
  896. WRITE_ONE_PARM_TO_REGISTRY( MAXCOLLECTIONCOUNT, DWordType );
  897. break;
  898. case 1013: // keep_conn
  899. WRITE_ONE_PARM_TO_REGISTRY( KEEPCONN, DWordType );
  900. break;
  901. case 1018: // sess_timeout
  902. WRITE_ONE_PARM_TO_REGISTRY( SESSTIMEOUT, DWordType );
  903. break;
  904. case 1023: // siz_char_buf
  905. WRITE_ONE_PARM_TO_REGISTRY( SIZCHARBUF, DWordType );
  906. break;
  907. case 1033: // max_threads
  908. WRITE_ONE_PARM_TO_REGISTRY( MAXTHREADS, DWordType );
  909. break;
  910. case 1041: // lock_quota
  911. WRITE_ONE_PARM_TO_REGISTRY( LOCKQUOTA, DWordType );
  912. break;
  913. case 1042: // lock_increment
  914. WRITE_ONE_PARM_TO_REGISTRY( LOCKINCREMENT, DWordType );
  915. break;
  916. case 1043: // lock_maximum
  917. WRITE_ONE_PARM_TO_REGISTRY( LOCKMAXIMUM, DWordType );
  918. break;
  919. case 1044: // pipe_increment
  920. WRITE_ONE_PARM_TO_REGISTRY( PIPEINCREMENT, DWordType );
  921. break;
  922. case 1045: // pipe_maximum
  923. WRITE_ONE_PARM_TO_REGISTRY( PIPEMAXIMUM, DWordType );
  924. break;
  925. case 1046: // dormant_file_limit
  926. WRITE_ONE_PARM_TO_REGISTRY( DORMANTFILELIMIT, DWordType );
  927. break;
  928. case 1047: // cache_file_timeout
  929. WRITE_ONE_PARM_TO_REGISTRY( CACHEFILETIMEOUT, DWordType );
  930. break;
  931. case 1048: // use_opportunistic_locking
  932. WRITE_ONE_PARM_TO_REGISTRY( USEOPLOCKING, BooleanType );
  933. break;
  934. case 1049: // use_unlock_behind
  935. WRITE_ONE_PARM_TO_REGISTRY( USEUNLOCKBEHIND, BooleanType );
  936. break;
  937. case 1050: // use_close_behind
  938. WRITE_ONE_PARM_TO_REGISTRY( USECLOSEBEHIND, BooleanType );
  939. break;
  940. case 1051: // buf_named_pipes
  941. WRITE_ONE_PARM_TO_REGISTRY( BUFNAMEDPIPES, BooleanType );
  942. break;
  943. case 1052: // use_lock_read_unlock
  944. WRITE_ONE_PARM_TO_REGISTRY( USELOCKREADUNLOCK, BooleanType );
  945. break;
  946. case 1053: // utilize_nt_caching
  947. WRITE_ONE_PARM_TO_REGISTRY( UTILIZENTCACHING, BooleanType );
  948. break;
  949. case 1054: // use_raw_read
  950. WRITE_ONE_PARM_TO_REGISTRY( USERAWREAD, BooleanType );
  951. break;
  952. case 1055: // use_raw_write
  953. WRITE_ONE_PARM_TO_REGISTRY( USERAWWRITE, BooleanType );
  954. break;
  955. case 1056: // use_write_raw_data
  956. WRITE_ONE_PARM_TO_REGISTRY( USEWRITERAWDATA, BooleanType );
  957. break;
  958. case 1057: // use_encryption
  959. WRITE_ONE_PARM_TO_REGISTRY( USEENCRYPTION, BooleanType );
  960. break;
  961. case 1058: // buf_files_deny_write
  962. WRITE_ONE_PARM_TO_REGISTRY( BUFFILESDENYWRITE, BooleanType );
  963. break;
  964. case 1059: // buf_read_only_files
  965. WRITE_ONE_PARM_TO_REGISTRY( BUFREADONLYFILES, BooleanType );
  966. break;
  967. case 1060: // force_core_create_mode
  968. WRITE_ONE_PARM_TO_REGISTRY( FORCECORECREATE, BooleanType );
  969. break;
  970. case 1061: // use_512_byte_max_transfer
  971. WRITE_ONE_PARM_TO_REGISTRY( USE512BYTEMAXTRANS, BooleanType );
  972. break;
  973. case 1062: // read_ahead_throughput
  974. WRITE_ONE_PARM_TO_REGISTRY( READAHEADTHRUPUT, DWordType );
  975. break;
  976. default:
  977. //
  978. // This should never happen
  979. //
  980. NetpAssert(FALSE);
  981. }
  982. if (SectionHandle != NULL) {
  983. (VOID) NetpCloseConfigData( SectionHandle );
  984. }
  985. }
  986. STATIC
  987. NET_API_STATUS
  988. WsFillSystemBufferInfo(
  989. IN DWORD Level,
  990. IN DWORD NumberOfLoggedOnUsers,
  991. OUT LPBYTE *OutputBuffer
  992. )
  993. /*++
  994. Routine Description:
  995. This function calculates the exact length of the output buffer needed,
  996. allocates that amount, and fill the output buffer with all the requested
  997. system-wide workstation information.
  998. NOTE: This function assumes that info structure level 102 is a superset
  999. of info structure level 100 and 101, and that the offset to each
  1000. common field is exactly the same. This allows us to take
  1001. advantage of a switch statement without a break between the levels.
  1002. Arguments:
  1003. Level - Supplies the level of information to be returned.
  1004. NumberOfLoggedOnUsers - Supplies the number of users logged on
  1005. interactively.
  1006. OutputBuffer - Returns a pointer to the buffer allocated by this routine
  1007. which is filled with the requested system-wide workstation
  1008. information.
  1009. Return Value:
  1010. NET_API_STATUS - NERR_Success or reason for failing to allocate the
  1011. output buffer.
  1012. --*/
  1013. {
  1014. PWKSTA_INFO_102 WkstaSystemInfo;
  1015. LPBYTE FixedDataEnd;
  1016. LPTSTR EndOfVariableData;
  1017. DWORD SystemInfoFixedLength = SYSTEM_INFO_FIXED_LENGTH(Level);
  1018. DWORD TotalBytesNeeded = SystemInfoFixedLength +
  1019. (WsInfo.WsComputerNameLength +
  1020. WsInfo.WsPrimaryDomainNameLength +
  1021. 3) * sizeof(TCHAR); // include NULL character
  1022. // for LAN root
  1023. if ((*OutputBuffer = MIDL_user_allocate(TotalBytesNeeded)) == NULL) {
  1024. return ERROR_NOT_ENOUGH_MEMORY;
  1025. }
  1026. RtlZeroMemory((PVOID) *OutputBuffer, TotalBytesNeeded);
  1027. WkstaSystemInfo = (PWKSTA_INFO_102) *OutputBuffer;
  1028. FixedDataEnd = (LPBYTE) ((DWORD_PTR) *OutputBuffer + SystemInfoFixedLength);
  1029. EndOfVariableData = (LPTSTR) ((DWORD_PTR) *OutputBuffer + TotalBytesNeeded);
  1030. //
  1031. // Put the data into the output buffer.
  1032. //
  1033. switch (Level) {
  1034. case 102:
  1035. WkstaSystemInfo->wki102_logged_on_users = NumberOfLoggedOnUsers;
  1036. case 101:
  1037. //
  1038. // LAN root is set to NULL on NT.
  1039. //
  1040. NetpCopyStringToBuffer(
  1041. NULL,
  1042. 0,
  1043. FixedDataEnd,
  1044. &EndOfVariableData,
  1045. &WkstaSystemInfo->wki102_lanroot
  1046. );
  1047. case 100:
  1048. WkstaSystemInfo->wki102_platform_id = WsInfo.RedirectorPlatform;
  1049. WkstaSystemInfo->wki102_ver_major = WsInfo.MajorVersion;
  1050. WkstaSystemInfo->wki102_ver_minor = WsInfo.MinorVersion;
  1051. NetpCopyStringToBuffer(
  1052. WsInfo.WsComputerName,
  1053. WsInfo.WsComputerNameLength,
  1054. FixedDataEnd,
  1055. &EndOfVariableData,
  1056. &WkstaSystemInfo->wki102_computername
  1057. );
  1058. NetpCopyStringToBuffer(
  1059. WsInfo.WsPrimaryDomainName,
  1060. WsInfo.WsPrimaryDomainNameLength,
  1061. FixedDataEnd,
  1062. &EndOfVariableData,
  1063. &WkstaSystemInfo->wki102_langroup
  1064. );
  1065. break;
  1066. default:
  1067. //
  1068. // This should never happen.
  1069. //
  1070. NetpKdPrint(("WsFillSystemBufferInfo: Invalid level %lu\n", Level));
  1071. NetpAssert(FALSE);
  1072. }
  1073. return NERR_Success;
  1074. }