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.

1422 lines
41 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. usegenum.c
  5. Abstract:
  6. This module contains the worker routines for the NetUseGetInfo and
  7. NetUseEnum APIs implemented in the Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 13-Mar-1991
  10. Revision History:
  11. --*/
  12. #include "wsutil.h"
  13. #include "wsdevice.h"
  14. #include "wsuse.h"
  15. //-------------------------------------------------------------------//
  16. // //
  17. // Local function prototypes //
  18. // //
  19. //-------------------------------------------------------------------//
  20. STATIC
  21. NET_API_STATUS
  22. WsGetUseInfo(
  23. IN PLUID LogonId,
  24. IN DWORD Level,
  25. IN HANDLE TreeConnection,
  26. IN PUSE_ENTRY UseEntry,
  27. OUT LPBYTE *OutputBuffer
  28. );
  29. STATIC
  30. NET_API_STATUS
  31. WsEnumUseInfo(
  32. IN PLUID LogonId,
  33. IN DWORD Level,
  34. IN PUSE_ENTRY UseList,
  35. IN LPBYTE ImplicitList,
  36. IN DWORD TotalImplicit,
  37. OUT LPBYTE *OutputBuffer,
  38. IN DWORD PreferedMaximumLength,
  39. OUT LPDWORD EntriesRead,
  40. OUT LPDWORD TotalEntries,
  41. IN OUT LPDWORD ResumeHandle OPTIONAL
  42. );
  43. STATIC
  44. NET_API_STATUS
  45. WsEnumCombinedUseInfo(
  46. IN PLUID LogonId,
  47. IN DWORD Level,
  48. IN LPBYTE ImplicitList,
  49. IN DWORD TotalImplicit,
  50. IN PUSE_ENTRY UseList,
  51. OUT LPBYTE OutputBuffer,
  52. IN DWORD OutputBufferLength,
  53. OUT LPDWORD EntriesRead,
  54. OUT LPDWORD TotalEntries,
  55. IN OUT LPDWORD ResumeHandle OPTIONAL
  56. );
  57. STATIC
  58. NET_API_STATUS
  59. WsGetRedirUseInfo(
  60. IN PLUID LogonId,
  61. IN DWORD Level,
  62. IN HANDLE TreeConnection,
  63. OUT LPBYTE *OutputBuffer
  64. );
  65. STATIC
  66. NET_API_STATUS
  67. WsGetCombinedUseInfo(
  68. IN DWORD Level,
  69. IN DWORD UseFixedLength,
  70. IN PUSE_ENTRY UseEntry,
  71. IN PLMR_CONNECTION_INFO_2 UncEntry,
  72. IN OUT LPBYTE *FixedPortion,
  73. IN OUT LPTSTR *EndOfVariableData,
  74. IN OUT LPDWORD EntriesRead OPTIONAL
  75. );
  76. STATIC
  77. BOOL
  78. WsFillUseBuffer(
  79. IN DWORD Level,
  80. IN PUSE_ENTRY UseEntry,
  81. IN PLMR_CONNECTION_INFO_2 UncEntry,
  82. IN OUT LPBYTE *FixedPortion,
  83. IN OUT LPTSTR *EndOfVariableData,
  84. IN DWORD UseFixedLength
  85. );
  86. //-------------------------------------------------------------------//
  87. // //
  88. // Macros //
  89. // //
  90. //-------------------------------------------------------------------//
  91. #define SET_USE_INFO_POINTER(InfoStruct, ResultBuffer) \
  92. InfoStruct->UseInfo2 = (PUSE_INFO_2) ResultBuffer;
  93. #define SET_USE_ENUM_POINTER(InfoStruct, ResultBuffer, NumRead) \
  94. {InfoStruct->UseInfo.Level2->Buffer = (PUSE_INFO_2) ResultBuffer;\
  95. InfoStruct->UseInfo.Level2->EntriesRead = NumRead;}
  96. NET_API_STATUS NET_API_FUNCTION
  97. NetrUseGetInfo(
  98. IN LPTSTR ServerName OPTIONAL,
  99. IN LPTSTR UseName,
  100. IN DWORD Level,
  101. OUT LPUSE_INFO InfoStruct
  102. )
  103. /*++
  104. Routine Description:
  105. This function is the NetUseGetInfo entry point in the Workstation service.
  106. This function assumes that UseName has been error checked and
  107. canonicalized.
  108. Arguments:
  109. UseName - Supplies the local device name or shared resource name of
  110. the tree connection.
  111. Level - Supplies the level of information to be returned regarding the
  112. specified tree connection.
  113. BufferPointer - Returns a pointer to the buffer allocated by the
  114. Workstation service which contains the requested information.
  115. This pointer is set to NULL if return code is not NERR_Success
  116. or ERROR_MORE_DATA.
  117. Return Value:
  118. NET_API_STATUS - NERR_Success or reason for failure.
  119. --*/
  120. {
  121. NET_API_STATUS status;
  122. LUID LogonId; // Logon Id of user
  123. DWORD Index; // Index to user entry in Use Table
  124. PUSE_ENTRY MatchedPointer; // Points to found use entry
  125. HANDLE TreeConnection; // Handle to connection
  126. TCHAR *FormattedUseName;
  127. // For canonicalizing a local device
  128. // name
  129. DWORD PathType = 0;
  130. LPBYTE Buffer = NULL;
  131. PUSE_ENTRY UseList;
  132. SET_USE_INFO_POINTER(InfoStruct, NULL);
  133. UNREFERENCED_PARAMETER(ServerName);
  134. if (Level > 3) {
  135. return ERROR_INVALID_LEVEL;
  136. }
  137. FormattedUseName = (TCHAR *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,(MAX_PATH+1)*sizeof(TCHAR));
  138. if (FormattedUseName == NULL) {
  139. return GetLastError();
  140. }
  141. //
  142. // Check to see if UseName is valid, and canonicalize it.
  143. //
  144. if (I_NetPathCanonicalize(
  145. NULL,
  146. UseName,
  147. FormattedUseName,
  148. (MAX_PATH+1)*sizeof(TCHAR),
  149. NULL,
  150. &PathType,
  151. 0
  152. ) != NERR_Success) {
  153. LocalFree(FormattedUseName);
  154. return NERR_UseNotFound;
  155. }
  156. IF_DEBUG(USE) {
  157. NetpKdPrint(("[Wksta] NetUseGetInfo %ws %lu\n", FormattedUseName, Level));
  158. }
  159. //
  160. // Impersonate caller and get the logon id
  161. //
  162. if ((status = WsImpersonateAndGetLogonId(&LogonId)) != NERR_Success) {
  163. LocalFree(FormattedUseName);
  164. return status;
  165. }
  166. //
  167. // Lock Use Table for read access
  168. //
  169. if (! RtlAcquireResourceShared(&Use.TableResource, TRUE)) {
  170. LocalFree(FormattedUseName);
  171. return NERR_InternalError;
  172. }
  173. //
  174. // See if the use entry is an explicit connection.
  175. //
  176. status = WsGetUserEntry(
  177. &Use,
  178. &LogonId,
  179. &Index,
  180. FALSE
  181. );
  182. UseList = (status == NERR_Success) ? (PUSE_ENTRY) Use.Table[Index].List :
  183. NULL;
  184. if ((status = WsFindUse(
  185. &LogonId,
  186. UseList,
  187. FormattedUseName,
  188. &TreeConnection,
  189. &MatchedPointer,
  190. NULL
  191. )) != NERR_Success) {
  192. RtlReleaseResource(&Use.TableResource);
  193. LocalFree(FormattedUseName);
  194. return status;
  195. }
  196. LocalFree(FormattedUseName);
  197. if (MatchedPointer == NULL) {
  198. //
  199. // UseName specified has an implicit connection. Don't need to hold
  200. // on to Use Table anymore.
  201. //
  202. RtlReleaseResource(&Use.TableResource);
  203. }
  204. status = WsGetUseInfo(
  205. &LogonId,
  206. Level,
  207. TreeConnection,
  208. MatchedPointer,
  209. &Buffer
  210. );
  211. if (MatchedPointer == NULL) {
  212. //
  213. // Close temporary handle to implicit connection.
  214. //
  215. NtClose(TreeConnection);
  216. }
  217. else {
  218. RtlReleaseResource(&Use.TableResource);
  219. }
  220. SET_USE_INFO_POINTER(InfoStruct, Buffer);
  221. IF_DEBUG(USE) {
  222. NetpKdPrint(("[Wksta] NetrUseGetInfo: about to return status=%lu\n",
  223. status));
  224. }
  225. return status;
  226. }
  227. NET_API_STATUS NET_API_FUNCTION
  228. NetrUseEnum(
  229. IN LPTSTR ServerName OPTIONAL,
  230. IN OUT LPUSE_ENUM_STRUCT InfoStruct,
  231. IN DWORD PreferedMaximumLength,
  232. OUT LPDWORD TotalEntries,
  233. IN OUT LPDWORD ResumeHandle OPTIONAL
  234. )
  235. /*++
  236. Routine Description:
  237. This function is the NetUseEnum entry point in the Workstation service.
  238. Arguments:
  239. ServerName - Supplies the name of server to execute this function
  240. InfoStruct - This structure supplies the level of information requested,
  241. returns a pointer to the buffer allocated by the Workstation service
  242. which contains a sequence of information structure of the specified
  243. information level, and returns the number of entries read. The buffer
  244. pointer is set to NULL if return code is not NERR_Success or
  245. ERROR_MORE_DATA, or if EntriesRead returned is 0. The EntriesRead
  246. value is only valid if the return code is NERR_Success or
  247. ERROR_MORE_DATA.
  248. PreferedMaximumLength - Supplies the number of bytes of information
  249. to return in the buffer. If this value is MAXULONG, all available
  250. information will be returned.
  251. TotalEntries - Returns the total number of entries available. This value
  252. is only valid if the return code is NERR_Success or ERROR_MORE_DATA.
  253. ResumeHandle - Supplies a handle to resume the enumeration from where it
  254. left off the last time through. Returns the resume handle if return
  255. code is ERROR_MORE_DATA.
  256. Return Value:
  257. NET_API_STATUS - NERR_Success or reason for failure.
  258. --*/
  259. {
  260. NET_API_STATUS status;
  261. LUID LogonId; // Logon Id of user
  262. DWORD Index; // Index to user entry in Use Table
  263. PUSE_ENTRY UseList; // Pointer to user's use list
  264. DWORD EnumConnectionHint = 0; // Hint size from redirector
  265. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  266. DWORD TotalImplicit; // Length of ImplicitList
  267. LPBYTE ImplicitList; // List of information on implicit
  268. // connections
  269. LPBYTE Buffer = NULL;
  270. DWORD EntriesRead = 0;
  271. DWORD Level = InfoStruct->Level;
  272. if (Level > 2) {
  273. return ERROR_INVALID_LEVEL;
  274. }
  275. if (InfoStruct->UseInfo.Level2 == NULL) {
  276. return ERROR_INVALID_PARAMETER;
  277. }
  278. try {
  279. SET_USE_ENUM_POINTER(InfoStruct, NULL, 0);
  280. }
  281. except(EXCEPTION_EXECUTE_HANDLER) {
  282. return ERROR_INVALID_PARAMETER;
  283. }
  284. UNREFERENCED_PARAMETER(ServerName);
  285. //
  286. // Impersonate caller and get the logon id
  287. //
  288. if ((status = WsImpersonateAndGetLogonId(&LogonId)) != NERR_Success) {
  289. return status;
  290. }
  291. //
  292. // Ask the redirector to enumerate the information of implicit connections
  293. // established by the caller.
  294. //
  295. Rrp.Type = GetConnectionInfo;
  296. Rrp.Version = REQUEST_PACKET_VERSION;
  297. RtlCopyLuid(&Rrp.LogonId, &LogonId);
  298. Rrp.Level = Level;
  299. Rrp.Parameters.Get.ResumeHandle = 0;
  300. if ((status = WsDeviceControlGetInfo(
  301. Redirector,
  302. WsRedirDeviceHandle,
  303. FSCTL_LMR_ENUMERATE_CONNECTIONS,
  304. &Rrp,
  305. sizeof(LMR_REQUEST_PACKET),
  306. (LPBYTE *) &ImplicitList,
  307. MAXULONG,
  308. EnumConnectionHint,
  309. NULL
  310. )) != NERR_Success) {
  311. return status;
  312. }
  313. //
  314. // If successful in getting all the implicit connection info from the
  315. // redirector, expect the total entries available to be equal to entries
  316. // read.
  317. //
  318. TotalImplicit = Rrp.Parameters.Get.TotalEntries;
  319. NetpAssert(TotalImplicit == Rrp.Parameters.Get.EntriesRead);
  320. //
  321. // Serialize access to Use Table.
  322. //
  323. if (! RtlAcquireResourceShared(&Use.TableResource, TRUE)) {
  324. status = NERR_InternalError;
  325. goto CleanUp;
  326. }
  327. //
  328. // See if the user has explicit connection entries in the Use Table.
  329. //
  330. status = WsGetUserEntry(
  331. &Use,
  332. &LogonId,
  333. &Index,
  334. FALSE
  335. );
  336. UseList = (status == NERR_Success) ? (PUSE_ENTRY) Use.Table[Index].List :
  337. NULL;
  338. //
  339. // User has no connections if both implicit and explicit lists are empty.
  340. //
  341. if (TotalImplicit == 0 && UseList == NULL) {
  342. *TotalEntries = 0;
  343. status = NERR_Success;
  344. goto CleanUp;
  345. }
  346. status = WsEnumUseInfo(
  347. &LogonId,
  348. Level,
  349. UseList,
  350. ImplicitList,
  351. TotalImplicit,
  352. &Buffer,
  353. PreferedMaximumLength,
  354. &EntriesRead,
  355. TotalEntries,
  356. ResumeHandle
  357. );
  358. CleanUp:
  359. MIDL_user_free(ImplicitList);
  360. RtlReleaseResource(&Use.TableResource);
  361. SET_USE_ENUM_POINTER(InfoStruct, Buffer, EntriesRead);
  362. IF_DEBUG(USE) {
  363. NetpKdPrint(("[Wksta] NetrUseEnum: about to return status=%lu\n",
  364. status));
  365. }
  366. return status;
  367. }
  368. STATIC
  369. NET_API_STATUS
  370. WsGetUseInfo(
  371. IN PLUID LogonId,
  372. IN DWORD Level,
  373. IN HANDLE TreeConnection,
  374. IN PUSE_ENTRY UseEntry,
  375. OUT LPBYTE *OutputBuffer
  376. )
  377. /*++
  378. Routine Description:
  379. This function allocates the output buffer of exactly the required size
  380. and fill it with the use information that is requested by the caller of
  381. NetUseGetInfo.
  382. Arguments:
  383. LogonId - Supplies a pointer to the user's Logon Id.
  384. Level - Supplies the level of information to be returned.
  385. TreeConnection - Supplies the handle to the tree connection which user is
  386. requesting information about.
  387. UseEntry - Supplies a pointer to the use entry if the tree connection is
  388. an explicit connection.
  389. OutputBuffer - Returns a pointer to the buffer allocated by this
  390. routine which contains the use information requested. This pointer
  391. is set to NULL if return code is not NERR_Success.
  392. Return Value:
  393. NET_API_STATUS - NERR_Success or reason for failure.
  394. --*/
  395. {
  396. NET_API_STATUS status;
  397. DWORD OutputBufferLength;
  398. LPBYTE FixedPortion;
  399. LPTSTR EndOfVariableData;
  400. PLMR_CONNECTION_INFO_2 ConnectionInfo;
  401. //
  402. // Get information of the requested connection from redirector
  403. // Only send Level 0,1,2 to redir. Send 2 in place of 3.
  404. //
  405. if ((status = WsGetRedirUseInfo(
  406. LogonId,
  407. (Level > 2 ? 2 : Level),
  408. TreeConnection,
  409. (LPBYTE *) &ConnectionInfo
  410. )) != NERR_Success) {
  411. return status;
  412. }
  413. OutputBufferLength =
  414. USE_TOTAL_LENGTH(
  415. Level,
  416. ((UseEntry != NULL) ?
  417. (UseEntry->LocalLength + UseEntry->Remote->UncNameLength +
  418. 2) * sizeof(TCHAR) :
  419. ConnectionInfo->UNCName.Length + (2 * sizeof(TCHAR))),
  420. ConnectionInfo->UserName.Length + sizeof(TCHAR)
  421. );
  422. if( Level >= 2 && ConnectionInfo->DomainName.Length != 0 ) {
  423. OutputBufferLength += ConnectionInfo->DomainName.Length + sizeof(TCHAR);
  424. }
  425. //
  426. // Allocate output buffer to be filled in and returned to user
  427. //
  428. if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
  429. return ERROR_NOT_ENOUGH_MEMORY;
  430. }
  431. RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
  432. FixedPortion = *OutputBuffer;
  433. EndOfVariableData = (LPTSTR) ((DWORD_PTR) FixedPortion + OutputBufferLength);
  434. if (UseEntry != NULL) {
  435. //
  436. // Use the UNC name of WorkStation Services instead of RDR which doesn't include the
  437. // deep net use path
  438. //
  439. ConnectionInfo->UNCName.Length =
  440. ConnectionInfo->UNCName.MaximumLength = (USHORT)UseEntry->Remote->UncNameLength * sizeof(TCHAR);
  441. ConnectionInfo->UNCName.Buffer = (PWSTR)UseEntry->Remote->UncName;
  442. }
  443. //
  444. // Combine the redirector information (if any) with the use entry
  445. // information into one output buffer.
  446. //
  447. status = WsGetCombinedUseInfo(
  448. Level,
  449. USE_FIXED_LENGTH(Level),
  450. UseEntry,
  451. ConnectionInfo,
  452. &FixedPortion,
  453. &EndOfVariableData,
  454. NULL
  455. );
  456. //
  457. // We should have allocated enough memory for all the data
  458. //
  459. NetpAssert(status == NERR_Success);
  460. //
  461. // If not successful in getting any data, free the output buffer and set
  462. // it to NULL.
  463. //
  464. if (status != NERR_Success) {
  465. MIDL_user_free(*OutputBuffer);
  466. *OutputBuffer = NULL;
  467. }
  468. MIDL_user_free(ConnectionInfo);
  469. return status;
  470. }
  471. STATIC
  472. NET_API_STATUS
  473. WsEnumUseInfo(
  474. IN PLUID LogonId,
  475. IN DWORD Level,
  476. IN PUSE_ENTRY UseList,
  477. IN LPBYTE ImplicitList,
  478. IN DWORD TotalImplicit,
  479. OUT LPBYTE *OutputBuffer,
  480. IN DWORD PreferedMaximumLength,
  481. OUT LPDWORD EntriesRead,
  482. OUT LPDWORD TotalEntries,
  483. IN OUT LPDWORD ResumeHandle OPTIONAL
  484. )
  485. /*++
  486. Routine Description:
  487. This function allocates the output buffer of exactly the required size
  488. and fill it with the use information that is requested by the caller of
  489. NetUseEnum.
  490. Arguments:
  491. LogonId - Supplies a pointer to the user's Logon Id.
  492. Level - Supplies the level of information to be returned.
  493. UseList - Supplies a pointer to the use list.
  494. ImplicitList - Supplies an array of information from the redirector
  495. about each implicit connection.
  496. TotalImplicit - Supplies the number of entries in ImplicitList.
  497. OutputBuffer - Returns a pointer to the buffer allocated by this
  498. routine which contains the use information requested. This pointer
  499. is set to NULL if return code is not NERR_Success.
  500. PreferedMaximumLength - Supplies the number of bytes of information
  501. to return in the buffer. If this value is MAXULONG, we will try
  502. to return all available information if there is enough memory
  503. resource.
  504. EntriesRead - Returns the number of entries read into the buffer. This
  505. value is returned only if the return code is NERR_Success or
  506. ERROR_MORE_DATA.
  507. TotalEntries - Returns the remaining total number of entries that would
  508. be read into output buffer if it has enough memory to hold all entries.
  509. This value is returned only if the return code is NERR_Success or
  510. ERROR_MORE_DATA.
  511. ResumeHandle - Supplies the resume key to begin enumeration, and returns
  512. the key to the next entry to resume the enumeration if the current
  513. call returns ERROR_MORE_DATA.
  514. Return Value:
  515. NET_API_STATUS - NERR_Success or reason for failure.
  516. --*/
  517. {
  518. NET_API_STATUS status;
  519. DWORD i;
  520. DWORD OutputBufferLength = 0;
  521. PUSE_ENTRY UseEntry = UseList;
  522. DWORD TotalExplicit = 0;
  523. //
  524. // Get the use information from the redirector for each explicit connection
  525. //
  526. while (UseEntry != NULL) {
  527. PLMR_CONNECTION_INFO_2 ci2;
  528. //
  529. // Get tree connection information from the redirector.
  530. //
  531. ci2 = NULL;
  532. if ((status = WsGetRedirUseInfo(
  533. LogonId,
  534. Level,
  535. UseEntry->TreeConnection,
  536. (LPBYTE *) &ci2
  537. )) != NERR_Success) {
  538. if( ci2 != NULL )
  539. MIDL_user_free( ci2 );
  540. return status;
  541. }
  542. if( ci2 == NULL ) {
  543. return NERR_InternalError;
  544. }
  545. //
  546. // Use the UNC name of WorkStation Services instead of RDR which doesn't include the
  547. // deep net use path
  548. //
  549. ci2->UNCName.Length =
  550. ci2->UNCName.MaximumLength = (USHORT)UseEntry->Remote->UncNameLength * sizeof(TCHAR);
  551. ci2->UNCName.Buffer = (PWSTR)UseEntry->Remote->UncName;
  552. //
  553. // While we are here, add up the amount of memory needed to hold the
  554. // explicit connection entries including information from the redir
  555. // like username.
  556. //
  557. if (PreferedMaximumLength == MAXULONG) {
  558. OutputBufferLength +=
  559. USE_TOTAL_LENGTH(
  560. Level,
  561. (UseEntry->LocalLength +
  562. ci2->UNCName.Length +
  563. 2) * sizeof(TCHAR),
  564. (ci2->UserName.Length +
  565. sizeof(TCHAR))
  566. );
  567. if( Level >= 2 && ci2->DomainName.Length != 0 ) {
  568. OutputBufferLength += ci2->DomainName.Length + sizeof(TCHAR);
  569. }
  570. }
  571. MIDL_user_free( ci2 );
  572. //
  573. // Sum up the number of explicit connections.
  574. //
  575. TotalExplicit++;
  576. UseEntry = UseEntry->Next;
  577. }
  578. IF_DEBUG(USE) {
  579. NetpKdPrint(("[Wksta] NetrUseEnum: length of explicit info %lu\n",
  580. OutputBufferLength));
  581. }
  582. //
  583. // If the user requests to enumerate all use entries with
  584. // PreferedMaximumLength == MAXULONG, add up the total number of bytes
  585. // we need to allocate for the output buffer. We know the amount we
  586. // need for explicit connections from above; now add the lengths of
  587. // implicit connection information.
  588. //
  589. if (PreferedMaximumLength == MAXULONG) {
  590. //
  591. // Pointer to the next entry in the ImplicitList is computed based
  592. // on the level of information requested from the redirector.
  593. //
  594. LPBYTE ImplicitEntry;
  595. DWORD ImplicitEntryLength = REDIR_ENUM_INFO_FIXED_LENGTH(Level);
  596. //
  597. // Add up the buffer size needed to hold the implicit connection
  598. // information
  599. //
  600. for (ImplicitEntry = ImplicitList, i = 0; i < TotalImplicit;
  601. ImplicitEntry += ImplicitEntryLength, i++) {
  602. OutputBufferLength +=
  603. USE_TOTAL_LENGTH(
  604. Level,
  605. ((PLMR_CONNECTION_INFO_2) ImplicitEntry)->UNCName.Length
  606. + (2 * sizeof(TCHAR)),
  607. ((PLMR_CONNECTION_INFO_2) ImplicitEntry)->UserName.Length
  608. + sizeof(TCHAR)
  609. );
  610. if( Level >= 2 ) {
  611. OutputBufferLength += (DNS_MAX_NAME_LENGTH + 1)*sizeof(TCHAR);
  612. }
  613. }
  614. IF_DEBUG(USE) {
  615. NetpKdPrint((
  616. "[Wksta] NetrUseEnum: length of implicit & explicit info %lu\n",
  617. OutputBufferLength));
  618. }
  619. }
  620. else {
  621. //
  622. // We will return as much as possible that fits into this specified
  623. // buffer size.
  624. //
  625. OutputBufferLength = ROUND_UP_COUNT(PreferedMaximumLength, ALIGN_WCHAR);
  626. if (OutputBufferLength < USE_FIXED_LENGTH(Level)) {
  627. *OutputBuffer = NULL;
  628. *EntriesRead = 0;
  629. *TotalEntries = TotalExplicit + TotalImplicit;
  630. return ERROR_MORE_DATA;
  631. }
  632. }
  633. //
  634. // Allocate the output buffer
  635. //
  636. if ((*OutputBuffer = MIDL_user_allocate(OutputBufferLength)) == NULL) {
  637. return ERROR_NOT_ENOUGH_MEMORY;
  638. }
  639. RtlZeroMemory((PVOID) *OutputBuffer, OutputBufferLength);
  640. //
  641. // Get the information
  642. //
  643. status = WsEnumCombinedUseInfo(
  644. LogonId,
  645. Level,
  646. ImplicitList,
  647. TotalImplicit,
  648. UseList,
  649. *OutputBuffer,
  650. OutputBufferLength,
  651. EntriesRead,
  652. TotalEntries,
  653. ResumeHandle
  654. );
  655. //
  656. // WsEnumCombinedUseInfo returns in *TotalEntries the number of
  657. // remaining unread entries. Therefore, the real total is the
  658. // sum of this returned value and the number of entries read.
  659. //
  660. (*TotalEntries) += (*EntriesRead);
  661. //
  662. // If the caller asked for all available data with
  663. // PreferedMaximumLength == MAXULONG and our buffer overflowed, free the
  664. // output buffer and set its pointer to NULL.
  665. //
  666. if (PreferedMaximumLength == MAXULONG && status == ERROR_MORE_DATA) {
  667. MIDL_user_free(*OutputBuffer);
  668. *OutputBuffer = NULL;
  669. //
  670. // PreferedMaximumLength == MAXULONG and buffer overflowed means
  671. // we do not have enough memory to satisfy the request.
  672. //
  673. if (status == ERROR_MORE_DATA) {
  674. status = ERROR_NOT_ENOUGH_MEMORY;
  675. }
  676. }
  677. else {
  678. if (*EntriesRead == 0) {
  679. MIDL_user_free(*OutputBuffer);
  680. *OutputBuffer = NULL;
  681. }
  682. }
  683. return status;
  684. }
  685. STATIC
  686. NET_API_STATUS
  687. WsEnumCombinedUseInfo(
  688. IN PLUID LogonId,
  689. IN DWORD Level,
  690. IN LPBYTE ImplicitList,
  691. IN DWORD TotalImplicit,
  692. IN PUSE_ENTRY UseList,
  693. OUT LPBYTE OutputBuffer,
  694. IN DWORD OutputBufferLength,
  695. OUT LPDWORD EntriesRead,
  696. OUT LPDWORD EntriesUnread,
  697. IN OUT LPDWORD ResumeHandle OPTIONAL
  698. )
  699. /*++
  700. Routine Description:
  701. This function lists all existing connections by going through the
  702. the explicit connections in the Use Table, and the implicit connections
  703. from the redirector.
  704. Arguments:
  705. Level - Supplies the level of information to be returned.
  706. ImplicitList - Supplies an array implicit connections from the redirector.
  707. TotalImplicit - Supplies the number of entries in ImplicitList.
  708. UseList - Supplies a pointer to the use list.
  709. OutputBuffer - Supplies the output buffer which receives the requested
  710. information.
  711. OutputBufferLength - Supplies the length of the output buffer.
  712. EntriesRead - Returns the number of entries written into the output
  713. buffer.
  714. EntriesUnread - Returns the remaining total number of unread entries.
  715. This value is returned only if the return code is NERR_Success or
  716. ERROR_MORE_DATA.
  717. ResumeHandle - Supplies the resume key to begin enumeration, and returns
  718. the key to the next entry to resume the enumeration if the current
  719. call returns ERROR_MORE_DATA.
  720. Return Value:
  721. NERR_Success - All entries fit into the output buffer.
  722. ERROR_MORE_DATA - 0 or more entries were written into the output buffer
  723. but not all entries fit.
  724. --*/
  725. {
  726. DWORD i;
  727. NET_API_STATUS status;
  728. DWORD UseFixedLength = USE_FIXED_LENGTH(Level);
  729. LPBYTE FixedPortion = OutputBuffer;
  730. LPTSTR EndOfVariableData = (LPTSTR) ((DWORD_PTR) FixedPortion +
  731. OutputBufferLength);
  732. //
  733. // Pointer to the next entry in the ImplicitList is computed based on the
  734. // level of information requested from the redirector.
  735. //
  736. LPBYTE ImplicitEntry;
  737. DWORD ImplicitEntryLength = REDIR_ENUM_INFO_FIXED_LENGTH(Level);
  738. DWORD StartEnumeration = 0;
  739. BOOL OnlyRedirectorList = FALSE;
  740. if (ARGUMENT_PRESENT(ResumeHandle)) {
  741. StartEnumeration = *ResumeHandle & ~(REDIR_LIST);
  742. OnlyRedirectorList = *ResumeHandle & REDIR_LIST;
  743. }
  744. IF_DEBUG(USE) {
  745. NetpKdPrint(("\nStartEnumeration=%lu\n, OnlyRedir=%u\n",
  746. StartEnumeration, OnlyRedirectorList));
  747. }
  748. *EntriesRead = 0;
  749. //
  750. // Enumerate explicit connections. This is done only if resume handle
  751. // says to start enumeration from the explicit list.
  752. //
  753. if (! OnlyRedirectorList) {
  754. for( ; UseList != NULL; UseList = UseList->Next ) {
  755. PLMR_CONNECTION_INFO_2 ci2;
  756. if( StartEnumeration > UseList->ResumeKey ) {
  757. continue;
  758. }
  759. //
  760. // Get tree connection information from the redirector.
  761. //
  762. ci2 = NULL;
  763. status = WsGetRedirUseInfo( LogonId, Level, UseList->TreeConnection, (LPBYTE *) &ci2 );
  764. if( status != NERR_Success || ci2 == NULL ) {
  765. if( ci2 != NULL )
  766. MIDL_user_free( ci2 );
  767. continue;
  768. }
  769. //
  770. // Use the UNC name of WorkStation Services instead of RDR which doesn't include the
  771. // deep net use path
  772. //
  773. ci2->UNCName.Length =
  774. ci2->UNCName.MaximumLength = (USHORT)UseList->Remote->UncNameLength * sizeof(TCHAR);
  775. ci2->UNCName.Buffer = (PWSTR)UseList->Remote->UncName;
  776. status = WsGetCombinedUseInfo(
  777. Level,
  778. UseFixedLength,
  779. UseList,
  780. ci2,
  781. &FixedPortion,
  782. &EndOfVariableData,
  783. EntriesRead );
  784. MIDL_user_free( ci2 );
  785. if( status == ERROR_MORE_DATA ) {
  786. if (ARGUMENT_PRESENT(ResumeHandle)) {
  787. *ResumeHandle = UseList->ResumeKey;
  788. }
  789. *EntriesUnread = TotalImplicit;
  790. while (UseList != NULL) {
  791. (*EntriesUnread)++;
  792. UseList = UseList->Next;
  793. }
  794. return status;
  795. }
  796. }
  797. //
  798. // Finished the explicit list. Start from the beginning of implicit
  799. // list.
  800. //
  801. StartEnumeration = 0;
  802. }
  803. //
  804. // Enumerate implicit connections
  805. //
  806. for (ImplicitEntry = ImplicitList, i = 0; i < TotalImplicit;
  807. ImplicitEntry += ImplicitEntryLength, i++) {
  808. IF_DEBUG(USE) {
  809. NetpKdPrint(("RedirList->ResumeKey=%lu\n",
  810. ((PLMR_CONNECTION_INFO_2) ImplicitEntry)->ResumeKey));
  811. }
  812. if (StartEnumeration <=
  813. ((PLMR_CONNECTION_INFO_2) ImplicitEntry)->ResumeKey) {
  814. if (WsGetCombinedUseInfo(
  815. Level,
  816. UseFixedLength,
  817. NULL,
  818. (PLMR_CONNECTION_INFO_2) ImplicitEntry,
  819. &FixedPortion,
  820. &EndOfVariableData,
  821. EntriesRead
  822. ) == ERROR_MORE_DATA) {
  823. if (ARGUMENT_PRESENT(ResumeHandle)) {
  824. *ResumeHandle = ((PLMR_CONNECTION_INFO_2)
  825. ImplicitEntry)->ResumeKey;
  826. *ResumeHandle |= REDIR_LIST;
  827. }
  828. *EntriesUnread = TotalImplicit - i;
  829. return ERROR_MORE_DATA;
  830. }
  831. }
  832. }
  833. //
  834. // Successful enumeration. Reset the resume handle to start from the
  835. // beginning.
  836. //
  837. if (ARGUMENT_PRESENT(ResumeHandle)) {
  838. *ResumeHandle = 0;
  839. }
  840. //
  841. // There are no more remaining entries.
  842. //
  843. *EntriesUnread = 0;
  844. return NERR_Success;
  845. }
  846. STATIC
  847. NET_API_STATUS
  848. WsGetRedirUseInfo(
  849. IN PLUID LogonId,
  850. IN DWORD Level,
  851. IN HANDLE TreeConnection,
  852. OUT LPBYTE *OutputBuffer
  853. )
  854. /*++
  855. Routine Description:
  856. This function gets the connection information from the redirector given
  857. the handle to the connection.
  858. Arguments:
  859. LogonId - Supplies a pointer to the user's Logon Id.
  860. Level - Supplies the level of information to be returned.
  861. TreeConnection - Supplies the handle to the tree connection which user is
  862. requesting information about.
  863. OutputBuffer - Returns a pointer to the buffer allocated by this
  864. routine which contains the connection information requested. This
  865. pointer is set to NULL if return code is not NERR_Success.
  866. Return Value:
  867. NET_API_STATUS - NERR_Success or reason for failure.
  868. --*/
  869. {
  870. LMR_REQUEST_PACKET Rrp;
  871. //
  872. // Get information of the requested connection from redirector
  873. //
  874. Rrp.Type = GetConnectionInfo;
  875. Rrp.Version = REQUEST_PACKET_VERSION;
  876. RtlCopyLuid(&Rrp.LogonId, LogonId);
  877. Rrp.Level = Level;
  878. Rrp.Parameters.Get.ResumeHandle = 0;
  879. Rrp.Parameters.Get.TotalBytesNeeded = 0;
  880. return WsDeviceControlGetInfo(
  881. Redirector,
  882. TreeConnection,
  883. FSCTL_LMR_GET_CONNECTION_INFO,
  884. &Rrp,
  885. sizeof(LMR_REQUEST_PACKET),
  886. OutputBuffer,
  887. MAXULONG,
  888. HINT_REDIR_INFO(Level),
  889. NULL
  890. );
  891. }
  892. STATIC
  893. NET_API_STATUS
  894. WsGetCombinedUseInfo(
  895. IN DWORD Level,
  896. IN DWORD UseFixedLength,
  897. IN PUSE_ENTRY UseEntry,
  898. IN PLMR_CONNECTION_INFO_2 UncEntry,
  899. IN OUT LPBYTE *FixedPortion,
  900. IN OUT LPTSTR *EndOfVariableData,
  901. IN OUT LPDWORD EntriesRead OPTIONAL
  902. )
  903. /*++
  904. Routine Description:
  905. This function puts together the use information from redirector and from
  906. the Use Table (if any) into the output buffer. It increments the
  907. EntriesRead variable when a use entry is written into the output buffer.
  908. Arguments:
  909. Level - Supplies the level of information to be returned.
  910. UseFixedLength - Supplies the length of the fixed portion of the use
  911. information returned.
  912. UseEntry - Supplies the pointer to the use entry in the Use Table if it
  913. is an explicit connection.
  914. UncEntry - Supplies a pointer to the use information retrieved from the
  915. redirector.
  916. FixedPortion - Supplies a pointer to the output buffer where the next
  917. entry of the fixed portion of the use information will be written.
  918. This pointer is updated to point to the next fixed portion entry
  919. after a use entry is written.
  920. EndOfVariableData - Supplies a pointer just off the last available byte
  921. in the output buffer. This is because the variable portion of the use
  922. information is written into the output buffer starting from the end.
  923. This pointer is updated after any variable length information is
  924. written to the output buffer.
  925. EntriesRead - Supplies a running total of the number of entries read
  926. into the buffer. This value is incremented every time a use entry is
  927. successfully written into the output buffer.
  928. Return Value:
  929. NERR_Success - The current entry fits into the output buffer.
  930. ERROR_MORE_DATA - The current entry does not fit into the output buffer.
  931. --*/
  932. {
  933. if (((DWORD_PTR) *FixedPortion + UseFixedLength) >=
  934. (DWORD_PTR) *EndOfVariableData) {
  935. //
  936. // Fixed length portion does not fit.
  937. //
  938. return ERROR_MORE_DATA;
  939. }
  940. if (! WsFillUseBuffer(
  941. Level,
  942. UseEntry,
  943. UncEntry,
  944. FixedPortion,
  945. EndOfVariableData,
  946. UseFixedLength
  947. )) {
  948. //
  949. // Variable length portion does not fit.
  950. //
  951. return ERROR_MORE_DATA;
  952. }
  953. if (ARGUMENT_PRESENT(EntriesRead)) {
  954. (*EntriesRead)++;
  955. }
  956. return NERR_Success;
  957. }
  958. STATIC
  959. BOOL
  960. WsFillUseBuffer(
  961. IN DWORD Level,
  962. IN PUSE_ENTRY UseEntry,
  963. IN PLMR_CONNECTION_INFO_2 UncEntry,
  964. IN OUT LPBYTE *FixedPortion,
  965. IN OUT LPTSTR *EndOfVariableData,
  966. IN DWORD UseFixedLength
  967. )
  968. /*++
  969. Routine Description:
  970. This function fills an entry in the output buffer with the supplied use
  971. information, and updates the FixedPortion and EndOfVariableData pointers.
  972. NOTE: This function assumes that the fixed size portion will fit into
  973. the output buffer.
  974. It also assumes that info structure level 2 is a superset of
  975. info structure level 1, which in turn is a superset of info
  976. structure level 0, and that the offset to each common field is
  977. exactly the same. This allows us to take advantage of a switch
  978. statement without a break between the levels.
  979. Arguments:
  980. Level - Supplies the level of information to be returned.
  981. UseEntry - Supplies the pointer to the use entry in the Use Table if it is
  982. an explicit connection.
  983. UncEntry - Supplies a pointer to the use information retrieved from the
  984. redirector.
  985. FixedPortion - Supplies a pointer to the output buffer where the next
  986. entry of the fixed portion of the use information will be written.
  987. This pointer is updated after a use entry is written to the
  988. output buffer.
  989. EndOfVariableData - Supplies a pointer just off the last available byte
  990. in the output buffer. This is because the variable portion of the use
  991. information is written into the output buffer starting from the end.
  992. This pointer is updated after any variable length information is
  993. written to the output buffer.
  994. UseFixedLength - Supplies the number of bytes needed to hold the fixed
  995. size portion.
  996. Return Value:
  997. Returns TRUE if entire entry fits into output buffer, FALSE otherwise.
  998. --*/
  999. {
  1000. PUSE_INFO_2 UseInfo = (PUSE_INFO_2) *FixedPortion;
  1001. *FixedPortion += UseFixedLength;
  1002. switch (Level) {
  1003. case 3:
  1004. if(UseEntry != NULL && (UseEntry->Flags & USE_DEFAULT_CREDENTIALS)) {
  1005. ((PUSE_INFO_3)*FixedPortion)->ui3_flags |= USE_DEFAULT_CREDENTIALS;
  1006. }
  1007. case 2:
  1008. if (! NetpCopyStringToBuffer(
  1009. UncEntry->UserName.Buffer,
  1010. UncEntry->UserName.Length / sizeof(TCHAR),
  1011. *FixedPortion,
  1012. EndOfVariableData,
  1013. &UseInfo->ui2_username
  1014. )) {
  1015. return FALSE;
  1016. }
  1017. if( UncEntry->DomainName.Length != 0 ) {
  1018. if(! NetpCopyStringToBuffer(
  1019. UncEntry->DomainName.Buffer,
  1020. UncEntry->DomainName.Length / sizeof(TCHAR),
  1021. *FixedPortion,
  1022. EndOfVariableData,
  1023. &UseInfo->ui2_domainname
  1024. )) {
  1025. return FALSE;
  1026. }
  1027. }
  1028. case 1:
  1029. UseInfo->ui2_password = NULL;
  1030. UseInfo->ui2_status = UncEntry->ConnectionStatus;
  1031. if ((UseEntry != NULL) && (UseEntry->Local != NULL)
  1032. && (UseEntry->LocalLength > 2)) {
  1033. //
  1034. // Reassign the status of the connection if it is paused
  1035. //
  1036. if (WsRedirectionPaused(UseEntry->Local)) {
  1037. UseInfo->ui2_status = USE_PAUSED;
  1038. }
  1039. }
  1040. switch (UncEntry->SharedResourceType) {
  1041. case FILE_DEVICE_DISK:
  1042. UseInfo->ui2_asg_type = USE_DISKDEV;
  1043. break;
  1044. case FILE_DEVICE_PRINTER:
  1045. UseInfo->ui2_asg_type = USE_SPOOLDEV;
  1046. break;
  1047. case FILE_DEVICE_SERIAL_PORT:
  1048. UseInfo->ui2_asg_type = USE_CHARDEV;
  1049. break;
  1050. case FILE_DEVICE_NAMED_PIPE:
  1051. UseInfo->ui2_asg_type = USE_IPC;
  1052. break;
  1053. default:
  1054. NetpKdPrint((
  1055. "WsFillUseBuffer: Unknown shared resource type %d.\n",
  1056. UncEntry->SharedResourceType
  1057. ));
  1058. case FILE_DEVICE_UNKNOWN:
  1059. UseInfo->ui2_asg_type = USE_WILDCARD;
  1060. break;
  1061. }
  1062. UseInfo->ui2_refcount = UncEntry->NumberFilesOpen;
  1063. UseInfo->ui2_usecount = (UseEntry == NULL) ? 0 :
  1064. UseEntry->Remote->TotalUseCount;
  1065. case 0:
  1066. if (UseEntry != NULL) {
  1067. //
  1068. // Explicit connection
  1069. //
  1070. if (! NetpCopyStringToBuffer(
  1071. UseEntry->Local,
  1072. UseEntry->LocalLength,
  1073. *FixedPortion,
  1074. EndOfVariableData,
  1075. &UseInfo->ui2_local
  1076. )) {
  1077. return FALSE;
  1078. }
  1079. }
  1080. else {
  1081. //
  1082. // Implicit connection
  1083. //
  1084. if (! NetpCopyStringToBuffer(
  1085. NULL,
  1086. 0,
  1087. *FixedPortion,
  1088. EndOfVariableData,
  1089. &UseInfo->ui2_local
  1090. )) {
  1091. return FALSE;
  1092. }
  1093. }
  1094. if (! NetpCopyStringToBuffer(
  1095. UncEntry->UNCName.Buffer,
  1096. UncEntry->UNCName.Length / sizeof(TCHAR),
  1097. *FixedPortion,
  1098. EndOfVariableData,
  1099. &UseInfo->ui2_remote
  1100. )) {
  1101. return FALSE;
  1102. }
  1103. break;
  1104. default:
  1105. //
  1106. // This should never happen.
  1107. //
  1108. NetpKdPrint(("WsFillUseBuffer: Invalid level %u.\n", Level));
  1109. NetpAssert(FALSE);
  1110. }
  1111. return TRUE;
  1112. }
  1113.