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

7770 lines
223 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. enum.c
  5. Abstract:
  6. This module contains server, volume, and directory enumeration
  7. routines supported by NetWare Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 15-Feb-1993
  10. Revision History:
  11. --*/
  12. #include <stdlib.h>
  13. #include <nw.h>
  14. #include <splutil.h>
  15. #include <nwmisc.h>
  16. #include <nwreg.h>
  17. #include <nds.h>
  18. #include <nwapi32.h>
  19. VOID
  20. GetLuid(
  21. IN OUT PLUID plogonid
  22. );
  23. //-------------------------------------------------------------------//
  24. // //
  25. // Definitions //
  26. // //
  27. //-------------------------------------------------------------------//
  28. //
  29. // Other definitions
  30. //
  31. #define ONE_KB 1024
  32. #define TWO_KB 2048
  33. #define FOUR_KB 4096
  34. #define EIGHT_KB 8192
  35. #define TREECHAR L'*'
  36. #define NW_VOLUME_NAME_LEN 256
  37. #define NW_MAX_VOLUME_NUMBER 64
  38. //
  39. // This structure is orginally defined in nwapi32.c, it is redefined
  40. // here so that the routine NWGetFileServerVersionInfo() can be called
  41. // with it.
  42. //
  43. typedef struct _NWC_SERVER_INFO {
  44. HANDLE hConn ;
  45. UNICODE_STRING ServerString ;
  46. } NWC_SERVER_INFO ;
  47. //-------------------------------------------------------------------//
  48. // //
  49. // Local Function Prototypes //
  50. // //
  51. //-------------------------------------------------------------------//
  52. DWORD
  53. NwrOpenEnumServersCommon(
  54. IN NW_ENUM_TYPE EnumType,
  55. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  56. );
  57. DWORD
  58. NwrOpenEnumCommon(
  59. IN LPWSTR ContainerName,
  60. IN NW_ENUM_TYPE EnumType,
  61. IN DWORD_PTR StartingPoint,
  62. IN BOOL ValidateUserFlag,
  63. IN LPWSTR UserName OPTIONAL,
  64. IN LPWSTR Password OPTIONAL,
  65. IN ULONG CreateDisposition,
  66. IN ULONG CreateOptions,
  67. OUT LPDWORD ClassTypeOfNDSLeaf,
  68. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  69. );
  70. DWORD
  71. NwEnumContextInfo(
  72. IN LPNW_ENUM_CONTEXT ContextHandle,
  73. IN DWORD_PTR EntriesRequested,
  74. OUT LPBYTE Buffer,
  75. IN DWORD BufferSize,
  76. OUT LPDWORD BytesNeeded,
  77. OUT LPDWORD EntriesRead
  78. );
  79. DWORD
  80. NwEnumServersAndNdsTrees(
  81. IN LPNW_ENUM_CONTEXT ContextHandle,
  82. IN DWORD_PTR EntriesRequested,
  83. OUT LPBYTE Buffer,
  84. IN DWORD BufferSize,
  85. OUT LPDWORD BytesNeeded,
  86. OUT LPDWORD EntriesRead
  87. );
  88. DWORD
  89. NwEnumPrintServers(
  90. IN LPNW_ENUM_CONTEXT ContextHandle,
  91. IN DWORD_PTR EntriesRequested,
  92. OUT LPBYTE Buffer,
  93. IN DWORD BufferSize,
  94. OUT LPDWORD BytesNeeded,
  95. OUT LPDWORD EntriesRead
  96. );
  97. DWORD
  98. NwEnumVolumes(
  99. IN LPNW_ENUM_CONTEXT ContextHandle,
  100. IN DWORD_PTR EntriesRequested,
  101. OUT LPBYTE Buffer,
  102. IN DWORD BufferSize,
  103. OUT LPDWORD BytesNeeded,
  104. OUT LPDWORD EntriesRead
  105. );
  106. DWORD
  107. NwEnumNdsSubTrees_Disk(
  108. IN LPNW_ENUM_CONTEXT ContextHandle,
  109. IN DWORD_PTR EntriesRequested,
  110. OUT LPBYTE Buffer,
  111. IN DWORD BufferSize,
  112. OUT LPDWORD BytesNeeded,
  113. OUT LPDWORD EntriesRead
  114. );
  115. DWORD
  116. NwEnumNdsSubTrees_Print(
  117. IN LPNW_ENUM_CONTEXT ContextHandle,
  118. IN DWORD_PTR EntriesRequested,
  119. OUT LPBYTE Buffer,
  120. IN DWORD BufferSize,
  121. OUT LPDWORD BytesNeeded,
  122. OUT LPDWORD EntriesRead
  123. );
  124. DWORD
  125. NwEnumNdsSubTrees_Any(
  126. IN LPNW_ENUM_CONTEXT ContextHandle,
  127. IN DWORD_PTR EntriesRequested,
  128. OUT LPBYTE Buffer,
  129. IN DWORD BufferSize,
  130. OUT LPDWORD BytesNeeded,
  131. OUT LPDWORD EntriesRead
  132. );
  133. DWORD
  134. NwEnumQueues(
  135. IN LPNW_ENUM_CONTEXT ContextHandle,
  136. IN DWORD_PTR EntriesRequested,
  137. OUT LPBYTE Buffer,
  138. IN DWORD BufferSize,
  139. OUT LPDWORD BytesNeeded,
  140. OUT LPDWORD EntriesRead
  141. );
  142. DWORD
  143. NwEnumVolumesQueues(
  144. IN LPNW_ENUM_CONTEXT ContextHandle,
  145. IN DWORD_PTR EntriesRequested,
  146. OUT LPBYTE Buffer,
  147. IN DWORD BufferSize,
  148. OUT LPDWORD BytesNeeded,
  149. OUT LPDWORD EntriesRead
  150. );
  151. DWORD
  152. NwEnumDirectories(
  153. IN LPNW_ENUM_CONTEXT ContextHandle,
  154. IN DWORD_PTR EntriesRequested,
  155. OUT LPBYTE Buffer,
  156. IN DWORD BufferSize,
  157. OUT LPDWORD BytesNeeded,
  158. OUT LPDWORD EntriesRead
  159. );
  160. DWORD
  161. NwEnumPrintQueues(
  162. IN LPNW_ENUM_CONTEXT ContextHandle,
  163. IN DWORD_PTR EntriesRequested,
  164. OUT LPBYTE Buffer,
  165. IN DWORD BufferSize,
  166. OUT LPDWORD BytesNeeded,
  167. OUT LPDWORD EntriesRead
  168. );
  169. DWORD
  170. NwGetFirstDirectoryEntry(
  171. IN HANDLE DirHandle,
  172. OUT LPWSTR *DirEntry
  173. );
  174. DWORD
  175. NwGetNextDirectoryEntry(
  176. IN HANDLE DirHandle,
  177. OUT LPWSTR *DirEntry
  178. );
  179. DWORD
  180. NwGetFirstNdsSubTreeEntry(
  181. OUT LPNW_ENUM_CONTEXT ContextHandle,
  182. IN DWORD BufferSize
  183. );
  184. DWORD
  185. NwGetNextNdsSubTreeEntry(
  186. OUT LPNW_ENUM_CONTEXT ContextHandle
  187. );
  188. BYTE
  189. NwGetSubTreeData(
  190. IN DWORD_PTR NdsRawDataPtr,
  191. OUT LPWSTR * SubTreeName,
  192. OUT LPDWORD ResourceScope,
  193. OUT LPDWORD ResourceType,
  194. OUT LPDWORD ResourceDisplayType,
  195. OUT LPDWORD ResourceUsage,
  196. OUT LPWSTR * StrippedObjectName
  197. );
  198. VOID
  199. NwStripNdsUncName(
  200. IN LPWSTR ObjectName,
  201. OUT LPWSTR * StrippedObjectName
  202. );
  203. #define VERIFY_ERROR_NOT_A_NDS_TREE 0x1010FFF0
  204. #define VERIFY_ERROR_PATH_NOT_FOUND 0x1010FFF1
  205. DWORD
  206. NwVerifyNDSObject(
  207. IN LPWSTR lpNDSObjectNamePath,
  208. OUT LPWSTR * lpFullNDSObjectNamePath,
  209. OUT LPDWORD lpClassType,
  210. OUT LPDWORD lpResourceScope,
  211. OUT LPDWORD lpResourceType,
  212. OUT LPDWORD lpResourceDisplayType,
  213. OUT LPDWORD lpResourceUsage
  214. );
  215. DWORD
  216. NwVerifyBinderyObject(
  217. IN LPWSTR lpBinderyObjectNamePath,
  218. OUT LPWSTR * lpFullBinderyObjectNamePath,
  219. OUT LPDWORD lpClassType,
  220. OUT LPDWORD lpResourceScope,
  221. OUT LPDWORD lpResourceType,
  222. OUT LPDWORD lpResourceDisplayType,
  223. OUT LPDWORD lpResourceUsage
  224. );
  225. DWORD
  226. NwGetNDSPathInfo(
  227. IN LPWSTR lpNDSObjectNamePath,
  228. OUT LPWSTR * lpSystemObjectNamePath,
  229. OUT LPWSTR * lpSystemPathPart,
  230. OUT LPDWORD lpClassType,
  231. OUT LPDWORD lpResourceScope,
  232. OUT LPDWORD lpResourceType,
  233. OUT LPDWORD lpResourceDisplayType,
  234. OUT LPDWORD lpResourceUsage
  235. );
  236. DWORD
  237. NwGetBinderyPathInfo(
  238. IN LPWSTR lpBinderyObjectNamePath,
  239. OUT LPWSTR * lpSystemObjectNamePath,
  240. OUT LPWSTR * lpSystemPathPart,
  241. OUT LPDWORD lpClassType,
  242. OUT LPDWORD lpResourceScope,
  243. OUT LPDWORD lpResourceType,
  244. OUT LPDWORD lpResourceDisplayType,
  245. OUT LPDWORD lpResourceUsage
  246. );
  247. BOOL
  248. NwGetRemoteNameParent(
  249. IN LPWSTR lpRemoteName,
  250. OUT LPWSTR * lpRemoteNameParent
  251. );
  252. int __cdecl
  253. SortFunc(
  254. IN CONST VOID *p1,
  255. IN CONST VOID *p2
  256. );
  257. DWORD
  258. NwGetConnectionInformation(
  259. IN LPWSTR lpName,
  260. OUT LPWSTR lpUserName,
  261. OUT LPWSTR lpHostServer
  262. );
  263. VOID
  264. NwpGetUncInfo(
  265. IN LPWSTR lpstrUnc,
  266. OUT WORD * slashCount,
  267. OUT BOOL * isNdsUnc,
  268. OUT LPWSTR * FourthSlash
  269. );
  270. DWORD
  271. NwpGetCurrentUserRegKey(
  272. IN DWORD DesiredAccess,
  273. OUT HKEY *phKeyCurrentUser
  274. );
  275. DWORD
  276. NwQueryInfo(
  277. OUT LPWSTR *ppszPreferredSrv
  278. );
  279. DWORD
  280. NwrOpenEnumContextInfo(
  281. IN LPWSTR Reserved OPTIONAL,
  282. IN DWORD ConnectionType,
  283. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  284. )
  285. /*++
  286. Routine Description:
  287. This function creates a new context handle and initializes it
  288. for enumerating context information (i.e. NDS user context objects
  289. and/or NetWare bindery server connections).
  290. Arguments:
  291. Reserved - Unused.
  292. EnumHandle - Receives the newly created context handle.
  293. Return Value:
  294. ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
  295. not be allocated.
  296. NO_ERROR - Call was successful.
  297. --*/
  298. {
  299. LPWSTR pszCurrentContext = NULL;
  300. DWORD dwPrintOptions;
  301. DWORD status = NwQueryInfo( &pszCurrentContext );
  302. WCHAR Context[MAX_NDS_NAME_CHARS];
  303. LPNW_ENUM_CONTEXT ContextHandle;
  304. UNREFERENCED_PARAMETER(Reserved);
  305. UNREFERENCED_PARAMETER(ConnectionType);
  306. #if DBG
  307. IF_DEBUG(ENUM) {
  308. KdPrint(("\nNWWORKSTATION: NwrOpenEnumContextInfo\n"));
  309. }
  310. #endif
  311. if ( pszCurrentContext &&
  312. status == NO_ERROR )
  313. {
  314. if ( pszCurrentContext[0] == TREECHAR )
  315. {
  316. wcscpy( Context, L"\\\\" );
  317. wcscat( Context, pszCurrentContext + 1 );
  318. LocalFree( pszCurrentContext );
  319. pszCurrentContext = NULL;
  320. return NwrOpenEnumCommon(
  321. Context,
  322. NwsHandleListContextInfo_Tree,
  323. (DWORD_PTR) -1,
  324. FALSE,
  325. NULL,
  326. NULL,
  327. 0,
  328. 0,
  329. NULL,
  330. EnumHandle
  331. );
  332. }
  333. else
  334. {
  335. //
  336. // The user does not have a preferred NDS tree and context. They
  337. // may have only a preferred server.
  338. //
  339. if ( pszCurrentContext[0] != 0 )
  340. {
  341. //
  342. // There is a prefered server.
  343. //
  344. LocalFree( pszCurrentContext );
  345. pszCurrentContext = NULL;
  346. ContextHandle = (PVOID) LocalAlloc(
  347. LMEM_ZEROINIT,
  348. sizeof(NW_ENUM_CONTEXT)
  349. );
  350. if (ContextHandle == NULL)
  351. {
  352. KdPrint(("NWWORKSTATION: NwrOpenEnumContextInfo LocalAlloc Failed %lu\n", GetLastError()));
  353. return ERROR_NOT_ENOUGH_MEMORY;
  354. }
  355. //
  356. // Initialize contents of the context handle structure.
  357. //
  358. ContextHandle->Signature = NW_HANDLE_SIGNATURE;
  359. ContextHandle->HandleType = NwsHandleListContextInfo_Server;
  360. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  361. ContextHandle->ResumeId = (DWORD_PTR) -1;
  362. // The following are set to zero due to the LMEM_ZEROINIT.
  363. // ContextHandle->NdsRawDataBuffer = 0;
  364. // ContextHandle->NdsRawDataSize = 0;
  365. // ContextHandle->NdsRawDataId = 0;
  366. // ContextHandle->NdsRawDataCount = 0;
  367. // ContextHandle->TreeConnectionHandle = 0;
  368. // ContextHandle->ConnectionType = 0;
  369. //
  370. // Return the newly created context.
  371. //
  372. *EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
  373. return NO_ERROR;
  374. }
  375. }
  376. }
  377. //
  378. // There is no information in the registry about the current user.
  379. // We go ahead and make an enumeration handle and return success.
  380. // Later, during a call to NPEnumResource, we will return zero items.
  381. // This is done because there is no valid return code to tell the
  382. // callee that we have no context information to provide.
  383. //
  384. ContextHandle = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  385. sizeof(NW_ENUM_CONTEXT) );
  386. if (ContextHandle == NULL)
  387. {
  388. KdPrint(("NWWORKSTATION: NwrOpenEnumContextInfo LocalAlloc Failed %lu\n", GetLastError()));
  389. return ERROR_NOT_ENOUGH_MEMORY;
  390. }
  391. //
  392. // Initialize contents of the context handle structure.
  393. //
  394. ContextHandle->Signature = NW_HANDLE_SIGNATURE;
  395. ContextHandle->HandleType = NwsHandleListContextInfo_Server;
  396. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  397. ContextHandle->ResumeId = 0; // This will tell NwrEnum to
  398. // give up (i.e. we are done).
  399. // The following are set to zero due to the LMEM_ZEROINIT.
  400. // ContextHandle->NdsRawDataBuffer = 0;
  401. // ContextHandle->NdsRawDataSize = 0;
  402. // ContextHandle->NdsRawDataId = 0;
  403. // ContextHandle->NdsRawDataCount = 0;
  404. // ContextHandle->TreeConnectionHandle = 0;
  405. // ContextHandle->ConnectionType = 0;
  406. //
  407. // Return the newly created context.
  408. //
  409. *EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
  410. return NO_ERROR;
  411. }
  412. DWORD
  413. NwrOpenEnumServersAndNdsTrees(
  414. IN LPWSTR Reserved OPTIONAL,
  415. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  416. )
  417. /*++
  418. Routine Description:
  419. This function creates a new context handle and initializes it
  420. for enumerating the servers and NDS trees on the network.
  421. Arguments:
  422. Reserved - Unused.
  423. EnumHandle - Receives the newly created context handle.
  424. Return Value:
  425. ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
  426. not be allocated.
  427. NO_ERROR - Call was successful.
  428. --*/ // NwrOpenEnumServersAndNdsTrees
  429. {
  430. UNREFERENCED_PARAMETER(Reserved);
  431. #if DBG
  432. IF_DEBUG(ENUM) {
  433. KdPrint( ("\nNWWORKSTATION: NwrOpenEnumServersAndNdsTrees\n") );
  434. }
  435. #endif
  436. return NwrOpenEnumServersCommon(
  437. NwsHandleListServersAndNdsTrees,
  438. EnumHandle
  439. );
  440. }
  441. DWORD
  442. NwOpenEnumPrintServers(
  443. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  444. )
  445. /*++
  446. Routine Description:
  447. This function creates a new context handle and initializes it
  448. for enumerating the print servers on the network.
  449. Arguments:
  450. Reserved - Unused.
  451. EnumHandle - Receives the newly created context handle.
  452. Return Value:
  453. ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
  454. not be allocated.
  455. NO_ERROR - Call was successful.
  456. --*/ // NwOpenEnumPrintServers
  457. {
  458. #if DBG
  459. IF_DEBUG(ENUM) {
  460. KdPrint( ("\nNWWORKSTATION: NwOpenEnumPrintServers\n") );
  461. }
  462. #endif
  463. return NwrOpenEnumServersCommon(
  464. NwsHandleListPrintServers,
  465. EnumHandle
  466. );
  467. }
  468. DWORD
  469. NwrOpenEnumVolumes(
  470. IN LPWSTR Reserved OPTIONAL,
  471. IN LPWSTR ServerName,
  472. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  473. )
  474. /*++
  475. Routine Description:
  476. This function calls a common routine which creates a new context
  477. handle and initializes it for enumerating the volumes on a server.
  478. Arguments:
  479. Reserved - Unused.
  480. ServerName - Supplies the name of the server to enumerate volumes.
  481. This name is prefixed by \\.
  482. EnumHandle - Receives the newly created context handle.
  483. Return Value:
  484. NO_ERROR or reason for failure.
  485. --*/ // NwrOpenEnumVolumes
  486. {
  487. UNREFERENCED_PARAMETER(Reserved);
  488. #if DBG
  489. IF_DEBUG(ENUM) {
  490. KdPrint(("\nNWWORKSTATION: NwrOpenEnumVolumes %ws\n",
  491. ServerName));
  492. }
  493. #endif
  494. return NwrOpenEnumCommon(
  495. ServerName,
  496. NwsHandleListVolumes,
  497. 0,
  498. FALSE,
  499. NULL,
  500. NULL,
  501. FILE_OPEN,
  502. FILE_SYNCHRONOUS_IO_NONALERT,
  503. NULL,
  504. EnumHandle
  505. );
  506. }
  507. DWORD
  508. NwrOpenEnumNdsSubTrees_Disk(
  509. IN LPWSTR Reserved OPTIONAL,
  510. IN LPWSTR ParentPathName,
  511. OUT LPDWORD ClassTypeOfNDSLeaf,
  512. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  513. )
  514. /*++
  515. Routine Description:
  516. This function calls a common routine which creates a new context
  517. handle and initializes it for enumerating the DISK object types
  518. and containers of a sub-tree in a NDS tree.
  519. Arguments:
  520. Reserved - Unused.
  521. ParentPathName - Supplies the name of the tree and the path to a container
  522. to enumerate sub-trees.
  523. EnumHandle - Receives the newly created context handle.
  524. Return Value:
  525. NO_ERROR or reason for failure.
  526. --*/ // NwrOpenEnumNdsSubTrees_Disk
  527. {
  528. UNREFERENCED_PARAMETER(Reserved);
  529. #if DBG
  530. IF_DEBUG(ENUM) {
  531. KdPrint(("\nNWWORKSTATION: NwrOpenEnumNdsSubTrees_Disk %ws\n",
  532. ParentPathName));
  533. }
  534. #endif
  535. return NwrOpenEnumCommon(
  536. ParentPathName,
  537. NwsHandleListNdsSubTrees_Disk,
  538. 0,
  539. FALSE,
  540. NULL,
  541. NULL,
  542. 0,
  543. 0,
  544. ClassTypeOfNDSLeaf,
  545. EnumHandle
  546. );
  547. }
  548. DWORD
  549. NwrOpenEnumNdsSubTrees_Print(
  550. IN LPWSTR Reserved OPTIONAL,
  551. IN LPWSTR ParentPathName,
  552. OUT LPDWORD ClassTypeOfNDSLeaf,
  553. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  554. )
  555. /*++
  556. Routine Description:
  557. This function calls a common routine which creates a new context
  558. handle and initializes it for enumerating the PRINT object types
  559. and containers of a sub-tree in a NDS tree.
  560. Arguments:
  561. Reserved - Unused.
  562. ParentPathName - Supplies the name of the tree and the path to a container
  563. to enumerate sub-trees.
  564. EnumHandle - Receives the newly created context handle.
  565. Return Value:
  566. NO_ERROR or reason for failure.
  567. --*/ // NwrOpenEnumNdsSubTrees_Print
  568. {
  569. #if DBG
  570. IF_DEBUG(ENUM) {
  571. KdPrint(("\nNWWORKSTATION: NwrOpenEnumNdsSubTrees_Print %ws\n",
  572. ParentPathName));
  573. }
  574. #endif
  575. return NwrOpenEnumCommon(
  576. ParentPathName,
  577. NwsHandleListNdsSubTrees_Print,
  578. 0,
  579. FALSE,
  580. NULL,
  581. NULL,
  582. 0,
  583. 0,
  584. ClassTypeOfNDSLeaf,
  585. EnumHandle
  586. );
  587. }
  588. DWORD
  589. NwrOpenEnumNdsSubTrees_Any(
  590. IN LPWSTR Reserved OPTIONAL,
  591. IN LPWSTR ParentPathName,
  592. OUT LPDWORD ClassTypeOfNDSLeaf,
  593. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  594. )
  595. /*++
  596. Routine Description:
  597. This function calls a common routine which creates a new context
  598. handle and initializes it for enumerating the ANY object types
  599. and containers of a sub-tree in a NDS tree.
  600. Arguments:
  601. Reserved - Unused.
  602. ParentPathName - Supplies the name of the tree and the path to a container
  603. to enumerate sub-trees.
  604. EnumHandle - Receives the newly created context handle.
  605. Return Value:
  606. NO_ERROR or reason for failure.
  607. --*/ // NwrOpenEnumNdsSubTrees_Any
  608. {
  609. UNREFERENCED_PARAMETER(Reserved);
  610. #if DBG
  611. IF_DEBUG(ENUM) {
  612. KdPrint(("\nNWWORKSTATION: NwrOpenEnumNdsSubTrees_Any %ws\n",
  613. ParentPathName));
  614. }
  615. #endif
  616. return NwrOpenEnumCommon(
  617. ParentPathName,
  618. NwsHandleListNdsSubTrees_Any,
  619. 0,
  620. FALSE,
  621. NULL,
  622. NULL,
  623. 0,
  624. 0,
  625. ClassTypeOfNDSLeaf,
  626. EnumHandle
  627. );
  628. }
  629. DWORD
  630. NwrOpenEnumQueues(
  631. IN LPWSTR Reserved OPTIONAL,
  632. IN LPWSTR ServerName,
  633. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  634. )
  635. /*++
  636. Routine Description:
  637. This function calls a common routine which creates a new context
  638. handle and initializes it for enumerating the volumes on a server.
  639. Arguments:
  640. Reserved - Unused.
  641. ServerName - Supplies the name of the server to enumerate volumes.
  642. This name is prefixed by \\.
  643. EnumHandle - Receives the newly created context handle.
  644. Return Value:
  645. NO_ERROR or reason for failure.
  646. --*/ // NwrOpenEnumQueues
  647. {
  648. UNREFERENCED_PARAMETER(Reserved);
  649. #if DBG
  650. IF_DEBUG(ENUM) {
  651. KdPrint(("\nNWWORKSTATION: NwrOpenEnumQueues %ws\n",
  652. ServerName));
  653. }
  654. #endif
  655. return NwrOpenEnumCommon(
  656. ServerName,
  657. NwsHandleListQueues,
  658. (DWORD_PTR) -1,
  659. TRUE,
  660. NULL,
  661. NULL,
  662. FILE_OPEN,
  663. FILE_SYNCHRONOUS_IO_NONALERT,
  664. NULL,
  665. EnumHandle
  666. );
  667. }
  668. DWORD
  669. NwrOpenEnumVolumesQueues(
  670. IN LPWSTR Reserved OPTIONAL,
  671. IN LPWSTR ServerName,
  672. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  673. )
  674. /*++
  675. Routine Description:
  676. This function calls a common routine which creates a new context
  677. handle and initializes it for enumerating the volumes/queues on a server.
  678. Arguments:
  679. Reserved - Unused.
  680. ServerName - Supplies the name of the server to enumerate volumes.
  681. This name is prefixed by \\.
  682. EnumHandle - Receives the newly created context handle.
  683. Return Value:
  684. NO_ERROR or reason for failure.
  685. --*/ // NwrOpenEnumVolumesQueues
  686. {
  687. DWORD status;
  688. UNREFERENCED_PARAMETER(Reserved);
  689. #if DBG
  690. IF_DEBUG(ENUM) {
  691. KdPrint(("\nNWWORKSTATION: NwrOpenEnumVolumesQueues %ws\n",
  692. ServerName));
  693. }
  694. #endif
  695. status = NwrOpenEnumCommon(
  696. ServerName,
  697. NwsHandleListVolumesQueues,
  698. 0,
  699. FALSE,
  700. NULL,
  701. NULL,
  702. FILE_OPEN,
  703. FILE_SYNCHRONOUS_IO_NONALERT,
  704. NULL,
  705. EnumHandle
  706. );
  707. if ( status == NO_ERROR )
  708. ((LPNW_ENUM_CONTEXT) *EnumHandle)->ConnectionType = CONNTYPE_DISK;
  709. return status;
  710. }
  711. DWORD
  712. NwrOpenEnumDirectories(
  713. IN LPWSTR Reserved OPTIONAL,
  714. IN LPWSTR ParentPathName,
  715. IN LPWSTR UserName OPTIONAL,
  716. IN LPWSTR Password OPTIONAL,
  717. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  718. )
  719. /*++
  720. Routine Description:
  721. This function calls a common routine which creates a new context
  722. handle and initializes it for enumerating the volumes on a server.
  723. Arguments:
  724. Reserved - Unused.
  725. ParentPathName - Supplies the parent path name in the format of
  726. \\Server\Volume.
  727. UserName - Supplies the username to connect with.
  728. Password - Supplies the password to connect with.
  729. EnumHandle - Receives the newly created context handle.
  730. Return Value:
  731. NO_ERROR or reason for failure.
  732. --*/ //NwrOpenEnumDirectories
  733. {
  734. UNREFERENCED_PARAMETER(Reserved);
  735. #if DBG
  736. IF_DEBUG(ENUM) {
  737. KdPrint(("\nNWWORKSTATION: NwrOpenEnumDirectories %ws\n",
  738. ParentPathName));
  739. }
  740. #endif
  741. return NwrOpenEnumCommon(
  742. ParentPathName,
  743. NwsHandleListDirectories,
  744. 0,
  745. FALSE,
  746. UserName,
  747. Password,
  748. FILE_CREATE,
  749. FILE_CREATE_TREE_CONNECTION |
  750. FILE_SYNCHRONOUS_IO_NONALERT,
  751. NULL,
  752. EnumHandle
  753. );
  754. }
  755. DWORD
  756. NwOpenEnumPrintQueues(
  757. IN LPWSTR ServerName,
  758. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  759. )
  760. /*++
  761. Routine Description:
  762. This function calls a common routine which creates a new context
  763. handle and initializes it for enumerating the print queues on a server.
  764. Arguments:
  765. Reserved - Unused.
  766. ServerName - Supplies the name of the server to enumerate volumes.
  767. This name is prefixed by \\.
  768. EnumHandle - Receives the newly created context handle.
  769. Return Value:
  770. NO_ERROR or reason for failure.
  771. --*/ // NwOpenEnumPrintQueues
  772. {
  773. #if DBG
  774. IF_DEBUG(ENUM) {
  775. KdPrint(("\nNWWORKSTATION: NwOpenEnumPrintQueues %ws\n",
  776. ServerName));
  777. }
  778. #endif
  779. return NwrOpenEnumCommon(
  780. ServerName,
  781. NwsHandleListPrintQueues,
  782. (DWORD_PTR) -1,
  783. TRUE,
  784. NULL,
  785. NULL,
  786. FILE_OPEN,
  787. FILE_SYNCHRONOUS_IO_NONALERT,
  788. NULL,
  789. EnumHandle
  790. );
  791. }
  792. DWORD
  793. NwrOpenEnumServersCommon(
  794. IN NW_ENUM_TYPE EnumType,
  795. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  796. )
  797. /*++
  798. Routine Description:
  799. This function creates a new context handle and initializes it
  800. for enumerating the servers on the network.
  801. Arguments:
  802. EnumType - Supplies the type of the object we want to enumerate
  803. EnumHandle - Receives the newly created context handle.
  804. Return Value:
  805. ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
  806. not be allocated.
  807. NO_ERROR - Call was successful.
  808. --*/ // NwrOpenEnumServersCommon
  809. {
  810. DWORD status = NO_ERROR;
  811. LPNW_ENUM_CONTEXT ContextHandle = NULL;
  812. //
  813. // Allocate memory for the context handle structure.
  814. //
  815. ContextHandle = (PVOID) LocalAlloc(
  816. LMEM_ZEROINIT,
  817. sizeof(NW_ENUM_CONTEXT)
  818. );
  819. if (ContextHandle == NULL) {
  820. KdPrint((
  821. "NWWORKSTATION: NwrOpenEnumServersCommon LocalAlloc Failed %lu\n",
  822. GetLastError()));
  823. return ERROR_NOT_ENOUGH_MEMORY;
  824. }
  825. //
  826. // Initialize contents of the context handle structure.
  827. //
  828. ContextHandle->Signature = NW_HANDLE_SIGNATURE;
  829. ContextHandle->HandleType = EnumType;
  830. ContextHandle->ResumeId = (DWORD_PTR) -1;
  831. ContextHandle->NdsRawDataBuffer = 0x00000000;
  832. ContextHandle->NdsRawDataSize = 0x00000000;
  833. ContextHandle->NdsRawDataId = 0x00000000;
  834. ContextHandle->NdsRawDataCount = 0x00000000;
  835. //
  836. // Set flag to indicate that we are going to enumerate NDS trees first.
  837. //
  838. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NDS;
  839. //
  840. // Impersonate the client
  841. //
  842. if ((status = NwImpersonateClient()) != NO_ERROR)
  843. {
  844. goto CleanExit;
  845. }
  846. //
  847. // We enum servers and nds trees from the preferred server.
  848. //
  849. status = NwOpenPreferredServer(
  850. &ContextHandle->TreeConnectionHandle
  851. );
  852. (void) NwRevertToSelf() ;
  853. if (status == NO_ERROR)
  854. {
  855. //
  856. // Return the newly created context.
  857. //
  858. *EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
  859. return status;
  860. }
  861. CleanExit:
  862. if ( ContextHandle )
  863. {
  864. ContextHandle->Signature = 0x0BADBAD0;
  865. (void) LocalFree((HLOCAL) ContextHandle);
  866. }
  867. return status;
  868. }
  869. DWORD
  870. NwrOpenEnumCommon(
  871. IN LPWSTR ContainerName,
  872. IN NW_ENUM_TYPE EnumType,
  873. IN DWORD_PTR StartingPoint,
  874. IN BOOL ValidateUserFlag,
  875. IN LPWSTR UserName OPTIONAL,
  876. IN LPWSTR Password OPTIONAL,
  877. IN ULONG CreateDisposition,
  878. IN ULONG CreateOptions,
  879. OUT LPDWORD ClassTypeOfNDSLeaf,
  880. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  881. )
  882. /*++
  883. Routine Description:
  884. This function is common code for creating a new context handle
  885. and initializing it for enumerating either volumes, directories,
  886. or NDS subtrees.
  887. Arguments:
  888. ContainerName - Supplies the full path name to the container object
  889. we are enumerating from.
  890. EnumType - Supplies the type of the object we want to enumerate
  891. StartingPoint - Supplies the initial resume ID.
  892. UserName - Supplies the username to connect with.
  893. Password - Supplies the password to connect with.
  894. EnumHandle - Receives the newly created context handle.
  895. Return Value:
  896. ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
  897. not be allocated.
  898. NO_ERROR - Call was successful.
  899. Other errors from failure to open a handle to the server.
  900. --*/ // NwrOpenEnumCommon
  901. {
  902. DWORD status = NO_ERROR;
  903. NTSTATUS ntstatus = STATUS_SUCCESS;
  904. LPNW_ENUM_CONTEXT ContextHandle = NULL;
  905. LPWSTR StrippedContainerName = NULL;
  906. BOOL fImpersonate = FALSE ;
  907. if ( ClassTypeOfNDSLeaf )
  908. *ClassTypeOfNDSLeaf = 0;
  909. //
  910. // Before we do anything, we need to convert the UNC passed to
  911. // us. We need to get rid of any CN=XXX.OU=YYY.O=ZZZ references, and
  912. // convert them to XXX.YYY.ZZZ format. Any NETRESOURCE that we generate
  913. // will look like \\TREE\XXX.YYY.ZZZ for a NDS Unc. We do this to
  914. // work around to a bug in WOW.EXE, that prevents 16 bit apps from
  915. // being launched when the user types NDS paths with the CN= stuff in it.
  916. //
  917. NwStripNdsUncName( ContainerName, &StrippedContainerName );
  918. if ( StrippedContainerName == NULL )
  919. {
  920. KdPrint(("NWWORKSTATION: NwrOpenEnumCommon LocalAlloc Failed %lu\n",
  921. GetLastError()));
  922. return ERROR_NOT_ENOUGH_MEMORY;
  923. }
  924. //
  925. // Allocate memory for the context handle structure and space for
  926. // the ContainerName plus \. Now need one more for NULL terminator
  927. // because it's already included in the structure.
  928. //
  929. ContextHandle = (PVOID) LocalAlloc(
  930. LMEM_ZEROINIT,
  931. sizeof(NW_ENUM_CONTEXT) +
  932. (wcslen(StrippedContainerName) + 1) * sizeof(WCHAR)
  933. );
  934. if (ContextHandle == NULL)
  935. {
  936. if ( StrippedContainerName )
  937. {
  938. (void) LocalFree((HLOCAL) StrippedContainerName);
  939. StrippedContainerName = NULL;
  940. }
  941. KdPrint(("NWWORKSTATION: NwrOpenEnumCommon LocalAlloc Failed %lu\n",
  942. GetLastError()));
  943. return ERROR_NOT_ENOUGH_MEMORY;
  944. }
  945. //
  946. // Initialize contents of the context handle structure.
  947. //
  948. ContextHandle->Signature = NW_HANDLE_SIGNATURE;
  949. ContextHandle->HandleType = EnumType;
  950. ContextHandle->ResumeId = StartingPoint;
  951. //
  952. // These are set to zero due to LMEM_ZEROINIT.
  953. //
  954. // ContextHandle->NdsRawDataBuffer = 0;
  955. // ContextHandle->NdsRawDataSize = 0;
  956. // ContextHandle->NdsRawDataId = 0;
  957. // ContextHandle->NdsRawDataCount = 0;
  958. // ContextHandle->TreeConnectionHandle = 0;
  959. //
  960. // Impersonate the client
  961. //
  962. if ( ( status = NwImpersonateClient() ) != NO_ERROR )
  963. {
  964. goto ErrorExit;
  965. }
  966. fImpersonate = TRUE;
  967. if ( EnumType == NwsHandleListNdsSubTrees_Disk ||
  968. EnumType == NwsHandleListNdsSubTrees_Print ||
  969. EnumType == NwsHandleListNdsSubTrees_Any ||
  970. EnumType == NwsHandleListContextInfo_Tree )
  971. {
  972. WCHAR lpServerName[NW_MAX_SERVER_LEN];
  973. UNICODE_STRING ServerName;
  974. UNICODE_STRING ObjectName;
  975. ServerName.Length = 0;
  976. ServerName.MaximumLength = sizeof( lpServerName );
  977. ServerName.Buffer = lpServerName;
  978. ObjectName.Buffer = NULL;
  979. if ( EnumType == NwsHandleListContextInfo_Tree )
  980. {
  981. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  982. }
  983. else
  984. {
  985. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NDS;
  986. }
  987. ObjectName.MaximumLength = ( wcslen( StrippedContainerName ) + 1 ) *
  988. sizeof( WCHAR );
  989. ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
  990. StrippedContainerName,
  991. PARSE_NDS_GET_TREE_NAME );
  992. if ( ObjectName.Length == 0 || ObjectName.Buffer == NULL )
  993. {
  994. status = ERROR_PATH_NOT_FOUND;
  995. goto ErrorExit;
  996. }
  997. //
  998. // Open a NDS tree connection handle to \\treename
  999. //
  1000. ntstatus = NwNdsOpenTreeHandle( &ObjectName,
  1001. &ContextHandle->TreeConnectionHandle );
  1002. if ( ntstatus != STATUS_SUCCESS )
  1003. {
  1004. status = RtlNtStatusToDosError(ntstatus);
  1005. goto ErrorExit;
  1006. }
  1007. //
  1008. // Get the path to the container to open.
  1009. //
  1010. ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
  1011. StrippedContainerName,
  1012. PARSE_NDS_GET_PATH_NAME
  1013. );
  1014. if ( ObjectName.Length == 0 )
  1015. {
  1016. UNICODE_STRING Root;
  1017. RtlInitUnicodeString(&Root, L"[Root]");
  1018. //
  1019. // Resolve the path to get a NDS object id of [Root].
  1020. //
  1021. ntstatus = NwNdsResolveName( ContextHandle->TreeConnectionHandle,
  1022. &Root,
  1023. &ContextHandle->dwOid,
  1024. &ServerName,
  1025. NULL,
  1026. 0 );
  1027. if ( ntstatus != STATUS_SUCCESS )
  1028. {
  1029. status = RtlNtStatusToDosError(ntstatus);
  1030. goto ErrorExit;
  1031. }
  1032. wcscpy(ContextHandle->ContainerName, StrippedContainerName);
  1033. }
  1034. else
  1035. {
  1036. //
  1037. // Resolve the path to get a NDS object id.
  1038. //
  1039. ntstatus = NwNdsResolveName( ContextHandle->TreeConnectionHandle,
  1040. &ObjectName,
  1041. &ContextHandle->dwOid,
  1042. &ServerName,
  1043. NULL,
  1044. 0 );
  1045. if ( ntstatus != STATUS_SUCCESS )
  1046. {
  1047. status = RtlNtStatusToDosError(ntstatus);
  1048. goto ErrorExit;
  1049. }
  1050. wcscpy(ContextHandle->ContainerName, StrippedContainerName);
  1051. }
  1052. if ( ServerName.Length )
  1053. {
  1054. DWORD dwHandleType;
  1055. //
  1056. // NwNdsResolveName succeeded, but we were referred to
  1057. // another server, though ContextHandle->dwOid is still valid.
  1058. if ( ContextHandle->TreeConnectionHandle )
  1059. CloseHandle( ContextHandle->TreeConnectionHandle );
  1060. ContextHandle->TreeConnectionHandle = 0;
  1061. //
  1062. // Open a NDS generic connection handle to \\ServerName
  1063. //
  1064. ntstatus = NwNdsOpenGenericHandle( &ServerName,
  1065. &dwHandleType,
  1066. &ContextHandle->TreeConnectionHandle );
  1067. if ( ntstatus != STATUS_SUCCESS )
  1068. {
  1069. status = RtlNtStatusToDosError(ntstatus);
  1070. goto ErrorExit;
  1071. }
  1072. ASSERT( dwHandleType == HANDLE_TYPE_NCP_SERVER );
  1073. }
  1074. //
  1075. // Check to see if object is either a Server, Directory Map, or Volume.
  1076. // If so, the object is a known leaf in terms of NDS, and therefore cannot
  1077. // be enumerated through NwNdsList API calls. We fail the OpenEnum call in these
  1078. // cases and pass back the type of object the leaf node was. This way the code in
  1079. // NWPROVAU!NPOpenEnum can call NwrOpenEnumServer, NwrOpenEnumVolume, or
  1080. // NwrOpenEnumDirectories accordingly.
  1081. //
  1082. {
  1083. BYTE RawResponse[TWO_KB];
  1084. DWORD RawResponseSize = sizeof(RawResponse);
  1085. DWORD dwStrLen;
  1086. PBYTE pbRawGetInfo;
  1087. ntstatus = NwNdsReadObjectInfo( ContextHandle->TreeConnectionHandle,
  1088. ContextHandle->dwOid,
  1089. RawResponse,
  1090. RawResponseSize );
  1091. if ( ntstatus != NO_ERROR )
  1092. {
  1093. status = RtlNtStatusToDosError(ntstatus);
  1094. goto ErrorExit;
  1095. }
  1096. (void) NwRevertToSelf() ;
  1097. fImpersonate = FALSE;
  1098. pbRawGetInfo = RawResponse;
  1099. //
  1100. // The structure of a NDS_RESPONSE_GET_OBJECT_INFO consists of 4 DWORDs
  1101. // followed by two standard NDS format UNICODE strings. Below we jump pbRawGetInfo
  1102. // into the buffer, past the 4 DWORDs.
  1103. //
  1104. pbRawGetInfo += sizeof ( NDS_RESPONSE_GET_OBJECT_INFO );
  1105. //
  1106. // Now we get the length of the first string (Base Class).
  1107. //
  1108. dwStrLen = * ( DWORD * ) pbRawGetInfo;
  1109. //
  1110. // Now we point pbRawGetInfo to the first WCHAR of the first string (Base Class).
  1111. //
  1112. pbRawGetInfo += sizeof( DWORD );
  1113. //
  1114. // If the object is either a NCP Server, Volume, or a Directory Map, we fail
  1115. // the OpenEnum call and return the class type of the NDS leaf object. We do
  1116. // this because we cannot enumerate through NwNdsList() calls any subordinates,
  1117. // all browsing below these types are done through system redirector calls. So
  1118. // the client side of the provider will instead call NwOpenEnumVolumes or
  1119. // NwOpenEnumDirectories, respectively.
  1120. //
  1121. if ( !wcscmp( (LPWSTR) pbRawGetInfo, L"NCP Server" ) )
  1122. {
  1123. if ( ClassTypeOfNDSLeaf )
  1124. *ClassTypeOfNDSLeaf = CLASS_TYPE_NCP_SERVER;
  1125. status = ERROR_NETWORK_ACCESS_DENIED;
  1126. goto ErrorExit;
  1127. }
  1128. if ( !wcscmp( (LPWSTR) pbRawGetInfo, L"Volume" ) )
  1129. {
  1130. if ( ClassTypeOfNDSLeaf )
  1131. *ClassTypeOfNDSLeaf = CLASS_TYPE_VOLUME;
  1132. status = ERROR_NETWORK_ACCESS_DENIED;
  1133. goto ErrorExit;
  1134. }
  1135. if ( !wcscmp( (LPWSTR) pbRawGetInfo, L"Directory Map" ) )
  1136. {
  1137. if ( ClassTypeOfNDSLeaf )
  1138. *ClassTypeOfNDSLeaf = CLASS_TYPE_DIRECTORY_MAP;
  1139. status = ERROR_NETWORK_ACCESS_DENIED;
  1140. goto ErrorExit;
  1141. }
  1142. } // End of block
  1143. }
  1144. else // EnumType is something other than a NDS Sub-tree
  1145. {
  1146. UNICODE_STRING TreeConnectStr;
  1147. TreeConnectStr.Buffer = NULL;
  1148. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  1149. wcscpy(ContextHandle->ContainerName, StrippedContainerName);
  1150. wcscat(ContextHandle->ContainerName, L"\\");
  1151. //
  1152. // Open a tree connection handle to \Device\NwRdr\ContainerName
  1153. //
  1154. status = NwCreateTreeConnectName( StrippedContainerName,
  1155. NULL,
  1156. &TreeConnectStr );
  1157. if ( status != NO_ERROR )
  1158. {
  1159. goto ErrorExit;
  1160. }
  1161. status = NwOpenCreateConnection( &TreeConnectStr,
  1162. UserName,
  1163. Password,
  1164. StrippedContainerName,
  1165. FILE_LIST_DIRECTORY | SYNCHRONIZE |
  1166. ( ValidateUserFlag? FILE_WRITE_DATA : 0 ),
  1167. CreateDisposition,
  1168. CreateOptions,
  1169. RESOURCETYPE_DISK, // When connecting beyond servername
  1170. &ContextHandle->TreeConnectionHandle,
  1171. NULL );
  1172. (void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
  1173. }
  1174. if (status == NO_ERROR)
  1175. {
  1176. VERSION_INFO vInfo;
  1177. if ( EnumType == NwsHandleListVolumes ||
  1178. EnumType == NwsHandleListVolumesQueues )
  1179. {
  1180. NWC_SERVER_INFO ServerInfo;
  1181. ServerInfo.hConn = ContextHandle->TreeConnectionHandle;
  1182. ServerInfo.ServerString.Length = 0;
  1183. ServerInfo.ServerString.MaximumLength = 0;
  1184. ServerInfo.ServerString.Buffer = NULL;
  1185. status = NWGetFileServerVersionInfo( (HANDLE) &ServerInfo,
  1186. &vInfo );
  1187. if ( status )
  1188. {
  1189. ContextHandle->dwMaxVolumes = NW_MAX_VOLUME_NUMBER;
  1190. status = NO_ERROR;
  1191. }
  1192. else
  1193. {
  1194. ContextHandle->dwMaxVolumes = (DWORD) vInfo.maxVolumes;
  1195. if ( ContextHandle->dwMaxVolumes == 0 )
  1196. {
  1197. ContextHandle->dwMaxVolumes = NW_MAX_VOLUME_NUMBER;
  1198. }
  1199. }
  1200. }
  1201. (void) NwRevertToSelf() ;
  1202. fImpersonate = FALSE;
  1203. if ( StrippedContainerName )
  1204. {
  1205. (void) LocalFree((HLOCAL) StrippedContainerName);
  1206. StrippedContainerName = NULL;
  1207. }
  1208. //
  1209. // Return the newly created context.
  1210. //
  1211. *EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
  1212. return status;
  1213. }
  1214. ErrorExit:
  1215. if ( fImpersonate )
  1216. (void) NwRevertToSelf() ;
  1217. if ( StrippedContainerName )
  1218. {
  1219. (void) LocalFree((HLOCAL) StrippedContainerName);
  1220. }
  1221. if ( ContextHandle )
  1222. {
  1223. if ( ContextHandle->TreeConnectionHandle )
  1224. CloseHandle( ContextHandle->TreeConnectionHandle );
  1225. ContextHandle->Signature = 0x0BADBAD0;
  1226. (void) LocalFree((HLOCAL) ContextHandle);
  1227. }
  1228. *EnumHandle = NULL;
  1229. if (status == ERROR_NOT_CONNECTED)
  1230. {
  1231. //
  1232. // Object name not found. We should return path not found.
  1233. //
  1234. status = ERROR_PATH_NOT_FOUND;
  1235. }
  1236. return status;
  1237. }
  1238. DWORD
  1239. NwrEnum(
  1240. IN NWWKSTA_CONTEXT_HANDLE EnumHandle,
  1241. IN DWORD_PTR EntriesRequested,
  1242. OUT LPBYTE Buffer,
  1243. IN DWORD BufferSize,
  1244. OUT LPDWORD BytesNeeded,
  1245. OUT LPDWORD EntriesRead
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. This function
  1250. Arguments:
  1251. EnumHandle - Supplies a pointer to the context handle which identifies
  1252. what type of object we are enumerating and the string of the
  1253. container name to concatenate to the returned object.
  1254. EntriesRequested - Supplies the number of entries to return. If
  1255. this value is -1, return all available entries.
  1256. Buffer - Receives the entries we are listing.
  1257. BufferSize - Supplies the size of the output buffer.
  1258. BytesNeeded - Receives the number of bytes required to get the
  1259. first entry. This value is returned iff WN_MORE_DATA is
  1260. the return code, and Buffer is too small to even fit one
  1261. entry.
  1262. EntriesRead - Receives the number of entries returned in Buffer.
  1263. This value is only returned iff NO_ERROR is the return code.
  1264. NO_ERROR is returned as long as at least one entry was written
  1265. into Buffer but does not necessarily mean that it's the number
  1266. of EntriesRequested.
  1267. Return Value:
  1268. NO_ERROR - At least one entry was written to output buffer,
  1269. irregardless of the number requested.
  1270. WN_NO_MORE_ENTRIES - No entries left to return.
  1271. WN_MORE_DATA - The buffer was too small to fit a single entry.
  1272. WN_BAD_HANDLE - The specified enumeration handle is invalid.
  1273. --*/ // NwrEnum
  1274. {
  1275. DWORD status;
  1276. LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) EnumHandle;
  1277. BOOL fImpersonate = FALSE ;
  1278. if (ContextHandle->Signature != NW_HANDLE_SIGNATURE) {
  1279. return WN_BAD_HANDLE;
  1280. }
  1281. //
  1282. // Impersonate the client
  1283. //
  1284. if ((status = NwImpersonateClient()) != NO_ERROR)
  1285. {
  1286. goto CleanExit;
  1287. }
  1288. fImpersonate = TRUE ;
  1289. *EntriesRead = 0;
  1290. *BytesNeeded = 0;
  1291. RtlZeroMemory(Buffer, BufferSize);
  1292. switch (ContextHandle->HandleType) {
  1293. case NwsHandleListConnections:
  1294. {
  1295. if (!(ContextHandle->ConnectionType & CONNTYPE_SYMBOLIC))
  1296. {
  1297. status = NwEnumerateConnections(
  1298. &ContextHandle->ResumeId,
  1299. EntriesRequested,
  1300. Buffer,
  1301. BufferSize,
  1302. BytesNeeded,
  1303. EntriesRead,
  1304. ContextHandle->ConnectionType,
  1305. NULL
  1306. );
  1307. if (status != ERROR_NO_MORE_ITEMS)
  1308. break;
  1309. else
  1310. {
  1311. //
  1312. // finished with all redir connections. look for
  1313. // symbolic ones. we got NO MORE ITEMS back, so we just
  1314. // carry one with the next set with the same buffers.
  1315. //
  1316. ContextHandle->ConnectionType |= CONNTYPE_SYMBOLIC ;
  1317. ContextHandle->ResumeId = 0 ;
  1318. }
  1319. }
  1320. if (ContextHandle->ConnectionType & CONNTYPE_SYMBOLIC)
  1321. {
  1322. //
  1323. // This works around a weirdness in
  1324. // QueryDosDevices called by NwrEnumGWDevices.
  1325. // While impersonating the Win32 API will just fail.
  1326. //
  1327. (void) NwRevertToSelf() ;
  1328. fImpersonate = FALSE ;
  1329. status = NwrEnumGWDevices(
  1330. NULL,
  1331. &((DWORD) ContextHandle->ResumeId),
  1332. Buffer,
  1333. BufferSize,
  1334. BytesNeeded,
  1335. EntriesRead) ;
  1336. //
  1337. // if we have more items, MPR expects success. map
  1338. // accordingly.
  1339. //
  1340. if ((status == ERROR_MORE_DATA) && *EntriesRead)
  1341. {
  1342. status = NO_ERROR ;
  1343. }
  1344. //
  1345. // if nothing left, map to the distinguished MPR error
  1346. //
  1347. else if ((status == NO_ERROR) && (*EntriesRead == 0))
  1348. {
  1349. status = ERROR_NO_MORE_ITEMS ;
  1350. }
  1351. break ;
  1352. }
  1353. }
  1354. case NwsHandleListContextInfo_Tree:
  1355. case NwsHandleListContextInfo_Server:
  1356. status = NwEnumContextInfo(
  1357. ContextHandle,
  1358. EntriesRequested,
  1359. Buffer,
  1360. BufferSize,
  1361. BytesNeeded,
  1362. EntriesRead
  1363. );
  1364. break;
  1365. case NwsHandleListServersAndNdsTrees:
  1366. status = NwEnumServersAndNdsTrees(
  1367. ContextHandle,
  1368. EntriesRequested,
  1369. Buffer,
  1370. BufferSize,
  1371. BytesNeeded,
  1372. EntriesRead
  1373. );
  1374. break;
  1375. case NwsHandleListVolumes:
  1376. status = NwEnumVolumes(
  1377. ContextHandle,
  1378. EntriesRequested,
  1379. Buffer,
  1380. BufferSize,
  1381. BytesNeeded,
  1382. EntriesRead
  1383. );
  1384. break;
  1385. case NwsHandleListNdsSubTrees_Disk:
  1386. status = NwEnumNdsSubTrees_Disk(
  1387. ContextHandle,
  1388. EntriesRequested,
  1389. Buffer,
  1390. BufferSize,
  1391. BytesNeeded,
  1392. EntriesRead
  1393. );
  1394. break;
  1395. case NwsHandleListNdsSubTrees_Print:
  1396. status = NwEnumNdsSubTrees_Print(
  1397. ContextHandle,
  1398. EntriesRequested,
  1399. Buffer,
  1400. BufferSize,
  1401. BytesNeeded,
  1402. EntriesRead
  1403. );
  1404. break;
  1405. case NwsHandleListNdsSubTrees_Any:
  1406. status = NwEnumNdsSubTrees_Any(
  1407. ContextHandle,
  1408. EntriesRequested,
  1409. Buffer,
  1410. BufferSize,
  1411. BytesNeeded,
  1412. EntriesRead
  1413. );
  1414. break;
  1415. case NwsHandleListQueues:
  1416. status = NwEnumQueues(
  1417. ContextHandle,
  1418. EntriesRequested,
  1419. Buffer,
  1420. BufferSize,
  1421. BytesNeeded,
  1422. EntriesRead
  1423. );
  1424. break;
  1425. case NwsHandleListVolumesQueues:
  1426. status = NwEnumVolumesQueues(
  1427. ContextHandle,
  1428. EntriesRequested,
  1429. Buffer,
  1430. BufferSize,
  1431. BytesNeeded,
  1432. EntriesRead
  1433. );
  1434. break;
  1435. case NwsHandleListDirectories:
  1436. status = NwEnumDirectories(
  1437. ContextHandle,
  1438. EntriesRequested,
  1439. Buffer,
  1440. BufferSize,
  1441. BytesNeeded,
  1442. EntriesRead
  1443. );
  1444. break;
  1445. case NwsHandleListPrintServers:
  1446. status = NwEnumPrintServers(
  1447. ContextHandle,
  1448. EntriesRequested,
  1449. Buffer,
  1450. BufferSize,
  1451. BytesNeeded,
  1452. EntriesRead
  1453. );
  1454. break;
  1455. case NwsHandleListPrintQueues:
  1456. status = NwEnumPrintQueues(
  1457. ContextHandle,
  1458. EntriesRequested,
  1459. Buffer,
  1460. BufferSize,
  1461. BytesNeeded,
  1462. EntriesRead
  1463. );
  1464. break;
  1465. default:
  1466. KdPrint(("NWWORKSTATION: NwrEnum unexpected handle type %lu\n",
  1467. ContextHandle->HandleType));
  1468. ASSERT(FALSE);
  1469. status = WN_BAD_HANDLE;
  1470. goto CleanExit ;
  1471. }
  1472. if (*EntriesRead > 0) {
  1473. switch ( ContextHandle->HandleType ) {
  1474. case NwsHandleListConnections:
  1475. case NwsHandleListContextInfo_Tree:
  1476. case NwsHandleListContextInfo_Server:
  1477. case NwsHandleListServersAndNdsTrees:
  1478. case NwsHandleListVolumes:
  1479. case NwsHandleListQueues:
  1480. case NwsHandleListVolumesQueues:
  1481. case NwsHandleListDirectories:
  1482. case NwsHandleListNdsSubTrees_Disk:
  1483. case NwsHandleListNdsSubTrees_Any:
  1484. {
  1485. DWORD i;
  1486. LPNETRESOURCEW NetR = (LPNETRESOURCEW) Buffer;
  1487. //
  1488. // Replace pointers to strings with offsets as need
  1489. //
  1490. if ((ContextHandle->HandleType == NwsHandleListConnections)
  1491. && (ContextHandle->ConnectionType & CONNTYPE_SYMBOLIC))
  1492. {
  1493. //
  1494. // NwrEnumGWDevices already return offsets.
  1495. //
  1496. break ;
  1497. }
  1498. for (i = 0; i < *EntriesRead; i++, NetR++) {
  1499. if (NetR->lpLocalName != NULL) {
  1500. NetR->lpLocalName = (LPWSTR)
  1501. ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) Buffer);
  1502. }
  1503. NetR->lpRemoteName =
  1504. (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR)Buffer);
  1505. if (NetR->lpComment != NULL) {
  1506. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) -
  1507. (DWORD_PTR) Buffer);
  1508. }
  1509. if (NetR->lpProvider != NULL) {
  1510. NetR->lpProvider =
  1511. (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) -
  1512. (DWORD_PTR) Buffer);
  1513. }
  1514. }
  1515. break;
  1516. }
  1517. case NwsHandleListPrintServers:
  1518. case NwsHandleListPrintQueues:
  1519. case NwsHandleListNdsSubTrees_Print:
  1520. {
  1521. DWORD i;
  1522. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) Buffer;
  1523. //
  1524. // Sort the entries in the buffer
  1525. //
  1526. if ( *EntriesRead > 1 )
  1527. qsort( Buffer, *EntriesRead,
  1528. sizeof( PRINTER_INFO_1W ), SortFunc );
  1529. //
  1530. // Replace pointers to strings with offsets
  1531. //
  1532. for (i = 0; i < *EntriesRead; i++, pPrinterInfo1++) {
  1533. MarshallDownStructure( (LPBYTE) pPrinterInfo1,
  1534. PrinterInfo1Offsets,
  1535. Buffer );
  1536. }
  1537. break;
  1538. }
  1539. default:
  1540. KdPrint(("NWWORKSTATION: NwrEnum (pointer to offset code) unexpected handle type %lu\n", ContextHandle->HandleType));
  1541. ASSERT( FALSE );
  1542. break;
  1543. }
  1544. }
  1545. CleanExit:
  1546. if (fImpersonate)
  1547. (void) NwRevertToSelf() ;
  1548. return status;
  1549. }
  1550. DWORD
  1551. NwrEnumConnections(
  1552. IN NWWKSTA_CONTEXT_HANDLE EnumHandle,
  1553. IN DWORD EntriesRequested,
  1554. OUT LPBYTE Buffer,
  1555. IN DWORD BufferSize,
  1556. OUT LPDWORD BytesNeeded,
  1557. OUT LPDWORD EntriesRead,
  1558. IN DWORD fImplicitConnections
  1559. )
  1560. /*++
  1561. Routine Description:
  1562. This function is an alternate to NwrEnum. It only accepts handles
  1563. that are opened with ListConnections. This function takes a flag
  1564. indicating whether we need to show all implicit connections or not.
  1565. Arguments:
  1566. ContextHandle - Supplies the enum context handle.
  1567. EntriesRequested - Supplies the number of entries to return. If
  1568. this value is -1, return all available entries.
  1569. Buffer - Receives the entries we are listing.
  1570. BufferSize - Supplies the size of the output buffer.
  1571. BytesNeeded - Receives the number of bytes required to get the
  1572. first entry. This value is returned iff ERROR_MORE_DATA is
  1573. the return code, and Buffer is too small to even fit one
  1574. entry.
  1575. EntriesRead - Receives the number of entries returned in Buffer.
  1576. This value is only returned iff NO_ERROR is the return code.
  1577. NO_ERROR is returned as long as at least one entry was written
  1578. into Buffer but does not necessarily mean that it's the number
  1579. of EntriesRequested.
  1580. fImplicitConnections - TRUE if we also want to get implicit connections,
  1581. FALSE otherwise.
  1582. Return Value:
  1583. NO_ERROR - At least one entry was written to output buffer,
  1584. irregardless of the number requested.
  1585. WN_NO_MORE_ENTRIES - No entries left to return.
  1586. ERROR_MORE_DATA - The buffer was too small to fit a single entry.
  1587. --*/ // NwrEnumConnections
  1588. {
  1589. DWORD status;
  1590. LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) EnumHandle;
  1591. if ( (ContextHandle->Signature != NW_HANDLE_SIGNATURE)
  1592. || ( ContextHandle->HandleType != NwsHandleListConnections )
  1593. )
  1594. {
  1595. return WN_BAD_HANDLE;
  1596. }
  1597. *EntriesRead = 0;
  1598. *BytesNeeded = 0;
  1599. RtlZeroMemory(Buffer, BufferSize);
  1600. if ( fImplicitConnections )
  1601. ContextHandle->ConnectionType |= CONNTYPE_IMPLICIT;
  1602. if ((status = NwImpersonateClient()) != NO_ERROR)
  1603. goto ErrorExit;
  1604. status = NwEnumerateConnections(
  1605. &ContextHandle->ResumeId,
  1606. EntriesRequested,
  1607. Buffer,
  1608. BufferSize,
  1609. BytesNeeded,
  1610. EntriesRead,
  1611. ContextHandle->ConnectionType,
  1612. NULL
  1613. );
  1614. if (*EntriesRead > 0) {
  1615. //
  1616. // Replace pointers to strings with offsets
  1617. //
  1618. DWORD i;
  1619. LPNETRESOURCEW NetR = (LPNETRESOURCEW) Buffer;
  1620. for (i = 0; i < *EntriesRead; i++, NetR++) {
  1621. if (NetR->lpLocalName != NULL) {
  1622. NetR->lpLocalName = (LPWSTR)
  1623. ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) Buffer);
  1624. }
  1625. NetR->lpRemoteName =
  1626. (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR)Buffer);
  1627. if (NetR->lpComment != NULL) {
  1628. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) -
  1629. (DWORD_PTR) Buffer);
  1630. }
  1631. if (NetR->lpProvider != NULL) {
  1632. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) -
  1633. (DWORD_PTR) Buffer);
  1634. }
  1635. }
  1636. }
  1637. (void) NwRevertToSelf();
  1638. ErrorExit:
  1639. return status;
  1640. }
  1641. DWORD
  1642. NwEnumContextInfo(
  1643. IN LPNW_ENUM_CONTEXT ContextHandle,
  1644. IN DWORD_PTR EntriesRequested,
  1645. OUT LPBYTE Buffer,
  1646. IN DWORD BufferSize,
  1647. OUT LPDWORD BytesNeeded,
  1648. OUT LPDWORD EntriesRead
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. This function enumerates all of the bindery servers that are currently
  1653. connected, then sets the context handle so that the next NPEnumResource
  1654. call goes to the NDS subtree for the user's NDS context information
  1655. (if using NDS).
  1656. Arguments:
  1657. ContextHandle - Supplies the enum context handle.
  1658. EntriesRequested - Supplies the number of entries to return. If
  1659. this value is -1, return all available entries.
  1660. Buffer - Receives the entries we are listing.
  1661. BufferSize - Supplies the size of the output buffer.
  1662. BytesNeeded - Receives the number of bytes required to get the
  1663. first entry. This value is returned iff WN_MORE_DATA is
  1664. the return code, and Buffer is too small to even fit one
  1665. entry.
  1666. EntriesRead - Receives the number of entries returned in Buffer.
  1667. This value is only returned iff NO_ERROR is the return code.
  1668. NO_ERROR is returned as long as at least one entry was written
  1669. into Buffer but does not necessarily mean that it's the number
  1670. of EntriesRequested.
  1671. Return Value:
  1672. NO_ERROR - At least one entry was written to output buffer,
  1673. irregardless of the number requested.
  1674. WN_NO_MORE_ENTRIES - No entries left to return.
  1675. WN_MORE_DATA - The buffer was too small to fit a single entry.
  1676. --*/ // NwEnumContextInfo
  1677. {
  1678. DWORD status = NO_ERROR;
  1679. DWORD_PTR tempResumeId = 0;
  1680. LPBYTE FixedPortion = Buffer;
  1681. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  1682. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  1683. BOOL FitInBuffer = TRUE;
  1684. DWORD EntrySize;
  1685. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  1686. while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
  1687. FitInBuffer &&
  1688. EntriesRequested > *EntriesRead &&
  1689. status == NO_ERROR )
  1690. {
  1691. tempResumeId = ContextHandle->ResumeId;
  1692. status = NwGetNextServerConnection( ContextHandle );
  1693. if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
  1694. {
  1695. //
  1696. // Pack bindery server name into output buffer.
  1697. //
  1698. status = NwWriteNetResourceEntry(
  1699. &FixedPortion,
  1700. &EndOfVariableData,
  1701. L"\\\\",
  1702. NULL,
  1703. (LPWSTR) ContextHandle->ResumeId, // A server name
  1704. RESOURCE_CONTEXT,
  1705. RESOURCEDISPLAYTYPE_SERVER,
  1706. RESOURCEUSAGE_CONTAINER,
  1707. RESOURCETYPE_ANY,
  1708. NULL,
  1709. NULL,
  1710. &EntrySize
  1711. );
  1712. if (status == WN_MORE_DATA)
  1713. {
  1714. //
  1715. // Could not write current entry into output buffer,
  1716. // backup ResumeId to previous entry.
  1717. //
  1718. ContextHandle->ResumeId = tempResumeId;
  1719. ContextHandle->NdsRawDataCount += 1;
  1720. if (*EntriesRead)
  1721. {
  1722. //
  1723. // Still return success because we got at least one.
  1724. //
  1725. status = NO_ERROR;
  1726. }
  1727. else
  1728. {
  1729. *BytesNeeded = EntrySize;
  1730. }
  1731. FitInBuffer = FALSE;
  1732. }
  1733. else if (status == NO_ERROR)
  1734. {
  1735. //
  1736. // Note that we've returned the current entry.
  1737. //
  1738. (*EntriesRead)++;
  1739. }
  1740. }
  1741. else if ( status == WN_NO_MORE_ENTRIES )
  1742. {
  1743. //
  1744. // We processed the last item in list, so
  1745. // start enumerating servers.
  1746. //
  1747. ContextHandle->ResumeId = 0;
  1748. LastObjectId = 0;
  1749. if ( ContextHandle->HandleType == NwsHandleListContextInfo_Tree )
  1750. {
  1751. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NDS;
  1752. }
  1753. }
  1754. }
  1755. if ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS )
  1756. {
  1757. ContextHandle->HandleType = NwsHandleListNdsSubTrees_Any;
  1758. status = NO_ERROR;
  1759. }
  1760. //
  1761. // User asked for more than there are entries. We just say that
  1762. // all is well.
  1763. //
  1764. // This is incompliance with the wierd provider API definition where
  1765. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  1766. // at least one entry fit into output buffer, there's no telling if
  1767. // the buffer was too small for more entries or there are no more
  1768. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  1769. // before knowing that the last call had actually reached the end of list.
  1770. //
  1771. if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  1772. {
  1773. status = NO_ERROR;
  1774. }
  1775. return status;
  1776. }
  1777. DWORD
  1778. NwEnumServersAndNdsTrees(
  1779. IN LPNW_ENUM_CONTEXT ContextHandle,
  1780. IN DWORD_PTR EntriesRequested,
  1781. OUT LPBYTE Buffer,
  1782. IN DWORD BufferSize,
  1783. OUT LPDWORD BytesNeeded,
  1784. OUT LPDWORD EntriesRead
  1785. )
  1786. /*++
  1787. Routine Description:
  1788. This function enumerates all the servers and NDS trees on the local
  1789. network by: 1) scanning the bindery for file server objects on the
  1790. preferred server and 2) scanning the bindery for directory servers
  1791. (NDS trees) on the preferred server. The server and tree entries are
  1792. returned in an array of NETRESOURCE entries; each servername is
  1793. prefixed by \\.
  1794. The ContextHandle->ResumeId field is initially -1 before
  1795. enumeration begins and contains the object ID of the last server
  1796. or NDS tree object returned, depending on the value of
  1797. ContextHandle->dwUsingNds.
  1798. Arguments:
  1799. ContextHandle - Supplies the enum context handle.
  1800. EntriesRequested - Supplies the number of entries to return. If
  1801. this value is -1, return all available entries.
  1802. Buffer - Receives the entries we are listing.
  1803. BufferSize - Supplies the size of the output buffer.
  1804. BytesNeeded - Receives the number of bytes required to get the
  1805. first entry. This value is returned iff WN_MORE_DATA is
  1806. the return code, and Buffer is too small to even fit one
  1807. entry.
  1808. This value is only returned iff NO_ERROR is the return code.
  1809. NO_ERROR is returned as long as at least one entry was written
  1810. into Buffer but does not necessarily mean that it's the number
  1811. of EntriesRequested.
  1812. Return Value:
  1813. NO_ERROR - At least one entry was written to output buffer,
  1814. irregardless of the number requested.
  1815. WN_NO_MORE_ENTRIES - No entries left to return.
  1816. WN_MORE_DATA - The buffer was too small to fit a single entry.
  1817. --*/ // NwEnumServersAndNdsTrees
  1818. {
  1819. DWORD status = NO_ERROR;
  1820. DWORD_PTR tempResumeId = 0;
  1821. LPBYTE FixedPortion = Buffer;
  1822. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  1823. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  1824. BOOL FitInBuffer = TRUE;
  1825. DWORD EntrySize;
  1826. SERVERNAME ServerName; // OEM server name
  1827. LPWSTR UServerName = NULL; // Unicode server name
  1828. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  1829. while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS &&
  1830. FitInBuffer &&
  1831. EntriesRequested > *EntriesRead &&
  1832. status == NO_ERROR )
  1833. {
  1834. tempResumeId = ContextHandle->ResumeId;
  1835. //
  1836. // Call the scan bindery object NCP to scan for all NDS
  1837. // tree objects.
  1838. //
  1839. status = NwGetNextNdsTreeEntry( ContextHandle );
  1840. if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
  1841. {
  1842. //
  1843. // Pack tree name into output buffer.
  1844. //
  1845. status = NwWriteNetResourceEntry(
  1846. &FixedPortion,
  1847. &EndOfVariableData,
  1848. L"\\\\",
  1849. NULL,
  1850. (LPWSTR) ContextHandle->ResumeId, // This is a NDS tree name
  1851. RESOURCE_GLOBALNET,
  1852. RESOURCEDISPLAYTYPE_TREE,
  1853. RESOURCEUSAGE_CONTAINER,
  1854. RESOURCETYPE_ANY,
  1855. NULL,
  1856. NULL,
  1857. &EntrySize
  1858. );
  1859. if (status == WN_MORE_DATA)
  1860. {
  1861. //
  1862. // Could not write current entry into output buffer, backup ResumeId to
  1863. // previous entry.
  1864. //
  1865. ContextHandle->ResumeId = tempResumeId;
  1866. ContextHandle->NdsRawDataCount += 1;
  1867. if (*EntriesRead)
  1868. {
  1869. //
  1870. // Still return success because we got at least one.
  1871. //
  1872. status = NO_ERROR;
  1873. }
  1874. else
  1875. {
  1876. *BytesNeeded = EntrySize;
  1877. }
  1878. FitInBuffer = FALSE;
  1879. }
  1880. else if (status == NO_ERROR)
  1881. {
  1882. //
  1883. // Note that we've returned the current entry.
  1884. //
  1885. (*EntriesRead)++;
  1886. }
  1887. }
  1888. else if ( status == WN_NO_MORE_ENTRIES )
  1889. {
  1890. //
  1891. // We processed the last item in list, so
  1892. // start enumerating servers.
  1893. //
  1894. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  1895. ContextHandle->ResumeId = (DWORD_PTR) -1;
  1896. LastObjectId = (DWORD) -1;
  1897. }
  1898. }
  1899. if ( status == WN_NO_MORE_ENTRIES)
  1900. {
  1901. status = NO_ERROR;
  1902. }
  1903. while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
  1904. FitInBuffer &&
  1905. EntriesRequested > *EntriesRead &&
  1906. status == NO_ERROR )
  1907. {
  1908. RtlZeroMemory(ServerName, sizeof(ServerName));
  1909. //
  1910. // Call the scan bindery object NCP to scan for all file
  1911. // server objects.
  1912. //
  1913. status = NwGetNextServerEntry(
  1914. ContextHandle->TreeConnectionHandle,
  1915. &LastObjectId,
  1916. ServerName
  1917. );
  1918. if (status == NO_ERROR && NwConvertToUnicode(&UServerName, ServerName))
  1919. {
  1920. //
  1921. // Pack server name into output buffer.
  1922. //
  1923. status = NwWriteNetResourceEntry(
  1924. &FixedPortion,
  1925. &EndOfVariableData,
  1926. L"\\\\",
  1927. NULL,
  1928. UServerName,
  1929. RESOURCE_GLOBALNET,
  1930. RESOURCEDISPLAYTYPE_SERVER,
  1931. RESOURCEUSAGE_CONTAINER,
  1932. RESOURCETYPE_ANY,
  1933. NULL,
  1934. NULL,
  1935. &EntrySize
  1936. );
  1937. if (status == WN_MORE_DATA)
  1938. {
  1939. //
  1940. // Could not write current entry into output buffer.
  1941. //
  1942. if (*EntriesRead)
  1943. {
  1944. //
  1945. // Still return success because we got at least one.
  1946. //
  1947. status = NO_ERROR;
  1948. }
  1949. else
  1950. {
  1951. *BytesNeeded = EntrySize;
  1952. }
  1953. FitInBuffer = FALSE;
  1954. }
  1955. else if (status == NO_ERROR)
  1956. {
  1957. //
  1958. // Note that we've returned the current entry.
  1959. //
  1960. (*EntriesRead)++;
  1961. ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
  1962. }
  1963. (void) LocalFree((HLOCAL) UServerName);
  1964. }
  1965. }
  1966. //
  1967. // User asked for more than there are entries. We just say that
  1968. // all is well.
  1969. //
  1970. // This is incompliance with the wierd provider API definition where
  1971. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  1972. // at least one entry fit into output buffer, there's no telling if
  1973. // the buffer was too small for more entries or there are no more
  1974. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  1975. // before knowing that the last call had actually reached the end of list.
  1976. //
  1977. if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  1978. {
  1979. status = NO_ERROR;
  1980. }
  1981. return status;
  1982. }
  1983. DWORD
  1984. NwEnumVolumes(
  1985. IN LPNW_ENUM_CONTEXT ContextHandle,
  1986. IN DWORD_PTR EntriesRequested,
  1987. OUT LPBYTE Buffer,
  1988. IN DWORD BufferSize,
  1989. OUT LPDWORD BytesNeeded,
  1990. OUT LPDWORD EntriesRead
  1991. )
  1992. /*++
  1993. Routine Description:
  1994. This function enumerates all the volumes on a server by
  1995. iteratively getting the volume name for each volume number from
  1996. 0 - 31 until we run into the first volume number that does not
  1997. map to a volume name (this method assumes that volume numbers
  1998. are used contiguously in ascending order). The volume entries
  1999. are returned in an array of NETRESOURCE entries; each volume
  2000. name if prefixed by \\Server\.
  2001. The ContextHandle->ResumeId field always indicates the next
  2002. volume entry to return. It is initially set to 0, which indicates
  2003. the first volume number to get.
  2004. Arguments:
  2005. ContextHandle - Supplies the enum context handle.
  2006. EntriesRequested - Supplies the number of entries to return. If
  2007. this value is -1, return all available entries.
  2008. Buffer - Receives the entries we are listing.
  2009. BufferSize - Supplies the size of the output buffer.
  2010. BytesNeeded - Receives the number of bytes required to get the
  2011. first entry. This value is returned iff WN_MORE_DATA is
  2012. the return code, and Buffer is too small to even fit one
  2013. entry.
  2014. EntriesRead - Receives the number of entries returned in Buffer.
  2015. This value is only returned iff NO_ERROR is the return code.
  2016. NO_ERROR is returned as long as at least one entry was written
  2017. into Buffer but does not necessarily mean that it's the number
  2018. of EntriesRequested.
  2019. Return Value:
  2020. NO_ERROR - At least one entry was written to output buffer,
  2021. irregardless of the number requested.
  2022. WN_NO_MORE_ENTRIES - No entries left to return.
  2023. WN_MORE_DATA - The buffer was too small to fit a single entry.
  2024. --*/ // NwEnumVolumes
  2025. {
  2026. DWORD status = NO_ERROR;
  2027. LPBYTE FixedPortion = Buffer;
  2028. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2029. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2030. BOOL FitInBuffer = TRUE;
  2031. DWORD EntrySize;
  2032. CHAR VolumeName[NW_VOLUME_NAME_LEN]; // OEM volume name
  2033. LPWSTR UVolumeName = NULL; // Unicode volume name
  2034. DWORD NextVolumeNumber = (DWORD) ContextHandle->ResumeId;
  2035. DWORD MaxVolumeNumber = ContextHandle->dwMaxVolumes;
  2036. ULONG Failures = 0;
  2037. if (NextVolumeNumber == MaxVolumeNumber) {
  2038. //
  2039. // Reached the end of enumeration
  2040. //
  2041. return WN_NO_MORE_ENTRIES;
  2042. }
  2043. while (FitInBuffer &&
  2044. EntriesRequested > *EntriesRead &&
  2045. NextVolumeNumber < MaxVolumeNumber &&
  2046. status == NO_ERROR) {
  2047. RtlZeroMemory(VolumeName, sizeof(VolumeName));
  2048. //
  2049. // Call the scan bindery object NCP to scan for all file
  2050. // volume objects.
  2051. //
  2052. status = NwGetNextVolumeEntry(
  2053. ContextHandle->TreeConnectionHandle,
  2054. NextVolumeNumber++,
  2055. VolumeName
  2056. );
  2057. if (status == NO_ERROR) {
  2058. if (VolumeName[0] == 0) {
  2059. //
  2060. // Got an empty volume name back for the next volume number
  2061. // which indicates there is no volume associated with the
  2062. // volume number but still got error success.
  2063. //
  2064. // Treat this as having reached the end of the enumeration
  2065. // only if we've gotten two three empty volumes in a row
  2066. // or reached the max number of volumes because there are
  2067. // some cases where there are holes in the way that volumes
  2068. // are allocated.
  2069. //
  2070. Failures++;
  2071. if ( Failures <= 3 ) {
  2072. continue;
  2073. } else {
  2074. NextVolumeNumber = MaxVolumeNumber;
  2075. ContextHandle->ResumeId = MaxVolumeNumber;
  2076. if (*EntriesRead == 0) {
  2077. status = WN_NO_MORE_ENTRIES;
  2078. }
  2079. }
  2080. } else if (NwConvertToUnicode(&UVolumeName, VolumeName)) {
  2081. //
  2082. // Pack volume name into output buffer.
  2083. //
  2084. status = NwWriteNetResourceEntry(
  2085. &FixedPortion,
  2086. &EndOfVariableData,
  2087. ContextHandle->ContainerName,
  2088. NULL,
  2089. UVolumeName,
  2090. RESOURCE_GLOBALNET,
  2091. RESOURCEDISPLAYTYPE_SHARE,
  2092. #ifdef NT1057
  2093. RESOURCEUSAGE_CONNECTABLE |
  2094. RESOURCEUSAGE_CONTAINER,
  2095. #else
  2096. RESOURCEUSAGE_CONNECTABLE |
  2097. RESOURCEUSAGE_NOLOCALDEVICE,
  2098. #endif
  2099. RESOURCETYPE_DISK,
  2100. NULL,
  2101. NULL,
  2102. &EntrySize
  2103. );
  2104. if (status == WN_MORE_DATA) {
  2105. //
  2106. // Could not write current entry into output buffer.
  2107. //
  2108. if (*EntriesRead) {
  2109. //
  2110. // Still return success because we got at least one.
  2111. //
  2112. status = NO_ERROR;
  2113. }
  2114. else {
  2115. *BytesNeeded = EntrySize;
  2116. }
  2117. FitInBuffer = FALSE;
  2118. }
  2119. else if (status == NO_ERROR) {
  2120. //
  2121. // Note that we've returned the current entry.
  2122. //
  2123. (*EntriesRead)++;
  2124. ContextHandle->ResumeId = NextVolumeNumber;
  2125. }
  2126. (void) LocalFree((HLOCAL) UVolumeName);
  2127. }
  2128. //
  2129. // We got an entry, so reset the failure counter.
  2130. //
  2131. Failures = 0;
  2132. }
  2133. }
  2134. //
  2135. // User asked for more than there are entries. We just say that
  2136. // all is well.
  2137. //
  2138. // This is incompliance with the wierd provider API definition where
  2139. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2140. // at least one entry fit into output buffer, there's no telling if
  2141. // the buffer was too small for more entries or there are no more
  2142. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2143. // before knowing that the last call had actually reached the end of list.
  2144. //
  2145. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  2146. status = NO_ERROR;
  2147. }
  2148. return status;
  2149. }
  2150. DWORD
  2151. NwEnumNdsSubTrees_Disk(
  2152. IN LPNW_ENUM_CONTEXT ContextHandle,
  2153. IN DWORD_PTR EntriesRequested,
  2154. OUT LPBYTE Buffer,
  2155. IN DWORD BufferSize,
  2156. OUT LPDWORD BytesNeeded,
  2157. OUT LPDWORD EntriesRead
  2158. )
  2159. /*++
  2160. Routine Description:
  2161. This function enumerates the sub-trees of a given NDS tree
  2162. handle. It returns the fully-qualified UNC path of the sub-tree
  2163. entries in an array of NETRESOURCE entries.
  2164. The ContextHandle->ResumeId field is 0 initially, and contains
  2165. a pointer to the subtree name string of the last sub-tree
  2166. returned. If there are no more sub-trees to return, this
  2167. field is set to -1.
  2168. Arguments:
  2169. ContextHandle - Supplies the enum context handle. It contains
  2170. an opened NDS tree handle.
  2171. EntriesRequested - Supplies the number of entries to return. If
  2172. this value is -1, return all available entries.
  2173. Buffer - Receives the entries we are listing.
  2174. BufferSize - Supplies the size of the output buffer.
  2175. BytesNeeded - Receives the number of bytes required to get the
  2176. first entry. This value is returned iff WN_MORE_DATA is
  2177. the return code, and Buffer is too small to even fit one
  2178. entry.
  2179. EntriesRead - Receives the number of entries returned in Buffer.
  2180. This value is only returned iff NO_ERROR is the return code.
  2181. NO_ERROR is returned as long as at least one entry was written
  2182. into Buffer but does not necessarily mean that it's the number
  2183. of EntriesRequested.
  2184. Return Value:
  2185. NO_ERROR - At least one entry was written to output buffer,
  2186. irregardless of the number requested.
  2187. WN_NO_MORE_ENTRIES - No entries left to return.
  2188. WN_MORE_DATA - The buffer was too small to fit a single entry.
  2189. --*/ // NwEnumNdsSubTrees_Disk
  2190. {
  2191. DWORD status = NO_ERROR;
  2192. LPBYTE FixedPortion = Buffer;
  2193. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2194. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2195. BOOL FitInBuffer = TRUE;
  2196. DWORD EntrySize = 0;
  2197. LPWSTR SubTreeName = NULL;
  2198. DWORD ResourceScope = 0;
  2199. DWORD ResourceType = 0;
  2200. DWORD ResourceDisplayType = 0;
  2201. DWORD ResourceUsage = 0;
  2202. LPWSTR StrippedObjectName = NULL;
  2203. if (ContextHandle->ResumeId == (DWORD_PTR) -1)
  2204. {
  2205. //
  2206. // Reached the end of enumeration.
  2207. //
  2208. return WN_NO_MORE_ENTRIES;
  2209. }
  2210. while (FitInBuffer &&
  2211. EntriesRequested > *EntriesRead &&
  2212. status == NO_ERROR)
  2213. {
  2214. if ( ContextHandle->ResumeId == 0 )
  2215. {
  2216. //
  2217. // Get the first subtree entry.
  2218. //
  2219. status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
  2220. }
  2221. //
  2222. // Either ResumeId contains the first entry we just got from
  2223. // NwGetFirstDirectoryEntry or it contains the next directory
  2224. // entry to return.
  2225. //
  2226. if (status == NO_ERROR && ContextHandle->ResumeId != 0)
  2227. {
  2228. BYTE ClassType;
  2229. LPWSTR newPathStr = NULL;
  2230. LPWSTR tempStr = NULL;
  2231. WORD tempStrLen;
  2232. //
  2233. // Get current subtree data from ContextHandle
  2234. //
  2235. ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
  2236. &SubTreeName,
  2237. &ResourceScope,
  2238. &ResourceType,
  2239. &ResourceDisplayType,
  2240. &ResourceUsage,
  2241. &StrippedObjectName );
  2242. if ( StrippedObjectName == NULL )
  2243. {
  2244. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk LocalAlloc Failed %lu\n",
  2245. GetLastError()));
  2246. return ERROR_NOT_ENOUGH_MEMORY;
  2247. }
  2248. switch( ClassType )
  2249. {
  2250. case CLASS_TYPE_COUNTRY:
  2251. case CLASS_TYPE_DIRECTORY_MAP:
  2252. case CLASS_TYPE_NCP_SERVER:
  2253. case CLASS_TYPE_ORGANIZATION:
  2254. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2255. case CLASS_TYPE_VOLUME:
  2256. //
  2257. // Need to build a string with the new NDS UNC path for subtree object
  2258. //
  2259. newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  2260. ( wcslen( StrippedObjectName ) +
  2261. wcslen( ContextHandle->ContainerName ) +
  2262. 3 ) * sizeof(WCHAR) );
  2263. if ( newPathStr == NULL )
  2264. {
  2265. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk LocalAlloc Failed %lu\n",
  2266. GetLastError()));
  2267. return ERROR_NOT_ENOUGH_MEMORY;
  2268. }
  2269. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2270. ContextHandle->ContainerName,
  2271. PARSE_NDS_GET_TREE_NAME );
  2272. tempStrLen /= sizeof( WCHAR );
  2273. if ( tempStrLen > 0 )
  2274. {
  2275. wcscpy( newPathStr, L"\\\\" );
  2276. wcsncat( newPathStr, tempStr, tempStrLen );
  2277. wcscat( newPathStr, L"\\" );
  2278. wcscat( newPathStr, StrippedObjectName );
  2279. }
  2280. (void) LocalFree((HLOCAL) StrippedObjectName );
  2281. StrippedObjectName = NULL;
  2282. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2283. ContextHandle->ContainerName,
  2284. PARSE_NDS_GET_PATH_NAME );
  2285. tempStrLen /= sizeof( WCHAR );
  2286. if ( tempStrLen > 0 )
  2287. {
  2288. wcscat( newPathStr, L"." );
  2289. wcsncat( newPathStr, tempStr, tempStrLen );
  2290. }
  2291. //
  2292. // Pack subtree name into output buffer.
  2293. //
  2294. status = NwWriteNetResourceEntry(
  2295. &FixedPortion,
  2296. &EndOfVariableData,
  2297. NULL,
  2298. NULL,
  2299. newPathStr,
  2300. ResourceScope,
  2301. ResourceDisplayType,
  2302. ResourceUsage,
  2303. ResourceType,
  2304. NULL,
  2305. NULL,
  2306. &EntrySize );
  2307. if ( status == NO_ERROR )
  2308. {
  2309. //
  2310. // Note that we've returned the current entry.
  2311. //
  2312. (*EntriesRead)++;
  2313. }
  2314. if ( newPathStr )
  2315. (void) LocalFree( (HLOCAL) newPathStr );
  2316. break;
  2317. case CLASS_TYPE_ALIAS:
  2318. case CLASS_TYPE_AFP_SERVER:
  2319. case CLASS_TYPE_BINDERY_OBJECT:
  2320. case CLASS_TYPE_BINDERY_QUEUE:
  2321. case CLASS_TYPE_COMPUTER:
  2322. case CLASS_TYPE_GROUP:
  2323. case CLASS_TYPE_LOCALITY:
  2324. case CLASS_TYPE_ORGANIZATIONAL_ROLE:
  2325. case CLASS_TYPE_PRINTER:
  2326. case CLASS_TYPE_PRINT_SERVER:
  2327. case CLASS_TYPE_PROFILE:
  2328. case CLASS_TYPE_QUEUE:
  2329. case CLASS_TYPE_TOP:
  2330. case CLASS_TYPE_UNKNOWN:
  2331. case CLASS_TYPE_USER:
  2332. break;
  2333. default:
  2334. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk - Unhandled switch statement case %lu\n", ClassType ));
  2335. ASSERT( FALSE );
  2336. break;
  2337. }
  2338. if (status == WN_MORE_DATA)
  2339. {
  2340. //
  2341. // Could not write current entry into output buffer.
  2342. //
  2343. if (*EntriesRead)
  2344. {
  2345. //
  2346. // Still return success because we got at least one.
  2347. //
  2348. status = NO_ERROR;
  2349. }
  2350. else
  2351. {
  2352. *BytesNeeded = EntrySize;
  2353. }
  2354. FitInBuffer = FALSE;
  2355. }
  2356. else if (status == NO_ERROR)
  2357. {
  2358. //
  2359. // Get next directory entry.
  2360. //
  2361. status = NwGetNextNdsSubTreeEntry( ContextHandle );
  2362. }
  2363. }
  2364. if (status == WN_NO_MORE_ENTRIES)
  2365. {
  2366. ContextHandle->ResumeId = (DWORD_PTR) -1;
  2367. }
  2368. }
  2369. //
  2370. // User asked for more than there are entries. We just say that
  2371. // all is well.
  2372. //
  2373. // This is incompliance with the wierd provider API definition where
  2374. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2375. // at least one entry fit into output buffer, there's no telling if
  2376. // the buffer was too small for more entries or there are no more
  2377. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2378. // before knowing that the last call had actually reached the end of list.
  2379. //
  2380. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  2381. status = NO_ERROR;
  2382. }
  2383. #if DBG
  2384. IF_DEBUG(ENUM)
  2385. {
  2386. KdPrint(("NwEnumNdsSubTrees_Disk returns %lu\n", status));
  2387. }
  2388. #endif
  2389. return status;
  2390. }
  2391. DWORD
  2392. NwEnumNdsSubTrees_Print(
  2393. IN LPNW_ENUM_CONTEXT ContextHandle,
  2394. IN DWORD_PTR EntriesRequested,
  2395. OUT LPBYTE Buffer,
  2396. IN DWORD BufferSize,
  2397. OUT LPDWORD BytesNeeded,
  2398. OUT LPDWORD EntriesRead
  2399. )
  2400. /*++
  2401. Routine Description:
  2402. This function enumerates all the NDS subtree objects that are either containers,
  2403. queues, printers, or servers from a given NDS tree or subtree. The entries are
  2404. returned in an array of PRINTER_INFO_1 entries and each name is prefixed
  2405. by the parent path in NDS UNC style (ex. \\tree\CN=foo.OU=bar.O=blah).
  2406. The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
  2407. enumeration begins and contains the object ID of the last NDS object returned.
  2408. Arguments:
  2409. ContextHandle - Supplies the enum context handle.
  2410. EntriesRequested - Supplies the number of entries to return. If
  2411. this value is (DWORD_PTR) -1, return all available entries.
  2412. Buffer - Receives the entries we are listing.
  2413. BufferSize - Supplies the size of the output buffer.
  2414. BytesNeeded - Receives the number of bytes copied or required to get all
  2415. the requested entries.
  2416. EntriesRead - Receives the number of entries returned in Buffer.
  2417. This value is only returned iff NO_ERROR is the return code.
  2418. Return Value:
  2419. NO_ERROR - Buffer contains all the entries requested.
  2420. WN_NO_MORE_ENTRIES - No entries left to return.
  2421. WN_MORE_DATA - The buffer was too small to fit the requested entries.
  2422. --*/ // NwEnumNdsSubTrees_Print
  2423. {
  2424. DWORD status = NO_ERROR;
  2425. LPBYTE FixedPortion = Buffer;
  2426. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2427. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2428. DWORD EntrySize;
  2429. BOOL FitInBuffer = TRUE;
  2430. LPWSTR SubTreeName = NULL;
  2431. DWORD ResourceScope = 0;
  2432. DWORD ResourceType = 0;
  2433. DWORD ResourceDisplayType = 0;
  2434. DWORD ResourceUsage = 0;
  2435. LPWSTR StrippedObjectName = NULL;
  2436. BYTE ClassType = 0;
  2437. LPWSTR newPathStr = NULL;
  2438. LPWSTR tempStr = NULL;
  2439. WORD tempStrLen = 0;
  2440. while ( EntriesRequested > *EntriesRead &&
  2441. ( (status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER)))
  2442. {
  2443. if (ContextHandle->ResumeId == 0)
  2444. {
  2445. //
  2446. // Get the first subtree entry.
  2447. //
  2448. status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
  2449. }
  2450. //
  2451. // Either ResumeId contains the first entry we just got from
  2452. // NwGetFirstDirectoryEntry or it contains the next directory
  2453. // entry to return.
  2454. //
  2455. if (status == NO_ERROR && ContextHandle->ResumeId != 0)
  2456. {
  2457. //
  2458. // Get current subtree data from ContextHandle
  2459. //
  2460. ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
  2461. &SubTreeName,
  2462. &ResourceScope,
  2463. &ResourceType,
  2464. &ResourceDisplayType,
  2465. &ResourceUsage,
  2466. &StrippedObjectName );
  2467. if ( StrippedObjectName == NULL )
  2468. {
  2469. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print LocalAlloc Failed %lu\n",
  2470. GetLastError()));
  2471. return ERROR_NOT_ENOUGH_MEMORY;
  2472. }
  2473. switch( ClassType )
  2474. {
  2475. case CLASS_TYPE_COUNTRY:
  2476. case CLASS_TYPE_ORGANIZATION:
  2477. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2478. case CLASS_TYPE_NCP_SERVER:
  2479. case CLASS_TYPE_QUEUE:
  2480. //
  2481. // Need to build a string with the new NDS UNC path for subtree object
  2482. //
  2483. newPathStr = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  2484. ( wcslen( StrippedObjectName ) +
  2485. wcslen( ContextHandle->ContainerName ) +
  2486. 2 ) * sizeof(WCHAR) );
  2487. if ( newPathStr == NULL )
  2488. {
  2489. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print LocalAlloc Failed %lu\n",
  2490. GetLastError()));
  2491. return ERROR_NOT_ENOUGH_MEMORY;
  2492. }
  2493. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2494. ContextHandle->ContainerName,
  2495. PARSE_NDS_GET_TREE_NAME );
  2496. tempStrLen /= sizeof( WCHAR );
  2497. if ( tempStrLen > 0 )
  2498. {
  2499. wcsncpy( newPathStr, tempStr, tempStrLen );
  2500. wcscat( newPathStr, L"\\" );
  2501. wcscat( newPathStr, StrippedObjectName );
  2502. }
  2503. (void) LocalFree((HLOCAL) StrippedObjectName );
  2504. StrippedObjectName = NULL;
  2505. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2506. ContextHandle->ContainerName,
  2507. PARSE_NDS_GET_PATH_NAME );
  2508. tempStrLen /= sizeof( WCHAR );
  2509. if ( tempStrLen > 0 )
  2510. {
  2511. wcscat( newPathStr, L"." );
  2512. wcsncat( newPathStr, tempStr, tempStrLen );
  2513. }
  2514. switch( ClassType )
  2515. {
  2516. case CLASS_TYPE_COUNTRY:
  2517. case CLASS_TYPE_ORGANIZATION:
  2518. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2519. //
  2520. // Pack sub-tree container name into output buffer.
  2521. //
  2522. status = NwWritePrinterInfoEntry(
  2523. &FixedPortion,
  2524. &EndOfVariableData,
  2525. NULL,
  2526. newPathStr,
  2527. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1,
  2528. &EntrySize );
  2529. break;
  2530. case CLASS_TYPE_NCP_SERVER:
  2531. //
  2532. // Pack server name into output buffer.
  2533. //
  2534. status = NwWritePrinterInfoEntry(
  2535. &FixedPortion,
  2536. &EndOfVariableData,
  2537. NULL,
  2538. newPathStr,
  2539. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON3,
  2540. &EntrySize );
  2541. break;
  2542. case CLASS_TYPE_QUEUE:
  2543. //
  2544. // Pack print server queue name into output buffer.
  2545. //
  2546. status = NwWritePrinterInfoEntry(
  2547. &FixedPortion,
  2548. &EndOfVariableData,
  2549. L"\\\\",
  2550. newPathStr,
  2551. PRINTER_ENUM_ICON8,
  2552. &EntrySize );
  2553. break;
  2554. default:
  2555. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print - Unhandled switch statement case %lu\n", ClassType ));
  2556. ASSERT(FALSE);
  2557. break;
  2558. }
  2559. switch ( status )
  2560. {
  2561. case ERROR_INSUFFICIENT_BUFFER:
  2562. FitInBuffer = FALSE;
  2563. // Falls through
  2564. case NO_ERROR:
  2565. *BytesNeeded += EntrySize;
  2566. (*EntriesRead)++;
  2567. break;
  2568. default:
  2569. break;
  2570. }
  2571. if ( newPathStr )
  2572. (void) LocalFree( (HLOCAL) newPathStr );
  2573. break;
  2574. case CLASS_TYPE_ALIAS:
  2575. case CLASS_TYPE_AFP_SERVER:
  2576. case CLASS_TYPE_BINDERY_OBJECT:
  2577. case CLASS_TYPE_BINDERY_QUEUE:
  2578. case CLASS_TYPE_COMPUTER:
  2579. case CLASS_TYPE_DIRECTORY_MAP:
  2580. case CLASS_TYPE_GROUP:
  2581. case CLASS_TYPE_LOCALITY:
  2582. case CLASS_TYPE_ORGANIZATIONAL_ROLE:
  2583. case CLASS_TYPE_PRINTER:
  2584. case CLASS_TYPE_PRINT_SERVER:
  2585. case CLASS_TYPE_PROFILE:
  2586. case CLASS_TYPE_TOP:
  2587. case CLASS_TYPE_UNKNOWN:
  2588. case CLASS_TYPE_USER:
  2589. case CLASS_TYPE_VOLUME:
  2590. break;
  2591. default:
  2592. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print - Unhandled switch statement case %lu\n", ClassType ));
  2593. ASSERT( FALSE );
  2594. break;
  2595. }
  2596. if ( status == NO_ERROR || status == ERROR_INSUFFICIENT_BUFFER )
  2597. {
  2598. //
  2599. // Get next directory entry.
  2600. //
  2601. status = NwGetNextNdsSubTreeEntry( ContextHandle );
  2602. }
  2603. }
  2604. }
  2605. //
  2606. // This is incompliance with the wierd provider API definition where
  2607. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2608. // at least one entry fit into output buffer, there's no telling if
  2609. // the buffer was too small for more entries or there are no more
  2610. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2611. // before knowing that the last call had actually reached the end of list.
  2612. //
  2613. if ( !FitInBuffer )
  2614. {
  2615. *EntriesRead = 0;
  2616. status = ERROR_INSUFFICIENT_BUFFER;
  2617. }
  2618. else if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  2619. {
  2620. status = NO_ERROR;
  2621. }
  2622. return status;
  2623. }
  2624. DWORD
  2625. NwEnumNdsSubTrees_Any(
  2626. IN LPNW_ENUM_CONTEXT ContextHandle,
  2627. IN DWORD_PTR EntriesRequested,
  2628. OUT LPBYTE Buffer,
  2629. IN DWORD BufferSize,
  2630. OUT LPDWORD BytesNeeded,
  2631. OUT LPDWORD EntriesRead
  2632. )
  2633. /*++
  2634. Routine Description:
  2635. This function enumerates the sub-trees of a given NDS tree
  2636. handle. It returns the fully-qualified UNC path of ANY sub-tree
  2637. entries in an array of NETRESOURCE entries.
  2638. The ContextHandle->ResumeId field is 0 initially, and contains
  2639. a pointer to the subtree name string of the last sub-tree
  2640. returned. If there are no more sub-trees to return, this
  2641. field is set to (DWORD_PTR) -1.
  2642. Arguments:
  2643. ContextHandle - Supplies the enum context handle. It contains
  2644. an opened NDS tree handle.
  2645. EntriesRequested - Supplies the number of entries to return. If
  2646. this value is (DWORD_PTR) -1, return all available entries.
  2647. Buffer - Receives the entries we are listing.
  2648. BufferSize - Supplies the size of the output buffer.
  2649. BytesNeeded - Receives the number of bytes required to get the
  2650. first entry. This value is returned iff WN_MORE_DATA is
  2651. the return code, and Buffer is too small to even fit one
  2652. entry.
  2653. EntriesRead - Receives the number of entries returned in Buffer.
  2654. This value is only returned iff NO_ERROR is the return code.
  2655. NO_ERROR is returned as long as at least one entry was written
  2656. into Buffer but does not necessarily mean that it's the number
  2657. of EntriesRequested.
  2658. Return Value:
  2659. NO_ERROR - At least one entry was written to output buffer,
  2660. irregardless of the number requested.
  2661. WN_NO_MORE_ENTRIES - No entries left to return.
  2662. WN_MORE_DATA - The buffer was too small to fit a single entry.
  2663. --*/ // NwEnumNdsSubTrees_Any
  2664. {
  2665. DWORD status = NO_ERROR;
  2666. LPBYTE FixedPortion = Buffer;
  2667. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2668. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2669. BOOL FitInBuffer = TRUE;
  2670. DWORD EntrySize = 0;
  2671. LPWSTR SubTreeName = NULL;
  2672. DWORD ResourceScope = 0;
  2673. DWORD ResourceType = 0;
  2674. DWORD ResourceDisplayType = 0;
  2675. DWORD ResourceUsage = 0;
  2676. LPWSTR StrippedObjectName = NULL;
  2677. if (ContextHandle->ResumeId == (DWORD_PTR) -1)
  2678. {
  2679. //
  2680. // Reached the end of enumeration.
  2681. //
  2682. return WN_NO_MORE_ENTRIES;
  2683. }
  2684. while (FitInBuffer &&
  2685. EntriesRequested > *EntriesRead &&
  2686. status == NO_ERROR)
  2687. {
  2688. if ( ContextHandle->ResumeId == 0 )
  2689. {
  2690. //
  2691. // Get the first subtree entry.
  2692. //
  2693. status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
  2694. }
  2695. //
  2696. // Either ResumeId contains the first entry we just got from
  2697. // NwGetFirstDirectoryEntry or it contains the next directory
  2698. // entry to return.
  2699. //
  2700. if (status == NO_ERROR && ContextHandle->ResumeId != 0)
  2701. {
  2702. BYTE ClassType;
  2703. LPWSTR newPathStr = NULL;
  2704. LPWSTR tempStr = NULL;
  2705. WORD tempStrLen;
  2706. //
  2707. // Get current subtree data from ContextHandle
  2708. //
  2709. ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
  2710. &SubTreeName,
  2711. &ResourceScope,
  2712. &ResourceType,
  2713. &ResourceDisplayType,
  2714. &ResourceUsage,
  2715. &StrippedObjectName );
  2716. if ( StrippedObjectName == NULL )
  2717. {
  2718. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any LocalAlloc Failed %lu\n",
  2719. GetLastError()));
  2720. return ERROR_NOT_ENOUGH_MEMORY;
  2721. }
  2722. switch( ClassType )
  2723. {
  2724. case CLASS_TYPE_COUNTRY:
  2725. case CLASS_TYPE_ORGANIZATION:
  2726. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2727. case CLASS_TYPE_VOLUME:
  2728. case CLASS_TYPE_DIRECTORY_MAP:
  2729. case CLASS_TYPE_NCP_SERVER:
  2730. case CLASS_TYPE_QUEUE:
  2731. //
  2732. // Need to build a string with the new NDS UNC path for subtree object
  2733. //
  2734. newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  2735. ( wcslen( StrippedObjectName ) +
  2736. wcslen( ContextHandle->ContainerName ) +
  2737. 3 ) * sizeof(WCHAR) );
  2738. if ( newPathStr == NULL )
  2739. {
  2740. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any LocalAlloc Failed %lu\n",
  2741. GetLastError()));
  2742. return ERROR_NOT_ENOUGH_MEMORY;
  2743. }
  2744. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2745. ContextHandle->ContainerName,
  2746. PARSE_NDS_GET_TREE_NAME );
  2747. tempStrLen /= sizeof( WCHAR );
  2748. if ( tempStrLen > 0 )
  2749. {
  2750. wcscpy( newPathStr, L"\\\\" );
  2751. wcsncat( newPathStr, tempStr, tempStrLen );
  2752. wcscat( newPathStr, L"\\" );
  2753. wcscat( newPathStr, StrippedObjectName );
  2754. }
  2755. (void) LocalFree((HLOCAL) StrippedObjectName );
  2756. StrippedObjectName = NULL;
  2757. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2758. ContextHandle->ContainerName,
  2759. PARSE_NDS_GET_PATH_NAME );
  2760. tempStrLen /= sizeof( WCHAR );
  2761. if ( tempStrLen > 0 )
  2762. {
  2763. wcscat( newPathStr, L"." );
  2764. wcsncat( newPathStr, tempStr, tempStrLen );
  2765. }
  2766. //
  2767. // Pack subtree name into output buffer.
  2768. //
  2769. status = NwWriteNetResourceEntry(
  2770. &FixedPortion,
  2771. &EndOfVariableData,
  2772. NULL,
  2773. NULL,
  2774. newPathStr,
  2775. ResourceScope,
  2776. ResourceDisplayType,
  2777. ResourceUsage,
  2778. ResourceType,
  2779. NULL,
  2780. NULL,
  2781. &EntrySize );
  2782. if ( status == NO_ERROR )
  2783. {
  2784. //
  2785. // Note that we've returned the current entry.
  2786. //
  2787. (*EntriesRead)++;
  2788. }
  2789. if ( newPathStr )
  2790. (void) LocalFree( (HLOCAL) newPathStr );
  2791. break;
  2792. case CLASS_TYPE_ALIAS:
  2793. case CLASS_TYPE_AFP_SERVER:
  2794. case CLASS_TYPE_BINDERY_OBJECT:
  2795. case CLASS_TYPE_BINDERY_QUEUE:
  2796. case CLASS_TYPE_COMPUTER:
  2797. case CLASS_TYPE_GROUP:
  2798. case CLASS_TYPE_LOCALITY:
  2799. case CLASS_TYPE_ORGANIZATIONAL_ROLE:
  2800. case CLASS_TYPE_PRINTER:
  2801. case CLASS_TYPE_PRINT_SERVER:
  2802. case CLASS_TYPE_PROFILE:
  2803. case CLASS_TYPE_TOP:
  2804. case CLASS_TYPE_UNKNOWN:
  2805. case CLASS_TYPE_USER:
  2806. break;
  2807. default:
  2808. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any - Unhandled switch statement case %lu\n", ClassType ));
  2809. ASSERT( FALSE );
  2810. break;
  2811. }
  2812. if (status == WN_MORE_DATA)
  2813. {
  2814. //
  2815. // Could not write current entry into output buffer.
  2816. //
  2817. if (*EntriesRead)
  2818. {
  2819. //
  2820. // Still return success because we got at least one.
  2821. //
  2822. status = NO_ERROR;
  2823. }
  2824. else
  2825. {
  2826. *BytesNeeded = EntrySize;
  2827. }
  2828. FitInBuffer = FALSE;
  2829. }
  2830. else if (status == NO_ERROR)
  2831. {
  2832. //
  2833. // Get next directory entry.
  2834. //
  2835. status = NwGetNextNdsSubTreeEntry( ContextHandle );
  2836. }
  2837. }
  2838. if (status == WN_NO_MORE_ENTRIES)
  2839. {
  2840. ContextHandle->ResumeId = (DWORD_PTR) -1;
  2841. }
  2842. }
  2843. //
  2844. // User asked for more than there are entries. We just say that
  2845. // all is well.
  2846. //
  2847. // This is incompliance with the wierd provider API definition where
  2848. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2849. // at least one entry fit into output buffer, there's no telling if
  2850. // the buffer was too small for more entries or there are no more
  2851. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2852. // before knowing that the last call had actually reached the end of list.
  2853. //
  2854. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  2855. status = NO_ERROR;
  2856. }
  2857. #if DBG
  2858. IF_DEBUG(ENUM)
  2859. {
  2860. KdPrint(("NwEnumNdsSubTrees_Any returns %lu\n", status));
  2861. }
  2862. #endif
  2863. return status;
  2864. }
  2865. DWORD
  2866. NwEnumVolumesQueues(
  2867. IN LPNW_ENUM_CONTEXT ContextHandle,
  2868. IN DWORD_PTR EntriesRequested,
  2869. OUT LPBYTE Buffer,
  2870. IN DWORD BufferSize,
  2871. OUT LPDWORD BytesNeeded,
  2872. OUT LPDWORD EntriesRead
  2873. )
  2874. /*++
  2875. Routine Description:
  2876. This function enumerates all the volumes and queues on a server.
  2877. The queue entries are returned in an array of NETRESOURCE entries;
  2878. each queue name is prefixed by \\Server\.
  2879. Arguments:
  2880. ContextHandle - Supplies the enum context handle.
  2881. EntriesRequested - Supplies the number of entries to return. If
  2882. this value is (DWORD_PTR) -1, return all available entries.
  2883. Buffer - Receives the entries we are listing.
  2884. BufferSize - Supplies the size of the output buffer.
  2885. BytesNeeded - Receives the number of bytes required to get the
  2886. first entry. This value is returned if WN_MORE_DATA is
  2887. the return code, and Buffer is too small to even fit one
  2888. entry.
  2889. EntriesRead - Receives the number of entries returned in Buffer.
  2890. This value is only returned iff NO_ERROR is the return code.
  2891. NO_ERROR is returned as long as at least one entry was written
  2892. into Buffer but does not necessarily mean that it's the number
  2893. of EntriesRequested.
  2894. Return Value:
  2895. NO_ERROR - At least one entry was written to output buffer,
  2896. irregardless of the number requested.
  2897. WN_NO_MORE_ENTRIES - No entries left to return.
  2898. WN_MORE_DATA - The buffer was too small to fit a single entry.
  2899. --*/ // NwEnumVolumesQueues
  2900. {
  2901. DWORD status = NO_ERROR;
  2902. LPBYTE FixedPortion = Buffer;
  2903. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2904. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2905. BOOL FitInBuffer = TRUE;
  2906. DWORD EntrySize;
  2907. CHAR VolumeName[NW_VOLUME_NAME_LEN]; // OEM volume name
  2908. LPWSTR UVolumeName = NULL; // Unicode volume name
  2909. DWORD NextObject = (DWORD) ContextHandle->ResumeId;
  2910. DWORD MaxVolumeNumber = ContextHandle->dwMaxVolumes;
  2911. ULONG Failures = 0;
  2912. //
  2913. // tommye - bug 139466
  2914. //
  2915. // removed if (NextObject >= 0) becaue NextObject is a DWORD
  2916. //
  2917. while (FitInBuffer &&
  2918. EntriesRequested > *EntriesRead &&
  2919. ContextHandle->ConnectionType == CONNTYPE_DISK &&
  2920. (NextObject < MaxVolumeNumber) &&
  2921. status == NO_ERROR) {
  2922. RtlZeroMemory(VolumeName, sizeof(VolumeName));
  2923. //
  2924. // Call the scan bindery object NCP to scan for all file
  2925. // volume objects.
  2926. //
  2927. status = NwGetNextVolumeEntry(
  2928. ContextHandle->TreeConnectionHandle,
  2929. NextObject++,
  2930. VolumeName
  2931. );
  2932. if (status == NO_ERROR) {
  2933. if (VolumeName[0] == 0) {
  2934. //
  2935. // Got an empty volume name back for the next volume number
  2936. // which indicates there is no volume associated with the
  2937. // volume number but still got error success.
  2938. //
  2939. // Treat this as having reached the end of the enumeration
  2940. // if we have had three failures in a row. This will allow
  2941. // us to function when there are small holes in the drive
  2942. // list.
  2943. //
  2944. Failures++;
  2945. if ( Failures <= 3 ) {
  2946. continue;
  2947. } else {
  2948. NextObject = (DWORD) -1;
  2949. ContextHandle->ResumeId = (DWORD_PTR) -1;
  2950. ContextHandle->ConnectionType = CONNTYPE_PRINT;
  2951. }
  2952. } else if (NwConvertToUnicode(&UVolumeName, VolumeName)) {
  2953. //
  2954. // Pack volume name into output buffer.
  2955. //
  2956. status = NwWriteNetResourceEntry(
  2957. &FixedPortion,
  2958. &EndOfVariableData,
  2959. ContextHandle->ContainerName,
  2960. NULL,
  2961. UVolumeName,
  2962. RESOURCE_GLOBALNET,
  2963. RESOURCEDISPLAYTYPE_SHARE,
  2964. #ifdef NT1057
  2965. RESOURCEUSAGE_CONNECTABLE |
  2966. RESOURCEUSAGE_CONTAINER,
  2967. #else
  2968. RESOURCEUSAGE_CONNECTABLE |
  2969. RESOURCEUSAGE_NOLOCALDEVICE,
  2970. #endif
  2971. RESOURCETYPE_DISK,
  2972. NULL,
  2973. NULL,
  2974. &EntrySize
  2975. );
  2976. if (status == WN_MORE_DATA) {
  2977. //
  2978. // Could not write current entry into output buffer.
  2979. //
  2980. if (*EntriesRead) {
  2981. //
  2982. // Still return success because we got at least one.
  2983. //
  2984. status = NO_ERROR;
  2985. }
  2986. else {
  2987. *BytesNeeded = EntrySize;
  2988. }
  2989. FitInBuffer = FALSE;
  2990. }
  2991. else if (status == NO_ERROR) {
  2992. //
  2993. // Note that we've returned the current entry.
  2994. //
  2995. (*EntriesRead)++;
  2996. ContextHandle->ResumeId = NextObject;
  2997. }
  2998. (void) LocalFree((HLOCAL) UVolumeName);
  2999. }
  3000. //
  3001. // Reset the failures counter.
  3002. //
  3003. Failures = 0;
  3004. }
  3005. }
  3006. //
  3007. // User asked for more than there are entries. We just say that
  3008. // all is well.
  3009. //
  3010. if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  3011. {
  3012. status = NO_ERROR;
  3013. }
  3014. if ( *EntriesRead == 0 &&
  3015. status == NO_ERROR &&
  3016. ContextHandle->ConnectionType == CONNTYPE_DISK )
  3017. {
  3018. ContextHandle->ConnectionType = CONNTYPE_PRINT;
  3019. ContextHandle->ResumeId = (DWORD_PTR) -1;
  3020. }
  3021. //
  3022. // The user needs to be validated on a netware311 server to
  3023. // get the print queues. So, we need to close the handle and
  3024. // open a new one with WRITE access. If any error occurred while
  3025. // we are enumerating the print queues, we will abort and
  3026. // assume there are no print queues on the server.
  3027. //
  3028. if ( FitInBuffer &&
  3029. EntriesRequested > *EntriesRead &&
  3030. ContextHandle->ConnectionType == CONNTYPE_PRINT &&
  3031. status == NO_ERROR )
  3032. {
  3033. UNICODE_STRING TreeConnectStr;
  3034. DWORD QueueEntriesRead = 0;
  3035. (void) NtClose(ContextHandle->TreeConnectionHandle);
  3036. //
  3037. // Open a tree connection handle to \Device\NwRdr\ContainerName
  3038. //
  3039. status = NwCreateTreeConnectName(
  3040. ContextHandle->ContainerName,
  3041. NULL,
  3042. &TreeConnectStr );
  3043. if (status != NO_ERROR)
  3044. return (*EntriesRead? NO_ERROR: WN_NO_MORE_ENTRIES );
  3045. status = NwOpenCreateConnection(
  3046. &TreeConnectStr,
  3047. NULL,
  3048. NULL,
  3049. ContextHandle->ContainerName,
  3050. FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_DATA,
  3051. FILE_OPEN,
  3052. FILE_SYNCHRONOUS_IO_NONALERT,
  3053. RESOURCETYPE_PRINT, // Only matters when connecting beyond servername
  3054. &ContextHandle->TreeConnectionHandle,
  3055. NULL );
  3056. (void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
  3057. if (status != NO_ERROR)
  3058. return (*EntriesRead? NO_ERROR: WN_NO_MORE_ENTRIES );
  3059. status = NwEnumQueues(
  3060. ContextHandle,
  3061. EntriesRequested == (DWORD_PTR) -1?
  3062. EntriesRequested : (EntriesRequested - *EntriesRead),
  3063. FixedPortion,
  3064. (DWORD) ((LPBYTE) EndOfVariableData - (LPBYTE) FixedPortion),
  3065. BytesNeeded,
  3066. &QueueEntriesRead );
  3067. if ( status == NO_ERROR )
  3068. {
  3069. *EntriesRead += QueueEntriesRead;
  3070. }
  3071. else if ( *EntriesRead )
  3072. {
  3073. //
  3074. // As long as we read something into the buffer,
  3075. // we should return success.
  3076. //
  3077. status = NO_ERROR;
  3078. *BytesNeeded = 0;
  3079. }
  3080. }
  3081. if ( status == NO_ERROR &&
  3082. *EntriesRead == 0 &&
  3083. ContextHandle->ConnectionType == CONNTYPE_PRINT )
  3084. {
  3085. return WN_NO_MORE_ENTRIES;
  3086. }
  3087. return status;
  3088. }
  3089. DWORD
  3090. NwEnumQueues(
  3091. IN LPNW_ENUM_CONTEXT ContextHandle,
  3092. IN DWORD_PTR EntriesRequested,
  3093. OUT LPBYTE Buffer,
  3094. IN DWORD BufferSize,
  3095. OUT LPDWORD BytesNeeded,
  3096. OUT LPDWORD EntriesRead
  3097. )
  3098. /*++
  3099. Routine Description:
  3100. This function enumerates all the queues on a server.
  3101. The queue entries are returned in an array of NETRESOURCE entries;
  3102. each queue name is prefixed by \\Server\.
  3103. Arguments:
  3104. ContextHandle - Supplies the enum context handle.
  3105. EntriesRequested - Supplies the number of entries to return. If
  3106. this value is (DWORD_PTR) -1, return all available entries.
  3107. Buffer - Receives the entries we are listing.
  3108. BufferSize - Supplies the size of the output buffer.
  3109. BytesNeeded - Receives the number of bytes required to get the
  3110. first entry. This value is returned iff WN_MORE_DATA is
  3111. the return code, and Buffer is too small to even fit one
  3112. entry.
  3113. EntriesRead - Receives the number of entries returned in Buffer.
  3114. This value is only returned iff NO_ERROR is the return code.
  3115. NO_ERROR is returned as long as at least one entry was written
  3116. into Buffer but does not necessarily mean that it's the number
  3117. of EntriesRequested.
  3118. Return Value:
  3119. NO_ERROR - At least one entry was written to output buffer,
  3120. irregardless of the number requested.
  3121. WN_NO_MORE_ENTRIES - No entries left to return.
  3122. WN_MORE_DATA - The buffer was too small to fit a single entry.
  3123. --*/ // NwEnumQueues
  3124. {
  3125. DWORD status = NO_ERROR;
  3126. LPBYTE FixedPortion = Buffer;
  3127. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3128. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3129. BOOL FitInBuffer = TRUE;
  3130. DWORD EntrySize;
  3131. DWORD NextObject = (DWORD) ContextHandle->ResumeId;
  3132. SERVERNAME QueueName; // OEM queue name
  3133. LPWSTR UQueueName = NULL; // Unicode queue name
  3134. while ( FitInBuffer &&
  3135. EntriesRequested > *EntriesRead &&
  3136. status == NO_ERROR ) {
  3137. RtlZeroMemory(QueueName, sizeof(QueueName));
  3138. //
  3139. // Call the scan bindery object NCP to scan for all file
  3140. // volume objects.
  3141. //
  3142. status = NwGetNextQueueEntry(
  3143. ContextHandle->TreeConnectionHandle,
  3144. &NextObject,
  3145. QueueName
  3146. );
  3147. if (status == NO_ERROR && NwConvertToUnicode(&UQueueName, QueueName)) {
  3148. //
  3149. // Pack server name into output buffer.
  3150. //
  3151. status = NwWriteNetResourceEntry(
  3152. &FixedPortion,
  3153. &EndOfVariableData,
  3154. ContextHandle->ContainerName,
  3155. NULL,
  3156. UQueueName,
  3157. RESOURCE_GLOBALNET,
  3158. RESOURCEDISPLAYTYPE_SHARE,
  3159. RESOURCEUSAGE_CONNECTABLE,
  3160. RESOURCETYPE_PRINT,
  3161. NULL,
  3162. NULL,
  3163. &EntrySize
  3164. );
  3165. if (status == WN_MORE_DATA) {
  3166. //
  3167. // Could not write current entry into output buffer.
  3168. //
  3169. if (*EntriesRead) {
  3170. //
  3171. // Still return success because we got at least one.
  3172. //
  3173. status = NO_ERROR;
  3174. }
  3175. else {
  3176. *BytesNeeded = EntrySize;
  3177. }
  3178. FitInBuffer = FALSE;
  3179. }
  3180. else if (status == NO_ERROR) {
  3181. //
  3182. // Note that we've returned the current entry.
  3183. //
  3184. (*EntriesRead)++;
  3185. ContextHandle->ResumeId = (DWORD_PTR) NextObject;
  3186. }
  3187. (void) LocalFree((HLOCAL) UQueueName);
  3188. }
  3189. }
  3190. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3191. status = NO_ERROR;
  3192. }
  3193. return status;
  3194. }
  3195. DWORD
  3196. NwEnumDirectories(
  3197. IN LPNW_ENUM_CONTEXT ContextHandle,
  3198. IN DWORD_PTR EntriesRequested,
  3199. OUT LPBYTE Buffer,
  3200. IN DWORD BufferSize,
  3201. OUT LPDWORD BytesNeeded,
  3202. OUT LPDWORD EntriesRead
  3203. )
  3204. /*++
  3205. Routine Description:
  3206. This function enumerates the directories of a given directory
  3207. handle by calling NtQueryDirectoryFile. It returns the
  3208. fully-qualified UNC path of the directory entries in an array
  3209. of NETRESOURCE entries.
  3210. The ContextHandle->ResumeId field is 0 initially, and contains
  3211. a pointer to the directory name string of the last directory
  3212. returned. If there are no more directories to return, this
  3213. field is set to (DWORD_PTR) -1.
  3214. Arguments:
  3215. ContextHandle - Supplies the enum context handle. It contains
  3216. an opened directory handle.
  3217. EntriesRequested - Supplies the number of entries to return. If
  3218. this value is (DWORD_PTR) -1, return all available entries.
  3219. Buffer - Receives the entries we are listing.
  3220. BufferSize - Supplies the size of the output buffer.
  3221. BytesNeeded - Receives the number of bytes required to get the
  3222. first entry. This value is returned iff WN_MORE_DATA is
  3223. the return code, and Buffer is too small to even fit one
  3224. entry.
  3225. EntriesRead - Receives the number of entries returned in Buffer.
  3226. This value is only returned iff NO_ERROR is the return code.
  3227. NO_ERROR is returned as long as at least one entry was written
  3228. into Buffer but does not necessarily mean that it's the number
  3229. of EntriesRequested.
  3230. Return Value:
  3231. NO_ERROR - At least one entry was written to output buffer,
  3232. irregardless of the number requested.
  3233. WN_NO_MORE_ENTRIES - No entries left to return.
  3234. WN_MORE_DATA - The buffer was too small to fit a single entry.
  3235. --*/ // NwEnumDirectories
  3236. {
  3237. DWORD status = NO_ERROR;
  3238. LPBYTE FixedPortion = Buffer;
  3239. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3240. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3241. BOOL FitInBuffer = TRUE;
  3242. DWORD EntrySize;
  3243. if (ContextHandle->ResumeId == (DWORD_PTR) -1) {
  3244. //
  3245. // Reached the end of enumeration.
  3246. //
  3247. return WN_NO_MORE_ENTRIES;
  3248. }
  3249. while (FitInBuffer &&
  3250. EntriesRequested > *EntriesRead &&
  3251. status == NO_ERROR) {
  3252. if (ContextHandle->ResumeId == 0) {
  3253. //
  3254. // Get the first directory entry.
  3255. //
  3256. status = NwGetFirstDirectoryEntry(
  3257. ContextHandle->TreeConnectionHandle,
  3258. (LPWSTR *) &ContextHandle->ResumeId
  3259. );
  3260. }
  3261. //
  3262. // Either ResumeId contains the first entry we just got from
  3263. // NwGetFirstDirectoryEntry or it contains the next directory
  3264. // entry to return.
  3265. //
  3266. if (ContextHandle->ResumeId != 0) {
  3267. //
  3268. // Pack directory name into output buffer.
  3269. //
  3270. status = NwWriteNetResourceEntry(
  3271. &FixedPortion,
  3272. &EndOfVariableData,
  3273. ContextHandle->ContainerName,
  3274. NULL,
  3275. (LPWSTR) ContextHandle->ResumeId,
  3276. RESOURCE_GLOBALNET,
  3277. RESOURCEDISPLAYTYPE_SHARE,
  3278. #ifdef NT1057
  3279. RESOURCEUSAGE_CONNECTABLE |
  3280. RESOURCEUSAGE_CONTAINER,
  3281. #else
  3282. RESOURCEUSAGE_CONNECTABLE |
  3283. RESOURCEUSAGE_NOLOCALDEVICE,
  3284. #endif
  3285. RESOURCETYPE_DISK,
  3286. NULL,
  3287. NULL,
  3288. &EntrySize
  3289. );
  3290. if (status == WN_MORE_DATA) {
  3291. //
  3292. // Could not write current entry into output buffer.
  3293. //
  3294. if (*EntriesRead) {
  3295. //
  3296. // Still return success because we got at least one.
  3297. //
  3298. status = NO_ERROR;
  3299. }
  3300. else {
  3301. *BytesNeeded = EntrySize;
  3302. }
  3303. FitInBuffer = FALSE;
  3304. }
  3305. else if (status == NO_ERROR) {
  3306. //
  3307. // Note that we've returned the current entry.
  3308. //
  3309. (*EntriesRead)++;
  3310. //
  3311. // Free memory allocated to save resume point, which is
  3312. // a buffer that contains the last directory we returned.
  3313. //
  3314. if (ContextHandle->ResumeId != 0) {
  3315. (void) LocalFree((HLOCAL) ContextHandle->ResumeId);
  3316. ContextHandle->ResumeId = 0;
  3317. }
  3318. //
  3319. // Get next directory entry.
  3320. //
  3321. status = NwGetNextDirectoryEntry(
  3322. (LPWSTR) ContextHandle->TreeConnectionHandle,
  3323. (LPWSTR *) &ContextHandle->ResumeId
  3324. );
  3325. }
  3326. }
  3327. if (status == WN_NO_MORE_ENTRIES) {
  3328. ContextHandle->ResumeId = (DWORD_PTR) -1;
  3329. }
  3330. }
  3331. //
  3332. // User asked for more than there are entries. We just say that
  3333. // all is well.
  3334. //
  3335. // This is incompliance with the wierd provider API definition where
  3336. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3337. // at least one entry fit into output buffer, there's no telling if
  3338. // the buffer was too small for more entries or there are no more
  3339. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  3340. // before knowing that the last call had actually reached the end of list.
  3341. //
  3342. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3343. status = NO_ERROR;
  3344. }
  3345. #if DBG
  3346. IF_DEBUG(ENUM) {
  3347. KdPrint(("EnumDirectories returns %lu\n", status));
  3348. }
  3349. #endif
  3350. return status;
  3351. }
  3352. DWORD
  3353. NwEnumPrintServers(
  3354. IN LPNW_ENUM_CONTEXT ContextHandle,
  3355. IN DWORD_PTR EntriesRequested,
  3356. OUT LPBYTE Buffer,
  3357. IN DWORD BufferSize,
  3358. OUT LPDWORD BytesNeeded,
  3359. OUT LPDWORD EntriesRead
  3360. )
  3361. /*++
  3362. Routine Description:
  3363. This function enumerates all the servers and NDS tree on the local network
  3364. by scanning the bindery for file server or directory objects on the
  3365. preferred server. The server and tree entries are returned in an
  3366. array of PRINTER_INFO_1 entries; each entry name is prefixed by
  3367. \\.
  3368. The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
  3369. enumeration begins and contains the object ID of the last server
  3370. object returned.
  3371. Arguments:
  3372. ContextHandle - Supplies the enum context handle.
  3373. EntriesRequested - Supplies the number of entries to return. If
  3374. this value is (DWORD_PTR) -1, return all available entries.
  3375. Buffer - Receives the entries we are listing.
  3376. BufferSize - Supplies the size of the output buffer.
  3377. BytesNeeded - Receives the number of bytes copied or required to get all
  3378. the requested entries.
  3379. EntriesRead - Receives the number of entries returned in Buffer.
  3380. This value is only returned iff NO_ERROR is the return code.
  3381. Return Value:
  3382. NO_ERROR - Buffer contains all the entries requested.
  3383. WN_NO_MORE_ENTRIES - No entries left to return.
  3384. WN_MORE_DATA - The buffer was too small to fit the requested entries.
  3385. --*/ // NwEnumPrintServers
  3386. {
  3387. DWORD status = NO_ERROR;
  3388. LPBYTE FixedPortion = Buffer;
  3389. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3390. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3391. DWORD EntrySize;
  3392. BOOL FitInBuffer = TRUE;
  3393. SERVERNAME ServerName; // OEM server name
  3394. LPWSTR UServerName = NULL; // Unicode server name
  3395. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  3396. WCHAR TempBuffer[500];
  3397. while ( EntriesRequested > *EntriesRead &&
  3398. ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS &&
  3399. ((status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER)))
  3400. {
  3401. //
  3402. // Call the scan bindery object NCP to scan for all NDS
  3403. // tree objects.
  3404. //
  3405. status = NwGetNextNdsTreeEntry( ContextHandle );
  3406. if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
  3407. {
  3408. //
  3409. // Put tree name into a buffer
  3410. //
  3411. RtlZeroMemory( TempBuffer, 500 );
  3412. wcscat( TempBuffer, (LPWSTR) ContextHandle->ResumeId );
  3413. //
  3414. // Pack server name into output buffer.
  3415. //
  3416. status = NwWritePrinterInfoEntry(
  3417. &FixedPortion,
  3418. &EndOfVariableData,
  3419. NULL,
  3420. TempBuffer, // This is a NDS tree name
  3421. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1,
  3422. &EntrySize
  3423. );
  3424. switch ( status )
  3425. {
  3426. case ERROR_INSUFFICIENT_BUFFER:
  3427. FitInBuffer = FALSE;
  3428. // Falls through
  3429. case NO_ERROR:
  3430. *BytesNeeded += EntrySize;
  3431. (*EntriesRead)++;
  3432. // ContextHandle->ResumeId = LastObjectId;
  3433. break;
  3434. default:
  3435. break;
  3436. }
  3437. }
  3438. else if ( status == WN_NO_MORE_ENTRIES )
  3439. {
  3440. //
  3441. // We processed the last item in list, so
  3442. // start enumerating servers.
  3443. //
  3444. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  3445. ContextHandle->ResumeId = (DWORD_PTR) -1;
  3446. LastObjectId = (DWORD) -1;
  3447. }
  3448. }
  3449. status = NO_ERROR;
  3450. while ( EntriesRequested > *EntriesRead &&
  3451. ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
  3452. ((status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER))) {
  3453. RtlZeroMemory(ServerName, sizeof(ServerName));
  3454. //
  3455. // Call the scan bindery object NCP to scan for all file
  3456. // server objects.
  3457. //
  3458. status = NwGetNextServerEntry(
  3459. ContextHandle->TreeConnectionHandle,
  3460. &LastObjectId,
  3461. ServerName
  3462. );
  3463. if (status == NO_ERROR && NwConvertToUnicode(&UServerName,ServerName)) {
  3464. //
  3465. // Pack server name into output buffer.
  3466. //
  3467. status = NwWritePrinterInfoEntry(
  3468. &FixedPortion,
  3469. &EndOfVariableData,
  3470. NULL,
  3471. UServerName,
  3472. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON3,
  3473. &EntrySize
  3474. );
  3475. switch ( status )
  3476. {
  3477. case ERROR_INSUFFICIENT_BUFFER:
  3478. FitInBuffer = FALSE;
  3479. // Falls through
  3480. case NO_ERROR:
  3481. *BytesNeeded += EntrySize;
  3482. (*EntriesRead)++;
  3483. ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
  3484. break;
  3485. default:
  3486. break;
  3487. }
  3488. (void) LocalFree((HLOCAL) UServerName);
  3489. }
  3490. }
  3491. //
  3492. // This is incompliance with the wierd provider API definition where
  3493. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3494. // at least one entry fit into output buffer, there's no telling if
  3495. // the buffer was too small for more entries or there are no more
  3496. //
  3497. // This is incompliance with the wierd provider API definition where
  3498. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3499. // at least one entry fit into output buffer, there's no telling if
  3500. // the buffer was too small for more entries or there are no more
  3501. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  3502. // before knowing that the last call had actually reached the end of list.
  3503. //
  3504. if ( !FitInBuffer ) {
  3505. *EntriesRead = 0;
  3506. status = ERROR_INSUFFICIENT_BUFFER;
  3507. }
  3508. else if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3509. status = NO_ERROR;
  3510. }
  3511. return status;
  3512. }
  3513. DWORD
  3514. NwEnumPrintQueues(
  3515. IN LPNW_ENUM_CONTEXT ContextHandle,
  3516. IN DWORD_PTR EntriesRequested,
  3517. OUT LPBYTE Buffer,
  3518. IN DWORD BufferSize,
  3519. OUT LPDWORD BytesNeeded,
  3520. OUT LPDWORD EntriesRead
  3521. )
  3522. /*++
  3523. Routine Description:
  3524. This function enumerates all the print queues on a server by scanning
  3525. the bindery on the server for print queues objects.
  3526. The print queues entries are returned in an array of PRINTER_INFO_1 entries
  3527. and each printer name is prefixed by \\Server\.
  3528. The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
  3529. enumeration begins and contains the object ID of the last print queue
  3530. object returned.
  3531. Arguments:
  3532. ContextHandle - Supplies the enum context handle.
  3533. EntriesRequested - Supplies the number of entries to return. If
  3534. this value is (DWORD_PTR) -1, return all available entries.
  3535. Buffer - Receives the entries we are listing.
  3536. BufferSize - Supplies the size of the output buffer.
  3537. BytesNeeded - Receives the number of bytes copied or required to get all
  3538. the requested entries.
  3539. EntriesRead - Receives the number of entries returned in Buffer.
  3540. This value is only returned iff NO_ERROR is the return code.
  3541. Return Value:
  3542. NO_ERROR - Buffer contains all the entries requested.
  3543. WN_NO_MORE_ENTRIES - No entries left to return.
  3544. WN_MORE_DATA - The buffer was too small to fit the requested entries.
  3545. --*/ // NwEnumPrintQueues
  3546. {
  3547. DWORD status = NO_ERROR;
  3548. LPBYTE FixedPortion = Buffer;
  3549. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3550. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3551. DWORD EntrySize;
  3552. BOOL FitInBuffer = TRUE;
  3553. SERVERNAME QueueName; // OEM queue name
  3554. LPWSTR UQueueName = NULL; // Unicode queue name
  3555. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  3556. while ( EntriesRequested > *EntriesRead &&
  3557. ( (status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER))) {
  3558. RtlZeroMemory(QueueName, sizeof(QueueName));
  3559. //
  3560. // Call the scan bindery object NCP to scan for all file
  3561. // volume objects.
  3562. //
  3563. status = NwGetNextQueueEntry(
  3564. ContextHandle->TreeConnectionHandle,
  3565. &LastObjectId,
  3566. QueueName
  3567. );
  3568. if (status == NO_ERROR && NwConvertToUnicode(&UQueueName, QueueName)) {
  3569. //
  3570. // Pack server name into output buffer.
  3571. //
  3572. status = NwWritePrinterInfoEntry(
  3573. &FixedPortion,
  3574. &EndOfVariableData,
  3575. ContextHandle->ContainerName,
  3576. UQueueName,
  3577. PRINTER_ENUM_ICON8,
  3578. &EntrySize
  3579. );
  3580. switch ( status )
  3581. {
  3582. case ERROR_INSUFFICIENT_BUFFER:
  3583. FitInBuffer = FALSE;
  3584. // Falls through
  3585. case NO_ERROR:
  3586. *BytesNeeded += EntrySize;
  3587. (*EntriesRead)++;
  3588. ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
  3589. break;
  3590. default:
  3591. break;
  3592. }
  3593. (void) LocalFree((HLOCAL) UQueueName);
  3594. }
  3595. }
  3596. //
  3597. // This is incompliance with the wierd provider API definition where
  3598. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3599. // at least one entry fit into output buffer, there's no telling if
  3600. // the buffer was too small for more entries or there are no more
  3601. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  3602. // before knowing that the last call had actually reached the end of list.
  3603. //
  3604. if ( !FitInBuffer ) {
  3605. *EntriesRead = 0;
  3606. status = ERROR_INSUFFICIENT_BUFFER;
  3607. }
  3608. else if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3609. status = NO_ERROR;
  3610. }
  3611. return status;
  3612. }
  3613. DWORD
  3614. NwrCloseEnum(
  3615. IN OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  3616. )
  3617. /*++
  3618. Routine Description:
  3619. This function closes an enum context handle.
  3620. Arguments:
  3621. EnumHandle - Supplies a pointer to the enum context handle.
  3622. Return Value:
  3623. WN_BAD_HANDLE - Handle is not recognizable.
  3624. NO_ERROR - Call was successful.
  3625. --*/ // NwrCloseEnum
  3626. {
  3627. LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) *EnumHandle;
  3628. DWORD status = NO_ERROR ;
  3629. #if DBG
  3630. IF_DEBUG(ENUM)
  3631. {
  3632. KdPrint(("\nNWWORKSTATION: NwrCloseEnum\n"));
  3633. }
  3634. #endif
  3635. if (ContextHandle->Signature != NW_HANDLE_SIGNATURE)
  3636. {
  3637. ASSERT(FALSE);
  3638. return WN_BAD_HANDLE;
  3639. }
  3640. //
  3641. // Resume handle for listing directories is a buffer which contains
  3642. // the last directory returned.
  3643. //
  3644. if (ContextHandle->HandleType == NwsHandleListDirectories &&
  3645. ContextHandle->ResumeId != 0 &&
  3646. ContextHandle->ResumeId != (DWORD_PTR) -1)
  3647. {
  3648. (void) LocalFree((HLOCAL) ContextHandle->ResumeId);
  3649. }
  3650. //
  3651. // NdsRawDataBuffer handle for listing NDS tree subordinates is a buffer which contains
  3652. // the last data chunk returned from redirector.
  3653. //
  3654. if ( ( ContextHandle->HandleType == NwsHandleListNdsSubTrees_Disk ||
  3655. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Print ||
  3656. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Any ||
  3657. ContextHandle->HandleType == NwsHandleListServersAndNdsTrees ) &&
  3658. ContextHandle->NdsRawDataBuffer )
  3659. {
  3660. (void) LocalFree((HLOCAL) ContextHandle->NdsRawDataBuffer);
  3661. ContextHandle->NdsRawDataBuffer = 0;
  3662. }
  3663. if (ContextHandle->TreeConnectionHandle != (HANDLE) NULL)
  3664. {
  3665. if (ContextHandle->HandleType == NwsHandleListDirectories)
  3666. {
  3667. //
  3668. // Delete the UNC connection created so that we can browse
  3669. // directories.
  3670. //
  3671. (void) NwNukeConnection(ContextHandle->TreeConnectionHandle, TRUE);
  3672. }
  3673. if ( ContextHandle->HandleType == NwsHandleListNdsSubTrees_Disk ||
  3674. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Print ||
  3675. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Any )
  3676. {
  3677. //
  3678. // Get rid of the connection to the NDS tree.
  3679. //
  3680. (void) CloseHandle(ContextHandle->TreeConnectionHandle);
  3681. ContextHandle->TreeConnectionHandle = 0;
  3682. }
  3683. else
  3684. {
  3685. (void) NtClose(ContextHandle->TreeConnectionHandle);
  3686. ContextHandle->TreeConnectionHandle = 0;
  3687. }
  3688. }
  3689. ContextHandle->Signature = 0x0BADBAD0;
  3690. (void) LocalFree((HLOCAL) ContextHandle);
  3691. *EnumHandle = NULL;
  3692. return status;
  3693. }
  3694. DWORD
  3695. NwrGetUser(
  3696. IN LPWSTR Reserved OPTIONAL,
  3697. IN LPWSTR lpName,
  3698. OUT LPBYTE lpUserName,
  3699. IN DWORD dwUserNameBufferSize,
  3700. OUT LPDWORD lpdwCharsRequired
  3701. )
  3702. /*++
  3703. Routine Description:
  3704. This is used to determine either the current default username, or the
  3705. username used to establish a network connection.
  3706. Arguments:
  3707. Reserved - Unused.
  3708. lpName - The connection for which user information is requested.
  3709. lpUserName - The buffer to receive the user name associated with the
  3710. connection referred to by lpName.
  3711. dwUserNameLen - The size of the buffer lpUserName.
  3712. lpdwCharsRequired - If return status is WN_MORE_DATA, then this is set to
  3713. the value which indicates the number of characters that the buffer
  3714. lpUserName must hold. Otherwise, this is not set.
  3715. Return Value:
  3716. WN_SUCCESS - If the call is successful. Otherwise, an error code is,
  3717. returned, which may include:
  3718. WN_NOT_CONNECTED - lpName not a redirected device nor a connected network
  3719. name.
  3720. WN_MORE_DATA - The buffer is too small.
  3721. --*/ // NwrGetUser
  3722. {
  3723. DWORD status = NO_ERROR;
  3724. WCHAR lpTempUserName[512];
  3725. WCHAR lpTempHostName[512];
  3726. if (lpName == NULL)
  3727. {
  3728. return ERROR_INVALID_PARAMETER;
  3729. }
  3730. status = NwGetConnectionInformation( lpName, lpTempUserName, lpTempHostName );
  3731. if ( status == ERROR_BAD_NETPATH )
  3732. {
  3733. return WN_NOT_CONNECTED;
  3734. }
  3735. if ( status != NO_ERROR )
  3736. {
  3737. return status;
  3738. }
  3739. if ( ( ( wcslen( lpTempUserName ) + 1 ) * sizeof(WCHAR) ) > dwUserNameBufferSize )
  3740. {
  3741. *lpdwCharsRequired = wcslen( lpTempUserName ) + 1;
  3742. return WN_MORE_DATA;
  3743. }
  3744. wcscpy( (LPWSTR) lpUserName, lpTempUserName );
  3745. return WN_SUCCESS;
  3746. }
  3747. DWORD
  3748. NwrGetResourceInformation(
  3749. IN LPWSTR Reserved OPTIONAL,
  3750. IN LPWSTR lpRemoteName,
  3751. IN DWORD dwType,
  3752. OUT LPBYTE lpBuffer,
  3753. IN DWORD dwBufferSize,
  3754. OUT LPDWORD lpdwBytesNeeded,
  3755. OUT LPDWORD lpdwSystemOffset
  3756. )
  3757. /*++
  3758. Routine Description:
  3759. This function returns an object which details information
  3760. about a specified network resource.
  3761. Arguments:
  3762. Reserved - Unused.
  3763. lpRemoteName - The full path name to be verified.
  3764. dwType - The type of the value, if the calling client knows it.
  3765. lpBuffer - A pointer to a buffer to receive a single NETRESOURCE entry.
  3766. dwBufferSize - The size of the buffer.
  3767. lpdwBytesNeeded - The buffer size needed if WN_MORE_DATA is returned.
  3768. lpdwSystemOffset - A DWORD that is an offset value to the beginning of a
  3769. string that specifies the part of the resource that is accessed through
  3770. resource type specific APIs rather than WNet APIs. The string is stored
  3771. in the same buffer as the returned NETRESOURCE structure, lpBuffer.
  3772. Return Value:
  3773. WN_SUCCESS - If the call is successful.
  3774. WN_MORE_DATA - If input buffer is too small.
  3775. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  3776. of parameters is specified (e.g. lpRemoteName does not correspond
  3777. to dwType).
  3778. WN_BAD_NETNAME - The resource is not recognized by this provider.
  3779. --*/ // NwrGetResourceInformation
  3780. {
  3781. DWORD status = NO_ERROR;
  3782. DWORD EntrySize;
  3783. LPBYTE FixedPortion = lpBuffer;
  3784. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3785. ROUND_DOWN_COUNT(dwBufferSize,ALIGN_DWORD));
  3786. LPWSTR lpObjectPathName = NULL;
  3787. LPWSTR lpSystemPathPart = NULL;
  3788. LPWSTR lpSystem = NULL;
  3789. DWORD ClassType;
  3790. DWORD ResourceScope = RESOURCE_CONTEXT; // prefix issue
  3791. DWORD ResourceType = 0;
  3792. DWORD ResourceDisplayType;
  3793. DWORD ResourceUsage;
  3794. BOOL fReturnBadNetName = FALSE;
  3795. if (lpRemoteName == NULL)
  3796. {
  3797. return ERROR_INVALID_PARAMETER;
  3798. }
  3799. *lpdwSystemOffset = 0;
  3800. status = NwGetNDSPathInfo( lpRemoteName,
  3801. &lpObjectPathName,
  3802. &lpSystemPathPart,
  3803. &ClassType,
  3804. &ResourceScope,
  3805. &ResourceType,
  3806. &ResourceDisplayType,
  3807. &ResourceUsage );
  3808. if ( status == VERIFY_ERROR_NOT_A_NDS_TREE )
  3809. {
  3810. //
  3811. // Code to handle \\SERVER\VOL\... here!
  3812. //
  3813. status = NwGetBinderyPathInfo( lpRemoteName,
  3814. &lpObjectPathName,
  3815. &lpSystemPathPart,
  3816. &ClassType,
  3817. &ResourceScope,
  3818. &ResourceType,
  3819. &ResourceDisplayType,
  3820. &ResourceUsage );
  3821. }
  3822. if ( status == VERIFY_ERROR_PATH_NOT_FOUND )
  3823. {
  3824. fReturnBadNetName = TRUE;
  3825. status = NO_ERROR;
  3826. }
  3827. if ( status == NO_ERROR &&
  3828. dwType != RESOURCETYPE_ANY &&
  3829. ResourceType != RESOURCETYPE_ANY &&
  3830. dwType != ResourceType )
  3831. {
  3832. status = WN_BAD_VALUE;
  3833. }
  3834. if ( status == NO_ERROR )
  3835. {
  3836. //
  3837. // Pack subtree name into output buffer.
  3838. //
  3839. status = NwWriteNetResourceEntry( &FixedPortion,
  3840. &EndOfVariableData,
  3841. NULL,
  3842. NULL,
  3843. lpObjectPathName == NULL ? NwProviderName : lpObjectPathName,
  3844. ResourceScope,
  3845. ResourceDisplayType,
  3846. ResourceUsage,
  3847. ResourceType,
  3848. lpSystemPathPart,
  3849. &lpSystem,
  3850. &EntrySize );
  3851. if ( lpObjectPathName )
  3852. (void) LocalFree( (HLOCAL) lpObjectPathName );
  3853. }
  3854. else
  3855. {
  3856. if ( lpSystemPathPart != NULL )
  3857. {
  3858. (void) LocalFree( (HLOCAL) lpSystemPathPart );
  3859. lpSystemPathPart = NULL;
  3860. }
  3861. return status;
  3862. }
  3863. if ( status != NO_ERROR )
  3864. {
  3865. if (status == WN_MORE_DATA)
  3866. {
  3867. //
  3868. // Could not write current entry into output buffer.
  3869. //
  3870. *lpdwBytesNeeded = EntrySize;
  3871. }
  3872. if ( lpSystemPathPart != NULL )
  3873. {
  3874. (void) LocalFree( (HLOCAL) lpSystemPathPart );
  3875. lpSystemPathPart = NULL;
  3876. }
  3877. if ( fReturnBadNetName )
  3878. return WN_BAD_NETNAME;
  3879. return status;
  3880. }
  3881. else
  3882. {
  3883. LPNETRESOURCEW NetR = (LPNETRESOURCEW) lpBuffer;
  3884. //
  3885. // Replace pointers to strings with offsets as need
  3886. //
  3887. if (NetR->lpLocalName != NULL)
  3888. {
  3889. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) lpBuffer);
  3890. }
  3891. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR) lpBuffer);
  3892. if (NetR->lpComment != NULL)
  3893. {
  3894. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) - (DWORD_PTR) lpBuffer);
  3895. }
  3896. if (NetR->lpProvider != NULL)
  3897. {
  3898. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) - (DWORD_PTR) lpBuffer);
  3899. }
  3900. if (lpSystem != NULL)
  3901. {
  3902. *lpdwSystemOffset = (DWORD)((DWORD_PTR) lpSystem - (DWORD_PTR) lpBuffer);
  3903. }
  3904. if ( lpSystemPathPart != NULL )
  3905. {
  3906. (void) LocalFree( (HLOCAL) lpSystemPathPart );
  3907. lpSystemPathPart = NULL;
  3908. }
  3909. if ( fReturnBadNetName )
  3910. return WN_BAD_NETNAME;
  3911. return WN_SUCCESS;
  3912. }
  3913. }
  3914. DWORD
  3915. NwrGetResourceParent(
  3916. IN LPWSTR Reserved OPTIONAL,
  3917. IN LPWSTR lpRemoteName,
  3918. IN DWORD dwType,
  3919. OUT LPBYTE lpBuffer,
  3920. IN DWORD dwBufferSize,
  3921. OUT LPDWORD lpdwBytesNeeded
  3922. )
  3923. /*++
  3924. Routine Description:
  3925. This function returns an object which details information
  3926. about the parent of a specified network resource.
  3927. Arguments:
  3928. Reserved - Unused.
  3929. lpRemoteName - The full path name of object to find the parent of.
  3930. dwType - The type of the value, if the calling client knows it.
  3931. lpBuffer - A pointer to a buffer to receive a single NETRESOURCE entry.
  3932. dwBufferSize - The size of the buffer.
  3933. lpdwBytesNeeded - The buffer size needed if WN_MORE_DATA is returned.
  3934. Return Value:
  3935. WN_SUCCESS - If the call is successful.
  3936. WN_MORE_DATA - If input buffer is too small.
  3937. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  3938. of parameters is specified (e.g. lpRemoteName does not correspond
  3939. to dwType).
  3940. --*/ // NwrGetResourceParent
  3941. {
  3942. DWORD status = NO_ERROR;
  3943. DWORD EntrySize;
  3944. LPBYTE FixedPortion = lpBuffer;
  3945. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3946. ROUND_DOWN_COUNT(dwBufferSize,ALIGN_DWORD));
  3947. LPWSTR lpRemoteNameParent = NULL;
  3948. LPWSTR lpFullObjectPathName = NULL;
  3949. DWORD ClassType;
  3950. DWORD ResourceScope;
  3951. DWORD ResourceType;
  3952. DWORD ResourceDisplayType;
  3953. DWORD ResourceUsage;
  3954. BOOL fReturnBadNetName = FALSE;
  3955. if (lpRemoteName == NULL)
  3956. {
  3957. return ERROR_INVALID_PARAMETER;
  3958. }
  3959. if ( ! NwGetRemoteNameParent( lpRemoteName, &lpRemoteNameParent ) )
  3960. {
  3961. return WN_BAD_NETNAME;
  3962. }
  3963. status = NwVerifyNDSObject( lpRemoteNameParent,
  3964. &lpFullObjectPathName,
  3965. &ClassType,
  3966. &ResourceScope,
  3967. &ResourceType,
  3968. &ResourceDisplayType,
  3969. &ResourceUsage );
  3970. if ( status == VERIFY_ERROR_NOT_A_NDS_TREE )
  3971. {
  3972. status = NwVerifyBinderyObject( lpRemoteNameParent,
  3973. &lpFullObjectPathName,
  3974. &ClassType,
  3975. &ResourceScope,
  3976. &ResourceType,
  3977. &ResourceDisplayType,
  3978. &ResourceUsage );
  3979. }
  3980. if ( lpRemoteNameParent )
  3981. (void) LocalFree( (HLOCAL) lpRemoteNameParent );
  3982. if ( status == VERIFY_ERROR_PATH_NOT_FOUND )
  3983. {
  3984. fReturnBadNetName = TRUE;
  3985. status = NO_ERROR;
  3986. }
  3987. if ( status == NO_ERROR )
  3988. {
  3989. //
  3990. // Pack subtree name into output buffer.
  3991. //
  3992. status = NwWriteNetResourceEntry( &FixedPortion,
  3993. &EndOfVariableData,
  3994. NULL,
  3995. NULL,
  3996. lpFullObjectPathName == NULL ? NwProviderName : lpFullObjectPathName,
  3997. ResourceScope,
  3998. ResourceDisplayType,
  3999. ResourceUsage,
  4000. ResourceType,
  4001. NULL,
  4002. NULL,
  4003. &EntrySize );
  4004. if ( lpFullObjectPathName )
  4005. (void) LocalFree( (HLOCAL) lpFullObjectPathName );
  4006. }
  4007. else
  4008. {
  4009. return status;
  4010. }
  4011. if ( status != NO_ERROR )
  4012. {
  4013. if (status == WN_MORE_DATA)
  4014. {
  4015. //
  4016. // Could not write current entry into output buffer.
  4017. //
  4018. *lpdwBytesNeeded = EntrySize;
  4019. }
  4020. if ( fReturnBadNetName )
  4021. return WN_BAD_NETNAME;
  4022. return status;
  4023. }
  4024. else
  4025. {
  4026. LPNETRESOURCEW NetR = (LPNETRESOURCEW) lpBuffer;
  4027. //
  4028. // Replace pointers to strings with offsets as need
  4029. //
  4030. if (NetR->lpLocalName != NULL)
  4031. {
  4032. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) lpBuffer);
  4033. }
  4034. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR) lpBuffer);
  4035. if (NetR->lpComment != NULL)
  4036. {
  4037. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) - (DWORD_PTR) lpBuffer);
  4038. }
  4039. if (NetR->lpProvider != NULL)
  4040. {
  4041. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) - (DWORD_PTR) lpBuffer);
  4042. }
  4043. if ( fReturnBadNetName )
  4044. return WN_BAD_NETNAME;
  4045. return WN_SUCCESS;
  4046. }
  4047. }
  4048. VOID
  4049. NWWKSTA_CONTEXT_HANDLE_rundown(
  4050. IN NWWKSTA_CONTEXT_HANDLE EnumHandle
  4051. )
  4052. /*++
  4053. Routine Description:
  4054. This function is called by RPC when a client terminates with an
  4055. opened handle. This allows us to clean up and deallocate any context
  4056. data associated with the handle.
  4057. Arguments:
  4058. EnumHandle - Supplies the handle opened for an enumeration.
  4059. Return Value:
  4060. None.
  4061. --*/
  4062. {
  4063. //
  4064. // Call our close handle routine.
  4065. //
  4066. NwrCloseEnum(&EnumHandle);
  4067. }
  4068. DWORD
  4069. NwGetFirstNdsSubTreeEntry(
  4070. OUT LPNW_ENUM_CONTEXT ContextHandle,
  4071. IN DWORD BufferSize
  4072. )
  4073. /*++
  4074. Routine Description:
  4075. This function is called by NwEnumNdsSubTrees to get the first
  4076. subtree entry given a handle to a NDS tree. It allocates
  4077. the output buffer to hold the returned subtree name; the
  4078. caller should free this output buffer with LocalFree when done.
  4079. Arguments:
  4080. Return Value:
  4081. NO_ERROR - The operation was successful.
  4082. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  4083. buffer.
  4084. Other errors from NwNdsList.
  4085. --*/ // NwGetFirstNdsSubTreeEntry
  4086. {
  4087. NTSTATUS ntstatus;
  4088. ContextHandle->NdsRawDataSize = BufferSize;
  4089. //
  4090. // Determine size of NDS raw data buffer to use.
  4091. //
  4092. if ( ContextHandle->NdsRawDataSize < EIGHT_KB )
  4093. ContextHandle->NdsRawDataSize = EIGHT_KB;
  4094. else // dfergus 19 Apr 2001 - 346859
  4095. // if buffer too big, set to max NDS buffer size
  4096. if (ContextHandle->NdsRawDataSize > 0xFC00) // NW_MAX_BUFFER = 0xFC00
  4097. ContextHandle->NdsRawDataSize = 0xFC00;
  4098. //
  4099. // Create NDS raw data buffer.
  4100. //
  4101. ContextHandle->NdsRawDataBuffer = (DWORD_PTR)
  4102. LocalAlloc( LMEM_ZEROINIT,
  4103. ContextHandle->NdsRawDataSize );
  4104. if ( ContextHandle->NdsRawDataBuffer == 0 )
  4105. {
  4106. KdPrint(("NWWORKSTATION: NwGetFirstNdsSubTreeEntry LocalAlloc Failed %lu\n", GetLastError()));
  4107. return ERROR_NOT_ENOUGH_MEMORY;
  4108. }
  4109. //
  4110. // Set up to get initial NDS subordinate list.
  4111. //
  4112. ContextHandle->NdsRawDataId = INITIAL_ITERATION;
  4113. ntstatus = NwNdsList( ContextHandle->TreeConnectionHandle,
  4114. ContextHandle->dwOid,
  4115. &ContextHandle->NdsRawDataId,
  4116. (LPBYTE) ContextHandle->NdsRawDataBuffer,
  4117. ContextHandle->NdsRawDataSize );
  4118. //
  4119. // If error, clean up the ContextHandle and return.
  4120. //
  4121. if ( ntstatus != STATUS_SUCCESS ||
  4122. ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4123. ContextHandle->NdsRawDataBuffer)->SubordinateEntries == 0 )
  4124. {
  4125. if ( ContextHandle->NdsRawDataBuffer )
  4126. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  4127. ContextHandle->NdsRawDataBuffer = 0;
  4128. ContextHandle->NdsRawDataSize = 0;
  4129. ContextHandle->NdsRawDataId = INITIAL_ITERATION;
  4130. ContextHandle->NdsRawDataCount = 0;
  4131. ContextHandle->ResumeId = 0;
  4132. return WN_NO_MORE_ENTRIES;
  4133. }
  4134. ContextHandle->NdsRawDataCount = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4135. ContextHandle->NdsRawDataBuffer)->SubordinateEntries - 1;
  4136. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer +
  4137. sizeof( NDS_RESPONSE_SUBORDINATE_LIST );
  4138. // Multi-user code merge
  4139. // 12/05/96 cjc Fix problem with FileManager not showing all the NDS entries.
  4140. // Problem occurs when the NDS entries don't fit in 1 NCP packet;
  4141. // need to keep track of the Iteration # and redo NCP.
  4142. ContextHandle->NdsRawDataId = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4143. ContextHandle->NdsRawDataBuffer)->IterationHandle;
  4144. return RtlNtStatusToDosError(ntstatus);
  4145. }
  4146. DWORD
  4147. NwGetNextNdsSubTreeEntry(
  4148. OUT LPNW_ENUM_CONTEXT ContextHandle
  4149. )
  4150. /*++
  4151. Routine Description:
  4152. This function is called by NwEnumNdsSubTrees to get the next
  4153. NDS subtree entry given a handle to a NDS tree. It allocates
  4154. the output buffer to hold the returned subtree name; the
  4155. caller should free this output buffer with LocalFree when done.
  4156. Arguments:
  4157. Return Value:
  4158. NO_ERROR - The operation was successful.
  4159. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  4160. buffer.
  4161. Other errors from NwNdsList.
  4162. --*/ // NwGetNextDirectoryEntry
  4163. {
  4164. NTSTATUS ntstatus = STATUS_SUCCESS;
  4165. PBYTE pbRaw;
  4166. DWORD dwStrLen;
  4167. if ( ContextHandle->NdsRawDataCount == 0 &&
  4168. ContextHandle->NdsRawDataId == INITIAL_ITERATION )
  4169. return WN_NO_MORE_ENTRIES;
  4170. if ( ContextHandle->NdsRawDataCount == 0 &&
  4171. ContextHandle->NdsRawDataId != INITIAL_ITERATION )
  4172. {
  4173. ntstatus = NwNdsList( ContextHandle->TreeConnectionHandle,
  4174. ContextHandle->dwOid,
  4175. &ContextHandle->NdsRawDataId,
  4176. (LPBYTE) ContextHandle->NdsRawDataBuffer,
  4177. ContextHandle->NdsRawDataSize );
  4178. //
  4179. // If error, clean up the ContextHandle and return.
  4180. //
  4181. if (ntstatus != STATUS_SUCCESS)
  4182. {
  4183. if ( ContextHandle->NdsRawDataBuffer )
  4184. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  4185. ContextHandle->NdsRawDataBuffer = 0;
  4186. ContextHandle->NdsRawDataSize = 0;
  4187. ContextHandle->NdsRawDataId = INITIAL_ITERATION;
  4188. ContextHandle->NdsRawDataCount = 0;
  4189. return WN_NO_MORE_ENTRIES;
  4190. }
  4191. ContextHandle->NdsRawDataCount = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4192. ContextHandle->NdsRawDataBuffer)->SubordinateEntries - 1;
  4193. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer +
  4194. sizeof( NDS_RESPONSE_SUBORDINATE_LIST );
  4195. // ---Multi-user change ---
  4196. // 12/05/96 cjc Fix problem with FileManager not showing all the NDS entries.
  4197. // Problem occurs when the NDS entries don't fit in 1 NCP packet;
  4198. // need to keep track of the Iteration # and redo NCP.
  4199. ContextHandle->NdsRawDataId = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4200. ContextHandle->NdsRawDataBuffer)->IterationHandle;
  4201. return RtlNtStatusToDosError(ntstatus);
  4202. }
  4203. ContextHandle->NdsRawDataCount--;
  4204. //
  4205. // Move pointer past the fixed header portion of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4206. //
  4207. pbRaw = (BYTE *) ContextHandle->ResumeId;
  4208. pbRaw += sizeof( NDS_RESPONSE_SUBORDINATE_ENTRY );
  4209. //
  4210. // Move pointer past the length value of the Class Name string
  4211. // of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4212. //
  4213. dwStrLen = * (DWORD *) pbRaw;
  4214. pbRaw += sizeof( DWORD );
  4215. //
  4216. // Move pointer past the Class Name string of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4217. //
  4218. pbRaw += ROUNDUP4( dwStrLen );
  4219. //
  4220. // Move pointer past the length value of the Object Name string
  4221. // of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4222. //
  4223. dwStrLen = * (DWORD *) pbRaw;
  4224. pbRaw += sizeof( DWORD );
  4225. ContextHandle->ResumeId = (DWORD_PTR) ( pbRaw + ROUNDUP4( dwStrLen ) );
  4226. return RtlNtStatusToDosError(ntstatus);
  4227. }
  4228. BYTE
  4229. NwGetSubTreeData(
  4230. IN DWORD_PTR NdsRawDataPtr,
  4231. OUT LPWSTR * SubTreeName,
  4232. OUT LPDWORD ResourceScope,
  4233. OUT LPDWORD ResourceType,
  4234. OUT LPDWORD ResourceDisplayType,
  4235. OUT LPDWORD ResourceUsage,
  4236. OUT LPWSTR * StrippedObjectName
  4237. )
  4238. /*++
  4239. Routine Description:
  4240. This function is called by NwEnumNdsSubTrees to get the information
  4241. needed to describe a single NETRESOURCE from an entry in the
  4242. NdsRawDataBuffer.
  4243. Arguments:
  4244. NdsRawDataPtr - Supplies the pointer to a buffer with the NDS raw data.
  4245. SubTreeName - Receives a pointer to the returned subtree object name
  4246. found in buffer.
  4247. ResourceScope - Receives the value of the scope for the subtree object
  4248. found in buffer.
  4249. ResourceType - Receives the value of the type for the subtree object
  4250. found in buffer.
  4251. ResourceDisplayType - Receives the value of the display type for the
  4252. subtree object found in buffer.
  4253. ResourceUsage - Receives the value of the usage for the subtree object
  4254. found in buffer.
  4255. StrippedObjectName - A pointer to receive the address of a buffer which
  4256. will contain the formatted object name. Callee must
  4257. free buffer with LocalFree().
  4258. Return Value:
  4259. A DWORD with a value that is used to represent NDS object class type..
  4260. --*/ // NwGetSubTreeData
  4261. {
  4262. PNDS_RESPONSE_SUBORDINATE_ENTRY pSubEntry =
  4263. (PNDS_RESPONSE_SUBORDINATE_ENTRY) NdsRawDataPtr;
  4264. PBYTE pbRaw;
  4265. DWORD dwStrLen;
  4266. LPWSTR ClassNameStr;
  4267. pbRaw = (BYTE *) pSubEntry;
  4268. //
  4269. // The structure of a NDS_RESPONSE_SUBORDINATE_ENTRY consists of 4 DWORDs
  4270. // followed by two standard NDS format UNICODE strings. Below we jump pbRaw
  4271. // into the buffer, past the 4 DWORDs.
  4272. //
  4273. pbRaw += sizeof( NDS_RESPONSE_SUBORDINATE_ENTRY );
  4274. //
  4275. // Now we get the length of the first string (Base Class).
  4276. //
  4277. dwStrLen = * (DWORD *) pbRaw;
  4278. //
  4279. // Now we point pbRaw to the first WCHAR of the first string (Base Class).
  4280. //
  4281. pbRaw += sizeof( DWORD_PTR );
  4282. ClassNameStr = (LPWSTR) pbRaw;
  4283. //
  4284. // Move pbRaw into the buffer, past the first UNICODE string (WORD aligned)
  4285. //
  4286. pbRaw += ROUNDUP4( dwStrLen );
  4287. //
  4288. // Now we get the length of the second string (Entry Name).
  4289. //
  4290. dwStrLen = * (DWORD *) pbRaw;
  4291. //
  4292. // Now we point pbRaw to the first WCHAR of the second string (Entry Name).
  4293. //
  4294. pbRaw += sizeof( DWORD_PTR );
  4295. *SubTreeName = (LPWSTR) pbRaw;
  4296. //
  4297. // Strip off any CN= stuff from the object name.
  4298. //
  4299. NwStripNdsUncName( *SubTreeName, StrippedObjectName );
  4300. *ResourceScope = RESOURCE_GLOBALNET;
  4301. if ( !wcscmp( ClassNameStr, CLASS_NAME_ALIAS ) )
  4302. {
  4303. *ResourceType = RESOURCETYPE_ANY;
  4304. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4305. *ResourceUsage = 0;
  4306. return CLASS_TYPE_ALIAS;
  4307. }
  4308. if ( !wcscmp( ClassNameStr, CLASS_NAME_AFP_SERVER ) )
  4309. {
  4310. *ResourceType = RESOURCETYPE_ANY;
  4311. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4312. *ResourceUsage = 0;
  4313. return CLASS_TYPE_AFP_SERVER;
  4314. }
  4315. if ( !wcscmp( ClassNameStr, CLASS_NAME_BINDERY_OBJECT ) )
  4316. {
  4317. *ResourceType = RESOURCETYPE_ANY;
  4318. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4319. *ResourceUsage = 0;
  4320. return CLASS_TYPE_BINDERY_OBJECT;
  4321. }
  4322. if ( !wcscmp( ClassNameStr, CLASS_NAME_BINDERY_QUEUE ) )
  4323. {
  4324. *ResourceType = RESOURCETYPE_ANY;
  4325. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4326. *ResourceUsage = 0;
  4327. return CLASS_TYPE_BINDERY_QUEUE;
  4328. }
  4329. if ( !wcscmp( ClassNameStr, CLASS_NAME_COMPUTER ) )
  4330. {
  4331. *ResourceType = RESOURCETYPE_ANY;
  4332. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4333. *ResourceUsage = 0;
  4334. return CLASS_TYPE_COMPUTER;
  4335. }
  4336. if ( !wcscmp( ClassNameStr, CLASS_NAME_COUNTRY ) )
  4337. {
  4338. *ResourceType = RESOURCETYPE_ANY;
  4339. *ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
  4340. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4341. return CLASS_TYPE_COUNTRY;
  4342. }
  4343. if ( !wcscmp( ClassNameStr, CLASS_NAME_DIRECTORY_MAP ) )
  4344. {
  4345. *ResourceType = RESOURCETYPE_DISK;
  4346. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4347. #ifdef NT1057
  4348. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4349. RESOURCEUSAGE_CONTAINER;
  4350. #else
  4351. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4352. RESOURCEUSAGE_NOLOCALDEVICE;
  4353. #endif
  4354. return CLASS_TYPE_DIRECTORY_MAP;
  4355. }
  4356. if ( !wcscmp( ClassNameStr, CLASS_NAME_GROUP ) )
  4357. {
  4358. *ResourceType = RESOURCETYPE_ANY;
  4359. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GROUP;
  4360. *ResourceUsage = 0;
  4361. return CLASS_TYPE_GROUP;
  4362. }
  4363. if ( !wcscmp( ClassNameStr, CLASS_NAME_LOCALITY ) )
  4364. {
  4365. *ResourceType = RESOURCETYPE_ANY;
  4366. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4367. *ResourceUsage = 0;
  4368. return CLASS_TYPE_LOCALITY;
  4369. }
  4370. if ( !wcscmp( ClassNameStr, CLASS_NAME_NCP_SERVER ) )
  4371. {
  4372. *ResourceType = RESOURCETYPE_ANY;
  4373. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  4374. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4375. return CLASS_TYPE_NCP_SERVER;
  4376. }
  4377. if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATION ) )
  4378. {
  4379. *ResourceType = RESOURCETYPE_ANY;
  4380. *ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
  4381. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4382. return CLASS_TYPE_ORGANIZATION;
  4383. }
  4384. if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATIONAL_ROLE ) )
  4385. {
  4386. *ResourceType = RESOURCETYPE_ANY;
  4387. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4388. *ResourceUsage = 0;
  4389. return CLASS_TYPE_ORGANIZATIONAL_ROLE;
  4390. }
  4391. if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATIONAL_UNIT ) )
  4392. {
  4393. *ResourceType = RESOURCETYPE_ANY;
  4394. *ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
  4395. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4396. return CLASS_TYPE_ORGANIZATIONAL_UNIT;
  4397. }
  4398. if ( !wcscmp( ClassNameStr, CLASS_NAME_PRINTER ) )
  4399. {
  4400. *ResourceType = RESOURCETYPE_PRINT;
  4401. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4402. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE;
  4403. return CLASS_TYPE_PRINTER;
  4404. }
  4405. if ( !wcscmp( ClassNameStr, CLASS_NAME_PRINT_SERVER ) )
  4406. {
  4407. *ResourceType = RESOURCETYPE_PRINT;
  4408. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  4409. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4410. return CLASS_TYPE_PRINT_SERVER;
  4411. }
  4412. if ( !wcscmp( ClassNameStr, CLASS_NAME_PROFILE ) )
  4413. {
  4414. *ResourceType = RESOURCETYPE_ANY;
  4415. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4416. *ResourceUsage = 0;
  4417. return CLASS_TYPE_PROFILE;
  4418. }
  4419. if ( !wcscmp( ClassNameStr, CLASS_NAME_QUEUE ) )
  4420. {
  4421. *ResourceType = RESOURCETYPE_PRINT;
  4422. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4423. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE;
  4424. return CLASS_TYPE_QUEUE;
  4425. }
  4426. if ( !wcscmp( ClassNameStr, CLASS_NAME_TOP ) )
  4427. {
  4428. *ResourceType = RESOURCETYPE_ANY;
  4429. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4430. *ResourceUsage = 0;
  4431. return CLASS_TYPE_TOP;
  4432. }
  4433. if ( !wcscmp( ClassNameStr, CLASS_NAME_USER ) )
  4434. {
  4435. *ResourceType = RESOURCETYPE_ANY;
  4436. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4437. *ResourceUsage = 0;
  4438. return CLASS_TYPE_USER;
  4439. }
  4440. if ( !wcscmp( ClassNameStr, CLASS_NAME_VOLUME ) )
  4441. {
  4442. *ResourceType = RESOURCETYPE_DISK;
  4443. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4444. #ifdef NT1057
  4445. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4446. RESOURCEUSAGE_CONTAINER;
  4447. #else
  4448. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4449. RESOURCEUSAGE_NOLOCALDEVICE;
  4450. #endif
  4451. return CLASS_TYPE_VOLUME;
  4452. }
  4453. //
  4454. // Otherwise if ClassNameStr is something other than Unknown, report it
  4455. //
  4456. if ( wcscmp( ClassNameStr, CLASS_NAME_UNKNOWN ) )
  4457. {
  4458. KdPrint(("NWWORKSTATION: NwGetSubTreeData failed to recognize"));
  4459. KdPrint((" ClassName: %S\n", ClassNameStr));
  4460. KdPrint((" Setting object attributes to Unknown for now . . .\n"));
  4461. }
  4462. *ResourceType = RESOURCETYPE_ANY;
  4463. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4464. *ResourceUsage = 0;
  4465. return CLASS_TYPE_UNKNOWN;
  4466. }
  4467. VOID
  4468. NwStripNdsUncName(
  4469. IN LPWSTR ObjectName,
  4470. OUT LPWSTR * StrippedObjectName
  4471. )
  4472. {
  4473. WORD slashCount;
  4474. BOOL isNdsUnc;
  4475. LPWSTR FourthSlash;
  4476. LPWSTR TreeName;
  4477. LPWSTR ObjectPath;
  4478. DWORD TreeNameLen;
  4479. DWORD ObjectPathLen;
  4480. DWORD PrefixBytes;
  4481. DWORD CurrentPathIndex;
  4482. DWORD StrippedNameLen;
  4483. DWORD StrippedNameMaxLen = MAX_NDS_NAME_CHARS;
  4484. WCHAR StrippedName[MAX_NDS_NAME_CHARS];
  4485. *StrippedObjectName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  4486. (wcslen(ObjectName) + 1) *
  4487. sizeof(WCHAR) );
  4488. if ( *StrippedObjectName == NULL )
  4489. {
  4490. return;
  4491. }
  4492. NwpGetUncInfo( ObjectName, &slashCount, &isNdsUnc, &FourthSlash );
  4493. if ( slashCount >= 2 )
  4494. {
  4495. TreeNameLen = NwParseNdsUncPath( &TreeName,
  4496. ObjectName,
  4497. PARSE_NDS_GET_TREE_NAME );
  4498. TreeNameLen /= sizeof(WCHAR);
  4499. wcscpy( *StrippedObjectName, L"\\\\" );
  4500. wcsncat( *StrippedObjectName, TreeName, TreeNameLen );
  4501. ObjectPathLen = NwParseNdsUncPath( &ObjectPath,
  4502. ObjectName,
  4503. PARSE_NDS_GET_PATH_NAME );
  4504. if ( ObjectPathLen == 0 )
  4505. {
  4506. _wcsupr( *StrippedObjectName );
  4507. return;
  4508. }
  4509. wcscat( *StrippedObjectName, L"\\" );
  4510. }
  4511. else
  4512. {
  4513. wcscpy( *StrippedObjectName, L"" );
  4514. ObjectPath = ObjectName;
  4515. ObjectPathLen = wcslen(ObjectName) * sizeof(WCHAR);
  4516. }
  4517. CurrentPathIndex = 0;
  4518. PrefixBytes = 0;
  4519. StrippedNameLen = 0;
  4520. //
  4521. // All of these indexes are in BYTES, not WCHARS!
  4522. //
  4523. while ( ( CurrentPathIndex < ObjectPathLen ) &&
  4524. ( StrippedNameLen < StrippedNameMaxLen ) )
  4525. {
  4526. if ( ObjectPath[CurrentPathIndex / sizeof( WCHAR )] == L'=' )
  4527. {
  4528. CurrentPathIndex += sizeof( WCHAR );
  4529. StrippedNameLen -= PrefixBytes;
  4530. PrefixBytes = 0;
  4531. continue;
  4532. }
  4533. StrippedName[StrippedNameLen / sizeof( WCHAR )] =
  4534. ObjectPath[CurrentPathIndex / sizeof( WCHAR )];
  4535. StrippedNameLen += sizeof( WCHAR );
  4536. CurrentPathIndex += sizeof( WCHAR );
  4537. if ( ObjectPath[CurrentPathIndex / sizeof( WCHAR )] == L'.' )
  4538. {
  4539. PrefixBytes = 0;
  4540. PrefixBytes -= sizeof( WCHAR );
  4541. }
  4542. else
  4543. {
  4544. PrefixBytes += sizeof( WCHAR );
  4545. }
  4546. }
  4547. StrippedName[StrippedNameLen / sizeof( WCHAR )] = L'\0';
  4548. wcscat( *StrippedObjectName, StrippedName );
  4549. _wcsupr( *StrippedObjectName );
  4550. }
  4551. DWORD
  4552. NwVerifyNDSObject(
  4553. IN LPWSTR lpNDSObjectNamePath,
  4554. OUT LPWSTR * lpFullNDSObjectNamePath,
  4555. OUT LPDWORD lpClassType,
  4556. OUT LPDWORD lpResourceScope,
  4557. OUT LPDWORD lpResourceType,
  4558. OUT LPDWORD lpResourceDisplayType,
  4559. OUT LPDWORD lpResourceUsage
  4560. )
  4561. {
  4562. DWORD status = NO_ERROR;
  4563. NTSTATUS ntstatus = STATUS_SUCCESS;
  4564. UNICODE_STRING TreeServerName;
  4565. UNICODE_STRING PathString;
  4566. HANDLE ConnectionHandle = NULL;
  4567. DWORD dwHandleType;
  4568. DWORD dwOid;
  4569. BOOL fImpersonate = FALSE ;
  4570. if ( lpNDSObjectNamePath == NULL )
  4571. {
  4572. //
  4573. // Handle this as if we are at the root of our provider hierarchy.
  4574. //
  4575. *lpResourceScope = RESOURCE_GLOBALNET;
  4576. *lpResourceType = RESOURCETYPE_ANY;
  4577. #ifdef NT1057
  4578. *lpResourceDisplayType = 0;
  4579. #else
  4580. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
  4581. #endif
  4582. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4583. *lpFullNDSObjectNamePath = NULL;
  4584. return NO_ERROR;
  4585. }
  4586. TreeServerName.Buffer = NULL;
  4587. PathString.Buffer = NULL;
  4588. TreeServerName.MaximumLength = ( wcslen( lpNDSObjectNamePath ) + 1 ) * sizeof( WCHAR );
  4589. PathString.MaximumLength = ( wcslen( lpNDSObjectNamePath ) + 1 ) * sizeof( WCHAR );
  4590. TreeServerName.Length = NwParseNdsUncPath( (LPWSTR *) &TreeServerName.Buffer,
  4591. lpNDSObjectNamePath,
  4592. PARSE_NDS_GET_TREE_NAME );
  4593. if ( TreeServerName.Length == 0 || TreeServerName.Buffer == NULL )
  4594. {
  4595. //
  4596. // lpNDSObjectNamePath is not in the form \\name[\blah.blah.blah][\foo][\bar]...
  4597. //
  4598. status = WN_BAD_NETNAME;
  4599. goto ErrorExit;
  4600. }
  4601. //
  4602. // Impersonate the client
  4603. //
  4604. if ( ( status = NwImpersonateClient() ) != NO_ERROR )
  4605. {
  4606. goto ErrorExit;
  4607. }
  4608. fImpersonate = TRUE;
  4609. //
  4610. // Open a connection handle to \\name
  4611. //
  4612. ntstatus = NwNdsOpenGenericHandle( &TreeServerName,
  4613. &dwHandleType,
  4614. &ConnectionHandle );
  4615. if ( ntstatus != STATUS_SUCCESS )
  4616. {
  4617. //
  4618. // The first part of lpNDSObjectNamePath was neither a NDS tree nor a NCP Server.
  4619. //
  4620. status = WN_BAD_NETNAME;
  4621. goto ErrorExit;
  4622. }
  4623. if ( dwHandleType != HANDLE_TYPE_NDS_TREE )
  4624. {
  4625. //
  4626. // The first part of lpNDSObjectNamePath was not a NDS tree.
  4627. //
  4628. status = VERIFY_ERROR_NOT_A_NDS_TREE;
  4629. goto ErrorExit;
  4630. }
  4631. //
  4632. // Adjust TreeServerName.Length to number of characters.
  4633. //
  4634. TreeServerName.Length /= sizeof(WCHAR);
  4635. //
  4636. // The lpNDSObjectNamePath points to a NDS tree. Now verify that the path is valid.
  4637. //
  4638. PathString.Length = NwParseNdsUncPath( (LPWSTR *) &PathString.Buffer,
  4639. lpNDSObjectNamePath,
  4640. PARSE_NDS_GET_PATH_NAME );
  4641. if ( PathString.Length == 0 )
  4642. {
  4643. LPWSTR treeNameStr = NULL;
  4644. if ( fImpersonate )
  4645. (void) NwRevertToSelf() ;
  4646. if ( ConnectionHandle )
  4647. CloseHandle( ConnectionHandle );
  4648. *lpResourceScope = RESOURCE_GLOBALNET;
  4649. *lpResourceType = RESOURCETYPE_ANY;
  4650. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_TREE;
  4651. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4652. //
  4653. // Need to build a string with the new NDS UNC path for subtree object
  4654. //
  4655. treeNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4656. ( TreeServerName.Length + 3 ) * sizeof(WCHAR) );
  4657. if ( treeNameStr == NULL )
  4658. {
  4659. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4660. GetLastError()));
  4661. status = ERROR_NOT_ENOUGH_MEMORY;
  4662. goto ErrorExit;
  4663. }
  4664. wcscpy( treeNameStr, L"\\\\" );
  4665. wcsncat( treeNameStr, TreeServerName.Buffer, TreeServerName.Length );
  4666. _wcsupr( treeNameStr );
  4667. *lpFullNDSObjectNamePath = treeNameStr;
  4668. return NO_ERROR;
  4669. }
  4670. else
  4671. {
  4672. WCHAR lpServerName[NW_MAX_SERVER_LEN];
  4673. UNICODE_STRING ServerName;
  4674. ServerName.Length = 0;
  4675. ServerName.MaximumLength = sizeof( lpServerName );
  4676. ServerName.Buffer = lpServerName;
  4677. //
  4678. // Resolve the path to get a NDS object id.
  4679. //
  4680. ntstatus = NwNdsResolveName( ConnectionHandle,
  4681. &PathString,
  4682. &dwOid,
  4683. &ServerName,
  4684. NULL,
  4685. 0 );
  4686. if ( ntstatus == STATUS_SUCCESS && ServerName.Length )
  4687. {
  4688. DWORD dwHandleType;
  4689. //
  4690. // NwNdsResolveName succeeded, but we were referred to
  4691. // another server, though ContextHandle->dwOid is still valid.
  4692. if ( ConnectionHandle )
  4693. CloseHandle( ConnectionHandle );
  4694. ConnectionHandle = NULL;
  4695. //
  4696. // Open a NDS generic connection handle to \\ServerName
  4697. //
  4698. ntstatus = NwNdsOpenGenericHandle( &ServerName,
  4699. &dwHandleType,
  4700. &ConnectionHandle );
  4701. if ( ntstatus != STATUS_SUCCESS )
  4702. {
  4703. status = RtlNtStatusToDosError(ntstatus);
  4704. goto ErrorExit;
  4705. }
  4706. ASSERT( dwHandleType != HANDLE_TYPE_NCP_SERVER );
  4707. }
  4708. }
  4709. if ( ntstatus != STATUS_SUCCESS )
  4710. {
  4711. LPWSTR treeNameStr = NULL;
  4712. *lpResourceScope = RESOURCE_GLOBALNET;
  4713. *lpResourceType = RESOURCETYPE_ANY;
  4714. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_TREE;
  4715. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4716. //
  4717. // Need to build a string with the new NDS UNC path for subtree object
  4718. //
  4719. treeNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4720. ( TreeServerName.Length + 3 ) * sizeof(WCHAR) );
  4721. if ( treeNameStr == NULL )
  4722. {
  4723. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4724. GetLastError()));
  4725. status = ERROR_NOT_ENOUGH_MEMORY;
  4726. goto ErrorExit;
  4727. }
  4728. wcscpy( treeNameStr, L"\\\\" );
  4729. wcsncat( treeNameStr, TreeServerName.Buffer, TreeServerName.Length );
  4730. _wcsupr( treeNameStr );
  4731. *lpFullNDSObjectNamePath = treeNameStr;
  4732. status = VERIFY_ERROR_PATH_NOT_FOUND;
  4733. goto ErrorExit;
  4734. }
  4735. //
  4736. // Check to see what kind of object is pointed to by lpRemoteName.
  4737. //
  4738. {
  4739. BYTE RawResponse[TWO_KB];
  4740. PBYTE pbRawGetInfo;
  4741. DWORD RawResponseSize = sizeof(RawResponse);
  4742. DWORD dwStrLen;
  4743. LPWSTR TreeObjectName;
  4744. LPWSTR StrippedObjectName = NULL;
  4745. LPWSTR newPathStr = NULL;
  4746. ntstatus = NwNdsReadObjectInfo( ConnectionHandle,
  4747. dwOid,
  4748. RawResponse,
  4749. RawResponseSize );
  4750. if ( ntstatus != NO_ERROR )
  4751. {
  4752. status = RtlNtStatusToDosError(ntstatus);
  4753. goto ErrorExit;
  4754. }
  4755. //
  4756. // Get current subtree data from ContextHandle
  4757. //
  4758. *lpClassType = NwGetSubTreeData( (DWORD_PTR) RawResponse,
  4759. &TreeObjectName,
  4760. lpResourceScope,
  4761. lpResourceType,
  4762. lpResourceDisplayType,
  4763. lpResourceUsage,
  4764. &StrippedObjectName );
  4765. if ( StrippedObjectName == NULL )
  4766. {
  4767. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4768. GetLastError()));
  4769. status = ERROR_NOT_ENOUGH_MEMORY;
  4770. goto ErrorExit;
  4771. }
  4772. //
  4773. // Need to build a string with the new NDS UNC path for subtree object
  4774. //
  4775. newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4776. ( wcslen( StrippedObjectName ) +
  4777. TreeServerName.Length + 4 )
  4778. * sizeof(WCHAR) );
  4779. if ( newPathStr == NULL )
  4780. {
  4781. (void) LocalFree((HLOCAL) StrippedObjectName);
  4782. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4783. GetLastError()));
  4784. status = ERROR_NOT_ENOUGH_MEMORY;
  4785. goto ErrorExit;
  4786. }
  4787. wcscpy( newPathStr, L"\\\\" );
  4788. wcsncat( newPathStr, TreeServerName.Buffer, TreeServerName.Length );
  4789. wcscat( newPathStr, L"\\" );
  4790. wcscat( newPathStr, StrippedObjectName );
  4791. _wcsupr( newPathStr );
  4792. //
  4793. // Don't need the StrippedObjectName string anymore
  4794. //
  4795. (void) LocalFree((HLOCAL) StrippedObjectName);
  4796. StrippedObjectName = NULL;
  4797. *lpFullNDSObjectNamePath = newPathStr;
  4798. status = NO_ERROR;
  4799. } // End of Block
  4800. ErrorExit:
  4801. if ( fImpersonate )
  4802. (void) NwRevertToSelf() ;
  4803. if ( ConnectionHandle )
  4804. CloseHandle( ConnectionHandle );
  4805. return status;
  4806. }
  4807. DWORD
  4808. NwVerifyBinderyObject(
  4809. IN LPWSTR lpBinderyObjectPathName,
  4810. OUT LPWSTR * lpFullBinderyObjectPathName,
  4811. OUT LPDWORD lpClassType,
  4812. OUT LPDWORD lpResourceScope,
  4813. OUT LPDWORD lpResourceType,
  4814. OUT LPDWORD lpResourceDisplayType,
  4815. OUT LPDWORD lpResourceUsage
  4816. )
  4817. {
  4818. DWORD status = NO_ERROR;
  4819. HANDLE ConnectionHandle = NULL;
  4820. BOOL fImpersonate = FALSE ;
  4821. BOOL fResourceTypeDisk = FALSE ;
  4822. BOOL fIsNdsUnc = FALSE ;
  4823. UNICODE_STRING BinderyConnectStr;
  4824. ULONG CreateDisposition = 0;
  4825. ULONG CreateOptions = 0;
  4826. WORD wSlashCount;
  4827. LPWSTR FourthSlash;
  4828. if ( lpBinderyObjectPathName == NULL )
  4829. {
  4830. //
  4831. // Handle this as if we are at the root of our provider hierarchy.
  4832. //
  4833. *lpResourceScope = RESOURCE_GLOBALNET;
  4834. *lpResourceType = RESOURCETYPE_ANY;
  4835. #ifdef NT1057
  4836. *lpResourceDisplayType = 0;
  4837. #else
  4838. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
  4839. #endif
  4840. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4841. *lpFullBinderyObjectPathName = NULL;
  4842. return NO_ERROR;
  4843. }
  4844. //
  4845. // Open a connection handle to \\server\vol\...
  4846. //
  4847. BinderyConnectStr.Buffer = NULL;
  4848. //
  4849. // Find out if we are looking at a \\server, \\server\vol, or
  4850. // \\server\vol\dir . . .
  4851. //
  4852. NwpGetUncInfo( lpBinderyObjectPathName,
  4853. &wSlashCount,
  4854. &fIsNdsUnc,
  4855. &FourthSlash );
  4856. if ( wSlashCount > 2 )
  4857. fResourceTypeDisk = TRUE;
  4858. //
  4859. // Impersonate the client
  4860. //
  4861. if ( ( status = NwImpersonateClient() ) != NO_ERROR )
  4862. {
  4863. goto ErrorExit;
  4864. }
  4865. fImpersonate = TRUE;
  4866. //
  4867. // Open a tree connection handle to \Device\NwRdr\ContainerName
  4868. //
  4869. status = NwCreateTreeConnectName( lpBinderyObjectPathName,
  4870. NULL,
  4871. &BinderyConnectStr );
  4872. if ( status != NO_ERROR )
  4873. {
  4874. status = WN_BAD_NETNAME;
  4875. goto ErrorExit;
  4876. }
  4877. CreateDisposition = FILE_OPEN;
  4878. CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
  4879. status = NwOpenCreateConnection( &BinderyConnectStr,
  4880. NULL,
  4881. NULL,
  4882. lpBinderyObjectPathName,
  4883. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  4884. CreateDisposition,
  4885. CreateOptions,
  4886. RESOURCETYPE_DISK, // When connecting beyond servername
  4887. &ConnectionHandle,
  4888. NULL );
  4889. if ( status == NO_ERROR )
  4890. {
  4891. LPWSTR BinderyNameStr = NULL;
  4892. //
  4893. // Need to build a string with the new UNC path for bindery object
  4894. //
  4895. BinderyNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4896. ( wcslen( lpBinderyObjectPathName ) + 1 )
  4897. * sizeof(WCHAR) );
  4898. if ( BinderyNameStr == NULL )
  4899. {
  4900. KdPrint(("NWWORKSTATION: NwVerifyBinderyObject LocalAlloc Failed %lu\n",
  4901. GetLastError()));
  4902. status = ERROR_NOT_ENOUGH_MEMORY;
  4903. goto ErrorExit;
  4904. }
  4905. wcscpy( BinderyNameStr, lpBinderyObjectPathName );
  4906. _wcsupr( BinderyNameStr );
  4907. *lpFullBinderyObjectPathName = BinderyNameStr;
  4908. if ( BinderyConnectStr.Buffer )
  4909. (void) LocalFree((HLOCAL) BinderyConnectStr.Buffer);
  4910. if ( fImpersonate )
  4911. (void) NwRevertToSelf() ;
  4912. if ( ConnectionHandle )
  4913. {
  4914. *lpResourceScope = RESOURCE_GLOBALNET;
  4915. *lpResourceType = fResourceTypeDisk ?
  4916. RESOURCETYPE_DISK :
  4917. RESOURCETYPE_ANY;
  4918. *lpResourceDisplayType = fResourceTypeDisk ?
  4919. RESOURCEDISPLAYTYPE_SHARE :
  4920. RESOURCEDISPLAYTYPE_SERVER;
  4921. #ifdef NT1057
  4922. *lpResourceUsage = fResourceTypeDisk ?
  4923. RESOURCEUSAGE_CONNECTABLE |
  4924. RESOURCEUSAGE_CONTAINER :
  4925. RESOURCEUSAGE_CONTAINER;
  4926. #else
  4927. *lpResourceUsage = fResourceTypeDisk ?
  4928. RESOURCEUSAGE_CONNECTABLE |
  4929. RESOURCEUSAGE_NOLOCALDEVICE :
  4930. RESOURCEUSAGE_CONTAINER;
  4931. #endif
  4932. CloseHandle( ConnectionHandle );
  4933. }
  4934. return NO_ERROR;
  4935. }
  4936. ErrorExit:
  4937. *lpFullBinderyObjectPathName = NULL;
  4938. if ( BinderyConnectStr.Buffer )
  4939. (void) LocalFree((HLOCAL) BinderyConnectStr.Buffer);
  4940. if ( fImpersonate )
  4941. (void) NwRevertToSelf() ;
  4942. if ( ConnectionHandle )
  4943. CloseHandle( ConnectionHandle );
  4944. return WN_BAD_NETNAME;
  4945. }
  4946. DWORD
  4947. NwGetNDSPathInfo(
  4948. IN LPWSTR lpNDSObjectNamePath,
  4949. OUT LPWSTR * lppSystemObjectNamePath,
  4950. OUT LPWSTR * lpSystemPathPart,
  4951. OUT LPDWORD lpClassType,
  4952. OUT LPDWORD lpResourceScope,
  4953. OUT LPDWORD lpResourceType,
  4954. OUT LPDWORD lpResourceDisplayType,
  4955. OUT LPDWORD lpResourceUsage
  4956. )
  4957. {
  4958. DWORD status = NO_ERROR;
  4959. WORD slashCount;
  4960. BOOL isNdsUnc;
  4961. BOOL fReturnBadNetName = FALSE;
  4962. LPWSTR FourthSlash;
  4963. LPWSTR lpSystemPath = NULL;
  4964. *lpSystemPathPart = NULL;
  4965. NwpGetUncInfo( lpNDSObjectNamePath,
  4966. &slashCount,
  4967. &isNdsUnc,
  4968. &FourthSlash );
  4969. if ( slashCount <= 3 )
  4970. {
  4971. //
  4972. // Path is to a possible NDS object, check to see if so and if valid...
  4973. //
  4974. status = NwVerifyNDSObject( lpNDSObjectNamePath,
  4975. lppSystemObjectNamePath,
  4976. lpClassType,
  4977. lpResourceScope,
  4978. lpResourceType,
  4979. lpResourceDisplayType,
  4980. lpResourceUsage );
  4981. *lpSystemPathPart = NULL;
  4982. return status;
  4983. }
  4984. else
  4985. {
  4986. //
  4987. // Path is to a directory, see if directory exists . . .
  4988. //
  4989. status = NwVerifyBinderyObject( lpNDSObjectNamePath,
  4990. lppSystemObjectNamePath,
  4991. lpClassType,
  4992. lpResourceScope,
  4993. lpResourceType,
  4994. lpResourceDisplayType,
  4995. lpResourceUsage );
  4996. }
  4997. if ( status == WN_BAD_NETNAME )
  4998. {
  4999. fReturnBadNetName = TRUE;
  5000. status = NO_ERROR;
  5001. }
  5002. if ( status == NO_ERROR )
  5003. {
  5004. WCHAR TempNDSObjectNamePath[256];
  5005. //
  5006. // Test \\tree\obj.obj... component and
  5007. // return network resource for valid parent and the string,
  5008. // lpSystemPathPart, for the directory part ( \dir1\...).
  5009. //
  5010. if ( *lppSystemObjectNamePath != NULL )
  5011. {
  5012. (void) LocalFree( (HLOCAL) (*lppSystemObjectNamePath) );
  5013. *lppSystemObjectNamePath = NULL;
  5014. }
  5015. lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  5016. ( wcslen( FourthSlash ) + 1 ) *
  5017. sizeof( WCHAR ) );
  5018. if ( lpSystemPath == NULL )
  5019. {
  5020. return ERROR_NOT_ENOUGH_MEMORY;
  5021. }
  5022. wcscpy( lpSystemPath, FourthSlash );
  5023. *FourthSlash = L'\0';
  5024. wcscpy( TempNDSObjectNamePath, lpNDSObjectNamePath );
  5025. *FourthSlash = L'\\';
  5026. //
  5027. // See if \\tree\obj.obj.... exists . . .
  5028. //
  5029. status = NwVerifyNDSObject( TempNDSObjectNamePath,
  5030. lppSystemObjectNamePath,
  5031. lpClassType,
  5032. lpResourceScope,
  5033. lpResourceType,
  5034. lpResourceDisplayType,
  5035. lpResourceUsage );
  5036. if ( status != NO_ERROR )
  5037. {
  5038. LocalFree( lpSystemPath );
  5039. lpSystemPath = NULL;
  5040. }
  5041. }
  5042. *lpSystemPathPart = lpSystemPath;
  5043. //
  5044. // The provider spec for this function used to tell us to create a
  5045. // NETRESOURCE, even if the system part of the path was invalid, while
  5046. // returning WN_BAD_NETNAME. Now we return SUCCESS and the NETRESOURCE,
  5047. // irregardless of whether the lpSystem part is valid.
  5048. // if ( fReturnBadNetName == TRUE )
  5049. // {
  5050. // return WN_BAD_NETNAME;
  5051. // }
  5052. return status;
  5053. }
  5054. DWORD
  5055. NwGetBinderyPathInfo(
  5056. IN LPWSTR lpBinderyObjectNamePath,
  5057. OUT LPWSTR * lppSystemObjectNamePath,
  5058. OUT LPWSTR * lpSystemPathPart,
  5059. OUT LPDWORD lpClassType,
  5060. OUT LPDWORD lpResourceScope,
  5061. OUT LPDWORD lpResourceType,
  5062. OUT LPDWORD lpResourceDisplayType,
  5063. OUT LPDWORD lpResourceUsage
  5064. )
  5065. {
  5066. DWORD status = NO_ERROR;
  5067. WORD slashCount;
  5068. BOOL isNdsUnc;
  5069. LPWSTR FourthSlash;
  5070. LPWSTR lpSystemPath = NULL;
  5071. *lpSystemPathPart = NULL;
  5072. NwpGetUncInfo( lpBinderyObjectNamePath,
  5073. &slashCount,
  5074. &isNdsUnc,
  5075. &FourthSlash );
  5076. if ( slashCount <= 3 )
  5077. {
  5078. //
  5079. // Path is to a server or volume, check to see which and if valid . . .
  5080. //
  5081. status = NwVerifyBinderyObject( lpBinderyObjectNamePath,
  5082. lppSystemObjectNamePath,
  5083. lpClassType,
  5084. lpResourceScope,
  5085. lpResourceType,
  5086. lpResourceDisplayType,
  5087. lpResourceUsage );
  5088. *lpSystemPathPart = NULL;
  5089. return status;
  5090. }
  5091. else
  5092. {
  5093. //
  5094. // Path is to a directory, see if directory exists . . .
  5095. //
  5096. status = NwVerifyBinderyObject( lpBinderyObjectNamePath,
  5097. lppSystemObjectNamePath,
  5098. lpClassType,
  5099. lpResourceScope,
  5100. lpResourceType,
  5101. lpResourceDisplayType,
  5102. lpResourceUsage );
  5103. }
  5104. if ( status == WN_BAD_NETNAME )
  5105. {
  5106. WCHAR TempBinderyObjectNamePath[256];
  5107. //
  5108. // Path is to a invalid directory. Test \\server\volume component and
  5109. // return network resource for valid parent and the string,
  5110. // lpSystemPathPart, for the directory part ( \dir1\...).
  5111. //
  5112. lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  5113. ( wcslen( FourthSlash ) + 1 ) *
  5114. sizeof( WCHAR ) );
  5115. if ( lpSystemPath == NULL )
  5116. {
  5117. return ERROR_NOT_ENOUGH_MEMORY;
  5118. }
  5119. wcscpy( lpSystemPath, FourthSlash );
  5120. *FourthSlash = L'\0';
  5121. wcscpy( TempBinderyObjectNamePath, lpBinderyObjectNamePath );
  5122. *FourthSlash = L'\\';
  5123. //
  5124. // See if \\server\volume exists . . .
  5125. //
  5126. status = NwVerifyBinderyObject( TempBinderyObjectNamePath,
  5127. lppSystemObjectNamePath,
  5128. lpClassType,
  5129. lpResourceScope,
  5130. lpResourceType,
  5131. lpResourceDisplayType,
  5132. lpResourceUsage );
  5133. if ( status != NO_ERROR )
  5134. {
  5135. LocalFree( lpSystemPath );
  5136. lpSystemPath = NULL;
  5137. }
  5138. //
  5139. // Return SUCCESS, since the NETRESOURCE for \\server\volume that
  5140. // we are describing is at least valid, even though the lpSystem
  5141. // part in not. This is a change in the provider spec (4/25/96).
  5142. //
  5143. // else
  5144. // {
  5145. // status = WN_BAD_NETNAME;
  5146. // }
  5147. }
  5148. else
  5149. {
  5150. //
  5151. // Path is to a valid directory. Return resource information for the
  5152. // \\server\volume component and the string, lpSystemPathPart, for the
  5153. // directory part ( \dir1\...).
  5154. //
  5155. NwpGetUncInfo( *lppSystemObjectNamePath,
  5156. &slashCount,
  5157. &isNdsUnc,
  5158. &FourthSlash );
  5159. lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  5160. ( wcslen( FourthSlash ) + 1 ) *
  5161. sizeof( WCHAR ) );
  5162. if ( lpSystemPath == NULL )
  5163. {
  5164. return ERROR_NOT_ENOUGH_MEMORY;
  5165. }
  5166. wcscpy( lpSystemPath, FourthSlash );
  5167. *FourthSlash = L'\0';
  5168. *lpResourceScope = RESOURCE_GLOBALNET;
  5169. *lpResourceType = RESOURCETYPE_DISK;
  5170. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  5171. #ifdef NT1057
  5172. *lpResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  5173. RESOURCEUSAGE_CONTAINER;
  5174. #else
  5175. *lpResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  5176. RESOURCEUSAGE_NOLOCALDEVICE;
  5177. #endif
  5178. status = NO_ERROR;
  5179. }
  5180. *lpSystemPathPart = lpSystemPath;
  5181. return status;
  5182. }
  5183. BOOL
  5184. NwGetRemoteNameParent(
  5185. IN LPWSTR lpRemoteName,
  5186. OUT LPWSTR * lpRemoteNameParent
  5187. )
  5188. {
  5189. unsigned short iter = 0;
  5190. unsigned short totalLength = (USHORT) wcslen( lpRemoteName );
  5191. unsigned short slashCount = 0;
  5192. unsigned short dotCount = 0;
  5193. unsigned short thirdSlash = 0;
  5194. unsigned short lastSlash = 0;
  5195. unsigned short parentNDSSubTree = 0;
  5196. LPWSTR newRemoteNameParent = NULL;
  5197. if ( totalLength < 2 )
  5198. return FALSE;
  5199. //
  5200. // Get thirdSlash to indicate the character in the string that indicates the
  5201. // "\" in between the tree name and the rest of the UNC path. Set parentNDSSubTree
  5202. // if available. And always set lastSlash to the most recent "\" seen as you walk.
  5203. //
  5204. // Example: \\<tree name>\path.to.object[\|.]<object>
  5205. // ^ ^
  5206. // | |
  5207. // thirdSlash parentNDSSubTree
  5208. //
  5209. while ( iter < totalLength )
  5210. {
  5211. if ( lpRemoteName[iter] == L'\\' )
  5212. {
  5213. slashCount += 1;
  5214. if ( slashCount == 3 )
  5215. thirdSlash = iter;
  5216. lastSlash = iter;
  5217. }
  5218. if ( lpRemoteName[iter] == L'.' )
  5219. {
  5220. dotCount += 1;
  5221. if ( dotCount == 1 )
  5222. parentNDSSubTree = iter;
  5223. }
  5224. iter++;
  5225. }
  5226. if ( slashCount > 3 )
  5227. {
  5228. newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  5229. ( lastSlash + 1 ) *
  5230. sizeof(WCHAR));
  5231. if ( newRemoteNameParent == NULL )
  5232. {
  5233. KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
  5234. GetLastError()));
  5235. return FALSE;
  5236. }
  5237. wcsncpy( newRemoteNameParent, lpRemoteName, lastSlash );
  5238. _wcsupr( newRemoteNameParent );
  5239. *lpRemoteNameParent = newRemoteNameParent;
  5240. return TRUE;
  5241. }
  5242. if ( slashCount == 3 )
  5243. {
  5244. if ( dotCount == 0 )
  5245. {
  5246. newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  5247. ( lastSlash + 1 ) *
  5248. sizeof(WCHAR));
  5249. if ( newRemoteNameParent == NULL )
  5250. {
  5251. KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
  5252. GetLastError()));
  5253. return FALSE;
  5254. }
  5255. wcsncpy( newRemoteNameParent, lpRemoteName, lastSlash );
  5256. _wcsupr( newRemoteNameParent );
  5257. *lpRemoteNameParent = newRemoteNameParent;
  5258. return TRUE;
  5259. }
  5260. else
  5261. {
  5262. newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  5263. ( totalLength -
  5264. ( parentNDSSubTree - thirdSlash )
  5265. + 1 )
  5266. * sizeof(WCHAR) );
  5267. if ( newRemoteNameParent == NULL )
  5268. {
  5269. KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
  5270. GetLastError()));
  5271. return FALSE;
  5272. }
  5273. wcsncpy( newRemoteNameParent, lpRemoteName, thirdSlash + 1 );
  5274. wcscat( newRemoteNameParent, &lpRemoteName[parentNDSSubTree+1] );
  5275. _wcsupr( newRemoteNameParent );
  5276. *lpRemoteNameParent = newRemoteNameParent;
  5277. return TRUE;
  5278. }
  5279. }
  5280. // Else we set lpRemoteNameParent to NULL, to indicate that we are at the top and
  5281. // return TRUE.
  5282. *lpRemoteNameParent = NULL;
  5283. return TRUE;
  5284. }
  5285. DWORD
  5286. NwGetFirstDirectoryEntry(
  5287. IN HANDLE DirHandle,
  5288. OUT LPWSTR *DirEntry
  5289. )
  5290. /*++
  5291. Routine Description:
  5292. This function is called by NwEnumDirectories to get the first
  5293. directory entry given a handle to the directory. It allocates
  5294. the output buffer to hold the returned directory name; the
  5295. caller should free this output buffer with LocalFree when done.
  5296. Arguments:
  5297. DirHandle - Supplies the opened handle to the container
  5298. directory find a directory within it.
  5299. DirEntry - Receives a pointer to the returned directory
  5300. found.
  5301. Return Value:
  5302. NO_ERROR - The operation was successful.
  5303. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  5304. buffer.
  5305. Other errors from NtQueryDirectoryFile.
  5306. --*/ // NwGetFirstDirectoryEntry
  5307. {
  5308. DWORD status = NO_ERROR;
  5309. NTSTATUS ntstatus = STATUS_SUCCESS;
  5310. IO_STATUS_BLOCK IoStatusBlock;
  5311. PFILE_DIRECTORY_INFORMATION DirInfo;
  5312. UNICODE_STRING StartFileName;
  5313. #if DBG
  5314. DWORD i = 0;
  5315. #endif
  5316. //
  5317. // Allocate a large buffer to get one directory information entry.
  5318. //
  5319. DirInfo = (PVOID) LocalAlloc(
  5320. LMEM_ZEROINIT,
  5321. sizeof(FILE_DIRECTORY_INFORMATION) +
  5322. (MAX_PATH * sizeof(WCHAR))
  5323. );
  5324. if (DirInfo == NULL) {
  5325. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry LocalAlloc Failed %lu\n",
  5326. GetLastError()));
  5327. return ERROR_NOT_ENOUGH_MEMORY;
  5328. }
  5329. RtlInitUnicodeString(&StartFileName, L"*");
  5330. ntstatus = NtQueryDirectoryFile(
  5331. DirHandle,
  5332. NULL,
  5333. NULL,
  5334. NULL,
  5335. &IoStatusBlock,
  5336. DirInfo,
  5337. sizeof(FILE_DIRECTORY_INFORMATION) +
  5338. (MAX_PATH * sizeof(WCHAR)),
  5339. FileDirectoryInformation, // Info class requested
  5340. TRUE, // Return single entry
  5341. &StartFileName, // Redirector needs this
  5342. TRUE // Restart scan
  5343. );
  5344. //
  5345. // For now, if buffer to NtQueryDirectoryFile is too small, just give
  5346. // up. We may want to try to reallocate a bigger buffer at a later time.
  5347. //
  5348. if (ntstatus == STATUS_SUCCESS) {
  5349. ntstatus = IoStatusBlock.Status;
  5350. }
  5351. if (ntstatus != STATUS_SUCCESS) {
  5352. if (ntstatus == STATUS_NO_MORE_FILES) {
  5353. //
  5354. // We ran out of entries.
  5355. //
  5356. status = WN_NO_MORE_ENTRIES;
  5357. }
  5358. else {
  5359. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
  5360. ntstatus));
  5361. status = RtlNtStatusToDosError(ntstatus);
  5362. }
  5363. goto CleanExit;
  5364. }
  5365. #if DBG
  5366. IF_DEBUG(ENUM) {
  5367. KdPrint(("GetFirst(%u) got %ws, attributes %08lx\n", ++i,
  5368. DirInfo->FileName, DirInfo->FileAttributes));
  5369. }
  5370. #endif
  5371. //
  5372. // Scan until we find the first directory entry that is not "." or ".."
  5373. //
  5374. while (!(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
  5375. memcmp(DirInfo->FileName, L".", DirInfo->FileNameLength) == 0 ||
  5376. memcmp(DirInfo->FileName, L"..", DirInfo->FileNameLength) == 0) {
  5377. ntstatus = NtQueryDirectoryFile(
  5378. DirHandle,
  5379. NULL,
  5380. NULL,
  5381. NULL,
  5382. &IoStatusBlock,
  5383. DirInfo,
  5384. sizeof(FILE_DIRECTORY_INFORMATION) +
  5385. (MAX_PATH * sizeof(WCHAR)),
  5386. FileDirectoryInformation, // Info class requested
  5387. TRUE, // Return single entry
  5388. NULL,
  5389. FALSE // Restart scan
  5390. );
  5391. if (ntstatus == STATUS_SUCCESS) {
  5392. ntstatus = IoStatusBlock.Status;
  5393. }
  5394. if (ntstatus != STATUS_SUCCESS) {
  5395. if (ntstatus == STATUS_NO_MORE_FILES) {
  5396. //
  5397. // We ran out of entries.
  5398. //
  5399. status = WN_NO_MORE_ENTRIES;
  5400. }
  5401. else {
  5402. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
  5403. ntstatus));
  5404. status = RtlNtStatusToDosError(ntstatus);
  5405. }
  5406. goto CleanExit;
  5407. }
  5408. #if DBG
  5409. IF_DEBUG(ENUM) {
  5410. KdPrint(("GetFirst(%u) got %ws, attributes %08lx\n", ++i,
  5411. DirInfo->FileName, DirInfo->FileAttributes));
  5412. }
  5413. #endif
  5414. }
  5415. //
  5416. // Allocate the output buffer for the returned directory name
  5417. //
  5418. *DirEntry = (PVOID) LocalAlloc(
  5419. LMEM_ZEROINIT,
  5420. DirInfo->FileNameLength + sizeof(WCHAR)
  5421. );
  5422. if (*DirEntry == NULL) {
  5423. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry LocalAlloc Failed %lu\n",
  5424. GetLastError()));
  5425. status = ERROR_NOT_ENOUGH_MEMORY;
  5426. goto CleanExit;
  5427. }
  5428. memcpy(*DirEntry, DirInfo->FileName, DirInfo->FileNameLength);
  5429. #if DBG
  5430. IF_DEBUG(ENUM) {
  5431. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry returns %ws\n",
  5432. *DirEntry));
  5433. }
  5434. #endif
  5435. status = NO_ERROR;
  5436. CleanExit:
  5437. (void) LocalFree((HLOCAL) DirInfo);
  5438. //
  5439. // We could not find any directories under the requested
  5440. // so we need to treat this as no entries.
  5441. //
  5442. if ( status == ERROR_FILE_NOT_FOUND )
  5443. status = WN_NO_MORE_ENTRIES;
  5444. return status;
  5445. }
  5446. DWORD
  5447. NwGetNextDirectoryEntry(
  5448. IN HANDLE DirHandle,
  5449. OUT LPWSTR *DirEntry
  5450. )
  5451. /*++
  5452. Routine Description:
  5453. This function is called by NwEnumDirectories to get the next
  5454. directory entry given a handle to the directory. It allocates
  5455. the output buffer to hold the returned directory name; the
  5456. caller should free this output buffer with LocalFree when done.
  5457. Arguments:
  5458. DirHandle - Supplies the opened handle to the container
  5459. directory find a directory within it.
  5460. DirEntry - Receives a pointer to the returned directory
  5461. found.
  5462. Return Value:
  5463. NO_ERROR - The operation was successful.
  5464. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  5465. buffer.
  5466. Other errors from NtQueryDirectoryFile.
  5467. --*/ // NwGetNextDirectoryEntry
  5468. {
  5469. DWORD status = NO_ERROR;
  5470. NTSTATUS ntstatus = STATUS_SUCCESS;
  5471. IO_STATUS_BLOCK IoStatusBlock;
  5472. PFILE_DIRECTORY_INFORMATION DirInfo;
  5473. //
  5474. // Allocate a large buffer to get one directory information entry.
  5475. //
  5476. DirInfo = (PVOID) LocalAlloc(
  5477. LMEM_ZEROINIT,
  5478. sizeof(FILE_DIRECTORY_INFORMATION) +
  5479. (MAX_PATH * sizeof(WCHAR))
  5480. );
  5481. if (DirInfo == NULL) {
  5482. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry LocalAlloc Failed %lu\n",
  5483. GetLastError()));
  5484. return ERROR_NOT_ENOUGH_MEMORY;
  5485. }
  5486. do {
  5487. ntstatus = NtQueryDirectoryFile(
  5488. DirHandle,
  5489. NULL,
  5490. NULL,
  5491. NULL,
  5492. &IoStatusBlock,
  5493. DirInfo,
  5494. sizeof(FILE_DIRECTORY_INFORMATION) +
  5495. (MAX_PATH * sizeof(WCHAR)),
  5496. FileDirectoryInformation, // Info class requested
  5497. TRUE, // Return single entry
  5498. NULL,
  5499. FALSE // Restart scan
  5500. );
  5501. if (ntstatus == STATUS_SUCCESS) {
  5502. ntstatus = IoStatusBlock.Status;
  5503. }
  5504. } while (ntstatus == STATUS_SUCCESS &&
  5505. !(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY));
  5506. if (ntstatus != STATUS_SUCCESS) {
  5507. if (ntstatus == STATUS_NO_MORE_FILES) {
  5508. //
  5509. // We ran out of entries.
  5510. //
  5511. status = WN_NO_MORE_ENTRIES;
  5512. }
  5513. else {
  5514. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
  5515. ntstatus));
  5516. status = RtlNtStatusToDosError(ntstatus);
  5517. }
  5518. goto CleanExit;
  5519. }
  5520. //
  5521. // Allocate the output buffer for the returned directory name
  5522. //
  5523. *DirEntry = (PVOID) LocalAlloc(
  5524. LMEM_ZEROINIT,
  5525. DirInfo->FileNameLength + sizeof(WCHAR)
  5526. );
  5527. if (*DirEntry == NULL) {
  5528. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry LocalAlloc Failed %lu\n",
  5529. GetLastError()));
  5530. status = ERROR_NOT_ENOUGH_MEMORY;
  5531. goto CleanExit;
  5532. }
  5533. memcpy(*DirEntry, DirInfo->FileName, DirInfo->FileNameLength);
  5534. #if DBG
  5535. IF_DEBUG(ENUM) {
  5536. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry returns %ws\n",
  5537. *DirEntry));
  5538. }
  5539. #endif
  5540. status = NO_ERROR;
  5541. CleanExit:
  5542. (void) LocalFree((HLOCAL) DirInfo);
  5543. return status;
  5544. }
  5545. DWORD
  5546. NwWriteNetResourceEntry(
  5547. IN OUT LPBYTE * FixedPortion,
  5548. IN OUT LPWSTR * EndOfVariableData,
  5549. IN LPWSTR ContainerName OPTIONAL,
  5550. IN LPWSTR LocalName OPTIONAL,
  5551. IN LPWSTR RemoteName,
  5552. IN DWORD ScopeFlag,
  5553. IN DWORD DisplayFlag,
  5554. IN DWORD UsageFlag,
  5555. IN DWORD ResourceType,
  5556. IN LPWSTR SystemPath OPTIONAL,
  5557. OUT LPWSTR * lppSystem OPTIONAL,
  5558. OUT LPDWORD EntrySize
  5559. )
  5560. /*++
  5561. Routine Description:
  5562. This function packages a NETRESOURCE entry into the user output buffer.
  5563. It is called by the various enum resource routines.
  5564. Arguments:
  5565. FixedPortion - Supplies a pointer to the output buffer where the next
  5566. entry of the fixed portion of the use information will be written.
  5567. This pointer is updated to point to the next fixed portion entry
  5568. after a NETRESOURCE entry is written.
  5569. EndOfVariableData - Supplies a pointer just off the last available byte
  5570. in the output buffer. This is because the variable portion of the
  5571. user information is written into the output buffer starting from
  5572. the end.
  5573. This pointer is updated after any variable length information is
  5574. written to the output buffer.
  5575. ContainerName - Supplies the full path qualifier to make RemoteName
  5576. a full UNC name.
  5577. LocalName - Supplies the local device name, if any.
  5578. RemoteName - Supplies the remote resource name.
  5579. ScopeFlag - Supplies the flag which indicates whether this is a
  5580. CONNECTED or GLOBALNET resource.
  5581. DisplayFlag - Supplies the flag which tells the UI how to display
  5582. the resource.
  5583. UsageFlag - Supplies the flag which indicates that the RemoteName
  5584. is either a container or a connectable resource or both.
  5585. SystemPath - Supplies the optional system path data to be stored in the
  5586. NETRESOURCE buffer. This is used by the NPGetResourceInformation
  5587. helper routines.
  5588. lppSystem - If SystemPath is provided, this will point to the location
  5589. in the NETRESOURCE buffer that contains the system path string.
  5590. EntrySize - Receives the size of the NETRESOURCE entry in bytes.
  5591. Return Value:
  5592. NO_ERROR - Successfully wrote entry into user buffer.
  5593. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate work buffer.
  5594. WN_MORE_DATA - Buffer was too small to fit entry.
  5595. --*/ // NwWriteNetResourceEntry
  5596. {
  5597. BOOL FitInBuffer = TRUE;
  5598. LPNETRESOURCEW NetR = (LPNETRESOURCEW) *FixedPortion;
  5599. LPWSTR RemoteBuffer;
  5600. LPWSTR lpSystem;
  5601. *EntrySize = sizeof(NETRESOURCEW) +
  5602. (wcslen(RemoteName) + wcslen(NwProviderName) + 2) *
  5603. sizeof(WCHAR);
  5604. if (ARGUMENT_PRESENT(LocalName)) {
  5605. *EntrySize += (wcslen(LocalName) + 1) * sizeof(WCHAR);
  5606. }
  5607. if (ARGUMENT_PRESENT(ContainerName)) {
  5608. *EntrySize += wcslen(ContainerName) * sizeof(WCHAR);
  5609. }
  5610. if (ARGUMENT_PRESENT(SystemPath)) {
  5611. *EntrySize += wcslen(SystemPath) * sizeof(WCHAR);
  5612. }
  5613. *EntrySize = ROUND_UP_COUNT( *EntrySize, ALIGN_DWORD);
  5614. //
  5615. // See if buffer is large enough to fit the entry.
  5616. //
  5617. if ((LPWSTR) ( *FixedPortion + *EntrySize) > *EndOfVariableData) {
  5618. return WN_MORE_DATA;
  5619. }
  5620. NetR->dwScope = ScopeFlag;
  5621. NetR->dwType = ResourceType;
  5622. NetR->dwDisplayType = DisplayFlag;
  5623. NetR->dwUsage = UsageFlag;
  5624. NetR->lpComment = NULL;
  5625. //
  5626. // Update fixed entry pointer to next entry.
  5627. //
  5628. (*FixedPortion) += sizeof(NETRESOURCEW);
  5629. //
  5630. // RemoteName
  5631. //
  5632. if (ARGUMENT_PRESENT(ContainerName)) {
  5633. //
  5634. // Prefix the RemoteName with its container name making the
  5635. // it a fully-qualified UNC name.
  5636. //
  5637. RemoteBuffer = (PVOID) LocalAlloc(
  5638. LMEM_ZEROINIT,
  5639. (wcslen(RemoteName) + wcslen(ContainerName) + 1) *
  5640. sizeof(WCHAR)
  5641. );
  5642. if (RemoteBuffer == NULL) {
  5643. KdPrint(("NWWORKSTATION: NwWriteNetResourceEntry LocalAlloc failed %lu\n",
  5644. GetLastError()));
  5645. return ERROR_NOT_ENOUGH_MEMORY;
  5646. }
  5647. wcscpy(RemoteBuffer, ContainerName);
  5648. wcscat(RemoteBuffer, RemoteName);
  5649. }
  5650. else {
  5651. RemoteBuffer = RemoteName;
  5652. }
  5653. FitInBuffer = NwlibCopyStringToBuffer(
  5654. RemoteBuffer,
  5655. wcslen(RemoteBuffer),
  5656. (LPCWSTR) *FixedPortion,
  5657. EndOfVariableData,
  5658. &NetR->lpRemoteName
  5659. );
  5660. if (ARGUMENT_PRESENT(ContainerName)) {
  5661. (void) LocalFree((HLOCAL) RemoteBuffer);
  5662. }
  5663. ASSERT(FitInBuffer);
  5664. //
  5665. // LocalName
  5666. //
  5667. if (ARGUMENT_PRESENT(LocalName)) {
  5668. FitInBuffer = NwlibCopyStringToBuffer(
  5669. LocalName,
  5670. wcslen(LocalName),
  5671. (LPCWSTR) *FixedPortion,
  5672. EndOfVariableData,
  5673. &NetR->lpLocalName
  5674. );
  5675. ASSERT(FitInBuffer);
  5676. }
  5677. else {
  5678. NetR->lpLocalName = NULL;
  5679. }
  5680. //
  5681. // SystemPath
  5682. //
  5683. if (ARGUMENT_PRESENT(SystemPath)) {
  5684. FitInBuffer = NwlibCopyStringToBuffer(
  5685. SystemPath,
  5686. wcslen(SystemPath),
  5687. (LPCWSTR) *FixedPortion,
  5688. EndOfVariableData,
  5689. &lpSystem
  5690. );
  5691. ASSERT(FitInBuffer);
  5692. }
  5693. else {
  5694. lpSystem = NULL;
  5695. }
  5696. if (ARGUMENT_PRESENT(lppSystem)) {
  5697. *lppSystem = lpSystem;
  5698. }
  5699. //
  5700. // ProviderName
  5701. //
  5702. FitInBuffer = NwlibCopyStringToBuffer(
  5703. NwProviderName,
  5704. wcslen(NwProviderName),
  5705. (LPCWSTR) *FixedPortion,
  5706. EndOfVariableData,
  5707. &NetR->lpProvider
  5708. );
  5709. ASSERT(FitInBuffer);
  5710. if (! FitInBuffer) {
  5711. return WN_MORE_DATA;
  5712. }
  5713. return NO_ERROR;
  5714. }
  5715. DWORD
  5716. NwWritePrinterInfoEntry(
  5717. IN OUT LPBYTE *FixedPortion,
  5718. IN OUT LPWSTR *EndOfVariableData,
  5719. IN LPWSTR ContainerName OPTIONAL,
  5720. IN LPWSTR RemoteName,
  5721. IN DWORD Flags,
  5722. OUT LPDWORD EntrySize
  5723. )
  5724. /*++
  5725. Routine Description:
  5726. This function packages a PRINTER_INFO_1 entry into the user output buffer.
  5727. Arguments:
  5728. FixedPortion - Supplies a pointer to the output buffer where the next
  5729. entry of the fixed portion of the use information will be written.
  5730. This pointer is updated to point to the next fixed portion entry
  5731. after a PRINT_INFO_1 entry is written.
  5732. EndOfVariableData - Supplies a pointer just off the last available byte
  5733. in the output buffer. This is because the variable portion of the
  5734. user information is written into the output buffer starting from
  5735. the end.
  5736. This pointer is updated after any variable length information is
  5737. written to the output buffer.
  5738. ContainerName - Supplies the full path qualifier to make RemoteName
  5739. a full UNC name.
  5740. RemoteName - Supplies the remote resource name.
  5741. Flags - Supplies the flag which indicates that the RemoteName
  5742. is either a container or not and the icon to use.
  5743. EntrySize - Receives the size of the PRINTER_INFO_1 entry in bytes.
  5744. Return Value:
  5745. NO_ERROR - Successfully wrote entry into user buffer.
  5746. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate work buffer.
  5747. ERROR_INSUFFICIENT_BUFFER - Buffer was too small to fit entry.
  5748. --*/ // NwWritePrinterInfoEntry
  5749. {
  5750. BOOL FitInBuffer = TRUE;
  5751. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) *FixedPortion;
  5752. LPWSTR RemoteBuffer;
  5753. *EntrySize = sizeof(PRINTER_INFO_1W) +
  5754. ( 2 * wcslen(RemoteName) + 2) * sizeof(WCHAR);
  5755. if (ARGUMENT_PRESENT(ContainerName)) {
  5756. *EntrySize += wcslen(ContainerName) * sizeof(WCHAR);
  5757. }
  5758. else {
  5759. // 3 is for the length of "!\\"
  5760. *EntrySize += (wcslen(NwProviderName) + 3) * sizeof(WCHAR);
  5761. }
  5762. *EntrySize = ROUND_UP_COUNT( *EntrySize, ALIGN_DWORD);
  5763. //
  5764. // See if buffer is large enough to fit the entry.
  5765. //
  5766. if ((LPWSTR) (*FixedPortion + *EntrySize) > *EndOfVariableData) {
  5767. return ERROR_INSUFFICIENT_BUFFER;
  5768. }
  5769. pPrinterInfo1->Flags = Flags;
  5770. pPrinterInfo1->pComment = NULL;
  5771. //
  5772. // Update fixed entry pointer to next entry.
  5773. //
  5774. (*FixedPortion) += sizeof(PRINTER_INFO_1W);
  5775. //
  5776. // Name
  5777. //
  5778. if (ARGUMENT_PRESENT(ContainerName)) {
  5779. //
  5780. // Prefix the RemoteName with its container name making the
  5781. // it a fully-qualified UNC name.
  5782. //
  5783. RemoteBuffer = (PVOID) LocalAlloc(
  5784. LMEM_ZEROINIT,
  5785. (wcslen(ContainerName) + wcslen(RemoteName)
  5786. + 1) * sizeof(WCHAR) );
  5787. if (RemoteBuffer == NULL) {
  5788. KdPrint(("NWWORKSTATION: NwWritePrinterInfoEntry LocalAlloc failed %lu\n", GetLastError()));
  5789. return ERROR_NOT_ENOUGH_MEMORY;
  5790. }
  5791. wcscpy(RemoteBuffer, ContainerName);
  5792. wcscat(RemoteBuffer, RemoteName);
  5793. }
  5794. else {
  5795. //
  5796. // Prefix the RemoteName with its provider name
  5797. //
  5798. RemoteBuffer = (PVOID) LocalAlloc(
  5799. LMEM_ZEROINIT,
  5800. (wcslen(RemoteName) +
  5801. wcslen(NwProviderName) + 4)
  5802. * sizeof(WCHAR) );
  5803. if (RemoteBuffer == NULL) {
  5804. KdPrint(("NWWORKSTATION: NwWritePrinterInfoEntry LocalAlloc failed %lu\n", GetLastError()));
  5805. return ERROR_NOT_ENOUGH_MEMORY;
  5806. }
  5807. wcscpy(RemoteBuffer, NwProviderName );
  5808. wcscat(RemoteBuffer, L"!\\\\" );
  5809. wcscat(RemoteBuffer, RemoteName);
  5810. }
  5811. FitInBuffer = NwlibCopyStringToBuffer(
  5812. RemoteBuffer,
  5813. wcslen(RemoteBuffer),
  5814. (LPCWSTR) *FixedPortion,
  5815. EndOfVariableData,
  5816. &pPrinterInfo1->pName );
  5817. (void) LocalFree((HLOCAL) RemoteBuffer);
  5818. ASSERT(FitInBuffer);
  5819. //
  5820. // Description
  5821. //
  5822. FitInBuffer = NwlibCopyStringToBuffer(
  5823. RemoteName,
  5824. wcslen(RemoteName),
  5825. (LPCWSTR) *FixedPortion,
  5826. EndOfVariableData,
  5827. &pPrinterInfo1->pDescription );
  5828. ASSERT(FitInBuffer);
  5829. if (! FitInBuffer) {
  5830. return ERROR_INSUFFICIENT_BUFFER;
  5831. }
  5832. return NO_ERROR;
  5833. }
  5834. int __cdecl
  5835. SortFunc(
  5836. IN CONST VOID *p1,
  5837. IN CONST VOID *p2
  5838. )
  5839. /*++
  5840. Routine Description:
  5841. This function is used in qsort to compare the descriptions of
  5842. two printer_info_1 structure.
  5843. Arguments:
  5844. p1 - Points to a PRINTER_INFO_1 structure
  5845. p2 - Points to a PRINTER_INFO_1 structure to compare with p1
  5846. Return Value:
  5847. Same as return value of lstrccmpi.
  5848. --*/
  5849. {
  5850. PRINTER_INFO_1W *pFirst = (PRINTER_INFO_1W *) p1;
  5851. PRINTER_INFO_1W *pSecond = (PRINTER_INFO_1W *) p2;
  5852. return lstrcmpiW( pFirst->pDescription, pSecond->pDescription );
  5853. }
  5854. DWORD
  5855. NwGetConnectionInformation(
  5856. IN LPWSTR lpName,
  5857. OUT LPWSTR lpUserName,
  5858. OUT LPWSTR lpHostServer
  5859. )
  5860. {
  5861. DWORD status = NO_ERROR;
  5862. NTSTATUS ntstatus = STATUS_SUCCESS;
  5863. IO_STATUS_BLOCK IoStatusBlock;
  5864. OBJECT_ATTRIBUTES ObjectAttributes;
  5865. ACCESS_MASK DesiredAccess = SYNCHRONIZE | FILE_LIST_DIRECTORY;
  5866. HANDLE hRdr = NULL;
  5867. BOOL fImpersonate = FALSE ;
  5868. WCHAR OpenString[] = L"\\Device\\Nwrdr\\*";
  5869. UNICODE_STRING OpenName;
  5870. OEM_STRING OemArg;
  5871. UNICODE_STRING ConnectionName;
  5872. WCHAR ConnectionBuffer[512];
  5873. ULONG BufferSize = 512;
  5874. ULONG RequestSize, ReplyLen;
  5875. PNWR_REQUEST_PACKET Request;
  5876. BYTE *Reply;
  5877. PCONN_INFORMATION pConnInfo;
  5878. UNICODE_STRING Name;
  5879. //
  5880. // Allocate buffer space.
  5881. //
  5882. Request = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT, BufferSize );
  5883. if ( !Request )
  5884. {
  5885. status = ERROR_NOT_ENOUGH_MEMORY;
  5886. goto ErrorExit;
  5887. }
  5888. //
  5889. // Impersonate the client
  5890. //
  5891. if ( ( status = NwImpersonateClient() ) != NO_ERROR )
  5892. {
  5893. goto ErrorExit;
  5894. }
  5895. fImpersonate = TRUE;
  5896. //
  5897. // Convert the connect name to unicode.
  5898. //
  5899. ConnectionName.Length = wcslen( lpName )* sizeof(WCHAR);
  5900. ConnectionName.MaximumLength = sizeof( ConnectionBuffer );
  5901. ConnectionName.Buffer = ConnectionBuffer;
  5902. wcscpy( ConnectionName.Buffer, lpName );
  5903. _wcsupr( ConnectionName.Buffer );
  5904. //
  5905. // Set up the object attributes.
  5906. //
  5907. RtlInitUnicodeString( &OpenName, OpenString );
  5908. InitializeObjectAttributes( &ObjectAttributes,
  5909. &OpenName,
  5910. OBJ_CASE_INSENSITIVE,
  5911. NULL,
  5912. NULL );
  5913. ntstatus = NtOpenFile( &hRdr,
  5914. DesiredAccess,
  5915. &ObjectAttributes,
  5916. &IoStatusBlock,
  5917. FILE_SHARE_VALID_FLAGS,
  5918. FILE_SYNCHRONOUS_IO_NONALERT );
  5919. if ( ntstatus != STATUS_SUCCESS )
  5920. {
  5921. status = RtlNtStatusToDosError(ntstatus);
  5922. goto ErrorExit;
  5923. }
  5924. //
  5925. // Fill out the request packet for FSCTL_NWR_GET_CONN_INFO.
  5926. //
  5927. Request->Parameters.GetConnInfo.ConnectionNameLength = ConnectionName.Length;
  5928. RtlCopyMemory( &(Request->Parameters.GetConnInfo.ConnectionName[0]),
  5929. ConnectionBuffer,
  5930. ConnectionName.Length );
  5931. RequestSize = sizeof( Request->Parameters.GetConnInfo ) + ConnectionName.Length;
  5932. Reply = ((PBYTE)Request) + RequestSize;
  5933. ReplyLen = BufferSize - RequestSize;
  5934. ntstatus = NtFsControlFile( hRdr,
  5935. NULL,
  5936. NULL,
  5937. NULL,
  5938. &IoStatusBlock,
  5939. FSCTL_NWR_GET_CONN_INFO,
  5940. (PVOID) Request,
  5941. RequestSize,
  5942. (PVOID) Reply,
  5943. ReplyLen );
  5944. if ( ntstatus != STATUS_SUCCESS )
  5945. {
  5946. status = RtlNtStatusToDosError(ntstatus);
  5947. goto ErrorExit;
  5948. }
  5949. (void) NwRevertToSelf() ;
  5950. fImpersonate = FALSE;
  5951. NtClose( hRdr );
  5952. pConnInfo = (PCONN_INFORMATION) Reply;
  5953. wcscpy( lpUserName, pConnInfo->UserName );
  5954. wcscpy( lpHostServer, pConnInfo->HostServer );
  5955. LocalFree( Request );
  5956. return NO_ERROR;
  5957. ErrorExit:
  5958. if ( fImpersonate )
  5959. (void) NwRevertToSelf() ;
  5960. if ( Request )
  5961. LocalFree( Request );
  5962. if ( hRdr )
  5963. NtClose( hRdr );
  5964. return status;
  5965. }
  5966. VOID
  5967. NwpGetUncInfo(
  5968. IN LPWSTR lpstrUnc,
  5969. OUT WORD * slashCount,
  5970. OUT BOOL * isNdsUnc,
  5971. OUT LPWSTR * FourthSlash
  5972. )
  5973. {
  5974. BYTE i;
  5975. WORD length = (WORD) wcslen( lpstrUnc );
  5976. *isNdsUnc = (BOOL) FALSE;
  5977. *slashCount = 0;
  5978. *FourthSlash = NULL;
  5979. for ( i = 0; i < length; i++ )
  5980. {
  5981. if ( lpstrUnc[i] == L'=' )
  5982. {
  5983. *isNdsUnc = TRUE;
  5984. }
  5985. if ( lpstrUnc[i] == L'\\' )
  5986. {
  5987. *slashCount += 1;
  5988. if ( *slashCount == 4 )
  5989. {
  5990. *FourthSlash = &lpstrUnc[i];
  5991. }
  5992. }
  5993. }
  5994. }
  5995. DWORD
  5996. NwpGetCurrentUserRegKey(
  5997. IN DWORD DesiredAccess,
  5998. OUT HKEY *phKeyCurrentUser
  5999. )
  6000. /*++
  6001. Routine Description:
  6002. This routine opens the current user's registry key under
  6003. \HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWCWorkstation\Parameters
  6004. Arguments:
  6005. DesiredAccess - The access mask to open the key with
  6006. phKeyCurrentUser - Receives the opened key handle
  6007. Return Value:
  6008. Returns the appropriate Win32 error.
  6009. --*/
  6010. {
  6011. DWORD err;
  6012. HKEY hkeyWksta;
  6013. LPWSTR CurrentUser;
  6014. HKEY hInteractiveLogonKey; //Multi-user
  6015. HKEY OneLogonKey; //Multi-user
  6016. LUID logonid; //Multi-user
  6017. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN]; //Multi-user
  6018. //
  6019. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  6020. // \NWCWorkstation\Parameters
  6021. //
  6022. err = RegOpenKeyExW(
  6023. HKEY_LOCAL_MACHINE,
  6024. NW_WORKSTATION_REGKEY,
  6025. REG_OPTION_NON_VOLATILE,
  6026. KEY_READ,
  6027. &hkeyWksta
  6028. );
  6029. if ( err ) {
  6030. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters key unexpected error %lu!\n", err));
  6031. return err;
  6032. }
  6033. //
  6034. // Impersonate the client
  6035. //
  6036. if ( ( err = NwImpersonateClient() ) != NO_ERROR ) {
  6037. (void) RegCloseKey( hkeyWksta );
  6038. return err;
  6039. }
  6040. //
  6041. // Get the NT logon id
  6042. //
  6043. GetLuid( &logonid );
  6044. //
  6045. // Revert
  6046. //
  6047. (void) NwRevertToSelf() ;
  6048. // Open interactive user section
  6049. err = RegOpenKeyExW(
  6050. HKEY_LOCAL_MACHINE,
  6051. NW_INTERACTIVE_LOGON_REGKEY,
  6052. REG_OPTION_NON_VOLATILE,
  6053. KEY_READ,
  6054. &hInteractiveLogonKey
  6055. );
  6056. if ( err ) {
  6057. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Interactive logon key unexpected error %lu!\n", err));
  6058. (void) RegCloseKey( hkeyWksta );
  6059. return err;
  6060. }
  6061. // Open the logonid
  6062. NwLuidToWStr(&logonid, LogonIdKeyName);
  6063. err = RegOpenKeyExW(
  6064. hInteractiveLogonKey,
  6065. LogonIdKeyName,
  6066. REG_OPTION_NON_VOLATILE,
  6067. KEY_READ,
  6068. &OneLogonKey
  6069. );
  6070. (void) RegCloseKey( hInteractiveLogonKey );
  6071. if ( err ) {
  6072. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open logon key unexpected error %lu!\n", err));
  6073. (void) RegCloseKey( hkeyWksta );
  6074. return err;
  6075. }
  6076. // Read SID
  6077. err = NwReadRegValue(
  6078. OneLogonKey,
  6079. NW_SID_VALUENAME,
  6080. &CurrentUser
  6081. );
  6082. if ( err ) {
  6083. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey read user Sid unexpected error %lu!\n", err));
  6084. (void) RegCloseKey( hkeyWksta );
  6085. return err;
  6086. }
  6087. (void) RegCloseKey( OneLogonKey );
  6088. (void) RegCloseKey( hkeyWksta );
  6089. //
  6090. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  6091. // \NWCWorkstation\Parameters\Option
  6092. //
  6093. err = RegOpenKeyExW(
  6094. HKEY_LOCAL_MACHINE,
  6095. NW_WORKSTATION_OPTION_REGKEY,
  6096. REG_OPTION_NON_VOLATILE,
  6097. KEY_READ,
  6098. &hkeyWksta
  6099. );
  6100. if ( err ) {
  6101. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters\\Option key unexpected error %lu!\n", err));
  6102. return err;
  6103. }
  6104. //
  6105. // Open current user's key
  6106. //
  6107. err = RegOpenKeyExW(
  6108. hkeyWksta,
  6109. CurrentUser,
  6110. REG_OPTION_NON_VOLATILE,
  6111. DesiredAccess,
  6112. phKeyCurrentUser
  6113. );
  6114. if ( err == ERROR_FILE_NOT_FOUND)
  6115. {
  6116. DWORD Disposition;
  6117. //
  6118. // Create <NewUser> key under NWCWorkstation\Parameters\Option
  6119. //
  6120. err = RegCreateKeyExW(
  6121. hkeyWksta,
  6122. CurrentUser,
  6123. 0,
  6124. WIN31_CLASS,
  6125. REG_OPTION_NON_VOLATILE,
  6126. DesiredAccess,
  6127. NULL, // security attr
  6128. phKeyCurrentUser,
  6129. &Disposition
  6130. );
  6131. }
  6132. if ( err ) {
  6133. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open or create of Parameters\\Option\\%ws key failed %lu\n", CurrentUser, err));
  6134. }
  6135. (void) RegCloseKey( hkeyWksta );
  6136. (void) LocalFree((HLOCAL)CurrentUser) ;
  6137. return err;
  6138. }
  6139. DWORD
  6140. NwQueryInfo(
  6141. OUT LPWSTR *ppszPreferredSrv
  6142. )
  6143. /*++
  6144. Routine Description:
  6145. This routine gets the user's preferred server and print options from
  6146. the registry.
  6147. Arguments:
  6148. ppszPreferredSrv - Receives the user's preferred server
  6149. Return Value:
  6150. Returns the appropriate Win32 error.
  6151. --*/
  6152. {
  6153. HKEY hKeyCurrentUser = NULL;
  6154. DWORD BufferSize;
  6155. DWORD BytesNeeded;
  6156. DWORD ValueType;
  6157. LPWSTR PreferredServer ;
  6158. DWORD err ;
  6159. //
  6160. // get to right place in registry and allocate dthe buffer
  6161. //
  6162. if (err = NwpGetCurrentUserRegKey( KEY_READ, &hKeyCurrentUser))
  6163. {
  6164. //
  6165. // If somebody mess around with the registry and we can't find
  6166. // the registry, just use the defaults.
  6167. //
  6168. *ppszPreferredSrv = NULL;
  6169. return NO_ERROR;
  6170. }
  6171. BufferSize = sizeof(WCHAR) * (MAX_PATH + 2) ;
  6172. PreferredServer = (LPWSTR) LocalAlloc(LPTR, BufferSize) ;
  6173. if (!PreferredServer)
  6174. return (GetLastError()) ;
  6175. //
  6176. // Read PreferredServer value into Buffer.
  6177. //
  6178. BytesNeeded = BufferSize ;
  6179. err = RegQueryValueExW( hKeyCurrentUser,
  6180. NW_SERVER_VALUENAME,
  6181. NULL,
  6182. &ValueType,
  6183. (LPBYTE) PreferredServer,
  6184. &BytesNeeded );
  6185. if (err != NO_ERROR)
  6186. {
  6187. //
  6188. // set to empty and carry on
  6189. //
  6190. PreferredServer[0] = 0;
  6191. }
  6192. if (hKeyCurrentUser != NULL)
  6193. (void) RegCloseKey(hKeyCurrentUser) ;
  6194. *ppszPreferredSrv = PreferredServer ;
  6195. return NO_ERROR ;
  6196. }