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

7723 lines
228 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. if (!(ContextHandle->ConnectionType & CONNTYPE_SYMBOLIC))
  1295. {
  1296. status = NwEnumerateConnections(
  1297. &ContextHandle->ResumeId,
  1298. EntriesRequested,
  1299. Buffer,
  1300. BufferSize,
  1301. BytesNeeded,
  1302. EntriesRead,
  1303. ContextHandle->ConnectionType,
  1304. NULL
  1305. );
  1306. }
  1307. break;
  1308. case NwsHandleListContextInfo_Tree:
  1309. case NwsHandleListContextInfo_Server:
  1310. status = NwEnumContextInfo(
  1311. ContextHandle,
  1312. EntriesRequested,
  1313. Buffer,
  1314. BufferSize,
  1315. BytesNeeded,
  1316. EntriesRead
  1317. );
  1318. break;
  1319. case NwsHandleListServersAndNdsTrees:
  1320. status = NwEnumServersAndNdsTrees(
  1321. ContextHandle,
  1322. EntriesRequested,
  1323. Buffer,
  1324. BufferSize,
  1325. BytesNeeded,
  1326. EntriesRead
  1327. );
  1328. break;
  1329. case NwsHandleListVolumes:
  1330. status = NwEnumVolumes(
  1331. ContextHandle,
  1332. EntriesRequested,
  1333. Buffer,
  1334. BufferSize,
  1335. BytesNeeded,
  1336. EntriesRead
  1337. );
  1338. break;
  1339. case NwsHandleListNdsSubTrees_Disk:
  1340. status = NwEnumNdsSubTrees_Disk(
  1341. ContextHandle,
  1342. EntriesRequested,
  1343. Buffer,
  1344. BufferSize,
  1345. BytesNeeded,
  1346. EntriesRead
  1347. );
  1348. break;
  1349. case NwsHandleListNdsSubTrees_Print:
  1350. status = NwEnumNdsSubTrees_Print(
  1351. ContextHandle,
  1352. EntriesRequested,
  1353. Buffer,
  1354. BufferSize,
  1355. BytesNeeded,
  1356. EntriesRead
  1357. );
  1358. break;
  1359. case NwsHandleListNdsSubTrees_Any:
  1360. status = NwEnumNdsSubTrees_Any(
  1361. ContextHandle,
  1362. EntriesRequested,
  1363. Buffer,
  1364. BufferSize,
  1365. BytesNeeded,
  1366. EntriesRead
  1367. );
  1368. break;
  1369. case NwsHandleListQueues:
  1370. status = NwEnumQueues(
  1371. ContextHandle,
  1372. EntriesRequested,
  1373. Buffer,
  1374. BufferSize,
  1375. BytesNeeded,
  1376. EntriesRead
  1377. );
  1378. break;
  1379. case NwsHandleListVolumesQueues:
  1380. status = NwEnumVolumesQueues(
  1381. ContextHandle,
  1382. EntriesRequested,
  1383. Buffer,
  1384. BufferSize,
  1385. BytesNeeded,
  1386. EntriesRead
  1387. );
  1388. break;
  1389. case NwsHandleListDirectories:
  1390. status = NwEnumDirectories(
  1391. ContextHandle,
  1392. EntriesRequested,
  1393. Buffer,
  1394. BufferSize,
  1395. BytesNeeded,
  1396. EntriesRead
  1397. );
  1398. break;
  1399. case NwsHandleListPrintServers:
  1400. status = NwEnumPrintServers(
  1401. ContextHandle,
  1402. EntriesRequested,
  1403. Buffer,
  1404. BufferSize,
  1405. BytesNeeded,
  1406. EntriesRead
  1407. );
  1408. break;
  1409. case NwsHandleListPrintQueues:
  1410. status = NwEnumPrintQueues(
  1411. ContextHandle,
  1412. EntriesRequested,
  1413. Buffer,
  1414. BufferSize,
  1415. BytesNeeded,
  1416. EntriesRead
  1417. );
  1418. break;
  1419. default:
  1420. KdPrint(("NWWORKSTATION: NwrEnum unexpected handle type %lu\n",
  1421. ContextHandle->HandleType));
  1422. ASSERT(FALSE);
  1423. status = WN_BAD_HANDLE;
  1424. goto CleanExit ;
  1425. }
  1426. if (*EntriesRead > 0) {
  1427. switch ( ContextHandle->HandleType ) {
  1428. case NwsHandleListConnections:
  1429. case NwsHandleListContextInfo_Tree:
  1430. case NwsHandleListContextInfo_Server:
  1431. case NwsHandleListServersAndNdsTrees:
  1432. case NwsHandleListVolumes:
  1433. case NwsHandleListQueues:
  1434. case NwsHandleListVolumesQueues:
  1435. case NwsHandleListDirectories:
  1436. case NwsHandleListNdsSubTrees_Disk:
  1437. case NwsHandleListNdsSubTrees_Any:
  1438. {
  1439. DWORD i;
  1440. LPNETRESOURCEW NetR = (LPNETRESOURCEW) Buffer;
  1441. //
  1442. // Replace pointers to strings with offsets as need
  1443. //
  1444. if ((ContextHandle->HandleType == NwsHandleListConnections)
  1445. && (ContextHandle->ConnectionType & CONNTYPE_SYMBOLIC))
  1446. {
  1447. //
  1448. // NwrEnumGWDevices already return offsets.
  1449. //
  1450. break ;
  1451. }
  1452. for (i = 0; i < *EntriesRead; i++, NetR++) {
  1453. if (NetR->lpLocalName != NULL) {
  1454. NetR->lpLocalName = (LPWSTR)
  1455. ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) Buffer);
  1456. }
  1457. NetR->lpRemoteName =
  1458. (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR)Buffer);
  1459. if (NetR->lpComment != NULL) {
  1460. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) -
  1461. (DWORD_PTR) Buffer);
  1462. }
  1463. if (NetR->lpProvider != NULL) {
  1464. NetR->lpProvider =
  1465. (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) -
  1466. (DWORD_PTR) Buffer);
  1467. }
  1468. }
  1469. break;
  1470. }
  1471. case NwsHandleListPrintServers:
  1472. case NwsHandleListPrintQueues:
  1473. case NwsHandleListNdsSubTrees_Print:
  1474. {
  1475. DWORD i;
  1476. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) Buffer;
  1477. //
  1478. // Sort the entries in the buffer
  1479. //
  1480. if ( *EntriesRead > 1 )
  1481. qsort( Buffer, *EntriesRead,
  1482. sizeof( PRINTER_INFO_1W ), SortFunc );
  1483. //
  1484. // Replace pointers to strings with offsets
  1485. //
  1486. for (i = 0; i < *EntriesRead; i++, pPrinterInfo1++) {
  1487. MarshallDownStructure( (LPBYTE) pPrinterInfo1,
  1488. PrinterInfo1Offsets,
  1489. Buffer );
  1490. }
  1491. break;
  1492. }
  1493. default:
  1494. KdPrint(("NWWORKSTATION: NwrEnum (pointer to offset code) unexpected handle type %lu\n", ContextHandle->HandleType));
  1495. ASSERT( FALSE );
  1496. break;
  1497. }
  1498. }
  1499. CleanExit:
  1500. if (fImpersonate)
  1501. (void) NwRevertToSelf() ;
  1502. return status;
  1503. }
  1504. DWORD
  1505. NwrEnumConnections(
  1506. IN NWWKSTA_CONTEXT_HANDLE EnumHandle,
  1507. IN DWORD EntriesRequested,
  1508. OUT LPBYTE Buffer,
  1509. IN DWORD BufferSize,
  1510. OUT LPDWORD BytesNeeded,
  1511. OUT LPDWORD EntriesRead,
  1512. IN DWORD fImplicitConnections
  1513. )
  1514. /*++
  1515. Routine Description:
  1516. This function is an alternate to NwrEnum. It only accepts handles
  1517. that are opened with ListConnections. This function takes a flag
  1518. indicating whether we need to show all implicit connections or not.
  1519. Arguments:
  1520. ContextHandle - Supplies the enum context handle.
  1521. EntriesRequested - Supplies the number of entries to return. If
  1522. this value is -1, return all available entries.
  1523. Buffer - Receives the entries we are listing.
  1524. BufferSize - Supplies the size of the output buffer.
  1525. BytesNeeded - Receives the number of bytes required to get the
  1526. first entry. This value is returned iff ERROR_MORE_DATA is
  1527. the return code, and Buffer is too small to even fit one
  1528. entry.
  1529. EntriesRead - Receives the number of entries returned in Buffer.
  1530. This value is only returned iff NO_ERROR is the return code.
  1531. NO_ERROR is returned as long as at least one entry was written
  1532. into Buffer but does not necessarily mean that it's the number
  1533. of EntriesRequested.
  1534. fImplicitConnections - TRUE if we also want to get implicit connections,
  1535. FALSE otherwise.
  1536. Return Value:
  1537. NO_ERROR - At least one entry was written to output buffer,
  1538. irregardless of the number requested.
  1539. WN_NO_MORE_ENTRIES - No entries left to return.
  1540. ERROR_MORE_DATA - The buffer was too small to fit a single entry.
  1541. --*/ // NwrEnumConnections
  1542. {
  1543. DWORD status;
  1544. LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) EnumHandle;
  1545. if ( (ContextHandle->Signature != NW_HANDLE_SIGNATURE)
  1546. || ( ContextHandle->HandleType != NwsHandleListConnections )
  1547. )
  1548. {
  1549. return WN_BAD_HANDLE;
  1550. }
  1551. *EntriesRead = 0;
  1552. *BytesNeeded = 0;
  1553. RtlZeroMemory(Buffer, BufferSize);
  1554. if ( fImplicitConnections )
  1555. ContextHandle->ConnectionType |= CONNTYPE_IMPLICIT;
  1556. if ((status = NwImpersonateClient()) != NO_ERROR)
  1557. goto ErrorExit;
  1558. status = NwEnumerateConnections(
  1559. &ContextHandle->ResumeId,
  1560. EntriesRequested,
  1561. Buffer,
  1562. BufferSize,
  1563. BytesNeeded,
  1564. EntriesRead,
  1565. ContextHandle->ConnectionType,
  1566. NULL
  1567. );
  1568. if (*EntriesRead > 0) {
  1569. //
  1570. // Replace pointers to strings with offsets
  1571. //
  1572. DWORD i;
  1573. LPNETRESOURCEW NetR = (LPNETRESOURCEW) Buffer;
  1574. for (i = 0; i < *EntriesRead; i++, NetR++) {
  1575. if (NetR->lpLocalName != NULL) {
  1576. NetR->lpLocalName = (LPWSTR)
  1577. ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) Buffer);
  1578. }
  1579. NetR->lpRemoteName =
  1580. (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR)Buffer);
  1581. if (NetR->lpComment != NULL) {
  1582. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) -
  1583. (DWORD_PTR) Buffer);
  1584. }
  1585. if (NetR->lpProvider != NULL) {
  1586. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) -
  1587. (DWORD_PTR) Buffer);
  1588. }
  1589. }
  1590. }
  1591. (void) NwRevertToSelf();
  1592. ErrorExit:
  1593. return status;
  1594. }
  1595. DWORD
  1596. NwEnumContextInfo(
  1597. IN LPNW_ENUM_CONTEXT ContextHandle,
  1598. IN DWORD_PTR EntriesRequested,
  1599. OUT LPBYTE Buffer,
  1600. IN DWORD BufferSize,
  1601. OUT LPDWORD BytesNeeded,
  1602. OUT LPDWORD EntriesRead
  1603. )
  1604. /*++
  1605. Routine Description:
  1606. This function enumerates all of the bindery servers that are currently
  1607. connected, then sets the context handle so that the next NPEnumResource
  1608. call goes to the NDS subtree for the user's NDS context information
  1609. (if using NDS).
  1610. Arguments:
  1611. ContextHandle - Supplies the enum context handle.
  1612. EntriesRequested - Supplies the number of entries to return. If
  1613. this value is -1, return all available entries.
  1614. Buffer - Receives the entries we are listing.
  1615. BufferSize - Supplies the size of the output buffer.
  1616. BytesNeeded - Receives the number of bytes required to get the
  1617. first entry. This value is returned iff WN_MORE_DATA is
  1618. the return code, and Buffer is too small to even fit one
  1619. entry.
  1620. EntriesRead - Receives the number of entries returned in Buffer.
  1621. This value is only returned iff NO_ERROR is the return code.
  1622. NO_ERROR is returned as long as at least one entry was written
  1623. into Buffer but does not necessarily mean that it's the number
  1624. of EntriesRequested.
  1625. Return Value:
  1626. NO_ERROR - At least one entry was written to output buffer,
  1627. irregardless of the number requested.
  1628. WN_NO_MORE_ENTRIES - No entries left to return.
  1629. WN_MORE_DATA - The buffer was too small to fit a single entry.
  1630. --*/ // NwEnumContextInfo
  1631. {
  1632. DWORD status = NO_ERROR;
  1633. DWORD_PTR tempResumeId = 0;
  1634. LPBYTE FixedPortion = Buffer;
  1635. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  1636. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  1637. BOOL FitInBuffer = TRUE;
  1638. DWORD EntrySize;
  1639. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  1640. while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
  1641. FitInBuffer &&
  1642. EntriesRequested > *EntriesRead &&
  1643. status == NO_ERROR )
  1644. {
  1645. tempResumeId = ContextHandle->ResumeId;
  1646. status = NwGetNextServerConnection( ContextHandle );
  1647. if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
  1648. {
  1649. //
  1650. // Pack bindery server name into output buffer.
  1651. //
  1652. status = NwWriteNetResourceEntry(
  1653. &FixedPortion,
  1654. &EndOfVariableData,
  1655. L"\\\\",
  1656. NULL,
  1657. (LPWSTR) ContextHandle->ResumeId, // A server name
  1658. RESOURCE_CONTEXT,
  1659. RESOURCEDISPLAYTYPE_SERVER,
  1660. RESOURCEUSAGE_CONTAINER,
  1661. RESOURCETYPE_ANY,
  1662. NULL,
  1663. NULL,
  1664. &EntrySize
  1665. );
  1666. if (status == WN_MORE_DATA)
  1667. {
  1668. //
  1669. // Could not write current entry into output buffer,
  1670. // backup ResumeId to previous entry.
  1671. //
  1672. ContextHandle->ResumeId = tempResumeId;
  1673. ContextHandle->NdsRawDataCount += 1;
  1674. if (*EntriesRead)
  1675. {
  1676. //
  1677. // Still return success because we got at least one.
  1678. //
  1679. status = NO_ERROR;
  1680. }
  1681. else
  1682. {
  1683. *BytesNeeded = EntrySize;
  1684. }
  1685. FitInBuffer = FALSE;
  1686. }
  1687. else if (status == NO_ERROR)
  1688. {
  1689. //
  1690. // Note that we've returned the current entry.
  1691. //
  1692. (*EntriesRead)++;
  1693. }
  1694. }
  1695. else if ( status == WN_NO_MORE_ENTRIES )
  1696. {
  1697. //
  1698. // We processed the last item in list, so
  1699. // start enumerating servers.
  1700. //
  1701. ContextHandle->ResumeId = 0;
  1702. LastObjectId = 0;
  1703. if ( ContextHandle->HandleType == NwsHandleListContextInfo_Tree )
  1704. {
  1705. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NDS;
  1706. }
  1707. }
  1708. }
  1709. if ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS )
  1710. {
  1711. ContextHandle->HandleType = NwsHandleListNdsSubTrees_Any;
  1712. status = NO_ERROR;
  1713. }
  1714. //
  1715. // User asked for more than there are entries. We just say that
  1716. // all is well.
  1717. //
  1718. // This is incompliance with the wierd provider API definition where
  1719. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  1720. // at least one entry fit into output buffer, there's no telling if
  1721. // the buffer was too small for more entries or there are no more
  1722. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  1723. // before knowing that the last call had actually reached the end of list.
  1724. //
  1725. if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  1726. {
  1727. status = NO_ERROR;
  1728. }
  1729. return status;
  1730. }
  1731. DWORD
  1732. NwEnumServersAndNdsTrees(
  1733. IN LPNW_ENUM_CONTEXT ContextHandle,
  1734. IN DWORD_PTR EntriesRequested,
  1735. OUT LPBYTE Buffer,
  1736. IN DWORD BufferSize,
  1737. OUT LPDWORD BytesNeeded,
  1738. OUT LPDWORD EntriesRead
  1739. )
  1740. /*++
  1741. Routine Description:
  1742. This function enumerates all the servers and NDS trees on the local
  1743. network by: 1) scanning the bindery for file server objects on the
  1744. preferred server and 2) scanning the bindery for directory servers
  1745. (NDS trees) on the preferred server. The server and tree entries are
  1746. returned in an array of NETRESOURCE entries; each servername is
  1747. prefixed by \\.
  1748. The ContextHandle->ResumeId field is initially -1 before
  1749. enumeration begins and contains the object ID of the last server
  1750. or NDS tree object returned, depending on the value of
  1751. ContextHandle->dwUsingNds.
  1752. Arguments:
  1753. ContextHandle - Supplies the enum context handle.
  1754. EntriesRequested - Supplies the number of entries to return. If
  1755. this value is -1, return all available entries.
  1756. Buffer - Receives the entries we are listing.
  1757. BufferSize - Supplies the size of the output buffer.
  1758. BytesNeeded - Receives the number of bytes required to get the
  1759. first entry. This value is returned iff WN_MORE_DATA is
  1760. the return code, and Buffer is too small to even fit one
  1761. entry.
  1762. This value is only returned iff NO_ERROR is the return code.
  1763. NO_ERROR is returned as long as at least one entry was written
  1764. into Buffer but does not necessarily mean that it's the number
  1765. of EntriesRequested.
  1766. Return Value:
  1767. NO_ERROR - At least one entry was written to output buffer,
  1768. irregardless of the number requested.
  1769. WN_NO_MORE_ENTRIES - No entries left to return.
  1770. WN_MORE_DATA - The buffer was too small to fit a single entry.
  1771. --*/ // NwEnumServersAndNdsTrees
  1772. {
  1773. DWORD status = NO_ERROR;
  1774. DWORD_PTR tempResumeId = 0;
  1775. LPBYTE FixedPortion = Buffer;
  1776. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  1777. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  1778. BOOL FitInBuffer = TRUE;
  1779. DWORD EntrySize;
  1780. SERVERNAME ServerName; // OEM server name
  1781. LPWSTR UServerName = NULL; // Unicode server name
  1782. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  1783. while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS &&
  1784. FitInBuffer &&
  1785. EntriesRequested > *EntriesRead &&
  1786. status == NO_ERROR )
  1787. {
  1788. tempResumeId = ContextHandle->ResumeId;
  1789. //
  1790. // Call the scan bindery object NCP to scan for all NDS
  1791. // tree objects.
  1792. //
  1793. status = NwGetNextNdsTreeEntry( ContextHandle );
  1794. if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
  1795. {
  1796. //
  1797. // Pack tree name into output buffer.
  1798. //
  1799. status = NwWriteNetResourceEntry(
  1800. &FixedPortion,
  1801. &EndOfVariableData,
  1802. L"\\\\",
  1803. NULL,
  1804. (LPWSTR) ContextHandle->ResumeId, // This is a NDS tree name
  1805. RESOURCE_GLOBALNET,
  1806. RESOURCEDISPLAYTYPE_TREE,
  1807. RESOURCEUSAGE_CONTAINER,
  1808. RESOURCETYPE_ANY,
  1809. NULL,
  1810. NULL,
  1811. &EntrySize
  1812. );
  1813. if (status == WN_MORE_DATA)
  1814. {
  1815. //
  1816. // Could not write current entry into output buffer, backup ResumeId to
  1817. // previous entry.
  1818. //
  1819. ContextHandle->ResumeId = tempResumeId;
  1820. ContextHandle->NdsRawDataCount += 1;
  1821. if (*EntriesRead)
  1822. {
  1823. //
  1824. // Still return success because we got at least one.
  1825. //
  1826. status = NO_ERROR;
  1827. }
  1828. else
  1829. {
  1830. *BytesNeeded = EntrySize;
  1831. }
  1832. FitInBuffer = FALSE;
  1833. }
  1834. else if (status == NO_ERROR)
  1835. {
  1836. //
  1837. // Note that we've returned the current entry.
  1838. //
  1839. (*EntriesRead)++;
  1840. }
  1841. }
  1842. else if ( status == WN_NO_MORE_ENTRIES )
  1843. {
  1844. //
  1845. // We processed the last item in list, so
  1846. // start enumerating servers.
  1847. //
  1848. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  1849. ContextHandle->ResumeId = (DWORD_PTR) -1;
  1850. LastObjectId = (DWORD) -1;
  1851. }
  1852. }
  1853. if ( status == WN_NO_MORE_ENTRIES)
  1854. {
  1855. status = NO_ERROR;
  1856. }
  1857. while ( ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
  1858. FitInBuffer &&
  1859. EntriesRequested > *EntriesRead &&
  1860. status == NO_ERROR )
  1861. {
  1862. RtlZeroMemory(ServerName, sizeof(ServerName));
  1863. //
  1864. // Call the scan bindery object NCP to scan for all file
  1865. // server objects.
  1866. //
  1867. status = NwGetNextServerEntry(
  1868. ContextHandle->TreeConnectionHandle,
  1869. &LastObjectId,
  1870. ServerName
  1871. );
  1872. if (status == NO_ERROR && NwConvertToUnicode(&UServerName, ServerName))
  1873. {
  1874. //
  1875. // Pack server name into output buffer.
  1876. //
  1877. status = NwWriteNetResourceEntry(
  1878. &FixedPortion,
  1879. &EndOfVariableData,
  1880. L"\\\\",
  1881. NULL,
  1882. UServerName,
  1883. RESOURCE_GLOBALNET,
  1884. RESOURCEDISPLAYTYPE_SERVER,
  1885. RESOURCEUSAGE_CONTAINER,
  1886. RESOURCETYPE_ANY,
  1887. NULL,
  1888. NULL,
  1889. &EntrySize
  1890. );
  1891. if (status == WN_MORE_DATA)
  1892. {
  1893. //
  1894. // Could not write current entry into output buffer.
  1895. //
  1896. if (*EntriesRead)
  1897. {
  1898. //
  1899. // Still return success because we got at least one.
  1900. //
  1901. status = NO_ERROR;
  1902. }
  1903. else
  1904. {
  1905. *BytesNeeded = EntrySize;
  1906. }
  1907. FitInBuffer = FALSE;
  1908. }
  1909. else if (status == NO_ERROR)
  1910. {
  1911. //
  1912. // Note that we've returned the current entry.
  1913. //
  1914. (*EntriesRead)++;
  1915. ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
  1916. }
  1917. (void) LocalFree((HLOCAL) UServerName);
  1918. }
  1919. }
  1920. //
  1921. // User asked for more than there are entries. We just say that
  1922. // all is well.
  1923. //
  1924. // This is incompliance with the wierd provider API definition where
  1925. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  1926. // at least one entry fit into output buffer, there's no telling if
  1927. // the buffer was too small for more entries or there are no more
  1928. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  1929. // before knowing that the last call had actually reached the end of list.
  1930. //
  1931. if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  1932. {
  1933. status = NO_ERROR;
  1934. }
  1935. return status;
  1936. }
  1937. DWORD
  1938. NwEnumVolumes(
  1939. IN LPNW_ENUM_CONTEXT ContextHandle,
  1940. IN DWORD_PTR EntriesRequested,
  1941. OUT LPBYTE Buffer,
  1942. IN DWORD BufferSize,
  1943. OUT LPDWORD BytesNeeded,
  1944. OUT LPDWORD EntriesRead
  1945. )
  1946. /*++
  1947. Routine Description:
  1948. This function enumerates all the volumes on a server by
  1949. iteratively getting the volume name for each volume number from
  1950. 0 - 31 until we run into the first volume number that does not
  1951. map to a volume name (this method assumes that volume numbers
  1952. are used contiguously in ascending order). The volume entries
  1953. are returned in an array of NETRESOURCE entries; each volume
  1954. name if prefixed by \\Server\.
  1955. The ContextHandle->ResumeId field always indicates the next
  1956. volume entry to return. It is initially set to 0, which indicates
  1957. the first volume number to get.
  1958. Arguments:
  1959. ContextHandle - Supplies the enum context handle.
  1960. EntriesRequested - Supplies the number of entries to return. If
  1961. this value is -1, return all available entries.
  1962. Buffer - Receives the entries we are listing.
  1963. BufferSize - Supplies the size of the output buffer.
  1964. BytesNeeded - Receives the number of bytes required to get the
  1965. first entry. This value is returned iff WN_MORE_DATA is
  1966. the return code, and Buffer is too small to even fit one
  1967. entry.
  1968. EntriesRead - Receives the number of entries returned in Buffer.
  1969. This value is only returned iff NO_ERROR is the return code.
  1970. NO_ERROR is returned as long as at least one entry was written
  1971. into Buffer but does not necessarily mean that it's the number
  1972. of EntriesRequested.
  1973. Return Value:
  1974. NO_ERROR - At least one entry was written to output buffer,
  1975. irregardless of the number requested.
  1976. WN_NO_MORE_ENTRIES - No entries left to return.
  1977. WN_MORE_DATA - The buffer was too small to fit a single entry.
  1978. --*/ // NwEnumVolumes
  1979. {
  1980. DWORD status = NO_ERROR;
  1981. LPBYTE FixedPortion = Buffer;
  1982. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  1983. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  1984. BOOL FitInBuffer = TRUE;
  1985. DWORD EntrySize;
  1986. CHAR VolumeName[NW_VOLUME_NAME_LEN]; // OEM volume name
  1987. LPWSTR UVolumeName = NULL; // Unicode volume name
  1988. DWORD NextVolumeNumber = (DWORD) ContextHandle->ResumeId;
  1989. DWORD MaxVolumeNumber = ContextHandle->dwMaxVolumes;
  1990. ULONG Failures = 0;
  1991. if (NextVolumeNumber == MaxVolumeNumber) {
  1992. //
  1993. // Reached the end of enumeration
  1994. //
  1995. return WN_NO_MORE_ENTRIES;
  1996. }
  1997. while (FitInBuffer &&
  1998. EntriesRequested > *EntriesRead &&
  1999. NextVolumeNumber < MaxVolumeNumber &&
  2000. status == NO_ERROR) {
  2001. RtlZeroMemory(VolumeName, sizeof(VolumeName));
  2002. //
  2003. // Call the scan bindery object NCP to scan for all file
  2004. // volume objects.
  2005. //
  2006. status = NwGetNextVolumeEntry(
  2007. ContextHandle->TreeConnectionHandle,
  2008. NextVolumeNumber++,
  2009. VolumeName
  2010. );
  2011. if (status == NO_ERROR) {
  2012. if (VolumeName[0] == 0) {
  2013. //
  2014. // Got an empty volume name back for the next volume number
  2015. // which indicates there is no volume associated with the
  2016. // volume number but still got error success.
  2017. //
  2018. // Treat this as having reached the end of the enumeration
  2019. // only if we've gotten two three empty volumes in a row
  2020. // or reached the max number of volumes because there are
  2021. // some cases where there are holes in the way that volumes
  2022. // are allocated.
  2023. //
  2024. Failures++;
  2025. if ( Failures <= 3 ) {
  2026. continue;
  2027. } else {
  2028. NextVolumeNumber = MaxVolumeNumber;
  2029. ContextHandle->ResumeId = MaxVolumeNumber;
  2030. if (*EntriesRead == 0) {
  2031. status = WN_NO_MORE_ENTRIES;
  2032. }
  2033. }
  2034. } else if (NwConvertToUnicode(&UVolumeName, VolumeName)) {
  2035. //
  2036. // Pack volume name into output buffer.
  2037. //
  2038. status = NwWriteNetResourceEntry(
  2039. &FixedPortion,
  2040. &EndOfVariableData,
  2041. ContextHandle->ContainerName,
  2042. NULL,
  2043. UVolumeName,
  2044. RESOURCE_GLOBALNET,
  2045. RESOURCEDISPLAYTYPE_SHARE,
  2046. #ifdef NT1057
  2047. RESOURCEUSAGE_CONNECTABLE |
  2048. RESOURCEUSAGE_CONTAINER,
  2049. #else
  2050. RESOURCEUSAGE_CONNECTABLE |
  2051. RESOURCEUSAGE_NOLOCALDEVICE,
  2052. #endif
  2053. RESOURCETYPE_DISK,
  2054. NULL,
  2055. NULL,
  2056. &EntrySize
  2057. );
  2058. if (status == WN_MORE_DATA) {
  2059. //
  2060. // Could not write current entry into output buffer.
  2061. //
  2062. if (*EntriesRead) {
  2063. //
  2064. // Still return success because we got at least one.
  2065. //
  2066. status = NO_ERROR;
  2067. }
  2068. else {
  2069. *BytesNeeded = EntrySize;
  2070. }
  2071. FitInBuffer = FALSE;
  2072. }
  2073. else if (status == NO_ERROR) {
  2074. //
  2075. // Note that we've returned the current entry.
  2076. //
  2077. (*EntriesRead)++;
  2078. ContextHandle->ResumeId = NextVolumeNumber;
  2079. }
  2080. (void) LocalFree((HLOCAL) UVolumeName);
  2081. }
  2082. //
  2083. // We got an entry, so reset the failure counter.
  2084. //
  2085. Failures = 0;
  2086. }
  2087. }
  2088. //
  2089. // User asked for more than there are entries. We just say that
  2090. // all is well.
  2091. //
  2092. // This is incompliance with the wierd provider API definition where
  2093. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2094. // at least one entry fit into output buffer, there's no telling if
  2095. // the buffer was too small for more entries or there are no more
  2096. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2097. // before knowing that the last call had actually reached the end of list.
  2098. //
  2099. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  2100. status = NO_ERROR;
  2101. }
  2102. return status;
  2103. }
  2104. DWORD
  2105. NwEnumNdsSubTrees_Disk(
  2106. IN LPNW_ENUM_CONTEXT ContextHandle,
  2107. IN DWORD_PTR EntriesRequested,
  2108. OUT LPBYTE Buffer,
  2109. IN DWORD BufferSize,
  2110. OUT LPDWORD BytesNeeded,
  2111. OUT LPDWORD EntriesRead
  2112. )
  2113. /*++
  2114. Routine Description:
  2115. This function enumerates the sub-trees of a given NDS tree
  2116. handle. It returns the fully-qualified UNC path of the sub-tree
  2117. entries in an array of NETRESOURCE entries.
  2118. The ContextHandle->ResumeId field is 0 initially, and contains
  2119. a pointer to the subtree name string of the last sub-tree
  2120. returned. If there are no more sub-trees to return, this
  2121. field is set to -1.
  2122. Arguments:
  2123. ContextHandle - Supplies the enum context handle. It contains
  2124. an opened NDS tree handle.
  2125. EntriesRequested - Supplies the number of entries to return. If
  2126. this value is -1, return all available entries.
  2127. Buffer - Receives the entries we are listing.
  2128. BufferSize - Supplies the size of the output buffer.
  2129. BytesNeeded - Receives the number of bytes required to get the
  2130. first entry. This value is returned iff WN_MORE_DATA is
  2131. the return code, and Buffer is too small to even fit one
  2132. entry.
  2133. EntriesRead - Receives the number of entries returned in Buffer.
  2134. This value is only returned iff NO_ERROR is the return code.
  2135. NO_ERROR is returned as long as at least one entry was written
  2136. into Buffer but does not necessarily mean that it's the number
  2137. of EntriesRequested.
  2138. Return Value:
  2139. NO_ERROR - At least one entry was written to output buffer,
  2140. irregardless of the number requested.
  2141. WN_NO_MORE_ENTRIES - No entries left to return.
  2142. WN_MORE_DATA - The buffer was too small to fit a single entry.
  2143. --*/ // NwEnumNdsSubTrees_Disk
  2144. {
  2145. DWORD status = NO_ERROR;
  2146. LPBYTE FixedPortion = Buffer;
  2147. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2148. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2149. BOOL FitInBuffer = TRUE;
  2150. DWORD EntrySize = 0;
  2151. LPWSTR SubTreeName = NULL;
  2152. DWORD ResourceScope = 0;
  2153. DWORD ResourceType = 0;
  2154. DWORD ResourceDisplayType = 0;
  2155. DWORD ResourceUsage = 0;
  2156. LPWSTR StrippedObjectName = NULL;
  2157. if (ContextHandle->ResumeId == (DWORD_PTR) -1)
  2158. {
  2159. //
  2160. // Reached the end of enumeration.
  2161. //
  2162. return WN_NO_MORE_ENTRIES;
  2163. }
  2164. while (FitInBuffer &&
  2165. EntriesRequested > *EntriesRead &&
  2166. status == NO_ERROR)
  2167. {
  2168. if ( ContextHandle->ResumeId == 0 )
  2169. {
  2170. //
  2171. // Get the first subtree entry.
  2172. //
  2173. status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
  2174. }
  2175. //
  2176. // Either ResumeId contains the first entry we just got from
  2177. // NwGetFirstDirectoryEntry or it contains the next directory
  2178. // entry to return.
  2179. //
  2180. if (status == NO_ERROR && ContextHandle->ResumeId != 0)
  2181. {
  2182. BYTE ClassType;
  2183. LPWSTR newPathStr = NULL;
  2184. LPWSTR tempStr = NULL;
  2185. WORD tempStrLen;
  2186. //
  2187. // Get current subtree data from ContextHandle
  2188. //
  2189. ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
  2190. &SubTreeName,
  2191. &ResourceScope,
  2192. &ResourceType,
  2193. &ResourceDisplayType,
  2194. &ResourceUsage,
  2195. &StrippedObjectName );
  2196. if ( StrippedObjectName == NULL )
  2197. {
  2198. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk LocalAlloc Failed %lu\n",
  2199. GetLastError()));
  2200. return ERROR_NOT_ENOUGH_MEMORY;
  2201. }
  2202. switch( ClassType )
  2203. {
  2204. case CLASS_TYPE_COUNTRY:
  2205. case CLASS_TYPE_DIRECTORY_MAP:
  2206. case CLASS_TYPE_NCP_SERVER:
  2207. case CLASS_TYPE_ORGANIZATION:
  2208. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2209. case CLASS_TYPE_VOLUME:
  2210. //
  2211. // Need to build a string with the new NDS UNC path for subtree object
  2212. //
  2213. newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  2214. ( wcslen( StrippedObjectName ) +
  2215. wcslen( ContextHandle->ContainerName ) +
  2216. 3 ) * sizeof(WCHAR) );
  2217. if ( newPathStr == NULL )
  2218. {
  2219. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk LocalAlloc Failed %lu\n",
  2220. GetLastError()));
  2221. return ERROR_NOT_ENOUGH_MEMORY;
  2222. }
  2223. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2224. ContextHandle->ContainerName,
  2225. PARSE_NDS_GET_TREE_NAME );
  2226. tempStrLen /= sizeof( WCHAR );
  2227. if ( tempStrLen > 0 )
  2228. {
  2229. wcscpy( newPathStr, L"\\\\" );
  2230. wcsncat( newPathStr, tempStr, tempStrLen );
  2231. wcscat( newPathStr, L"\\" );
  2232. wcscat( newPathStr, StrippedObjectName );
  2233. }
  2234. (void) LocalFree((HLOCAL) StrippedObjectName );
  2235. StrippedObjectName = NULL;
  2236. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2237. ContextHandle->ContainerName,
  2238. PARSE_NDS_GET_PATH_NAME );
  2239. tempStrLen /= sizeof( WCHAR );
  2240. if ( tempStrLen > 0 )
  2241. {
  2242. wcscat( newPathStr, L"." );
  2243. wcsncat( newPathStr, tempStr, tempStrLen );
  2244. }
  2245. //
  2246. // Pack subtree name into output buffer.
  2247. //
  2248. status = NwWriteNetResourceEntry(
  2249. &FixedPortion,
  2250. &EndOfVariableData,
  2251. NULL,
  2252. NULL,
  2253. newPathStr,
  2254. ResourceScope,
  2255. ResourceDisplayType,
  2256. ResourceUsage,
  2257. ResourceType,
  2258. NULL,
  2259. NULL,
  2260. &EntrySize );
  2261. if ( status == NO_ERROR )
  2262. {
  2263. //
  2264. // Note that we've returned the current entry.
  2265. //
  2266. (*EntriesRead)++;
  2267. }
  2268. if ( newPathStr )
  2269. (void) LocalFree( (HLOCAL) newPathStr );
  2270. break;
  2271. case CLASS_TYPE_ALIAS:
  2272. case CLASS_TYPE_AFP_SERVER:
  2273. case CLASS_TYPE_BINDERY_OBJECT:
  2274. case CLASS_TYPE_BINDERY_QUEUE:
  2275. case CLASS_TYPE_COMPUTER:
  2276. case CLASS_TYPE_GROUP:
  2277. case CLASS_TYPE_LOCALITY:
  2278. case CLASS_TYPE_ORGANIZATIONAL_ROLE:
  2279. case CLASS_TYPE_PRINTER:
  2280. case CLASS_TYPE_PRINT_SERVER:
  2281. case CLASS_TYPE_PROFILE:
  2282. case CLASS_TYPE_QUEUE:
  2283. case CLASS_TYPE_TOP:
  2284. case CLASS_TYPE_UNKNOWN:
  2285. case CLASS_TYPE_USER:
  2286. break;
  2287. default:
  2288. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Disk - Unhandled switch statement case %lu\n", ClassType ));
  2289. ASSERT( FALSE );
  2290. break;
  2291. }
  2292. if (status == WN_MORE_DATA)
  2293. {
  2294. //
  2295. // Could not write current entry into output buffer.
  2296. //
  2297. if (*EntriesRead)
  2298. {
  2299. //
  2300. // Still return success because we got at least one.
  2301. //
  2302. status = NO_ERROR;
  2303. }
  2304. else
  2305. {
  2306. *BytesNeeded = EntrySize;
  2307. }
  2308. FitInBuffer = FALSE;
  2309. }
  2310. else if (status == NO_ERROR)
  2311. {
  2312. //
  2313. // Get next directory entry.
  2314. //
  2315. status = NwGetNextNdsSubTreeEntry( ContextHandle );
  2316. }
  2317. }
  2318. if (status == WN_NO_MORE_ENTRIES)
  2319. {
  2320. ContextHandle->ResumeId = (DWORD_PTR) -1;
  2321. }
  2322. }
  2323. //
  2324. // User asked for more than there are entries. We just say that
  2325. // all is well.
  2326. //
  2327. // This is incompliance with the wierd provider API definition where
  2328. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2329. // at least one entry fit into output buffer, there's no telling if
  2330. // the buffer was too small for more entries or there are no more
  2331. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2332. // before knowing that the last call had actually reached the end of list.
  2333. //
  2334. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  2335. status = NO_ERROR;
  2336. }
  2337. #if DBG
  2338. IF_DEBUG(ENUM)
  2339. {
  2340. KdPrint(("NwEnumNdsSubTrees_Disk returns %lu\n", status));
  2341. }
  2342. #endif
  2343. return status;
  2344. }
  2345. DWORD
  2346. NwEnumNdsSubTrees_Print(
  2347. IN LPNW_ENUM_CONTEXT ContextHandle,
  2348. IN DWORD_PTR EntriesRequested,
  2349. OUT LPBYTE Buffer,
  2350. IN DWORD BufferSize,
  2351. OUT LPDWORD BytesNeeded,
  2352. OUT LPDWORD EntriesRead
  2353. )
  2354. /*++
  2355. Routine Description:
  2356. This function enumerates all the NDS subtree objects that are either containers,
  2357. queues, printers, or servers from a given NDS tree or subtree. The entries are
  2358. returned in an array of PRINTER_INFO_1 entries and each name is prefixed
  2359. by the parent path in NDS UNC style (ex. \\tree\CN=foo.OU=bar.O=blah).
  2360. The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
  2361. enumeration begins and contains the object ID of the last NDS object returned.
  2362. Arguments:
  2363. ContextHandle - Supplies the enum context handle.
  2364. EntriesRequested - Supplies the number of entries to return. If
  2365. this value is (DWORD_PTR) -1, return all available entries.
  2366. Buffer - Receives the entries we are listing.
  2367. BufferSize - Supplies the size of the output buffer.
  2368. BytesNeeded - Receives the number of bytes copied or required to get all
  2369. the requested entries.
  2370. EntriesRead - Receives the number of entries returned in Buffer.
  2371. This value is only returned iff NO_ERROR is the return code.
  2372. Return Value:
  2373. NO_ERROR - Buffer contains all the entries requested.
  2374. WN_NO_MORE_ENTRIES - No entries left to return.
  2375. WN_MORE_DATA - The buffer was too small to fit the requested entries.
  2376. --*/ // NwEnumNdsSubTrees_Print
  2377. {
  2378. DWORD status = NO_ERROR;
  2379. LPBYTE FixedPortion = Buffer;
  2380. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2381. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2382. DWORD EntrySize;
  2383. BOOL FitInBuffer = TRUE;
  2384. LPWSTR SubTreeName = NULL;
  2385. DWORD ResourceScope = 0;
  2386. DWORD ResourceType = 0;
  2387. DWORD ResourceDisplayType = 0;
  2388. DWORD ResourceUsage = 0;
  2389. LPWSTR StrippedObjectName = NULL;
  2390. BYTE ClassType = 0;
  2391. LPWSTR newPathStr = NULL;
  2392. LPWSTR tempStr = NULL;
  2393. WORD tempStrLen = 0;
  2394. while ( EntriesRequested > *EntriesRead &&
  2395. ( (status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER)))
  2396. {
  2397. if (ContextHandle->ResumeId == 0)
  2398. {
  2399. //
  2400. // Get the first subtree entry.
  2401. //
  2402. status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
  2403. }
  2404. //
  2405. // Either ResumeId contains the first entry we just got from
  2406. // NwGetFirstDirectoryEntry or it contains the next directory
  2407. // entry to return.
  2408. //
  2409. if (status == NO_ERROR && ContextHandle->ResumeId != 0)
  2410. {
  2411. //
  2412. // Get current subtree data from ContextHandle
  2413. //
  2414. ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
  2415. &SubTreeName,
  2416. &ResourceScope,
  2417. &ResourceType,
  2418. &ResourceDisplayType,
  2419. &ResourceUsage,
  2420. &StrippedObjectName );
  2421. if ( StrippedObjectName == NULL )
  2422. {
  2423. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print LocalAlloc Failed %lu\n",
  2424. GetLastError()));
  2425. return ERROR_NOT_ENOUGH_MEMORY;
  2426. }
  2427. switch( ClassType )
  2428. {
  2429. case CLASS_TYPE_COUNTRY:
  2430. case CLASS_TYPE_ORGANIZATION:
  2431. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2432. case CLASS_TYPE_NCP_SERVER:
  2433. case CLASS_TYPE_QUEUE:
  2434. //
  2435. // Need to build a string with the new NDS UNC path for subtree object
  2436. //
  2437. newPathStr = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  2438. ( wcslen( StrippedObjectName ) +
  2439. wcslen( ContextHandle->ContainerName ) +
  2440. 2 ) * sizeof(WCHAR) );
  2441. if ( newPathStr == NULL )
  2442. {
  2443. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print LocalAlloc Failed %lu\n",
  2444. GetLastError()));
  2445. return ERROR_NOT_ENOUGH_MEMORY;
  2446. }
  2447. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2448. ContextHandle->ContainerName,
  2449. PARSE_NDS_GET_TREE_NAME );
  2450. tempStrLen /= sizeof( WCHAR );
  2451. if ( tempStrLen > 0 )
  2452. {
  2453. wcsncpy( newPathStr, tempStr, tempStrLen );
  2454. wcscat( newPathStr, L"\\" );
  2455. wcscat( newPathStr, StrippedObjectName );
  2456. }
  2457. (void) LocalFree((HLOCAL) StrippedObjectName );
  2458. StrippedObjectName = NULL;
  2459. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2460. ContextHandle->ContainerName,
  2461. PARSE_NDS_GET_PATH_NAME );
  2462. tempStrLen /= sizeof( WCHAR );
  2463. if ( tempStrLen > 0 )
  2464. {
  2465. wcscat( newPathStr, L"." );
  2466. wcsncat( newPathStr, tempStr, tempStrLen );
  2467. }
  2468. switch( ClassType )
  2469. {
  2470. case CLASS_TYPE_COUNTRY:
  2471. case CLASS_TYPE_ORGANIZATION:
  2472. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2473. //
  2474. // Pack sub-tree container name into output buffer.
  2475. //
  2476. status = NwWritePrinterInfoEntry(
  2477. &FixedPortion,
  2478. &EndOfVariableData,
  2479. NULL,
  2480. newPathStr,
  2481. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1,
  2482. &EntrySize );
  2483. break;
  2484. case CLASS_TYPE_NCP_SERVER:
  2485. //
  2486. // Pack server name into output buffer.
  2487. //
  2488. status = NwWritePrinterInfoEntry(
  2489. &FixedPortion,
  2490. &EndOfVariableData,
  2491. NULL,
  2492. newPathStr,
  2493. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON3,
  2494. &EntrySize );
  2495. break;
  2496. case CLASS_TYPE_QUEUE:
  2497. //
  2498. // Pack print server queue name into output buffer.
  2499. //
  2500. status = NwWritePrinterInfoEntry(
  2501. &FixedPortion,
  2502. &EndOfVariableData,
  2503. L"\\\\",
  2504. newPathStr,
  2505. PRINTER_ENUM_ICON8,
  2506. &EntrySize );
  2507. break;
  2508. default:
  2509. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print - Unhandled switch statement case %lu\n", ClassType ));
  2510. ASSERT(FALSE);
  2511. break;
  2512. }
  2513. switch ( status )
  2514. {
  2515. case ERROR_INSUFFICIENT_BUFFER:
  2516. FitInBuffer = FALSE;
  2517. // Falls through
  2518. case NO_ERROR:
  2519. *BytesNeeded += EntrySize;
  2520. (*EntriesRead)++;
  2521. break;
  2522. default:
  2523. break;
  2524. }
  2525. if ( newPathStr )
  2526. (void) LocalFree( (HLOCAL) newPathStr );
  2527. break;
  2528. case CLASS_TYPE_ALIAS:
  2529. case CLASS_TYPE_AFP_SERVER:
  2530. case CLASS_TYPE_BINDERY_OBJECT:
  2531. case CLASS_TYPE_BINDERY_QUEUE:
  2532. case CLASS_TYPE_COMPUTER:
  2533. case CLASS_TYPE_DIRECTORY_MAP:
  2534. case CLASS_TYPE_GROUP:
  2535. case CLASS_TYPE_LOCALITY:
  2536. case CLASS_TYPE_ORGANIZATIONAL_ROLE:
  2537. case CLASS_TYPE_PRINTER:
  2538. case CLASS_TYPE_PRINT_SERVER:
  2539. case CLASS_TYPE_PROFILE:
  2540. case CLASS_TYPE_TOP:
  2541. case CLASS_TYPE_UNKNOWN:
  2542. case CLASS_TYPE_USER:
  2543. case CLASS_TYPE_VOLUME:
  2544. break;
  2545. default:
  2546. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Print - Unhandled switch statement case %lu\n", ClassType ));
  2547. ASSERT( FALSE );
  2548. break;
  2549. }
  2550. if ( status == NO_ERROR || status == ERROR_INSUFFICIENT_BUFFER )
  2551. {
  2552. //
  2553. // Get next directory entry.
  2554. //
  2555. status = NwGetNextNdsSubTreeEntry( ContextHandle );
  2556. }
  2557. }
  2558. }
  2559. //
  2560. // This is incompliance with the wierd provider API definition where
  2561. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2562. // at least one entry fit into output buffer, there's no telling if
  2563. // the buffer was too small for more entries or there are no more
  2564. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2565. // before knowing that the last call had actually reached the end of list.
  2566. //
  2567. if ( !FitInBuffer )
  2568. {
  2569. *EntriesRead = 0;
  2570. status = ERROR_INSUFFICIENT_BUFFER;
  2571. }
  2572. else if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  2573. {
  2574. status = NO_ERROR;
  2575. }
  2576. return status;
  2577. }
  2578. DWORD
  2579. NwEnumNdsSubTrees_Any(
  2580. IN LPNW_ENUM_CONTEXT ContextHandle,
  2581. IN DWORD_PTR EntriesRequested,
  2582. OUT LPBYTE Buffer,
  2583. IN DWORD BufferSize,
  2584. OUT LPDWORD BytesNeeded,
  2585. OUT LPDWORD EntriesRead
  2586. )
  2587. /*++
  2588. Routine Description:
  2589. This function enumerates the sub-trees of a given NDS tree
  2590. handle. It returns the fully-qualified UNC path of ANY sub-tree
  2591. entries in an array of NETRESOURCE entries.
  2592. The ContextHandle->ResumeId field is 0 initially, and contains
  2593. a pointer to the subtree name string of the last sub-tree
  2594. returned. If there are no more sub-trees to return, this
  2595. field is set to (DWORD_PTR) -1.
  2596. Arguments:
  2597. ContextHandle - Supplies the enum context handle. It contains
  2598. an opened NDS tree handle.
  2599. EntriesRequested - Supplies the number of entries to return. If
  2600. this value is (DWORD_PTR) -1, return all available entries.
  2601. Buffer - Receives the entries we are listing.
  2602. BufferSize - Supplies the size of the output buffer.
  2603. BytesNeeded - Receives the number of bytes required to get the
  2604. first entry. This value is returned iff WN_MORE_DATA is
  2605. the return code, and Buffer is too small to even fit one
  2606. entry.
  2607. EntriesRead - Receives the number of entries returned in Buffer.
  2608. This value is only returned iff NO_ERROR is the return code.
  2609. NO_ERROR is returned as long as at least one entry was written
  2610. into Buffer but does not necessarily mean that it's the number
  2611. of EntriesRequested.
  2612. Return Value:
  2613. NO_ERROR - At least one entry was written to output buffer,
  2614. irregardless of the number requested.
  2615. WN_NO_MORE_ENTRIES - No entries left to return.
  2616. WN_MORE_DATA - The buffer was too small to fit a single entry.
  2617. --*/ // NwEnumNdsSubTrees_Any
  2618. {
  2619. DWORD status = NO_ERROR;
  2620. LPBYTE FixedPortion = Buffer;
  2621. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2622. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2623. BOOL FitInBuffer = TRUE;
  2624. DWORD EntrySize = 0;
  2625. LPWSTR SubTreeName = NULL;
  2626. DWORD ResourceScope = 0;
  2627. DWORD ResourceType = 0;
  2628. DWORD ResourceDisplayType = 0;
  2629. DWORD ResourceUsage = 0;
  2630. LPWSTR StrippedObjectName = NULL;
  2631. if (ContextHandle->ResumeId == (DWORD_PTR) -1)
  2632. {
  2633. //
  2634. // Reached the end of enumeration.
  2635. //
  2636. return WN_NO_MORE_ENTRIES;
  2637. }
  2638. while (FitInBuffer &&
  2639. EntriesRequested > *EntriesRead &&
  2640. status == NO_ERROR)
  2641. {
  2642. if ( ContextHandle->ResumeId == 0 )
  2643. {
  2644. //
  2645. // Get the first subtree entry.
  2646. //
  2647. status = NwGetFirstNdsSubTreeEntry( ContextHandle, BufferSize );
  2648. }
  2649. //
  2650. // Either ResumeId contains the first entry we just got from
  2651. // NwGetFirstDirectoryEntry or it contains the next directory
  2652. // entry to return.
  2653. //
  2654. if (status == NO_ERROR && ContextHandle->ResumeId != 0)
  2655. {
  2656. BYTE ClassType;
  2657. LPWSTR newPathStr = NULL;
  2658. LPWSTR tempStr = NULL;
  2659. WORD tempStrLen;
  2660. //
  2661. // Get current subtree data from ContextHandle
  2662. //
  2663. ClassType = NwGetSubTreeData( ContextHandle->ResumeId,
  2664. &SubTreeName,
  2665. &ResourceScope,
  2666. &ResourceType,
  2667. &ResourceDisplayType,
  2668. &ResourceUsage,
  2669. &StrippedObjectName );
  2670. if ( StrippedObjectName == NULL )
  2671. {
  2672. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any LocalAlloc Failed %lu\n",
  2673. GetLastError()));
  2674. return ERROR_NOT_ENOUGH_MEMORY;
  2675. }
  2676. switch( ClassType )
  2677. {
  2678. case CLASS_TYPE_COUNTRY:
  2679. case CLASS_TYPE_ORGANIZATION:
  2680. case CLASS_TYPE_ORGANIZATIONAL_UNIT:
  2681. case CLASS_TYPE_VOLUME:
  2682. case CLASS_TYPE_DIRECTORY_MAP:
  2683. case CLASS_TYPE_NCP_SERVER:
  2684. case CLASS_TYPE_QUEUE:
  2685. //
  2686. // Need to build a string with the new NDS UNC path for subtree object
  2687. //
  2688. newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  2689. ( wcslen( StrippedObjectName ) +
  2690. wcslen( ContextHandle->ContainerName ) +
  2691. 3 ) * sizeof(WCHAR) );
  2692. if ( newPathStr == NULL )
  2693. {
  2694. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any LocalAlloc Failed %lu\n",
  2695. GetLastError()));
  2696. return ERROR_NOT_ENOUGH_MEMORY;
  2697. }
  2698. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2699. ContextHandle->ContainerName,
  2700. PARSE_NDS_GET_TREE_NAME );
  2701. tempStrLen /= sizeof( WCHAR );
  2702. if ( tempStrLen > 0 )
  2703. {
  2704. wcscpy( newPathStr, L"\\\\" );
  2705. wcsncat( newPathStr, tempStr, tempStrLen );
  2706. wcscat( newPathStr, L"\\" );
  2707. wcscat( newPathStr, StrippedObjectName );
  2708. }
  2709. (void) LocalFree((HLOCAL) StrippedObjectName );
  2710. StrippedObjectName = NULL;
  2711. tempStrLen = NwParseNdsUncPath( (LPWSTR *) &tempStr,
  2712. ContextHandle->ContainerName,
  2713. PARSE_NDS_GET_PATH_NAME );
  2714. tempStrLen /= sizeof( WCHAR );
  2715. if ( tempStrLen > 0 )
  2716. {
  2717. wcscat( newPathStr, L"." );
  2718. wcsncat( newPathStr, tempStr, tempStrLen );
  2719. }
  2720. //
  2721. // Pack subtree name into output buffer.
  2722. //
  2723. status = NwWriteNetResourceEntry(
  2724. &FixedPortion,
  2725. &EndOfVariableData,
  2726. NULL,
  2727. NULL,
  2728. newPathStr,
  2729. ResourceScope,
  2730. ResourceDisplayType,
  2731. ResourceUsage,
  2732. ResourceType,
  2733. NULL,
  2734. NULL,
  2735. &EntrySize );
  2736. if ( status == NO_ERROR )
  2737. {
  2738. //
  2739. // Note that we've returned the current entry.
  2740. //
  2741. (*EntriesRead)++;
  2742. }
  2743. if ( newPathStr )
  2744. (void) LocalFree( (HLOCAL) newPathStr );
  2745. break;
  2746. case CLASS_TYPE_ALIAS:
  2747. case CLASS_TYPE_AFP_SERVER:
  2748. case CLASS_TYPE_BINDERY_OBJECT:
  2749. case CLASS_TYPE_BINDERY_QUEUE:
  2750. case CLASS_TYPE_COMPUTER:
  2751. case CLASS_TYPE_GROUP:
  2752. case CLASS_TYPE_LOCALITY:
  2753. case CLASS_TYPE_ORGANIZATIONAL_ROLE:
  2754. case CLASS_TYPE_PRINTER:
  2755. case CLASS_TYPE_PRINT_SERVER:
  2756. case CLASS_TYPE_PROFILE:
  2757. case CLASS_TYPE_TOP:
  2758. case CLASS_TYPE_UNKNOWN:
  2759. case CLASS_TYPE_USER:
  2760. break;
  2761. default:
  2762. KdPrint(("NWWORKSTATION: NwEnumNdsSubTrees_Any - Unhandled switch statement case %lu\n", ClassType ));
  2763. ASSERT( FALSE );
  2764. break;
  2765. }
  2766. if (status == WN_MORE_DATA)
  2767. {
  2768. //
  2769. // Could not write current entry into output buffer.
  2770. //
  2771. if (*EntriesRead)
  2772. {
  2773. //
  2774. // Still return success because we got at least one.
  2775. //
  2776. status = NO_ERROR;
  2777. }
  2778. else
  2779. {
  2780. *BytesNeeded = EntrySize;
  2781. }
  2782. FitInBuffer = FALSE;
  2783. }
  2784. else if (status == NO_ERROR)
  2785. {
  2786. //
  2787. // Get next directory entry.
  2788. //
  2789. status = NwGetNextNdsSubTreeEntry( ContextHandle );
  2790. }
  2791. }
  2792. if (status == WN_NO_MORE_ENTRIES)
  2793. {
  2794. ContextHandle->ResumeId = (DWORD_PTR) -1;
  2795. }
  2796. }
  2797. //
  2798. // User asked for more than there are entries. We just say that
  2799. // all is well.
  2800. //
  2801. // This is incompliance with the wierd provider API definition where
  2802. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  2803. // at least one entry fit into output buffer, there's no telling if
  2804. // the buffer was too small for more entries or there are no more
  2805. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  2806. // before knowing that the last call had actually reached the end of list.
  2807. //
  2808. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  2809. status = NO_ERROR;
  2810. }
  2811. #if DBG
  2812. IF_DEBUG(ENUM)
  2813. {
  2814. KdPrint(("NwEnumNdsSubTrees_Any returns %lu\n", status));
  2815. }
  2816. #endif
  2817. return status;
  2818. }
  2819. DWORD
  2820. NwEnumVolumesQueues(
  2821. IN LPNW_ENUM_CONTEXT ContextHandle,
  2822. IN DWORD_PTR EntriesRequested,
  2823. OUT LPBYTE Buffer,
  2824. IN DWORD BufferSize,
  2825. OUT LPDWORD BytesNeeded,
  2826. OUT LPDWORD EntriesRead
  2827. )
  2828. /*++
  2829. Routine Description:
  2830. This function enumerates all the volumes and queues on a server.
  2831. The queue entries are returned in an array of NETRESOURCE entries;
  2832. each queue name is prefixed by \\Server\.
  2833. Arguments:
  2834. ContextHandle - Supplies the enum context handle.
  2835. EntriesRequested - Supplies the number of entries to return. If
  2836. this value is (DWORD_PTR) -1, return all available entries.
  2837. Buffer - Receives the entries we are listing.
  2838. BufferSize - Supplies the size of the output buffer.
  2839. BytesNeeded - Receives the number of bytes required to get the
  2840. first entry. This value is returned if WN_MORE_DATA is
  2841. the return code, and Buffer is too small to even fit one
  2842. entry.
  2843. EntriesRead - Receives the number of entries returned in Buffer.
  2844. This value is only returned iff NO_ERROR is the return code.
  2845. NO_ERROR is returned as long as at least one entry was written
  2846. into Buffer but does not necessarily mean that it's the number
  2847. of EntriesRequested.
  2848. Return Value:
  2849. NO_ERROR - At least one entry was written to output buffer,
  2850. irregardless of the number requested.
  2851. WN_NO_MORE_ENTRIES - No entries left to return.
  2852. WN_MORE_DATA - The buffer was too small to fit a single entry.
  2853. --*/ // NwEnumVolumesQueues
  2854. {
  2855. DWORD status = NO_ERROR;
  2856. LPBYTE FixedPortion = Buffer;
  2857. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  2858. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  2859. BOOL FitInBuffer = TRUE;
  2860. DWORD EntrySize;
  2861. CHAR VolumeName[NW_VOLUME_NAME_LEN]; // OEM volume name
  2862. LPWSTR UVolumeName = NULL; // Unicode volume name
  2863. DWORD NextObject = (DWORD) ContextHandle->ResumeId;
  2864. DWORD MaxVolumeNumber = ContextHandle->dwMaxVolumes;
  2865. ULONG Failures = 0;
  2866. //
  2867. // tommye - bug 139466
  2868. //
  2869. // removed if (NextObject >= 0) becaue NextObject is a DWORD
  2870. //
  2871. while (FitInBuffer &&
  2872. EntriesRequested > *EntriesRead &&
  2873. ContextHandle->ConnectionType == CONNTYPE_DISK &&
  2874. (NextObject < MaxVolumeNumber) &&
  2875. status == NO_ERROR) {
  2876. RtlZeroMemory(VolumeName, sizeof(VolumeName));
  2877. //
  2878. // Call the scan bindery object NCP to scan for all file
  2879. // volume objects.
  2880. //
  2881. status = NwGetNextVolumeEntry(
  2882. ContextHandle->TreeConnectionHandle,
  2883. NextObject++,
  2884. VolumeName
  2885. );
  2886. if (status == NO_ERROR) {
  2887. if (VolumeName[0] == 0) {
  2888. //
  2889. // Got an empty volume name back for the next volume number
  2890. // which indicates there is no volume associated with the
  2891. // volume number but still got error success.
  2892. //
  2893. // Treat this as having reached the end of the enumeration
  2894. // if we have had three failures in a row. This will allow
  2895. // us to function when there are small holes in the drive
  2896. // list.
  2897. //
  2898. Failures++;
  2899. if ( Failures <= 3 ) {
  2900. continue;
  2901. } else {
  2902. NextObject = (DWORD) -1;
  2903. ContextHandle->ResumeId = (DWORD_PTR) -1;
  2904. ContextHandle->ConnectionType = CONNTYPE_PRINT;
  2905. }
  2906. } else if (NwConvertToUnicode(&UVolumeName, VolumeName)) {
  2907. //
  2908. // Pack volume name into output buffer.
  2909. //
  2910. status = NwWriteNetResourceEntry(
  2911. &FixedPortion,
  2912. &EndOfVariableData,
  2913. ContextHandle->ContainerName,
  2914. NULL,
  2915. UVolumeName,
  2916. RESOURCE_GLOBALNET,
  2917. RESOURCEDISPLAYTYPE_SHARE,
  2918. #ifdef NT1057
  2919. RESOURCEUSAGE_CONNECTABLE |
  2920. RESOURCEUSAGE_CONTAINER,
  2921. #else
  2922. RESOURCEUSAGE_CONNECTABLE |
  2923. RESOURCEUSAGE_NOLOCALDEVICE,
  2924. #endif
  2925. RESOURCETYPE_DISK,
  2926. NULL,
  2927. NULL,
  2928. &EntrySize
  2929. );
  2930. if (status == WN_MORE_DATA) {
  2931. //
  2932. // Could not write current entry into output buffer.
  2933. //
  2934. if (*EntriesRead) {
  2935. //
  2936. // Still return success because we got at least one.
  2937. //
  2938. status = NO_ERROR;
  2939. }
  2940. else {
  2941. *BytesNeeded = EntrySize;
  2942. }
  2943. FitInBuffer = FALSE;
  2944. }
  2945. else if (status == NO_ERROR) {
  2946. //
  2947. // Note that we've returned the current entry.
  2948. //
  2949. (*EntriesRead)++;
  2950. ContextHandle->ResumeId = NextObject;
  2951. }
  2952. (void) LocalFree((HLOCAL) UVolumeName);
  2953. }
  2954. //
  2955. // Reset the failures counter.
  2956. //
  2957. Failures = 0;
  2958. }
  2959. }
  2960. //
  2961. // User asked for more than there are entries. We just say that
  2962. // all is well.
  2963. //
  2964. if (*EntriesRead && status == WN_NO_MORE_ENTRIES)
  2965. {
  2966. status = NO_ERROR;
  2967. }
  2968. if ( *EntriesRead == 0 &&
  2969. status == NO_ERROR &&
  2970. ContextHandle->ConnectionType == CONNTYPE_DISK )
  2971. {
  2972. ContextHandle->ConnectionType = CONNTYPE_PRINT;
  2973. ContextHandle->ResumeId = (DWORD_PTR) -1;
  2974. }
  2975. //
  2976. // The user needs to be validated on a netware311 server to
  2977. // get the print queues. So, we need to close the handle and
  2978. // open a new one with WRITE access. If any error occurred while
  2979. // we are enumerating the print queues, we will abort and
  2980. // assume there are no print queues on the server.
  2981. //
  2982. if ( FitInBuffer &&
  2983. EntriesRequested > *EntriesRead &&
  2984. ContextHandle->ConnectionType == CONNTYPE_PRINT &&
  2985. status == NO_ERROR )
  2986. {
  2987. UNICODE_STRING TreeConnectStr;
  2988. DWORD QueueEntriesRead = 0;
  2989. (void) NtClose(ContextHandle->TreeConnectionHandle);
  2990. //
  2991. // Open a tree connection handle to \Device\NwRdr\ContainerName
  2992. //
  2993. status = NwCreateTreeConnectName(
  2994. ContextHandle->ContainerName,
  2995. NULL,
  2996. &TreeConnectStr );
  2997. if (status != NO_ERROR)
  2998. return (*EntriesRead? NO_ERROR: WN_NO_MORE_ENTRIES );
  2999. status = NwOpenCreateConnection(
  3000. &TreeConnectStr,
  3001. NULL,
  3002. NULL,
  3003. ContextHandle->ContainerName,
  3004. FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_DATA,
  3005. FILE_OPEN,
  3006. FILE_SYNCHRONOUS_IO_NONALERT,
  3007. RESOURCETYPE_PRINT, // Only matters when connecting beyond servername
  3008. &ContextHandle->TreeConnectionHandle,
  3009. NULL );
  3010. (void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
  3011. if (status != NO_ERROR)
  3012. return (*EntriesRead? NO_ERROR: WN_NO_MORE_ENTRIES );
  3013. status = NwEnumQueues(
  3014. ContextHandle,
  3015. EntriesRequested == (DWORD_PTR) -1?
  3016. EntriesRequested : (EntriesRequested - *EntriesRead),
  3017. FixedPortion,
  3018. (DWORD) ((LPBYTE) EndOfVariableData - (LPBYTE) FixedPortion),
  3019. BytesNeeded,
  3020. &QueueEntriesRead );
  3021. if ( status == NO_ERROR )
  3022. {
  3023. *EntriesRead += QueueEntriesRead;
  3024. }
  3025. else if ( *EntriesRead )
  3026. {
  3027. //
  3028. // As long as we read something into the buffer,
  3029. // we should return success.
  3030. //
  3031. status = NO_ERROR;
  3032. *BytesNeeded = 0;
  3033. }
  3034. }
  3035. if ( status == NO_ERROR &&
  3036. *EntriesRead == 0 &&
  3037. ContextHandle->ConnectionType == CONNTYPE_PRINT )
  3038. {
  3039. return WN_NO_MORE_ENTRIES;
  3040. }
  3041. return status;
  3042. }
  3043. DWORD
  3044. NwEnumQueues(
  3045. IN LPNW_ENUM_CONTEXT ContextHandle,
  3046. IN DWORD_PTR EntriesRequested,
  3047. OUT LPBYTE Buffer,
  3048. IN DWORD BufferSize,
  3049. OUT LPDWORD BytesNeeded,
  3050. OUT LPDWORD EntriesRead
  3051. )
  3052. /*++
  3053. Routine Description:
  3054. This function enumerates all the queues on a server.
  3055. The queue entries are returned in an array of NETRESOURCE entries;
  3056. each queue name is prefixed by \\Server\.
  3057. Arguments:
  3058. ContextHandle - Supplies the enum context handle.
  3059. EntriesRequested - Supplies the number of entries to return. If
  3060. this value is (DWORD_PTR) -1, return all available entries.
  3061. Buffer - Receives the entries we are listing.
  3062. BufferSize - Supplies the size of the output buffer.
  3063. BytesNeeded - Receives the number of bytes required to get the
  3064. first entry. This value is returned iff WN_MORE_DATA is
  3065. the return code, and Buffer is too small to even fit one
  3066. entry.
  3067. EntriesRead - Receives the number of entries returned in Buffer.
  3068. This value is only returned iff NO_ERROR is the return code.
  3069. NO_ERROR is returned as long as at least one entry was written
  3070. into Buffer but does not necessarily mean that it's the number
  3071. of EntriesRequested.
  3072. Return Value:
  3073. NO_ERROR - At least one entry was written to output buffer,
  3074. irregardless of the number requested.
  3075. WN_NO_MORE_ENTRIES - No entries left to return.
  3076. WN_MORE_DATA - The buffer was too small to fit a single entry.
  3077. --*/ // NwEnumQueues
  3078. {
  3079. DWORD status = NO_ERROR;
  3080. LPBYTE FixedPortion = Buffer;
  3081. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3082. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3083. BOOL FitInBuffer = TRUE;
  3084. DWORD EntrySize;
  3085. DWORD NextObject = (DWORD) ContextHandle->ResumeId;
  3086. SERVERNAME QueueName; // OEM queue name
  3087. LPWSTR UQueueName = NULL; // Unicode queue name
  3088. while ( FitInBuffer &&
  3089. EntriesRequested > *EntriesRead &&
  3090. status == NO_ERROR ) {
  3091. RtlZeroMemory(QueueName, sizeof(QueueName));
  3092. //
  3093. // Call the scan bindery object NCP to scan for all file
  3094. // volume objects.
  3095. //
  3096. status = NwGetNextQueueEntry(
  3097. ContextHandle->TreeConnectionHandle,
  3098. &NextObject,
  3099. QueueName
  3100. );
  3101. if (status == NO_ERROR && NwConvertToUnicode(&UQueueName, QueueName)) {
  3102. //
  3103. // Pack server name into output buffer.
  3104. //
  3105. status = NwWriteNetResourceEntry(
  3106. &FixedPortion,
  3107. &EndOfVariableData,
  3108. ContextHandle->ContainerName,
  3109. NULL,
  3110. UQueueName,
  3111. RESOURCE_GLOBALNET,
  3112. RESOURCEDISPLAYTYPE_SHARE,
  3113. RESOURCEUSAGE_CONNECTABLE,
  3114. RESOURCETYPE_PRINT,
  3115. NULL,
  3116. NULL,
  3117. &EntrySize
  3118. );
  3119. if (status == WN_MORE_DATA) {
  3120. //
  3121. // Could not write current entry into output buffer.
  3122. //
  3123. if (*EntriesRead) {
  3124. //
  3125. // Still return success because we got at least one.
  3126. //
  3127. status = NO_ERROR;
  3128. }
  3129. else {
  3130. *BytesNeeded = EntrySize;
  3131. }
  3132. FitInBuffer = FALSE;
  3133. }
  3134. else if (status == NO_ERROR) {
  3135. //
  3136. // Note that we've returned the current entry.
  3137. //
  3138. (*EntriesRead)++;
  3139. ContextHandle->ResumeId = (DWORD_PTR) NextObject;
  3140. }
  3141. (void) LocalFree((HLOCAL) UQueueName);
  3142. }
  3143. }
  3144. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3145. status = NO_ERROR;
  3146. }
  3147. return status;
  3148. }
  3149. DWORD
  3150. NwEnumDirectories(
  3151. IN LPNW_ENUM_CONTEXT ContextHandle,
  3152. IN DWORD_PTR EntriesRequested,
  3153. OUT LPBYTE Buffer,
  3154. IN DWORD BufferSize,
  3155. OUT LPDWORD BytesNeeded,
  3156. OUT LPDWORD EntriesRead
  3157. )
  3158. /*++
  3159. Routine Description:
  3160. This function enumerates the directories of a given directory
  3161. handle by calling NtQueryDirectoryFile. It returns the
  3162. fully-qualified UNC path of the directory entries in an array
  3163. of NETRESOURCE entries.
  3164. The ContextHandle->ResumeId field is 0 initially, and contains
  3165. a pointer to the directory name string of the last directory
  3166. returned. If there are no more directories to return, this
  3167. field is set to (DWORD_PTR) -1.
  3168. Arguments:
  3169. ContextHandle - Supplies the enum context handle. It contains
  3170. an opened directory handle.
  3171. EntriesRequested - Supplies the number of entries to return. If
  3172. this value is (DWORD_PTR) -1, return all available entries.
  3173. Buffer - Receives the entries we are listing.
  3174. BufferSize - Supplies the size of the output buffer.
  3175. BytesNeeded - Receives the number of bytes required to get the
  3176. first entry. This value is returned iff WN_MORE_DATA is
  3177. the return code, and Buffer is too small to even fit one
  3178. entry.
  3179. EntriesRead - Receives the number of entries returned in Buffer.
  3180. This value is only returned iff NO_ERROR is the return code.
  3181. NO_ERROR is returned as long as at least one entry was written
  3182. into Buffer but does not necessarily mean that it's the number
  3183. of EntriesRequested.
  3184. Return Value:
  3185. NO_ERROR - At least one entry was written to output buffer,
  3186. irregardless of the number requested.
  3187. WN_NO_MORE_ENTRIES - No entries left to return.
  3188. WN_MORE_DATA - The buffer was too small to fit a single entry.
  3189. --*/ // NwEnumDirectories
  3190. {
  3191. DWORD status = NO_ERROR;
  3192. LPBYTE FixedPortion = Buffer;
  3193. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3194. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3195. BOOL FitInBuffer = TRUE;
  3196. DWORD EntrySize;
  3197. if (ContextHandle->ResumeId == (DWORD_PTR) -1) {
  3198. //
  3199. // Reached the end of enumeration.
  3200. //
  3201. return WN_NO_MORE_ENTRIES;
  3202. }
  3203. while (FitInBuffer &&
  3204. EntriesRequested > *EntriesRead &&
  3205. status == NO_ERROR) {
  3206. if (ContextHandle->ResumeId == 0) {
  3207. //
  3208. // Get the first directory entry.
  3209. //
  3210. status = NwGetFirstDirectoryEntry(
  3211. ContextHandle->TreeConnectionHandle,
  3212. (LPWSTR *) &ContextHandle->ResumeId
  3213. );
  3214. }
  3215. //
  3216. // Either ResumeId contains the first entry we just got from
  3217. // NwGetFirstDirectoryEntry or it contains the next directory
  3218. // entry to return.
  3219. //
  3220. if (ContextHandle->ResumeId != 0) {
  3221. //
  3222. // Pack directory name into output buffer.
  3223. //
  3224. status = NwWriteNetResourceEntry(
  3225. &FixedPortion,
  3226. &EndOfVariableData,
  3227. ContextHandle->ContainerName,
  3228. NULL,
  3229. (LPWSTR) ContextHandle->ResumeId,
  3230. RESOURCE_GLOBALNET,
  3231. RESOURCEDISPLAYTYPE_SHARE,
  3232. #ifdef NT1057
  3233. RESOURCEUSAGE_CONNECTABLE |
  3234. RESOURCEUSAGE_CONTAINER,
  3235. #else
  3236. RESOURCEUSAGE_CONNECTABLE |
  3237. RESOURCEUSAGE_NOLOCALDEVICE,
  3238. #endif
  3239. RESOURCETYPE_DISK,
  3240. NULL,
  3241. NULL,
  3242. &EntrySize
  3243. );
  3244. if (status == WN_MORE_DATA) {
  3245. //
  3246. // Could not write current entry into output buffer.
  3247. //
  3248. if (*EntriesRead) {
  3249. //
  3250. // Still return success because we got at least one.
  3251. //
  3252. status = NO_ERROR;
  3253. }
  3254. else {
  3255. *BytesNeeded = EntrySize;
  3256. }
  3257. FitInBuffer = FALSE;
  3258. }
  3259. else if (status == NO_ERROR) {
  3260. //
  3261. // Note that we've returned the current entry.
  3262. //
  3263. (*EntriesRead)++;
  3264. //
  3265. // Free memory allocated to save resume point, which is
  3266. // a buffer that contains the last directory we returned.
  3267. //
  3268. if (ContextHandle->ResumeId != 0) {
  3269. (void) LocalFree((HLOCAL) ContextHandle->ResumeId);
  3270. ContextHandle->ResumeId = 0;
  3271. }
  3272. //
  3273. // Get next directory entry.
  3274. //
  3275. status = NwGetNextDirectoryEntry(
  3276. (LPWSTR) ContextHandle->TreeConnectionHandle,
  3277. (LPWSTR *) &ContextHandle->ResumeId
  3278. );
  3279. }
  3280. }
  3281. if (status == WN_NO_MORE_ENTRIES) {
  3282. ContextHandle->ResumeId = (DWORD_PTR) -1;
  3283. }
  3284. }
  3285. //
  3286. // User asked for more than there are entries. We just say that
  3287. // all is well.
  3288. //
  3289. // This is incompliance with the wierd provider API definition where
  3290. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3291. // at least one entry fit into output buffer, there's no telling if
  3292. // the buffer was too small for more entries or there are no more
  3293. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  3294. // before knowing that the last call had actually reached the end of list.
  3295. //
  3296. if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3297. status = NO_ERROR;
  3298. }
  3299. #if DBG
  3300. IF_DEBUG(ENUM) {
  3301. KdPrint(("EnumDirectories returns %lu\n", status));
  3302. }
  3303. #endif
  3304. return status;
  3305. }
  3306. DWORD
  3307. NwEnumPrintServers(
  3308. IN LPNW_ENUM_CONTEXT ContextHandle,
  3309. IN DWORD_PTR EntriesRequested,
  3310. OUT LPBYTE Buffer,
  3311. IN DWORD BufferSize,
  3312. OUT LPDWORD BytesNeeded,
  3313. OUT LPDWORD EntriesRead
  3314. )
  3315. /*++
  3316. Routine Description:
  3317. This function enumerates all the servers and NDS tree on the local network
  3318. by scanning the bindery for file server or directory objects on the
  3319. preferred server. The server and tree entries are returned in an
  3320. array of PRINTER_INFO_1 entries; each entry name is prefixed by
  3321. \\.
  3322. The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
  3323. enumeration begins and contains the object ID of the last server
  3324. object returned.
  3325. Arguments:
  3326. ContextHandle - Supplies the enum context handle.
  3327. EntriesRequested - Supplies the number of entries to return. If
  3328. this value is (DWORD_PTR) -1, return all available entries.
  3329. Buffer - Receives the entries we are listing.
  3330. BufferSize - Supplies the size of the output buffer.
  3331. BytesNeeded - Receives the number of bytes copied or required to get all
  3332. the requested entries.
  3333. EntriesRead - Receives the number of entries returned in Buffer.
  3334. This value is only returned iff NO_ERROR is the return code.
  3335. Return Value:
  3336. NO_ERROR - Buffer contains all the entries requested.
  3337. WN_NO_MORE_ENTRIES - No entries left to return.
  3338. WN_MORE_DATA - The buffer was too small to fit the requested entries.
  3339. --*/ // NwEnumPrintServers
  3340. {
  3341. DWORD status = NO_ERROR;
  3342. LPBYTE FixedPortion = Buffer;
  3343. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3344. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3345. DWORD EntrySize;
  3346. BOOL FitInBuffer = TRUE;
  3347. SERVERNAME ServerName; // OEM server name
  3348. LPWSTR UServerName = NULL; // Unicode server name
  3349. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  3350. WCHAR TempBuffer[500];
  3351. while ( EntriesRequested > *EntriesRead &&
  3352. ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NDS &&
  3353. ((status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER)))
  3354. {
  3355. //
  3356. // Call the scan bindery object NCP to scan for all NDS
  3357. // tree objects.
  3358. //
  3359. status = NwGetNextNdsTreeEntry( ContextHandle );
  3360. if ( status == NO_ERROR && ContextHandle->ResumeId != 0 )
  3361. {
  3362. //
  3363. // Put tree name into a buffer
  3364. //
  3365. RtlZeroMemory( TempBuffer, 500 );
  3366. wcscat( TempBuffer, (LPWSTR) ContextHandle->ResumeId );
  3367. //
  3368. // Pack server name into output buffer.
  3369. //
  3370. status = NwWritePrinterInfoEntry(
  3371. &FixedPortion,
  3372. &EndOfVariableData,
  3373. NULL,
  3374. TempBuffer, // This is a NDS tree name
  3375. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON1,
  3376. &EntrySize
  3377. );
  3378. switch ( status )
  3379. {
  3380. case ERROR_INSUFFICIENT_BUFFER:
  3381. FitInBuffer = FALSE;
  3382. // Falls through
  3383. case NO_ERROR:
  3384. *BytesNeeded += EntrySize;
  3385. (*EntriesRead)++;
  3386. // ContextHandle->ResumeId = LastObjectId;
  3387. break;
  3388. default:
  3389. break;
  3390. }
  3391. }
  3392. else if ( status == WN_NO_MORE_ENTRIES )
  3393. {
  3394. //
  3395. // We processed the last item in list, so
  3396. // start enumerating servers.
  3397. //
  3398. ContextHandle->dwUsingNds = CURRENTLY_ENUMERATING_NON_NDS;
  3399. ContextHandle->ResumeId = (DWORD_PTR) -1;
  3400. LastObjectId = (DWORD) -1;
  3401. }
  3402. }
  3403. status = NO_ERROR;
  3404. while ( EntriesRequested > *EntriesRead &&
  3405. ContextHandle->dwUsingNds == CURRENTLY_ENUMERATING_NON_NDS &&
  3406. ((status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER))) {
  3407. RtlZeroMemory(ServerName, sizeof(ServerName));
  3408. //
  3409. // Call the scan bindery object NCP to scan for all file
  3410. // server objects.
  3411. //
  3412. status = NwGetNextServerEntry(
  3413. ContextHandle->TreeConnectionHandle,
  3414. &LastObjectId,
  3415. ServerName
  3416. );
  3417. if (status == NO_ERROR && NwConvertToUnicode(&UServerName,ServerName)) {
  3418. //
  3419. // Pack server name into output buffer.
  3420. //
  3421. status = NwWritePrinterInfoEntry(
  3422. &FixedPortion,
  3423. &EndOfVariableData,
  3424. NULL,
  3425. UServerName,
  3426. PRINTER_ENUM_CONTAINER | PRINTER_ENUM_ICON3,
  3427. &EntrySize
  3428. );
  3429. switch ( status )
  3430. {
  3431. case ERROR_INSUFFICIENT_BUFFER:
  3432. FitInBuffer = FALSE;
  3433. // Falls through
  3434. case NO_ERROR:
  3435. *BytesNeeded += EntrySize;
  3436. (*EntriesRead)++;
  3437. ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
  3438. break;
  3439. default:
  3440. break;
  3441. }
  3442. (void) LocalFree((HLOCAL) UServerName);
  3443. }
  3444. }
  3445. //
  3446. // This is incompliance with the wierd provider API definition where
  3447. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3448. // at least one entry fit into output buffer, there's no telling if
  3449. // the buffer was too small for more entries or there are no more
  3450. //
  3451. // This is incompliance with the wierd provider API definition where
  3452. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3453. // at least one entry fit into output buffer, there's no telling if
  3454. // the buffer was too small for more entries or there are no more
  3455. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  3456. // before knowing that the last call had actually reached the end of list.
  3457. //
  3458. if ( !FitInBuffer ) {
  3459. *EntriesRead = 0;
  3460. status = ERROR_INSUFFICIENT_BUFFER;
  3461. }
  3462. else if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3463. status = NO_ERROR;
  3464. }
  3465. return status;
  3466. }
  3467. DWORD
  3468. NwEnumPrintQueues(
  3469. IN LPNW_ENUM_CONTEXT ContextHandle,
  3470. IN DWORD_PTR EntriesRequested,
  3471. OUT LPBYTE Buffer,
  3472. IN DWORD BufferSize,
  3473. OUT LPDWORD BytesNeeded,
  3474. OUT LPDWORD EntriesRead
  3475. )
  3476. /*++
  3477. Routine Description:
  3478. This function enumerates all the print queues on a server by scanning
  3479. the bindery on the server for print queues objects.
  3480. The print queues entries are returned in an array of PRINTER_INFO_1 entries
  3481. and each printer name is prefixed by \\Server\.
  3482. The ContextHandle->ResumeId field is initially (DWORD_PTR) -1 before
  3483. enumeration begins and contains the object ID of the last print queue
  3484. object returned.
  3485. Arguments:
  3486. ContextHandle - Supplies the enum context handle.
  3487. EntriesRequested - Supplies the number of entries to return. If
  3488. this value is (DWORD_PTR) -1, return all available entries.
  3489. Buffer - Receives the entries we are listing.
  3490. BufferSize - Supplies the size of the output buffer.
  3491. BytesNeeded - Receives the number of bytes copied or required to get all
  3492. the requested entries.
  3493. EntriesRead - Receives the number of entries returned in Buffer.
  3494. This value is only returned iff NO_ERROR is the return code.
  3495. Return Value:
  3496. NO_ERROR - Buffer contains all the entries requested.
  3497. WN_NO_MORE_ENTRIES - No entries left to return.
  3498. WN_MORE_DATA - The buffer was too small to fit the requested entries.
  3499. --*/ // NwEnumPrintQueues
  3500. {
  3501. DWORD status = NO_ERROR;
  3502. LPBYTE FixedPortion = Buffer;
  3503. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3504. ROUND_DOWN_COUNT(BufferSize,ALIGN_DWORD));
  3505. DWORD EntrySize;
  3506. BOOL FitInBuffer = TRUE;
  3507. SERVERNAME QueueName; // OEM queue name
  3508. LPWSTR UQueueName = NULL; // Unicode queue name
  3509. DWORD LastObjectId = (DWORD) ContextHandle->ResumeId;
  3510. while ( EntriesRequested > *EntriesRead &&
  3511. ( (status == NO_ERROR) || (status == ERROR_INSUFFICIENT_BUFFER))) {
  3512. RtlZeroMemory(QueueName, sizeof(QueueName));
  3513. //
  3514. // Call the scan bindery object NCP to scan for all file
  3515. // volume objects.
  3516. //
  3517. status = NwGetNextQueueEntry(
  3518. ContextHandle->TreeConnectionHandle,
  3519. &LastObjectId,
  3520. QueueName
  3521. );
  3522. if (status == NO_ERROR && NwConvertToUnicode(&UQueueName, QueueName)) {
  3523. //
  3524. // Pack server name into output buffer.
  3525. //
  3526. status = NwWritePrinterInfoEntry(
  3527. &FixedPortion,
  3528. &EndOfVariableData,
  3529. ContextHandle->ContainerName,
  3530. UQueueName,
  3531. PRINTER_ENUM_ICON8,
  3532. &EntrySize
  3533. );
  3534. switch ( status )
  3535. {
  3536. case ERROR_INSUFFICIENT_BUFFER:
  3537. FitInBuffer = FALSE;
  3538. // Falls through
  3539. case NO_ERROR:
  3540. *BytesNeeded += EntrySize;
  3541. (*EntriesRead)++;
  3542. ContextHandle->ResumeId = (DWORD_PTR) LastObjectId;
  3543. break;
  3544. default:
  3545. break;
  3546. }
  3547. (void) LocalFree((HLOCAL) UQueueName);
  3548. }
  3549. }
  3550. //
  3551. // This is incompliance with the wierd provider API definition where
  3552. // if user gets NO_ERROR, and EntriesRequested > *EntriesRead, and
  3553. // at least one entry fit into output buffer, there's no telling if
  3554. // the buffer was too small for more entries or there are no more
  3555. // entries. The user has to call this API again and get WN_NO_MORE_ENTRIES
  3556. // before knowing that the last call had actually reached the end of list.
  3557. //
  3558. if ( !FitInBuffer ) {
  3559. *EntriesRead = 0;
  3560. status = ERROR_INSUFFICIENT_BUFFER;
  3561. }
  3562. else if (*EntriesRead && status == WN_NO_MORE_ENTRIES) {
  3563. status = NO_ERROR;
  3564. }
  3565. return status;
  3566. }
  3567. DWORD
  3568. NwrCloseEnum(
  3569. IN OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  3570. )
  3571. /*++
  3572. Routine Description:
  3573. This function closes an enum context handle.
  3574. Arguments:
  3575. EnumHandle - Supplies a pointer to the enum context handle.
  3576. Return Value:
  3577. WN_BAD_HANDLE - Handle is not recognizable.
  3578. NO_ERROR - Call was successful.
  3579. --*/ // NwrCloseEnum
  3580. {
  3581. LPNW_ENUM_CONTEXT ContextHandle = (LPNW_ENUM_CONTEXT) *EnumHandle;
  3582. DWORD status = NO_ERROR ;
  3583. #if DBG
  3584. IF_DEBUG(ENUM)
  3585. {
  3586. KdPrint(("\nNWWORKSTATION: NwrCloseEnum\n"));
  3587. }
  3588. #endif
  3589. if (ContextHandle->Signature != NW_HANDLE_SIGNATURE)
  3590. {
  3591. ASSERT(FALSE);
  3592. return WN_BAD_HANDLE;
  3593. }
  3594. //
  3595. // Resume handle for listing directories is a buffer which contains
  3596. // the last directory returned.
  3597. //
  3598. if (ContextHandle->HandleType == NwsHandleListDirectories &&
  3599. ContextHandle->ResumeId != 0 &&
  3600. ContextHandle->ResumeId != (DWORD_PTR) -1)
  3601. {
  3602. (void) LocalFree((HLOCAL) ContextHandle->ResumeId);
  3603. }
  3604. //
  3605. // NdsRawDataBuffer handle for listing NDS tree subordinates is a buffer which contains
  3606. // the last data chunk returned from redirector.
  3607. //
  3608. if ( ( ContextHandle->HandleType == NwsHandleListNdsSubTrees_Disk ||
  3609. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Print ||
  3610. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Any ||
  3611. ContextHandle->HandleType == NwsHandleListServersAndNdsTrees ) &&
  3612. ContextHandle->NdsRawDataBuffer )
  3613. {
  3614. (void) LocalFree((HLOCAL) ContextHandle->NdsRawDataBuffer);
  3615. ContextHandle->NdsRawDataBuffer = 0;
  3616. }
  3617. if (ContextHandle->TreeConnectionHandle != (HANDLE) NULL)
  3618. {
  3619. if (ContextHandle->HandleType == NwsHandleListDirectories)
  3620. {
  3621. //
  3622. // Delete the UNC connection created so that we can browse
  3623. // directories.
  3624. //
  3625. (void) NwNukeConnection(ContextHandle->TreeConnectionHandle, TRUE);
  3626. }
  3627. if ( ContextHandle->HandleType == NwsHandleListNdsSubTrees_Disk ||
  3628. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Print ||
  3629. ContextHandle->HandleType == NwsHandleListNdsSubTrees_Any )
  3630. {
  3631. //
  3632. // Get rid of the connection to the NDS tree.
  3633. //
  3634. (void) CloseHandle(ContextHandle->TreeConnectionHandle);
  3635. ContextHandle->TreeConnectionHandle = 0;
  3636. }
  3637. else
  3638. {
  3639. (void) NtClose(ContextHandle->TreeConnectionHandle);
  3640. ContextHandle->TreeConnectionHandle = 0;
  3641. }
  3642. }
  3643. ContextHandle->Signature = 0x0BADBAD0;
  3644. (void) LocalFree((HLOCAL) ContextHandle);
  3645. *EnumHandle = NULL;
  3646. return status;
  3647. }
  3648. DWORD
  3649. NwrGetUser(
  3650. IN LPWSTR Reserved OPTIONAL,
  3651. IN LPWSTR lpName,
  3652. OUT LPBYTE lpUserName,
  3653. IN DWORD dwUserNameBufferSize,
  3654. OUT LPDWORD lpdwCharsRequired
  3655. )
  3656. /*++
  3657. Routine Description:
  3658. This is used to determine either the current default username, or the
  3659. username used to establish a network connection.
  3660. Arguments:
  3661. Reserved - Unused.
  3662. lpName - The connection for which user information is requested.
  3663. lpUserName - The buffer to receive the user name associated with the
  3664. connection referred to by lpName.
  3665. dwUserNameLen - The size of the buffer lpUserName.
  3666. lpdwCharsRequired - If return status is WN_MORE_DATA, then this is set to
  3667. the value which indicates the number of characters that the buffer
  3668. lpUserName must hold. Otherwise, this is not set.
  3669. Return Value:
  3670. WN_SUCCESS - If the call is successful. Otherwise, an error code is,
  3671. returned, which may include:
  3672. WN_NOT_CONNECTED - lpName not a redirected device nor a connected network
  3673. name.
  3674. WN_MORE_DATA - The buffer is too small.
  3675. --*/ // NwrGetUser
  3676. {
  3677. DWORD status = NO_ERROR;
  3678. WCHAR lpTempUserName[512];
  3679. WCHAR lpTempHostName[512];
  3680. if (lpName == NULL)
  3681. {
  3682. return ERROR_INVALID_PARAMETER;
  3683. }
  3684. status = NwGetConnectionInformation( lpName, lpTempUserName, lpTempHostName );
  3685. if ( status == ERROR_BAD_NETPATH )
  3686. {
  3687. return WN_NOT_CONNECTED;
  3688. }
  3689. if ( status != NO_ERROR )
  3690. {
  3691. return status;
  3692. }
  3693. if ( ( ( wcslen( lpTempUserName ) + 1 ) * sizeof(WCHAR) ) > dwUserNameBufferSize )
  3694. {
  3695. *lpdwCharsRequired = wcslen( lpTempUserName ) + 1;
  3696. return WN_MORE_DATA;
  3697. }
  3698. wcscpy( (LPWSTR) lpUserName, lpTempUserName );
  3699. return WN_SUCCESS;
  3700. }
  3701. DWORD
  3702. NwrGetResourceInformation(
  3703. IN LPWSTR Reserved OPTIONAL,
  3704. IN LPWSTR lpRemoteName,
  3705. IN DWORD dwType,
  3706. OUT LPBYTE lpBuffer,
  3707. IN DWORD dwBufferSize,
  3708. OUT LPDWORD lpdwBytesNeeded,
  3709. OUT LPDWORD lpdwSystemOffset
  3710. )
  3711. /*++
  3712. Routine Description:
  3713. This function returns an object which details information
  3714. about a specified network resource.
  3715. Arguments:
  3716. Reserved - Unused.
  3717. lpRemoteName - The full path name to be verified.
  3718. dwType - The type of the value, if the calling client knows it.
  3719. lpBuffer - A pointer to a buffer to receive a single NETRESOURCE entry.
  3720. dwBufferSize - The size of the buffer.
  3721. lpdwBytesNeeded - The buffer size needed if WN_MORE_DATA is returned.
  3722. lpdwSystemOffset - A DWORD that is an offset value to the beginning of a
  3723. string that specifies the part of the resource that is accessed through
  3724. resource type specific APIs rather than WNet APIs. The string is stored
  3725. in the same buffer as the returned NETRESOURCE structure, lpBuffer.
  3726. Return Value:
  3727. WN_SUCCESS - If the call is successful.
  3728. WN_MORE_DATA - If input buffer is too small.
  3729. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  3730. of parameters is specified (e.g. lpRemoteName does not correspond
  3731. to dwType).
  3732. WN_BAD_NETNAME - The resource is not recognized by this provider.
  3733. --*/ // NwrGetResourceInformation
  3734. {
  3735. DWORD status = NO_ERROR;
  3736. DWORD EntrySize;
  3737. LPBYTE FixedPortion = lpBuffer;
  3738. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3739. ROUND_DOWN_COUNT(dwBufferSize,ALIGN_DWORD));
  3740. LPWSTR lpObjectPathName = NULL;
  3741. LPWSTR lpSystemPathPart = NULL;
  3742. LPWSTR lpSystem = NULL;
  3743. DWORD ClassType;
  3744. DWORD ResourceScope = RESOURCE_CONTEXT; // prefix issue
  3745. DWORD ResourceType = 0;
  3746. DWORD ResourceDisplayType;
  3747. DWORD ResourceUsage;
  3748. BOOL fReturnBadNetName = FALSE;
  3749. if (lpRemoteName == NULL)
  3750. {
  3751. return ERROR_INVALID_PARAMETER;
  3752. }
  3753. *lpdwSystemOffset = 0;
  3754. status = NwGetNDSPathInfo( lpRemoteName,
  3755. &lpObjectPathName,
  3756. &lpSystemPathPart,
  3757. &ClassType,
  3758. &ResourceScope,
  3759. &ResourceType,
  3760. &ResourceDisplayType,
  3761. &ResourceUsage );
  3762. if ( status == VERIFY_ERROR_NOT_A_NDS_TREE )
  3763. {
  3764. //
  3765. // Code to handle \\SERVER\VOL\... here!
  3766. //
  3767. status = NwGetBinderyPathInfo( lpRemoteName,
  3768. &lpObjectPathName,
  3769. &lpSystemPathPart,
  3770. &ClassType,
  3771. &ResourceScope,
  3772. &ResourceType,
  3773. &ResourceDisplayType,
  3774. &ResourceUsage );
  3775. }
  3776. if ( status == VERIFY_ERROR_PATH_NOT_FOUND )
  3777. {
  3778. fReturnBadNetName = TRUE;
  3779. status = NO_ERROR;
  3780. }
  3781. if ( status == NO_ERROR &&
  3782. dwType != RESOURCETYPE_ANY &&
  3783. ResourceType != RESOURCETYPE_ANY &&
  3784. dwType != ResourceType )
  3785. {
  3786. status = WN_BAD_VALUE;
  3787. }
  3788. if ( status == NO_ERROR )
  3789. {
  3790. //
  3791. // Pack subtree name into output buffer.
  3792. //
  3793. status = NwWriteNetResourceEntry( &FixedPortion,
  3794. &EndOfVariableData,
  3795. NULL,
  3796. NULL,
  3797. lpObjectPathName == NULL ? NwProviderName : lpObjectPathName,
  3798. ResourceScope,
  3799. ResourceDisplayType,
  3800. ResourceUsage,
  3801. ResourceType,
  3802. lpSystemPathPart,
  3803. &lpSystem,
  3804. &EntrySize );
  3805. if ( lpObjectPathName )
  3806. (void) LocalFree( (HLOCAL) lpObjectPathName );
  3807. }
  3808. else
  3809. {
  3810. if ( lpSystemPathPart != NULL )
  3811. {
  3812. (void) LocalFree( (HLOCAL) lpSystemPathPart );
  3813. lpSystemPathPart = NULL;
  3814. }
  3815. return status;
  3816. }
  3817. if ( status != NO_ERROR )
  3818. {
  3819. if (status == WN_MORE_DATA)
  3820. {
  3821. //
  3822. // Could not write current entry into output buffer.
  3823. //
  3824. *lpdwBytesNeeded = EntrySize;
  3825. }
  3826. if ( lpSystemPathPart != NULL )
  3827. {
  3828. (void) LocalFree( (HLOCAL) lpSystemPathPart );
  3829. lpSystemPathPart = NULL;
  3830. }
  3831. if ( fReturnBadNetName )
  3832. return WN_BAD_NETNAME;
  3833. return status;
  3834. }
  3835. else
  3836. {
  3837. LPNETRESOURCEW NetR = (LPNETRESOURCEW) lpBuffer;
  3838. //
  3839. // Replace pointers to strings with offsets as need
  3840. //
  3841. if (NetR->lpLocalName != NULL)
  3842. {
  3843. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) lpBuffer);
  3844. }
  3845. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR) lpBuffer);
  3846. if (NetR->lpComment != NULL)
  3847. {
  3848. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) - (DWORD_PTR) lpBuffer);
  3849. }
  3850. if (NetR->lpProvider != NULL)
  3851. {
  3852. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) - (DWORD_PTR) lpBuffer);
  3853. }
  3854. if (lpSystem != NULL)
  3855. {
  3856. *lpdwSystemOffset = (DWORD)((DWORD_PTR) lpSystem - (DWORD_PTR) lpBuffer);
  3857. }
  3858. if ( lpSystemPathPart != NULL )
  3859. {
  3860. (void) LocalFree( (HLOCAL) lpSystemPathPart );
  3861. lpSystemPathPart = NULL;
  3862. }
  3863. if ( fReturnBadNetName )
  3864. return WN_BAD_NETNAME;
  3865. return WN_SUCCESS;
  3866. }
  3867. }
  3868. DWORD
  3869. NwrGetResourceParent(
  3870. IN LPWSTR Reserved OPTIONAL,
  3871. IN LPWSTR lpRemoteName,
  3872. IN DWORD dwType,
  3873. OUT LPBYTE lpBuffer,
  3874. IN DWORD dwBufferSize,
  3875. OUT LPDWORD lpdwBytesNeeded
  3876. )
  3877. /*++
  3878. Routine Description:
  3879. This function returns an object which details information
  3880. about the parent of a specified network resource.
  3881. Arguments:
  3882. Reserved - Unused.
  3883. lpRemoteName - The full path name of object to find the parent of.
  3884. dwType - The type of the value, if the calling client knows it.
  3885. lpBuffer - A pointer to a buffer to receive a single NETRESOURCE entry.
  3886. dwBufferSize - The size of the buffer.
  3887. lpdwBytesNeeded - The buffer size needed if WN_MORE_DATA is returned.
  3888. Return Value:
  3889. WN_SUCCESS - If the call is successful.
  3890. WN_MORE_DATA - If input buffer is too small.
  3891. WN_BAD_VALUE - Invalid dwScope or dwUsage or dwType, or bad combination
  3892. of parameters is specified (e.g. lpRemoteName does not correspond
  3893. to dwType).
  3894. --*/ // NwrGetResourceParent
  3895. {
  3896. DWORD status = NO_ERROR;
  3897. DWORD EntrySize;
  3898. LPBYTE FixedPortion = lpBuffer;
  3899. LPWSTR EndOfVariableData = (LPWSTR) ((DWORD_PTR) FixedPortion +
  3900. ROUND_DOWN_COUNT(dwBufferSize,ALIGN_DWORD));
  3901. LPWSTR lpRemoteNameParent = NULL;
  3902. LPWSTR lpFullObjectPathName = NULL;
  3903. DWORD ClassType;
  3904. DWORD ResourceScope;
  3905. DWORD ResourceType;
  3906. DWORD ResourceDisplayType;
  3907. DWORD ResourceUsage;
  3908. BOOL fReturnBadNetName = FALSE;
  3909. if (lpRemoteName == NULL)
  3910. {
  3911. return ERROR_INVALID_PARAMETER;
  3912. }
  3913. if ( ! NwGetRemoteNameParent( lpRemoteName, &lpRemoteNameParent ) )
  3914. {
  3915. return WN_BAD_NETNAME;
  3916. }
  3917. status = NwVerifyNDSObject( lpRemoteNameParent,
  3918. &lpFullObjectPathName,
  3919. &ClassType,
  3920. &ResourceScope,
  3921. &ResourceType,
  3922. &ResourceDisplayType,
  3923. &ResourceUsage );
  3924. if ( status == VERIFY_ERROR_NOT_A_NDS_TREE )
  3925. {
  3926. status = NwVerifyBinderyObject( lpRemoteNameParent,
  3927. &lpFullObjectPathName,
  3928. &ClassType,
  3929. &ResourceScope,
  3930. &ResourceType,
  3931. &ResourceDisplayType,
  3932. &ResourceUsage );
  3933. }
  3934. if ( lpRemoteNameParent )
  3935. (void) LocalFree( (HLOCAL) lpRemoteNameParent );
  3936. if ( status == VERIFY_ERROR_PATH_NOT_FOUND )
  3937. {
  3938. fReturnBadNetName = TRUE;
  3939. status = NO_ERROR;
  3940. }
  3941. if ( status == NO_ERROR )
  3942. {
  3943. //
  3944. // Pack subtree name into output buffer.
  3945. //
  3946. status = NwWriteNetResourceEntry( &FixedPortion,
  3947. &EndOfVariableData,
  3948. NULL,
  3949. NULL,
  3950. lpFullObjectPathName == NULL ? NwProviderName : lpFullObjectPathName,
  3951. ResourceScope,
  3952. ResourceDisplayType,
  3953. ResourceUsage,
  3954. ResourceType,
  3955. NULL,
  3956. NULL,
  3957. &EntrySize );
  3958. if ( lpFullObjectPathName )
  3959. (void) LocalFree( (HLOCAL) lpFullObjectPathName );
  3960. }
  3961. else
  3962. {
  3963. return status;
  3964. }
  3965. if ( status != NO_ERROR )
  3966. {
  3967. if (status == WN_MORE_DATA)
  3968. {
  3969. //
  3970. // Could not write current entry into output buffer.
  3971. //
  3972. *lpdwBytesNeeded = EntrySize;
  3973. }
  3974. if ( fReturnBadNetName )
  3975. return WN_BAD_NETNAME;
  3976. return status;
  3977. }
  3978. else
  3979. {
  3980. LPNETRESOURCEW NetR = (LPNETRESOURCEW) lpBuffer;
  3981. //
  3982. // Replace pointers to strings with offsets as need
  3983. //
  3984. if (NetR->lpLocalName != NULL)
  3985. {
  3986. NetR->lpLocalName = (LPWSTR) ((DWORD_PTR) (NetR->lpLocalName) - (DWORD_PTR) lpBuffer);
  3987. }
  3988. NetR->lpRemoteName = (LPWSTR) ((DWORD_PTR) (NetR->lpRemoteName) - (DWORD_PTR) lpBuffer);
  3989. if (NetR->lpComment != NULL)
  3990. {
  3991. NetR->lpComment = (LPWSTR) ((DWORD_PTR) (NetR->lpComment) - (DWORD_PTR) lpBuffer);
  3992. }
  3993. if (NetR->lpProvider != NULL)
  3994. {
  3995. NetR->lpProvider = (LPWSTR) ((DWORD_PTR) (NetR->lpProvider) - (DWORD_PTR) lpBuffer);
  3996. }
  3997. if ( fReturnBadNetName )
  3998. return WN_BAD_NETNAME;
  3999. return WN_SUCCESS;
  4000. }
  4001. }
  4002. VOID
  4003. NWWKSTA_CONTEXT_HANDLE_rundown(
  4004. IN NWWKSTA_CONTEXT_HANDLE EnumHandle
  4005. )
  4006. /*++
  4007. Routine Description:
  4008. This function is called by RPC when a client terminates with an
  4009. opened handle. This allows us to clean up and deallocate any context
  4010. data associated with the handle.
  4011. Arguments:
  4012. EnumHandle - Supplies the handle opened for an enumeration.
  4013. Return Value:
  4014. None.
  4015. --*/
  4016. {
  4017. //
  4018. // Call our close handle routine.
  4019. //
  4020. NwrCloseEnum(&EnumHandle);
  4021. }
  4022. DWORD
  4023. NwGetFirstNdsSubTreeEntry(
  4024. OUT LPNW_ENUM_CONTEXT ContextHandle,
  4025. IN DWORD BufferSize
  4026. )
  4027. /*++
  4028. Routine Description:
  4029. This function is called by NwEnumNdsSubTrees to get the first
  4030. subtree entry given a handle to a NDS tree. It allocates
  4031. the output buffer to hold the returned subtree name; the
  4032. caller should free this output buffer with LocalFree when done.
  4033. Arguments:
  4034. Return Value:
  4035. NO_ERROR - The operation was successful.
  4036. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  4037. buffer.
  4038. Other errors from NwNdsList.
  4039. --*/ // NwGetFirstNdsSubTreeEntry
  4040. {
  4041. NTSTATUS ntstatus;
  4042. ContextHandle->NdsRawDataSize = BufferSize;
  4043. //
  4044. // Determine size of NDS raw data buffer to use.
  4045. //
  4046. if ( ContextHandle->NdsRawDataSize < EIGHT_KB )
  4047. ContextHandle->NdsRawDataSize = EIGHT_KB;
  4048. else // dfergus 19 Apr 2001 - 346859
  4049. // if buffer too big, set to max NDS buffer size
  4050. if (ContextHandle->NdsRawDataSize > 0xFC00) // NW_MAX_BUFFER = 0xFC00
  4051. ContextHandle->NdsRawDataSize = 0xFC00;
  4052. //
  4053. // Create NDS raw data buffer.
  4054. //
  4055. ContextHandle->NdsRawDataBuffer = (DWORD_PTR)
  4056. LocalAlloc( LMEM_ZEROINIT,
  4057. ContextHandle->NdsRawDataSize );
  4058. if ( ContextHandle->NdsRawDataBuffer == 0 )
  4059. {
  4060. KdPrint(("NWWORKSTATION: NwGetFirstNdsSubTreeEntry LocalAlloc Failed %lu\n", GetLastError()));
  4061. return ERROR_NOT_ENOUGH_MEMORY;
  4062. }
  4063. //
  4064. // Set up to get initial NDS subordinate list.
  4065. //
  4066. ContextHandle->NdsRawDataId = INITIAL_ITERATION;
  4067. ntstatus = NwNdsList( ContextHandle->TreeConnectionHandle,
  4068. ContextHandle->dwOid,
  4069. &ContextHandle->NdsRawDataId,
  4070. (LPBYTE) ContextHandle->NdsRawDataBuffer,
  4071. ContextHandle->NdsRawDataSize );
  4072. //
  4073. // If error, clean up the ContextHandle and return.
  4074. //
  4075. if ( ntstatus != STATUS_SUCCESS ||
  4076. ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4077. ContextHandle->NdsRawDataBuffer)->SubordinateEntries == 0 )
  4078. {
  4079. if ( ContextHandle->NdsRawDataBuffer )
  4080. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  4081. ContextHandle->NdsRawDataBuffer = 0;
  4082. ContextHandle->NdsRawDataSize = 0;
  4083. ContextHandle->NdsRawDataId = INITIAL_ITERATION;
  4084. ContextHandle->NdsRawDataCount = 0;
  4085. ContextHandle->ResumeId = 0;
  4086. return WN_NO_MORE_ENTRIES;
  4087. }
  4088. ContextHandle->NdsRawDataCount = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4089. ContextHandle->NdsRawDataBuffer)->SubordinateEntries - 1;
  4090. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer +
  4091. sizeof( NDS_RESPONSE_SUBORDINATE_LIST );
  4092. // Multi-user code merge
  4093. // 12/05/96 cjc Fix problem with FileManager not showing all the NDS entries.
  4094. // Problem occurs when the NDS entries don't fit in 1 NCP packet;
  4095. // need to keep track of the Iteration # and redo NCP.
  4096. ContextHandle->NdsRawDataId = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4097. ContextHandle->NdsRawDataBuffer)->IterationHandle;
  4098. return RtlNtStatusToDosError(ntstatus);
  4099. }
  4100. DWORD
  4101. NwGetNextNdsSubTreeEntry(
  4102. OUT LPNW_ENUM_CONTEXT ContextHandle
  4103. )
  4104. /*++
  4105. Routine Description:
  4106. This function is called by NwEnumNdsSubTrees to get the next
  4107. NDS subtree entry given a handle to a NDS tree. It allocates
  4108. the output buffer to hold the returned subtree name; the
  4109. caller should free this output buffer with LocalFree when done.
  4110. Arguments:
  4111. Return Value:
  4112. NO_ERROR - The operation was successful.
  4113. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  4114. buffer.
  4115. Other errors from NwNdsList.
  4116. --*/ // NwGetNextDirectoryEntry
  4117. {
  4118. NTSTATUS ntstatus = STATUS_SUCCESS;
  4119. PBYTE pbRaw;
  4120. DWORD dwStrLen;
  4121. if ( ContextHandle->NdsRawDataCount == 0 &&
  4122. ContextHandle->NdsRawDataId == INITIAL_ITERATION )
  4123. return WN_NO_MORE_ENTRIES;
  4124. if ( ContextHandle->NdsRawDataCount == 0 &&
  4125. ContextHandle->NdsRawDataId != INITIAL_ITERATION )
  4126. {
  4127. ntstatus = NwNdsList( ContextHandle->TreeConnectionHandle,
  4128. ContextHandle->dwOid,
  4129. &ContextHandle->NdsRawDataId,
  4130. (LPBYTE) ContextHandle->NdsRawDataBuffer,
  4131. ContextHandle->NdsRawDataSize );
  4132. //
  4133. // If error, clean up the ContextHandle and return.
  4134. //
  4135. if (ntstatus != STATUS_SUCCESS)
  4136. {
  4137. if ( ContextHandle->NdsRawDataBuffer )
  4138. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  4139. ContextHandle->NdsRawDataBuffer = 0;
  4140. ContextHandle->NdsRawDataSize = 0;
  4141. ContextHandle->NdsRawDataId = INITIAL_ITERATION;
  4142. ContextHandle->NdsRawDataCount = 0;
  4143. return WN_NO_MORE_ENTRIES;
  4144. }
  4145. ContextHandle->NdsRawDataCount = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4146. ContextHandle->NdsRawDataBuffer)->SubordinateEntries - 1;
  4147. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer +
  4148. sizeof( NDS_RESPONSE_SUBORDINATE_LIST );
  4149. // ---Multi-user change ---
  4150. // 12/05/96 cjc Fix problem with FileManager not showing all the NDS entries.
  4151. // Problem occurs when the NDS entries don't fit in 1 NCP packet;
  4152. // need to keep track of the Iteration # and redo NCP.
  4153. ContextHandle->NdsRawDataId = ((PNDS_RESPONSE_SUBORDINATE_LIST)
  4154. ContextHandle->NdsRawDataBuffer)->IterationHandle;
  4155. return RtlNtStatusToDosError(ntstatus);
  4156. }
  4157. ContextHandle->NdsRawDataCount--;
  4158. //
  4159. // Move pointer past the fixed header portion of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4160. //
  4161. pbRaw = (BYTE *) ContextHandle->ResumeId;
  4162. pbRaw += sizeof( NDS_RESPONSE_SUBORDINATE_ENTRY );
  4163. //
  4164. // Move pointer past the length value of the Class Name string
  4165. // of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4166. //
  4167. dwStrLen = * (DWORD *) pbRaw;
  4168. pbRaw += sizeof( DWORD );
  4169. //
  4170. // Move pointer past the Class Name string of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4171. //
  4172. pbRaw += ROUNDUP4( dwStrLen );
  4173. //
  4174. // Move pointer past the length value of the Object Name string
  4175. // of a NDS_RESPONSE_SUBORDINATE_ENTRY
  4176. //
  4177. dwStrLen = * (DWORD *) pbRaw;
  4178. pbRaw += sizeof( DWORD );
  4179. ContextHandle->ResumeId = (DWORD_PTR) ( pbRaw + ROUNDUP4( dwStrLen ) );
  4180. return RtlNtStatusToDosError(ntstatus);
  4181. }
  4182. BYTE
  4183. NwGetSubTreeData(
  4184. IN DWORD_PTR NdsRawDataPtr,
  4185. OUT LPWSTR * SubTreeName,
  4186. OUT LPDWORD ResourceScope,
  4187. OUT LPDWORD ResourceType,
  4188. OUT LPDWORD ResourceDisplayType,
  4189. OUT LPDWORD ResourceUsage,
  4190. OUT LPWSTR * StrippedObjectName
  4191. )
  4192. /*++
  4193. Routine Description:
  4194. This function is called by NwEnumNdsSubTrees to get the information
  4195. needed to describe a single NETRESOURCE from an entry in the
  4196. NdsRawDataBuffer.
  4197. Arguments:
  4198. NdsRawDataPtr - Supplies the pointer to a buffer with the NDS raw data.
  4199. SubTreeName - Receives a pointer to the returned subtree object name
  4200. found in buffer.
  4201. ResourceScope - Receives the value of the scope for the subtree object
  4202. found in buffer.
  4203. ResourceType - Receives the value of the type for the subtree object
  4204. found in buffer.
  4205. ResourceDisplayType - Receives the value of the display type for the
  4206. subtree object found in buffer.
  4207. ResourceUsage - Receives the value of the usage for the subtree object
  4208. found in buffer.
  4209. StrippedObjectName - A pointer to receive the address of a buffer which
  4210. will contain the formatted object name. Callee must
  4211. free buffer with LocalFree().
  4212. Return Value:
  4213. A DWORD with a value that is used to represent NDS object class type..
  4214. --*/ // NwGetSubTreeData
  4215. {
  4216. PNDS_RESPONSE_SUBORDINATE_ENTRY pSubEntry =
  4217. (PNDS_RESPONSE_SUBORDINATE_ENTRY) NdsRawDataPtr;
  4218. PBYTE pbRaw;
  4219. DWORD dwStrLen;
  4220. LPWSTR ClassNameStr;
  4221. pbRaw = (BYTE *) pSubEntry;
  4222. //
  4223. // The structure of a NDS_RESPONSE_SUBORDINATE_ENTRY consists of 4 DWORDs
  4224. // followed by two standard NDS format UNICODE strings. Below we jump pbRaw
  4225. // into the buffer, past the 4 DWORDs.
  4226. //
  4227. pbRaw += sizeof( NDS_RESPONSE_SUBORDINATE_ENTRY );
  4228. //
  4229. // Now we get the length of the first string (Base Class).
  4230. //
  4231. dwStrLen = * (DWORD *) pbRaw;
  4232. //
  4233. // Now we point pbRaw to the first WCHAR of the first string (Base Class).
  4234. //
  4235. pbRaw += sizeof( DWORD_PTR );
  4236. ClassNameStr = (LPWSTR) pbRaw;
  4237. //
  4238. // Move pbRaw into the buffer, past the first UNICODE string (WORD aligned)
  4239. //
  4240. pbRaw += ROUNDUP4( dwStrLen );
  4241. //
  4242. // Now we get the length of the second string (Entry Name).
  4243. //
  4244. dwStrLen = * (DWORD *) pbRaw;
  4245. //
  4246. // Now we point pbRaw to the first WCHAR of the second string (Entry Name).
  4247. //
  4248. pbRaw += sizeof( DWORD_PTR );
  4249. *SubTreeName = (LPWSTR) pbRaw;
  4250. //
  4251. // Strip off any CN= stuff from the object name.
  4252. //
  4253. NwStripNdsUncName( *SubTreeName, StrippedObjectName );
  4254. *ResourceScope = RESOURCE_GLOBALNET;
  4255. if ( !wcscmp( ClassNameStr, CLASS_NAME_ALIAS ) )
  4256. {
  4257. *ResourceType = RESOURCETYPE_ANY;
  4258. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4259. *ResourceUsage = 0;
  4260. return CLASS_TYPE_ALIAS;
  4261. }
  4262. if ( !wcscmp( ClassNameStr, CLASS_NAME_AFP_SERVER ) )
  4263. {
  4264. *ResourceType = RESOURCETYPE_ANY;
  4265. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4266. *ResourceUsage = 0;
  4267. return CLASS_TYPE_AFP_SERVER;
  4268. }
  4269. if ( !wcscmp( ClassNameStr, CLASS_NAME_BINDERY_OBJECT ) )
  4270. {
  4271. *ResourceType = RESOURCETYPE_ANY;
  4272. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4273. *ResourceUsage = 0;
  4274. return CLASS_TYPE_BINDERY_OBJECT;
  4275. }
  4276. if ( !wcscmp( ClassNameStr, CLASS_NAME_BINDERY_QUEUE ) )
  4277. {
  4278. *ResourceType = RESOURCETYPE_ANY;
  4279. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4280. *ResourceUsage = 0;
  4281. return CLASS_TYPE_BINDERY_QUEUE;
  4282. }
  4283. if ( !wcscmp( ClassNameStr, CLASS_NAME_COMPUTER ) )
  4284. {
  4285. *ResourceType = RESOURCETYPE_ANY;
  4286. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4287. *ResourceUsage = 0;
  4288. return CLASS_TYPE_COMPUTER;
  4289. }
  4290. if ( !wcscmp( ClassNameStr, CLASS_NAME_COUNTRY ) )
  4291. {
  4292. *ResourceType = RESOURCETYPE_ANY;
  4293. *ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
  4294. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4295. return CLASS_TYPE_COUNTRY;
  4296. }
  4297. if ( !wcscmp( ClassNameStr, CLASS_NAME_DIRECTORY_MAP ) )
  4298. {
  4299. *ResourceType = RESOURCETYPE_DISK;
  4300. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4301. #ifdef NT1057
  4302. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4303. RESOURCEUSAGE_CONTAINER;
  4304. #else
  4305. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4306. RESOURCEUSAGE_NOLOCALDEVICE;
  4307. #endif
  4308. return CLASS_TYPE_DIRECTORY_MAP;
  4309. }
  4310. if ( !wcscmp( ClassNameStr, CLASS_NAME_GROUP ) )
  4311. {
  4312. *ResourceType = RESOURCETYPE_ANY;
  4313. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GROUP;
  4314. *ResourceUsage = 0;
  4315. return CLASS_TYPE_GROUP;
  4316. }
  4317. if ( !wcscmp( ClassNameStr, CLASS_NAME_LOCALITY ) )
  4318. {
  4319. *ResourceType = RESOURCETYPE_ANY;
  4320. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4321. *ResourceUsage = 0;
  4322. return CLASS_TYPE_LOCALITY;
  4323. }
  4324. if ( !wcscmp( ClassNameStr, CLASS_NAME_NCP_SERVER ) )
  4325. {
  4326. *ResourceType = RESOURCETYPE_ANY;
  4327. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  4328. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4329. return CLASS_TYPE_NCP_SERVER;
  4330. }
  4331. if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATION ) )
  4332. {
  4333. *ResourceType = RESOURCETYPE_ANY;
  4334. *ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
  4335. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4336. return CLASS_TYPE_ORGANIZATION;
  4337. }
  4338. if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATIONAL_ROLE ) )
  4339. {
  4340. *ResourceType = RESOURCETYPE_ANY;
  4341. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4342. *ResourceUsage = 0;
  4343. return CLASS_TYPE_ORGANIZATIONAL_ROLE;
  4344. }
  4345. if ( !wcscmp( ClassNameStr, CLASS_NAME_ORGANIZATIONAL_UNIT ) )
  4346. {
  4347. *ResourceType = RESOURCETYPE_ANY;
  4348. *ResourceDisplayType = RESOURCEDISPLAYTYPE_NDSCONTAINER;
  4349. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4350. return CLASS_TYPE_ORGANIZATIONAL_UNIT;
  4351. }
  4352. if ( !wcscmp( ClassNameStr, CLASS_NAME_PRINTER ) )
  4353. {
  4354. *ResourceType = RESOURCETYPE_PRINT;
  4355. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4356. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE;
  4357. return CLASS_TYPE_PRINTER;
  4358. }
  4359. if ( !wcscmp( ClassNameStr, CLASS_NAME_PRINT_SERVER ) )
  4360. {
  4361. *ResourceType = RESOURCETYPE_PRINT;
  4362. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  4363. *ResourceUsage = RESOURCEUSAGE_CONTAINER;
  4364. return CLASS_TYPE_PRINT_SERVER;
  4365. }
  4366. if ( !wcscmp( ClassNameStr, CLASS_NAME_PROFILE ) )
  4367. {
  4368. *ResourceType = RESOURCETYPE_ANY;
  4369. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4370. *ResourceUsage = 0;
  4371. return CLASS_TYPE_PROFILE;
  4372. }
  4373. if ( !wcscmp( ClassNameStr, CLASS_NAME_QUEUE ) )
  4374. {
  4375. *ResourceType = RESOURCETYPE_PRINT;
  4376. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4377. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE;
  4378. return CLASS_TYPE_QUEUE;
  4379. }
  4380. if ( !wcscmp( ClassNameStr, CLASS_NAME_TOP ) )
  4381. {
  4382. *ResourceType = RESOURCETYPE_ANY;
  4383. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4384. *ResourceUsage = 0;
  4385. return CLASS_TYPE_TOP;
  4386. }
  4387. if ( !wcscmp( ClassNameStr, CLASS_NAME_USER ) )
  4388. {
  4389. *ResourceType = RESOURCETYPE_ANY;
  4390. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4391. *ResourceUsage = 0;
  4392. return CLASS_TYPE_USER;
  4393. }
  4394. if ( !wcscmp( ClassNameStr, CLASS_NAME_VOLUME ) )
  4395. {
  4396. *ResourceType = RESOURCETYPE_DISK;
  4397. *ResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  4398. #ifdef NT1057
  4399. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4400. RESOURCEUSAGE_CONTAINER;
  4401. #else
  4402. *ResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  4403. RESOURCEUSAGE_NOLOCALDEVICE;
  4404. #endif
  4405. return CLASS_TYPE_VOLUME;
  4406. }
  4407. //
  4408. // Otherwise if ClassNameStr is something other than Unknown, report it
  4409. //
  4410. if ( wcscmp( ClassNameStr, CLASS_NAME_UNKNOWN ) )
  4411. {
  4412. KdPrint(("NWWORKSTATION: NwGetSubTreeData failed to recognize"));
  4413. KdPrint((" ClassName: %S\n", ClassNameStr));
  4414. KdPrint((" Setting object attributes to Unknown for now . . .\n"));
  4415. }
  4416. *ResourceType = RESOURCETYPE_ANY;
  4417. *ResourceDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  4418. *ResourceUsage = 0;
  4419. return CLASS_TYPE_UNKNOWN;
  4420. }
  4421. VOID
  4422. NwStripNdsUncName(
  4423. IN LPWSTR ObjectName,
  4424. OUT LPWSTR * StrippedObjectName
  4425. )
  4426. {
  4427. WORD slashCount;
  4428. BOOL isNdsUnc;
  4429. LPWSTR FourthSlash;
  4430. LPWSTR TreeName;
  4431. LPWSTR ObjectPath;
  4432. DWORD TreeNameLen;
  4433. DWORD ObjectPathLen;
  4434. DWORD PrefixBytes;
  4435. DWORD CurrentPathIndex;
  4436. DWORD StrippedNameLen;
  4437. DWORD StrippedNameMaxLen = MAX_NDS_NAME_CHARS;
  4438. WCHAR StrippedName[MAX_NDS_NAME_CHARS];
  4439. *StrippedObjectName = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  4440. (wcslen(ObjectName) + 1) *
  4441. sizeof(WCHAR) );
  4442. if ( *StrippedObjectName == NULL )
  4443. {
  4444. return;
  4445. }
  4446. NwpGetUncInfo( ObjectName, &slashCount, &isNdsUnc, &FourthSlash );
  4447. if ( slashCount >= 2 )
  4448. {
  4449. TreeNameLen = NwParseNdsUncPath( &TreeName,
  4450. ObjectName,
  4451. PARSE_NDS_GET_TREE_NAME );
  4452. TreeNameLen /= sizeof(WCHAR);
  4453. wcscpy( *StrippedObjectName, L"\\\\" );
  4454. wcsncat( *StrippedObjectName, TreeName, TreeNameLen );
  4455. ObjectPathLen = NwParseNdsUncPath( &ObjectPath,
  4456. ObjectName,
  4457. PARSE_NDS_GET_PATH_NAME );
  4458. if ( ObjectPathLen == 0 )
  4459. {
  4460. _wcsupr( *StrippedObjectName );
  4461. return;
  4462. }
  4463. wcscat( *StrippedObjectName, L"\\" );
  4464. }
  4465. else
  4466. {
  4467. wcscpy( *StrippedObjectName, L"" );
  4468. ObjectPath = ObjectName;
  4469. ObjectPathLen = wcslen(ObjectName) * sizeof(WCHAR);
  4470. }
  4471. CurrentPathIndex = 0;
  4472. PrefixBytes = 0;
  4473. StrippedNameLen = 0;
  4474. //
  4475. // All of these indexes are in BYTES, not WCHARS!
  4476. //
  4477. while ( ( CurrentPathIndex < ObjectPathLen ) &&
  4478. ( StrippedNameLen < StrippedNameMaxLen ) )
  4479. {
  4480. if ( ObjectPath[CurrentPathIndex / sizeof( WCHAR )] == L'=' )
  4481. {
  4482. CurrentPathIndex += sizeof( WCHAR );
  4483. StrippedNameLen -= PrefixBytes;
  4484. PrefixBytes = 0;
  4485. continue;
  4486. }
  4487. StrippedName[StrippedNameLen / sizeof( WCHAR )] =
  4488. ObjectPath[CurrentPathIndex / sizeof( WCHAR )];
  4489. StrippedNameLen += sizeof( WCHAR );
  4490. CurrentPathIndex += sizeof( WCHAR );
  4491. if ( ObjectPath[CurrentPathIndex / sizeof( WCHAR )] == L'.' )
  4492. {
  4493. PrefixBytes = 0;
  4494. PrefixBytes -= sizeof( WCHAR );
  4495. }
  4496. else
  4497. {
  4498. PrefixBytes += sizeof( WCHAR );
  4499. }
  4500. }
  4501. StrippedName[StrippedNameLen / sizeof( WCHAR )] = L'\0';
  4502. wcscat( *StrippedObjectName, StrippedName );
  4503. _wcsupr( *StrippedObjectName );
  4504. }
  4505. DWORD
  4506. NwVerifyNDSObject(
  4507. IN LPWSTR lpNDSObjectNamePath,
  4508. OUT LPWSTR * lpFullNDSObjectNamePath,
  4509. OUT LPDWORD lpClassType,
  4510. OUT LPDWORD lpResourceScope,
  4511. OUT LPDWORD lpResourceType,
  4512. OUT LPDWORD lpResourceDisplayType,
  4513. OUT LPDWORD lpResourceUsage
  4514. )
  4515. {
  4516. DWORD status = NO_ERROR;
  4517. NTSTATUS ntstatus = STATUS_SUCCESS;
  4518. UNICODE_STRING TreeServerName;
  4519. UNICODE_STRING PathString;
  4520. HANDLE ConnectionHandle = NULL;
  4521. DWORD dwHandleType;
  4522. DWORD dwOid;
  4523. BOOL fImpersonate = FALSE ;
  4524. if ( lpNDSObjectNamePath == NULL )
  4525. {
  4526. //
  4527. // Handle this as if we are at the root of our provider hierarchy.
  4528. //
  4529. *lpResourceScope = RESOURCE_GLOBALNET;
  4530. *lpResourceType = RESOURCETYPE_ANY;
  4531. #ifdef NT1057
  4532. *lpResourceDisplayType = 0;
  4533. #else
  4534. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
  4535. #endif
  4536. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4537. *lpFullNDSObjectNamePath = NULL;
  4538. return NO_ERROR;
  4539. }
  4540. TreeServerName.Buffer = NULL;
  4541. PathString.Buffer = NULL;
  4542. TreeServerName.MaximumLength = ( wcslen( lpNDSObjectNamePath ) + 1 ) * sizeof( WCHAR );
  4543. PathString.MaximumLength = ( wcslen( lpNDSObjectNamePath ) + 1 ) * sizeof( WCHAR );
  4544. TreeServerName.Length = NwParseNdsUncPath( (LPWSTR *) &TreeServerName.Buffer,
  4545. lpNDSObjectNamePath,
  4546. PARSE_NDS_GET_TREE_NAME );
  4547. if ( TreeServerName.Length == 0 || TreeServerName.Buffer == NULL )
  4548. {
  4549. //
  4550. // lpNDSObjectNamePath is not in the form \\name[\blah.blah.blah][\foo][\bar]...
  4551. //
  4552. status = WN_BAD_NETNAME;
  4553. goto ErrorExit;
  4554. }
  4555. //
  4556. // Impersonate the client
  4557. //
  4558. if ( ( status = NwImpersonateClient() ) != NO_ERROR )
  4559. {
  4560. goto ErrorExit;
  4561. }
  4562. fImpersonate = TRUE;
  4563. //
  4564. // Open a connection handle to \\name
  4565. //
  4566. ntstatus = NwNdsOpenGenericHandle( &TreeServerName,
  4567. &dwHandleType,
  4568. &ConnectionHandle );
  4569. if ( ntstatus != STATUS_SUCCESS )
  4570. {
  4571. //
  4572. // The first part of lpNDSObjectNamePath was neither a NDS tree nor a NCP Server.
  4573. //
  4574. status = WN_BAD_NETNAME;
  4575. goto ErrorExit;
  4576. }
  4577. if ( dwHandleType != HANDLE_TYPE_NDS_TREE )
  4578. {
  4579. //
  4580. // The first part of lpNDSObjectNamePath was not a NDS tree.
  4581. //
  4582. status = VERIFY_ERROR_NOT_A_NDS_TREE;
  4583. goto ErrorExit;
  4584. }
  4585. //
  4586. // Adjust TreeServerName.Length to number of characters.
  4587. //
  4588. TreeServerName.Length /= sizeof(WCHAR);
  4589. //
  4590. // The lpNDSObjectNamePath points to a NDS tree. Now verify that the path is valid.
  4591. //
  4592. PathString.Length = NwParseNdsUncPath( (LPWSTR *) &PathString.Buffer,
  4593. lpNDSObjectNamePath,
  4594. PARSE_NDS_GET_PATH_NAME );
  4595. if ( PathString.Length == 0 )
  4596. {
  4597. LPWSTR treeNameStr = NULL;
  4598. if ( fImpersonate )
  4599. (void) NwRevertToSelf() ;
  4600. if ( ConnectionHandle )
  4601. CloseHandle( ConnectionHandle );
  4602. *lpResourceScope = RESOURCE_GLOBALNET;
  4603. *lpResourceType = RESOURCETYPE_ANY;
  4604. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_TREE;
  4605. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4606. //
  4607. // Need to build a string with the new NDS UNC path for subtree object
  4608. //
  4609. treeNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4610. ( TreeServerName.Length + 3 ) * sizeof(WCHAR) );
  4611. if ( treeNameStr == NULL )
  4612. {
  4613. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4614. GetLastError()));
  4615. status = ERROR_NOT_ENOUGH_MEMORY;
  4616. goto ErrorExit;
  4617. }
  4618. wcscpy( treeNameStr, L"\\\\" );
  4619. wcsncat( treeNameStr, TreeServerName.Buffer, TreeServerName.Length );
  4620. _wcsupr( treeNameStr );
  4621. *lpFullNDSObjectNamePath = treeNameStr;
  4622. return NO_ERROR;
  4623. }
  4624. else
  4625. {
  4626. WCHAR lpServerName[NW_MAX_SERVER_LEN];
  4627. UNICODE_STRING ServerName;
  4628. ServerName.Length = 0;
  4629. ServerName.MaximumLength = sizeof( lpServerName );
  4630. ServerName.Buffer = lpServerName;
  4631. //
  4632. // Resolve the path to get a NDS object id.
  4633. //
  4634. ntstatus = NwNdsResolveName( ConnectionHandle,
  4635. &PathString,
  4636. &dwOid,
  4637. &ServerName,
  4638. NULL,
  4639. 0 );
  4640. if ( ntstatus == STATUS_SUCCESS && ServerName.Length )
  4641. {
  4642. DWORD dwHandleType;
  4643. //
  4644. // NwNdsResolveName succeeded, but we were referred to
  4645. // another server, though ContextHandle->dwOid is still valid.
  4646. if ( ConnectionHandle )
  4647. CloseHandle( ConnectionHandle );
  4648. ConnectionHandle = NULL;
  4649. //
  4650. // Open a NDS generic connection handle to \\ServerName
  4651. //
  4652. ntstatus = NwNdsOpenGenericHandle( &ServerName,
  4653. &dwHandleType,
  4654. &ConnectionHandle );
  4655. if ( ntstatus != STATUS_SUCCESS )
  4656. {
  4657. status = RtlNtStatusToDosError(ntstatus);
  4658. goto ErrorExit;
  4659. }
  4660. ASSERT( dwHandleType != HANDLE_TYPE_NCP_SERVER );
  4661. }
  4662. }
  4663. if ( ntstatus != STATUS_SUCCESS )
  4664. {
  4665. LPWSTR treeNameStr = NULL;
  4666. *lpResourceScope = RESOURCE_GLOBALNET;
  4667. *lpResourceType = RESOURCETYPE_ANY;
  4668. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_TREE;
  4669. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4670. //
  4671. // Need to build a string with the new NDS UNC path for subtree object
  4672. //
  4673. treeNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4674. ( TreeServerName.Length + 3 ) * sizeof(WCHAR) );
  4675. if ( treeNameStr == NULL )
  4676. {
  4677. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4678. GetLastError()));
  4679. status = ERROR_NOT_ENOUGH_MEMORY;
  4680. goto ErrorExit;
  4681. }
  4682. wcscpy( treeNameStr, L"\\\\" );
  4683. wcsncat( treeNameStr, TreeServerName.Buffer, TreeServerName.Length );
  4684. _wcsupr( treeNameStr );
  4685. *lpFullNDSObjectNamePath = treeNameStr;
  4686. status = VERIFY_ERROR_PATH_NOT_FOUND;
  4687. goto ErrorExit;
  4688. }
  4689. //
  4690. // Check to see what kind of object is pointed to by lpRemoteName.
  4691. //
  4692. {
  4693. BYTE RawResponse[TWO_KB];
  4694. PBYTE pbRawGetInfo;
  4695. DWORD RawResponseSize = sizeof(RawResponse);
  4696. DWORD dwStrLen;
  4697. LPWSTR TreeObjectName;
  4698. LPWSTR StrippedObjectName = NULL;
  4699. LPWSTR newPathStr = NULL;
  4700. ntstatus = NwNdsReadObjectInfo( ConnectionHandle,
  4701. dwOid,
  4702. RawResponse,
  4703. RawResponseSize );
  4704. if ( ntstatus != NO_ERROR )
  4705. {
  4706. status = RtlNtStatusToDosError(ntstatus);
  4707. goto ErrorExit;
  4708. }
  4709. //
  4710. // Get current subtree data from ContextHandle
  4711. //
  4712. *lpClassType = NwGetSubTreeData( (DWORD_PTR) RawResponse,
  4713. &TreeObjectName,
  4714. lpResourceScope,
  4715. lpResourceType,
  4716. lpResourceDisplayType,
  4717. lpResourceUsage,
  4718. &StrippedObjectName );
  4719. if ( StrippedObjectName == NULL )
  4720. {
  4721. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4722. GetLastError()));
  4723. status = ERROR_NOT_ENOUGH_MEMORY;
  4724. goto ErrorExit;
  4725. }
  4726. //
  4727. // Need to build a string with the new NDS UNC path for subtree object
  4728. //
  4729. newPathStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4730. ( wcslen( StrippedObjectName ) +
  4731. TreeServerName.Length + 4 )
  4732. * sizeof(WCHAR) );
  4733. if ( newPathStr == NULL )
  4734. {
  4735. (void) LocalFree((HLOCAL) StrippedObjectName);
  4736. KdPrint(("NWWORKSTATION: NwVerifyNDSObject LocalAlloc Failed %lu\n",
  4737. GetLastError()));
  4738. status = ERROR_NOT_ENOUGH_MEMORY;
  4739. goto ErrorExit;
  4740. }
  4741. wcscpy( newPathStr, L"\\\\" );
  4742. wcsncat( newPathStr, TreeServerName.Buffer, TreeServerName.Length );
  4743. wcscat( newPathStr, L"\\" );
  4744. wcscat( newPathStr, StrippedObjectName );
  4745. _wcsupr( newPathStr );
  4746. //
  4747. // Don't need the StrippedObjectName string anymore
  4748. //
  4749. (void) LocalFree((HLOCAL) StrippedObjectName);
  4750. StrippedObjectName = NULL;
  4751. *lpFullNDSObjectNamePath = newPathStr;
  4752. status = NO_ERROR;
  4753. } // End of Block
  4754. ErrorExit:
  4755. if ( fImpersonate )
  4756. (void) NwRevertToSelf() ;
  4757. if ( ConnectionHandle )
  4758. CloseHandle( ConnectionHandle );
  4759. return status;
  4760. }
  4761. DWORD
  4762. NwVerifyBinderyObject(
  4763. IN LPWSTR lpBinderyObjectPathName,
  4764. OUT LPWSTR * lpFullBinderyObjectPathName,
  4765. OUT LPDWORD lpClassType,
  4766. OUT LPDWORD lpResourceScope,
  4767. OUT LPDWORD lpResourceType,
  4768. OUT LPDWORD lpResourceDisplayType,
  4769. OUT LPDWORD lpResourceUsage
  4770. )
  4771. {
  4772. DWORD status = NO_ERROR;
  4773. HANDLE ConnectionHandle = NULL;
  4774. BOOL fImpersonate = FALSE ;
  4775. BOOL fResourceTypeDisk = FALSE ;
  4776. BOOL fIsNdsUnc = FALSE ;
  4777. UNICODE_STRING BinderyConnectStr;
  4778. ULONG CreateDisposition = 0;
  4779. ULONG CreateOptions = 0;
  4780. WORD wSlashCount;
  4781. LPWSTR FourthSlash;
  4782. if ( lpBinderyObjectPathName == NULL )
  4783. {
  4784. //
  4785. // Handle this as if we are at the root of our provider hierarchy.
  4786. //
  4787. *lpResourceScope = RESOURCE_GLOBALNET;
  4788. *lpResourceType = RESOURCETYPE_ANY;
  4789. #ifdef NT1057
  4790. *lpResourceDisplayType = 0;
  4791. #else
  4792. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
  4793. #endif
  4794. *lpResourceUsage = RESOURCEUSAGE_CONTAINER;
  4795. *lpFullBinderyObjectPathName = NULL;
  4796. return NO_ERROR;
  4797. }
  4798. //
  4799. // Open a connection handle to \\server\vol\...
  4800. //
  4801. BinderyConnectStr.Buffer = NULL;
  4802. //
  4803. // Find out if we are looking at a \\server, \\server\vol, or
  4804. // \\server\vol\dir . . .
  4805. //
  4806. NwpGetUncInfo( lpBinderyObjectPathName,
  4807. &wSlashCount,
  4808. &fIsNdsUnc,
  4809. &FourthSlash );
  4810. if ( wSlashCount > 2 )
  4811. fResourceTypeDisk = TRUE;
  4812. //
  4813. // Impersonate the client
  4814. //
  4815. if ( ( status = NwImpersonateClient() ) != NO_ERROR )
  4816. {
  4817. goto ErrorExit;
  4818. }
  4819. fImpersonate = TRUE;
  4820. //
  4821. // Open a tree connection handle to \Device\NwRdr\ContainerName
  4822. //
  4823. status = NwCreateTreeConnectName( lpBinderyObjectPathName,
  4824. NULL,
  4825. &BinderyConnectStr );
  4826. if ( status != NO_ERROR )
  4827. {
  4828. status = WN_BAD_NETNAME;
  4829. goto ErrorExit;
  4830. }
  4831. CreateDisposition = FILE_OPEN;
  4832. CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
  4833. status = NwOpenCreateConnection( &BinderyConnectStr,
  4834. NULL,
  4835. NULL,
  4836. lpBinderyObjectPathName,
  4837. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  4838. CreateDisposition,
  4839. CreateOptions,
  4840. RESOURCETYPE_DISK, // When connecting beyond servername
  4841. &ConnectionHandle,
  4842. NULL );
  4843. if ( status == NO_ERROR )
  4844. {
  4845. LPWSTR BinderyNameStr = NULL;
  4846. //
  4847. // Need to build a string with the new UNC path for bindery object
  4848. //
  4849. BinderyNameStr = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  4850. ( wcslen( lpBinderyObjectPathName ) + 1 )
  4851. * sizeof(WCHAR) );
  4852. if ( BinderyNameStr == NULL )
  4853. {
  4854. KdPrint(("NWWORKSTATION: NwVerifyBinderyObject LocalAlloc Failed %lu\n",
  4855. GetLastError()));
  4856. status = ERROR_NOT_ENOUGH_MEMORY;
  4857. goto ErrorExit;
  4858. }
  4859. wcscpy( BinderyNameStr, lpBinderyObjectPathName );
  4860. _wcsupr( BinderyNameStr );
  4861. *lpFullBinderyObjectPathName = BinderyNameStr;
  4862. if ( BinderyConnectStr.Buffer )
  4863. (void) LocalFree((HLOCAL) BinderyConnectStr.Buffer);
  4864. if ( fImpersonate )
  4865. (void) NwRevertToSelf() ;
  4866. if ( ConnectionHandle )
  4867. {
  4868. *lpResourceScope = RESOURCE_GLOBALNET;
  4869. *lpResourceType = fResourceTypeDisk ?
  4870. RESOURCETYPE_DISK :
  4871. RESOURCETYPE_ANY;
  4872. *lpResourceDisplayType = fResourceTypeDisk ?
  4873. RESOURCEDISPLAYTYPE_SHARE :
  4874. RESOURCEDISPLAYTYPE_SERVER;
  4875. #ifdef NT1057
  4876. *lpResourceUsage = fResourceTypeDisk ?
  4877. RESOURCEUSAGE_CONNECTABLE |
  4878. RESOURCEUSAGE_CONTAINER :
  4879. RESOURCEUSAGE_CONTAINER;
  4880. #else
  4881. *lpResourceUsage = fResourceTypeDisk ?
  4882. RESOURCEUSAGE_CONNECTABLE |
  4883. RESOURCEUSAGE_NOLOCALDEVICE :
  4884. RESOURCEUSAGE_CONTAINER;
  4885. #endif
  4886. CloseHandle( ConnectionHandle );
  4887. }
  4888. return NO_ERROR;
  4889. }
  4890. ErrorExit:
  4891. *lpFullBinderyObjectPathName = NULL;
  4892. if ( BinderyConnectStr.Buffer )
  4893. (void) LocalFree((HLOCAL) BinderyConnectStr.Buffer);
  4894. if ( fImpersonate )
  4895. (void) NwRevertToSelf() ;
  4896. if ( ConnectionHandle )
  4897. CloseHandle( ConnectionHandle );
  4898. return WN_BAD_NETNAME;
  4899. }
  4900. DWORD
  4901. NwGetNDSPathInfo(
  4902. IN LPWSTR lpNDSObjectNamePath,
  4903. OUT LPWSTR * lppSystemObjectNamePath,
  4904. OUT LPWSTR * lpSystemPathPart,
  4905. OUT LPDWORD lpClassType,
  4906. OUT LPDWORD lpResourceScope,
  4907. OUT LPDWORD lpResourceType,
  4908. OUT LPDWORD lpResourceDisplayType,
  4909. OUT LPDWORD lpResourceUsage
  4910. )
  4911. {
  4912. DWORD status = NO_ERROR;
  4913. WORD slashCount;
  4914. BOOL isNdsUnc;
  4915. BOOL fReturnBadNetName = FALSE;
  4916. LPWSTR FourthSlash;
  4917. LPWSTR lpSystemPath = NULL;
  4918. *lpSystemPathPart = NULL;
  4919. NwpGetUncInfo( lpNDSObjectNamePath,
  4920. &slashCount,
  4921. &isNdsUnc,
  4922. &FourthSlash );
  4923. if ( slashCount <= 3 )
  4924. {
  4925. //
  4926. // Path is to a possible NDS object, check to see if so and if valid...
  4927. //
  4928. status = NwVerifyNDSObject( lpNDSObjectNamePath,
  4929. lppSystemObjectNamePath,
  4930. lpClassType,
  4931. lpResourceScope,
  4932. lpResourceType,
  4933. lpResourceDisplayType,
  4934. lpResourceUsage );
  4935. *lpSystemPathPart = NULL;
  4936. return status;
  4937. }
  4938. else
  4939. {
  4940. //
  4941. // Path is to a directory, see if directory exists . . .
  4942. //
  4943. status = NwVerifyBinderyObject( lpNDSObjectNamePath,
  4944. lppSystemObjectNamePath,
  4945. lpClassType,
  4946. lpResourceScope,
  4947. lpResourceType,
  4948. lpResourceDisplayType,
  4949. lpResourceUsage );
  4950. }
  4951. if ( status == WN_BAD_NETNAME )
  4952. {
  4953. fReturnBadNetName = TRUE;
  4954. status = NO_ERROR;
  4955. }
  4956. if ( status == NO_ERROR )
  4957. {
  4958. WCHAR TempNDSObjectNamePath[256];
  4959. //
  4960. // Test \\tree\obj.obj... component and
  4961. // return network resource for valid parent and the string,
  4962. // lpSystemPathPart, for the directory part ( \dir1\...).
  4963. //
  4964. if ( *lppSystemObjectNamePath != NULL )
  4965. {
  4966. (void) LocalFree( (HLOCAL) (*lppSystemObjectNamePath) );
  4967. *lppSystemObjectNamePath = NULL;
  4968. }
  4969. lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  4970. ( wcslen( FourthSlash ) + 1 ) *
  4971. sizeof( WCHAR ) );
  4972. if ( lpSystemPath == NULL )
  4973. {
  4974. return ERROR_NOT_ENOUGH_MEMORY;
  4975. }
  4976. wcscpy( lpSystemPath, FourthSlash );
  4977. *FourthSlash = L'\0';
  4978. wcscpy( TempNDSObjectNamePath, lpNDSObjectNamePath );
  4979. *FourthSlash = L'\\';
  4980. //
  4981. // See if \\tree\obj.obj.... exists . . .
  4982. //
  4983. status = NwVerifyNDSObject( TempNDSObjectNamePath,
  4984. lppSystemObjectNamePath,
  4985. lpClassType,
  4986. lpResourceScope,
  4987. lpResourceType,
  4988. lpResourceDisplayType,
  4989. lpResourceUsage );
  4990. if ( status != NO_ERROR )
  4991. {
  4992. LocalFree( lpSystemPath );
  4993. lpSystemPath = NULL;
  4994. }
  4995. }
  4996. *lpSystemPathPart = lpSystemPath;
  4997. //
  4998. // The provider spec for this function used to tell us to create a
  4999. // NETRESOURCE, even if the system part of the path was invalid, while
  5000. // returning WN_BAD_NETNAME. Now we return SUCCESS and the NETRESOURCE,
  5001. // irregardless of whether the lpSystem part is valid.
  5002. // if ( fReturnBadNetName == TRUE )
  5003. // {
  5004. // return WN_BAD_NETNAME;
  5005. // }
  5006. return status;
  5007. }
  5008. DWORD
  5009. NwGetBinderyPathInfo(
  5010. IN LPWSTR lpBinderyObjectNamePath,
  5011. OUT LPWSTR * lppSystemObjectNamePath,
  5012. OUT LPWSTR * lpSystemPathPart,
  5013. OUT LPDWORD lpClassType,
  5014. OUT LPDWORD lpResourceScope,
  5015. OUT LPDWORD lpResourceType,
  5016. OUT LPDWORD lpResourceDisplayType,
  5017. OUT LPDWORD lpResourceUsage
  5018. )
  5019. {
  5020. DWORD status = NO_ERROR;
  5021. WORD slashCount;
  5022. BOOL isNdsUnc;
  5023. LPWSTR FourthSlash;
  5024. LPWSTR lpSystemPath = NULL;
  5025. *lpSystemPathPart = NULL;
  5026. NwpGetUncInfo( lpBinderyObjectNamePath,
  5027. &slashCount,
  5028. &isNdsUnc,
  5029. &FourthSlash );
  5030. if ( slashCount <= 3 )
  5031. {
  5032. //
  5033. // Path is to a server or volume, check to see which and if valid . . .
  5034. //
  5035. status = NwVerifyBinderyObject( lpBinderyObjectNamePath,
  5036. lppSystemObjectNamePath,
  5037. lpClassType,
  5038. lpResourceScope,
  5039. lpResourceType,
  5040. lpResourceDisplayType,
  5041. lpResourceUsage );
  5042. *lpSystemPathPart = NULL;
  5043. return status;
  5044. }
  5045. else
  5046. {
  5047. //
  5048. // Path is to a directory, see if directory exists . . .
  5049. //
  5050. status = NwVerifyBinderyObject( lpBinderyObjectNamePath,
  5051. lppSystemObjectNamePath,
  5052. lpClassType,
  5053. lpResourceScope,
  5054. lpResourceType,
  5055. lpResourceDisplayType,
  5056. lpResourceUsage );
  5057. }
  5058. if ( status == WN_BAD_NETNAME )
  5059. {
  5060. WCHAR TempBinderyObjectNamePath[256];
  5061. //
  5062. // Path is to a invalid directory. Test \\server\volume component and
  5063. // return network resource for valid parent and the string,
  5064. // lpSystemPathPart, for the directory part ( \dir1\...).
  5065. //
  5066. lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  5067. ( wcslen( FourthSlash ) + 1 ) *
  5068. sizeof( WCHAR ) );
  5069. if ( lpSystemPath == NULL )
  5070. {
  5071. return ERROR_NOT_ENOUGH_MEMORY;
  5072. }
  5073. wcscpy( lpSystemPath, FourthSlash );
  5074. *FourthSlash = L'\0';
  5075. wcscpy( TempBinderyObjectNamePath, lpBinderyObjectNamePath );
  5076. *FourthSlash = L'\\';
  5077. //
  5078. // See if \\server\volume exists . . .
  5079. //
  5080. status = NwVerifyBinderyObject( TempBinderyObjectNamePath,
  5081. lppSystemObjectNamePath,
  5082. lpClassType,
  5083. lpResourceScope,
  5084. lpResourceType,
  5085. lpResourceDisplayType,
  5086. lpResourceUsage );
  5087. if ( status != NO_ERROR )
  5088. {
  5089. LocalFree( lpSystemPath );
  5090. lpSystemPath = NULL;
  5091. }
  5092. //
  5093. // Return SUCCESS, since the NETRESOURCE for \\server\volume that
  5094. // we are describing is at least valid, even though the lpSystem
  5095. // part in not. This is a change in the provider spec (4/25/96).
  5096. //
  5097. // else
  5098. // {
  5099. // status = WN_BAD_NETNAME;
  5100. // }
  5101. }
  5102. else
  5103. {
  5104. //
  5105. // Path is to a valid directory. Return resource information for the
  5106. // \\server\volume component and the string, lpSystemPathPart, for the
  5107. // directory part ( \dir1\...).
  5108. //
  5109. NwpGetUncInfo( *lppSystemObjectNamePath,
  5110. &slashCount,
  5111. &isNdsUnc,
  5112. &FourthSlash );
  5113. lpSystemPath = (LPWSTR) LocalAlloc( LMEM_ZEROINIT,
  5114. ( wcslen( FourthSlash ) + 1 ) *
  5115. sizeof( WCHAR ) );
  5116. if ( lpSystemPath == NULL )
  5117. {
  5118. return ERROR_NOT_ENOUGH_MEMORY;
  5119. }
  5120. wcscpy( lpSystemPath, FourthSlash );
  5121. *FourthSlash = L'\0';
  5122. *lpResourceScope = RESOURCE_GLOBALNET;
  5123. *lpResourceType = RESOURCETYPE_DISK;
  5124. *lpResourceDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  5125. #ifdef NT1057
  5126. *lpResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  5127. RESOURCEUSAGE_CONTAINER;
  5128. #else
  5129. *lpResourceUsage = RESOURCEUSAGE_CONNECTABLE |
  5130. RESOURCEUSAGE_NOLOCALDEVICE;
  5131. #endif
  5132. status = NO_ERROR;
  5133. }
  5134. *lpSystemPathPart = lpSystemPath;
  5135. return status;
  5136. }
  5137. BOOL
  5138. NwGetRemoteNameParent(
  5139. IN LPWSTR lpRemoteName,
  5140. OUT LPWSTR * lpRemoteNameParent
  5141. )
  5142. {
  5143. unsigned short iter = 0;
  5144. unsigned short totalLength = (USHORT) wcslen( lpRemoteName );
  5145. unsigned short slashCount = 0;
  5146. unsigned short dotCount = 0;
  5147. unsigned short thirdSlash = 0;
  5148. unsigned short lastSlash = 0;
  5149. unsigned short parentNDSSubTree = 0;
  5150. LPWSTR newRemoteNameParent = NULL;
  5151. if ( totalLength < 2 )
  5152. return FALSE;
  5153. //
  5154. // Get thirdSlash to indicate the character in the string that indicates the
  5155. // "\" in between the tree name and the rest of the UNC path. Set parentNDSSubTree
  5156. // if available. And always set lastSlash to the most recent "\" seen as you walk.
  5157. //
  5158. // Example: \\<tree name>\path.to.object[\|.]<object>
  5159. // ^ ^
  5160. // | |
  5161. // thirdSlash parentNDSSubTree
  5162. //
  5163. while ( iter < totalLength )
  5164. {
  5165. if ( lpRemoteName[iter] == L'\\' )
  5166. {
  5167. slashCount += 1;
  5168. if ( slashCount == 3 )
  5169. thirdSlash = iter;
  5170. lastSlash = iter;
  5171. }
  5172. if ( lpRemoteName[iter] == L'.' )
  5173. {
  5174. dotCount += 1;
  5175. if ( dotCount == 1 )
  5176. parentNDSSubTree = iter;
  5177. }
  5178. iter++;
  5179. }
  5180. if ( slashCount > 3 )
  5181. {
  5182. newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  5183. ( lastSlash + 1 ) *
  5184. sizeof(WCHAR));
  5185. if ( newRemoteNameParent == NULL )
  5186. {
  5187. KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
  5188. GetLastError()));
  5189. return FALSE;
  5190. }
  5191. wcsncpy( newRemoteNameParent, lpRemoteName, lastSlash );
  5192. _wcsupr( newRemoteNameParent );
  5193. *lpRemoteNameParent = newRemoteNameParent;
  5194. return TRUE;
  5195. }
  5196. if ( slashCount == 3 )
  5197. {
  5198. if ( dotCount == 0 )
  5199. {
  5200. newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  5201. ( lastSlash + 1 ) *
  5202. sizeof(WCHAR));
  5203. if ( newRemoteNameParent == NULL )
  5204. {
  5205. KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
  5206. GetLastError()));
  5207. return FALSE;
  5208. }
  5209. wcsncpy( newRemoteNameParent, lpRemoteName, lastSlash );
  5210. _wcsupr( newRemoteNameParent );
  5211. *lpRemoteNameParent = newRemoteNameParent;
  5212. return TRUE;
  5213. }
  5214. else
  5215. {
  5216. newRemoteNameParent = (PVOID) LocalAlloc( LMEM_ZEROINIT,
  5217. ( totalLength -
  5218. ( parentNDSSubTree - thirdSlash )
  5219. + 1 )
  5220. * sizeof(WCHAR) );
  5221. if ( newRemoteNameParent == NULL )
  5222. {
  5223. KdPrint(("NWWORKSTATION: NwGetRemoteNameParent LocalAlloc Failed %lu\n",
  5224. GetLastError()));
  5225. return FALSE;
  5226. }
  5227. wcsncpy( newRemoteNameParent, lpRemoteName, thirdSlash + 1 );
  5228. wcscat( newRemoteNameParent, &lpRemoteName[parentNDSSubTree+1] );
  5229. _wcsupr( newRemoteNameParent );
  5230. *lpRemoteNameParent = newRemoteNameParent;
  5231. return TRUE;
  5232. }
  5233. }
  5234. // Else we set lpRemoteNameParent to NULL, to indicate that we are at the top and
  5235. // return TRUE.
  5236. *lpRemoteNameParent = NULL;
  5237. return TRUE;
  5238. }
  5239. DWORD
  5240. NwGetFirstDirectoryEntry(
  5241. IN HANDLE DirHandle,
  5242. OUT LPWSTR *DirEntry
  5243. )
  5244. /*++
  5245. Routine Description:
  5246. This function is called by NwEnumDirectories to get the first
  5247. directory entry given a handle to the directory. It allocates
  5248. the output buffer to hold the returned directory name; the
  5249. caller should free this output buffer with LocalFree when done.
  5250. Arguments:
  5251. DirHandle - Supplies the opened handle to the container
  5252. directory find a directory within it.
  5253. DirEntry - Receives a pointer to the returned directory
  5254. found.
  5255. Return Value:
  5256. NO_ERROR - The operation was successful.
  5257. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  5258. buffer.
  5259. Other errors from NtQueryDirectoryFile.
  5260. --*/ // NwGetFirstDirectoryEntry
  5261. {
  5262. DWORD status = NO_ERROR;
  5263. NTSTATUS ntstatus = STATUS_SUCCESS;
  5264. IO_STATUS_BLOCK IoStatusBlock;
  5265. PFILE_DIRECTORY_INFORMATION DirInfo;
  5266. UNICODE_STRING StartFileName;
  5267. #if DBG
  5268. DWORD i = 0;
  5269. #endif
  5270. //
  5271. // Allocate a large buffer to get one directory information entry.
  5272. //
  5273. DirInfo = (PVOID) LocalAlloc(
  5274. LMEM_ZEROINIT,
  5275. sizeof(FILE_DIRECTORY_INFORMATION) +
  5276. (MAX_PATH * sizeof(WCHAR))
  5277. );
  5278. if (DirInfo == NULL) {
  5279. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry LocalAlloc Failed %lu\n",
  5280. GetLastError()));
  5281. return ERROR_NOT_ENOUGH_MEMORY;
  5282. }
  5283. RtlInitUnicodeString(&StartFileName, L"*");
  5284. ntstatus = NtQueryDirectoryFile(
  5285. DirHandle,
  5286. NULL,
  5287. NULL,
  5288. NULL,
  5289. &IoStatusBlock,
  5290. DirInfo,
  5291. sizeof(FILE_DIRECTORY_INFORMATION) +
  5292. (MAX_PATH * sizeof(WCHAR)),
  5293. FileDirectoryInformation, // Info class requested
  5294. TRUE, // Return single entry
  5295. &StartFileName, // Redirector needs this
  5296. TRUE // Restart scan
  5297. );
  5298. //
  5299. // For now, if buffer to NtQueryDirectoryFile is too small, just give
  5300. // up. We may want to try to reallocate a bigger buffer at a later time.
  5301. //
  5302. if (ntstatus == STATUS_SUCCESS) {
  5303. ntstatus = IoStatusBlock.Status;
  5304. }
  5305. if (ntstatus != STATUS_SUCCESS) {
  5306. if (ntstatus == STATUS_NO_MORE_FILES) {
  5307. //
  5308. // We ran out of entries.
  5309. //
  5310. status = WN_NO_MORE_ENTRIES;
  5311. }
  5312. else {
  5313. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
  5314. ntstatus));
  5315. status = RtlNtStatusToDosError(ntstatus);
  5316. }
  5317. goto CleanExit;
  5318. }
  5319. #if DBG
  5320. IF_DEBUG(ENUM) {
  5321. KdPrint(("GetFirst(%u) got %ws, attributes %08lx\n", ++i,
  5322. DirInfo->FileName, DirInfo->FileAttributes));
  5323. }
  5324. #endif
  5325. //
  5326. // Scan until we find the first directory entry that is not "." or ".."
  5327. //
  5328. while (!(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
  5329. memcmp(DirInfo->FileName, L".", DirInfo->FileNameLength) == 0 ||
  5330. memcmp(DirInfo->FileName, L"..", DirInfo->FileNameLength) == 0) {
  5331. ntstatus = NtQueryDirectoryFile(
  5332. DirHandle,
  5333. NULL,
  5334. NULL,
  5335. NULL,
  5336. &IoStatusBlock,
  5337. DirInfo,
  5338. sizeof(FILE_DIRECTORY_INFORMATION) +
  5339. (MAX_PATH * sizeof(WCHAR)),
  5340. FileDirectoryInformation, // Info class requested
  5341. TRUE, // Return single entry
  5342. NULL,
  5343. FALSE // Restart scan
  5344. );
  5345. if (ntstatus == STATUS_SUCCESS) {
  5346. ntstatus = IoStatusBlock.Status;
  5347. }
  5348. if (ntstatus != STATUS_SUCCESS) {
  5349. if (ntstatus == STATUS_NO_MORE_FILES) {
  5350. //
  5351. // We ran out of entries.
  5352. //
  5353. status = WN_NO_MORE_ENTRIES;
  5354. }
  5355. else {
  5356. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
  5357. ntstatus));
  5358. status = RtlNtStatusToDosError(ntstatus);
  5359. }
  5360. goto CleanExit;
  5361. }
  5362. #if DBG
  5363. IF_DEBUG(ENUM) {
  5364. KdPrint(("GetFirst(%u) got %ws, attributes %08lx\n", ++i,
  5365. DirInfo->FileName, DirInfo->FileAttributes));
  5366. }
  5367. #endif
  5368. }
  5369. //
  5370. // Allocate the output buffer for the returned directory name
  5371. //
  5372. *DirEntry = (PVOID) LocalAlloc(
  5373. LMEM_ZEROINIT,
  5374. DirInfo->FileNameLength + sizeof(WCHAR)
  5375. );
  5376. if (*DirEntry == NULL) {
  5377. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry LocalAlloc Failed %lu\n",
  5378. GetLastError()));
  5379. status = ERROR_NOT_ENOUGH_MEMORY;
  5380. goto CleanExit;
  5381. }
  5382. memcpy(*DirEntry, DirInfo->FileName, DirInfo->FileNameLength);
  5383. #if DBG
  5384. IF_DEBUG(ENUM) {
  5385. KdPrint(("NWWORKSTATION: NwGetFirstDirectoryEntry returns %ws\n",
  5386. *DirEntry));
  5387. }
  5388. #endif
  5389. status = NO_ERROR;
  5390. CleanExit:
  5391. (void) LocalFree((HLOCAL) DirInfo);
  5392. //
  5393. // We could not find any directories under the requested
  5394. // so we need to treat this as no entries.
  5395. //
  5396. if ( status == ERROR_FILE_NOT_FOUND )
  5397. status = WN_NO_MORE_ENTRIES;
  5398. return status;
  5399. }
  5400. DWORD
  5401. NwGetNextDirectoryEntry(
  5402. IN HANDLE DirHandle,
  5403. OUT LPWSTR *DirEntry
  5404. )
  5405. /*++
  5406. Routine Description:
  5407. This function is called by NwEnumDirectories to get the next
  5408. directory entry given a handle to the directory. It allocates
  5409. the output buffer to hold the returned directory name; the
  5410. caller should free this output buffer with LocalFree when done.
  5411. Arguments:
  5412. DirHandle - Supplies the opened handle to the container
  5413. directory find a directory within it.
  5414. DirEntry - Receives a pointer to the returned directory
  5415. found.
  5416. Return Value:
  5417. NO_ERROR - The operation was successful.
  5418. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating output
  5419. buffer.
  5420. Other errors from NtQueryDirectoryFile.
  5421. --*/ // NwGetNextDirectoryEntry
  5422. {
  5423. DWORD status = NO_ERROR;
  5424. NTSTATUS ntstatus = STATUS_SUCCESS;
  5425. IO_STATUS_BLOCK IoStatusBlock;
  5426. PFILE_DIRECTORY_INFORMATION DirInfo;
  5427. //
  5428. // Allocate a large buffer to get one directory information entry.
  5429. //
  5430. DirInfo = (PVOID) LocalAlloc(
  5431. LMEM_ZEROINIT,
  5432. sizeof(FILE_DIRECTORY_INFORMATION) +
  5433. (MAX_PATH * sizeof(WCHAR))
  5434. );
  5435. if (DirInfo == NULL) {
  5436. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry LocalAlloc Failed %lu\n",
  5437. GetLastError()));
  5438. return ERROR_NOT_ENOUGH_MEMORY;
  5439. }
  5440. do {
  5441. ntstatus = NtQueryDirectoryFile(
  5442. DirHandle,
  5443. NULL,
  5444. NULL,
  5445. NULL,
  5446. &IoStatusBlock,
  5447. DirInfo,
  5448. sizeof(FILE_DIRECTORY_INFORMATION) +
  5449. (MAX_PATH * sizeof(WCHAR)),
  5450. FileDirectoryInformation, // Info class requested
  5451. TRUE, // Return single entry
  5452. NULL,
  5453. FALSE // Restart scan
  5454. );
  5455. if (ntstatus == STATUS_SUCCESS) {
  5456. ntstatus = IoStatusBlock.Status;
  5457. }
  5458. } while (ntstatus == STATUS_SUCCESS &&
  5459. !(DirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY));
  5460. if (ntstatus != STATUS_SUCCESS) {
  5461. if (ntstatus == STATUS_NO_MORE_FILES) {
  5462. //
  5463. // We ran out of entries.
  5464. //
  5465. status = WN_NO_MORE_ENTRIES;
  5466. }
  5467. else {
  5468. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry: NtQueryDirectoryFile returns %08lx\n",
  5469. ntstatus));
  5470. status = RtlNtStatusToDosError(ntstatus);
  5471. }
  5472. goto CleanExit;
  5473. }
  5474. //
  5475. // Allocate the output buffer for the returned directory name
  5476. //
  5477. *DirEntry = (PVOID) LocalAlloc(
  5478. LMEM_ZEROINIT,
  5479. DirInfo->FileNameLength + sizeof(WCHAR)
  5480. );
  5481. if (*DirEntry == NULL) {
  5482. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry LocalAlloc Failed %lu\n",
  5483. GetLastError()));
  5484. status = ERROR_NOT_ENOUGH_MEMORY;
  5485. goto CleanExit;
  5486. }
  5487. memcpy(*DirEntry, DirInfo->FileName, DirInfo->FileNameLength);
  5488. #if DBG
  5489. IF_DEBUG(ENUM) {
  5490. KdPrint(("NWWORKSTATION: NwGetNextDirectoryEntry returns %ws\n",
  5491. *DirEntry));
  5492. }
  5493. #endif
  5494. status = NO_ERROR;
  5495. CleanExit:
  5496. (void) LocalFree((HLOCAL) DirInfo);
  5497. return status;
  5498. }
  5499. DWORD
  5500. NwWriteNetResourceEntry(
  5501. IN OUT LPBYTE * FixedPortion,
  5502. IN OUT LPWSTR * EndOfVariableData,
  5503. IN LPWSTR ContainerName OPTIONAL,
  5504. IN LPWSTR LocalName OPTIONAL,
  5505. IN LPWSTR RemoteName,
  5506. IN DWORD ScopeFlag,
  5507. IN DWORD DisplayFlag,
  5508. IN DWORD UsageFlag,
  5509. IN DWORD ResourceType,
  5510. IN LPWSTR SystemPath OPTIONAL,
  5511. OUT LPWSTR * lppSystem OPTIONAL,
  5512. OUT LPDWORD EntrySize
  5513. )
  5514. /*++
  5515. Routine Description:
  5516. This function packages a NETRESOURCE entry into the user output buffer.
  5517. It is called by the various enum resource routines.
  5518. Arguments:
  5519. FixedPortion - Supplies a pointer to the output buffer where the next
  5520. entry of the fixed portion of the use information will be written.
  5521. This pointer is updated to point to the next fixed portion entry
  5522. after a NETRESOURCE entry is written.
  5523. EndOfVariableData - Supplies a pointer just off the last available byte
  5524. in the output buffer. This is because the variable portion of the
  5525. user information is written into the output buffer starting from
  5526. the end.
  5527. This pointer is updated after any variable length information is
  5528. written to the output buffer.
  5529. ContainerName - Supplies the full path qualifier to make RemoteName
  5530. a full UNC name.
  5531. LocalName - Supplies the local device name, if any.
  5532. RemoteName - Supplies the remote resource name.
  5533. ScopeFlag - Supplies the flag which indicates whether this is a
  5534. CONNECTED or GLOBALNET resource.
  5535. DisplayFlag - Supplies the flag which tells the UI how to display
  5536. the resource.
  5537. UsageFlag - Supplies the flag which indicates that the RemoteName
  5538. is either a container or a connectable resource or both.
  5539. SystemPath - Supplies the optional system path data to be stored in the
  5540. NETRESOURCE buffer. This is used by the NPGetResourceInformation
  5541. helper routines.
  5542. lppSystem - If SystemPath is provided, this will point to the location
  5543. in the NETRESOURCE buffer that contains the system path string.
  5544. EntrySize - Receives the size of the NETRESOURCE entry in bytes.
  5545. Return Value:
  5546. NO_ERROR - Successfully wrote entry into user buffer.
  5547. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate work buffer.
  5548. WN_MORE_DATA - Buffer was too small to fit entry.
  5549. --*/ // NwWriteNetResourceEntry
  5550. {
  5551. BOOL FitInBuffer = TRUE;
  5552. LPNETRESOURCEW NetR = (LPNETRESOURCEW) *FixedPortion;
  5553. LPWSTR RemoteBuffer;
  5554. LPWSTR lpSystem;
  5555. *EntrySize = sizeof(NETRESOURCEW) +
  5556. (wcslen(RemoteName) + wcslen(NwProviderName) + 2) *
  5557. sizeof(WCHAR);
  5558. if (ARGUMENT_PRESENT(LocalName)) {
  5559. *EntrySize += (wcslen(LocalName) + 1) * sizeof(WCHAR);
  5560. }
  5561. if (ARGUMENT_PRESENT(ContainerName)) {
  5562. *EntrySize += wcslen(ContainerName) * sizeof(WCHAR);
  5563. }
  5564. if (ARGUMENT_PRESENT(SystemPath)) {
  5565. *EntrySize += wcslen(SystemPath) * sizeof(WCHAR);
  5566. }
  5567. *EntrySize = ROUND_UP_COUNT( *EntrySize, ALIGN_DWORD);
  5568. //
  5569. // See if buffer is large enough to fit the entry.
  5570. //
  5571. if ((LPWSTR) ( *FixedPortion + *EntrySize) > *EndOfVariableData) {
  5572. return WN_MORE_DATA;
  5573. }
  5574. NetR->dwScope = ScopeFlag;
  5575. NetR->dwType = ResourceType;
  5576. NetR->dwDisplayType = DisplayFlag;
  5577. NetR->dwUsage = UsageFlag;
  5578. NetR->lpComment = NULL;
  5579. //
  5580. // Update fixed entry pointer to next entry.
  5581. //
  5582. (*FixedPortion) += sizeof(NETRESOURCEW);
  5583. //
  5584. // RemoteName
  5585. //
  5586. if (ARGUMENT_PRESENT(ContainerName)) {
  5587. //
  5588. // Prefix the RemoteName with its container name making the
  5589. // it a fully-qualified UNC name.
  5590. //
  5591. RemoteBuffer = (PVOID) LocalAlloc(
  5592. LMEM_ZEROINIT,
  5593. (wcslen(RemoteName) + wcslen(ContainerName) + 1) *
  5594. sizeof(WCHAR)
  5595. );
  5596. if (RemoteBuffer == NULL) {
  5597. KdPrint(("NWWORKSTATION: NwWriteNetResourceEntry LocalAlloc failed %lu\n",
  5598. GetLastError()));
  5599. return ERROR_NOT_ENOUGH_MEMORY;
  5600. }
  5601. wcscpy(RemoteBuffer, ContainerName);
  5602. wcscat(RemoteBuffer, RemoteName);
  5603. }
  5604. else {
  5605. RemoteBuffer = RemoteName;
  5606. }
  5607. FitInBuffer = NwlibCopyStringToBuffer(
  5608. RemoteBuffer,
  5609. wcslen(RemoteBuffer),
  5610. (LPCWSTR) *FixedPortion,
  5611. EndOfVariableData,
  5612. &NetR->lpRemoteName
  5613. );
  5614. if (ARGUMENT_PRESENT(ContainerName)) {
  5615. (void) LocalFree((HLOCAL) RemoteBuffer);
  5616. }
  5617. ASSERT(FitInBuffer);
  5618. //
  5619. // LocalName
  5620. //
  5621. if (ARGUMENT_PRESENT(LocalName)) {
  5622. FitInBuffer = NwlibCopyStringToBuffer(
  5623. LocalName,
  5624. wcslen(LocalName),
  5625. (LPCWSTR) *FixedPortion,
  5626. EndOfVariableData,
  5627. &NetR->lpLocalName
  5628. );
  5629. ASSERT(FitInBuffer);
  5630. }
  5631. else {
  5632. NetR->lpLocalName = NULL;
  5633. }
  5634. //
  5635. // SystemPath
  5636. //
  5637. if (ARGUMENT_PRESENT(SystemPath)) {
  5638. FitInBuffer = NwlibCopyStringToBuffer(
  5639. SystemPath,
  5640. wcslen(SystemPath),
  5641. (LPCWSTR) *FixedPortion,
  5642. EndOfVariableData,
  5643. &lpSystem
  5644. );
  5645. ASSERT(FitInBuffer);
  5646. }
  5647. else {
  5648. lpSystem = NULL;
  5649. }
  5650. if (ARGUMENT_PRESENT(lppSystem)) {
  5651. *lppSystem = lpSystem;
  5652. }
  5653. //
  5654. // ProviderName
  5655. //
  5656. FitInBuffer = NwlibCopyStringToBuffer(
  5657. NwProviderName,
  5658. wcslen(NwProviderName),
  5659. (LPCWSTR) *FixedPortion,
  5660. EndOfVariableData,
  5661. &NetR->lpProvider
  5662. );
  5663. ASSERT(FitInBuffer);
  5664. if (! FitInBuffer) {
  5665. return WN_MORE_DATA;
  5666. }
  5667. return NO_ERROR;
  5668. }
  5669. DWORD
  5670. NwWritePrinterInfoEntry(
  5671. IN OUT LPBYTE *FixedPortion,
  5672. IN OUT LPWSTR *EndOfVariableData,
  5673. IN LPWSTR ContainerName OPTIONAL,
  5674. IN LPWSTR RemoteName,
  5675. IN DWORD Flags,
  5676. OUT LPDWORD EntrySize
  5677. )
  5678. /*++
  5679. Routine Description:
  5680. This function packages a PRINTER_INFO_1 entry into the user output buffer.
  5681. Arguments:
  5682. FixedPortion - Supplies a pointer to the output buffer where the next
  5683. entry of the fixed portion of the use information will be written.
  5684. This pointer is updated to point to the next fixed portion entry
  5685. after a PRINT_INFO_1 entry is written.
  5686. EndOfVariableData - Supplies a pointer just off the last available byte
  5687. in the output buffer. This is because the variable portion of the
  5688. user information is written into the output buffer starting from
  5689. the end.
  5690. This pointer is updated after any variable length information is
  5691. written to the output buffer.
  5692. ContainerName - Supplies the full path qualifier to make RemoteName
  5693. a full UNC name.
  5694. RemoteName - Supplies the remote resource name.
  5695. Flags - Supplies the flag which indicates that the RemoteName
  5696. is either a container or not and the icon to use.
  5697. EntrySize - Receives the size of the PRINTER_INFO_1 entry in bytes.
  5698. Return Value:
  5699. NO_ERROR - Successfully wrote entry into user buffer.
  5700. ERROR_NOT_ENOUGH_MEMORY - Failed to allocate work buffer.
  5701. ERROR_INSUFFICIENT_BUFFER - Buffer was too small to fit entry.
  5702. --*/ // NwWritePrinterInfoEntry
  5703. {
  5704. BOOL FitInBuffer = TRUE;
  5705. PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) *FixedPortion;
  5706. LPWSTR RemoteBuffer;
  5707. *EntrySize = sizeof(PRINTER_INFO_1W) +
  5708. ( 2 * wcslen(RemoteName) + 2) * sizeof(WCHAR);
  5709. if (ARGUMENT_PRESENT(ContainerName)) {
  5710. *EntrySize += wcslen(ContainerName) * sizeof(WCHAR);
  5711. }
  5712. else {
  5713. // 3 is for the length of "!\\"
  5714. *EntrySize += (wcslen(NwProviderName) + 3) * sizeof(WCHAR);
  5715. }
  5716. *EntrySize = ROUND_UP_COUNT( *EntrySize, ALIGN_DWORD);
  5717. //
  5718. // See if buffer is large enough to fit the entry.
  5719. //
  5720. if ((LPWSTR) (*FixedPortion + *EntrySize) > *EndOfVariableData) {
  5721. return ERROR_INSUFFICIENT_BUFFER;
  5722. }
  5723. pPrinterInfo1->Flags = Flags;
  5724. pPrinterInfo1->pComment = NULL;
  5725. //
  5726. // Update fixed entry pointer to next entry.
  5727. //
  5728. (*FixedPortion) += sizeof(PRINTER_INFO_1W);
  5729. //
  5730. // Name
  5731. //
  5732. if (ARGUMENT_PRESENT(ContainerName)) {
  5733. //
  5734. // Prefix the RemoteName with its container name making the
  5735. // it a fully-qualified UNC name.
  5736. //
  5737. RemoteBuffer = (PVOID) LocalAlloc(
  5738. LMEM_ZEROINIT,
  5739. (wcslen(ContainerName) + wcslen(RemoteName)
  5740. + 1) * sizeof(WCHAR) );
  5741. if (RemoteBuffer == NULL) {
  5742. KdPrint(("NWWORKSTATION: NwWritePrinterInfoEntry LocalAlloc failed %lu\n", GetLastError()));
  5743. return ERROR_NOT_ENOUGH_MEMORY;
  5744. }
  5745. wcscpy(RemoteBuffer, ContainerName);
  5746. wcscat(RemoteBuffer, RemoteName);
  5747. }
  5748. else {
  5749. //
  5750. // Prefix the RemoteName with its provider name
  5751. //
  5752. RemoteBuffer = (PVOID) LocalAlloc(
  5753. LMEM_ZEROINIT,
  5754. (wcslen(RemoteName) +
  5755. wcslen(NwProviderName) + 4)
  5756. * sizeof(WCHAR) );
  5757. if (RemoteBuffer == NULL) {
  5758. KdPrint(("NWWORKSTATION: NwWritePrinterInfoEntry LocalAlloc failed %lu\n", GetLastError()));
  5759. return ERROR_NOT_ENOUGH_MEMORY;
  5760. }
  5761. wcscpy(RemoteBuffer, NwProviderName );
  5762. wcscat(RemoteBuffer, L"!\\\\" );
  5763. wcscat(RemoteBuffer, RemoteName);
  5764. }
  5765. FitInBuffer = NwlibCopyStringToBuffer(
  5766. RemoteBuffer,
  5767. wcslen(RemoteBuffer),
  5768. (LPCWSTR) *FixedPortion,
  5769. EndOfVariableData,
  5770. &pPrinterInfo1->pName );
  5771. (void) LocalFree((HLOCAL) RemoteBuffer);
  5772. ASSERT(FitInBuffer);
  5773. //
  5774. // Description
  5775. //
  5776. FitInBuffer = NwlibCopyStringToBuffer(
  5777. RemoteName,
  5778. wcslen(RemoteName),
  5779. (LPCWSTR) *FixedPortion,
  5780. EndOfVariableData,
  5781. &pPrinterInfo1->pDescription );
  5782. ASSERT(FitInBuffer);
  5783. if (! FitInBuffer) {
  5784. return ERROR_INSUFFICIENT_BUFFER;
  5785. }
  5786. return NO_ERROR;
  5787. }
  5788. int __cdecl
  5789. SortFunc(
  5790. IN CONST VOID *p1,
  5791. IN CONST VOID *p2
  5792. )
  5793. /*++
  5794. Routine Description:
  5795. This function is used in qsort to compare the descriptions of
  5796. two printer_info_1 structure.
  5797. Arguments:
  5798. p1 - Points to a PRINTER_INFO_1 structure
  5799. p2 - Points to a PRINTER_INFO_1 structure to compare with p1
  5800. Return Value:
  5801. Same as return value of lstrccmpi.
  5802. --*/
  5803. {
  5804. PRINTER_INFO_1W *pFirst = (PRINTER_INFO_1W *) p1;
  5805. PRINTER_INFO_1W *pSecond = (PRINTER_INFO_1W *) p2;
  5806. return lstrcmpiW( pFirst->pDescription, pSecond->pDescription );
  5807. }
  5808. DWORD
  5809. NwGetConnectionInformation(
  5810. IN LPWSTR lpName,
  5811. OUT LPWSTR lpUserName,
  5812. OUT LPWSTR lpHostServer
  5813. )
  5814. {
  5815. DWORD status = NO_ERROR;
  5816. NTSTATUS ntstatus = STATUS_SUCCESS;
  5817. IO_STATUS_BLOCK IoStatusBlock;
  5818. OBJECT_ATTRIBUTES ObjectAttributes;
  5819. ACCESS_MASK DesiredAccess = SYNCHRONIZE | FILE_LIST_DIRECTORY;
  5820. HANDLE hRdr = NULL;
  5821. BOOL fImpersonate = FALSE ;
  5822. WCHAR OpenString[] = L"\\Device\\Nwrdr\\*";
  5823. UNICODE_STRING OpenName;
  5824. OEM_STRING OemArg;
  5825. UNICODE_STRING ConnectionName;
  5826. WCHAR ConnectionBuffer[512];
  5827. ULONG BufferSize = 512;
  5828. ULONG RequestSize, ReplyLen;
  5829. PNWR_REQUEST_PACKET Request;
  5830. BYTE *Reply;
  5831. PCONN_INFORMATION pConnInfo;
  5832. UNICODE_STRING Name;
  5833. //
  5834. // Allocate buffer space.
  5835. //
  5836. Request = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT, BufferSize );
  5837. if ( !Request )
  5838. {
  5839. status = ERROR_NOT_ENOUGH_MEMORY;
  5840. goto ErrorExit;
  5841. }
  5842. //
  5843. // Impersonate the client
  5844. //
  5845. if ( ( status = NwImpersonateClient() ) != NO_ERROR )
  5846. {
  5847. goto ErrorExit;
  5848. }
  5849. fImpersonate = TRUE;
  5850. //
  5851. // Convert the connect name to unicode.
  5852. //
  5853. ConnectionName.Length = wcslen( lpName )* sizeof(WCHAR);
  5854. ConnectionName.MaximumLength = sizeof( ConnectionBuffer );
  5855. ConnectionName.Buffer = ConnectionBuffer;
  5856. if (ConnectionName.Length > MAX_NDS_NAME_SIZE)
  5857. {
  5858. status = ERROR_INVALID_PARAMETER;
  5859. goto ErrorExit;
  5860. }
  5861. wcscpy( ConnectionName.Buffer, lpName );
  5862. _wcsupr( ConnectionName.Buffer );
  5863. //
  5864. // Set up the object attributes.
  5865. //
  5866. RtlInitUnicodeString( &OpenName, OpenString );
  5867. InitializeObjectAttributes( &ObjectAttributes,
  5868. &OpenName,
  5869. OBJ_CASE_INSENSITIVE,
  5870. NULL,
  5871. NULL );
  5872. ntstatus = NtOpenFile( &hRdr,
  5873. DesiredAccess,
  5874. &ObjectAttributes,
  5875. &IoStatusBlock,
  5876. FILE_SHARE_VALID_FLAGS,
  5877. FILE_SYNCHRONOUS_IO_NONALERT );
  5878. if ( ntstatus != STATUS_SUCCESS )
  5879. {
  5880. status = RtlNtStatusToDosError(ntstatus);
  5881. goto ErrorExit;
  5882. }
  5883. //
  5884. // Fill out the request packet for FSCTL_NWR_GET_CONN_INFO.
  5885. //
  5886. Request->Parameters.GetConnInfo.ConnectionNameLength = ConnectionName.Length;
  5887. RtlCopyMemory( &(Request->Parameters.GetConnInfo.ConnectionName[0]),
  5888. ConnectionBuffer,
  5889. ConnectionName.Length );
  5890. RequestSize = sizeof( Request->Parameters.GetConnInfo ) + ConnectionName.Length;
  5891. Reply = ((PBYTE)Request) + RequestSize;
  5892. ReplyLen = BufferSize - RequestSize;
  5893. ntstatus = NtFsControlFile( hRdr,
  5894. NULL,
  5895. NULL,
  5896. NULL,
  5897. &IoStatusBlock,
  5898. FSCTL_NWR_GET_CONN_INFO,
  5899. (PVOID) Request,
  5900. RequestSize,
  5901. (PVOID) Reply,
  5902. ReplyLen );
  5903. if ( ntstatus != STATUS_SUCCESS )
  5904. {
  5905. status = RtlNtStatusToDosError(ntstatus);
  5906. goto ErrorExit;
  5907. }
  5908. (void) NwRevertToSelf() ;
  5909. fImpersonate = FALSE;
  5910. NtClose( hRdr );
  5911. pConnInfo = (PCONN_INFORMATION) Reply;
  5912. wcscpy( lpUserName, pConnInfo->UserName );
  5913. wcscpy( lpHostServer, pConnInfo->HostServer );
  5914. LocalFree( Request );
  5915. return NO_ERROR;
  5916. ErrorExit:
  5917. if ( fImpersonate )
  5918. (void) NwRevertToSelf() ;
  5919. if ( Request )
  5920. LocalFree( Request );
  5921. if ( hRdr )
  5922. NtClose( hRdr );
  5923. return status;
  5924. }
  5925. VOID
  5926. NwpGetUncInfo(
  5927. IN LPWSTR lpstrUnc,
  5928. OUT WORD * slashCount,
  5929. OUT BOOL * isNdsUnc,
  5930. OUT LPWSTR * FourthSlash
  5931. )
  5932. {
  5933. WORD i;
  5934. WORD length = (WORD) wcslen( lpstrUnc );
  5935. *isNdsUnc = (BOOL) FALSE;
  5936. *slashCount = 0;
  5937. *FourthSlash = NULL;
  5938. for ( i = 0; i < length; i++ )
  5939. {
  5940. if ( lpstrUnc[i] == L'=' )
  5941. {
  5942. *isNdsUnc = TRUE;
  5943. }
  5944. if ( lpstrUnc[i] == L'\\' )
  5945. {
  5946. *slashCount += 1;
  5947. if ( *slashCount == 4 )
  5948. {
  5949. *FourthSlash = &lpstrUnc[i];
  5950. }
  5951. }
  5952. }
  5953. }
  5954. DWORD
  5955. NwpGetCurrentUserRegKey(
  5956. IN DWORD DesiredAccess,
  5957. OUT HKEY *phKeyCurrentUser
  5958. )
  5959. /*++
  5960. Routine Description:
  5961. This routine opens the current user's registry key under
  5962. \HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NWCWorkstation\Parameters
  5963. Arguments:
  5964. DesiredAccess - The access mask to open the key with
  5965. phKeyCurrentUser - Receives the opened key handle
  5966. Return Value:
  5967. Returns the appropriate Win32 error.
  5968. --*/
  5969. {
  5970. DWORD err;
  5971. HKEY hkeyWksta;
  5972. LPWSTR CurrentUser;
  5973. HKEY hInteractiveLogonKey; //Multi-user
  5974. HKEY OneLogonKey; //Multi-user
  5975. LUID logonid; //Multi-user
  5976. WCHAR LogonIdKeyName[NW_MAX_LOGON_ID_LEN]; //Multi-user
  5977. //
  5978. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  5979. // \NWCWorkstation\Parameters
  5980. //
  5981. err = RegOpenKeyExW(
  5982. HKEY_LOCAL_MACHINE,
  5983. NW_WORKSTATION_REGKEY,
  5984. REG_OPTION_NON_VOLATILE,
  5985. KEY_READ,
  5986. &hkeyWksta
  5987. );
  5988. if ( err ) {
  5989. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters key unexpected error %lu!\n", err));
  5990. return err;
  5991. }
  5992. //
  5993. // Impersonate the client
  5994. //
  5995. if ( ( err = NwImpersonateClient() ) != NO_ERROR ) {
  5996. (void) RegCloseKey( hkeyWksta );
  5997. return err;
  5998. }
  5999. //
  6000. // Get the NT logon id
  6001. //
  6002. GetLuid( &logonid );
  6003. //
  6004. // Revert
  6005. //
  6006. (void) NwRevertToSelf() ;
  6007. // Open interactive user section
  6008. err = RegOpenKeyExW(
  6009. HKEY_LOCAL_MACHINE,
  6010. NW_INTERACTIVE_LOGON_REGKEY,
  6011. REG_OPTION_NON_VOLATILE,
  6012. KEY_READ,
  6013. &hInteractiveLogonKey
  6014. );
  6015. if ( err ) {
  6016. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Interactive logon key unexpected error %lu!\n", err));
  6017. (void) RegCloseKey( hkeyWksta );
  6018. return err;
  6019. }
  6020. // Open the logonid
  6021. NwLuidToWStr(&logonid, LogonIdKeyName);
  6022. err = RegOpenKeyExW(
  6023. hInteractiveLogonKey,
  6024. LogonIdKeyName,
  6025. REG_OPTION_NON_VOLATILE,
  6026. KEY_READ,
  6027. &OneLogonKey
  6028. );
  6029. (void) RegCloseKey( hInteractiveLogonKey );
  6030. if ( err ) {
  6031. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open logon key unexpected error %lu!\n", err));
  6032. (void) RegCloseKey( hkeyWksta );
  6033. return err;
  6034. }
  6035. // Read SID
  6036. err = NwReadRegValue(
  6037. OneLogonKey,
  6038. NW_SID_VALUENAME,
  6039. &CurrentUser
  6040. );
  6041. (void) RegCloseKey( OneLogonKey );
  6042. (void) RegCloseKey( hkeyWksta );
  6043. if ( err ) {
  6044. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey read user Sid unexpected error %lu!\n", err));
  6045. return err;
  6046. }
  6047. //
  6048. // Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
  6049. // \NWCWorkstation\Parameters\Option
  6050. //
  6051. err = RegOpenKeyExW(
  6052. HKEY_LOCAL_MACHINE,
  6053. NW_WORKSTATION_OPTION_REGKEY,
  6054. REG_OPTION_NON_VOLATILE,
  6055. KEY_READ,
  6056. &hkeyWksta
  6057. );
  6058. if ( err ) {
  6059. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open Parameters\\Option key unexpected error %lu!\n", err));
  6060. return err;
  6061. }
  6062. //
  6063. // Open current user's key
  6064. //
  6065. err = RegOpenKeyExW(
  6066. hkeyWksta,
  6067. CurrentUser,
  6068. REG_OPTION_NON_VOLATILE,
  6069. DesiredAccess,
  6070. phKeyCurrentUser
  6071. );
  6072. if ( err == ERROR_FILE_NOT_FOUND)
  6073. {
  6074. DWORD Disposition;
  6075. //
  6076. // Create <NewUser> key under NWCWorkstation\Parameters\Option
  6077. //
  6078. err = RegCreateKeyExW(
  6079. hkeyWksta,
  6080. CurrentUser,
  6081. 0,
  6082. WIN31_CLASS,
  6083. REG_OPTION_NON_VOLATILE,
  6084. DesiredAccess,
  6085. NULL, // security attr
  6086. phKeyCurrentUser,
  6087. &Disposition
  6088. );
  6089. }
  6090. if ( err ) {
  6091. KdPrint(("NWPROVAU: NwGetCurrentUserRegKey open or create of Parameters\\Option\\%ws key failed %lu\n", CurrentUser, err));
  6092. }
  6093. (void) RegCloseKey( hkeyWksta );
  6094. (void) LocalFree((HLOCAL)CurrentUser) ;
  6095. return err;
  6096. }
  6097. DWORD
  6098. NwQueryInfo(
  6099. OUT LPWSTR *ppszPreferredSrv
  6100. )
  6101. /*++
  6102. Routine Description:
  6103. This routine gets the user's preferred server and print options from
  6104. the registry.
  6105. Arguments:
  6106. ppszPreferredSrv - Receives the user's preferred server
  6107. Return Value:
  6108. Returns the appropriate Win32 error.
  6109. --*/
  6110. {
  6111. HKEY hKeyCurrentUser = NULL;
  6112. DWORD BufferSize;
  6113. DWORD BytesNeeded;
  6114. DWORD ValueType;
  6115. LPWSTR PreferredServer ;
  6116. DWORD err ;
  6117. //
  6118. // get to right place in registry and allocate dthe buffer
  6119. //
  6120. if (err = NwpGetCurrentUserRegKey( KEY_READ, &hKeyCurrentUser))
  6121. {
  6122. //
  6123. // If somebody mess around with the registry and we can't find
  6124. // the registry, just use the defaults.
  6125. //
  6126. *ppszPreferredSrv = NULL;
  6127. return NO_ERROR;
  6128. }
  6129. BufferSize = sizeof(WCHAR) * (MAX_PATH + 2) ;
  6130. PreferredServer = (LPWSTR) LocalAlloc(LPTR, BufferSize) ;
  6131. if (!PreferredServer)
  6132. return (GetLastError()) ;
  6133. //
  6134. // Read PreferredServer value into Buffer.
  6135. //
  6136. BytesNeeded = BufferSize ;
  6137. err = RegQueryValueExW( hKeyCurrentUser,
  6138. NW_SERVER_VALUENAME,
  6139. NULL,
  6140. &ValueType,
  6141. (LPBYTE) PreferredServer,
  6142. &BytesNeeded );
  6143. if (err != NO_ERROR)
  6144. {
  6145. //
  6146. // set to empty and carry on
  6147. //
  6148. PreferredServer[0] = 0;
  6149. }
  6150. if (hKeyCurrentUser != NULL)
  6151. (void) RegCloseKey(hKeyCurrentUser) ;
  6152. *ppszPreferredSrv = PreferredServer ;
  6153. return NO_ERROR ;
  6154. }