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

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