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.

920 lines
24 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. nwutil.c
  5. Abstract:
  6. Contains some misc functions used by shell extensions
  7. Author:
  8. Yi-Hsin Sung (yihsins) 25-Oct-1995
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <ntddnwfs.h>
  17. #include <ndsapi32.h>
  18. #include <nwmisc.h>
  19. #include "nwclient.h"
  20. #include "nwapi.h"
  21. #include "nwutil.h"
  22. #define EXTRA_BYTES 256
  23. BOOL
  24. NwIsNdsSyntax(
  25. IN LPWSTR lpstrUnc
  26. )
  27. {
  28. HANDLE hTreeConn;
  29. DWORD dwOid;
  30. DWORD status = NO_ERROR;
  31. if ( lpstrUnc == NULL )
  32. return FALSE;
  33. status = NwOpenAndGetTreeInfo( lpstrUnc, &hTreeConn, &dwOid );
  34. if ( status != NO_ERROR )
  35. {
  36. return FALSE;
  37. }
  38. CloseHandle( hTreeConn );
  39. return TRUE;
  40. }
  41. VOID
  42. NwAbbreviateUserName(
  43. IN LPWSTR pszFullName,
  44. OUT LPWSTR pszUserName
  45. )
  46. {
  47. if ( pszUserName == NULL )
  48. return;
  49. if ( NwIsNdsSyntax( pszFullName ))
  50. {
  51. //
  52. // TRACKING - This part of the code never gets called due to the
  53. // change in how NwIsNdsSyntax works. Post NT 4.0, get rid of the
  54. // NwIsNdsSyntax test and run this section of code no matter what.
  55. // This bug was not fixed in NT4.0 due to the extremely close time
  56. // to the ship date.
  57. //
  58. LPWSTR pszTemp = pszFullName;
  59. LPWSTR pszLast = pszTemp;
  60. *pszUserName = 0;
  61. while ( pszTemp = wcschr( pszTemp, L'='))
  62. {
  63. WCHAR NextChar;
  64. NextChar = *(++pszTemp);
  65. while ( NextChar != 0 && NextChar != L'.' )
  66. {
  67. *(pszUserName++) = *pszTemp;
  68. NextChar = *(++pszTemp);
  69. }
  70. if ( NextChar == 0 )
  71. {
  72. pszLast = NULL;
  73. break;
  74. }
  75. *(pszUserName++) = *pszTemp; // put back the '.'
  76. pszLast = ++pszTemp;
  77. }
  78. if ( pszLast != NULL )
  79. {
  80. while ( *pszLast != 0 )
  81. *(pszUserName++) = *(pszLast++);
  82. }
  83. *pszUserName = 0;
  84. }
  85. else
  86. {
  87. wcscpy( pszUserName, pszFullName );
  88. }
  89. }
  90. VOID
  91. NwMakePrettyDisplayName(
  92. IN LPWSTR pszName
  93. )
  94. {
  95. if ( pszName )
  96. {
  97. CharLower( pszName );
  98. CharUpperBuff( pszName, 1);
  99. }
  100. }
  101. VOID
  102. NwExtractTreeName(
  103. IN LPWSTR pszUNCPath,
  104. OUT LPWSTR pszTreeName
  105. )
  106. {
  107. LPWSTR pszTemp = NULL;
  108. if ( pszTreeName == NULL )
  109. return;
  110. pszTreeName[0] = 0;
  111. if ( pszUNCPath == NULL )
  112. return;
  113. if ( pszUNCPath[0] == L' ')
  114. pszUNCPath++;
  115. if ( ( pszUNCPath[0] != L'\\') || ( pszUNCPath[1] != L'\\') )
  116. return;
  117. wcscpy( pszTreeName, pszUNCPath + 2 ); // get past "\\"
  118. if ( pszTemp = wcschr( pszTreeName, L'\\' ))
  119. *pszTemp = 0;
  120. }
  121. VOID
  122. NwExtractServerName(
  123. IN LPWSTR pszUNCPath,
  124. OUT LPWSTR pszServerName
  125. )
  126. {
  127. LPWSTR pszTemp = NULL;
  128. if ( pszServerName == NULL ) {
  129. return;
  130. }
  131. pszServerName[0] = 0;
  132. if ( pszUNCPath == NULL ) {
  133. return;
  134. }
  135. if ( pszUNCPath[0] == L' ') {
  136. pszUNCPath++;
  137. }
  138. if ( ( pszUNCPath[0] != L'\\') || ( pszUNCPath[1] != L'\\') ) {
  139. return;
  140. }
  141. //
  142. // tommye - fix for bug 5005 - if there is a NW server having
  143. // the same name as a NDS Tree, then NwIsNdsSyntax will return
  144. // TRUE even though the path points to the server (not the tree).
  145. // This was blowing up becuase the wschr was returning NULL, and
  146. // wasn't being checked. If this returns NULL, then we'll make
  147. // the assumption that we've got a server name after all.
  148. //
  149. if ( NwIsNdsSyntax( pszUNCPath ))
  150. {
  151. pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
  152. if (pszTemp) {
  153. wcscpy( pszServerName, pszTemp + 1 ); // get past "\"
  154. if ( pszTemp = wcschr( pszServerName, L'.' )) {
  155. *pszTemp = 0;
  156. }
  157. return;
  158. }
  159. }
  160. //
  161. // tommye
  162. // Fall through - this must be a server name only
  163. //
  164. wcscpy( pszServerName, pszUNCPath + 2 ); // get past "\\"
  165. if ( pszTemp = wcschr( pszServerName, L'\\' )) {
  166. *pszTemp = 0;
  167. }
  168. }
  169. VOID
  170. NwExtractShareName(
  171. IN LPWSTR pszUNCPath,
  172. OUT LPWSTR pszShareName
  173. )
  174. {
  175. LPWSTR pszTemp = NULL;
  176. if ( pszShareName == NULL ) {
  177. return;
  178. }
  179. pszShareName[0] = 0;
  180. if ( ( pszUNCPath == NULL )
  181. || ( pszUNCPath[0] != L'\\')
  182. || ( pszUNCPath[1] != L'\\')
  183. )
  184. {
  185. return;
  186. }
  187. //
  188. // tommye - fix for bug 5005 - if there is a NW server having
  189. // the same name as a NDS Tree, then NwIsNdsSyntax will return
  190. // TRUE even though the path points to the server (not the tree).
  191. // This was blowing up becuase the wschr was returning NULL, and
  192. // wasn't being checked. If this returns NULL, then we'll make
  193. // the assumption that we've got a server name after all.
  194. //
  195. if ( NwIsNdsSyntax( pszUNCPath ))
  196. {
  197. pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
  198. if (pszTemp) {
  199. wcscpy( pszShareName, pszTemp + 1 ); // get past "\"
  200. if ( pszTemp = wcschr( pszShareName, L'.' )) {
  201. *pszTemp = 0;
  202. }
  203. return;
  204. }
  205. }
  206. //
  207. // tommye
  208. // Fall through - this must be a server name only
  209. //
  210. pszTemp = wcschr( pszUNCPath + 2, L'\\' ); // get past "\\"
  211. wcscpy( pszShareName, pszTemp + 1); // get past "\"
  212. if ( pszTemp = wcschr( pszShareName, L'\\' )) {
  213. *pszTemp = 0;
  214. }
  215. }
  216. DWORD
  217. NwIsServerInDefaultTree(
  218. IN LPWSTR pszFullServerName,
  219. OUT BOOL *pfInDefaultTree
  220. )
  221. {
  222. DWORD err = NO_ERROR;
  223. LPWSTR pszCurrentContext = NULL;
  224. DWORD dwPrintOptions;
  225. WCHAR szTreeName[MAX_PATH + 1];
  226. *pfInDefaultTree = FALSE;
  227. if ( !NwIsNdsSyntax( pszFullServerName ))
  228. {
  229. // The full server name does not contain any NDS information
  230. // In this case, assume the server is not in the tree.
  231. // If a server belongs the default tree, we would get the full
  232. // NDS information.
  233. return NO_ERROR;
  234. }
  235. // Get the current default tree or server name
  236. err = NwQueryInfo( &dwPrintOptions, &pszCurrentContext );
  237. if ( (err == NO_ERROR) && ( *pszCurrentContext == TREECHAR))
  238. {
  239. // Yes, there is a default tree.
  240. // So, get the tree name out of *TREE\CONTEXT
  241. LPWSTR pszTemp = wcschr( pszCurrentContext, L'\\');
  242. if ( pszTemp )
  243. *pszTemp = 0;
  244. // Need to extract the tree name from full UNC path
  245. NwExtractTreeName( pszFullServerName, szTreeName );
  246. if ( _wcsicmp( szTreeName,
  247. pszCurrentContext + 1) == 0 ) // get past the tree char
  248. {
  249. *pfInDefaultTree = TRUE;
  250. }
  251. }
  252. if ( pszCurrentContext != NULL )
  253. LocalFree( pszCurrentContext );
  254. return err;
  255. }
  256. DWORD
  257. NwIsServerOrTreeAttached(
  258. IN LPWSTR pszName,
  259. OUT BOOL *pfAttached,
  260. OUT BOOL *pfAuthenticated
  261. )
  262. {
  263. DWORD err = NO_ERROR;
  264. DWORD EntriesRead = 0;
  265. DWORD_PTR ResumeKey = 0;
  266. LPBYTE Buffer = NULL;
  267. err = NwGetConnectionStatus(
  268. pszName,
  269. &ResumeKey,
  270. &Buffer,
  271. &EntriesRead );
  272. *pfAttached = FALSE;
  273. *pfAuthenticated = FALSE;
  274. if (( err == NO_ERROR ) && ( EntriesRead > 0 ))
  275. {
  276. // For trees, we might get more than one entries back.
  277. PCONN_STATUS pConnStatus = (PCONN_STATUS) Buffer;
  278. if ( !pConnStatus->fPreferred )
  279. {
  280. // We only need to return as attached if this is not a preferred
  281. // server implicit connection since we don't want the user to know
  282. // about this connection ( which rdr does not allow user to delete)
  283. *pfAttached = TRUE;
  284. *pfAuthenticated = (pConnStatus->dwConnType != NW_CONN_NOT_AUTHENTICATED);
  285. }
  286. }
  287. if ( Buffer != NULL )
  288. {
  289. LocalFree( Buffer );
  290. Buffer = NULL;
  291. }
  292. return err;
  293. }
  294. DWORD
  295. NwGetConnectionInformation(
  296. IN LPWSTR pszName,
  297. OUT LPBYTE Buffer,
  298. IN DWORD BufferSize
  299. )
  300. {
  301. NTSTATUS ntstatus = STATUS_SUCCESS;
  302. HANDLE handleRdr = NULL;
  303. OBJECT_ATTRIBUTES ObjectAttributes;
  304. IO_STATUS_BLOCK IoStatusBlock;
  305. UNICODE_STRING uRdrName;
  306. WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
  307. PNWR_REQUEST_PACKET RequestPacket = NULL;
  308. DWORD RequestPacketSize = 0;
  309. DWORD dwNameLen = 0;
  310. if ( pszName == NULL )
  311. return ERROR_INVALID_PARAMETER;
  312. //
  313. // Set up the object attributes.
  314. //
  315. RtlInitUnicodeString( &uRdrName, RdrPrefix );
  316. InitializeObjectAttributes( &ObjectAttributes,
  317. &uRdrName,
  318. OBJ_CASE_INSENSITIVE,
  319. NULL,
  320. NULL );
  321. ntstatus = NtOpenFile( &handleRdr,
  322. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  323. &ObjectAttributes,
  324. &IoStatusBlock,
  325. FILE_SHARE_VALID_FLAGS,
  326. FILE_SYNCHRONOUS_IO_NONALERT );
  327. if ( !NT_SUCCESS(ntstatus) )
  328. goto CleanExit;
  329. dwNameLen = wcslen(pszName) * sizeof(WCHAR);
  330. RequestPacketSize = sizeof( NWR_REQUEST_PACKET ) + dwNameLen;
  331. RequestPacket = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT,
  332. RequestPacketSize );
  333. if ( RequestPacket == NULL )
  334. {
  335. ntstatus = STATUS_NO_MEMORY;
  336. goto CleanExit;
  337. }
  338. //
  339. // Fill out the request packet for FSCTL_NWR_GET_CONN_INFO.
  340. //
  341. RequestPacket->Version = REQUEST_PACKET_VERSION;
  342. RequestPacket->Parameters.GetConnInfo.ConnectionNameLength = dwNameLen;
  343. RtlCopyMemory( &(RequestPacket->Parameters.GetConnInfo.ConnectionName[0]),
  344. pszName,
  345. dwNameLen );
  346. ntstatus = NtFsControlFile( handleRdr,
  347. NULL,
  348. NULL,
  349. NULL,
  350. &IoStatusBlock,
  351. FSCTL_NWR_GET_CONN_INFO,
  352. (PVOID) RequestPacket,
  353. RequestPacketSize,
  354. (PVOID) Buffer,
  355. BufferSize );
  356. if ( NT_SUCCESS( ntstatus ))
  357. ntstatus = IoStatusBlock.Status;
  358. CleanExit:
  359. if ( handleRdr != NULL )
  360. NtClose( handleRdr );
  361. if ( RequestPacket != NULL )
  362. LocalFree( RequestPacket );
  363. return RtlNtStatusToDosError( ntstatus );
  364. }
  365. DWORD
  366. NWPGetConnectionStatus(
  367. IN LPWSTR pszRemoteName,
  368. IN OUT PDWORD_PTR ResumeKey,
  369. OUT LPBYTE Buffer,
  370. IN DWORD BufferSize,
  371. OUT PDWORD BytesNeeded,
  372. OUT PDWORD EntriesRead
  373. )
  374. {
  375. NTSTATUS ntstatus = STATUS_SUCCESS;
  376. HANDLE handleRdr = NULL;
  377. OBJECT_ATTRIBUTES ObjectAttributes;
  378. IO_STATUS_BLOCK IoStatusBlock;
  379. UNICODE_STRING uRdrName;
  380. WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
  381. PNWR_REQUEST_PACKET RequestPacket = NULL;
  382. DWORD RequestPacketSize = 0;
  383. DWORD dwRemoteNameLen = 0;
  384. //
  385. // Set up the object attributes.
  386. //
  387. RtlInitUnicodeString( &uRdrName, RdrPrefix );
  388. InitializeObjectAttributes( &ObjectAttributes,
  389. &uRdrName,
  390. OBJ_CASE_INSENSITIVE,
  391. NULL,
  392. NULL );
  393. ntstatus = NtOpenFile( &handleRdr,
  394. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  395. &ObjectAttributes,
  396. &IoStatusBlock,
  397. FILE_SHARE_VALID_FLAGS,
  398. FILE_SYNCHRONOUS_IO_NONALERT );
  399. if ( !NT_SUCCESS(ntstatus) )
  400. goto CleanExit;
  401. dwRemoteNameLen = pszRemoteName? wcslen(pszRemoteName)*sizeof(WCHAR) : 0;
  402. RequestPacketSize = sizeof( NWR_REQUEST_PACKET ) + dwRemoteNameLen;
  403. RequestPacket = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT,
  404. RequestPacketSize );
  405. if ( RequestPacket == NULL )
  406. {
  407. ntstatus = STATUS_NO_MEMORY;
  408. goto CleanExit;
  409. }
  410. //
  411. // Fill out the request packet for FSCTL_NWR_GET_CONN_STATUS.
  412. //
  413. RequestPacket->Parameters.GetConnStatus.ResumeKey = *ResumeKey;
  414. RequestPacket->Version = REQUEST_PACKET_VERSION;
  415. RequestPacket->Parameters.GetConnStatus.ConnectionNameLength = dwRemoteNameLen;
  416. RtlCopyMemory( &(RequestPacket->Parameters.GetConnStatus.ConnectionName[0]),
  417. pszRemoteName,
  418. dwRemoteNameLen );
  419. ntstatus = NtFsControlFile( handleRdr,
  420. NULL,
  421. NULL,
  422. NULL,
  423. &IoStatusBlock,
  424. FSCTL_NWR_GET_CONN_STATUS,
  425. (PVOID) RequestPacket,
  426. RequestPacketSize,
  427. (PVOID) Buffer,
  428. BufferSize );
  429. if ( NT_SUCCESS( ntstatus ))
  430. ntstatus = IoStatusBlock.Status;
  431. *EntriesRead = RequestPacket->Parameters.GetConnStatus.EntriesReturned;
  432. *ResumeKey = RequestPacket->Parameters.GetConnStatus.ResumeKey;
  433. *BytesNeeded = RequestPacket->Parameters.GetConnStatus.BytesNeeded;
  434. CleanExit:
  435. if ( handleRdr != NULL )
  436. NtClose( handleRdr );
  437. if ( RequestPacket != NULL )
  438. LocalFree( RequestPacket );
  439. return RtlNtStatusToDosError( ntstatus );
  440. }
  441. DWORD
  442. NwGetConnectionStatus(
  443. IN LPWSTR pszRemoteName,
  444. OUT PDWORD_PTR ResumeKey,
  445. OUT LPBYTE *Buffer,
  446. OUT PDWORD EntriesRead
  447. )
  448. {
  449. DWORD err = NO_ERROR;
  450. DWORD dwBytesNeeded = 0;
  451. DWORD dwBufferSize = TWO_KB;
  452. *Buffer = NULL;
  453. *EntriesRead = 0;
  454. do {
  455. *Buffer = (LPBYTE) LocalAlloc( LMEM_ZEROINIT, dwBufferSize );
  456. if ( *Buffer == NULL )
  457. return ERROR_NOT_ENOUGH_MEMORY;
  458. err = NWPGetConnectionStatus( pszRemoteName,
  459. ResumeKey,
  460. *Buffer,
  461. dwBufferSize,
  462. &dwBytesNeeded,
  463. EntriesRead );
  464. if ( err == ERROR_INSUFFICIENT_BUFFER )
  465. {
  466. dwBufferSize = dwBytesNeeded + EXTRA_BYTES;
  467. LocalFree( *Buffer );
  468. *Buffer = NULL;
  469. }
  470. } while ( err == ERROR_INSUFFICIENT_BUFFER );
  471. if ( err == ERROR_INVALID_PARAMETER ) // not attached
  472. {
  473. err = NO_ERROR;
  474. *EntriesRead = 0;
  475. }
  476. return err;
  477. }
  478. DWORD
  479. NwGetNdsVolumeInfo(
  480. IN LPWSTR pszName,
  481. OUT LPWSTR pszServerBuffer,
  482. IN WORD wServerBufferSize, // in bytes
  483. OUT LPWSTR pszVolumeBuffer,
  484. IN WORD wVolumeBufferSize // in bytes
  485. )
  486. {
  487. NTSTATUS ntstatus = STATUS_SUCCESS;
  488. HANDLE handleNdsTree;
  489. LPWSTR pszTree, pszVolume, pszTemp;
  490. UNICODE_STRING uTree, uVolume;
  491. UNICODE_STRING uHostServer, uHostVolume;
  492. WCHAR HostVolumeBuffer[256];
  493. pszTree = pszName + 2; // get past two backslashes
  494. pszTemp = wcschr( pszTree, L'\\' );
  495. if ( pszTemp )
  496. *pszTemp = 0;
  497. else
  498. return ERROR_INVALID_PARAMETER;
  499. pszVolume = pszTemp + 1;
  500. RtlInitUnicodeString( &uTree, pszTree );
  501. RtlInitUnicodeString( &uVolume, pszVolume );
  502. //
  503. // Open up a handle to the tree.
  504. //
  505. ntstatus = NwNdsOpenTreeHandle( &uTree,
  506. &handleNdsTree );
  507. if ( !NT_SUCCESS( ntstatus ))
  508. goto CleanExit;
  509. //
  510. // Set up the reply strings.
  511. //
  512. uHostServer.Length = 0;
  513. uHostServer.MaximumLength = wServerBufferSize;
  514. uHostServer.Buffer = pszServerBuffer;
  515. RtlZeroMemory( pszServerBuffer, wServerBufferSize );
  516. if ( pszVolumeBuffer != NULL )
  517. {
  518. uHostVolume.Length = 0;
  519. uHostVolume.MaximumLength = wVolumeBufferSize;
  520. uHostVolume.Buffer = pszVolumeBuffer;
  521. RtlZeroMemory( pszVolumeBuffer, wVolumeBufferSize );
  522. }
  523. else
  524. {
  525. uHostVolume.Length = 0;
  526. uHostVolume.MaximumLength = sizeof( HostVolumeBuffer );
  527. uHostVolume.Buffer = HostVolumeBuffer;
  528. }
  529. ntstatus = NwNdsGetVolumeInformation( handleNdsTree,
  530. &uVolume,
  531. &uHostServer,
  532. &uHostVolume );
  533. CloseHandle( handleNdsTree );
  534. CleanExit:
  535. //
  536. // Note: This change added to fix NT bug 338991 on Win2000
  537. //
  538. if ( ntstatus == STATUS_BAD_NETWORK_PATH )
  539. {
  540. ntstatus = STATUS_ACCESS_DENIED;
  541. }
  542. if ( pszTemp )
  543. *pszTemp = L'\\';
  544. return RtlNtStatusToDosError( ntstatus );
  545. }
  546. DWORD
  547. NwOpenAndGetTreeInfo(
  548. LPWSTR pszNdsUNCPath,
  549. HANDLE *phTreeConn,
  550. DWORD *pdwOid
  551. )
  552. {
  553. NTSTATUS ntstatus = STATUS_SUCCESS;
  554. WCHAR lpServerName[NW_MAX_SERVER_LEN];
  555. UNICODE_STRING ServerName;
  556. UNICODE_STRING ObjectName;
  557. *phTreeConn = NULL;
  558. ServerName.Length = 0;
  559. ServerName.MaximumLength = sizeof( lpServerName );
  560. ServerName.Buffer = lpServerName;
  561. ObjectName.Buffer = NULL;
  562. ObjectName.MaximumLength = ( wcslen( pszNdsUNCPath) + 1 ) * sizeof( WCHAR );
  563. ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
  564. pszNdsUNCPath,
  565. PARSE_NDS_GET_TREE_NAME );
  566. if ( ObjectName.Length == 0 || ObjectName.Buffer == NULL )
  567. {
  568. return ERROR_PATH_NOT_FOUND;
  569. }
  570. //
  571. // Open a NDS tree connection handle to \\treename
  572. //
  573. ntstatus = NwNdsOpenTreeHandle( &ObjectName, phTreeConn );
  574. if ( !NT_SUCCESS( ntstatus ))
  575. {
  576. return RtlNtStatusToDosError( ntstatus );
  577. }
  578. //
  579. // Get the path to the container to open.
  580. //
  581. ObjectName.Length = NwParseNdsUncPath( (LPWSTR *) &ObjectName.Buffer,
  582. pszNdsUNCPath,
  583. PARSE_NDS_GET_PATH_NAME );
  584. if ( ObjectName.Length == 0 )
  585. {
  586. UNICODE_STRING Root;
  587. RtlInitUnicodeString(&Root, L"[Root]");
  588. //
  589. // Resolve the path to get a NDS object id.
  590. //
  591. ntstatus = NwNdsResolveName( *phTreeConn,
  592. &Root,
  593. pdwOid,
  594. &ServerName,
  595. NULL,
  596. 0 );
  597. }
  598. else
  599. {
  600. //
  601. // Resolve the path to get a NDS object id.
  602. //
  603. ntstatus = NwNdsResolveName( *phTreeConn,
  604. &ObjectName,
  605. pdwOid,
  606. &ServerName,
  607. NULL,
  608. 0 );
  609. }
  610. if ( ntstatus == STATUS_SUCCESS && ServerName.Length )
  611. {
  612. DWORD dwHandleType;
  613. //
  614. // NwNdsResolveName succeeded, but we were referred to
  615. // another server, though pdwOid is still valid.
  616. if ( *phTreeConn )
  617. CloseHandle( *phTreeConn );
  618. *phTreeConn = NULL;
  619. //
  620. // Open a NDS generic connection handle to \\ServerName
  621. //
  622. ntstatus = NwNdsOpenGenericHandle( &ServerName,
  623. &dwHandleType,
  624. phTreeConn );
  625. if ( ntstatus != STATUS_SUCCESS )
  626. {
  627. return RtlNtStatusToDosError(ntstatus);
  628. }
  629. ASSERT( dwHandleType != HANDLE_TYPE_NCP_SERVER );
  630. }
  631. if ( !NT_SUCCESS( ntstatus ))
  632. {
  633. if ( *phTreeConn != NULL )
  634. {
  635. CloseHandle( *phTreeConn );
  636. *phTreeConn = NULL;
  637. }
  638. return RtlNtStatusToDosError(ntstatus);
  639. }
  640. return NO_ERROR;
  641. }
  642. DWORD
  643. NwGetConnectedTrees(
  644. IN LPWSTR pszNtUserName,
  645. OUT LPBYTE Buffer,
  646. IN DWORD BufferSize,
  647. OUT LPDWORD lpEntriesRead,
  648. OUT LPDWORD lpUserLUID
  649. )
  650. {
  651. NTSTATUS ntstatus = STATUS_SUCCESS;
  652. HANDLE handleRdr = NULL;
  653. OBJECT_ATTRIBUTES ObjectAttributes;
  654. IO_STATUS_BLOCK IoStatusBlock;
  655. WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
  656. UNICODE_STRING uRdrName;
  657. UNICODE_STRING uNtUserName;
  658. PNWR_NDS_REQUEST_PACKET Request = NULL;
  659. BYTE RequestBuffer[2048];
  660. DWORD RequestSize = 0;
  661. *lpEntriesRead = 0;
  662. //
  663. // Convert the user name to unicode.
  664. //
  665. RtlInitUnicodeString( &uNtUserName, pszNtUserName );
  666. //
  667. // Set up the object attributes.
  668. //
  669. RtlInitUnicodeString( &uRdrName, RdrPrefix );
  670. InitializeObjectAttributes( &ObjectAttributes,
  671. &uRdrName,
  672. OBJ_CASE_INSENSITIVE,
  673. NULL,
  674. NULL );
  675. ntstatus = NtOpenFile( &handleRdr,
  676. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  677. &ObjectAttributes,
  678. &IoStatusBlock,
  679. FILE_SHARE_VALID_FLAGS,
  680. FILE_SYNCHRONOUS_IO_NONALERT );
  681. if ( !NT_SUCCESS(ntstatus) )
  682. goto CleanExit;
  683. //
  684. // Fill out the request packet for FSCTL_NWR_NDS_LIST_TREES;
  685. //
  686. Request = ( PNWR_NDS_REQUEST_PACKET ) RequestBuffer;
  687. Request->Parameters.ListTrees.NtUserNameLength = uNtUserName.Length;
  688. RtlCopyMemory( &(Request->Parameters.ListTrees.NtUserName[0]),
  689. uNtUserName.Buffer,
  690. uNtUserName.Length );
  691. RequestSize = sizeof( Request->Parameters.ListTrees ) +
  692. uNtUserName.Length +
  693. sizeof( DWORD );
  694. ntstatus = NtFsControlFile( handleRdr,
  695. NULL,
  696. NULL,
  697. NULL,
  698. &IoStatusBlock,
  699. FSCTL_NWR_NDS_LIST_TREES,
  700. (PVOID) Request,
  701. RequestSize,
  702. (PVOID) Buffer,
  703. BufferSize );
  704. if ( NT_SUCCESS( ntstatus ))
  705. {
  706. ntstatus = IoStatusBlock.Status;
  707. *lpEntriesRead = Request->Parameters.ListTrees.TreesReturned;
  708. *lpUserLUID = Request->Parameters.ListTrees.UserLuid.LowPart;
  709. }
  710. CleanExit:
  711. if ( handleRdr != NULL )
  712. NtClose( handleRdr );
  713. return RtlNtStatusToDosError( ntstatus );
  714. }