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.

3210 lines
87 KiB

  1. /*++
  2. Copyright (c) 1991-1993 Microsoft Corporation
  3. Module Name:
  4. device.c
  5. Abstract:
  6. This module contains the support routines for the APIs that call
  7. into the NetWare redirector
  8. Author:
  9. Rita Wong (ritaw) 20-Feb-1991
  10. Colin Watson (colinw) 30-Dec-1992
  11. Revision History:
  12. --*/
  13. #include <nw.h>
  14. #include <nwcons.h>
  15. #include <nwxchg.h>
  16. #include <nwapi32.h>
  17. #include <nwstatus.h>
  18. #include <nwmisc.h>
  19. #include <nwcons.h>
  20. #include <nds.h>
  21. #include <svcguid.h>
  22. #include <tdi.h>
  23. #include <nwreg.h>
  24. #define NW_LINKAGE_REGISTRY_PATH L"NWCWorkstation\\Linkage"
  25. #define NW_BIND_VALUENAME L"Bind"
  26. #define TWO_KB 2048
  27. #define EIGHT_KB 8192
  28. #define EXTRA_BYTES 256
  29. #define TREECHAR L'*'
  30. #define BUFFSIZE 1024
  31. //-------------------------------------------------------------------//
  32. // //
  33. // Local Function Prototypes //
  34. // //
  35. //-------------------------------------------------------------------//
  36. STATIC
  37. NTSTATUS
  38. BindToEachTransport(
  39. IN PWSTR ValueName,
  40. IN ULONG ValueType,
  41. IN PVOID ValueData,
  42. IN ULONG ValueLength,
  43. IN PVOID Context,
  44. IN PVOID EntryContext
  45. );
  46. DWORD
  47. NwBindTransport(
  48. IN LPWSTR TransportName,
  49. IN DWORD QualityOfService
  50. );
  51. DWORD
  52. GetConnectedBinderyServers(
  53. OUT LPNW_ENUM_CONTEXT ContextHandle
  54. );
  55. DWORD
  56. GetTreeEntriesFromBindery(
  57. OUT LPNW_ENUM_CONTEXT ContextHandle
  58. );
  59. DWORD
  60. NwGetConnectionStatus(
  61. IN LPWSTR pszServerName,
  62. IN OUT PDWORD_PTR ResumeKey,
  63. OUT LPBYTE *Buffer,
  64. OUT PDWORD EntriesRead
  65. );
  66. VOID
  67. GetLuid(
  68. IN OUT PLUID plogonid
  69. );
  70. VOID
  71. GetNearestDirServer(
  72. IN LPWSTR TreeName,
  73. OUT LPDWORD lpdwReplicaAddressSize,
  74. OUT LPBYTE lpReplicaAddress
  75. );
  76. VOID
  77. GetPreferredServerAddress(
  78. IN LPWSTR PreferredServerName,
  79. OUT LPDWORD lpdwReplicaAddressSize,
  80. OUT LPBYTE lpReplicaAddress
  81. );
  82. BOOL
  83. NwpCompareTreeNames(
  84. LPWSTR lpServiceInstanceName,
  85. LPWSTR lpTreeName
  86. );
  87. //-------------------------------------------------------------------//
  88. // //
  89. // Global variables //
  90. // //
  91. //-------------------------------------------------------------------//
  92. //
  93. // Handle to the Redirector FSD
  94. //
  95. STATIC HANDLE RedirDeviceHandle = NULL;
  96. //
  97. // Redirector name in NT string format
  98. //
  99. STATIC UNICODE_STRING RedirDeviceName;
  100. extern BOOL NwLUIDDeviceMapsEnabled;
  101. DWORD
  102. NwInitializeRedirector(
  103. VOID
  104. )
  105. /*++
  106. Routine Description:
  107. This routine initializes the NetWare redirector FSD.
  108. Arguments:
  109. None.
  110. Return Value:
  111. NO_ERROR or reason for failure.
  112. --*/
  113. {
  114. DWORD error;
  115. NWR_REQUEST_PACKET Rrp;
  116. //
  117. // Initialize global handles
  118. //
  119. RedirDeviceHandle = NULL;
  120. //
  121. // Initialize the global NT-style redirector device name string.
  122. //
  123. RtlInitUnicodeString(&RedirDeviceName, DD_NWFS_DEVICE_NAME_U);
  124. //
  125. // Load driver
  126. //
  127. /* error = NwLoadOrUnloadDriver(TRUE);
  128. // JimTh - 3/5/02 - Driver loading turned over to SCM via service dependency on NwRdr
  129. if (error != NO_ERROR && error != ERROR_SERVICE_ALREADY_RUNNING) {
  130. return error;
  131. }
  132. */
  133. if ((error = NwOpenRedirector()) != NO_ERROR) {
  134. //
  135. // Unload the redirector driver
  136. //
  137. // (void) NwLoadOrUnloadDriver(FALSE);
  138. // JimTh - 3/5/02 - Driver loading turned over to SCM
  139. return error;
  140. }
  141. //
  142. // Send the start FSCTL to the redirector
  143. //
  144. Rrp.Version = REQUEST_PACKET_VERSION;
  145. return NwRedirFsControl(
  146. RedirDeviceHandle,
  147. FSCTL_NWR_START,
  148. &Rrp,
  149. sizeof(NWR_REQUEST_PACKET),
  150. NULL,
  151. 0,
  152. NULL
  153. );
  154. }
  155. DWORD
  156. NwOpenRedirector(
  157. VOID
  158. )
  159. /*++
  160. Routine Description:
  161. This routine opens the NT NetWare redirector FSD.
  162. Arguments:
  163. None.
  164. Return Value:
  165. NO_ERROR or reason for failure.
  166. --*/
  167. {
  168. return RtlNtStatusToDosError(
  169. NwOpenHandle(&RedirDeviceName, FALSE, &RedirDeviceHandle)
  170. );
  171. }
  172. DWORD
  173. NwShutdownRedirector(
  174. VOID
  175. )
  176. /*++
  177. Routine Description:
  178. This routine stops the NetWare Redirector FSD and unloads it if
  179. possible.
  180. Arguments:
  181. None.
  182. Return Value:
  183. NO_ERROR or ERROR_REDIRECTOR_HAS_OPEN_HANDLES
  184. --*/
  185. {
  186. NWR_REQUEST_PACKET Rrp;
  187. DWORD error;
  188. Rrp.Version = REQUEST_PACKET_VERSION;
  189. error = NwRedirFsControl(
  190. RedirDeviceHandle,
  191. FSCTL_NWR_STOP,
  192. &Rrp,
  193. sizeof(NWR_REQUEST_PACKET),
  194. NULL,
  195. 0,
  196. NULL
  197. );
  198. (void) NtClose(RedirDeviceHandle);
  199. RedirDeviceHandle = NULL;
  200. if (error != ERROR_REDIRECTOR_HAS_OPEN_HANDLES) {
  201. //
  202. // Unload the redirector only if all its open handles are closed.
  203. //
  204. // (void) NwLoadOrUnloadDriver(FALSE);
  205. // JimTh - 3/5/02 - Driver loading turned over to SCM
  206. }
  207. return error;
  208. }
  209. /*
  210. // JimTh - 3/5/02 - Driver loading turned over to SCM via service dependency on NwRdr
  211. DWORD
  212. NwLoadOrUnloadDriver(
  213. BOOL Load
  214. )
  215. /*++
  216. Routine Description:
  217. This routine loads or unloads the NetWare redirector driver.
  218. Arguments:
  219. Load - Supplies the flag which if TRUE load the driver; otherwise
  220. unloads the driver.
  221. Return Value:
  222. NO_ERROR or reason for failure.
  223. --* /
  224. {
  225. LPWSTR DriverRegistryName;
  226. UNICODE_STRING DriverRegistryString;
  227. NTSTATUS ntstatus;
  228. BOOLEAN WasEnabled;
  229. DriverRegistryName = (LPWSTR) LocalAlloc(
  230. LMEM_FIXED,
  231. (UINT) (sizeof(SERVICE_REGISTRY_KEY) +
  232. (wcslen(NW_DRIVER_NAME) *
  233. sizeof(WCHAR)))
  234. );
  235. if (DriverRegistryName == NULL) {
  236. return ERROR_NOT_ENOUGH_MEMORY;
  237. }
  238. ntstatus = RtlAdjustPrivilege(
  239. SE_LOAD_DRIVER_PRIVILEGE,
  240. TRUE,
  241. FALSE,
  242. &WasEnabled
  243. );
  244. if (! NT_SUCCESS(ntstatus)) {
  245. (void) LocalFree(DriverRegistryName);
  246. return RtlNtStatusToDosError(ntstatus);
  247. }
  248. wcscpy(DriverRegistryName, SERVICE_REGISTRY_KEY);
  249. wcscat(DriverRegistryName, NW_DRIVER_NAME);
  250. RtlInitUnicodeString(&DriverRegistryString, DriverRegistryName);
  251. if (Load) {
  252. ntstatus = NtLoadDriver(&DriverRegistryString);
  253. }
  254. else {
  255. ntstatus = NtUnloadDriver(&DriverRegistryString);
  256. }
  257. (void) RtlAdjustPrivilege(
  258. SE_LOAD_DRIVER_PRIVILEGE,
  259. WasEnabled,
  260. FALSE,
  261. &WasEnabled
  262. );
  263. (void) LocalFree(DriverRegistryName);
  264. if (Load) {
  265. if (ntstatus != STATUS_SUCCESS && ntstatus != STATUS_IMAGE_ALREADY_LOADED) {
  266. LPWSTR SubString[1];
  267. KdPrint(("NWWORKSTATION: NtLoadDriver returned %08lx\n", ntstatus));
  268. SubString[0] = NW_DRIVER_NAME;
  269. NwLogEvent(
  270. EVENT_NWWKSTA_CANT_CREATE_REDIRECTOR,
  271. 1,
  272. SubString,
  273. ntstatus
  274. );
  275. }
  276. }
  277. if (ntstatus == STATUS_OBJECT_NAME_NOT_FOUND) {
  278. return ERROR_FILE_NOT_FOUND;
  279. }
  280. return NwMapStatus(ntstatus);
  281. }
  282. */
  283. DWORD
  284. NwRedirFsControl(
  285. IN HANDLE FileHandle,
  286. IN ULONG RedirControlCode,
  287. IN PNWR_REQUEST_PACKET Rrp,
  288. IN ULONG RrpLength,
  289. IN PVOID SecondBuffer OPTIONAL,
  290. IN ULONG SecondBufferLength,
  291. OUT PULONG Information OPTIONAL
  292. )
  293. /*++
  294. Routine Description:
  295. Arguments:
  296. FileHandle - Supplies a handle to the file or device on which the service
  297. is being performed.
  298. RedirControlCode - Supplies the NtFsControlFile function code given to
  299. the redirector.
  300. Rrp - Supplies the redirector request packet.
  301. RrpLength - Supplies the length of the redirector request packet.
  302. SecondBuffer - Supplies the second buffer in call to NtFsControlFile.
  303. SecondBufferLength - Supplies the length of the second buffer.
  304. Information - Returns the information field of the I/O status block.
  305. Return Value:
  306. NO_ERROR or reason for failure.
  307. --*/
  308. {
  309. NTSTATUS ntstatus;
  310. IO_STATUS_BLOCK IoStatusBlock;
  311. if (FileHandle == NULL)
  312. return ERROR_INVALID_PARAMETER;
  313. //
  314. // Send the request to the Redirector FSD.
  315. //
  316. ntstatus = NtFsControlFile(
  317. FileHandle,
  318. NULL,
  319. NULL,
  320. NULL,
  321. &IoStatusBlock,
  322. RedirControlCode,
  323. (PVOID) Rrp,
  324. RrpLength,
  325. SecondBuffer,
  326. SecondBufferLength
  327. );
  328. if (ntstatus == STATUS_SUCCESS) {
  329. ntstatus = IoStatusBlock.Status;
  330. }
  331. if (ARGUMENT_PRESENT(Information)) {
  332. *Information = (ULONG) IoStatusBlock.Information;
  333. }
  334. #if DBG
  335. if (ntstatus != STATUS_SUCCESS) {
  336. IF_DEBUG(DEVICE) {
  337. KdPrint(("NWWORKSTATION: fsctl to redir returns %08lx\n", ntstatus));
  338. }
  339. }
  340. #endif
  341. return NwMapStatus(ntstatus);
  342. }
  343. DWORD
  344. NwBindToTransports(
  345. VOID
  346. )
  347. /*++
  348. Routine Description:
  349. This routine binds to every transport specified under the linkage
  350. key of the NetWare Workstation service.
  351. Arguments:
  352. None.
  353. Return Value:
  354. NET_API_STATUS - success/failure of the operation.
  355. --*/
  356. {
  357. NTSTATUS ntstatus;
  358. PRTL_QUERY_REGISTRY_TABLE QueryTable;
  359. ULONG NumberOfBindings = 0;
  360. //
  361. // Ask the RTL to call us back for each subvalue in the MULTI_SZ
  362. // value \NWCWorkstation\Linkage\Bind.
  363. //
  364. if ((QueryTable = (PVOID) LocalAlloc(
  365. LMEM_ZEROINIT,
  366. sizeof(RTL_QUERY_REGISTRY_TABLE) * 2
  367. )) == NULL) {
  368. return ERROR_NOT_ENOUGH_MEMORY;
  369. }
  370. QueryTable[0].QueryRoutine = (PRTL_QUERY_REGISTRY_ROUTINE) BindToEachTransport;
  371. QueryTable[0].Flags = 0;
  372. QueryTable[0].Name = NW_BIND_VALUENAME;
  373. QueryTable[0].EntryContext = NULL;
  374. QueryTable[0].DefaultType = REG_NONE;
  375. QueryTable[0].DefaultData = NULL;
  376. QueryTable[0].DefaultLength = 0;
  377. QueryTable[1].QueryRoutine = NULL;
  378. QueryTable[1].Flags = 0;
  379. QueryTable[1].Name = NULL;
  380. ntstatus = RtlQueryRegistryValues(
  381. RTL_REGISTRY_SERVICES,
  382. NW_LINKAGE_REGISTRY_PATH,
  383. QueryTable,
  384. &NumberOfBindings,
  385. NULL
  386. );
  387. (void) LocalFree((HLOCAL) QueryTable);
  388. //
  389. // If failed to bind to any transports, the workstation will
  390. // not start.
  391. //
  392. if (! NT_SUCCESS(ntstatus)) {
  393. #if DBG
  394. IF_DEBUG(INIT) {
  395. KdPrint(("NwBindToTransports: RtlQueryRegistryValues failed: "
  396. "%lx\n", ntstatus));
  397. }
  398. #endif
  399. return RtlNtStatusToDosError(ntstatus);
  400. }
  401. if (NumberOfBindings == 0) {
  402. #if 0
  403. //
  404. // tommye - MS 24187 / MCS 255
  405. //
  406. //
  407. // We don't want to log an event unnecessarily and panic the user that
  408. // G/CSNW could not bind. This could have been caused by the user unbinding
  409. // G/CSNW and rebooting.
  410. //
  411. NwLogEvent(
  412. EVENT_NWWKSTA_NO_TRANSPORTS,
  413. 0,
  414. NULL,
  415. NO_ERROR
  416. );
  417. #endif
  418. KdPrint(("NWWORKSTATION: NwBindToTransports: could not bind "
  419. "to any transport\n"));
  420. return ERROR_INVALID_PARAMETER;
  421. }
  422. return NO_ERROR;
  423. }
  424. STATIC
  425. NTSTATUS
  426. BindToEachTransport(
  427. IN PWSTR ValueName,
  428. IN ULONG ValueType,
  429. IN PVOID ValueData,
  430. IN ULONG ValueLength,
  431. IN PVOID Context,
  432. IN PVOID EntryContext
  433. )
  434. {
  435. DWORD error;
  436. LPDWORD NumberOfBindings = Context;
  437. LPWSTR SubStrings[2];
  438. static DWORD QualityOfService = 65536;
  439. UNREFERENCED_PARAMETER(ValueName);
  440. UNREFERENCED_PARAMETER(ValueLength);
  441. UNREFERENCED_PARAMETER(EntryContext);
  442. //
  443. // The value type must be REG_SZ (translated from REG_MULTI_SZ by
  444. // the RTL).
  445. //
  446. if (ValueType != REG_SZ) {
  447. SubStrings[0] = ValueName;
  448. SubStrings[1] = NW_LINKAGE_REGISTRY_PATH;
  449. NwLogEvent(
  450. EVENT_NWWKSTA_INVALID_REGISTRY_VALUE,
  451. 2,
  452. SubStrings,
  453. NO_ERROR
  454. );
  455. KdPrint(("NWWORKSTATION: Skipping invalid value %ws\n", ValueName));
  456. return STATUS_SUCCESS;
  457. }
  458. //
  459. // The value data is the name of the transport device object.
  460. //
  461. //
  462. // Bind to the transport.
  463. //
  464. #if DBG
  465. IF_DEBUG(INIT) {
  466. KdPrint(("NWWORKSTATION: Binding to transport %ws with QOS %lu\n",
  467. ValueData, QualityOfService));
  468. }
  469. #endif
  470. error = NwBindTransport(ValueData, QualityOfService--);
  471. if (error != NO_ERROR) {
  472. //
  473. // If failed to bind to one transport, don't fail starting yet.
  474. // Try other transports.
  475. //
  476. SubStrings[0] = ValueData;
  477. NwLogEvent(
  478. EVENT_NWWKSTA_CANT_BIND_TO_TRANSPORT,
  479. 1,
  480. SubStrings,
  481. error
  482. );
  483. }
  484. else {
  485. (*NumberOfBindings)++;
  486. }
  487. return STATUS_SUCCESS;
  488. }
  489. DWORD
  490. NwBindTransport(
  491. IN LPWSTR TransportName,
  492. IN DWORD QualityOfService
  493. )
  494. /*++
  495. Routine Description:
  496. This function binds the specified transport to the redirector
  497. and the datagram receiver.
  498. NOTE: The transport name length pass to the redirector and
  499. datagram receiver is the number of bytes.
  500. Arguments:
  501. TransportName - Supplies the name of the transport to bind to.
  502. QualityOfService - Supplies a value which specifies the search
  503. order of the transport with respect to other transports. The
  504. highest value is searched first.
  505. Return Value:
  506. NO_ERROR or reason for failure.
  507. --*/
  508. {
  509. DWORD status;
  510. DWORD RequestPacketSize;
  511. DWORD TransportNameSize = wcslen(TransportName) * sizeof(WCHAR);
  512. PNWR_REQUEST_PACKET Rrp;
  513. //
  514. // Size of request packet buffer
  515. //
  516. RequestPacketSize = TransportNameSize + sizeof(NWR_REQUEST_PACKET);
  517. //
  518. // Allocate memory for redirector/datagram receiver request packet
  519. //
  520. if ((Rrp = (PVOID) LocalAlloc(LMEM_ZEROINIT, (UINT) RequestPacketSize)) == NULL) {
  521. return ERROR_NOT_ENOUGH_MEMORY;
  522. }
  523. //
  524. // Get redirector to bind to transport
  525. //
  526. Rrp->Version = REQUEST_PACKET_VERSION;
  527. Rrp->Parameters.Bind.QualityOfService = QualityOfService;
  528. Rrp->Parameters.Bind.TransportNameLength = TransportNameSize;
  529. wcscpy((LPWSTR) Rrp->Parameters.Bind.TransportName, TransportName);
  530. if ((status = NwRedirFsControl(
  531. RedirDeviceHandle,
  532. FSCTL_NWR_BIND_TO_TRANSPORT,
  533. Rrp,
  534. RequestPacketSize,
  535. NULL,
  536. 0,
  537. NULL
  538. )) != NO_ERROR) {
  539. KdPrint(("NWWORKSTATION: NwBindTransport fsctl to bind to transport %ws failed\n",
  540. TransportName));
  541. }
  542. (void) LocalFree((HLOCAL) Rrp);
  543. return status;
  544. }
  545. DWORD
  546. NwGetCallerLuid (
  547. IN OUT PLUID pLuid
  548. )
  549. /*++
  550. Routine Description:
  551. Retrieves the caller's LUID from the effective access_token
  552. The effective access_token will be the thread's token if
  553. impersonating, else the process' token
  554. Arguments:
  555. pLuid [IN OUT] - pointer to a buffer to hold the LUID
  556. Return Value:
  557. STATUS_SUCCESS - operations successful, did not encounter any errors
  558. STATUS_INVALID_PARAMETER - pLuid is NULL
  559. STATUS_NO_TOKEN - could not find a token for the user
  560. appropriate NTSTATUS code - an unexpected error encountered
  561. --*/
  562. {
  563. TOKEN_STATISTICS TokenStats;
  564. HANDLE hToken = NULL;
  565. DWORD dwLength = 0;
  566. NTSTATUS Status;
  567. ULONG DosError;
  568. if( (pLuid == NULL) || (sizeof(*pLuid) != sizeof(LUID)) ) {
  569. return( STATUS_INVALID_PARAMETER );
  570. }
  571. //
  572. // Get the access token
  573. // Try to get the impersonation token, else the primary token
  574. //
  575. Status = NtOpenThreadToken( NtCurrentThread(), TOKEN_READ, TRUE, &hToken );
  576. if( Status == STATUS_NO_TOKEN ) {
  577. Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_READ, &hToken );
  578. }
  579. if( NT_SUCCESS(Status) ) {
  580. //
  581. // Query the LUID for the user.
  582. //
  583. Status = NtQueryInformationToken( hToken,
  584. TokenStatistics,
  585. &TokenStats,
  586. sizeof(TokenStats),
  587. &dwLength );
  588. if( NT_SUCCESS(Status) ) {
  589. RtlCopyLuid( pLuid, &(TokenStats.AuthenticationId) );
  590. }
  591. }
  592. if( hToken != NULL ) {
  593. NtClose( hToken );
  594. }
  595. DosError = RtlNtStatusToDosError(Status);
  596. return( (DWORD)DosError );
  597. }
  598. DWORD
  599. NwCreateTreeConnectName(
  600. IN LPWSTR UncName,
  601. IN LPWSTR LocalName OPTIONAL,
  602. OUT PUNICODE_STRING TreeConnectStr
  603. )
  604. /*++
  605. Routine Description:
  606. This function replaces \\ with \Device\NwRdr\LocalName:\ in the
  607. UncName to form the NT-style tree connection name. LocalName:\ is part
  608. of the tree connection name only if LocalName is specified. A buffer
  609. is allocated by this function and returned as the output string.
  610. Arguments:
  611. UncName - Supplies the UNC name of the shared resource.
  612. LocalName - Supplies the local device name for the redirection.
  613. TreeConnectStr - Returns a string with a newly allocated buffer that
  614. contains the NT-style tree connection name.
  615. Return Value:
  616. NO_ERROR - the operation was successful.
  617. ERROR_NOT_ENOUGH_MEMORY - Could not allocate output buffer.
  618. --*/
  619. {
  620. WCHAR LUIDBuffer[NW_MAX_LOGON_ID_LEN];
  621. DWORD UncNameLength = wcslen(UncName);
  622. LUID CallerLuid;
  623. BOOLEAN UseLUID;
  624. //UseLUID = (ARGUMENT_PRESENT(LocalName) && NwLUIDDeviceMapsEnabled);
  625. //
  626. // Temporary disable passing the LUID until LUID support is added in
  627. // the nwrdr.sys for parsing the device name
  628. //
  629. UseLUID = FALSE;
  630. //
  631. // Initialize tree connect string maximum length to hold
  632. // If LUID DosDevices enabled && LocalName Specified,
  633. // \Device\NwRdr\LocalName:XXXXXXXXxxxxxxxx\Server\Volume\Path
  634. // XXXXXXXX - LUID.HighPart
  635. // xxxxxxxx - LUID.LowPart
  636. // else
  637. // \Device\NwRdr\LocalName:\Server\Volume\Path
  638. //
  639. if( UseLUID ) {
  640. DWORD DosError;
  641. DosError = NwGetCallerLuid(&CallerLuid);
  642. if( DosError != NO_ERROR) {
  643. return DosError;
  644. }
  645. }
  646. TreeConnectStr->MaximumLength = RedirDeviceName.Length +
  647. sizeof(WCHAR) + // For ending 0
  648. sizeof(WCHAR) + // For '\'
  649. (ARGUMENT_PRESENT(LocalName) ? (wcslen(LocalName) * sizeof(WCHAR)) : 0) +
  650. (UseLUID ? NW_MAX_LOGON_ID_LEN * sizeof(WCHAR): 0) +
  651. (USHORT) (UncNameLength * sizeof(WCHAR)); // Includes '\'
  652. if ((TreeConnectStr->Buffer = (PWSTR) LocalAlloc(
  653. LMEM_ZEROINIT,
  654. (UINT) TreeConnectStr->MaximumLength
  655. )) == NULL) {
  656. KdPrint(("NWWORKSTATION: NwCreateTreeConnectName LocalAlloc failed %lu\n",
  657. GetLastError()));
  658. return ERROR_NOT_ENOUGH_MEMORY;
  659. }
  660. //
  661. // Copy \Device\NwRdr
  662. //
  663. RtlCopyUnicodeString(TreeConnectStr, &RedirDeviceName);
  664. //
  665. // Concatenate \LocalName:
  666. //
  667. if (ARGUMENT_PRESENT(LocalName)) {
  668. wcscat(TreeConnectStr->Buffer, L"\\");
  669. TreeConnectStr->Length += sizeof(WCHAR);
  670. wcscat(TreeConnectStr->Buffer, LocalName);
  671. TreeConnectStr->Length += (USHORT) (wcslen(LocalName) * sizeof(WCHAR));
  672. //
  673. // Concatenate the caller's LUID
  674. //
  675. if( UseLUID ) {
  676. _snwprintf( LUIDBuffer,
  677. NW_MAX_LOGON_ID_LEN - 1,
  678. L"%08x%08x",
  679. CallerLuid.HighPart,
  680. CallerLuid.LowPart );
  681. LUIDBuffer[NW_MAX_LOGON_ID_LEN - 1] = 0;
  682. wcscat(TreeConnectStr->Buffer, LUIDBuffer);
  683. TreeConnectStr->Length += (USHORT) (wcslen(LUIDBuffer) * sizeof(WCHAR));
  684. }
  685. }
  686. //
  687. // Concatenate \Server\Volume\Path
  688. //
  689. if (UncNameLength > 0) {
  690. wcscat(TreeConnectStr->Buffer, &UncName[1]);
  691. TreeConnectStr->Length += (USHORT) ((UncNameLength - 1) * sizeof(WCHAR));
  692. }
  693. #if DBG
  694. IF_DEBUG(CONNECT) {
  695. KdPrint(("NWWORKSTATION: NwCreateTreeConnectName %ws, maxlength %u, length %u\n",
  696. TreeConnectStr->Buffer, TreeConnectStr->MaximumLength,
  697. TreeConnectStr->Length));
  698. }
  699. #endif
  700. return NO_ERROR;
  701. }
  702. DWORD
  703. NwOpenCreateConnection(
  704. IN PUNICODE_STRING TreeConnectionName,
  705. IN LPWSTR UserName OPTIONAL,
  706. IN LPWSTR Password OPTIONAL,
  707. IN LPWSTR UncName,
  708. IN ACCESS_MASK DesiredAccess,
  709. IN ULONG CreateDisposition,
  710. IN ULONG CreateOptions,
  711. IN ULONG ConnectionType,
  712. OUT PHANDLE TreeConnectionHandle,
  713. OUT PULONG_PTR Information OPTIONAL
  714. )
  715. /*++
  716. Routine Description:
  717. This function asks the redirector to either open an existing tree
  718. connection (CreateDisposition == FILE_OPEN), or create a new tree
  719. connection if one does not exist (CreateDisposition == FILE_CREATE).
  720. The password and user name passed to the redirector via the EA buffer
  721. in the NtCreateFile call. The EA buffer is NULL if neither password
  722. or user name is specified.
  723. The redirector expects the EA descriptor strings to be in ANSI
  724. but the password and username themselves are in Unicode.
  725. Arguments:
  726. TreeConnectionName - Supplies the name of the tree connection in NT-style
  727. file name format: \Device\NwRdr\Server\Volume\Directory
  728. UserName - Supplies the user name to create the tree connection with.
  729. Password - Supplies the password to create the tree connection with.
  730. DesiredAccess - Supplies the access need on the connection handle.
  731. CreateDisposition - Supplies the create disposition value to either
  732. open or create the tree connection.
  733. CreateOptions - Supplies the options used when creating or opening
  734. the tree connection.
  735. ConnectionType - Supplies the type of the connection (DISK, PRINT,
  736. or ANY).
  737. TreeConnectionHandle - Returns the handle to the tree connection
  738. created/opened by the redirector.
  739. Information - Returns the information field of the I/O status block.
  740. Return Value:
  741. NO_ERROR or reason for failure.
  742. --*/
  743. {
  744. DWORD status;
  745. NTSTATUS ntstatus;
  746. OBJECT_ATTRIBUTES UncNameAttributes;
  747. IO_STATUS_BLOCK IoStatusBlock;
  748. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  749. PFILE_FULL_EA_INFORMATION Ea;
  750. ULONG EaBufferSize = 0;
  751. UCHAR EaNamePasswordSize = (UCHAR) (ROUND_UP_COUNT(
  752. strlen(EA_NAME_PASSWORD) + sizeof(CHAR),
  753. ALIGN_WCHAR
  754. ) - sizeof(CHAR));
  755. UCHAR EaNameUserNameSize = (UCHAR) (ROUND_UP_COUNT(
  756. strlen(EA_NAME_USERNAME) + sizeof(CHAR),
  757. ALIGN_WCHAR
  758. ) - sizeof(CHAR));
  759. UCHAR EaNameTypeSize = (UCHAR) (ROUND_UP_COUNT(
  760. strlen(EA_NAME_TYPE) + sizeof(CHAR),
  761. ALIGN_DWORD
  762. ) - sizeof(CHAR));
  763. USHORT PasswordSize = 0;
  764. USHORT UserNameSize = 0;
  765. USHORT TypeSize = sizeof(ULONG);
  766. InitializeObjectAttributes(
  767. &UncNameAttributes,
  768. TreeConnectionName,
  769. OBJ_CASE_INSENSITIVE,
  770. NULL,
  771. NULL
  772. );
  773. //
  774. // Calculate the number of bytes needed for the EA buffer to put the
  775. // password or user name.
  776. //
  777. if (ARGUMENT_PRESENT(Password)) {
  778. #if DBG
  779. IF_DEBUG(CONNECT) {
  780. KdPrint(("NWWORKSTATION: NwOpenCreateConnection password is %ws\n",
  781. Password));
  782. }
  783. #endif
  784. PasswordSize = (USHORT) (wcslen(Password) * sizeof(WCHAR));
  785. EaBufferSize = ROUND_UP_COUNT(
  786. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  787. EaNamePasswordSize + sizeof(CHAR) +
  788. PasswordSize,
  789. ALIGN_DWORD
  790. );
  791. }
  792. if (ARGUMENT_PRESENT(UserName)) {
  793. #if DBG
  794. IF_DEBUG(CONNECT) {
  795. KdPrint(("NWWORKSTATION: NwOpenCreateConnection username is %ws\n",
  796. UserName));
  797. }
  798. #endif
  799. UserNameSize = (USHORT) (wcslen(UserName) * sizeof(WCHAR));
  800. EaBufferSize += ROUND_UP_COUNT(
  801. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  802. EaNameUserNameSize + sizeof(CHAR) +
  803. UserNameSize,
  804. ALIGN_DWORD
  805. );
  806. }
  807. EaBufferSize += FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  808. EaNameTypeSize + sizeof(CHAR) +
  809. TypeSize;
  810. //
  811. // Allocate the EA buffer
  812. //
  813. if ((EaBuffer = (PFILE_FULL_EA_INFORMATION) LocalAlloc(
  814. LMEM_ZEROINIT,
  815. (UINT) EaBufferSize
  816. )) == NULL) {
  817. status = GetLastError();
  818. goto FreeMemory;
  819. }
  820. Ea = EaBuffer;
  821. if (ARGUMENT_PRESENT(Password)) {
  822. //
  823. // Copy the EA name into EA buffer. EA name length does not
  824. // include the zero terminator.
  825. //
  826. strcpy((LPSTR) Ea->EaName, EA_NAME_PASSWORD);
  827. Ea->EaNameLength = EaNamePasswordSize;
  828. //
  829. // Copy the EA value into EA buffer. EA value length does not
  830. // include the zero terminator.
  831. //
  832. wcscpy(
  833. (LPWSTR) &(Ea->EaName[EaNamePasswordSize + sizeof(CHAR)]),
  834. Password
  835. );
  836. Ea->EaValueLength = PasswordSize;
  837. Ea->NextEntryOffset = ROUND_UP_COUNT(
  838. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  839. EaNamePasswordSize + sizeof(CHAR) +
  840. PasswordSize,
  841. ALIGN_DWORD
  842. );
  843. Ea->Flags = 0;
  844. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  845. }
  846. if (ARGUMENT_PRESENT(UserName)) {
  847. //
  848. // Copy the EA name into EA buffer. EA name length does not
  849. // include the zero terminator.
  850. //
  851. strcpy((LPSTR) Ea->EaName, EA_NAME_USERNAME);
  852. Ea->EaNameLength = EaNameUserNameSize;
  853. //
  854. // Copy the EA value into EA buffer. EA value length does not
  855. // include the zero terminator.
  856. //
  857. wcscpy(
  858. (LPWSTR) &(Ea->EaName[EaNameUserNameSize + sizeof(CHAR)]),
  859. UserName
  860. );
  861. Ea->EaValueLength = UserNameSize;
  862. Ea->NextEntryOffset = ROUND_UP_COUNT(
  863. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  864. EaNameUserNameSize + sizeof(CHAR) +
  865. UserNameSize,
  866. ALIGN_DWORD
  867. );
  868. Ea->Flags = 0;
  869. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  870. }
  871. //
  872. // Copy the connection type name into EA buffer. EA name length
  873. // does not include the zero terminator.
  874. //
  875. strcpy((LPSTR) Ea->EaName, EA_NAME_TYPE);
  876. Ea->EaNameLength = EaNameTypeSize;
  877. *((PULONG) &(Ea->EaName[EaNameTypeSize + sizeof(CHAR)])) = ConnectionType;
  878. Ea->EaValueLength = TypeSize;
  879. //
  880. // Terminate the EA.
  881. //
  882. Ea->NextEntryOffset = 0;
  883. Ea->Flags = 0;
  884. //
  885. // Create or open a tree connection
  886. //
  887. ntstatus = NtCreateFile(
  888. TreeConnectionHandle,
  889. DesiredAccess,
  890. &UncNameAttributes,
  891. &IoStatusBlock,
  892. NULL,
  893. FILE_ATTRIBUTE_NORMAL,
  894. FILE_SHARE_VALID_FLAGS,
  895. CreateDisposition,
  896. CreateOptions,
  897. (PVOID) EaBuffer,
  898. EaBufferSize
  899. );
  900. if (ntstatus == NWRDR_PASSWORD_HAS_EXPIRED) {
  901. //
  902. // wait till other thread is not using the popup data struct.
  903. // if we timeout, then we just lose the popup.
  904. //
  905. switch (WaitForSingleObject(NwPopupDoneEvent, 3000))
  906. {
  907. case WAIT_OBJECT_0:
  908. {
  909. LPWSTR lpServerStart, lpServerEnd ;
  910. WCHAR UserNameW[NW_MAX_USERNAME_LEN+1] ;
  911. DWORD dwUserNameWSize = sizeof(UserNameW)/sizeof(UserNameW[0]) ;
  912. DWORD dwServerLength, dwGraceLogins ;
  913. DWORD dwMessageId = NW_PASSWORD_HAS_EXPIRED ;
  914. //
  915. // get the current username
  916. //
  917. if (UserName)
  918. {
  919. wcscpy(UserNameW, UserName) ;
  920. }
  921. else
  922. {
  923. if (!GetUserNameW(UserNameW, &dwUserNameWSize))
  924. {
  925. SetEvent(NwPopupDoneEvent) ;
  926. break ;
  927. }
  928. }
  929. //
  930. // allocate string and fill in the username
  931. //
  932. if (!(PopupData.InsertStrings[0] =
  933. (LPWSTR)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  934. sizeof(WCHAR) * (wcslen(UserNameW)+1))))
  935. {
  936. SetEvent(NwPopupDoneEvent) ;
  937. break ;
  938. }
  939. wcscpy(PopupData.InsertStrings[0], UserNameW) ;
  940. //
  941. // find the server name from unc name
  942. //
  943. lpServerStart = (*UncName == L'\\') ? UncName+2 : UncName ;
  944. lpServerEnd = wcschr(lpServerStart,L'\\') ;
  945. dwServerLength = lpServerEnd ? (DWORD) (lpServerEnd-lpServerStart) :
  946. wcslen(lpServerStart) ;
  947. //
  948. // allocate string and fill in the server insert string
  949. //
  950. if (!(PopupData.InsertStrings[1] =
  951. (LPWSTR)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  952. sizeof(WCHAR) * (dwServerLength+1))))
  953. {
  954. (void) LocalFree((HLOCAL) PopupData.InsertStrings[0]);
  955. SetEvent(NwPopupDoneEvent) ;
  956. break ;
  957. }
  958. wcsncpy(PopupData.InsertStrings[1],
  959. lpServerStart,
  960. dwServerLength) ;
  961. //
  962. // now call the NCP. if an error occurs while getting
  963. // the grace login count, dont use it.
  964. //
  965. if (NwGetGraceLoginCount(
  966. PopupData.InsertStrings[1],
  967. UserNameW,
  968. &dwGraceLogins) != NO_ERROR)
  969. {
  970. dwMessageId = NW_PASSWORD_HAS_EXPIRED1 ;
  971. dwGraceLogins = 0 ;
  972. }
  973. //
  974. // stick the number of grace logins in second insert string.
  975. //
  976. if (!(PopupData.InsertStrings[2] =
  977. (LPWSTR)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  978. sizeof(WCHAR) * 16)))
  979. {
  980. (void) LocalFree((HLOCAL) PopupData.InsertStrings[0]);
  981. (void) LocalFree((HLOCAL) PopupData.InsertStrings[1]);
  982. SetEvent(NwPopupDoneEvent) ;
  983. break ;
  984. }
  985. wsprintfW(PopupData.InsertStrings[2], L"%d", dwGraceLogins);
  986. PopupData.InsertCount = 3 ;
  987. PopupData.MessageId = dwMessageId ;
  988. //--Mutl-user change ----
  989. GetLuid( &PopupData.LogonId );
  990. //
  991. // all done at last, trigger the other thread do the popup
  992. //
  993. SetEvent(NwPopupEvent) ;
  994. break ;
  995. }
  996. default:
  997. break ; // dont bother if we cannot
  998. }
  999. }
  1000. if (NT_SUCCESS(ntstatus)) {
  1001. ntstatus = IoStatusBlock.Status;
  1002. }
  1003. if (ntstatus == NWRDR_PASSWORD_HAS_EXPIRED) {
  1004. ntstatus = STATUS_SUCCESS ;
  1005. }
  1006. if (ARGUMENT_PRESENT(Information)) {
  1007. *Information = IoStatusBlock.Information;
  1008. }
  1009. #if DBG
  1010. IF_DEBUG(CONNECT) {
  1011. KdPrint(("NWWORKSTATION: NtCreateFile returns %lx\n", ntstatus));
  1012. }
  1013. #endif
  1014. status = NwMapStatus(ntstatus);
  1015. FreeMemory:
  1016. if (EaBuffer != NULL) {
  1017. RtlZeroMemory( EaBuffer, EaBufferSize ); // Clear the password
  1018. (void) LocalFree((HLOCAL) EaBuffer);
  1019. }
  1020. return status;
  1021. }
  1022. DWORD
  1023. NwNukeConnection(
  1024. IN HANDLE TreeConnection,
  1025. IN DWORD UseForce
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. This function asks the redirector to delete an existing tree
  1030. connection.
  1031. Arguments:
  1032. TreeConnection - Supplies the handle to an existing tree connection.
  1033. UseForce - Supplies the force flag to delete the tree connection.
  1034. Return Value:
  1035. NO_ERROR or reason for failure.
  1036. --*/
  1037. {
  1038. DWORD status;
  1039. NWR_REQUEST_PACKET Rrp; // Redirector request packet
  1040. //
  1041. // Tell the redirector to delete the tree connection
  1042. //
  1043. Rrp.Version = REQUEST_PACKET_VERSION;
  1044. Rrp.Parameters.DeleteConn.UseForce = (BOOLEAN) UseForce;
  1045. status = NwRedirFsControl(
  1046. TreeConnection,
  1047. FSCTL_NWR_DELETE_CONNECTION,
  1048. &Rrp,
  1049. sizeof(NWR_REQUEST_PACKET),
  1050. NULL,
  1051. 0,
  1052. NULL
  1053. );
  1054. return status;
  1055. }
  1056. DWORD
  1057. NwGetServerResource(
  1058. IN LPWSTR LocalName,
  1059. IN DWORD LocalNameLength,
  1060. OUT LPWSTR RemoteName,
  1061. IN DWORD RemoteNameLen,
  1062. OUT LPDWORD CharsRequired
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. This function
  1067. Arguments:
  1068. Return Value:
  1069. --*/
  1070. {
  1071. DWORD status = NO_ERROR;
  1072. BYTE Buffer[sizeof(NWR_REQUEST_PACKET) + 2 * sizeof(WCHAR)];
  1073. PNWR_REQUEST_PACKET Rrp = (PNWR_REQUEST_PACKET) Buffer;
  1074. //
  1075. // local device name should not be longer than 4 characters e.g. LPTx, X:
  1076. //
  1077. if ( LocalNameLength > 4 )
  1078. return ERROR_INVALID_PARAMETER;
  1079. Rrp->Version = REQUEST_PACKET_VERSION;
  1080. wcsncpy(Rrp->Parameters.GetConn.DeviceName, LocalName, LocalNameLength);
  1081. Rrp->Parameters.GetConn.DeviceNameLength = LocalNameLength * sizeof(WCHAR);
  1082. status = NwRedirFsControl(
  1083. RedirDeviceHandle,
  1084. FSCTL_NWR_GET_CONNECTION,
  1085. Rrp,
  1086. sizeof(NWR_REQUEST_PACKET) +
  1087. Rrp->Parameters.GetConn.DeviceNameLength,
  1088. RemoteName,
  1089. RemoteNameLen * sizeof(WCHAR),
  1090. NULL
  1091. );
  1092. if (status == ERROR_INSUFFICIENT_BUFFER) {
  1093. *CharsRequired = Rrp->Parameters.GetConn.BytesNeeded / sizeof(WCHAR);
  1094. }
  1095. else if (status == ERROR_FILE_NOT_FOUND) {
  1096. //
  1097. // Redirector could not find the specified LocalName
  1098. //
  1099. status = WN_NOT_CONNECTED;
  1100. }
  1101. return status;
  1102. }
  1103. DWORD
  1104. NwEnumerateConnections(
  1105. IN OUT PDWORD_PTR ResumeId,
  1106. IN DWORD_PTR EntriesRequested,
  1107. IN LPBYTE Buffer,
  1108. IN DWORD BufferSize,
  1109. OUT LPDWORD BytesNeeded,
  1110. OUT LPDWORD EntriesRead,
  1111. IN DWORD ConnectionType,
  1112. IN PLUID LogonId
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. This function asks the redirector to enumerate all existing
  1117. connections.
  1118. Arguments:
  1119. ResumeId - On input, supplies the resume ID of the next entry
  1120. to begin the enumeration. This ID is an integer value that
  1121. is either the smaller or the same value as the ID of the
  1122. next entry to return. On output, this ID indicates the next
  1123. entry to start resuming from for the subsequent call.
  1124. EntriesRequested - Supplies the number of entries to return. If
  1125. this value is -1, return all available entries.
  1126. Buffer - Receives the entries we are listing.
  1127. BufferSize - Supplies the size of the output buffer.
  1128. BytesNeeded - Receives the number of bytes required to get the
  1129. first entry. This value is returned iff ERROR_MORE_DATA is
  1130. the return code, and Buffer is too small to even fit one
  1131. entry.
  1132. EntriesRead - Receives the number of entries returned in Buffer.
  1133. This value is only returned iff NO_ERROR is the return code.
  1134. NO_ERROR is returned as long as at least one entry was written
  1135. into Buffer but does not necessarily mean that it's the number
  1136. of EntriesRequested.
  1137. ConnectionType - The type of connected resource wanted ( DISK, PRINT, ...)
  1138. Return Value:
  1139. NO_ERROR or reason for failure.
  1140. --*/
  1141. {
  1142. DWORD status;
  1143. NWR_REQUEST_PACKET Rrp; // Redirector request packet
  1144. //
  1145. // Tell the redirector to enumerate all connections.
  1146. //
  1147. Rrp.Version = REQUEST_PACKET_VERSION;
  1148. Rrp.Parameters.EnumConn.ResumeKey = *ResumeId;
  1149. Rrp.Parameters.EnumConn.EntriesRequested = (ULONG) EntriesRequested;
  1150. Rrp.Parameters.EnumConn.ConnectionType = ConnectionType;
  1151. //Multi-user change
  1152. if (LogonId != NULL ) {
  1153. Rrp.Parameters.EnumConn.Uid = *LogonId;
  1154. }
  1155. //
  1156. // This is good to do, the the fix below is also needed.
  1157. //
  1158. Rrp.Parameters.EnumConn.EntriesReturned = 0;
  1159. status = NwRedirFsControl(
  1160. RedirDeviceHandle,
  1161. FSCTL_NWR_ENUMERATE_CONNECTIONS,
  1162. &Rrp,
  1163. sizeof(NWR_REQUEST_PACKET),
  1164. Buffer, // User output buffer
  1165. BufferSize,
  1166. NULL
  1167. );
  1168. *EntriesRead = Rrp.Parameters.EnumConn.EntriesReturned;
  1169. //
  1170. // Strange bug on shutdown
  1171. // WinLogon was clearing connections after the shutdown
  1172. //
  1173. if (status == ERROR_INVALID_HANDLE ) {
  1174. KdPrint(("NWWORKSTATION: NwEnumerateConnections Invalid Handle!\n"));
  1175. *EntriesRead = 0;
  1176. }
  1177. else if (status == WN_MORE_DATA) {
  1178. *BytesNeeded = Rrp.Parameters.EnumConn.BytesNeeded;
  1179. //
  1180. // NP specs expect WN_SUCCESS in this case.
  1181. //
  1182. if (*EntriesRead)
  1183. status = WN_SUCCESS ;
  1184. }
  1185. *ResumeId = Rrp.Parameters.EnumConn.ResumeKey;
  1186. return status;
  1187. }
  1188. DWORD
  1189. NwGetNextServerEntry(
  1190. IN HANDLE PreferredServer,
  1191. IN OUT LPDWORD LastObjectId,
  1192. OUT LPSTR ServerName
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. This function uses an opened handle to the preferred server to
  1197. scan it bindery for all file server objects.
  1198. Arguments:
  1199. PreferredServer - Supplies the handle to the preferred server on
  1200. which to scan the bindery.
  1201. LastObjectId - On input, supplies the object ID to the last file
  1202. server object returned, which is the resume handle to get the
  1203. next file server object. On output, receives the object ID
  1204. of the file server object returned.
  1205. ServerName - Receives the name of the returned file server object.
  1206. Return Value:
  1207. NO_ERROR - Successfully gotten a file server name.
  1208. WN_NO_MORE_ENTRIES - No other file server object past the one
  1209. specified by LastObjectId.
  1210. --*/
  1211. {
  1212. NTSTATUS ntstatus;
  1213. WORD ObjectType;
  1214. #if DBG
  1215. IF_DEBUG(ENUM) {
  1216. KdPrint(("NWWORKSTATION: NwGetNextServerEntry LastObjectId %lu\n",
  1217. *LastObjectId));
  1218. }
  1219. #endif
  1220. ntstatus = NwlibMakeNcp(
  1221. PreferredServer,
  1222. FSCTL_NWR_NCP_E3H, // Bindery function
  1223. 58, // Max request packet size
  1224. 59, // Max response packet size
  1225. "bdwp|dwc", // Format string
  1226. 0x37, // Scan bindery object
  1227. *LastObjectId, // Previous ID
  1228. 0x4, // File server object
  1229. "*", // Wildcard to match all
  1230. LastObjectId, // Current ID
  1231. &ObjectType, // Ignore
  1232. ServerName // Currently returned server
  1233. );
  1234. #if DBG
  1235. if (ntstatus == STATUS_SUCCESS) {
  1236. IF_DEBUG(ENUM) {
  1237. KdPrint(("NWWORKSTATION: NwGetNextServerEntry NewObjectId %08lx, ServerName %s\n",
  1238. *LastObjectId, ServerName));
  1239. }
  1240. }
  1241. #endif
  1242. return NwMapBinderyCompletionCode(ntstatus);
  1243. }
  1244. DWORD
  1245. GetConnectedBinderyServers(
  1246. OUT LPNW_ENUM_CONTEXT ContextHandle
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. This function is a helper routine for the function
  1251. NwGetNextServerConnection. It allocates a buffer to cache
  1252. bindery server names returned from calls to the redirector. Since the
  1253. redirector may return duplicate bindery server names, this
  1254. function checks to see if the server name already exist in the buffer
  1255. before adding it.
  1256. Arguments:
  1257. ContextHandle - Used to track cached bindery information and the
  1258. current server name pointer in the cache buffer.
  1259. Return Value:
  1260. NO_ERROR - Successfully returned a server name and cache buffer.
  1261. WN_NO_MORE_ENTRIES - No other server object past the one
  1262. specified by CH->ResumeId.
  1263. ERROR_NOT_ENOUGH_MEMORY - Function was unable to allocate a buffer.
  1264. ++*/
  1265. {
  1266. DWORD_PTR ResumeKey = 0;
  1267. LPBYTE pBuffer = NULL;
  1268. DWORD EntriesRead = 0;
  1269. BYTE tokenIter;
  1270. LPWSTR tokenPtr;
  1271. BOOL fAddToList;
  1272. DWORD status = NwGetConnectionStatus( NULL,
  1273. &ResumeKey,
  1274. &pBuffer,
  1275. &EntriesRead );
  1276. if ( status == NO_ERROR && EntriesRead > 0 )
  1277. {
  1278. DWORD i;
  1279. PCONN_STATUS pConnStatus = (PCONN_STATUS) pBuffer;
  1280. ContextHandle->ResumeId = 0;
  1281. ContextHandle->NdsRawDataCount = 0;
  1282. ContextHandle->NdsRawDataSize = (NW_MAX_SERVER_LEN + 2) * EntriesRead;
  1283. ContextHandle->NdsRawDataBuffer =
  1284. (DWORD_PTR) LocalAlloc( LMEM_ZEROINIT,
  1285. ContextHandle->NdsRawDataSize );
  1286. if ( ContextHandle->NdsRawDataBuffer == 0 )
  1287. {
  1288. KdPrint(("NWWORKSTATION: GetConnectedBinderyServers LocalAlloc failed %lu\n",
  1289. GetLastError()));
  1290. ContextHandle->NdsRawDataSize = 0;
  1291. return ERROR_NOT_ENOUGH_MEMORY;
  1292. }
  1293. for ( i = 0; i < EntriesRead ; i++ )
  1294. {
  1295. fAddToList = FALSE;
  1296. if ( pConnStatus->fNds == 0 &&
  1297. ( pConnStatus->dwConnType == NW_CONN_BINDERY_LOGIN ||
  1298. pConnStatus->dwConnType == NW_CONN_NDS_AUTHENTICATED_NO_LICENSE ||
  1299. pConnStatus->dwConnType == NW_CONN_NDS_AUTHENTICATED_LICENSED ||
  1300. pConnStatus->dwConnType == NW_CONN_DISCONNECTED ) )
  1301. {
  1302. fAddToList = TRUE;
  1303. tokenPtr = (LPWSTR) ContextHandle->NdsRawDataBuffer;
  1304. tokenIter = 0;
  1305. //
  1306. // Walk through buffer to see if the tree name already exists.
  1307. //
  1308. while ( tokenIter < ContextHandle->NdsRawDataCount )
  1309. {
  1310. if ( !wcscmp( tokenPtr, pConnStatus->pszServerName ) )
  1311. {
  1312. fAddToList = FALSE;
  1313. }
  1314. tokenPtr = tokenPtr + wcslen( tokenPtr ) + 1;
  1315. tokenIter++;
  1316. }
  1317. }
  1318. //
  1319. // Add the new tree name to end of buffer if needed.
  1320. //
  1321. if ( fAddToList )
  1322. {
  1323. wcscpy( tokenPtr, pConnStatus->pszServerName );
  1324. _wcsupr( tokenPtr );
  1325. ContextHandle->NdsRawDataCount += 1;
  1326. }
  1327. pConnStatus = (PCONN_STATUS) ( pConnStatus +
  1328. pConnStatus->dwTotalLength );
  1329. }
  1330. if ( pBuffer != NULL )
  1331. {
  1332. LocalFree( pBuffer );
  1333. pBuffer = NULL;
  1334. }
  1335. if ( ContextHandle->NdsRawDataCount > 0 )
  1336. {
  1337. //
  1338. // Set ResumeId to point to the first entry in buffer
  1339. // and have NdsRawDataCount set to the number
  1340. // of tree entries left in buffer (ie. substract 1)
  1341. //
  1342. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer;
  1343. ContextHandle->NdsRawDataCount -= 1;
  1344. }
  1345. return NO_ERROR;
  1346. }
  1347. return WN_NO_MORE_ENTRIES;
  1348. }
  1349. DWORD
  1350. NwGetNextServerConnection(
  1351. OUT LPNW_ENUM_CONTEXT ContextHandle
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. This function queries the redirector for bindery server connections
  1356. Arguments:
  1357. ContextHandle - Receives the name of the returned bindery server.
  1358. Return Value:
  1359. NO_ERROR - Successfully returned a server name.
  1360. WN_NO_MORE_ENTRIES - No other server objects past the one
  1361. specified by CH->ResumeId exist.
  1362. --*/
  1363. {
  1364. #if DBG
  1365. IF_DEBUG(ENUM) {
  1366. KdPrint(("NWWORKSTATION: NwGetNextServerConnection ResumeId %lu\n",
  1367. ContextHandle->ResumeId));
  1368. }
  1369. #endif
  1370. if ( ContextHandle->ResumeId == (DWORD_PTR) -1 &&
  1371. ContextHandle->NdsRawDataBuffer == 0 &&
  1372. ContextHandle->NdsRawDataCount == 0 )
  1373. {
  1374. //
  1375. // Fill the buffer and point ResumeId to the last
  1376. // server entry name in it. NdsRawDataCount will be
  1377. // set to one less than the number of server names in buffer.
  1378. //
  1379. return GetConnectedBinderyServers( ContextHandle );
  1380. }
  1381. if ( ContextHandle->NdsRawDataBuffer != 0 &&
  1382. ContextHandle->NdsRawDataCount > 0 )
  1383. {
  1384. //
  1385. // Move ResumeId to point to the next entry in the buffer
  1386. // and decrement the NdsRawDataCount by one. Watch for case
  1387. // where we backed up to -1.
  1388. //
  1389. if (ContextHandle->ResumeId == (DWORD_PTR) -1) {
  1390. //
  1391. // Reset to start of buffer.
  1392. //
  1393. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer;
  1394. }
  1395. else {
  1396. //
  1397. // Treat as pointer and advance as need.
  1398. //
  1399. ContextHandle->ResumeId =
  1400. ContextHandle->ResumeId +
  1401. ( ( wcslen( (LPWSTR) ContextHandle->ResumeId ) + 1 ) *
  1402. sizeof(WCHAR) );
  1403. }
  1404. ContextHandle->NdsRawDataCount -= 1;
  1405. return NO_ERROR;
  1406. }
  1407. if ( ContextHandle->NdsRawDataBuffer != 0 &&
  1408. ContextHandle->NdsRawDataCount == 0 )
  1409. {
  1410. //
  1411. // We already have a buffer and processed all server names
  1412. // in it, and there is no more data to get.
  1413. // So free the memory used for the buffer and return
  1414. // WN_NO_MORE_ENTRIES to tell WinFile that we are done.
  1415. //
  1416. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  1417. ContextHandle->NdsRawDataBuffer = 0;
  1418. ContextHandle->NdsRawDataSize = 0;
  1419. return WN_NO_MORE_ENTRIES;
  1420. }
  1421. //
  1422. // Were done
  1423. //
  1424. return WN_NO_MORE_ENTRIES;
  1425. }
  1426. DWORD
  1427. GetTreeEntriesFromBindery(
  1428. OUT LPNW_ENUM_CONTEXT ContextHandle
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. This function is a helper routine for the function NwGetNextNdsTreeEntry.
  1433. It allocates a buffer (if needed) to cache NDS tree names returned from
  1434. calls to the bindery. Since the bindery often returns duplicates of a
  1435. NDS tree name, this function checks to see if the tree name already
  1436. exist in the buffer before adding it to it if not present.
  1437. Arguments:
  1438. ContextHandle - Used to track cached bindery information and the
  1439. current tree name pointer in the cache buffer.
  1440. Return Value:
  1441. NO_ERROR - Successfully returned a NDS tree name and cache buffer.
  1442. WN_NO_MORE_ENTRIES - No other NDS tree object past the one
  1443. specified by CH->ResumeId.
  1444. ERROR_NOT_ENOUGH_MEMORY - Function was unable to allocate a buffer.
  1445. ++*/
  1446. {
  1447. NTSTATUS ntstatus = STATUS_SUCCESS;
  1448. SERVERNAME TreeName;
  1449. LPWSTR UTreeName = NULL; //Unicode tree name
  1450. DWORD tempDataId;
  1451. WORD ObjectType;
  1452. BYTE iter;
  1453. BYTE tokenIter;
  1454. LPWSTR tokenPtr;
  1455. BOOL fAddToList;
  1456. //
  1457. // Check to see if we need to allocate a buffer for use
  1458. //
  1459. if ( ContextHandle->NdsRawDataBuffer == 0x00000000 )
  1460. {
  1461. ContextHandle->NdsRawDataId = (DWORD) ContextHandle->ResumeId;
  1462. ContextHandle->NdsRawDataSize = EIGHT_KB;
  1463. ContextHandle->NdsRawDataBuffer =
  1464. (DWORD_PTR) LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  1465. ContextHandle->NdsRawDataSize );
  1466. if ( ContextHandle->NdsRawDataBuffer == 0 )
  1467. {
  1468. KdPrint(("NWWORKSTATION: GetTreeEntriesFromBindery LocalAlloc failed %lu\n",
  1469. GetLastError()));
  1470. ContextHandle->NdsRawDataSize = 0;
  1471. ContextHandle->NdsRawDataId = (DWORD) -1;
  1472. return ERROR_NOT_ENOUGH_MEMORY;
  1473. }
  1474. }
  1475. //
  1476. // Repeatedly call bindery to fill buffer with NDS tree names until
  1477. // buffer is full.
  1478. //
  1479. while ( ntstatus == STATUS_SUCCESS )
  1480. {
  1481. RtlZeroMemory( TreeName, sizeof( TreeName ) );
  1482. tempDataId = ContextHandle->NdsRawDataId;
  1483. ntstatus = NwlibMakeNcp(
  1484. ContextHandle->TreeConnectionHandle,
  1485. FSCTL_NWR_NCP_E3H, // Bindery function
  1486. 58, // Max request packet size
  1487. 59, // Max response packet size
  1488. "bdwp|dwc", // Format string
  1489. 0x37, // Scan bindery object
  1490. ContextHandle->NdsRawDataId, // Previous ID
  1491. 0x278, // Directory server object
  1492. "*", // Wildcard to match all
  1493. &ContextHandle->NdsRawDataId, // Current ID
  1494. &ObjectType, // Ignore
  1495. TreeName // Currently returned NDS tree
  1496. );
  1497. //
  1498. // We got a tree name, clean it up (i.e. get rid of underscores ),
  1499. // and add it to buffer if unique.
  1500. //
  1501. if ( ntstatus == STATUS_SUCCESS )
  1502. {
  1503. iter = 31;
  1504. while ( TreeName[iter] == '_' && iter > 0 )
  1505. {
  1506. iter--;
  1507. }
  1508. TreeName[iter + 1] = '\0';
  1509. //
  1510. // Convert tree name to a UNICODE string and proccess it,
  1511. // else just skip it and move on to the next tree name.
  1512. //
  1513. if ( NwConvertToUnicode( &UTreeName, TreeName ) )
  1514. {
  1515. tokenPtr = (LPWSTR) ContextHandle->NdsRawDataBuffer;
  1516. tokenIter = 0;
  1517. fAddToList = TRUE;
  1518. //
  1519. // Walk through buffer to see if the tree name already exists.
  1520. //
  1521. while ( tokenIter < ContextHandle->NdsRawDataCount )
  1522. {
  1523. if ( !wcscmp( tokenPtr, UTreeName ) )
  1524. {
  1525. fAddToList = FALSE;
  1526. }
  1527. tokenPtr = tokenPtr + wcslen( tokenPtr ) + 1;
  1528. tokenIter++;
  1529. }
  1530. //
  1531. // Add the new tree name to end of buffer if needed.
  1532. //
  1533. if ( fAddToList )
  1534. {
  1535. DWORD BytesNeededToAddTreeName = (wcslen(UTreeName)+1) * sizeof(WCHAR);
  1536. DWORD NumberOfBytesAvailable =(DWORD) ( ContextHandle->NdsRawDataBuffer +
  1537. ContextHandle->NdsRawDataSize -
  1538. (DWORD_PTR) tokenPtr );
  1539. if ( BytesNeededToAddTreeName < NumberOfBytesAvailable )
  1540. {
  1541. wcscpy( tokenPtr, UTreeName );
  1542. ContextHandle->NdsRawDataCount += 1;
  1543. }
  1544. else
  1545. {
  1546. ContextHandle->NdsRawDataId = tempDataId;
  1547. ntstatus = ERROR_NOT_ENOUGH_MEMORY;
  1548. }
  1549. }
  1550. (void) LocalFree((HLOCAL) UTreeName);
  1551. }
  1552. }
  1553. }
  1554. //
  1555. // We are done filling buffer, and there are no more tree names
  1556. // to request. Set id to indicate last value.
  1557. //
  1558. if ( ntstatus == STATUS_NO_MORE_ENTRIES )
  1559. {
  1560. ContextHandle->NdsRawDataId = (DWORD) -1;
  1561. ntstatus = STATUS_SUCCESS;
  1562. }
  1563. //
  1564. // We are done because the buffer is full. So we return NO_ERROR to
  1565. // indicate completion, and leave ContextHandle->NdsRawDataId as is
  1566. // to indicate where we left off.
  1567. //
  1568. if ( ntstatus == ERROR_NOT_ENOUGH_MEMORY )
  1569. {
  1570. ntstatus = STATUS_SUCCESS;
  1571. }
  1572. if ( ContextHandle->NdsRawDataCount == 0 )
  1573. {
  1574. if ( ContextHandle->NdsRawDataBuffer )
  1575. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  1576. ContextHandle->NdsRawDataBuffer = 0;
  1577. ContextHandle->NdsRawDataSize = 0;
  1578. ContextHandle->NdsRawDataId = (DWORD) -1;
  1579. return WN_NO_MORE_ENTRIES;
  1580. }
  1581. if ( ContextHandle->NdsRawDataCount > 0 )
  1582. {
  1583. //
  1584. // Set ResumeId to point to the first entry in buffer
  1585. // and have NdsRawDataCount set to the number
  1586. // of tree entries left in buffer (ie. substract 1)
  1587. //
  1588. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer;
  1589. ContextHandle->NdsRawDataCount -= 1;
  1590. return NO_ERROR;
  1591. }
  1592. if ( ContextHandle->NdsRawDataBuffer )
  1593. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  1594. ContextHandle->NdsRawDataBuffer = 0;
  1595. ContextHandle->NdsRawDataSize = 0;
  1596. ContextHandle->NdsRawDataId = (DWORD) -1;
  1597. return NwMapStatus( ntstatus );
  1598. }
  1599. DWORD
  1600. NwGetNextNdsTreeEntry(
  1601. OUT LPNW_ENUM_CONTEXT ContextHandle
  1602. )
  1603. /*++
  1604. Routine Description:
  1605. This function uses an opened handle to the preferred server to
  1606. scan it bindery for all NDS tree objects.
  1607. Arguments:
  1608. ContextHandle - Receives the name of the returned NDS tree object
  1609. given the current preferred server connection and CH->ResumeId.
  1610. Return Value:
  1611. NO_ERROR - Successfully returned a NDS tree name.
  1612. WN_NO_MORE_ENTRIES - No other NDS tree objects past the one
  1613. specified by CH->ResumeId exist.
  1614. --*/
  1615. {
  1616. #if DBG
  1617. IF_DEBUG(ENUM) {
  1618. KdPrint(("NWWORKSTATION: NwGetNextNdsTreeEntry ResumeId %lu\n",
  1619. ContextHandle->ResumeId));
  1620. }
  1621. #endif
  1622. if ( ContextHandle->ResumeId == (DWORD_PTR) -1 &&
  1623. ContextHandle->NdsRawDataBuffer == 0 &&
  1624. ContextHandle->NdsRawDataCount == 0 )
  1625. {
  1626. //
  1627. // Fill the buffer and point ResumeId to the last
  1628. // tree entry name in it. NdsRawDataCount will be
  1629. // set to one less than the number of tree names in buffer.
  1630. //
  1631. return GetTreeEntriesFromBindery( ContextHandle );
  1632. }
  1633. if ( ContextHandle->NdsRawDataBuffer != 0 &&
  1634. ContextHandle->NdsRawDataCount > 0 )
  1635. {
  1636. //
  1637. // Move ResumeId to point to the next entry in the buffer
  1638. // and decrement the NdsRawDataCount by one. Watch for case
  1639. // where we backed up to -1.
  1640. //
  1641. if (ContextHandle->ResumeId == (DWORD_PTR) -1) {
  1642. //
  1643. // Reset to start of buffer.
  1644. //
  1645. ContextHandle->ResumeId = ContextHandle->NdsRawDataBuffer;
  1646. }
  1647. else {
  1648. //
  1649. // Move ResumeId to point to the next entry in the buffer
  1650. // and decrement the NdsRawDataCount by one
  1651. //
  1652. ContextHandle->ResumeId =
  1653. ContextHandle->ResumeId +
  1654. ( ( wcslen( (LPWSTR) ContextHandle->ResumeId ) + 1 ) *
  1655. sizeof(WCHAR) );
  1656. }
  1657. ContextHandle->NdsRawDataCount -= 1;
  1658. return NO_ERROR;
  1659. }
  1660. if ( ContextHandle->NdsRawDataBuffer != 0 &&
  1661. ContextHandle->NdsRawDataCount == 0 &&
  1662. ContextHandle->NdsRawDataId != (DWORD) -1 )
  1663. {
  1664. //
  1665. // We already have a buffer and processed all tree names
  1666. // in it, and there is more data in the bindery to get.
  1667. // So go get it and point ResumeId to the last tree
  1668. // entry name in the buffer and set NdsRawDataCount to
  1669. // one less than the number of tree names in buffer.
  1670. //
  1671. return GetTreeEntriesFromBindery( ContextHandle );
  1672. }
  1673. if ( ContextHandle->NdsRawDataBuffer != 0 &&
  1674. ContextHandle->NdsRawDataCount == 0 &&
  1675. ContextHandle->NdsRawDataId == (DWORD) -1 )
  1676. {
  1677. //
  1678. // We already have a buffer and processed all tree names
  1679. // in it, and there is no more data in the bindery to get.
  1680. // So free the memory used for the buffer and return
  1681. // WN_NO_MORE_ENTRIES to tell WinFile that we are done.
  1682. //
  1683. (void) LocalFree( (HLOCAL) ContextHandle->NdsRawDataBuffer );
  1684. ContextHandle->NdsRawDataBuffer = 0;
  1685. ContextHandle->NdsRawDataSize = 0;
  1686. return WN_NO_MORE_ENTRIES;
  1687. }
  1688. //
  1689. // We should never hit this area!
  1690. //
  1691. return WN_NO_MORE_ENTRIES;
  1692. }
  1693. DWORD
  1694. NwGetNextVolumeEntry(
  1695. IN HANDLE ServerConnection,
  1696. IN DWORD NextVolumeNumber,
  1697. OUT LPSTR VolumeName
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. This function lists the volumes on the server specified by
  1702. an opened tree connection handle to the server.
  1703. Arguments:
  1704. ServerConnection - Supplies the tree connection handle to the
  1705. server to enumerate volumes from.
  1706. NextVolumeNumber - Supplies the volume number which to look
  1707. up the name.
  1708. VolumeName - Receives the name of the volume associated with
  1709. NextVolumeNumber.
  1710. Return Value:
  1711. NO_ERROR - Successfully gotten the volume name.
  1712. WN_NO_MORE_ENTRIES - No other volume name associated with the
  1713. specified volume number.
  1714. --*/
  1715. {
  1716. NTSTATUS ntstatus;
  1717. #if DBG
  1718. IF_DEBUG(ENUM) {
  1719. KdPrint(("NWWORKSTATION: NwGetNextVolumeEntry volume number %lu\n",
  1720. NextVolumeNumber));
  1721. }
  1722. #endif
  1723. ntstatus = NwlibMakeNcp(
  1724. ServerConnection,
  1725. FSCTL_NWR_NCP_E2H, // Directory function
  1726. 4, // Max request packet size
  1727. 19, // Max response packet size
  1728. "bb|p", // Format string
  1729. 0x6, // Get volume name
  1730. (BYTE) NextVolumeNumber, // Previous ID
  1731. VolumeName // Currently returned server
  1732. );
  1733. return NwMapStatus(ntstatus);
  1734. }
  1735. DWORD
  1736. NwRdrLogonUser(
  1737. IN PLUID LogonId,
  1738. IN LPWSTR UserName,
  1739. IN DWORD UserNameSize,
  1740. IN LPWSTR Password OPTIONAL,
  1741. IN DWORD PasswordSize,
  1742. IN LPWSTR PreferredServer OPTIONAL,
  1743. IN DWORD PreferredServerSize,
  1744. IN LPWSTR NdsPreferredServer OPTIONAL,
  1745. IN DWORD NdsPreferredServerSize,
  1746. IN DWORD PrintOption
  1747. )
  1748. /*++
  1749. Routine Description:
  1750. This function tells the redirector the user logon credential.
  1751. Arguments:
  1752. UserName - Supplies the user name.
  1753. UserNameSize - Supplies the size in bytes of the user name string without
  1754. the NULL terminator.
  1755. Password - Supplies the password.
  1756. PasswordSize - Supplies the size in bytes of the password string without
  1757. the NULL terminator.
  1758. PreferredServer - Supplies the preferred server name.
  1759. PreferredServerSize - Supplies the size in bytes of the preferred server
  1760. string without the NULL terminator.
  1761. Return Value:
  1762. NO_ERROR or reason for failure.
  1763. --*/
  1764. {
  1765. DWORD status;
  1766. PNWR_REQUEST_PACKET Rrp; // Redirector request packet
  1767. DWORD RrpSize = sizeof(NWR_REQUEST_PACKET) +
  1768. UserNameSize +
  1769. PasswordSize +
  1770. PreferredServerSize;
  1771. LPBYTE Dest;
  1772. BYTE lpReplicaAddress[sizeof(TDI_ADDRESS_IPX)];
  1773. DWORD ReplicaAddressSize = 0;
  1774. #if DBG
  1775. IF_DEBUG(LOGON) {
  1776. BYTE PW[128];
  1777. RtlZeroMemory(PW, sizeof(PW));
  1778. if (PasswordSize > (sizeof(PW) - 1)) {
  1779. memcpy(PW, Password, sizeof(PW) - 1);
  1780. }
  1781. else {
  1782. memcpy(PW, Password, PasswordSize);
  1783. }
  1784. KdPrint(("NWWORKSTATION: NwRdrLogonUser: UserName %ws\n", UserName));
  1785. KdPrint((" Password %ws\n", PW));
  1786. if ( PreferredServer )
  1787. KdPrint((" Server %ws\n", PreferredServer ));
  1788. }
  1789. #endif
  1790. if ( PreferredServer &&
  1791. PreferredServer[0] == TREECHAR &&
  1792. PreferredServer[1] )
  1793. {
  1794. WCHAR TreeName[MAX_NDS_NAME_CHARS + 1];
  1795. LPWSTR lpTemp;
  1796. //
  1797. // Find the nearest dir server for the tree that the user wants to
  1798. // connect to.
  1799. //
  1800. // Citrix Terminal Server Merge
  1801. // 12/09/96 cjc PreferredServer also includes organizational units -
  1802. // not just the tree name so the size of it can be
  1803. // > MAX_NDS_TREE_NAME_LEN and when it is, the wcscpy
  1804. // below overwrites other stack data and causes errors
  1805. // during NW logins.
  1806. if ( PreferredServerSize > (MAX_NDS_TREE_NAME_LEN*sizeof(WCHAR)) ) {
  1807. memcpy(TreeName, PreferredServer+1,
  1808. (MAX_NDS_TREE_NAME_LEN*sizeof(WCHAR)) );
  1809. TreeName[MAX_NDS_TREE_NAME_LEN] = L'\0';
  1810. }
  1811. else {
  1812. wcscpy( TreeName, PreferredServer + 1 );
  1813. }
  1814. lpTemp = wcschr( TreeName, L'\\' );
  1815. if (lpTemp) {
  1816. lpTemp[0] = L'\0';
  1817. }
  1818. if (NdsPreferredServerSize != 0) {
  1819. KdPrint(("NWWORKSTATION: NdsPreferredServer: %ws\n", NdsPreferredServer));
  1820. GetPreferredServerAddress( NdsPreferredServer/*L"red_41b"*/,
  1821. &ReplicaAddressSize,
  1822. lpReplicaAddress );
  1823. } else {
  1824. GetNearestDirServer( TreeName,
  1825. &ReplicaAddressSize,
  1826. lpReplicaAddress );
  1827. }
  1828. RrpSize += ReplicaAddressSize;
  1829. }
  1830. if ( PreferredServer &&
  1831. PreferredServer[0] == TREECHAR &&
  1832. !PreferredServer[1] )
  1833. {
  1834. PreferredServerSize = 0;
  1835. }
  1836. //
  1837. // Allocate the request packet
  1838. //
  1839. if ((Rrp = (PVOID) LocalAlloc(
  1840. LMEM_ZEROINIT,
  1841. RrpSize
  1842. )) == NULL) {
  1843. KdPrint(("NWWORKSTATION: NwRdrLogonUser LocalAlloc failed %lu\n",
  1844. GetLastError()));
  1845. return ERROR_NOT_ENOUGH_MEMORY;
  1846. }
  1847. //
  1848. // Tell the redirector the user logon credential.
  1849. //
  1850. Rrp->Version = REQUEST_PACKET_VERSION;
  1851. RtlCopyLuid(&(Rrp->Parameters.Logon.LogonId), LogonId);
  1852. #if DBG
  1853. IF_DEBUG(LOGON) {
  1854. KdPrint(("NWWORKSTATION: NwRdrLogonUser passing to Rdr logon ID %lu %lu\n",
  1855. *LogonId, *((PULONG) ((DWORD_PTR) LogonId + sizeof(ULONG)))));
  1856. }
  1857. #endif
  1858. Rrp->Parameters.Logon.UserNameLength = UserNameSize;
  1859. Rrp->Parameters.Logon.PasswordLength = PasswordSize;
  1860. Rrp->Parameters.Logon.ServerNameLength = PreferredServerSize;
  1861. Rrp->Parameters.Logon.ReplicaAddrLength = ReplicaAddressSize;
  1862. Rrp->Parameters.Logon.PrintOption = PrintOption;
  1863. memcpy(Rrp->Parameters.Logon.UserName, UserName, UserNameSize);
  1864. Dest = (LPBYTE) ((DWORD_PTR) Rrp->Parameters.Logon.UserName + UserNameSize);
  1865. if (PasswordSize > 0)
  1866. {
  1867. memcpy(Dest, Password, PasswordSize);
  1868. Dest = (LPBYTE) ((DWORD_PTR) Dest + PasswordSize);
  1869. }
  1870. if (PreferredServerSize > 0)
  1871. {
  1872. memcpy(Dest, PreferredServer, PreferredServerSize);
  1873. if (ReplicaAddressSize > 0)
  1874. {
  1875. Dest = (LPBYTE) ((DWORD_PTR) Dest + PreferredServerSize);
  1876. memcpy(Dest, lpReplicaAddress, ReplicaAddressSize);
  1877. }
  1878. }
  1879. status = NwRedirFsControl(
  1880. RedirDeviceHandle,
  1881. FSCTL_NWR_LOGON,
  1882. Rrp,
  1883. RrpSize,
  1884. NULL, // No logon script in this release
  1885. 0,
  1886. NULL
  1887. );
  1888. RtlZeroMemory(Rrp, RrpSize); // Clear the password
  1889. (void) LocalFree((HLOCAL) Rrp);
  1890. return status;
  1891. }
  1892. VOID
  1893. NwRdrChangePassword(
  1894. IN PNWR_REQUEST_PACKET Rrp
  1895. )
  1896. /*++
  1897. Routine Description:
  1898. This function tells the redirector the new password for a user on
  1899. a particular server.
  1900. Arguments:
  1901. Rrp - Supplies the username, new password and servername.
  1902. RrpSize - Supplies the size of the request packet.
  1903. Return Value:
  1904. None.
  1905. --*/
  1906. {
  1907. //
  1908. // Tell the redirector the user new password.
  1909. //
  1910. Rrp->Version = REQUEST_PACKET_VERSION;
  1911. (void) NwRedirFsControl(
  1912. RedirDeviceHandle,
  1913. FSCTL_NWR_CHANGE_PASS,
  1914. Rrp,
  1915. sizeof(NWR_REQUEST_PACKET) +
  1916. Rrp->Parameters.ChangePass.UserNameLength +
  1917. Rrp->Parameters.ChangePass.PasswordLength +
  1918. Rrp->Parameters.ChangePass.ServerNameLength,
  1919. NULL,
  1920. 0,
  1921. NULL
  1922. );
  1923. }
  1924. DWORD
  1925. NwRdrSetInfo(
  1926. IN DWORD PrintOption,
  1927. IN DWORD PacketBurstSize,
  1928. IN LPWSTR PreferredServer OPTIONAL,
  1929. IN DWORD PreferredServerSize,
  1930. IN LPWSTR ProviderName OPTIONAL,
  1931. IN DWORD ProviderNameSize
  1932. )
  1933. /*++
  1934. Routine Description:
  1935. This function passes some workstation configuration and current user's
  1936. preference to the redirector. This includes the network provider name, the
  1937. packet burst size, the user's selected preferred server and print option.
  1938. Arguments:
  1939. PrintOption - The current user's print option
  1940. PacketBurstSize - The packet burst size stored in the registry
  1941. PreferredServer - The preferred server the current user selected
  1942. PreferredServerSize - Supplies the size in bytes of the preferred server
  1943. string without the NULL terminator.
  1944. ProviderName - Supplies the provider name.
  1945. ProviderNameSize - Supplies the size in bytes of the provider name
  1946. string without the NULL terminator.
  1947. Return Value:
  1948. NO_ERROR or reason for failure.
  1949. --*/
  1950. {
  1951. DWORD status;
  1952. PNWR_REQUEST_PACKET Rrp; // Redirector request packet
  1953. DWORD RrpSize = sizeof(NWR_REQUEST_PACKET) +
  1954. PreferredServerSize +
  1955. ProviderNameSize;
  1956. LPBYTE Dest;
  1957. BOOL Impersonate = FALSE;
  1958. //
  1959. // Allocate the request packet
  1960. //
  1961. if ((Rrp = (PVOID) LocalAlloc(
  1962. LMEM_ZEROINIT,
  1963. RrpSize
  1964. )) == NULL) {
  1965. KdPrint(("NWWORKSTATION: NwRdrSetInfo LocalAlloc failed %lu\n",
  1966. GetLastError()));
  1967. return ERROR_NOT_ENOUGH_MEMORY;
  1968. }
  1969. Rrp->Version = REQUEST_PACKET_VERSION;
  1970. Rrp->Parameters.SetInfo.PrintOption = PrintOption;
  1971. Rrp->Parameters.SetInfo.MaximumBurstSize = PacketBurstSize;
  1972. Rrp->Parameters.SetInfo.PreferredServerLength = PreferredServerSize;
  1973. Rrp->Parameters.SetInfo.ProviderNameLength = ProviderNameSize;
  1974. if (ProviderNameSize > 0) {
  1975. memcpy( Rrp->Parameters.SetInfo.PreferredServer,
  1976. PreferredServer, PreferredServerSize);
  1977. }
  1978. Dest = (LPBYTE) ((DWORD_PTR) Rrp->Parameters.SetInfo.PreferredServer
  1979. + PreferredServerSize);
  1980. if (ProviderNameSize > 0) {
  1981. memcpy(Dest, ProviderName, ProviderNameSize);
  1982. }
  1983. /* --- Multi-user change
  1984. * For print options
  1985. * It's OK if it doesn't work
  1986. */
  1987. if ((status = NwImpersonateClient()) == NO_ERROR)
  1988. {
  1989. Impersonate = TRUE;
  1990. }
  1991. status = NwRedirFsControl(
  1992. RedirDeviceHandle,
  1993. FSCTL_NWR_SET_INFO,
  1994. Rrp,
  1995. RrpSize,
  1996. NULL,
  1997. 0,
  1998. NULL
  1999. );
  2000. if ( Impersonate ) {
  2001. (void) NwRevertToSelf() ;
  2002. }
  2003. (void) LocalFree((HLOCAL) Rrp);
  2004. if ( status != NO_ERROR )
  2005. {
  2006. KdPrint(("NwRedirFsControl: FSCTL_NWR_SET_INFO failed with %d\n",
  2007. status ));
  2008. }
  2009. return status;
  2010. }
  2011. DWORD
  2012. NwRdrLogoffUser(
  2013. IN PLUID LogonId
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. This function asks the redirector to log off the interactive user.
  2018. Arguments:
  2019. None.
  2020. Return Value:
  2021. NO_ERROR or reason for failure.
  2022. --*/
  2023. {
  2024. DWORD status;
  2025. NWR_REQUEST_PACKET Rrp; // Redirector request packet
  2026. //
  2027. // Tell the redirector to logoff user.
  2028. //
  2029. Rrp.Version = REQUEST_PACKET_VERSION;
  2030. RtlCopyLuid(&Rrp.Parameters.Logoff.LogonId, LogonId);
  2031. status = NwRedirFsControl(
  2032. RedirDeviceHandle,
  2033. FSCTL_NWR_LOGOFF,
  2034. &Rrp,
  2035. sizeof(NWR_REQUEST_PACKET),
  2036. NULL,
  2037. 0,
  2038. NULL
  2039. );
  2040. return status;
  2041. }
  2042. DWORD
  2043. NwConnectToServer(
  2044. IN LPWSTR ServerName
  2045. )
  2046. /*++
  2047. Routine Description:
  2048. This function opens a handle to \Device\Nwrdr\ServerName, given
  2049. ServerName, and then closes the handle if the open was successful.
  2050. It is to validate that the current user credential can access
  2051. the server.
  2052. Arguments:
  2053. ServerName - Supplies the name of the server to validate the
  2054. user credential.
  2055. Return Value:
  2056. NO_ERROR or reason for failure.
  2057. --*/
  2058. {
  2059. DWORD status;
  2060. UNICODE_STRING ServerStr;
  2061. HANDLE ServerHandle;
  2062. ServerStr.MaximumLength = (wcslen(ServerName) + 2) *
  2063. sizeof(WCHAR) + // \ServerName0
  2064. RedirDeviceName.Length; // \Device\Nwrdr
  2065. if ((ServerStr.Buffer = (PWSTR) LocalAlloc(
  2066. LMEM_ZEROINIT,
  2067. (UINT) ServerStr.MaximumLength
  2068. )) == NULL) {
  2069. return ERROR_NOT_ENOUGH_MEMORY;
  2070. }
  2071. //
  2072. // Copy \Device\NwRdr
  2073. //
  2074. RtlCopyUnicodeString(&ServerStr, &RedirDeviceName);
  2075. //
  2076. // Concatenate \ServerName
  2077. //
  2078. wcscat(ServerStr.Buffer, L"\\");
  2079. ServerStr.Length += sizeof(WCHAR);
  2080. wcscat(ServerStr.Buffer, ServerName);
  2081. ServerStr.Length += (USHORT) (wcslen(ServerName) * sizeof(WCHAR));
  2082. status = NwOpenCreateConnection(
  2083. &ServerStr,
  2084. NULL,
  2085. NULL,
  2086. ServerName,
  2087. SYNCHRONIZE | FILE_WRITE_DATA,
  2088. FILE_OPEN,
  2089. FILE_SYNCHRONOUS_IO_NONALERT,
  2090. RESOURCETYPE_DISK,
  2091. &ServerHandle,
  2092. NULL
  2093. );
  2094. if (status == ERROR_FILE_NOT_FOUND) {
  2095. status = ERROR_BAD_NETPATH;
  2096. }
  2097. (void) LocalFree((HLOCAL) ServerStr.Buffer);
  2098. if (status == NO_ERROR || status == NW_PASSWORD_HAS_EXPIRED) {
  2099. (void) NtClose(ServerHandle);
  2100. }
  2101. return status;
  2102. }
  2103. DWORD
  2104. NWPGetConnectionStatus(
  2105. IN LPWSTR pszRemoteName,
  2106. IN OUT PDWORD_PTR ResumeKey,
  2107. OUT LPBYTE Buffer,
  2108. IN DWORD BufferSize,
  2109. OUT PDWORD BytesNeeded,
  2110. OUT PDWORD EntriesRead
  2111. )
  2112. {
  2113. NTSTATUS ntstatus = STATUS_SUCCESS;
  2114. HANDLE handleRdr = NULL;
  2115. OBJECT_ATTRIBUTES ObjectAttributes;
  2116. IO_STATUS_BLOCK IoStatusBlock;
  2117. UNICODE_STRING uRdrName;
  2118. WCHAR RdrPrefix[] = L"\\Device\\NwRdr\\*";
  2119. PNWR_REQUEST_PACKET RequestPacket = NULL;
  2120. DWORD RequestPacketSize = 0;
  2121. DWORD dwRemoteNameLen = 0;
  2122. //
  2123. // Set up the object attributes.
  2124. //
  2125. RtlInitUnicodeString( &uRdrName, RdrPrefix );
  2126. InitializeObjectAttributes( &ObjectAttributes,
  2127. &uRdrName,
  2128. OBJ_CASE_INSENSITIVE,
  2129. NULL,
  2130. NULL );
  2131. ntstatus = NtOpenFile( &handleRdr,
  2132. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  2133. &ObjectAttributes,
  2134. &IoStatusBlock,
  2135. FILE_SHARE_VALID_FLAGS,
  2136. FILE_SYNCHRONOUS_IO_NONALERT );
  2137. if ( !NT_SUCCESS(ntstatus) )
  2138. goto CleanExit;
  2139. dwRemoteNameLen = pszRemoteName? wcslen(pszRemoteName)*sizeof(WCHAR) : 0;
  2140. RequestPacketSize = sizeof( NWR_REQUEST_PACKET ) + dwRemoteNameLen;
  2141. RequestPacket = (PNWR_REQUEST_PACKET) LocalAlloc( LMEM_ZEROINIT,
  2142. RequestPacketSize );
  2143. if ( RequestPacket == NULL )
  2144. {
  2145. ntstatus = STATUS_NO_MEMORY;
  2146. goto CleanExit;
  2147. }
  2148. //
  2149. // Fill out the request packet for FSCTL_NWR_GET_CONN_STATUS.
  2150. //
  2151. RequestPacket->Parameters.GetConnStatus.ResumeKey = *ResumeKey;
  2152. RequestPacket->Version = REQUEST_PACKET_VERSION;
  2153. RequestPacket->Parameters.GetConnStatus.ConnectionNameLength = dwRemoteNameLen;
  2154. RtlCopyMemory( &(RequestPacket->Parameters.GetConnStatus.ConnectionName[0]),
  2155. pszRemoteName,
  2156. dwRemoteNameLen );
  2157. ntstatus = NtFsControlFile( handleRdr,
  2158. NULL,
  2159. NULL,
  2160. NULL,
  2161. &IoStatusBlock,
  2162. FSCTL_NWR_GET_CONN_STATUS,
  2163. (PVOID) RequestPacket,
  2164. RequestPacketSize,
  2165. (PVOID) Buffer,
  2166. BufferSize );
  2167. if ( NT_SUCCESS( ntstatus ))
  2168. ntstatus = IoStatusBlock.Status;
  2169. *EntriesRead = RequestPacket->Parameters.GetConnStatus.EntriesReturned;
  2170. *ResumeKey = RequestPacket->Parameters.GetConnStatus.ResumeKey;
  2171. *BytesNeeded = RequestPacket->Parameters.GetConnStatus.BytesNeeded;
  2172. CleanExit:
  2173. if ( handleRdr != NULL )
  2174. NtClose( handleRdr );
  2175. if ( RequestPacket != NULL )
  2176. LocalFree( RequestPacket );
  2177. return RtlNtStatusToDosError( ntstatus );
  2178. }
  2179. DWORD
  2180. NwGetConnectionStatus(
  2181. IN LPWSTR pszRemoteName,
  2182. OUT PDWORD_PTR ResumeKey,
  2183. OUT LPBYTE *Buffer,
  2184. OUT PDWORD EntriesRead
  2185. )
  2186. {
  2187. DWORD err = NO_ERROR;
  2188. DWORD dwBytesNeeded = 0;
  2189. DWORD dwBufferSize = TWO_KB;
  2190. *Buffer = NULL;
  2191. *EntriesRead = 0;
  2192. do {
  2193. *Buffer = (LPBYTE) LocalAlloc( LMEM_ZEROINIT, dwBufferSize );
  2194. if ( *Buffer == NULL )
  2195. return ERROR_NOT_ENOUGH_MEMORY;
  2196. err = NWPGetConnectionStatus( pszRemoteName,
  2197. ResumeKey,
  2198. *Buffer,
  2199. dwBufferSize,
  2200. &dwBytesNeeded,
  2201. EntriesRead );
  2202. if ( err == ERROR_INSUFFICIENT_BUFFER )
  2203. {
  2204. dwBufferSize = dwBytesNeeded + EXTRA_BYTES;
  2205. LocalFree( *Buffer );
  2206. *Buffer = NULL;
  2207. }
  2208. } while ( err == ERROR_INSUFFICIENT_BUFFER );
  2209. if ( err == ERROR_INVALID_PARAMETER ) // not attached
  2210. {
  2211. err = NO_ERROR;
  2212. *EntriesRead = 0;
  2213. }
  2214. return err;
  2215. }
  2216. VOID
  2217. GetNearestDirServer(
  2218. IN LPWSTR TreeName,
  2219. OUT LPDWORD lpdwReplicaAddressSize,
  2220. OUT LPBYTE lpReplicaAddress
  2221. )
  2222. {
  2223. WCHAR Buffer[BUFFSIZE];
  2224. PWSAQUERYSETW Query = (PWSAQUERYSETW)Buffer;
  2225. HANDLE hRnr;
  2226. DWORD dwQuerySize = BUFFSIZE;
  2227. GUID gdService = SVCID_NETWARE(0x278);
  2228. WSADATA wsaData;
  2229. WCHAR ServiceInstanceName[] = L"*";
  2230. WSAStartup(MAKEWORD(1, 1), &wsaData);
  2231. memset(Query, 0, sizeof(*Query));
  2232. //
  2233. // putting a "*" in the lpszServiceInstanceName causes
  2234. // the query to look for all server instances. Putting a
  2235. // specific name in here will search only for instance of
  2236. // that name. If you have a specific name to look for,
  2237. // put a pointer to the name here.
  2238. //
  2239. Query->lpszServiceInstanceName = ServiceInstanceName;
  2240. Query->dwNameSpace = NS_SAP;
  2241. Query->dwSize = sizeof(*Query);
  2242. Query->lpServiceClassId = &gdService;
  2243. //
  2244. // Find the servers. The flags indicate:
  2245. // LUP_NEAREST: look for nearest servers
  2246. // LUP_DEEP : if none are found on the local segement look
  2247. // for server using a general query
  2248. // LUP_RETURN_NAME: return the name
  2249. // LUP_RETURN_ADDR: return the server address
  2250. //
  2251. // if only servers on the local segment are acceptable, omit
  2252. // setting LUP_DEEP
  2253. //
  2254. if( WSALookupServiceBegin( Query,
  2255. LUP_NEAREST |
  2256. LUP_DEEP |
  2257. LUP_RETURN_NAME |
  2258. LUP_RETURN_ADDR,
  2259. &hRnr ) == SOCKET_ERROR )
  2260. {
  2261. //
  2262. // Something went wrong, return no address. The redirector will
  2263. // have to come up with a dir server on its own.
  2264. //
  2265. *lpdwReplicaAddressSize = 0;
  2266. return ;
  2267. }
  2268. else
  2269. {
  2270. //
  2271. // Ready to look for one of them ...
  2272. //
  2273. Query->dwSize = BUFFSIZE;
  2274. while( WSALookupServiceNext( hRnr,
  2275. 0,
  2276. &dwQuerySize,
  2277. Query ) == NO_ERROR )
  2278. {
  2279. //
  2280. // Found a dir server, now see if it is a server for the NDS tree
  2281. // TreeName.
  2282. //
  2283. if ( NwpCompareTreeNames( Query->lpszServiceInstanceName,
  2284. TreeName ) )
  2285. {
  2286. *lpdwReplicaAddressSize = sizeof(TDI_ADDRESS_IPX);
  2287. memcpy( lpReplicaAddress,
  2288. Query->lpcsaBuffer->RemoteAddr.lpSockaddr->sa_data,
  2289. sizeof(TDI_ADDRESS_IPX) );
  2290. WSALookupServiceEnd(hRnr);
  2291. return ;
  2292. }
  2293. }
  2294. //
  2295. // Could not find a dir server, return no address. The redirector will
  2296. // have to come up with a dir server on its own.
  2297. //
  2298. *lpdwReplicaAddressSize = 0;
  2299. WSALookupServiceEnd(hRnr);
  2300. }
  2301. }
  2302. BOOL
  2303. NwpCompareTreeNames(
  2304. LPWSTR lpServiceInstanceName,
  2305. LPWSTR lpTreeName
  2306. )
  2307. {
  2308. DWORD iter = 31;
  2309. while ( lpServiceInstanceName[iter] == '_' && iter > 0 )
  2310. {
  2311. iter--;
  2312. }
  2313. lpServiceInstanceName[iter + 1] = '\0';
  2314. if ( !_wcsicmp( lpServiceInstanceName, lpTreeName ) )
  2315. {
  2316. return TRUE;
  2317. }
  2318. return FALSE;
  2319. }
  2320. #define SIZE_OF_STATISTICS_TOKEN_INFORMATION \
  2321. sizeof( TOKEN_STATISTICS )
  2322. VOID
  2323. GetLuid(
  2324. IN OUT PLUID plogonid
  2325. )
  2326. /*++
  2327. Routine Description:
  2328. Returns an LUID
  2329. Arguments:
  2330. none
  2331. Return Value:
  2332. LUID
  2333. --*/
  2334. {
  2335. HANDLE TokenHandle;
  2336. UCHAR TokenInformation[ SIZE_OF_STATISTICS_TOKEN_INFORMATION ];
  2337. ULONG ReturnLength;
  2338. LUID NullId = { 0, 0 };
  2339. // We can use OpenThreadToken because this server thread
  2340. // is impersonating a client
  2341. if ( !OpenThreadToken( GetCurrentThread(),
  2342. TOKEN_READ,
  2343. TRUE, /* Open as self */
  2344. &TokenHandle ))
  2345. {
  2346. #if DBG
  2347. KdPrint(("GetLuid: OpenThreadToken failed: Error %d\n",
  2348. GetLastError()));
  2349. #endif
  2350. *plogonid = NullId;
  2351. return;
  2352. }
  2353. // notice that we've allocated enough space for the
  2354. // TokenInformation structure. so if we fail, we
  2355. // return a NULL pointer indicating failure
  2356. if ( !GetTokenInformation( TokenHandle,
  2357. TokenStatistics,
  2358. TokenInformation,
  2359. sizeof( TokenInformation ),
  2360. &ReturnLength ))
  2361. {
  2362. #if DBG
  2363. KdPrint(("GetLuid: GetTokenInformation failed: Error %d\n",
  2364. GetLastError()));
  2365. #endif
  2366. *plogonid = NullId;
  2367. return;
  2368. }
  2369. CloseHandle( TokenHandle );
  2370. *plogonid = ( ((PTOKEN_STATISTICS)TokenInformation)->AuthenticationId );
  2371. return;
  2372. }
  2373. DWORD
  2374. NwCloseAllConnections(
  2375. VOID
  2376. )
  2377. /*++
  2378. Routine Description:
  2379. This routine closes all connections. It is used when stopping the
  2380. redirector.
  2381. Arguments:
  2382. None.
  2383. Return Value:
  2384. NO_ERROR or error
  2385. --*/
  2386. {
  2387. NWR_REQUEST_PACKET Rrp;
  2388. DWORD error;
  2389. Rrp.Version = REQUEST_PACKET_VERSION;
  2390. error = NwRedirFsControl(
  2391. RedirDeviceHandle,
  2392. FSCTL_NWR_CLOSEALL,
  2393. &Rrp,
  2394. sizeof(NWR_REQUEST_PACKET),
  2395. NULL,
  2396. 0,
  2397. NULL
  2398. );
  2399. return error;
  2400. }
  2401. VOID
  2402. GetPreferredServerAddress(
  2403. IN LPWSTR PreferredServerName,
  2404. OUT LPDWORD lpdwReplicaAddressSize,
  2405. OUT LPBYTE lpReplicaAddress
  2406. )
  2407. {
  2408. WCHAR Buffer[1024];
  2409. PWSAQUERYSETW Query = (PWSAQUERYSETW)Buffer;
  2410. HANDLE hRnr;
  2411. DWORD dwQuerySize = 1024;
  2412. GUID gdService = SVCID_NETWARE( 0x4 );
  2413. WSADATA wsaData;
  2414. PWCHAR ServiceInstanceName = PreferredServerName;
  2415. WSAStartup(MAKEWORD(1, 1), &wsaData);
  2416. memset(Query, 0, sizeof(*Query));
  2417. //
  2418. // putting a "*" in the lpszServiceInstanceName causes
  2419. // the query to look for all server instances. Putting a
  2420. // specific name in here will search only for instance of
  2421. // that name. If you have a specific name to look for,
  2422. // put a pointer to the name here.
  2423. //
  2424. Query->lpszServiceInstanceName = ServiceInstanceName;
  2425. Query->dwNameSpace = NS_SAP;
  2426. Query->dwSize = sizeof(*Query);
  2427. Query->lpServiceClassId = &gdService;
  2428. //
  2429. // Find the servers. The flags indicate:
  2430. // LUP_NEAREST: look for nearest servers
  2431. // LUP_DEEP : if none are found on the local segement look
  2432. // for server using a general query
  2433. // LUP_RETURN_NAME: return the name
  2434. // LUP_RETURN_ADDR: return the server address
  2435. //
  2436. // if only servers on the local segment are acceptable, omit
  2437. // setting LUP_DEEP
  2438. //
  2439. if( WSALookupServiceBeginW( Query,
  2440. // LUP_NEAREST |
  2441. LUP_DEEP |
  2442. LUP_RETURN_NAME |
  2443. LUP_RETURN_ADDR,
  2444. &hRnr ) == SOCKET_ERROR )
  2445. {
  2446. //
  2447. // Something went wrong, return no address. The redirector will
  2448. // have to come up with a dir server on its own.
  2449. //
  2450. *lpdwReplicaAddressSize = 0;
  2451. return ;
  2452. }
  2453. else
  2454. {
  2455. //
  2456. // Ready to look for one of them ...
  2457. //
  2458. Query->dwSize = 1024;
  2459. while( WSALookupServiceNextW( hRnr,
  2460. 0,
  2461. &dwQuerySize,
  2462. Query ) == NO_ERROR )
  2463. {
  2464. //
  2465. // Found a dir server, now see if it is a server for the NDS tree
  2466. // TreeName.
  2467. //
  2468. // if ( NwpCompareTreeNames( Query->lpszServiceInstanceName,
  2469. // TreeName ) )
  2470. {
  2471. *lpdwReplicaAddressSize = sizeof(TDI_ADDRESS_IPX);
  2472. memcpy( lpReplicaAddress,
  2473. Query->lpcsaBuffer->RemoteAddr.lpSockaddr->sa_data,
  2474. sizeof(TDI_ADDRESS_IPX) );
  2475. WSALookupServiceEnd(hRnr);
  2476. return ;
  2477. }
  2478. }
  2479. //
  2480. // Could not find a dir server, return no address. The redirector will
  2481. // have to come up with a dir server on its own.
  2482. //
  2483. *lpdwReplicaAddressSize = 0;
  2484. WSALookupServiceEnd(hRnr);
  2485. }
  2486. }