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.

1885 lines
49 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. connect.c
  5. Abstract:
  6. This module contains tree connections routines supported by
  7. NetWare Workstation service.
  8. Author:
  9. Rita Wong (ritaw) 15-Feb-1993
  10. Revision History:
  11. --*/
  12. #include <nw.h>
  13. #include <handle.h>
  14. #include <nwauth.h>
  15. #include <nwcanon.h>
  16. #include <nwreg.h>
  17. #include <winbasep.h>
  18. #define NW_ENUM_EXTRA_BYTES 256
  19. extern BOOL NwLUIDDeviceMapsEnabled;
  20. //-------------------------------------------------------------------//
  21. // //
  22. // Local Function Prototypes //
  23. // //
  24. //-------------------------------------------------------------------//
  25. DWORD
  26. NwAllocAndGetUncName(
  27. IN LPWSTR LocalName,
  28. IN DWORD LocalNameLength,
  29. OUT LPWSTR *UncName
  30. );
  31. DWORD
  32. NwDeleteAllInRegistry(
  33. VOID
  34. );
  35. DWORD
  36. NwDeleteUidSymLinks(
  37. IN LUID Uid,
  38. IN ULONG WinStationId
  39. );
  40. LPTSTR
  41. NwReturnSessionPath(
  42. IN LPTSTR LocalDeviceName
  43. );
  44. //-------------------------------------------------------------------//
  45. DWORD
  46. NwrCreateConnection(
  47. IN LPWSTR Reserved OPTIONAL,
  48. IN LPWSTR LocalName OPTIONAL,
  49. IN LPWSTR RemoteName,
  50. IN DWORD Type,
  51. IN LPWSTR Password OPTIONAL,
  52. IN LPWSTR UserName OPTIONAL
  53. )
  54. /*++
  55. Routine Description:
  56. This function creates a tree connection to the specified RemoteName
  57. (UNC name) and maps it to the LocalName (local device name), if
  58. it is specified. The password and user name are the credentials
  59. used to create the connection, if specified; otherwise, the
  60. interactive logged on user's credentials are used by default.
  61. NOTE: This code now calls a helper routine to do the work, this helper
  62. routine (NwCreateConnection) is identical to the code that used to be
  63. here with the exception that the helper does call ImpersonateClient().
  64. We now do the client impersonation outside of the helper routine.
  65. Arguments:
  66. Reserved - Must be NULL.
  67. LocalName - Supplies the local device name to map to the created tree
  68. connection. Only drive letter device names are accepted. (No
  69. LPT or COM).
  70. RemoteName - Supplies the UNC name of the remote resource in the format
  71. of Server\Volume\Directory. It must be a disk resource.
  72. Type - Supplies the connection type.
  73. Password - Supplies the password to use to make the connection to the
  74. server.
  75. UserName - Supplies the user name to use to make the connection.
  76. Return Value:
  77. NO_ERROR - Operation was successful.
  78. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating internal work buffers.
  79. WN_BAD_NETNAME - Remote resource name is invalid.
  80. WN_BAD_LOCALNAME - Local DOS device name is invalid.
  81. ERROR_BAD_NETPATH - The UNC name does not exist on the network.
  82. ERROR_INVALID_PARAMETER - LPT or COM LocalName was specified.
  83. Other errors from the redirector.
  84. --*/
  85. {
  86. DWORD status;
  87. BOOL Impersonate = FALSE ;
  88. UNREFERENCED_PARAMETER(Reserved);
  89. //
  90. // Impersonate the client
  91. //
  92. if ((status = NwImpersonateClient()) != NO_ERROR)
  93. {
  94. goto CleanExit;
  95. }
  96. Impersonate = TRUE ;
  97. status = NwCreateConnection( LocalName,
  98. RemoteName,
  99. Type,
  100. Password,
  101. UserName );
  102. CleanExit:
  103. if (Impersonate) {
  104. (void) NwRevertToSelf();
  105. }
  106. #if DBG
  107. IF_DEBUG(CONNECT) {
  108. KdPrint(("NWWORKSTATION: NwrCreateConnection returns %lu\n", status));
  109. }
  110. #endif
  111. return status;
  112. }
  113. DWORD
  114. NwrDeleteConnection(
  115. IN LPWSTR Reserved OPTIONAL,
  116. IN LPWSTR ConnectionName,
  117. IN DWORD UseForce
  118. )
  119. /*++
  120. Routine Description:
  121. This function deletes an existing connection.
  122. Arguments:
  123. Reserved - Must be NULL.
  124. ConnectionName - Supplies the local device name or UNC name which
  125. specifies the connection to delete. If UNC name is specified,
  126. the UNC connection must exist.
  127. UseForce - Supplies a flag which if TRUE specifies to tear down
  128. the connection eventhough files are opened. If FALSE, the
  129. connection is deleted only if there are no opened files.
  130. Return Value:
  131. NO_ERROR - Operation was successful.
  132. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating internal work buffers.
  133. WN_BAD_NETNAME - ConnectionName is invalid.
  134. ERROR_BAD_NETPATH - The UNC name does not exist on the network.
  135. ERROR_INVALID_PARAMETER - LPT or COM LocalName was specified.
  136. Other errors from the redirector.
  137. --*/
  138. {
  139. DWORD status;
  140. LPWSTR ConnectName = NULL;
  141. DWORD ConnectLength;
  142. LPWSTR LocalName;
  143. LPWSTR UncName = NULL;
  144. BOOL Impersonate = FALSE ;
  145. UNREFERENCED_PARAMETER(Reserved);
  146. if (*ConnectionName == 0) {
  147. return ERROR_INVALID_PARAMETER;
  148. }
  149. #if DBG
  150. IF_DEBUG(CONNECT) {
  151. KdPrint(("\nNWWORKSTATION: NwrDeleteConnection: ConnectionName %ws, Force %lu\n",
  152. ConnectionName, UseForce));
  153. }
  154. #endif
  155. if ((status = NwLibCanonLocalName(
  156. ConnectionName,
  157. &ConnectName,
  158. &ConnectLength
  159. )) == NO_ERROR) {
  160. //
  161. // Get the UNC name mapped to this drive letter so that we can
  162. // open a handle to it for deletion.
  163. //
  164. // ----Multi-user---------
  165. // Need to impersonate the client
  166. if ((status = NwImpersonateClient()) != NO_ERROR) {
  167. goto CleanExit;
  168. }
  169. Impersonate = TRUE ;
  170. if ((status = NwAllocAndGetUncName(
  171. ConnectName,
  172. ConnectLength,
  173. &UncName
  174. )) != NO_ERROR) {
  175. (void) LocalFree((HLOCAL) ConnectName);
  176. if (Impersonate) {
  177. (void) NwRevertToSelf();
  178. }
  179. return status;
  180. }
  181. LocalName = ConnectName;
  182. }
  183. else {
  184. //
  185. // Not a device name. See if it is a UNC name.
  186. //
  187. if ((status = NwLibCanonRemoteName(
  188. NULL,
  189. ConnectionName,
  190. &ConnectName,
  191. NULL
  192. )) != NO_ERROR) {
  193. return status;
  194. }
  195. UncName = ConnectName;
  196. LocalName = NULL;
  197. }
  198. if ( !Impersonate ) {
  199. if ((status = NwImpersonateClient()) != NO_ERROR) {
  200. goto CleanExit;
  201. }
  202. Impersonate = TRUE ;
  203. }
  204. //
  205. // To delete a connection, a tree connection handle must be opened to
  206. // it so that the handle can be specified to the redirector to delete
  207. // the connection.
  208. //
  209. status = NwOpenHandleToDeleteConn(
  210. UncName,
  211. LocalName,
  212. UseForce,
  213. FALSE,
  214. TRUE
  215. );
  216. if ( status == ERROR_FILE_NOT_FOUND )
  217. status = ERROR_BAD_NETPATH;
  218. CleanExit:
  219. if (Impersonate) {
  220. (void) NwRevertToSelf();
  221. }
  222. if (UncName != NULL && UncName != ConnectName) {
  223. (void) LocalFree((HLOCAL) UncName);
  224. }
  225. if (ConnectName != NULL) {
  226. (void) LocalFree((HLOCAL) ConnectName);
  227. }
  228. #if DBG
  229. IF_DEBUG(CONNECT) {
  230. KdPrint(("NWWORKSTATION: NwrDeleteConnection returns %lu\n", status));
  231. }
  232. #endif
  233. return status;
  234. }
  235. DWORD
  236. NwrQueryServerResource(
  237. IN LPWSTR Reserved OPTIONAL,
  238. IN LPWSTR LocalName,
  239. OUT LPWSTR RemoteName,
  240. IN DWORD RemoteNameLen,
  241. OUT LPDWORD CharsRequired
  242. )
  243. /*++
  244. Routine Description:
  245. This function looks up the UNC name associated with the given DOS
  246. device name.
  247. Arguments:
  248. Reserved - Must be NULL.
  249. LocalName - Supplies the local device name to look up.
  250. RemoteName - Receives the UNC name mapped to the LocalName.
  251. RemoteNameLen - Supplies the length of the RemoteName buffer.
  252. CharsRequired - Receives the length required of the RemoteName buffer
  253. to get the UNC name. This value is only returned if the return
  254. code is ERROR_MORE_DATA.
  255. Return Value:
  256. NO_ERROR - Operation was successful.
  257. WN_BAD_LOCALNAME - LocalName was invalid.
  258. ERROR_INVALID_PARAMETER - LPT or COM LocalName was specified.
  259. ERROR_MORE_DATA - RemoteName buffer was too small.
  260. ERROR_NOT_CONNECTED - LocalName does not map to any server resource.
  261. --*/
  262. {
  263. DWORD status;
  264. LPWSTR Local;
  265. DWORD LocalLength;
  266. BOOL Impersonate = FALSE ;
  267. UNREFERENCED_PARAMETER(Reserved);
  268. #if DBG
  269. IF_DEBUG(CONNECT) {
  270. KdPrint(("\nNWWORKSTATION: NwrQueryServerResource: LocalName %ws, RemoteNameLen %lu\n",
  271. LocalName, RemoteNameLen));
  272. }
  273. #endif
  274. //
  275. // Canonicalize the LocalName
  276. //
  277. if ((status = NwLibCanonLocalName(
  278. LocalName,
  279. &Local,
  280. &LocalLength
  281. )) != NO_ERROR) {
  282. return WN_BAD_LOCALNAME;
  283. }
  284. if ((status = NwImpersonateClient()) != NO_ERROR)
  285. {
  286. goto CleanExit;
  287. }
  288. Impersonate = TRUE ;
  289. status = NwGetServerResource(
  290. Local,
  291. LocalLength,
  292. RemoteName,
  293. RemoteNameLen,
  294. CharsRequired
  295. );
  296. CleanExit:
  297. if (Impersonate) {
  298. (void) NwRevertToSelf();
  299. }
  300. (void) LocalFree((HLOCAL) Local);
  301. #if DBG
  302. IF_DEBUG(CONNECT) {
  303. KdPrint(("NWWORKSTATION: NwrQueryServerResource returns %lu\n", status));
  304. if (status == NO_ERROR) {
  305. KdPrint((" RemoteName is %ws\n", RemoteName));
  306. }
  307. else if (status == ERROR_MORE_DATA) {
  308. KdPrint((" RemoteNameLen %lu too small. Need %lu\n",
  309. RemoteNameLen, *CharsRequired));
  310. }
  311. }
  312. #endif
  313. return status;
  314. }
  315. DWORD
  316. NwrOpenEnumConnections(
  317. IN LPWSTR Reserved OPTIONAL,
  318. IN DWORD ConnectionType,
  319. OUT LPNWWKSTA_CONTEXT_HANDLE EnumHandle
  320. )
  321. /*++
  322. Routine Description:
  323. This function creates a new context handle and initializes it
  324. for enumerating the connections.
  325. Arguments:
  326. Reserved - Unused.
  327. EnumHandle - Receives the newly created context handle.
  328. Return Value:
  329. ERROR_NOT_ENOUGH_MEMORY - if the memory for the context could
  330. not be allocated.
  331. NO_ERROR - Call was successful.
  332. --*/
  333. {
  334. LPNW_ENUM_CONTEXT ContextHandle;
  335. UNREFERENCED_PARAMETER(Reserved);
  336. #if DBG
  337. IF_DEBUG(CONNECT) {
  338. KdPrint(("\nNWWORKSTATION: NwrOpenEnumConnections\n"));
  339. }
  340. #endif
  341. //
  342. // Allocate memory for the context handle structure.
  343. //
  344. ContextHandle = (PVOID) LocalAlloc(
  345. LMEM_ZEROINIT,
  346. sizeof(NW_ENUM_CONTEXT)
  347. );
  348. if (ContextHandle == NULL) {
  349. KdPrint(("NWWORKSTATION: NwrOpenEnumConnections LocalAlloc Failed %lu\n",
  350. GetLastError()));
  351. return ERROR_NOT_ENOUGH_MEMORY;
  352. }
  353. //
  354. // Initialize contents of the context handle structure.
  355. //
  356. ContextHandle->Signature = NW_HANDLE_SIGNATURE;
  357. ContextHandle->HandleType = NwsHandleListConnections;
  358. ContextHandle->ResumeId = 0;
  359. ContextHandle->ConnectionType = 0;
  360. if ( ConnectionType == RESOURCETYPE_ANY ) {
  361. ContextHandle->ConnectionType = CONNTYPE_ANY;
  362. }
  363. else {
  364. if ( ConnectionType & RESOURCETYPE_DISK )
  365. ContextHandle->ConnectionType |= CONNTYPE_DISK;
  366. if ( ConnectionType & RESOURCETYPE_PRINT )
  367. ContextHandle->ConnectionType |= CONNTYPE_PRINT;
  368. }
  369. //
  370. // Return the newly created context.
  371. //
  372. *EnumHandle = (LPNWWKSTA_CONTEXT_HANDLE) ContextHandle;
  373. return NO_ERROR;
  374. }
  375. DWORD
  376. NwrGetConnectionPerformance(
  377. IN LPWSTR Reserved OPTIONAL,
  378. IN LPWSTR lpRemoteName,
  379. OUT LPBYTE lpNetConnectInfo,
  380. IN DWORD dwBufferSize
  381. )
  382. /*++
  383. Routine Description:
  384. This function returns information about the expected performance of a
  385. connection used to access a network resource. The request can only be
  386. for a network resource to which there is currently a connection.
  387. Arguments:
  388. Reserved - Unused.
  389. lpRemoteName - Contains the local name or remote name for a resource
  390. for which a connection exists.
  391. lpNetConnectInfo - This is a pointer to a NETCONNECTINFOSTRUCT structure
  392. which is to be filled if the connection performance
  393. of connection lpRemoteName can be determined.
  394. Return Value:
  395. NO_ERROR - Successful.
  396. WN_NOT_CONNECTED - Connection could not be found.
  397. WN_NONETWORK - Network is not present.
  398. Other network errors.
  399. --*/
  400. {
  401. DWORD status = NO_ERROR;
  402. LPNETCONNECTINFOSTRUCT lpNetConnInfo =
  403. (LPNETCONNECTINFOSTRUCT) lpNetConnectInfo;
  404. NTSTATUS ntstatus;
  405. IO_STATUS_BLOCK IoStatusBlock;
  406. OBJECT_ATTRIBUTES ObjectAttributes;
  407. ACCESS_MASK DesiredAccess = SYNCHRONIZE | FILE_LIST_DIRECTORY;
  408. //
  409. // dfergus 19 Apr 2001 - #333280
  410. // Init hRdr so test for null is valid
  411. HANDLE hRdr = NULL;
  412. WCHAR OpenString[] = L"\\Device\\Nwrdr\\*";
  413. UNICODE_STRING OpenName;
  414. UNICODE_STRING ConnectionName;
  415. PNWR_REQUEST_PACKET Request = NULL;
  416. ULONG BufferSize = 0;
  417. ULONG RequestSize;
  418. BOOL Impersonate = FALSE ;
  419. UNREFERENCED_PARAMETER(Reserved);
  420. UNREFERENCED_PARAMETER(dwBufferSize);
  421. if (lpRemoteName == NULL)
  422. {
  423. return ERROR_INVALID_PARAMETER;
  424. }
  425. BufferSize = sizeof(NWR_REQUEST_PACKET) +
  426. ( ( wcslen(lpRemoteName) + 1 ) * sizeof(WCHAR) );
  427. //
  428. // Impersonate the client
  429. //
  430. if ((status = NwImpersonateClient()) != NO_ERROR)
  431. {
  432. goto ExitWithClose;
  433. }
  434. Impersonate = TRUE;
  435. //
  436. // Allocate buffer space.
  437. //
  438. Request = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT, BufferSize );
  439. if ( Request == NULL )
  440. {
  441. KdPrint(("NWWORKSTATION: NwrGetConnectionPerformance LocalAlloc Failed %lu\n",
  442. GetLastError()));
  443. return ERROR_NOT_ENOUGH_MEMORY;
  444. }
  445. RtlInitUnicodeString( &OpenName, OpenString );
  446. InitializeObjectAttributes( &ObjectAttributes,
  447. &OpenName,
  448. OBJ_CASE_INSENSITIVE,
  449. NULL,
  450. NULL );
  451. ntstatus = NtOpenFile( &hRdr,
  452. DesiredAccess,
  453. &ObjectAttributes,
  454. &IoStatusBlock,
  455. FILE_SHARE_VALID_FLAGS,
  456. FILE_SYNCHRONOUS_IO_NONALERT );
  457. if ( !NT_SUCCESS(ntstatus) )
  458. {
  459. status = RtlNtStatusToDosError(ntstatus);
  460. goto ExitWithClose;
  461. }
  462. //
  463. // Fill out the request packet for FSCTL_NWR_GET_CONN_PERFORMANCE.
  464. //
  465. RtlInitUnicodeString( &ConnectionName, lpRemoteName );
  466. Request->Parameters.GetConnPerformance.RemoteNameLength =
  467. ConnectionName.Length;
  468. RtlCopyMemory( Request->Parameters.GetConnPerformance.RemoteName,
  469. ConnectionName.Buffer,
  470. ConnectionName.Length );
  471. RequestSize = sizeof( NWR_REQUEST_PACKET ) + ConnectionName.Length;
  472. ntstatus = NtFsControlFile( hRdr,
  473. NULL,
  474. NULL,
  475. NULL,
  476. &IoStatusBlock,
  477. FSCTL_NWR_GET_CONN_PERFORMANCE,
  478. (PVOID) Request,
  479. RequestSize,
  480. NULL,
  481. 0 );
  482. if ( !NT_SUCCESS( ntstatus ) )
  483. {
  484. status = RtlNtStatusToDosError(ntstatus);
  485. goto ExitWithClose;
  486. }
  487. lpNetConnInfo->cbStructure = sizeof(NETCONNECTINFOSTRUCT);
  488. lpNetConnInfo->dwFlags = Request->Parameters.GetConnPerformance.dwFlags;
  489. lpNetConnInfo->dwSpeed = Request->Parameters.GetConnPerformance.dwSpeed;
  490. lpNetConnInfo->dwDelay = Request->Parameters.GetConnPerformance.dwDelay;
  491. lpNetConnInfo->dwOptDataSize =
  492. Request->Parameters.GetConnPerformance.dwOptDataSize;
  493. ExitWithClose:
  494. if ( Request )
  495. LocalFree( Request );
  496. if ( Impersonate )
  497. {
  498. (void) NwRevertToSelf();
  499. }
  500. if ( hRdr )
  501. NtClose( hRdr );
  502. return status;
  503. }
  504. DWORD
  505. NwAllocAndGetUncName(
  506. IN LPWSTR LocalName,
  507. IN DWORD LocalNameLength,
  508. OUT LPWSTR *UncName
  509. )
  510. /*++
  511. Routine Description:
  512. This function calls an internal routine to ask the redirector for the
  513. UNC name of a given DOS device name. It also allocates the output
  514. buffer to hold the UNC name.
  515. Arguments:
  516. LocalName - Supplies the DOS device name.
  517. LocalNameLength - Supplies the length of the DOS device name (chars).
  518. UncName - Receives a pointer to the output buffer allocated by this
  519. routine which contains the UNC name of the DOS device.
  520. Return Value:
  521. NO_ERROR - Operation was successful.
  522. ERROR_NOT_ENOUGH_MEMORY - Could not allocate output buffer.
  523. Other errors from the redirector.
  524. --*/
  525. {
  526. DWORD status;
  527. DWORD UncNameLength;
  528. *UncName = (PVOID) LocalAlloc(
  529. LMEM_ZEROINIT,
  530. (MAX_PATH + 1) * sizeof(WCHAR)
  531. );
  532. if (*UncName == NULL) {
  533. KdPrint(("NWWORKSTATION: NwAllocAndGetUncName LocalAlloc Failed %lu\n",
  534. GetLastError()));
  535. return ERROR_NOT_ENOUGH_MEMORY;
  536. }
  537. status = NwGetServerResource(
  538. LocalName,
  539. LocalNameLength,
  540. *UncName,
  541. MAX_PATH + 1,
  542. &UncNameLength
  543. );
  544. if ((status == ERROR_MORE_DATA) || (status == ERROR_INSUFFICIENT_BUFFER)) {
  545. //
  546. // Our output buffer was too small. Try again.
  547. //
  548. (void) LocalFree((HLOCAL) *UncName);
  549. *UncName = (PVOID) LocalAlloc(
  550. LMEM_ZEROINIT,
  551. UncNameLength * sizeof(WCHAR)
  552. );
  553. if (*UncName == NULL) {
  554. KdPrint(("NWWORKSTATION: NwAllocAndGetUncName LocalAlloc Failed %lu\n",
  555. GetLastError()));
  556. return ERROR_NOT_ENOUGH_MEMORY;
  557. }
  558. status = NwGetServerResource(
  559. LocalName,
  560. LocalNameLength,
  561. *UncName,
  562. UncNameLength,
  563. &UncNameLength
  564. );
  565. }
  566. //
  567. // callers will only free this if success.
  568. //
  569. if (status != NO_ERROR)
  570. {
  571. (void) LocalFree((HLOCAL) *UncName);
  572. *UncName = NULL ;
  573. }
  574. return status;
  575. }
  576. DWORD
  577. NwOpenHandleToDeleteConn(
  578. IN LPWSTR UncName,
  579. IN LPWSTR LocalName OPTIONAL,
  580. IN DWORD UseForce,
  581. IN BOOL IsStopWksta,
  582. IN BOOL ImpersonatingClient
  583. )
  584. /*++
  585. Routine Description:
  586. This function deletes an active connection by opening a tree connection
  587. handle to the connection first, and specifying this handle to the
  588. redirector to delete. This is because the workstation service does
  589. not keep any connection information.
  590. Arguments:
  591. UncName - Supplies the UNC name of the connection to delete.
  592. LocalName - Supplies the DOS device name of the connection, if any.
  593. UseForce - Supplies a flag which if TRUE specifies to tear down
  594. the connection eventhough files are opened. If FALSE, the
  595. connection is deleted only if there are no opened files.
  596. IsStopWksta - Supplies a flag which if TRUE indicates that we must
  597. delete the symbolic link, even when we have failed to delete the
  598. connection in the redirector. As much as possible must be cleaned
  599. up because the workstation service is stopping. A value of FALSE,
  600. indicates that the delete is aborted if we cannot delete it in
  601. the redirector.
  602. ImpersonatingClient - Flag that indicates whether the thread has
  603. called NwImpersonateClient. The gateway service functions don't
  604. impersonate, where as the client service operations do.
  605. Return Value:
  606. NO_ERROR - Operation was successful.
  607. ERROR_NOT_ENOUGH_MEMORY - Could not allocate output buffer.
  608. Other errors from the redirector.
  609. --*/
  610. {
  611. DWORD status;
  612. NTSTATUS ntstatus ;
  613. UNICODE_STRING TreeConnectStr;
  614. HANDLE TreeConnection = NULL;
  615. TreeConnectStr.Buffer = NULL;
  616. //
  617. // Create an NT-style tree connection name, either: \Device\Nwrdr\Server\Vol
  618. // or \Device\Nwrdr\X:\Server\Vol, if LocalName is specified.
  619. //
  620. if ((status = NwCreateTreeConnectName(
  621. UncName,
  622. LocalName,
  623. &TreeConnectStr
  624. )) != NO_ERROR) {
  625. return status;
  626. }
  627. ntstatus = NwCallNtOpenFile( &TreeConnection,
  628. SYNCHRONIZE | DELETE,
  629. &TreeConnectStr,
  630. FILE_CREATE_TREE_CONNECTION
  631. | FILE_SYNCHRONOUS_IO_NONALERT
  632. | FILE_DELETE_ON_CLOSE
  633. );
  634. //
  635. // treat the 2 as the same in order to return nicer error to user
  636. //
  637. if (ntstatus == STATUS_OBJECT_NAME_INVALID)
  638. ntstatus = STATUS_OBJECT_NAME_NOT_FOUND ;
  639. status = NwMapStatus(ntstatus) ;
  640. if (status == NO_ERROR) {
  641. //
  642. // Ask the redirector to delete the tree connection.
  643. //
  644. status = NwNukeConnection(
  645. TreeConnection,
  646. UseForce
  647. );
  648. (void) CloseHandle(TreeConnection);
  649. }
  650. if (ARGUMENT_PRESENT(LocalName) &&
  651. (status == NO_ERROR || IsStopWksta))
  652. {
  653. //
  654. // Delete the symbolic link we created.
  655. //
  656. NwDeleteSymbolicLink(
  657. LocalName,
  658. TreeConnectStr.Buffer,
  659. NULL,
  660. ImpersonatingClient
  661. );
  662. }
  663. if (TreeConnectStr.Buffer != NULL) {
  664. (void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
  665. }
  666. return status;
  667. }
  668. VOID
  669. DeleteAllConnections(
  670. VOID
  671. )
  672. /*++
  673. Routine Description:
  674. This function deletes all active connections returned by the
  675. redirector ENUMERATE_CONNECTIONS fsctl on workstation termination.
  676. Arguments:
  677. None.
  678. Return Value:
  679. None.
  680. --*/
  681. {
  682. DWORD status;
  683. NWWKSTA_CONTEXT_HANDLE EnumHandle;
  684. LPNETRESOURCEW NetR = NULL;
  685. DWORD BytesNeeded = 256;
  686. DWORD EntriesRead;
  687. status = NwrOpenEnumConnections(NULL, RESOURCETYPE_ANY, &EnumHandle);
  688. if ( status != NO_ERROR )
  689. return;
  690. //
  691. // Allocate buffer to get connection list.
  692. //
  693. if ((NetR = (LPVOID) LocalAlloc(
  694. 0,
  695. BytesNeeded
  696. )) == NULL) {
  697. status = ERROR_NOT_ENOUGH_MEMORY;
  698. goto CleanExit;
  699. }
  700. do {
  701. status = NwEnumerateConnections(
  702. &((LPNW_ENUM_CONTEXT) EnumHandle)->ResumeId,
  703. (DWORD) -1,
  704. (LPBYTE) NetR,
  705. BytesNeeded,
  706. &BytesNeeded,
  707. &EntriesRead,
  708. CONNTYPE_ANY,
  709. NULL
  710. );
  711. if (status == NO_ERROR) {
  712. DWORD i;
  713. LPNETRESOURCEW SavePtr = NetR;
  714. LPWSTR Local;
  715. for (i = 0; i < EntriesRead; i++, NetR++) {
  716. Local = NetR->lpLocalName;
  717. if (NetR->lpLocalName && *(NetR->lpLocalName) == 0) {
  718. Local = NULL;
  719. }
  720. (void) NwOpenHandleToDeleteConn(
  721. NetR->lpRemoteName,
  722. Local,
  723. TRUE,
  724. TRUE,
  725. FALSE
  726. );
  727. }
  728. NetR = SavePtr;
  729. }
  730. else if (status == WN_MORE_DATA) {
  731. //
  732. // Original buffer was too small. Free it and allocate
  733. // the recommended size and then some to get as many
  734. // entries as possible.
  735. //
  736. (void) LocalFree((HLOCAL) NetR);
  737. BytesNeeded += NW_ENUM_EXTRA_BYTES;
  738. if ((NetR = (LPVOID) LocalAlloc(
  739. 0,
  740. BytesNeeded
  741. )) == NULL) {
  742. status = ERROR_NOT_ENOUGH_MEMORY;
  743. goto CleanExit;
  744. }
  745. }
  746. else {
  747. // give up if see any other return code
  748. break ;
  749. }
  750. } while (status != WN_NO_MORE_ENTRIES);
  751. CleanExit:
  752. (void) NwrCloseEnum(&EnumHandle);
  753. if (NetR != NULL) {
  754. (void) LocalFree((HLOCAL) NetR);
  755. }
  756. (void) NwDeleteAllInRegistry();
  757. }
  758. DWORD
  759. NwCreateSymbolicLink(
  760. IN LPWSTR Local,
  761. IN LPWSTR TreeConnectStr,
  762. IN BOOL ImpersonatingClient
  763. )
  764. /*++
  765. Routine Description:
  766. This function creates a symbolic link object for the specified local
  767. device name which is linked to the tree connection name that has a
  768. format of \Device\NwRdr\Device:\Server\Volume\Directory.
  769. Arguments:
  770. Local - Supplies the local device name.
  771. TreeConnectStr - Supplies the tree connection name string which is
  772. the link target of the symbolick link object.
  773. ImpersonatingClient - Flag that indicates whether the thread has
  774. called NwImpersonateClient. The gateway service functions don't
  775. impersonate, where as the client service operations do.
  776. Return Value:
  777. NO_ERROR or reason for failure.
  778. --*/
  779. {
  780. WCHAR TempBuf[64];
  781. LPWSTR Session = NULL; //Terminal Server Addition
  782. NTSTATUS Status = NO_ERROR;
  783. BOOL ResetToClient = FALSE;
  784. DWORD LocalLength = wcslen(Local);
  785. Session = NwReturnSessionPath(Local);
  786. if (Session == 0)
  787. {
  788. Status = GetLastError();
  789. goto Exit;
  790. }
  791. if ( (NwLUIDDeviceMapsEnabled == FALSE) && ImpersonatingClient )
  792. {
  793. (void) NwRevertToSelf();
  794. ResetToClient = TRUE;
  795. }
  796. if (LocalLength > 2)
  797. {
  798. LPWSTR UncName;
  799. //
  800. // Local device is LPTn:
  801. //
  802. //
  803. // Check to see if we already have this UNC name mapped.
  804. //
  805. if (NwAllocAndGetUncName(
  806. Local,
  807. LocalLength,
  808. &UncName
  809. ) == NO_ERROR)
  810. {
  811. LocalFree((HLOCAL) UncName);
  812. Status = ERROR_ALREADY_ASSIGNED;
  813. goto Exit;
  814. }
  815. }
  816. else
  817. {
  818. //
  819. // Local device is X:
  820. //
  821. if (! QueryDosDeviceW( Session,
  822. TempBuf,
  823. sizeof(TempBuf) / sizeof(WCHAR) ))
  824. {
  825. if (GetLastError() != ERROR_FILE_NOT_FOUND)
  826. {
  827. //
  828. // Most likely failure occurred because our output
  829. // buffer is too small. It still means someone already
  830. // has an existing symbolic link for this device.
  831. //
  832. Status = ERROR_ALREADY_ASSIGNED;
  833. goto Exit;
  834. }
  835. }
  836. else
  837. {
  838. //
  839. // QueryDosDevice successfully an existing symbolic link--
  840. // somebody is already using this device.
  841. //
  842. Status = ERROR_ALREADY_ASSIGNED;
  843. goto Exit;
  844. }
  845. }
  846. //
  847. // Create a symbolic link object to the device we are redirecting
  848. //
  849. if (! DefineDosDeviceW(
  850. DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM,
  851. Session,
  852. TreeConnectStr
  853. ))
  854. {
  855. Status = GetLastError();
  856. goto Exit;
  857. }
  858. Exit:
  859. if ( ResetToClient )
  860. {
  861. (void) NwImpersonateClient();
  862. }
  863. if (Session)
  864. {
  865. LocalFree(Session);
  866. }
  867. return Status;
  868. }
  869. VOID
  870. NwDeleteSymbolicLink(
  871. IN LPWSTR LocalDeviceName,
  872. IN LPWSTR TreeConnectStr,
  873. IN LPWSTR SessionDeviceName, //Terminal Server Addition
  874. // This parameter is required because
  875. // the device created is per session
  876. IN BOOL ImpersonatingClient
  877. )
  878. /*++
  879. Routine Description:
  880. This function deletes the symbolic link we had created earlier for
  881. the device.
  882. Arguments:
  883. LocalDeviceName - Supplies the local device name string of which the
  884. symbolic link object is created.
  885. TreeConnectStr - Supplies a pointer to the Unicode string which
  886. contains the link target string we want to match and delete.
  887. ImpersonatingClient - Flag that indicates whether the thread has
  888. called NwImpersonateClient. The gateway service functions don't
  889. impersonate, where as the client service operations do.
  890. Return Value:
  891. None.
  892. --*/
  893. {
  894. BOOLEAN DeleteSession = FALSE;
  895. BOOL ResetToClient = FALSE;
  896. if (LocalDeviceName != NULL ||
  897. SessionDeviceName != NULL) {
  898. if (SessionDeviceName == NULL) {
  899. SessionDeviceName = NwReturnSessionPath(LocalDeviceName);
  900. if ( SessionDeviceName == NULL ) return;
  901. DeleteSession = TRUE;
  902. }
  903. if ( (NwLUIDDeviceMapsEnabled == FALSE) && ImpersonatingClient )
  904. {
  905. (void) NwRevertToSelf();
  906. ResetToClient = TRUE;
  907. }
  908. if (! DefineDosDeviceW(
  909. DDD_REMOVE_DEFINITION |
  910. DDD_RAW_TARGET_PATH |
  911. DDD_EXACT_MATCH_ON_REMOVE |
  912. DDD_NO_BROADCAST_SYSTEM,
  913. // LocalDeviceName,
  914. SessionDeviceName,
  915. TreeConnectStr
  916. ))
  917. {
  918. #if DBG
  919. IF_DEBUG(CONNECT) {
  920. KdPrint(("NWWORKSTATION: DefineDosDevice DEL of %ws %ws returned %lu\n",
  921. LocalDeviceName, TreeConnectStr, GetLastError()));
  922. }
  923. #endif
  924. }
  925. #if DBG
  926. else {
  927. IF_DEBUG(CONNECT) {
  928. KdPrint(("NWWORKSTATION: DefineDosDevice DEL of %ws %ws returned successful\n",
  929. LocalDeviceName, TreeConnectStr));
  930. }
  931. }
  932. #endif
  933. }
  934. if ( SessionDeviceName && DeleteSession) {
  935. LocalFree( SessionDeviceName );
  936. }
  937. if ( ResetToClient )
  938. {
  939. (void) NwImpersonateClient();
  940. }
  941. }
  942. DWORD
  943. NwCreateConnection(
  944. IN LPWSTR LocalName OPTIONAL,
  945. IN LPWSTR RemoteName,
  946. IN DWORD Type,
  947. IN LPWSTR Password OPTIONAL,
  948. IN LPWSTR UserName OPTIONAL
  949. )
  950. /*++
  951. Routine Description:
  952. This function creates a tree connection to the specified RemoteName
  953. (UNC name) and maps it to the LocalName (local device name), if
  954. it is specified. The password and user name are the credentials
  955. used to create the connection, if specified; otherwise, the
  956. interactive logged on user's credentials are used by default.
  957. NOTE: This code used to be NwrCreateConnection, except that it used
  958. to have the ImpersonateClient() call in it. Now this code is here, and
  959. NwrCreateConnection calls this function and handles the client
  960. impersonation there. The reason for this is to allow the print spooler
  961. code to call this helper routine without calling Impersonate client a
  962. second time, thus reverting the credentials to that of services.exe.
  963. 4/15/99 - GlennC - Assumption is that this routine is currently only
  964. called while impersonating the client (NwImpersonateClient == TRUE)!!!
  965. Arguments:
  966. LocalName - Supplies the local device name to map to the created tree
  967. connection. Only drive letter device names are accepted. (No
  968. LPT or COM).
  969. RemoteName - Supplies the UNC name of the remote resource in the format
  970. of Server\Volume\Directory. It must be a disk resource.
  971. Type - Supplies the connection type.
  972. Password - Supplies the password to use to make the connection to the
  973. server.
  974. UserName - Supplies the user name to use to make the connection.
  975. Return Value:
  976. NO_ERROR - Operation was successful.
  977. ERROR_NOT_ENOUGH_MEMORY - Out of memory allocating internal work buffers.
  978. WN_BAD_NETNAME - Remote resource name is invalid.
  979. WN_BAD_LOCALNAME - Local DOS device name is invalid.
  980. ERROR_BAD_NETPATH - The UNC name does not exist on the network.
  981. ERROR_INVALID_PARAMETER - LPT or COM LocalName was specified.
  982. Other errors from the redirector.
  983. --*/
  984. {
  985. DWORD status;
  986. DWORD LocalLength;
  987. LPWSTR Local = NULL;
  988. LPWSTR Unc = NULL;
  989. LPWSTR User = NULL;
  990. UNICODE_STRING TreeConnectStr;
  991. UNICODE_STRING EncodedPassword;
  992. HANDLE TreeConnection;
  993. TreeConnectStr.Buffer = NULL;
  994. EncodedPassword.Length = 0;
  995. //
  996. // If local device is an empty string, it will be treated as a pointer to
  997. // NULL.
  998. //
  999. if (LocalName != NULL && *LocalName != 0) {
  1000. //
  1001. // Local device name is not NULL, canonicalize it
  1002. //
  1003. #if DBG
  1004. IF_DEBUG(CONNECT) {
  1005. KdPrint(("\nNWWORKSTATION: NwCreateConnection: LocalName %ws\n", LocalName));
  1006. }
  1007. #endif
  1008. if ((status = NwLibCanonLocalName(
  1009. LocalName,
  1010. &Local, // Must be freed with LocalFree when done.
  1011. &LocalLength
  1012. )) != NO_ERROR) {
  1013. return WN_BAD_LOCALNAME;
  1014. }
  1015. }
  1016. #if DBG
  1017. IF_DEBUG(CONNECT) {
  1018. KdPrint(("NWWORKSTATION: NwCreateConnection: RemoteName %ws\n", RemoteName));
  1019. }
  1020. #endif
  1021. //
  1022. // Canonicalize the remote name, if it is not \\Server.
  1023. //
  1024. status = NwLibCanonRemoteName(
  1025. Local,
  1026. RemoteName,
  1027. &Unc, // Must be freed with LocalFree when done.
  1028. NULL
  1029. );
  1030. if (status != NO_ERROR)
  1031. {
  1032. status = WN_BAD_NETNAME;
  1033. goto CleanExit;
  1034. }
  1035. //
  1036. // Canonicalize user name.
  1037. //
  1038. if (UserName != NULL) {
  1039. //
  1040. // Canonicalize username
  1041. //
  1042. #if DBG
  1043. IF_DEBUG(CONNECT) {
  1044. KdPrint(("NWWORKSTATION: NwCreateConnection: UserName %ws\n",
  1045. UserName));
  1046. }
  1047. #endif
  1048. if ((status = NwLibCanonUserName(
  1049. UserName,
  1050. &User, // Must be freed with LocalFree when done.
  1051. NULL
  1052. )) != NO_ERROR) {
  1053. #ifdef QFE_BUILD
  1054. //
  1055. // if not valid, just ignore the username. this works
  1056. // around MPR bug where if you pass say domain\user to NWRDR
  1057. // as first provider, and he throws it out, then the next one
  1058. // doesnt get a chance.
  1059. //
  1060. // TRACKING - this should be removed when MPR bug #4051 is fixed
  1061. // and all platforms we ship NWRDR have that fix.
  1062. //
  1063. UserName = NULL ;
  1064. status = NO_ERROR;
  1065. #else
  1066. status = WN_BAD_VALUE;
  1067. goto CleanExit;
  1068. #endif
  1069. }
  1070. }
  1071. //
  1072. // For password any syntax or length is accepted.
  1073. //
  1074. if (Password != NULL) {
  1075. #if DBG
  1076. IF_DEBUG(CONNECT) {
  1077. KdPrint(("NWWORKSTATION: NwCreateConnection: Password %ws\n",
  1078. Password));
  1079. }
  1080. #endif
  1081. //
  1082. // Decode the password
  1083. //
  1084. RtlInitUnicodeString(&EncodedPassword, Password);
  1085. RtlRunDecodeUnicodeString(NW_ENCODE_SEED3, &EncodedPassword);
  1086. }
  1087. //
  1088. // Create an NT-style tree connection name
  1089. //
  1090. if ((status = NwCreateTreeConnectName(
  1091. Unc,
  1092. Local,
  1093. &TreeConnectStr
  1094. )) != NO_ERROR) {
  1095. goto CleanExit;
  1096. }
  1097. if (Local != NULL) {
  1098. //
  1099. // Create symbolic link for local device name.
  1100. //
  1101. if ((status = NwCreateSymbolicLink(
  1102. Local,
  1103. TreeConnectStr.Buffer,
  1104. TRUE // We are impersonating the client!
  1105. )) != NO_ERROR)
  1106. {
  1107. goto CleanExit;
  1108. }
  1109. }
  1110. //
  1111. // Create the tree connection while impersonating the client so
  1112. // that redirector can get to caller's logon id.
  1113. //
  1114. status = NwOpenCreateConnection(
  1115. &TreeConnectStr,
  1116. User,
  1117. Password,
  1118. Unc,
  1119. SYNCHRONIZE | GENERIC_WRITE,
  1120. FILE_CREATE, // Fail if already exist
  1121. FILE_CREATE_TREE_CONNECTION |
  1122. FILE_SYNCHRONOUS_IO_NONALERT,
  1123. Type,
  1124. &TreeConnection,
  1125. NULL
  1126. );
  1127. //
  1128. // If there's a problem creating the tree connection, remove symbolic
  1129. // link if any.
  1130. //
  1131. if (status != NO_ERROR) {
  1132. if ( (status == ERROR_NOT_CONNECTED) ||
  1133. (status == ERROR_FILE_NOT_FOUND) ||
  1134. (status == ERROR_INVALID_NAME) )
  1135. {
  1136. status = ERROR_BAD_NETPATH;
  1137. }
  1138. if ( status == ERROR_CONNECTION_INVALID )
  1139. {
  1140. status = WN_BAD_NETNAME;
  1141. }
  1142. //
  1143. // Delete the symbolic link we created.
  1144. //
  1145. NwDeleteSymbolicLink(
  1146. Local,
  1147. TreeConnectStr.Buffer,
  1148. NULL,
  1149. TRUE // We are impersonating the client!
  1150. );
  1151. }
  1152. else {
  1153. //
  1154. // Just close the connection handle.
  1155. //
  1156. (void) NtClose(TreeConnection);
  1157. }
  1158. CleanExit:
  1159. if (Local != NULL) {
  1160. (void) LocalFree((HLOCAL) Local);
  1161. }
  1162. if (Unc != NULL) {
  1163. (void) LocalFree((HLOCAL) Unc);
  1164. }
  1165. if (User != NULL) {
  1166. (void) LocalFree((HLOCAL) User);
  1167. }
  1168. if (TreeConnectStr.Buffer != NULL) {
  1169. (void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
  1170. }
  1171. //
  1172. // Put the password back the way we found it.
  1173. //
  1174. if (EncodedPassword.Length != 0) {
  1175. UCHAR Seed = NW_ENCODE_SEED3;
  1176. RtlRunEncodeUnicodeString(&Seed, &EncodedPassword);
  1177. }
  1178. #if DBG
  1179. IF_DEBUG(CONNECT) {
  1180. KdPrint(("NWWORKSTATION: NwCreateConnection returns %lu\n", status));
  1181. }
  1182. #endif
  1183. return status;
  1184. }
  1185. //Terminal Server
  1186. DWORD
  1187. NwDeleteAllInRegistry(
  1188. VOID
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. This function spins through the registry deleting the symbolic
  1193. links and closing all connections for all logons.
  1194. This is neccessary since the the users are not neccessarily in the
  1195. system context.
  1196. Arguments:
  1197. none
  1198. Return Value:
  1199. NO_ERROR or reason for failure.
  1200. --*/
  1201. {
  1202. LONG RegError;
  1203. HKEY InteractiveLogonKey;
  1204. DWORD Index = 0;
  1205. WCHAR LogonIdName[NW_MAX_LOGON_ID_LEN];
  1206. LUID LogonId;
  1207. HKEY OneLogonKey;
  1208. ULONG WinStationId = 0L;
  1209. PULONG pWinId = NULL;
  1210. RegError = RegOpenKeyExW(
  1211. HKEY_LOCAL_MACHINE,
  1212. NW_INTERACTIVE_LOGON_REGKEY,
  1213. REG_OPTION_NON_VOLATILE,
  1214. KEY_READ,
  1215. &InteractiveLogonKey
  1216. );
  1217. if (RegError == ERROR_SUCCESS) {
  1218. do {
  1219. RegError = RegEnumKeyW(
  1220. InteractiveLogonKey,
  1221. Index,
  1222. LogonIdName,
  1223. sizeof(LogonIdName) / sizeof(WCHAR)
  1224. );
  1225. if (RegError == ERROR_SUCCESS) {
  1226. //
  1227. // Got a logon id key.
  1228. //
  1229. NwWStrToLuid(LogonIdName, &LogonId);
  1230. //
  1231. // Open the <LogonIdName> key under Logon
  1232. //
  1233. RegError = RegOpenKeyExW(
  1234. InteractiveLogonKey,
  1235. LogonIdName,
  1236. REG_OPTION_NON_VOLATILE,
  1237. KEY_READ,
  1238. &OneLogonKey
  1239. );
  1240. if ( RegError != ERROR_SUCCESS ) {
  1241. KdPrint(("NWWORKSTATION: NwDeleteAllInRegistry: RegOpenKeyExW failed, Not interactive Logon: Error %d\n", GetLastError()));
  1242. } else {
  1243. //
  1244. // Read the WinStation value.
  1245. //
  1246. RegError = NwReadRegValue(
  1247. OneLogonKey,
  1248. NW_WINSTATION_VALUENAME,
  1249. (LPWSTR *) &pWinId
  1250. );
  1251. (void) RegCloseKey(OneLogonKey);
  1252. if ( RegError != NO_ERROR ) {
  1253. KdPrint(("NWWORKSTATION: NwDeleteAllInRegistry: Could not read SID from reg %lu\n", RegError));
  1254. continue;
  1255. } else {
  1256. if (pWinId != NULL) {
  1257. WinStationId = *pWinId;
  1258. (void) LocalFree((HLOCAL) pWinId);
  1259. }
  1260. NwDeleteUidSymLinks( LogonId, WinStationId );
  1261. }
  1262. }
  1263. } else if (RegError != ERROR_NO_MORE_ITEMS) {
  1264. KdPrint(("NWWORKSTATION: NwDeleteAllInRegistry failed to enum logon IDs RegError=%lu\n",
  1265. RegError));
  1266. }
  1267. Index++;
  1268. } while (RegError == ERROR_SUCCESS);
  1269. (void) RegCloseKey(InteractiveLogonKey);
  1270. }
  1271. NwCloseAllConnections();
  1272. return NO_ERROR;
  1273. }
  1274. DWORD
  1275. NwDeleteUidSymLinks(
  1276. IN LUID Uid,
  1277. IN ULONG WinStationId
  1278. )
  1279. /*++
  1280. Routine Description:
  1281. This function deletes all symbolic links for a given UID/Winstation.
  1282. Arguments:
  1283. None.
  1284. Return Value:
  1285. NO_ERROR
  1286. --*/
  1287. {
  1288. DWORD status= NO_ERROR;
  1289. NWWKSTA_CONTEXT_HANDLE EnumHandle;
  1290. LPNETRESOURCEW NetR = NULL;
  1291. DWORD BytesNeeded = 256;
  1292. DWORD EntriesRead;
  1293. WCHAR LocalUidCombo[256];
  1294. UNICODE_STRING TreeConnectStr;
  1295. status = NwrOpenEnumConnections(NULL, RESOURCETYPE_ANY, &EnumHandle);
  1296. if ( status != NO_ERROR )
  1297. return status;
  1298. //
  1299. // Allocate buffer to get connection list.
  1300. //
  1301. if ((NetR = (LPVOID) LocalAlloc(
  1302. 0,
  1303. BytesNeeded
  1304. )) == NULL) {
  1305. status = ERROR_NOT_ENOUGH_MEMORY;
  1306. goto CleanExit;
  1307. }
  1308. do {
  1309. status = NwEnumerateConnections(
  1310. &((LPNW_ENUM_CONTEXT) EnumHandle)->ResumeId,
  1311. 0xFFFFFFFF,
  1312. (LPBYTE) NetR,
  1313. BytesNeeded,
  1314. &BytesNeeded,
  1315. &EntriesRead,
  1316. CONNTYPE_ANY | CONNTYPE_UID,
  1317. &Uid
  1318. );
  1319. if (status == NO_ERROR) {
  1320. DWORD i;
  1321. LPNETRESOURCEW SavePtr = NetR;
  1322. LPWSTR Local;
  1323. for (i = 0; i < EntriesRead; i++, NetR++) {
  1324. Local = NetR->lpLocalName;
  1325. TreeConnectStr.Buffer = NULL;
  1326. if (NetR->lpLocalName && *(NetR->lpLocalName) == 0) {
  1327. Local = NULL;
  1328. } else if ((status = NwCreateTreeConnectName(
  1329. NetR->lpRemoteName,
  1330. Local,
  1331. &TreeConnectStr
  1332. )) != NO_ERROR) {
  1333. Local = NULL;
  1334. }
  1335. if ( Local != NULL ) {
  1336. swprintf(LocalUidCombo, L"%ws:%x", Local, WinStationId);
  1337. //
  1338. // Delete the symbolic link we created.
  1339. //
  1340. if (! DefineDosDeviceW(
  1341. DDD_REMOVE_DEFINITION |
  1342. DDD_RAW_TARGET_PATH |
  1343. DDD_EXACT_MATCH_ON_REMOVE |
  1344. 0x80000000,
  1345. LocalUidCombo,
  1346. TreeConnectStr.Buffer
  1347. )) {
  1348. #if DBG
  1349. IF_DEBUG(CONNECT) {
  1350. KdPrint(("NWWORKSTATION: DefineDosDevice DEL of %ws %ws returned %lu\n",
  1351. LocalUidCombo, TreeConnectStr.Buffer, GetLastError()));
  1352. }
  1353. #endif
  1354. }
  1355. #if DBG
  1356. else {
  1357. IF_DEBUG(CONNECT) {
  1358. KdPrint(("NWWORKSTATION: DefineDosDevice DEL of %ws %ws returned successful\n",
  1359. LocalUidCombo, TreeConnectStr.Buffer));
  1360. }
  1361. }
  1362. #endif
  1363. if (TreeConnectStr.Buffer != NULL) {
  1364. (void) LocalFree((HLOCAL) TreeConnectStr.Buffer);
  1365. TreeConnectStr.Buffer = NULL;
  1366. }
  1367. }
  1368. }
  1369. NetR = SavePtr;
  1370. } else if (status == WN_MORE_DATA) {
  1371. //
  1372. // Original buffer was too small. Free it and allocate
  1373. // the recommended size and then some to get as many
  1374. // entries as possible.
  1375. //
  1376. (void) LocalFree((HLOCAL) NetR);
  1377. BytesNeeded += NW_ENUM_EXTRA_BYTES;
  1378. if ((NetR = (LPVOID) LocalAlloc(
  1379. 0,
  1380. BytesNeeded
  1381. )) == NULL) {
  1382. status = ERROR_NOT_ENOUGH_MEMORY;
  1383. goto CleanExit;
  1384. }
  1385. } else {
  1386. // give up if see any other return code
  1387. break ;
  1388. }
  1389. } while (status != WN_NO_MORE_ENTRIES);
  1390. CleanExit:
  1391. (void) NwrCloseEnum(&EnumHandle);
  1392. if (NetR != NULL) {
  1393. (void) LocalFree((HLOCAL) NetR);
  1394. }
  1395. return NO_ERROR;
  1396. }
  1397. //
  1398. // Terminal Server Addition
  1399. //
  1400. LPTSTR
  1401. NwReturnSessionPath(
  1402. IN LPTSTR LocalDeviceName
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. This function returns the per session path to access the
  1407. specific dos device for multiple session support.
  1408. Arguments:
  1409. LocalDeviceName - Supplies the local device name specified by the API
  1410. caller.
  1411. Return Value:
  1412. LPTSTR - Pointer to per session path in newly allocated memory
  1413. by LocalAlloc().
  1414. --*/
  1415. {
  1416. BOOL rc;
  1417. DWORD SessionId;
  1418. CLIENT_ID ClientId;
  1419. LPTSTR SessionDeviceName = NULL;
  1420. NTSTATUS status;
  1421. if ((status = NwGetSessionId(&SessionId)) != NO_ERROR) {
  1422. return NULL;
  1423. }
  1424. rc = DosPathToSessionPath(
  1425. SessionId,
  1426. LocalDeviceName,
  1427. &SessionDeviceName
  1428. );
  1429. if ( !rc ) {
  1430. return NULL;
  1431. }
  1432. return SessionDeviceName;
  1433. }