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.

2753 lines
82 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. enum.cxx
  5. Abstract:
  6. Contains the entry points for the WinNet Enum API supported by the
  7. Multi-Provider Router. The following functions are in this file:
  8. WNetOpenEnumW
  9. WNetEnumResourceW
  10. WNetCloseEnum
  11. MprOpenEnumConnect
  12. MprOpenEnumNetwork
  13. MprEnumConnect
  14. MprEnumNetwork
  15. MprProviderEnum
  16. MprCopyResource
  17. MprCopyProviderEnum
  18. MprProviderOpen
  19. MprOpenRemember
  20. MprEnumRemembered
  21. MprMultiStrBuffSize
  22. Author:
  23. Dan Lafferty (danl) 14-Oct-1991
  24. Environment:
  25. User Mode -Win32
  26. Notes:
  27. Revision History:
  28. 14-Oct-1991 danl
  29. created
  30. 21-Sep-1992 KeithMo
  31. Handle odd-sized buffers.
  32. 02-Nov-1992 danl
  33. Fail with NO_NETWORK if there are no providers.
  34. 02-Mar-1995 anirudhs
  35. Add support for RESOURCE_CONTEXT.
  36. 17-Jul-1995 anirudhs
  37. Add recognition (but not true support) of RESOURCE_RECENT.
  38. Clean up code for detecting top-level enum.
  39. 03-Aug-1995 anirudhs
  40. WNetEnumResourceW: Allow a *lpcCount of 0.
  41. 15-Sep-1995 anirudhs
  42. MprEnumRemembered: Fail after all resources have been enumerated.
  43. 24-Sep-1995 anirudhs
  44. Add support for customization of the RESOURCE_CONTEXT enumeration
  45. based on policy settings.
  46. 11-Apr-1996 anirudhs
  47. Use CRoutedOperation in one case of WNetOpenEnumW.
  48. 16-Mar-1999 jschwart
  49. Add support for RESOURCE_SHAREABLE
  50. 05-May-1999 jschwart
  51. Make provider addition/removal dynamic
  52. --*/
  53. //
  54. // INCLUDES
  55. //
  56. #include "precomp.hxx"
  57. #include <memory.h> // memcpy
  58. #include <lmcons.h> // needed for netlib.h
  59. #include <regstr.h> // Registry keys and value names
  60. //
  61. // EXTERNALS
  62. //
  63. extern DWORD GlobalNumActiveProviders;
  64. extern HMODULE hDLL;
  65. //
  66. // DATA STRUCTURES
  67. //
  68. //
  69. // "Manually" align headers and put pointers first in ENUM
  70. // structures to avoid Win64 alignment faults. Keep Key as
  71. // the first field in the header so MPR knows where to check
  72. // to see what type of enum it is.
  73. //
  74. typedef struct _CONNECT_HEADER
  75. {
  76. DWORD Key;
  77. DWORD ReturnRoot;
  78. DWORD dwNumProviders;
  79. DWORD dwNumActiveProviders;
  80. }
  81. CONNECT_HEADER, *LPCONNECT_HEADER;
  82. typedef struct _CONNECT_ENUM
  83. {
  84. HANDLE ProviderEnumHandle;
  85. HINSTANCE hProviderDll; // Refcount the provider DLL
  86. PF_NPEnumResource pfEnumResource;
  87. PF_NPCloseEnum pfCloseEnum;
  88. DWORD State;
  89. }
  90. CONNECT_ENUM, *LPCONNECT_ENUM;
  91. typedef struct _NETWORK_HEADER
  92. {
  93. DWORD Key;
  94. DWORD dwNumProviders;
  95. DWORD dwNumActiveProviders;
  96. DWORD dwPad;
  97. }
  98. NETWORK_HEADER, *LPNETWORK_HEADER;
  99. typedef struct _NETWORK_ENUM
  100. {
  101. HINSTANCE hProviderDll;
  102. LPNETRESOURCE lpnr;
  103. DWORD State;
  104. }
  105. NETWORK_ENUM, *LPNETWORK_ENUM;
  106. typedef struct _ENUM_HANDLE
  107. {
  108. DWORD Key;
  109. DWORD dwPad;
  110. HANDLE EnumHandle;
  111. HINSTANCE hProviderDll;
  112. PF_NPEnumResource pfEnumResource;
  113. PF_NPCloseEnum pfCloseEnum;
  114. }
  115. ENUM_HANDLE, *LPENUM_HANDLE;
  116. typedef struct _REMEMBER_HANDLE
  117. {
  118. DWORD Key;
  119. DWORD dwPad;
  120. HKEY ConnectKey;
  121. DWORD KeyIndex;
  122. DWORD ConnectionType;
  123. }
  124. REMEMBER_HANDLE, *LPREMEMBER_HANDLE;
  125. //
  126. // CONSTANTS
  127. //
  128. #define DONE 1
  129. #define MORE_ENTRIES 2
  130. #define NOT_OPENED 3
  131. #define CONNECT_TABLE_KEY 0x6e6e4f63 // "cOnn"
  132. #define STATE_TABLE_KEY 0x74417473 // "stAt"
  133. #define PROVIDER_ENUM_KEY 0x764f7270 // "prOv"
  134. #define REMEMBER_KEY 0x626D4572 // "rEmb"
  135. #define REGSTR_PATH_NETWORK_POLICIES \
  136. REGSTR_PATH_POLICIES L"\\" REGSTR_KEY_NETWORK
  137. //
  138. // Macros for rounding a value up/down to a WCHAR boundary.
  139. // Note: These macros assume that sizeof(WCHAR) is a power of 2.
  140. //
  141. #define ROUND_DOWN(x) ((x) & ~(sizeof(WCHAR) - 1))
  142. #define ROUND_UP(x) (((x) + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1))
  143. //
  144. // LOCAL FUNCTION PROTOTYPES
  145. //
  146. DWORD
  147. MprCopyProviderEnum(
  148. IN LPNETRESOURCEW ProviderBuffer,
  149. IN OUT LPDWORD EntryCount,
  150. IN OUT LPBYTE *TempBufPtr,
  151. IN OUT LPDWORD BytesLeft
  152. );
  153. DWORD
  154. MprCopyResource(
  155. IN OUT LPBYTE *BufPtr,
  156. IN const NETRESOURCEW *Resource,
  157. IN OUT LPDWORD BytesLeft
  158. );
  159. DWORD
  160. MprEnumNetwork(
  161. IN OUT LPNETWORK_HEADER StateTable,
  162. IN OUT LPDWORD NumEntries,
  163. IN OUT LPVOID lpBuffer,
  164. IN OUT LPDWORD lpBufferSize
  165. );
  166. DWORD
  167. MprEnumConnect(
  168. IN OUT LPCONNECT_HEADER ConnectEnumHeader,
  169. IN OUT LPDWORD NumEntries,
  170. IN OUT LPVOID lpBuffer,
  171. IN OUT LPDWORD lpBufferSize
  172. );
  173. DWORD
  174. MprOpenEnumNetwork(
  175. OUT LPHANDLE lphEnum
  176. );
  177. DWORD
  178. MprOpenEnumConnect(
  179. IN DWORD dwScope,
  180. IN DWORD dwType,
  181. IN DWORD dwUsage,
  182. IN LPNETRESOURCE lpNetResource,
  183. OUT LPHANDLE lphEnum
  184. );
  185. DWORD
  186. MprProviderEnum(
  187. IN LPENUM_HANDLE EnumHandlePtr,
  188. IN OUT LPDWORD lpcCount,
  189. IN LPVOID lpBuffer,
  190. IN OUT LPDWORD lpBufferSize
  191. );
  192. DWORD
  193. MprOpenRemember(
  194. IN DWORD dwType,
  195. OUT LPHANDLE lphRemember
  196. );
  197. DWORD
  198. MprEnumRemembered(
  199. IN OUT LPREMEMBER_HANDLE RememberInfo,
  200. IN OUT LPDWORD NumEntries,
  201. IN OUT LPBYTE lpBuffer,
  202. IN OUT LPDWORD lpBufferSize
  203. );
  204. DWORD
  205. MprMultiStrBuffSize(
  206. IN LPTSTR lpString1,
  207. IN LPTSTR lpString2,
  208. IN LPTSTR lpString3,
  209. IN LPTSTR lpString4,
  210. IN LPTSTR lpString5
  211. ) ;
  212. class CProviderOpenEnum : public CRoutedOperation
  213. {
  214. public:
  215. CProviderOpenEnum(
  216. DWORD dwScope,
  217. DWORD dwType,
  218. DWORD dwUsage,
  219. LPNETRESOURCEW lpNetResource,
  220. LPHANDLE lphEnum
  221. ) :
  222. CRoutedOperation(DBGPARM("ProviderOpenEnum")
  223. PROVIDERFUNC(OpenEnum)),
  224. _dwScope (dwScope ),
  225. _dwType (dwType ),
  226. _dwUsage (dwUsage ),
  227. _lpNetResource(lpNetResource),
  228. _lphEnum (lphEnum )
  229. { }
  230. protected:
  231. DWORD GetResult(); // overrides CRoutedOperation implementation
  232. private:
  233. DWORD _dwScope;
  234. DWORD _dwType;
  235. DWORD _dwUsage;
  236. LPNETRESOURCEW _lpNetResource;
  237. LPHANDLE _lphEnum;
  238. HANDLE _ProviderEnumHandle; // Enum handle returned by provider
  239. DECLARE_CROUTED
  240. };
  241. DWORD
  242. WNetOpenEnumW (
  243. IN DWORD dwScope,
  244. IN DWORD dwType,
  245. IN DWORD dwUsage,
  246. IN LPNETRESOURCEW lpNetResource,
  247. OUT LPHANDLE lphEnum
  248. )
  249. /*++
  250. Routine Description:
  251. This API is used to open an enumeration of network resources or existing
  252. connections. It must be called to obtain a valid handle for enumeration.
  253. NOTE:
  254. For GlobalNet Enum, the caller must get a new handle for each level that
  255. is desired. For the other scopes, the caller gets a single handle and
  256. with that can enumerate all resources.
  257. Arguments:
  258. dwScope - Determines the scope of the enumeration. This can be one of:
  259. RESOURCE_CONNECTED - All Currently connected resources.
  260. RESOURCE_GLOBALNET - All resources on the network.
  261. RESOURCE_REMEMBERED - All persistent connections.
  262. RESOURCE_RECENT - Same as RESOURCE_REMEMBERED (supported for Win95
  263. semi-compatibility)
  264. RESOURCE_CONTEXT - The resources associated with the user's current
  265. and default network context (as defined by the providers).
  266. RESOURCE_SHAREABLE - All shareable resources on the given server
  267. dwType - Used to specify the type of resources on interest. This is a
  268. bitmask which may be any combination of:
  269. RESOURCETYPE_DISK - All disk resources
  270. RESOURCETYPE_PRINT - All print resources
  271. If this is 0. all types of resources are returned. If a provider does
  272. not have the capability to distinguish between print and disk
  273. resources at a level, it may return all resources.
  274. dwUsage - Used to specify the usage of resources of interest. This is a
  275. bitmask which may be any combination of:
  276. RESOURCEUSAGE_CONNECTABLE - all connectable resources.
  277. RESOURCEUSAGE_CONTAINER - all container resources.
  278. The bitmask may be 0 to match all.
  279. lpNetResource - This specifies the container to perform the enumeration.
  280. If it is NULL, the logical root of the network is assumed, and the
  281. router is responsible for obtaining the information for return.
  282. lphEnum - If the Open was successful, this will contain a handle that
  283. can be used for future calls to WNetEnumResource.
  284. Return Value:
  285. WN_SUCCESS - Indicates the operation was successful.
  286. WN_NOT_CONTAINER - Indicates that lpNetResource does not point to a
  287. container.
  288. WN_BAD_VALUE - Invalid dwScope or dwType, or bad combination of parameters
  289. is specified.
  290. WN_NO_NETWORK - network is not present.
  291. --*/
  292. {
  293. DWORD status = WN_SUCCESS;
  294. //
  295. // dwScope MUST be set to either GLOBALNET or CONNECTED or REMEMBERED
  296. // or RECENT or CONTEXT or SHAREABLE.
  297. // This is verified in the switch statement below.
  298. //
  299. //
  300. // dwType is a bit mask that can have any combination of the DISK
  301. // or PRINT bits set. Or it can be the value 0.
  302. //
  303. if (dwType & ~(RESOURCETYPE_DISK | RESOURCETYPE_PRINT)) {
  304. status = WN_BAD_VALUE;
  305. goto CleanExit;
  306. }
  307. //
  308. // dwUsage is a bit mask that can have any combination of the CONNECTABLE
  309. // or CONTAINER bits set. Or it can be the value 0. This field is
  310. // ignored if dwScope is not RESOURCE_GLOBALNET.
  311. //
  312. if (dwScope == RESOURCE_GLOBALNET) {
  313. if (dwUsage & ~(RESOURCEUSAGE_ALL)) {
  314. status = WN_BAD_VALUE;
  315. goto CleanExit;
  316. }
  317. }
  318. //
  319. // Make sure the user passed in a valid OUT parameter
  320. //
  321. __try
  322. {
  323. PROBE_FOR_WRITE((LPDWORD)lphEnum);
  324. }
  325. __except(EXCEPTION_EXECUTE_HANDLER)
  326. {
  327. status = WN_BAD_POINTER;
  328. }
  329. if (status != WN_SUCCESS)
  330. {
  331. goto CleanExit;
  332. }
  333. //
  334. // Check to see if it is a top-level enum request.
  335. //
  336. if (lpNetResource == NULL
  337. ||
  338. (IS_EMPTY_STRING(lpNetResource->lpProvider) &&
  339. IS_EMPTY_STRING(lpNetResource->lpRemoteName))
  340. ||
  341. dwScope == RESOURCE_SHAREABLE)
  342. {
  343. //
  344. // lpNetResource is NULL or represents no resource or this is
  345. // a request for shareable resources.
  346. // This is a top-level enum request, therefore, the MPR must provide
  347. // the information.
  348. //
  349. switch(dwScope) {
  350. case RESOURCE_CONNECTED:
  351. case RESOURCE_CONTEXT:
  352. case RESOURCE_SHAREABLE:
  353. {
  354. MprCheckProviders();
  355. CProviderSharedLock PLock;
  356. INIT_IF_NECESSARY(NETWORK_LEVEL,status);
  357. if (MprNetIsAvailable()) {
  358. status = MprOpenEnumConnect(dwScope,
  359. dwType,
  360. dwUsage,
  361. lpNetResource,
  362. lphEnum);
  363. }
  364. else
  365. status = WN_NO_NETWORK ;
  366. break;
  367. }
  368. case RESOURCE_GLOBALNET:
  369. {
  370. MprCheckProviders();
  371. CProviderSharedLock PLock;
  372. INIT_IF_NECESSARY(NETWORK_LEVEL,status);
  373. if (MprNetIsAvailable()) {
  374. status = MprOpenEnumNetwork(lphEnum);
  375. }
  376. else
  377. status = WN_NO_NETWORK ;
  378. break;
  379. }
  380. case RESOURCE_REMEMBERED:
  381. case RESOURCE_RECENT:
  382. MPR_LOG(TRACE,"OpenEnum RESOURCE_REMEMBERED\n",0);
  383. status = MprOpenRemember(dwType, lphEnum);
  384. break;
  385. default:
  386. status = WN_BAD_VALUE;
  387. break;
  388. }
  389. }
  390. else {
  391. //
  392. // Request is for one of the providers. It should be for a
  393. // GLOBALNET enumeration. It is not allowed to request any
  394. // other type of enumeration with a pointer to a resource
  395. // buffer.
  396. //
  397. if (dwScope != RESOURCE_GLOBALNET) {
  398. status = WN_BAD_VALUE;
  399. goto CleanExit;
  400. }
  401. CProviderOpenEnum ProviderOpenEnum(
  402. dwScope,
  403. dwType,
  404. dwUsage,
  405. lpNetResource,
  406. lphEnum);
  407. status = ProviderOpenEnum.Perform(TRUE);
  408. }
  409. CleanExit:
  410. if (status != WN_SUCCESS) {
  411. SetLastError(status);
  412. }
  413. return(status);
  414. }
  415. DWORD
  416. WNetEnumResourceW (
  417. IN HANDLE hEnum,
  418. IN OUT LPDWORD lpcCount,
  419. OUT LPVOID lpBuffer,
  420. IN OUT LPDWORD lpBufferSize
  421. )
  422. /*++
  423. Routine Description:
  424. This function is used to obtain an array of NETRESOURCE structures each
  425. of which describes a network resource.
  426. Arguments:
  427. hEnum - This is a handle that was obtained from an WNetOpenEnum call.
  428. lpcCount - Specifies the number of entries requested. -1 indicates
  429. as many entries as possible are requested. If the operation is
  430. successful, this location will receive the number of entries
  431. actually read.
  432. lpBuffer - A pointer to the buffer to receive the enumeration result,
  433. which are returned as an array of NETRESOURCE entries. The buffer
  434. is valid until the next call using hEnum.
  435. lpBufferSize - This specifies the size of the buffer passed to the function
  436. call. It will contain the required buffer size if WN_MORE_DATA is
  437. returned.
  438. Return Value:
  439. WN_SUCCESS - Indicates that the call is successful, and that the caller
  440. should continue to call WNetEnumResource to continue the enumeration.
  441. WN_NO_MORE_ENTRIES - Indicates that the enumeration completed successfully.
  442. The following return codes indicate an error occured and GetLastError
  443. may be used to obtain another copy of the error code:
  444. WN_MORE_DATA - Indicates that the buffer is too small for even one
  445. entry.
  446. WN_BAD_HANDLE - hEnum is not a valid handle.
  447. WN_NO_NETWORK - The Network is not present. This condition is checked
  448. for before hEnum is tested for validity.
  449. History:
  450. 12-Feb-1992 Johnl Removed requirement that buffersize must be at
  451. least as large as NETRESOURCEW (bug 5790)
  452. --*/
  453. {
  454. DWORD status = WN_SUCCESS;
  455. //
  456. // Screen the parameters as best we can.
  457. //
  458. //
  459. // Probe the handle
  460. //
  461. __try {
  462. *(volatile DWORD *)hEnum;
  463. }
  464. __except(EXCEPTION_EXECUTE_HANDLER) {
  465. status = GetExceptionCode();
  466. if (status != EXCEPTION_ACCESS_VIOLATION) {
  467. MPR_LOG(ERROR,"WNetEnumResource:Unexpected Exception 0x%lx\n",status);
  468. }
  469. status = WN_BAD_HANDLE;
  470. }
  471. __try {
  472. PROBE_FOR_WRITE(lpcCount);
  473. if (IS_BAD_BYTE_BUFFER(lpBuffer, lpBufferSize)) {
  474. status = WN_BAD_POINTER;
  475. }
  476. }
  477. __except (EXCEPTION_EXECUTE_HANDLER) {
  478. status = GetExceptionCode();
  479. if (status != EXCEPTION_ACCESS_VIOLATION) {
  480. MPR_LOG(ERROR,"WNetEnumResource:Unexpected Exception 0x%lx\n",status);
  481. }
  482. status = WN_BAD_POINTER;
  483. }
  484. if (status != WN_SUCCESS) {
  485. goto CleanExit;
  486. }
  487. switch(*(LPDWORD)hEnum){
  488. case CONNECT_TABLE_KEY:
  489. //
  490. // Call on Providers to enumerate connections.
  491. //
  492. status = MprEnumConnect(
  493. (LPCONNECT_HEADER)hEnum, // key is part of structure
  494. lpcCount,
  495. lpBuffer,
  496. lpBufferSize);
  497. break;
  498. case STATE_TABLE_KEY:
  499. //
  500. // Enumerate the top level NetResource structure maintained by
  501. // the router.
  502. //
  503. status = MprEnumNetwork(
  504. (LPNETWORK_HEADER)hEnum,
  505. lpcCount,
  506. lpBuffer,
  507. lpBufferSize);
  508. break;
  509. case PROVIDER_ENUM_KEY:
  510. //
  511. // Call on providers to enumerate resources on the network.
  512. //
  513. status = MprProviderEnum(
  514. (LPENUM_HANDLE)hEnum, // key is part of structure
  515. lpcCount,
  516. lpBuffer,
  517. lpBufferSize);
  518. break;
  519. case REMEMBER_KEY:
  520. //
  521. // Enumerate the connections in the current user section of the
  522. // registry.
  523. //
  524. status = MprEnumRemembered(
  525. (LPREMEMBER_HANDLE)hEnum,
  526. lpcCount,
  527. (LPBYTE)lpBuffer,
  528. lpBufferSize);
  529. break;
  530. default:
  531. status = WN_BAD_HANDLE;
  532. }
  533. CleanExit:
  534. if(status != WN_SUCCESS) {
  535. SetLastError(status);
  536. }
  537. return(status);
  538. }
  539. DWORD
  540. WNetCloseEnum (
  541. IN HANDLE hEnum
  542. )
  543. /*++
  544. Routine Description:
  545. Closes an enumeration handle that is owned by the router.
  546. In cases where the router is acting as a proxy for a single provider,
  547. an attempt is made to return any error information from this provider
  548. back to the user. This makes the router as transparent as possible.
  549. Arguments:
  550. hEnum - This must be a handle obtained from a call to WNetOpenEnum.
  551. Return Value:
  552. WN_SUCCESS - The operation was successful.
  553. WN_NO_NETWORK - The Network is not present. This condition is checked
  554. before hEnum is tested for validity.
  555. WN_BAD_HANDLE - hEnum is not a valid handle.
  556. --*/
  557. {
  558. DWORD status = WN_SUCCESS;
  559. DWORD i;
  560. //
  561. // Probe the handle
  562. //
  563. __try {
  564. *(volatile DWORD *)hEnum;
  565. }
  566. __except(EXCEPTION_EXECUTE_HANDLER) {
  567. status = GetExceptionCode();
  568. if (status != EXCEPTION_ACCESS_VIOLATION) {
  569. MPR_LOG(ERROR,"WNetCloseEnum:Unexpected Exception 0x%lx\n",status);
  570. }
  571. status = WN_BAD_HANDLE;
  572. }
  573. if (status != WN_SUCCESS) {
  574. SetLastError(WN_BAD_HANDLE);
  575. return(status);
  576. }
  577. //
  578. // Use hEnum as a pointer and check the DWORD value at its location.
  579. // If it contains a CONNECT_TABLE_KEY, we must close all handles to
  580. // the providers before freeing the memory for the table.
  581. // If it is a STATE_TABLE_KEY, we just free the memory.
  582. //
  583. switch(*(LPDWORD)hEnum){
  584. case CONNECT_TABLE_KEY:
  585. {
  586. LPCONNECT_HEADER connectEnumHeader;
  587. LPCONNECT_ENUM connectEnumTable;
  588. connectEnumHeader = (LPCONNECT_HEADER)hEnum;
  589. connectEnumTable = (LPCONNECT_ENUM)(connectEnumHeader + 1);
  590. //
  591. // Close all the open provider handles
  592. //
  593. MPR_LOG(TRACE,"Closing Connection Enum Handles from Providers\n",0);
  594. for(i = 0; i < connectEnumHeader->dwNumProviders; i++) {
  595. if((connectEnumTable[i].State != NOT_OPENED) &&
  596. (connectEnumTable[i].pfCloseEnum != NULL))
  597. {
  598. status = connectEnumTable[i].pfCloseEnum(
  599. connectEnumTable[i].ProviderEnumHandle);
  600. if(status != WN_SUCCESS) {
  601. //
  602. // Because we are closing many handles at once, the failure
  603. // is noted for debug purposes only.
  604. //
  605. MPR_LOG(ERROR,"WNetCloseEnum:(connect-provider #%d) failed\n",i);
  606. MPR_LOG(ERROR,"WNetCloseEnum: error code = %d\n",status);
  607. //
  608. // Error information is returned if there is only one
  609. // provider.
  610. //
  611. if (connectEnumHeader->dwNumProviders != 1) {
  612. status = WN_SUCCESS;
  613. }
  614. }
  615. //
  616. // If this fires, the logic in MprOpenEnumConnect is wrong
  617. //
  618. ASSERT(connectEnumTable[i].hProviderDll != NULL);
  619. FreeLibrary(connectEnumTable[i].hProviderDll);
  620. }
  621. else
  622. {
  623. //
  624. // If this fires, the logic in MprOpenEnumConnect is wrong
  625. // and we're not releasing a refcounted provider DLL
  626. //
  627. ASSERT(connectEnumTable[i].hProviderDll == NULL);
  628. }
  629. }
  630. //
  631. // Free the Table Memory
  632. //
  633. if (LocalFree(hEnum)) {
  634. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(connect) failed %d\n",
  635. GetLastError());
  636. }
  637. if (status != WN_SUCCESS)
  638. {
  639. SetLastError(status);
  640. }
  641. return(status);
  642. }
  643. case STATE_TABLE_KEY:
  644. {
  645. LPNETWORK_HEADER StateTableHeader;
  646. LPNETWORK_ENUM StateTable;
  647. //
  648. // Free the State Table Memory.
  649. //
  650. MPR_LOG(TRACE,"Free State Table for Network Enum\n",0);
  651. StateTableHeader = (LPNETWORK_HEADER)hEnum;
  652. StateTable = (LPNETWORK_ENUM)(StateTableHeader + 1);
  653. for (i = 0; i < StateTableHeader->dwNumProviders; i++)
  654. {
  655. if (StateTable[i].hProviderDll != NULL)
  656. {
  657. FreeLibrary(StateTable[i].hProviderDll);
  658. LocalFree(StateTable[i].lpnr);
  659. }
  660. else
  661. {
  662. //
  663. // If this fires, MprOpenEnumNetwork is causing a mem leak
  664. //
  665. ASSERT(StateTable[i].lpnr == NULL);
  666. }
  667. }
  668. if (LocalFree(hEnum)) {
  669. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(network) failed %d\n",
  670. GetLastError());
  671. }
  672. return(WN_SUCCESS);
  673. }
  674. case PROVIDER_ENUM_KEY:
  675. {
  676. LPENUM_HANDLE enumHandle;
  677. //
  678. // Close the providers enumeration handle, and free the
  679. // ENUM_HANDLE structure.
  680. //
  681. MPR_LOG(TRACE,"Closing Provider Enum Handle\n",0);
  682. enumHandle = (LPENUM_HANDLE)hEnum;
  683. ASSERT(enumHandle->pfCloseEnum != NULL);
  684. status = (enumHandle->pfCloseEnum)(enumHandle->EnumHandle);
  685. ASSERT(enumHandle->hProviderDll != NULL);
  686. FreeLibrary(enumHandle->hProviderDll);
  687. if (LocalFree(enumHandle) != 0) {
  688. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(provider) failed %d\n",
  689. GetLastError());
  690. }
  691. //
  692. // Check the status returned from the Provider's CloseEnum
  693. //
  694. if(status != WN_SUCCESS) {
  695. MPR_LOG(ERROR,"WNetCloseEnum:(provider) failed %d\n",status);
  696. SetLastError(status);
  697. }
  698. return(status);
  699. }
  700. case REMEMBER_KEY:
  701. {
  702. LPREMEMBER_HANDLE rememberHandle;
  703. rememberHandle = (LPREMEMBER_HANDLE)hEnum;
  704. //
  705. // Close the RegistryKey Handle associated with this handle.
  706. //
  707. if (rememberHandle->ConnectKey != NULL) {
  708. RegCloseKey(rememberHandle->ConnectKey);
  709. }
  710. //
  711. // Free up the memory for the handle.
  712. //
  713. if (LocalFree(rememberHandle) != 0) {
  714. MPR_LOG(ERROR,"WNetCloseEnum:LocalFree(remember) failed %d\n",
  715. GetLastError());
  716. }
  717. return(WN_SUCCESS);
  718. }
  719. default:
  720. SetLastError(WN_BAD_HANDLE);
  721. return(WN_BAD_HANDLE);
  722. }
  723. }
  724. DWORD
  725. MprOpenEnumConnect(
  726. IN DWORD dwScope,
  727. IN DWORD dwType,
  728. IN DWORD dwUsage,
  729. IN LPNETRESOURCE lpNetResource,
  730. OUT LPHANDLE lphEnum
  731. )
  732. /*++
  733. Routine Description:
  734. This function handles the opening of connection enumerations and context
  735. enumerations. It does this by sending an OpenEnum to all Providers, and
  736. storing the returned handles in a table. The handle that is returned is
  737. a pointer to this table.
  738. The first DWORD in the table is a key that will help to identify a
  739. correct table. The second DWORD is a Boolean value that tells whether
  740. a NETRESOURCE structure representing the root of the network needs to be
  741. returned in the enumeration.
  742. Arguments:
  743. dwScope - RESOURCE_CONNECTED, RESOURCE_CONTEXT, or RESOURCE_SHAREABLE
  744. dwType -
  745. dwUsage -
  746. lpNetResource -
  747. lphEnum - This is a pointer to a location where the handle for
  748. the connection enumeration is to be stored.
  749. Return Value:
  750. WN_SUCCESS - The operation was successful.
  751. WN_OUT_OF_MEMORY - The memory allocation for the handle was unsuccessful.
  752. --*/
  753. {
  754. DWORD i;
  755. DWORD status;
  756. LPCONNECT_HEADER connectEnumHeader;
  757. LPCONNECT_ENUM connectEnumTable;
  758. LPPROVIDER provider;
  759. BOOL fcnSupported = FALSE; // Is fcn supported by a provider?
  760. BOOL atLeastOne=FALSE;
  761. BOOL bDynamicEntries = TRUE; // Whether to show dynamic entries
  762. // in the net neighborhood
  763. HKEY hkPolicies = NULL;
  764. ASSERT(dwScope == RESOURCE_CONNECTED
  765. ||
  766. dwScope == RESOURCE_CONTEXT
  767. ||
  768. dwScope == RESOURCE_SHAREABLE);
  769. ASSERT_INITIALIZED(NETWORK);
  770. //
  771. // If there are no providers, return NO_NETWORK
  772. //
  773. if (GlobalNumActiveProviders == 0) {
  774. return(WN_NO_NETWORK);
  775. }
  776. //
  777. // Allocate the handle table with enough room for a header.
  778. //
  779. connectEnumHeader = (LPCONNECT_HEADER) LocalAlloc(
  780. LPTR,
  781. sizeof(CONNECT_HEADER) +
  782. sizeof(CONNECT_ENUM) * GlobalNumProviders
  783. );
  784. if (connectEnumHeader == NULL) {
  785. MPR_LOG(ERROR,"MprOpenEnumConnect:LocalAlloc Failed %d\n",GetLastError());
  786. return(WN_OUT_OF_MEMORY);
  787. }
  788. //
  789. // Initialize the key used in the connect table.
  790. //
  791. connectEnumHeader->Key = CONNECT_TABLE_KEY;
  792. connectEnumHeader->ReturnRoot = FALSE;
  793. connectEnumHeader->dwNumProviders = GlobalNumProviders;
  794. connectEnumHeader->dwNumActiveProviders = GlobalNumActiveProviders;
  795. connectEnumTable = (LPCONNECT_ENUM)(connectEnumHeader + 1);
  796. //
  797. // Check the policy on whether dynamic entries are to be shown in the
  798. // network neighborhood. By default, they are shown.
  799. //
  800. if (dwScope == RESOURCE_CONTEXT)
  801. {
  802. if (MprOpenKey(
  803. HKEY_CURRENT_USER,
  804. REGSTR_PATH_NETWORK_POLICIES,
  805. &hkPolicies,
  806. KEY_READ))
  807. {
  808. bDynamicEntries = ! (MprGetKeyNumberValue(
  809. hkPolicies,
  810. REGSTR_VAL_NOWORKGROUPCONTENTS,
  811. FALSE));
  812. }
  813. else
  814. {
  815. hkPolicies = NULL;
  816. }
  817. }
  818. //
  819. // Initialize all state flags for providers to the NOT_OPENED state, so
  820. // we won't try to enumerate or close their handles unless we actually
  821. // got handles from them.
  822. // Initialize handles for the network providers by calling them with
  823. // OpenEnum.
  824. //
  825. for(i=0; i<GlobalNumProviders; i++) {
  826. connectEnumTable[i].State = NOT_OPENED;
  827. provider = GlobalProviderInfo + i;
  828. if ((provider->InitClass & NETWORK_TYPE) &&
  829. (provider->OpenEnum != NULL)) {
  830. if (dwScope == RESOURCE_CONTEXT)
  831. {
  832. DWORD dwCaps = provider->GetCaps(WNNC_ENUMERATION);
  833. if (dwCaps & WNNC_ENUM_GLOBAL)
  834. {
  835. // A browsing network is present, so show root,
  836. // even if network is down, and even if ENUM_CONTEXT
  837. // isn't supported.
  838. connectEnumHeader->ReturnRoot = TRUE;
  839. }
  840. if ((dwCaps & WNNC_ENUM_CONTEXT) == 0)
  841. {
  842. // This provider can't show hood entries, so skip it.
  843. continue;
  844. }
  845. }
  846. else if (dwScope == RESOURCE_SHAREABLE)
  847. {
  848. DWORD dwCaps = provider->GetCaps(WNNC_ENUMERATION);
  849. if ((dwCaps & WNNC_ENUM_SHAREABLE) == 0)
  850. {
  851. // This provider can't show shareable resources, so skip it.
  852. continue;
  853. }
  854. }
  855. fcnSupported = TRUE;
  856. if (bDynamicEntries)
  857. {
  858. //
  859. // Refcount the provider
  860. //
  861. connectEnumTable[i].hProviderDll = LoadLibraryEx(provider->DllName,
  862. NULL,
  863. LOAD_WITH_ALTERED_SEARCH_PATH);
  864. if (connectEnumTable[i].hProviderDll == NULL)
  865. {
  866. status = GetLastError();
  867. //
  868. // This can happen under extreme low memory conditions. The
  869. // loader can sometimes return ERROR_MOD_NOT_FOUND in this case.
  870. //
  871. MPR_LOG2(ERROR,
  872. "MprOpenEnumConnect: LoadLibraryEx on %ws FAILED %d\n",
  873. provider->DllName,
  874. status);
  875. ASSERT(status == ERROR_NOT_ENOUGH_MEMORY || status == ERROR_MOD_NOT_FOUND);
  876. continue;
  877. }
  878. connectEnumTable[i].pfEnumResource = provider->EnumResource;
  879. connectEnumTable[i].pfCloseEnum = provider->CloseEnum;
  880. status = provider->OpenEnum(
  881. dwScope, // Scope
  882. dwType, // Type
  883. dwUsage, // Usage
  884. (dwScope == RESOURCE_SHAREABLE ? lpNetResource : NULL), // NetResource
  885. &(connectEnumTable[i].ProviderEnumHandle)); // hEnum
  886. if (status != WN_SUCCESS) {
  887. MPR_LOG(ERROR,"MprOpenEnumConnect:OpenEnum Failed %d\n",status);
  888. MPR_LOG(ERROR,
  889. "That was for the %ws Provider\n",
  890. provider->Resource.lpProvider);
  891. FreeLibrary(connectEnumTable[i].hProviderDll);
  892. connectEnumTable[i].hProviderDll = NULL;
  893. connectEnumTable[i].pfEnumResource = NULL;
  894. connectEnumTable[i].pfCloseEnum = NULL;
  895. }
  896. else {
  897. //
  898. // At least one provider has returned a handle.
  899. //
  900. atLeastOne = TRUE;
  901. //
  902. // Set the state to MORE_ENTRIES, so we later enumerate from the
  903. // handle and/or close it.
  904. //
  905. connectEnumTable[i].State = MORE_ENTRIES;
  906. MPR_LOG(TRACE,"MprOpenEnumConnect: OpenEnum Handle = 0x%lx\n",
  907. connectEnumTable[i].ProviderEnumHandle);
  908. }
  909. }
  910. else
  911. {
  912. // Succeed the WNetOpenEnum but leave this provider as NOT_OPENED
  913. atLeastOne = TRUE;
  914. }
  915. }
  916. }
  917. if (connectEnumHeader->ReturnRoot)
  918. {
  919. // Able to show the root object. Check the policy on whether
  920. // to show it.
  921. connectEnumHeader->ReturnRoot = ! (MprGetKeyNumberValue(
  922. hkPolicies,
  923. REGSTR_VAL_NOENTIRENETWORK,
  924. FALSE));
  925. fcnSupported = TRUE;
  926. atLeastOne = TRUE;
  927. }
  928. if (hkPolicies)
  929. {
  930. RegCloseKey(hkPolicies);
  931. }
  932. if (fcnSupported == FALSE) {
  933. //
  934. // No providers in the list support the API function. Therefore,
  935. // we assume that no networks are installed.
  936. // Note that in this case, atLeastOne will always be FALSE.
  937. //
  938. status = WN_NOT_SUPPORTED;
  939. }
  940. //
  941. // return the handle (pointer to connectEnumTable);
  942. //
  943. *lphEnum = connectEnumHeader;
  944. if (atLeastOne == FALSE) {
  945. //
  946. // If none of the providers returned a handle, then return the
  947. // status from the last provider.
  948. //
  949. *lphEnum = NULL;
  950. LocalFree( connectEnumHeader);
  951. return(status);
  952. }
  953. return(WN_SUCCESS);
  954. }
  955. DWORD
  956. MprOpenEnumNetwork(
  957. OUT LPHANDLE lphEnum
  958. )
  959. /*++
  960. Routine Description:
  961. This function handles the opening of net resource enumerations.
  962. It does this by allocating a table of Provider State Flags and returning
  963. a handle to that table. The state flags (or for each provider) will
  964. be set to MORE_ENTRIES. Later, when enumerations take place, the state
  965. for each provider is changed to DONE after the buffer is successfully
  966. loaded with the the NETRESOURCE info for that provider.
  967. Arguments:
  968. lphEnum - This is a pointer to a location where the handle for
  969. the network resource enumeration is to be stored.
  970. Return Value:
  971. WN_SUCCESS - The operation was successful.
  972. WN_OUT_OF_MEMORY - The memory allocation for the handle was unsuccessful.
  973. --*/
  974. {
  975. LPNETWORK_ENUM stateTable;
  976. LPNETWORK_HEADER stateTableHeader;
  977. DWORD i;
  978. ASSERT_INITIALIZED(NETWORK);
  979. //
  980. // If there are no providers, return NO_NETWORK
  981. //
  982. if (GlobalNumActiveProviders == 0) {
  983. return(WN_NO_NETWORK);
  984. }
  985. //
  986. // Allocate the state table.
  987. //
  988. stateTableHeader = (LPNETWORK_HEADER) LocalAlloc(
  989. LPTR,
  990. sizeof(NETWORK_HEADER) +
  991. sizeof(NETWORK_ENUM) * GlobalNumProviders
  992. );
  993. if (stateTableHeader == NULL) {
  994. MPR_LOG(ERROR,"MprOpenEnumNetwork:LocalAlloc Failed %d\n",GetLastError());
  995. return(WN_OUT_OF_MEMORY);
  996. }
  997. stateTableHeader->Key = STATE_TABLE_KEY;
  998. stateTableHeader->dwNumProviders = GlobalNumProviders;
  999. stateTableHeader->dwNumActiveProviders = GlobalNumActiveProviders;
  1000. stateTable = (LPNETWORK_ENUM)(stateTableHeader + 1);
  1001. //
  1002. // Initialize state flags for all network providers to the MORE_ENTRIES state.
  1003. //
  1004. for(i = 0; i < GlobalNumProviders; i++) {
  1005. if (GlobalProviderInfo[i].InitClass & NETWORK_TYPE)
  1006. {
  1007. if (GlobalProviderInfo[i].Handle != NULL)
  1008. {
  1009. stateTable[i].hProviderDll = LoadLibraryEx(GlobalProviderInfo[i].DllName,
  1010. NULL,
  1011. LOAD_WITH_ALTERED_SEARCH_PATH);
  1012. if (stateTable[i].hProviderDll == NULL)
  1013. {
  1014. DWORD status = GetLastError();
  1015. //
  1016. // This can happen under extreme low memory conditions. The
  1017. // loader can sometimes return ERROR_MOD_NOT_FOUND in this case.
  1018. //
  1019. MPR_LOG1(ERROR,
  1020. "MprOpenEnumNetwork: LoadLibraryEx on %ws FAILED\n",
  1021. GlobalProviderInfo[i].DllName);
  1022. ASSERT(status == ERROR_NOT_ENOUGH_MEMORY || status == ERROR_MOD_NOT_FOUND);
  1023. }
  1024. else
  1025. {
  1026. LPBYTE lpTempBuffer;
  1027. DWORD dwSize = 0;
  1028. DWORD dwStatus;
  1029. //
  1030. // Figure out how much space we'll need for the NETRESOURCE.
  1031. // It needs to be copied since the provider (and its resource)
  1032. // may go away between now and the WNetEnumResource call.
  1033. //
  1034. dwStatus = MprCopyResource(NULL,
  1035. &GlobalProviderInfo[i].Resource,
  1036. &dwSize);
  1037. ASSERT(dwStatus == WN_MORE_DATA);
  1038. stateTable[i].lpnr = (LPNETRESOURCE)LocalAlloc(LPTR, dwSize);
  1039. if (stateTable[i].lpnr == NULL)
  1040. {
  1041. MPR_LOG0(ERROR, "MprOpenEnumNetwork: LocalAlloc FAILED\n");
  1042. //
  1043. // Rather than fail silently in this case, bail out
  1044. //
  1045. for (UINT j = 0; j <= i; j++)
  1046. {
  1047. if (stateTable[j].hProviderDll)
  1048. {
  1049. FreeLibrary(stateTable[j].hProviderDll);
  1050. stateTable[j].hProviderDll = NULL;
  1051. stateTable[j].State = MORE_ENTRIES;
  1052. }
  1053. LocalFree(stateTable[j].lpnr);
  1054. }
  1055. LocalFree(stateTableHeader);
  1056. return(WN_OUT_OF_MEMORY);
  1057. }
  1058. else
  1059. {
  1060. lpTempBuffer = (LPBYTE)stateTable[i].lpnr;
  1061. dwStatus = MprCopyResource(&lpTempBuffer,
  1062. &GlobalProviderInfo[i].Resource,
  1063. &dwSize);
  1064. ASSERT(dwStatus == WN_SUCCESS);
  1065. }
  1066. }
  1067. }
  1068. stateTable[i].State = MORE_ENTRIES;
  1069. }
  1070. else {
  1071. stateTable[i].State = DONE;
  1072. }
  1073. }
  1074. //
  1075. // return the handle (pointer to stateTable);
  1076. //
  1077. *lphEnum = stateTableHeader;
  1078. return(WN_SUCCESS);
  1079. }
  1080. DWORD
  1081. MprEnumConnect(
  1082. IN OUT LPCONNECT_HEADER ConnectEnumHeader,
  1083. IN OUT LPDWORD NumEntries,
  1084. IN OUT LPVOID lpBuffer,
  1085. IN OUT LPDWORD lpBufferSize
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. This function looks in the ConnectEnumTable for the next provider that
  1090. has MORE_ENTRIES. It begins requesting Enum Data from that provider -
  1091. each time copying data that is returned from the provider enum into the
  1092. users enum buffer (lpBuffer). This continues until we finish, or
  1093. we reach the requested number of elements, or the user buffer is full.
  1094. Each time we enumerate a provider to completion, that provider is
  1095. marked as DONE.
  1096. Note, for a context enumeration, the first NETRESOURCE returned in the
  1097. enumeration is a constant NETRESOURCE representing the root of the
  1098. network. This is done to make it easy for the shell to display a
  1099. "Rest of Network" object in a "Network Neighborhood" view.
  1100. Arguments:
  1101. ConnectEnumHeader - This is a pointer to a CONNECT_HEADER structure
  1102. followed by an array of CONNECT_ENUM structures. The ReturnRoot
  1103. member of the header tells whether the root object needs to be
  1104. returned at the start of the enumeration. On exit, if the root
  1105. object has been returned, the ReturnRoot member is set to FALSE.
  1106. NumEntries - On entry this points to the maximum number of entries
  1107. that the user desires to receive. On exit it points to the
  1108. number of entries that were placed in the users buffer.
  1109. lpBuffer - This is a pointer to the users buffer in which the
  1110. enumeration data is to be placed.
  1111. lpBufferSize - This is the size (in bytes) of the users buffer. It will
  1112. be set to the size of the required buffer size of WN_MORE_DATA is
  1113. returned.
  1114. Return Value:
  1115. WN_SUCCESS - This indicates that the call is returning some entries.
  1116. However, the enumeration is not complete due to one of the following:
  1117. 1) There was not enough buffer space.
  1118. 2) The requested number of entries was reached.
  1119. 3) There is no more data to enumerate - the next call will
  1120. return WN_NO_MORE_ENTRIES.
  1121. WN_MORE_DATA - This indicates that the buffer was not large enough
  1122. to receive one enumeration entry.
  1123. WN_NO_MORE_ENTRIES - This indicates that there are no more entries
  1124. to enumerate. No data is returned with this return code.
  1125. WN_NO_NETWORK - If there are no providers loaded.
  1126. Note:
  1127. --*/
  1128. {
  1129. DWORD i; // provider index
  1130. DWORD status=WN_NO_MORE_ENTRIES;
  1131. DWORD entriesRead=0; // number of entries read into the buffer.
  1132. LPBYTE tempBufPtr; // pointer to top of remaining free buffer space.
  1133. LPNETRESOURCEW providerBuffer; // buffer for data returned from provider
  1134. DWORD bytesLeft; // Numer of bytes left in the buffer
  1135. DWORD entryCount; // number of entries read from provider
  1136. LPCONNECT_ENUM ConnectEnumTable = (LPCONNECT_ENUM) (ConnectEnumHeader + 1);
  1137. // Start of array
  1138. //
  1139. // If there are no providers, return NO_NETWORK
  1140. //
  1141. if (ConnectEnumHeader->dwNumActiveProviders == 0) {
  1142. return(WN_NO_NETWORK);
  1143. }
  1144. bytesLeft = ROUND_DOWN(*lpBufferSize);
  1145. tempBufPtr = (LPBYTE) lpBuffer;
  1146. //
  1147. // Check to see if there are any flags in state table that indicate
  1148. // MORE_ENTRIES. If not, we want to return WN_NO_MORE_ENTRIES.
  1149. //
  1150. for(i = 0; i < ConnectEnumHeader->dwNumProviders; i++) {
  1151. if(ConnectEnumTable[i].State == MORE_ENTRIES) {
  1152. break;
  1153. }
  1154. }
  1155. if ( (i == ConnectEnumHeader->dwNumProviders) && (! ConnectEnumHeader->ReturnRoot) ) {
  1156. *NumEntries = 0;
  1157. return(WN_NO_MORE_ENTRIES);
  1158. }
  1159. //
  1160. // If no entries are requested, we have nothing to do
  1161. //
  1162. if (*NumEntries == 0) {
  1163. return WN_SUCCESS;
  1164. }
  1165. //
  1166. // Allocate a buffer for the provider to return data in.
  1167. // The buffer size must equal the number of bytes left in the
  1168. // user buffer.
  1169. // (We can't have the provider write data directly to the caller's
  1170. // buffer because NPEnumResource is not required to place strings
  1171. // at the end of the buffer -- only at the end of the array of
  1172. // NETRESOURCEs.)
  1173. //
  1174. providerBuffer = (LPNETRESOURCEW) LocalAlloc(LPTR, bytesLeft);
  1175. if (providerBuffer == NULL) {
  1176. MPR_LOG(ERROR,"MprEnumConnect:LocalAlloc Failed %d\n",
  1177. GetLastError());
  1178. *NumEntries = 0;
  1179. return(WN_OUT_OF_MEMORY);
  1180. }
  1181. //
  1182. // Copy the root-of-network resource if required.
  1183. //
  1184. if (ConnectEnumHeader->ReturnRoot)
  1185. {
  1186. NETRESOURCEW RootResource = {
  1187. RESOURCE_GLOBALNET, // dwScope
  1188. RESOURCETYPE_ANY, // dwType
  1189. RESOURCEDISPLAYTYPE_ROOT, // dwDisplayType
  1190. RESOURCEUSAGE_CONTAINER, // dwUsage
  1191. NULL, // lpLocalName
  1192. NULL, // lpRemoteName
  1193. g_wszEntireNetwork, // lpComment
  1194. NULL // lpProvider
  1195. };
  1196. status = MprCopyResource(&tempBufPtr, &RootResource, &bytesLeft);
  1197. if (status == WN_SUCCESS)
  1198. {
  1199. entriesRead = 1;
  1200. ConnectEnumHeader->ReturnRoot = FALSE;
  1201. }
  1202. else
  1203. {
  1204. if (status == WN_MORE_DATA)
  1205. {
  1206. //
  1207. // Not even enough room for one NETRESOURCE
  1208. //
  1209. *lpBufferSize = bytesLeft;
  1210. }
  1211. goto CleanExit;
  1212. }
  1213. }
  1214. //
  1215. // Loop until we have copied from all Providers or until the
  1216. // the maximum number of entries has been reached.
  1217. //
  1218. for ( ; i < ConnectEnumHeader->dwNumProviders && entriesRead < *NumEntries; i++)
  1219. {
  1220. if (ConnectEnumTable[i].State != MORE_ENTRIES)
  1221. {
  1222. //
  1223. // Skip providers that don't have more entries
  1224. //
  1225. continue;
  1226. }
  1227. if (ConnectEnumTable[i].hProviderDll == NULL) {
  1228. //
  1229. // If the provider has not been initialized because it is
  1230. // not "ACTIVE", then skip it.
  1231. //
  1232. ConnectEnumTable[i].State = DONE;
  1233. status = WN_SUCCESS;
  1234. continue;
  1235. }
  1236. //
  1237. // Adjust the entry count for any entries that have been read
  1238. // so far.
  1239. //
  1240. entryCount = *NumEntries - entriesRead;
  1241. //
  1242. // Call the provider to get the enumerated data
  1243. //
  1244. status = ConnectEnumTable[i].pfEnumResource(
  1245. ConnectEnumTable[i].ProviderEnumHandle,
  1246. &entryCount,
  1247. providerBuffer,
  1248. &bytesLeft ); // (note, the provider updates
  1249. // bytesLeft only if it returns
  1250. // WN_MORE_DATA)
  1251. switch (status)
  1252. {
  1253. case WN_SUCCESS:
  1254. MPR_LOG(TRACE,"EnumResourceHandle = 0x%lx\n",
  1255. ConnectEnumTable[i].ProviderEnumHandle);
  1256. status = MprCopyProviderEnum(
  1257. providerBuffer,
  1258. &entryCount,
  1259. &tempBufPtr,
  1260. &bytesLeft);
  1261. entriesRead += entryCount;
  1262. if (status != WN_SUCCESS) {
  1263. //
  1264. // An internal error occured - for some reason the
  1265. // buffer space left in the user buffer was smaller
  1266. // than the buffer space that the provider filled in.
  1267. // The best we can do in this case is return what data
  1268. // we have. WARNING: the data that didn't make it
  1269. // will become lost since the provider thinks it
  1270. // enumerated successfully, but we couldn't do anything
  1271. // with it.
  1272. //
  1273. MPR_LOG(ERROR,
  1274. "MprEnumConnect:MprCopyProviderEnum Internal Error %d\n",
  1275. status);
  1276. if(entriesRead > 0) {
  1277. status = WN_SUCCESS;
  1278. }
  1279. goto CleanExit;
  1280. }
  1281. //
  1282. // We successfully placed all the received data from
  1283. // that provider into the user buffer. In this case,
  1284. // if we haven't reached the requested number of entries,
  1285. // we want to loop around and ask the same provider
  1286. // to enumerate more. This time the provider should
  1287. // indicate why it quit last time - either there are
  1288. // no more entries, or we ran out of buffer space.
  1289. //
  1290. break;
  1291. case WN_NO_MORE_ENTRIES:
  1292. //
  1293. // This Provider has completed its enumeration, mark it
  1294. // as done and increment to the next provider. We don't
  1295. // want to return NO_MORE_ENTRIES status. That should
  1296. // only be returned by the check at beginning or end
  1297. // of this function.
  1298. //
  1299. ConnectEnumTable[i].State = DONE;
  1300. status = WN_SUCCESS;
  1301. break;
  1302. case WN_MORE_DATA:
  1303. //
  1304. // This provider has more data, but there is not enough
  1305. // room left in the user buffer to place any more data
  1306. // from this provider. We don't want to go on to the
  1307. // next provider until we're finished with this one. So
  1308. // if we have any entries at all to return, we send back
  1309. // a SUCCESS status. Otherwise, the WN_MORE_DATA status
  1310. // is appropriate.
  1311. //
  1312. if(entriesRead > 0) {
  1313. status = WN_SUCCESS;
  1314. }
  1315. else
  1316. {
  1317. //
  1318. // If 0 entries were read, then the provider should
  1319. // have set bytesLeft with the required buffer size
  1320. //
  1321. *lpBufferSize = ROUND_UP(bytesLeft);
  1322. }
  1323. goto CleanExit;
  1324. break;
  1325. default:
  1326. //
  1327. // We received an unexpected error from the Provider Enum
  1328. // call.
  1329. //
  1330. MPR_LOG(ERROR,"MprEnumConnect:ProviderEnum Error %d\n",status);
  1331. if(entriesRead > 0) {
  1332. //
  1333. // If we have received data so far, ignore this error
  1334. // and move on to the next provider. This provider will
  1335. // be left in the MORE_ENTRIES state, so that on some other
  1336. // pass - when all other providers are done, this error
  1337. // will be returned.
  1338. //
  1339. status = WN_SUCCESS;
  1340. }
  1341. else{
  1342. //
  1343. // No entries have been read so far. We can return
  1344. // immediately with the error.
  1345. //
  1346. goto CleanExit;
  1347. }
  1348. } // end switch (status)
  1349. } // end for (each provider)
  1350. //
  1351. // If we looped through all providers and they are all DONE.
  1352. // If there were no connections, then return proper error code.
  1353. //
  1354. if ((entriesRead == 0) && (status == WN_SUCCESS)) {
  1355. status = WN_NO_MORE_ENTRIES;
  1356. }
  1357. CleanExit:
  1358. //
  1359. // Update the number of entries to be returned to user.
  1360. //
  1361. *NumEntries = entriesRead;
  1362. LocalFree(providerBuffer);
  1363. return(status);
  1364. }
  1365. DWORD
  1366. MprEnumNetwork(
  1367. IN OUT LPNETWORK_HEADER StateTableHeader,
  1368. IN OUT LPDWORD NumEntries,
  1369. IN OUT LPVOID lpBuffer,
  1370. IN OUT LPDWORD lpBufferSize
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. This function Looks in the state table for the next provider that has
  1375. MORE_ENTRIES. It begins by copying the NETRESOURCE info for that one.
  1376. This continues until we finish, or we reach the requested number of
  1377. elements, or the buffer is full. Each time we copy a complete structure,
  1378. we mark that provider as DONE.
  1379. Arguments:
  1380. StateTable - This is a pointer to the state table that is managed by
  1381. the handle used in this request. The state table is a table of
  1382. flags used to indicate the enumeration state for a given
  1383. provider. These flags are in the same order as the provider
  1384. information in the GlobalProviderInfo Array. The state can be
  1385. either DONE or MORE_ENTRIES.
  1386. NumEntries - On entry this points to the maximum number of entries
  1387. that the user desires to receive. On exit it points to the
  1388. number of entries that were placed in the users buffer.
  1389. lpBuffer - This is a pointer to the users buffer in which the
  1390. enumeration data is to be placed.
  1391. lpBufferSize - This is the size (in bytes) of the users buffer.
  1392. Return Value:
  1393. WN_SUCCESS - This indicates that the call is returning some entries.
  1394. However, the enumeration is not complete due to one of the following:
  1395. 1) There was not enough buffer space.
  1396. 2) The requested number of entries was reached.
  1397. 3) There is no more data to enumerate - the next call will
  1398. return WN_NO_MORE_ENTRIES.
  1399. WN_MORE_DATA - This indicates that the buffer was not large enough
  1400. to receive one enumeration entry.
  1401. WN_NO_MORE_ENTRIES - This indicates that there are no more entries
  1402. to enumerate. No data is returned with this return code.
  1403. Note:
  1404. CAUTION: "DONE" entries may appear anywhere in the statetable.
  1405. You cannot always rely on the fact that all of the entries
  1406. after a MORE_ENTRIES entry are also in the MORE_ENTRIES state.
  1407. This is because a provider that would not pass back a handle
  1408. at open time will be marked as DONE so that it gets skipped
  1409. at Enum Time.
  1410. --*/
  1411. {
  1412. DWORD i;
  1413. DWORD status;
  1414. DWORD entriesRead=0; // number of entries read into the buffer.
  1415. LPBYTE tempBufPtr; // pointer to top of remaining free buffer space.
  1416. DWORD bytesLeft; // num bytes left in free buffer space
  1417. LPNETWORK_ENUM StateTable = (LPNETWORK_ENUM)(StateTableHeader + 1);
  1418. //
  1419. // If there are no providers, return NO_NETWORK
  1420. //
  1421. if (StateTableHeader->dwNumActiveProviders == 0) {
  1422. return(WN_NO_NETWORK);
  1423. }
  1424. bytesLeft = ROUND_DOWN(*lpBufferSize);
  1425. tempBufPtr = (LPBYTE) lpBuffer;
  1426. //
  1427. // Check to see if there are any flags in state table that indicate
  1428. // MORE_ENTRIES. If not, we want to return WN_NO_MORE_ENTRIES.
  1429. //
  1430. for(i = 0; i < StateTableHeader->dwNumProviders; i++) {
  1431. if(StateTable[i].State == MORE_ENTRIES) {
  1432. break;
  1433. }
  1434. }
  1435. if ( i >= StateTableHeader->dwNumProviders ) {
  1436. *NumEntries = 0;
  1437. return(WN_NO_MORE_ENTRIES);
  1438. }
  1439. //
  1440. // Loop until we have copied from all Providers or until the
  1441. // the maximum number of entries has been reached.
  1442. //
  1443. for(; (i < StateTableHeader->dwNumProviders) && (entriesRead < *NumEntries); i++)
  1444. {
  1445. if (StateTable[i].State == MORE_ENTRIES) {
  1446. if (StateTable[i].hProviderDll == NULL)
  1447. {
  1448. //
  1449. // If the provider is not ACTIVE, skip it.
  1450. //
  1451. StateTable[i].State = DONE;
  1452. }
  1453. else
  1454. {
  1455. status = MprCopyResource(
  1456. &tempBufPtr,
  1457. StateTable[i].lpnr,
  1458. &bytesLeft);
  1459. if (status == WN_SUCCESS)
  1460. {
  1461. StateTable[i].State = DONE;
  1462. entriesRead++;
  1463. }
  1464. else
  1465. {
  1466. //
  1467. // The buffer must be full - so exit.
  1468. // If no entries are being returned, we will indicate
  1469. // that the buffer was not large enough for even one entry.
  1470. //
  1471. *NumEntries = entriesRead;
  1472. if (entriesRead > 0) {
  1473. return(WN_SUCCESS);
  1474. }
  1475. else {
  1476. *lpBufferSize = ROUND_UP(bytesLeft);
  1477. return(WN_MORE_DATA);
  1478. }
  1479. }
  1480. }
  1481. } // EndIf (state == MORE_ENTRIES)
  1482. } // EndFor (each provider)
  1483. //
  1484. // Update the number of entries to be returned to user
  1485. //
  1486. *NumEntries = entriesRead;
  1487. return(WN_SUCCESS);
  1488. }
  1489. DWORD
  1490. MprProviderEnum(
  1491. IN LPENUM_HANDLE EnumHandlePtr,
  1492. IN OUT LPDWORD lpcCount,
  1493. IN LPVOID lpBuffer,
  1494. IN OUT LPDWORD lpBufferSize
  1495. )
  1496. /*++
  1497. Routine Description:
  1498. This function calls the provider (identified by the EnumHandlePtr)
  1499. with a WNetEnumResource request. Aside from the EnumHandlePtr, all the
  1500. rest of the parameters are simply passed thru to the provider.
  1501. Arguments:
  1502. EnumHandlePtr - This is a pointer to an ENUM_HANDLE structure which
  1503. contains a pointer to the provider structure and the handle for
  1504. that provider's enumeration.
  1505. lpcCount - A pointer to a value that on entry contains the requested
  1506. number of elements to enumerate. On exit this contains the
  1507. actual number of elements enumerated.
  1508. lpBuffer - A pointer to the users buffer that the enumeration data
  1509. is to be placed into.
  1510. lpBufferSize - The number of bytes of free space in the user's buffer.
  1511. Return Value:
  1512. This function can return any return code that WNetEnumResource()
  1513. can return.
  1514. --*/
  1515. {
  1516. DWORD status;
  1517. ASSERT(EnumHandlePtr->pfEnumResource != NULL);
  1518. //
  1519. // Call the provider listed in the ENUM_HANDLE structure and ask it
  1520. // to enumerate.
  1521. //
  1522. status = EnumHandlePtr->pfEnumResource(
  1523. EnumHandlePtr->EnumHandle,
  1524. lpcCount,
  1525. lpBuffer,
  1526. lpBufferSize);
  1527. if (status == WN_SUCCESS) {
  1528. MPR_LOG(TRACE,"EnumResourceHandle = 0x%lx\n",
  1529. EnumHandlePtr->EnumHandle);
  1530. }
  1531. return(status);
  1532. }
  1533. DWORD
  1534. MprCopyResource(
  1535. IN OUT LPBYTE *BufPtr,
  1536. IN const NETRESOURCEW *Resource,
  1537. IN OUT LPDWORD BytesLeft
  1538. )
  1539. /*++
  1540. Routine Description:
  1541. This function copies a single NETRESOURCE structure into a buffer.
  1542. The structure gets copied to the top of the buffer, and the strings
  1543. that the structure references are copied to the bottom of the
  1544. buffer. So any remaining free buffer space is left in the middle.
  1545. Upon successful return from this function, BufPtr will point to
  1546. the top of this remaining free space, and BytesLeft will be updated
  1547. to indicate how many bytes of free space are remaining.
  1548. If there is not enough room in the buffer to copy the Resource and its
  1549. strings, an error is returned, and BufPtr is not changed.
  1550. Arguments:
  1551. BufPtr - This is a pointer to a location that upon entry, contains a
  1552. pointer to the buffer that the copied data is to be placed into.
  1553. Upon exit, this pointer location points to the next free location
  1554. in the buffer.
  1555. Resource - This points to the Resource Structure that is to be copied
  1556. into the buffer.
  1557. BytesLeft - This points to a location to where a count of the remaining
  1558. free bytes in the buffer is stored. This is updated on exit to
  1559. indicate the adjusted number of free bytes left in the buffer.
  1560. If the buffer is not large enough, and WN_MORE_DATA is returned, then
  1561. the size of the buffer required to fit all the data is returned in
  1562. this field.
  1563. Return Value:
  1564. WN_SUCCESS - The operation was successful
  1565. WN_MORE_DATA - The buffer was not large enough to contain the
  1566. Resource structure an its accompanying strings.
  1567. Note:
  1568. History:
  1569. 02-Apr-1992 JohnL
  1570. Changed error return code to WN_MORE_DATA, added code to set the
  1571. required buffer size if WN_MORE_DATA is returned.
  1572. --*/
  1573. {
  1574. LPTSTR startOfFreeBuf;
  1575. LPTSTR endOfFreeBuf;
  1576. LPNETRESOURCEW newResource;
  1577. //
  1578. // The buffer must be at least large enough to hold a resource structure.
  1579. //
  1580. if (*BytesLeft < sizeof(NETRESOURCEW)) {
  1581. *BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
  1582. Resource->lpLocalName,
  1583. Resource->lpComment,
  1584. Resource->lpProvider,
  1585. NULL ) + sizeof(NETRESOURCEW) ;
  1586. return(WN_MORE_DATA);
  1587. }
  1588. //
  1589. // Copy the Resource structure into the beginning of the buffer.
  1590. //
  1591. newResource = (LPNETRESOURCEW) *BufPtr;
  1592. memcpy(newResource, Resource, sizeof(NETRESOURCEW));
  1593. startOfFreeBuf = (LPTSTR)((PCHAR)newResource + sizeof(NETRESOURCEW));
  1594. endOfFreeBuf = (LPTSTR)((LPBYTE)newResource + *BytesLeft);
  1595. //
  1596. // If a REMOTE_NAME string is to be copied, copy that and update the
  1597. // pointer in the structure.
  1598. //
  1599. if (Resource->lpRemoteName != NULL) {
  1600. //
  1601. // If we must copy the remote name,
  1602. //
  1603. if (!NetpCopyStringToBuffer(
  1604. Resource->lpRemoteName, // pointer to string
  1605. wcslen(Resource->lpRemoteName), // num chars in string
  1606. startOfFreeBuf, // start of open space
  1607. &endOfFreeBuf, // end of open space
  1608. &newResource->lpRemoteName)) { // where string pointer goes
  1609. *BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
  1610. Resource->lpLocalName,
  1611. Resource->lpComment,
  1612. Resource->lpProvider,
  1613. NULL ) ;
  1614. goto ErrorMoreData ;
  1615. }
  1616. }
  1617. else{
  1618. newResource->lpRemoteName = NULL;
  1619. }
  1620. //
  1621. // If a LOCAL_NAME string is to be copied, copy that and update the
  1622. // pointer in the structure.
  1623. //
  1624. if( ((Resource->dwScope == RESOURCE_CONNECTED) ||
  1625. (Resource->dwScope == RESOURCE_REMEMBERED))
  1626. &&
  1627. (Resource->lpLocalName != NULL) ) {
  1628. //
  1629. // If we must copy the local name,
  1630. //
  1631. if (!NetpCopyStringToBuffer(
  1632. Resource->lpLocalName, // pointer to string
  1633. wcslen(Resource->lpLocalName), // num chars in string
  1634. startOfFreeBuf, // start of open space
  1635. &endOfFreeBuf, // end of open space
  1636. &newResource->lpLocalName)) // where string pointer goes
  1637. {
  1638. goto ErrorMoreData ;
  1639. }
  1640. }
  1641. else{
  1642. newResource->lpLocalName = NULL;
  1643. }
  1644. //
  1645. // If a COMMENT string is to be copied, copy that and update the
  1646. // pointer in the structure.
  1647. //
  1648. if (Resource->lpComment != NULL) {
  1649. //
  1650. // If we must copy the comment string,
  1651. //
  1652. if (!NetpCopyStringToBuffer(
  1653. Resource->lpComment, // pointer to string
  1654. wcslen(Resource->lpComment), // num chars in string
  1655. startOfFreeBuf, // start of open space
  1656. &endOfFreeBuf, // end of open space
  1657. &newResource->lpComment)) // where string pointer goes
  1658. {
  1659. goto ErrorMoreData ;
  1660. }
  1661. }
  1662. else{
  1663. newResource->lpComment = NULL;
  1664. }
  1665. //
  1666. // If a PROVIDER string is to be copied, copy that and update the
  1667. // pointer in the structure.
  1668. //
  1669. if (Resource->lpProvider != NULL) {
  1670. //
  1671. // If we must copy the provider name,
  1672. //
  1673. if (!NetpCopyStringToBuffer(
  1674. Resource->lpProvider, // pointer to string
  1675. wcslen(Resource->lpProvider), // num chars in string
  1676. startOfFreeBuf, // start of open space
  1677. &endOfFreeBuf, // end of open space
  1678. &newResource->lpProvider)) // where string pointer goes
  1679. {
  1680. goto ErrorMoreData ;
  1681. }
  1682. }
  1683. else{
  1684. newResource->lpProvider = NULL;
  1685. }
  1686. //
  1687. // Update the returned information
  1688. //
  1689. *BufPtr = (LPBYTE)startOfFreeBuf;
  1690. *BytesLeft = (DWORD) ((LPBYTE) endOfFreeBuf - (LPBYTE) startOfFreeBuf);
  1691. return (WN_SUCCESS);
  1692. //
  1693. // This is reached when we couldn't fill the buffer because the given
  1694. // buffer size is too small. We therefore need to set the required
  1695. // buffer size before returning.
  1696. ErrorMoreData:
  1697. *BytesLeft = MprMultiStrBuffSize( Resource->lpRemoteName,
  1698. Resource->lpLocalName,
  1699. Resource->lpComment,
  1700. Resource->lpProvider,
  1701. NULL ) + sizeof(NETRESOURCEW) ;
  1702. return (WN_MORE_DATA);
  1703. }
  1704. DWORD
  1705. MprCopyProviderEnum(
  1706. IN LPNETRESOURCEW ProviderBuffer,
  1707. IN OUT LPDWORD EntryCount,
  1708. IN OUT LPBYTE *TempBufPtr,
  1709. IN OUT LPDWORD BytesLeft
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. This function moves the enumerated NETRESOURCE structures that are
  1714. returned from a provider to a buffer that can be returned to the user.
  1715. The buffer that is returned to the user may contain enum data from
  1716. several providers. Because, we don't know how strings are packed in
  1717. the buffer that is returned from the provider, we must simply walk
  1718. through each structure and copy the information into the user buffer
  1719. in a format that we do know about. Then the amount of free space
  1720. left in the user buffer can be determined so that enum data from
  1721. another provider can be added to it.
  1722. Arguments:
  1723. ProviderBuffer - This is a pointer to the top of an array of NETRESOURCE
  1724. structures that is returned from one of the providers.
  1725. EntryCount - This points to the number of elements in the array that
  1726. was returned from the provider. On exit, this points to the number
  1727. of elements that was successfully copied. This should always be
  1728. the same as the number of elements passed in.
  1729. TempBufPtr - This is a pointer to the top of the free space in the user
  1730. buffer.
  1731. BytesLeft - Upon entry, this contains the number of free space bytes
  1732. in the user buffer. Upon exit, this contains the updated number
  1733. of free space bytes in the user buffer.
  1734. Return Value:
  1735. WN_SUCCESS - The operation was successful
  1736. WN_OUT_OF_MEMORY - The buffer was not large enough to contain all of
  1737. data the provider returned. This should never happen.
  1738. Note:
  1739. --*/
  1740. {
  1741. DWORD i;
  1742. DWORD status;
  1743. DWORD entriesRead=0;
  1744. //
  1745. // Loop for each element in the array of NetResource Structures.
  1746. //
  1747. for(i=0; i<*EntryCount; i++,ProviderBuffer++) {
  1748. status = MprCopyResource(
  1749. TempBufPtr,
  1750. ProviderBuffer,
  1751. BytesLeft);
  1752. if (status != WN_SUCCESS) {
  1753. MPR_LOG(ERROR,"MprCopyProviderEnum: Buffer Size Mismatch\n",0);
  1754. //
  1755. // The buffer must be full - this should never happen since
  1756. // the amount of data placed in the ProviderBuffer is limited
  1757. // by the number of bytes left in the user buffer.
  1758. //
  1759. ASSERT(0);
  1760. *EntryCount = entriesRead;
  1761. return(status);
  1762. }
  1763. entriesRead++;
  1764. }
  1765. *EntryCount = entriesRead;
  1766. return(WN_SUCCESS);
  1767. }
  1768. //===================================================================
  1769. // CProviderOpenEnum - open an enumeration by a provider
  1770. //===================================================================
  1771. DWORD
  1772. CProviderOpenEnum::ValidateRoutedParameters(
  1773. LPCWSTR * ppProviderName,
  1774. LPCWSTR * ppRemoteName,
  1775. LPCWSTR * ppLocalName
  1776. )
  1777. {
  1778. //
  1779. // Let the base class validate any specified provider name.
  1780. // Note: This must be done before setting _lpNetResource to NULL!
  1781. //
  1782. *ppProviderName = _lpNetResource->lpProvider;
  1783. //
  1784. // Check to see if a top level enumeration for the provider is requested.
  1785. // (This is different from a top level MPR enumeration.)
  1786. // A top level enum is signified by a net resource with either a special
  1787. // bit set in the dwUsage field, or a provider name but no remote name.
  1788. //
  1789. if ((_lpNetResource->dwUsage & RESOURCEUSAGE_RESERVED) ||
  1790. IS_EMPTY_STRING(_lpNetResource->lpRemoteName))
  1791. {
  1792. //
  1793. // Top level enum. Don't pass the net resource to the provider.
  1794. //
  1795. ASSERT(! IS_EMPTY_STRING(_lpNetResource->lpProvider));
  1796. _lpNetResource = NULL;
  1797. }
  1798. else
  1799. {
  1800. //
  1801. // Use the remote name as a hint to pick the provider order.
  1802. //
  1803. *ppRemoteName = _lpNetResource->lpRemoteName;
  1804. }
  1805. *ppLocalName = NULL;
  1806. return WN_SUCCESS;
  1807. }
  1808. DWORD
  1809. CProviderOpenEnum::TestProvider(
  1810. const PROVIDER * pProvider
  1811. )
  1812. {
  1813. ASSERT(MPR_IS_INITIALIZED(NETWORK));
  1814. if ((pProvider->GetCaps(WNNC_ENUMERATION) & WNNC_ENUM_GLOBAL) == 0)
  1815. {
  1816. return WN_NOT_SUPPORTED;
  1817. }
  1818. return ( pProvider->OpenEnum(
  1819. _dwScope,
  1820. _dwType,
  1821. _dwUsage,
  1822. _lpNetResource,
  1823. &_ProviderEnumHandle) );
  1824. }
  1825. DWORD
  1826. CProviderOpenEnum::GetResult()
  1827. {
  1828. //
  1829. // Let the base class try the providers until one responds
  1830. // CRoutedOperation::GetResult calls INIT_IF_NECESSARY
  1831. //
  1832. DWORD status = CRoutedOperation::GetResult();
  1833. if (status != WN_SUCCESS)
  1834. {
  1835. return status;
  1836. }
  1837. MPR_LOG(TRACE,"CProviderOpenEnum: OpenEnum Handle = 0x%lx\n",
  1838. _ProviderEnumHandle);
  1839. //
  1840. // Allocate memory to store the handle.
  1841. //
  1842. LPENUM_HANDLE enumHandleStruct =
  1843. (ENUM_HANDLE *) LocalAlloc(LPTR, sizeof(ENUM_HANDLE));
  1844. if (enumHandleStruct == NULL)
  1845. {
  1846. //
  1847. // If we can't allocate memory to store the handle
  1848. // away, then we must close it, and change the status
  1849. // to indicate a memory failure.
  1850. //
  1851. MPR_LOG(ERROR,"CProviderOpenEnum: LocalAlloc failed %d\n",
  1852. GetLastError());
  1853. LastProvider()->CloseEnum(_ProviderEnumHandle);
  1854. status = WN_OUT_OF_MEMORY;
  1855. }
  1856. else
  1857. {
  1858. //
  1859. // Store the handle in the ENUM_HANDLE structure and
  1860. // return the pointer to that structure as a handle
  1861. // for the user.
  1862. //
  1863. enumHandleStruct->Key = PROVIDER_ENUM_KEY;
  1864. //
  1865. // Refcount the provider
  1866. //
  1867. enumHandleStruct->hProviderDll = LoadLibraryEx(LastProvider()->DllName,
  1868. NULL,
  1869. LOAD_WITH_ALTERED_SEARCH_PATH);
  1870. if (enumHandleStruct->hProviderDll == NULL)
  1871. {
  1872. status = GetLastError();
  1873. //
  1874. // This can happen under extreme low memory conditions. The
  1875. // loader can sometimes return ERROR_MOD_NOT_FOUND in this case.
  1876. //
  1877. MPR_LOG2(ERROR,
  1878. "MprOpenEnumConnect: LoadLibraryEx on %ws FAILED %d\n",
  1879. LastProvider()->DllName,
  1880. status);
  1881. ASSERT(status == ERROR_NOT_ENOUGH_MEMORY || status == ERROR_MOD_NOT_FOUND);
  1882. LastProvider()->CloseEnum(_ProviderEnumHandle);
  1883. LocalFree(enumHandleStruct);
  1884. }
  1885. else
  1886. {
  1887. enumHandleStruct->pfEnumResource = LastProvider()->EnumResource;
  1888. enumHandleStruct->pfCloseEnum = LastProvider()->CloseEnum;
  1889. enumHandleStruct->EnumHandle = _ProviderEnumHandle;
  1890. *_lphEnum = enumHandleStruct;
  1891. }
  1892. }
  1893. return status;
  1894. }
  1895. DWORD
  1896. MprOpenRemember(
  1897. IN DWORD dwType,
  1898. OUT LPHANDLE lphRemember
  1899. )
  1900. /*++
  1901. Routine Description:
  1902. Arguments:
  1903. Return Value:
  1904. Note:
  1905. --*/
  1906. {
  1907. LPREMEMBER_HANDLE rememberInfo;
  1908. rememberInfo = (REMEMBER_HANDLE *) LocalAlloc(LPTR, sizeof(REMEMBER_HANDLE));
  1909. if (rememberInfo == NULL) {
  1910. MPR_LOG(ERROR,"MprOpenRemember:LocalAlloc Failed %d\n",GetLastError());
  1911. return(WN_OUT_OF_MEMORY);
  1912. }
  1913. rememberInfo->Key = REMEMBER_KEY;
  1914. rememberInfo->KeyIndex = 0;
  1915. rememberInfo->ConnectionType = dwType;
  1916. //
  1917. // Open the key to the connection information in the current user
  1918. // section of the registry.
  1919. //
  1920. // NOTE: If this fails, we must assume that there is no connection
  1921. // information stored. This is not an error condition.
  1922. // In this case, we store a NULL for the handle so that we know
  1923. // the situation. Each time EnumResource is called, we can try
  1924. // to open the key again.
  1925. //
  1926. if (!MprOpenKey(
  1927. HKEY_CURRENT_USER,
  1928. CONNECTION_KEY_NAME,
  1929. &(rememberInfo->ConnectKey),
  1930. DA_READ)) {
  1931. MPR_LOG(ERROR,"MprOpenRemember: MprOpenKey Failed\n",0);
  1932. rememberInfo->ConnectKey = NULL;
  1933. }
  1934. *lphRemember = (HANDLE)rememberInfo;
  1935. return(WN_SUCCESS);
  1936. }
  1937. DWORD
  1938. MprEnumRemembered(
  1939. IN OUT LPREMEMBER_HANDLE RememberInfo,
  1940. IN OUT LPDWORD NumEntries,
  1941. IN OUT LPBYTE lpBuffer,
  1942. IN OUT LPDWORD lpBufferSize
  1943. )
  1944. /*++
  1945. Routine Description:
  1946. Arguments:
  1947. RememberInfo - This is a pointer to REMEMBER_HANDLE data structure
  1948. that contains the context information for this enumeration handle.
  1949. NumEntries - On entry this points to the maximum number of entries
  1950. that the user desires to receive. On exit it points to the
  1951. number of entries that were placed in the users buffer.
  1952. lpBuffer - This is a pointer to the users buffer in which the
  1953. enumeration data is to be placed.
  1954. lpBufferSize - This is the size (in bytes) of the users buffer.
  1955. Return Value:
  1956. WN_SUCCESS - The call was successful, and some entries were returned.
  1957. However, there are still more entries to be enumerated.
  1958. WN_NO_MORE_ENTRIES - This function has no data to return because
  1959. there was no further connection information in the registry.
  1960. WN_CONNOT_OPEN_PROFILE - This function could open a key to the
  1961. connection information, but could not get any information about
  1962. that key.
  1963. WN_MORE_DATA - The caller's buffer was too small for even one entry.
  1964. Note:
  1965. History:
  1966. Changed to return "status" instead of WN_SUCCESS
  1967. --*/
  1968. {
  1969. DWORD status = WN_SUCCESS ;
  1970. LPTSTR userName;
  1971. NETRESOURCEW netResource;
  1972. LPBYTE tempBufPtr;
  1973. DWORD bytesLeft;
  1974. DWORD entriesRead = 0;
  1975. DWORD numSubKeys;
  1976. DWORD maxSubKeyLen;
  1977. DWORD maxValueLen;
  1978. if ((RememberInfo->ConnectKey == NULL) && (RememberInfo->KeyIndex == 0)) {
  1979. //
  1980. // If we failed to open the key at Open-time, attempt to open it
  1981. // now. This registry key is closed when the CloseEnum function is
  1982. // called.
  1983. //
  1984. if (!MprOpenKey(
  1985. HKEY_CURRENT_USER,
  1986. CONNECTION_KEY_NAME,
  1987. &(RememberInfo->ConnectKey),
  1988. DA_READ)) {
  1989. //
  1990. // We couldn't open the key. So we must assume that it doesn't
  1991. // exist because there if no connection information stored.
  1992. //
  1993. MPR_LOG(ERROR,"MprEnumRemembered: MprOpenKey Failed\n",0);
  1994. RememberInfo->ConnectKey = NULL;
  1995. return(WN_NO_MORE_ENTRIES);
  1996. }
  1997. }
  1998. //
  1999. // Find out the size of the largest key name.
  2000. //
  2001. if(!MprGetKeyInfo(
  2002. RememberInfo->ConnectKey,
  2003. NULL,
  2004. &numSubKeys,
  2005. &maxSubKeyLen,
  2006. NULL,
  2007. &maxValueLen)) {
  2008. MPR_LOG(ERROR,"MprEnumRemembered: MprGetKeyInfo Failed\n",0);
  2009. return(WN_CANNOT_OPEN_PROFILE);
  2010. }
  2011. //
  2012. // If we've already enumerated all the subkeys, there are no more entries.
  2013. //
  2014. if (RememberInfo->KeyIndex >= numSubKeys) {
  2015. return(WN_NO_MORE_ENTRIES);
  2016. }
  2017. tempBufPtr = lpBuffer;
  2018. bytesLeft = ROUND_DOWN(*lpBufferSize);
  2019. tempBufPtr = lpBuffer;
  2020. netResource.lpComment = NULL;
  2021. netResource.dwScope = RESOURCE_REMEMBERED;
  2022. netResource.dwUsage = 0;
  2023. netResource.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  2024. //
  2025. // MprReadConnectionInfo may access the providers
  2026. //
  2027. MprCheckProviders();
  2028. CProviderSharedLock PLock;
  2029. while(
  2030. (RememberInfo->KeyIndex < numSubKeys) &&
  2031. (entriesRead < *NumEntries) &&
  2032. (bytesLeft > sizeof(NETRESOURCE))
  2033. )
  2034. {
  2035. //
  2036. // Get the connection info from the key and stuff it into
  2037. // a NETRESOURCE structure.
  2038. //
  2039. BOOL fMatch = FALSE;
  2040. DWORD ProviderFlags; // ignored
  2041. DWORD DeferFlags; // ignored
  2042. if(!MprReadConnectionInfo(
  2043. RememberInfo->ConnectKey,
  2044. NULL,
  2045. RememberInfo->KeyIndex,
  2046. &ProviderFlags,
  2047. &DeferFlags,
  2048. &userName,
  2049. &netResource,
  2050. NULL,
  2051. maxSubKeyLen)) {
  2052. //
  2053. // NOTE: The ReadConnectionInfo call could return FALSE
  2054. // if it failed in a memory allocation.
  2055. //
  2056. if (entriesRead == 0) {
  2057. status = WN_NO_MORE_ENTRIES;
  2058. }
  2059. else {
  2060. status = WN_SUCCESS;
  2061. }
  2062. break;
  2063. }
  2064. else
  2065. {
  2066. if ((netResource.dwType == RememberInfo->ConnectionType) ||
  2067. (RememberInfo->ConnectionType == RESOURCETYPE_ANY)) {
  2068. fMatch = TRUE;
  2069. }
  2070. }
  2071. //
  2072. // Copy the new netResource information into the user's
  2073. // buffer. Each time this function is called, the tempBufPtr
  2074. // gets updated to point to the next free space in the user's
  2075. // buffer.
  2076. //
  2077. if ( fMatch )
  2078. {
  2079. status = MprCopyResource(
  2080. &tempBufPtr,
  2081. &netResource,
  2082. &bytesLeft);
  2083. if (status != WN_SUCCESS) {
  2084. if (entriesRead == 0) {
  2085. *lpBufferSize = ROUND_UP(bytesLeft);
  2086. status = WN_MORE_DATA;
  2087. }
  2088. else {
  2089. status = WN_SUCCESS;
  2090. }
  2091. break;
  2092. }
  2093. entriesRead++;
  2094. }
  2095. //
  2096. // Free the allocated memory resources.
  2097. //
  2098. LocalFree(netResource.lpLocalName);
  2099. LocalFree(netResource.lpRemoteName);
  2100. LocalFree(netResource.lpProvider);
  2101. if (userName != NULL) {
  2102. LocalFree(userName);
  2103. }
  2104. (RememberInfo->KeyIndex)++;
  2105. }
  2106. *NumEntries = entriesRead;
  2107. return(status);
  2108. }
  2109. DWORD
  2110. MprMultiStrBuffSize(
  2111. IN LPTSTR lpString1,
  2112. IN LPTSTR lpString2,
  2113. IN LPTSTR lpString3,
  2114. IN LPTSTR lpString4,
  2115. IN LPTSTR lpString5
  2116. )
  2117. /*++
  2118. Routine Description:
  2119. This function is a worker function that simply determines the total
  2120. storage requirements needed by the passed set of strings. Any of the
  2121. strings maybe NULL in which case the string will be ignored.
  2122. The NULL terminator is added into the total memory requirements.
  2123. Arguments:
  2124. lpString1 -> 5 - Pointers to valid strings or NULL.
  2125. Return Value:
  2126. The count of bytes required to store the passed strings.
  2127. Note:
  2128. --*/
  2129. {
  2130. DWORD cbRequired = 0 ;
  2131. if ( lpString1 != NULL )
  2132. {
  2133. cbRequired += (wcslen( lpString1 ) + 1) * sizeof(TCHAR);
  2134. }
  2135. if ( lpString2 != NULL )
  2136. {
  2137. cbRequired += (wcslen( lpString2 ) + 1) * sizeof(TCHAR) ;
  2138. }
  2139. if ( lpString3 != NULL )
  2140. {
  2141. cbRequired += (wcslen( lpString3 ) + 1) * sizeof(TCHAR) ;
  2142. }
  2143. if ( lpString4 != NULL )
  2144. {
  2145. cbRequired += (wcslen( lpString4 ) + 1) * sizeof(TCHAR) ;
  2146. }
  2147. if ( lpString5 != NULL )
  2148. {
  2149. cbRequired += (wcslen( lpString5 ) + 1) * sizeof(TCHAR) ;
  2150. }
  2151. return cbRequired ;
  2152. }
  2153. BOOL
  2154. MprNetIsAvailable(
  2155. VOID)
  2156. /*++
  2157. Routine Description:
  2158. This function checks if the net is available by calling the GetCaps
  2159. of each provider to make sure it is started.
  2160. Arguments:
  2161. none
  2162. Return Value:
  2163. TRUE is yes, FALSE otherwise
  2164. Note:
  2165. --*/
  2166. {
  2167. DWORD status = WN_SUCCESS;
  2168. LPDWORD index;
  2169. DWORD indexArray[DEFAULT_MAX_PROVIDERS];
  2170. DWORD numProviders, i;
  2171. LPPROVIDER provider;
  2172. DWORD dwResult ;
  2173. //
  2174. // Find the list of providers to call for this request.
  2175. // If there are no active providers, MprFindCallOrder returns
  2176. // WN_NO_NETWORK.
  2177. //
  2178. index = indexArray;
  2179. status = MprFindCallOrder(
  2180. NULL,
  2181. &index,
  2182. &numProviders,
  2183. NETWORK_TYPE);
  2184. if (status != WN_SUCCESS)
  2185. return(FALSE);
  2186. //
  2187. // Loop through the list of providers, making sure at least one
  2188. // is started
  2189. //
  2190. ASSERT(MPR_IS_INITIALIZED(NETWORK));
  2191. for (i=0; i<numProviders; i++)
  2192. {
  2193. //
  2194. // Call the appropriate providers API entry point
  2195. //
  2196. provider = GlobalProviderInfo + index[i];
  2197. if (provider->GetCaps != NULL)
  2198. {
  2199. dwResult = provider->GetCaps( WNNC_START );
  2200. if (dwResult != 0)
  2201. {
  2202. if (index != indexArray)
  2203. LocalFree(index);
  2204. return (TRUE) ;
  2205. }
  2206. }
  2207. }
  2208. //
  2209. // If memory was allocated by MprFindCallOrder, free it.
  2210. //
  2211. if (index != indexArray)
  2212. LocalFree(index);
  2213. return(FALSE);
  2214. }