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.

1902 lines
49 KiB

  1. /*++
  2. Copyright (c) 1991-1992 Microsoft Corporation
  3. Module Name:
  4. useutil.c
  5. Abstract:
  6. This module contains the common utility routines for needed to
  7. implement the NetUse APIs.
  8. Author:
  9. Rita Wong (ritaw) 10-Mar-1991
  10. Revision History:
  11. --*/
  12. #include "wsutil.h"
  13. #include "wsdevice.h"
  14. #include "wsuse.h"
  15. #include "wsmain.h"
  16. #include <names.h>
  17. #include <winbasep.h>
  18. //-------------------------------------------------------------------//
  19. // //
  20. // Local function prototypes //
  21. // //
  22. //-------------------------------------------------------------------//
  23. STATIC
  24. NET_API_STATUS
  25. WsGrowUseTable(
  26. VOID
  27. );
  28. STATIC
  29. VOID
  30. WsFindLocal(
  31. IN PUSE_ENTRY UseList,
  32. IN LPTSTR Local,
  33. OUT PUSE_ENTRY *MatchedPointer,
  34. OUT PUSE_ENTRY *BackPointer
  35. );
  36. LPTSTR
  37. WsReturnSessionPath(
  38. IN LPTSTR LocalDeviceName
  39. );
  40. //-------------------------------------------------------------------//
  41. // //
  42. // Global variables //
  43. // //
  44. //-------------------------------------------------------------------//
  45. //
  46. // Redirector name in NT string format
  47. //
  48. UNICODE_STRING RedirectorDeviceName;
  49. //
  50. // Use Table
  51. //
  52. USERS_OBJECT Use;
  53. NET_API_STATUS
  54. WsInitUseStructures(
  55. VOID
  56. )
  57. /*++
  58. Routine Description:
  59. This function creates the Use Table, and initialize the NT-style string
  60. of the redirector device name.
  61. Arguments:
  62. None
  63. Return Value:
  64. NET_API_STATUS - NERR_Success or reason for failure.
  65. --*/
  66. {
  67. //
  68. // Initialize NT-style redirector device name string.
  69. //
  70. RtlInitUnicodeString(&RedirectorDeviceName, DD_NFS_DEVICE_NAME_U);
  71. //
  72. // Allocate and initialize the Use Table which is an array of logged
  73. // on user entries, with a linked list of use entries for each user.
  74. //
  75. return WsInitializeUsersObject(&Use);
  76. }
  77. VOID
  78. WsDestroyUseStructures(
  79. VOID
  80. )
  81. /*++
  82. Routine Description:
  83. This function destroys the Use Table.
  84. Arguments:
  85. None
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. DWORD i;
  91. PUSE_ENTRY UseEntry;
  92. PUSE_ENTRY PreviousEntry;
  93. //
  94. // Lock Use Table
  95. //
  96. if (! RtlAcquireResourceExclusive(&Use.TableResource, TRUE)) {
  97. return;
  98. }
  99. //
  100. // Close handles for every use entry that still exist and free the memory
  101. // allocated for the use entry.
  102. //
  103. for (i = 0; i < Use.TableSize; i++) {
  104. UseEntry = Use.Table[i].List;
  105. while (UseEntry != NULL) {
  106. (void) WsDeleteConnection(
  107. &Use.Table[i].LogonId,
  108. UseEntry->TreeConnection,
  109. USE_NOFORCE
  110. );
  111. WsDeleteSymbolicLink(
  112. UseEntry->Local,
  113. UseEntry->TreeConnectStr,
  114. NULL
  115. );
  116. UseEntry->Remote->TotalUseCount -= UseEntry->UseCount;
  117. if (UseEntry->Remote->TotalUseCount == 0) {
  118. (void) LocalFree((HLOCAL) UseEntry->Remote);
  119. }
  120. PreviousEntry = UseEntry;
  121. UseEntry = UseEntry->Next;
  122. (void) LocalFree((HLOCAL) PreviousEntry);
  123. }
  124. }
  125. RtlReleaseResource(&Use.TableResource);
  126. //
  127. // Free the array of logged on user entries, and delete the resource
  128. // created to serialize access to the array.
  129. //
  130. WsDestroyUsersObject(&Use);
  131. }
  132. NET_API_STATUS
  133. WsFindUse(
  134. IN PLUID LogonId,
  135. IN PUSE_ENTRY UseList,
  136. IN LPTSTR UseName,
  137. OUT PHANDLE TreeConnection,
  138. OUT PUSE_ENTRY *MatchedPointer,
  139. OUT PUSE_ENTRY *BackPointer OPTIONAL
  140. )
  141. /*++
  142. Routine Description:
  143. This function searches the Use Table for the specified tree connection.
  144. If the connection is found, NERR_Success is returned.
  145. If the UseName is found in the Use Table (explicit connection), a
  146. pointer to the matching use entry is returned. Otherwise, MatchedPointer
  147. is set to NULL.
  148. WARNING: This function assumes that the Use.TableResource is claimed.
  149. Arguments:
  150. LogonId - Supplies a pointer to the user's Logon Id.
  151. UseList - Supplies the use list of the user.
  152. UseName - Supplies the name of the tree connection, this is either a
  153. local device name or a UNC name.
  154. TreeConnection - Returns a handle to the found tree connection.
  155. MatchedPointer - Returns the pointer to the matching use entry. This
  156. pointer is set to NULL if the specified use is an implicit
  157. connection.
  158. BackPointer - Returns the pointer to the entry previous to the matching
  159. use entry if MatchedPointer is not NULL.
  160. Return Value:
  161. NET_API_STATUS - NERR_Success or reason for failure.
  162. --*/
  163. {
  164. PUSE_ENTRY Back;
  165. IF_DEBUG(USE) {
  166. NetpKdPrint(("[Wksta] WsFindUse: Usename is %ws\n", UseName));
  167. }
  168. //
  169. // Look for use entry depending on whether the local device name or
  170. // UNC name is specified.
  171. //
  172. if (UseName[1] != TCHAR_BACKSLASH) {
  173. //
  174. // Local device name is specified.
  175. //
  176. WsFindLocal(
  177. UseList,
  178. UseName,
  179. MatchedPointer,
  180. &Back
  181. );
  182. if (*MatchedPointer == NULL) {
  183. return NERR_UseNotFound;
  184. }
  185. else {
  186. *TreeConnection = (*MatchedPointer)->TreeConnection;
  187. if (ARGUMENT_PRESENT(BackPointer)) {
  188. *BackPointer = Back;
  189. }
  190. return NERR_Success;
  191. }
  192. }
  193. else {
  194. //
  195. // UNC name is specified, need to find matching shared resource
  196. // in use list.
  197. //
  198. WsFindUncName(
  199. UseList,
  200. UseName,
  201. MatchedPointer,
  202. &Back
  203. );
  204. if (*MatchedPointer == NULL) {
  205. NET_API_STATUS status;
  206. DWORD EnumConnectionHint = 0; // Hint size from redirector
  207. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  208. PLMR_CONNECTION_INFO_0 UncList; // List of information on UNC
  209. // connections
  210. PLMR_CONNECTION_INFO_0 SavePtr;
  211. DWORD i;
  212. BOOL FoundImplicitEntry = FALSE;
  213. DWORD UseNameLength = STRLEN(UseName);
  214. UNICODE_STRING TreeConnectStr;
  215. IF_DEBUG(USE) {
  216. NetpKdPrint(("[Wksta] WsFindUse: No explicit entry\n"));
  217. }
  218. //
  219. // Did not find an explicit connection, see if there is an
  220. // implicit connection by enumerating all implicit connections
  221. //
  222. Rrp.Type = GetConnectionInfo;
  223. Rrp.Version = REQUEST_PACKET_VERSION;
  224. RtlCopyLuid(&Rrp.LogonId, LogonId);
  225. Rrp.Level = 0;
  226. Rrp.Parameters.Get.ResumeHandle = 0;
  227. if ((status = WsDeviceControlGetInfo(
  228. Redirector,
  229. WsRedirDeviceHandle,
  230. FSCTL_LMR_ENUMERATE_CONNECTIONS,
  231. (PVOID) &Rrp,
  232. sizeof(LMR_REQUEST_PACKET),
  233. (LPBYTE *) &UncList,
  234. MAXULONG,
  235. EnumConnectionHint,
  236. NULL
  237. )) != NERR_Success) {
  238. return status;
  239. }
  240. SavePtr = UncList;
  241. for (i = 0; i < Rrp.Parameters.Get.EntriesRead &&
  242. FoundImplicitEntry == FALSE; i++, UncList++) {
  243. if (WsCompareStringU(
  244. UncList->UNCName.Buffer,
  245. UncList->UNCName.Length / sizeof(WCHAR),
  246. UseName,
  247. UseNameLength
  248. ) == 0) {
  249. FoundImplicitEntry = TRUE;
  250. }
  251. }
  252. MIDL_user_free((PVOID) SavePtr);
  253. //
  254. // Fail if no such connection.
  255. //
  256. if (! FoundImplicitEntry) {
  257. IF_DEBUG(USE) {
  258. NetpKdPrint(("[Wksta] WsFindUse: No implicit entry\n"));
  259. }
  260. return NERR_UseNotFound;
  261. }
  262. //
  263. // Otherwise open the connection and return the handle
  264. //
  265. //
  266. // Replace \\ with \Device\LanmanRedirector\ in UseName
  267. //
  268. if ((status = WsCreateTreeConnectName(
  269. UseName,
  270. STRLEN(UseName),
  271. NULL,
  272. 0,
  273. &TreeConnectStr
  274. )) != NERR_Success) {
  275. return status;
  276. }
  277. //
  278. // Redirector will pick up the logon username and password
  279. // from the LSA if the authentication package is loaded.
  280. //
  281. status = WsOpenCreateConnection(
  282. &TreeConnectStr,
  283. NULL,
  284. NULL,
  285. NULL,
  286. 0, // no special flags
  287. FILE_OPEN,
  288. USE_WILDCARD,
  289. TreeConnection,
  290. NULL
  291. );
  292. (void) LocalFree(TreeConnectStr.Buffer);
  293. return status;
  294. }
  295. else {
  296. IF_DEBUG(USE) {
  297. NetpKdPrint(("[Wksta] WsFindUse: Found an explicit entry\n"));
  298. }
  299. //
  300. // Found an explicit UNC connection (NULL local device name).
  301. //
  302. NetpAssert((*MatchedPointer)->Local == NULL);
  303. *TreeConnection = (*MatchedPointer)->TreeConnection;
  304. if (ARGUMENT_PRESENT(BackPointer)) {
  305. *BackPointer = Back;
  306. }
  307. return NERR_Success;
  308. }
  309. }
  310. }
  311. VOID
  312. WsFindInsertLocation(
  313. IN PUSE_ENTRY UseList,
  314. IN LPTSTR UncName,
  315. OUT PUSE_ENTRY *MatchedPointer,
  316. OUT PUSE_ENTRY *InsertPointer
  317. )
  318. /*++
  319. Routine Description:
  320. This function searches the use list for the location to insert a new use
  321. entry. The use entry is inserted to the end of the use list so the
  322. pointer to the last node in the use list is returned via InsertPointer.
  323. We also have to save a pointer to the node with the same UNC name so that
  324. the new use entry can be set to point to the same remote node (where the
  325. UNC name is stored). This pointer is returned as MatchedPointer.
  326. WARNING: This function assumes that the Use.TableResource has been claimed.
  327. Arguments:
  328. UseList - Supplies the pointer to the use list.
  329. UncName - Supplies the pointer to the shared resource (UNC name).
  330. MatchedPointer - Returns a pointer to the node that holds the matching
  331. UncName. If no matching UncName is found, this pointer is set to
  332. NULL. If there are more than one node that has the same UNC name,
  333. this pointer will point to the node with the NULL local device name,
  334. if any; otherwise, if all nodes with matching UNC names have non-null
  335. local device names, the pointer to the last matching node will be
  336. returned.
  337. InsertPointer - Returns a pointer to the last use entry, after which the
  338. new entry is to be inserted.
  339. Return Value:
  340. None.
  341. --*/
  342. {
  343. BOOL IsMatchWithNullDevice = FALSE;
  344. *MatchedPointer = NULL;
  345. while (UseList != NULL) {
  346. //
  347. // Do the string comparison only if we haven't found a matching UNC
  348. // name with a NULL local device name.
  349. //
  350. if (! IsMatchWithNullDevice &&
  351. (STRICMP((LPWSTR) UseList->Remote->UncName, UncName) == 0)) {
  352. //
  353. // Found matching entry
  354. //
  355. *MatchedPointer = UseList;
  356. IsMatchWithNullDevice = (UseList->Local == NULL);
  357. }
  358. *InsertPointer = UseList;
  359. UseList = UseList->Next;
  360. }
  361. }
  362. VOID
  363. WsFindUncName(
  364. IN PUSE_ENTRY UseList,
  365. IN LPTSTR UncName,
  366. OUT PUSE_ENTRY *MatchedPointer,
  367. OUT PUSE_ENTRY *BackPointer
  368. )
  369. /*++
  370. Routine Description:
  371. This function searches the use list for the use entry with the specified
  372. UNC name with a NULL local device name.
  373. WARNING: This function assumes that the Use.TableResource has been claimed.
  374. Arguments:
  375. UseList - Supplies the pointer to the use list.
  376. UncName - Supplies the pointer to the shared resource (UNC name).
  377. MatchedPointer - Returns a pointer to the node that holds the matching
  378. UncName. If no matching UncName is found, this pointer is set to
  379. NULL.
  380. BackPointer - Returns a pointer to the entry previous to the found entry.
  381. If UncName is not found, this pointer is set to NULL.
  382. Return Value:
  383. None.
  384. --*/
  385. {
  386. *BackPointer = UseList;
  387. while (UseList != NULL) {
  388. if ((UseList->Local == NULL) &&
  389. (STRICMP((LPWSTR) UseList->Remote->UncName, UncName) == 0)) {
  390. //
  391. // Found matching entry
  392. //
  393. *MatchedPointer = UseList;
  394. return;
  395. }
  396. else {
  397. *BackPointer = UseList;
  398. UseList = UseList->Next;
  399. }
  400. }
  401. //
  402. // Did not find matching UNC name with a NULL local device name in the
  403. // entire list.
  404. //
  405. *MatchedPointer = NULL;
  406. *BackPointer = NULL;
  407. }
  408. STATIC
  409. VOID
  410. WsFindLocal(
  411. IN PUSE_ENTRY UseList,
  412. IN LPTSTR Local,
  413. OUT PUSE_ENTRY *MatchedPointer,
  414. OUT PUSE_ENTRY *BackPointer
  415. )
  416. /*++
  417. Routine Description:
  418. This function searches the use list for the specified local device name.
  419. WARNING: This function assumes that the Use.TableResource has been claimed.
  420. Arguments:
  421. UseList - Supplies the pointer to the use list.
  422. Local - Supplies the local device name.
  423. MatchedPointer - Returns a pointer to the use entry that holds the matching
  424. local device name. If no matching local device name is found, this
  425. pointer is set to NULL.
  426. BackPointer - Returns a pointer to the entry previous to the found entry.
  427. If the local device name is not found, this pointer is set to NULL.
  428. Return Value:
  429. None.
  430. --*/
  431. {
  432. *BackPointer = UseList;
  433. while (UseList != NULL) {
  434. if ((UseList->Local != NULL) &&
  435. (STRICMP(UseList->Local, Local) == 0)) {
  436. //
  437. // Found matching entry
  438. //
  439. *MatchedPointer = UseList;
  440. return;
  441. }
  442. else {
  443. *BackPointer = UseList;
  444. UseList = UseList->Next;
  445. }
  446. }
  447. //
  448. // Did not find matching local device name in the entire list.
  449. //
  450. *MatchedPointer = NULL;
  451. *BackPointer = NULL;
  452. }
  453. NET_API_STATUS
  454. WsCreateTreeConnectName(
  455. IN LPTSTR UncName,
  456. IN DWORD UncNameLength,
  457. IN LPTSTR LocalName OPTIONAL,
  458. IN DWORD SessionId,
  459. OUT PUNICODE_STRING TreeConnectStr
  460. )
  461. /*++
  462. Routine Description:
  463. This function replaces \\ with \Device\LanmanRedirector\DEVICE: in the
  464. UncName to form the NT-style tree connection name. A buffer is allocated
  465. by this function and returned as the output string.
  466. Arguments:
  467. UncName - Supplies the UNC name of the shared resource.
  468. UncNameLength - Supplies the length of the UNC name.
  469. LocalName - Supplies the local device name for the redirection.
  470. SessionId - Id that uniquely identifies a Hydra session. This value is always
  471. 0 for non-hydra NT and console hydra session
  472. TreeConnectStr - Returns a string with a newly allocated buffer that
  473. contains the NT-style tree connection name.
  474. Return Value:
  475. NET_API_STATUS - NERR_Success or reason for failure.
  476. --*/
  477. {
  478. BOOLEAN IsDeviceName = FALSE;
  479. WCHAR IdBuffer[16]; // Value from RtlIntegerToUnicodeString
  480. UNICODE_STRING IdString;
  481. LUID LogonId;
  482. WCHAR LUIDBuffer[32]; // Value from _snwprintf
  483. UNICODE_STRING LUIDString;
  484. NET_API_STATUS status;
  485. IdString.Length = 0;
  486. IdString.MaximumLength = sizeof(IdBuffer);
  487. IdString.Buffer = IdBuffer;
  488. RtlIntegerToUnicodeString( SessionId, 10, &IdString );
  489. if (WsLUIDDeviceMapsEnabled == TRUE) {
  490. //
  491. // Get LogonID of the user
  492. //
  493. if ((status = WsImpersonateAndGetLogonId(&LogonId)) != NERR_Success) {
  494. return status;
  495. }
  496. _snwprintf( LUIDBuffer,
  497. sizeof(LUIDBuffer)/sizeof(WCHAR),
  498. L"%08x%08x",
  499. LogonId.HighPart,
  500. LogonId.LowPart );
  501. RtlInitUnicodeString( &LUIDString, LUIDBuffer );
  502. }
  503. if (ARGUMENT_PRESENT(LocalName)) {
  504. IsDeviceName = ((STRNICMP(LocalName, TEXT("LPT"), 3) == 0) ||
  505. (STRNICMP(LocalName, TEXT("COM"), 3) == 0));
  506. }
  507. //
  508. // Initialize tree connect string maximum length to hold
  509. // \Device\LanmanRedirector\DEVICE:\SERVER\SHARE
  510. //
  511. // The new redirector requires an additional character for name
  512. // canonicalization.
  513. if (!LoadedMRxSmbInsteadOfRdr) {
  514. // The old redirector
  515. TreeConnectStr->MaximumLength = (USHORT)(RedirectorDeviceName.Length +
  516. (USHORT) (UncNameLength * sizeof(WCHAR)) +
  517. (ARGUMENT_PRESENT(LocalName) ? (STRLEN(LocalName)*sizeof(WCHAR)) : 0) +
  518. sizeof(WCHAR) + // For "\"
  519. (IsDeviceName ? sizeof(WCHAR) : 0));
  520. } else {
  521. // The new redirector
  522. TreeConnectStr->MaximumLength = (USHORT)(RedirectorDeviceName.Length +
  523. (USHORT) (UncNameLength * sizeof(WCHAR)) +
  524. (ARGUMENT_PRESENT(LocalName) ? ((STRLEN(LocalName)+1)*sizeof(WCHAR)) //+1 for ';'
  525. : 0) +
  526. sizeof(WCHAR) + // For "\"
  527. ((WsLUIDDeviceMapsEnabled == TRUE) ?
  528. (LUIDString.Length * sizeof(WCHAR)) :
  529. (IdString.Length * sizeof(WCHAR))) +
  530. (IsDeviceName ? sizeof(WCHAR) : 0));
  531. }
  532. if ((TreeConnectStr->Buffer = (PWSTR) LocalAlloc(
  533. LMEM_ZEROINIT,
  534. (UINT) TreeConnectStr->MaximumLength
  535. )) == NULL) {
  536. return ERROR_NOT_ENOUGH_MEMORY;
  537. }
  538. //
  539. // Copy \Device\LanmanRedirector
  540. //
  541. RtlCopyUnicodeString(TreeConnectStr, &RedirectorDeviceName);
  542. //
  543. // Concatenate \DEVICE:
  544. //
  545. if (ARGUMENT_PRESENT(LocalName)) {
  546. wcscat(TreeConnectStr->Buffer, L"\\");
  547. TreeConnectStr->Length += sizeof(WCHAR);
  548. // Concatenate the ; required by the new redirector for canonicalization
  549. if (LoadedMRxSmbInsteadOfRdr) {
  550. wcscat(TreeConnectStr->Buffer, L";");
  551. TreeConnectStr->Length += sizeof(WCHAR);
  552. }
  553. wcscat(TreeConnectStr->Buffer, LocalName);
  554. TreeConnectStr->Length += (USHORT)(STRLEN(LocalName)*sizeof(WCHAR));
  555. if (IsDeviceName) {
  556. wcscat(TreeConnectStr->Buffer, L":");
  557. TreeConnectStr->Length += sizeof(WCHAR);
  558. }
  559. if (LoadedMRxSmbInsteadOfRdr) {
  560. if (WsLUIDDeviceMapsEnabled == TRUE) {
  561. // Add the Logon Id
  562. RtlAppendUnicodeStringToString( TreeConnectStr, &LUIDString );
  563. }
  564. else {
  565. // Add the session id
  566. RtlAppendUnicodeStringToString( TreeConnectStr, &IdString );
  567. }
  568. }
  569. }
  570. //
  571. // Concatenate \SERVER\SHARE
  572. //
  573. wcscat(TreeConnectStr->Buffer, &UncName[1]);
  574. TreeConnectStr->Length += (USHORT)((UncNameLength - 1) * sizeof(WCHAR));
  575. return NERR_Success;
  576. }
  577. NET_API_STATUS
  578. WsOpenCreateConnection(
  579. IN PUNICODE_STRING TreeConnectionName,
  580. IN LPTSTR UserName OPTIONAL,
  581. IN LPTSTR DomainName OPTIONAL,
  582. IN LPTSTR Password OPTIONAL,
  583. IN ULONG CreateFlags,
  584. IN ULONG CreateDisposition,
  585. IN ULONG ConnectionType,
  586. OUT PHANDLE TreeConnectionHandle,
  587. OUT PULONG_PTR Information OPTIONAL
  588. )
  589. /*++
  590. Routine Description:
  591. This function asks the redirector to either open an existing tree
  592. connection (CreateDisposition == FILE_OPEN), or create a new tree
  593. connection if one does not exist (CreateDisposition == FILE_OPEN_IF).
  594. The password and user name passed to the redirector via the EA buffer
  595. in the NtCreateFile call. The EA buffer is NULL if neither password
  596. or user name is specified.
  597. The redirector expects the EA descriptor string to be in Unicode
  598. but the password and username strings to be in ANSI.
  599. Arguments:
  600. TreeConnectionName - Supplies the name of the tree connection in NT-style
  601. file name format: \Device\LanmanRedirector\SERVER\SHARE
  602. UserName - Supplies the user name to create the tree connection with.
  603. DomainName - Supplies the name of the domain to get user credentials from.
  604. Password - Supplies the password to create the tree connection with.
  605. CreateDisposition - Supplies the create disposition value to either
  606. open or create the tree connection.
  607. ConnectionType - Supplies the type of the connection (USE_xxx)
  608. TreeConnectionHandle - Returns the handle to the tree connection
  609. created/opened by the redirector.
  610. Information - Returns the information field of the I/O status block.
  611. Return Value:
  612. NET_API_STATUS - NERR_Success or reason for failure.
  613. --*/
  614. {
  615. NET_API_STATUS status;
  616. NTSTATUS ntstatus;
  617. OBJECT_ATTRIBUTES UncNameAttributes;
  618. IO_STATUS_BLOCK IoStatusBlock;
  619. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  620. PFILE_FULL_EA_INFORMATION Ea;
  621. ULONG EaBufferSize = 0;
  622. UCHAR EaNamePasswordSize = (UCHAR) (ROUND_UP_COUNT(
  623. strlen(EA_NAME_PASSWORD) + sizeof(CHAR),
  624. ALIGN_WCHAR
  625. ) - sizeof(CHAR));
  626. UCHAR EaNameUserNameSize = (UCHAR) (ROUND_UP_COUNT(
  627. strlen(EA_NAME_USERNAME) + sizeof(CHAR),
  628. ALIGN_WCHAR
  629. ) - sizeof(CHAR));
  630. UCHAR EaNameDomainNameSize = (UCHAR) (ROUND_UP_COUNT(
  631. strlen(EA_NAME_DOMAIN) + sizeof(CHAR),
  632. ALIGN_WCHAR
  633. ) - sizeof(CHAR));
  634. UCHAR EaNameTypeSize = (UCHAR) (ROUND_UP_COUNT(
  635. strlen(EA_NAME_TYPE) + sizeof(CHAR),
  636. ALIGN_DWORD
  637. ) - sizeof(CHAR));
  638. UCHAR EaNameConnectSize = (UCHAR) (ROUND_UP_COUNT(
  639. strlen(EA_NAME_CONNECT) + sizeof(CHAR),
  640. ALIGN_DWORD
  641. ) - sizeof(CHAR));
  642. UCHAR EaNameCSCAgentSize = (UCHAR) (ROUND_UP_COUNT(
  643. strlen(EA_NAME_CSCAGENT) + sizeof(CHAR),
  644. ALIGN_DWORD
  645. ) - sizeof(CHAR));
  646. USHORT PasswordSize = 0;
  647. USHORT UserNameSize = 0;
  648. USHORT DomainNameSize = 0;
  649. USHORT TypeSize = sizeof(ULONG);
  650. InitializeObjectAttributes(
  651. &UncNameAttributes,
  652. TreeConnectionName,
  653. OBJ_CASE_INSENSITIVE,
  654. NULL,
  655. NULL
  656. );
  657. //
  658. // Calculate the number of bytes needed for the EA buffer to put the
  659. // password or user name.
  660. //
  661. if (ARGUMENT_PRESENT(Password)) {
  662. PasswordSize = (USHORT) (wcslen(Password) * sizeof(WCHAR));
  663. EaBufferSize = ROUND_UP_COUNT(
  664. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
  665. EaNamePasswordSize + sizeof(CHAR) +
  666. PasswordSize,
  667. ALIGN_DWORD
  668. );
  669. }
  670. if (ARGUMENT_PRESENT(UserName)) {
  671. UserNameSize = (USHORT) (wcslen(UserName) * sizeof(WCHAR));
  672. EaBufferSize += ROUND_UP_COUNT(
  673. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  674. EaNameUserNameSize + sizeof(CHAR) +
  675. UserNameSize,
  676. ALIGN_DWORD
  677. );
  678. }
  679. if (ARGUMENT_PRESENT(DomainName)) {
  680. DomainNameSize = (USHORT) (wcslen(DomainName) * sizeof(WCHAR));
  681. EaBufferSize += ROUND_UP_COUNT(
  682. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  683. EaNameDomainNameSize + sizeof(CHAR) +
  684. DomainNameSize,
  685. ALIGN_DWORD
  686. );
  687. }
  688. if(CreateFlags & CREATE_NO_CONNECT)
  689. {
  690. EaBufferSize += ROUND_UP_COUNT(
  691. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  692. EaNameConnectSize + sizeof(CHAR),
  693. ALIGN_DWORD
  694. );
  695. }
  696. if(CreateFlags & CREATE_BYPASS_CSC)
  697. {
  698. EaBufferSize += ROUND_UP_COUNT(
  699. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  700. EaNameCSCAgentSize + sizeof(CHAR),
  701. ALIGN_DWORD
  702. );
  703. }
  704. EaBufferSize += FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
  705. EaNameTypeSize + sizeof(CHAR) +
  706. TypeSize;
  707. //
  708. // Allocate the EA buffer
  709. //
  710. if ((EaBuffer = (PFILE_FULL_EA_INFORMATION) LocalAlloc(
  711. LMEM_ZEROINIT,
  712. (UINT) EaBufferSize
  713. )) == NULL) {
  714. status = GetLastError();
  715. goto FreeMemory;
  716. }
  717. Ea = EaBuffer;
  718. if(CreateFlags & CREATE_NO_CONNECT)
  719. {
  720. //
  721. // Copy the EA name into EA buffer. EA name length does not
  722. // include the zero terminator.
  723. //
  724. strcpy((LPSTR) Ea->EaName, EA_NAME_CONNECT);
  725. Ea->EaNameLength = EaNameConnectSize;
  726. Ea->EaValueLength = 0;
  727. Ea->NextEntryOffset = ROUND_UP_COUNT(
  728. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  729. EaNameConnectSize + sizeof(CHAR) +
  730. 0,
  731. ALIGN_DWORD
  732. );
  733. IF_DEBUG(USE) {
  734. NetpKdPrint(("[Wksta] OpenCreate: After round, NextEntryOffset=%lu\n",
  735. Ea->NextEntryOffset));
  736. }
  737. Ea->Flags = 0;
  738. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  739. }
  740. if( CreateFlags & CREATE_BYPASS_CSC ) {
  741. strcpy((LPSTR)Ea->EaName, EA_NAME_CSCAGENT);
  742. Ea->EaNameLength = EaNameCSCAgentSize;
  743. Ea->EaValueLength = 0;
  744. Ea->NextEntryOffset = ROUND_UP_COUNT(
  745. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  746. EaNameCSCAgentSize + sizeof(CHAR) +
  747. 0,
  748. ALIGN_DWORD
  749. );
  750. IF_DEBUG(USE) {
  751. NetpKdPrint(("[Wksta] OpenCreate: After round, NextEntryOffset=%lu\n",
  752. Ea->NextEntryOffset));
  753. }
  754. Ea->Flags = 0;
  755. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  756. }
  757. if (ARGUMENT_PRESENT(Password)) {
  758. //
  759. // Copy the EA name into EA buffer. EA name length does not
  760. // include the zero terminator.
  761. //
  762. strcpy((LPSTR) Ea->EaName, EA_NAME_PASSWORD);
  763. Ea->EaNameLength = EaNamePasswordSize;
  764. //
  765. // Copy the EA value into EA buffer. EA value length does not
  766. // include the zero terminator.
  767. //
  768. wcscpy(
  769. (LPWSTR) &(Ea->EaName[EaNamePasswordSize + sizeof(CHAR)]),
  770. Password
  771. );
  772. Ea->EaValueLength = PasswordSize;
  773. Ea->NextEntryOffset = ROUND_UP_COUNT(
  774. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  775. EaNamePasswordSize + sizeof(CHAR) +
  776. PasswordSize,
  777. ALIGN_DWORD
  778. );
  779. IF_DEBUG(USE) {
  780. NetpKdPrint(("[Wksta] OpenCreate: After round, NextEntryOffset=%lu\n",
  781. Ea->NextEntryOffset));
  782. }
  783. Ea->Flags = 0;
  784. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  785. }
  786. if (ARGUMENT_PRESENT(UserName)) {
  787. //
  788. // Copy the EA name into EA buffer. EA name length does not
  789. // include the zero terminator.
  790. //
  791. strcpy((LPSTR) Ea->EaName, EA_NAME_USERNAME);
  792. Ea->EaNameLength = EaNameUserNameSize;
  793. //
  794. // Copy the EA value into EA buffer. EA value length does not
  795. // include the zero terminator.
  796. //
  797. wcscpy(
  798. (LPWSTR) &(Ea->EaName[EaNameUserNameSize + sizeof(CHAR)]),
  799. UserName
  800. );
  801. Ea->EaValueLength = UserNameSize;
  802. Ea->NextEntryOffset = ROUND_UP_COUNT(
  803. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
  804. EaNameUserNameSize + sizeof(CHAR) +
  805. UserNameSize,
  806. ALIGN_DWORD
  807. );
  808. Ea->Flags = 0;
  809. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  810. }
  811. if (ARGUMENT_PRESENT(DomainName)) {
  812. //
  813. // Copy the EA name into EA buffer. EA name length does not
  814. // include the zero terminator.
  815. //
  816. strcpy((LPSTR) Ea->EaName, EA_NAME_DOMAIN);
  817. Ea->EaNameLength = EaNameDomainNameSize;
  818. //
  819. // Copy the EA value into EA buffer. EA value length does not
  820. // include the zero terminator.
  821. //
  822. wcscpy(
  823. (LPWSTR) &(Ea->EaName[EaNameDomainNameSize + sizeof(CHAR)]),
  824. DomainName
  825. );
  826. Ea->EaValueLength = DomainNameSize;
  827. Ea->NextEntryOffset = ROUND_UP_COUNT(
  828. FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
  829. EaNameDomainNameSize + sizeof(CHAR) +
  830. DomainNameSize,
  831. ALIGN_DWORD
  832. );
  833. Ea->Flags = 0;
  834. (ULONG_PTR) Ea += Ea->NextEntryOffset;
  835. }
  836. //
  837. // Copy the EA for the connection type name into EA buffer. EA name length
  838. // does not include the zero terminator.
  839. //
  840. strcpy((LPSTR) Ea->EaName, EA_NAME_TYPE);
  841. Ea->EaNameLength = EaNameTypeSize;
  842. *((PULONG) &(Ea->EaName[EaNameTypeSize + sizeof(CHAR)])) = ConnectionType;
  843. Ea->EaValueLength = TypeSize;
  844. Ea->NextEntryOffset = 0;
  845. Ea->Flags = 0;
  846. if ((status = WsImpersonateClient()) != NERR_Success) {
  847. goto FreeMemory;
  848. }
  849. //
  850. // Create or open a tree connection
  851. //
  852. ntstatus = NtCreateFile(
  853. TreeConnectionHandle,
  854. SYNCHRONIZE,
  855. &UncNameAttributes,
  856. &IoStatusBlock,
  857. NULL,
  858. FILE_ATTRIBUTE_NORMAL,
  859. FILE_SHARE_READ | FILE_SHARE_WRITE |
  860. FILE_SHARE_DELETE,
  861. CreateDisposition,
  862. FILE_CREATE_TREE_CONNECTION
  863. | FILE_SYNCHRONOUS_IO_NONALERT,
  864. (PVOID) EaBuffer,
  865. EaBufferSize
  866. );
  867. WsRevertToSelf();
  868. if (NT_SUCCESS(ntstatus)) {
  869. ntstatus = IoStatusBlock.Status;
  870. }
  871. if (ARGUMENT_PRESENT(Information)) {
  872. *Information = IoStatusBlock.Information;
  873. }
  874. IF_DEBUG(USE) {
  875. NetpKdPrint(("[Wksta] NtCreateFile returns %lx\n", ntstatus));
  876. }
  877. status = WsMapStatus(ntstatus);
  878. FreeMemory:
  879. if (EaBuffer != NULL) {
  880. // Prevent password from making it to pagefile.
  881. RtlZeroMemory( EaBuffer, EaBufferSize );
  882. (void) LocalFree((HLOCAL) EaBuffer);
  883. }
  884. return status;
  885. }
  886. NET_API_STATUS
  887. WsDeleteConnection(
  888. IN PLUID LogonId,
  889. IN HANDLE TreeConnection,
  890. IN DWORD ForceLevel
  891. )
  892. /*++
  893. Routine Description:
  894. This function asks the redirector to delete the tree connection
  895. associated with the tree connection handle, and closes the handle.
  896. Arguments:
  897. LogonId - Supplies a pointer to the user's Logon Id.
  898. TreeConnection - Supplies the handle to the tree connection created.
  899. ForceLevel - Supplies the level of force to delete the tree connection.
  900. Return Value:
  901. NET_API_STATUS - NERR_Success or reason for failure.
  902. --*/
  903. {
  904. NET_API_STATUS status;
  905. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  906. //
  907. // Map force level to values the redirector understand
  908. //
  909. switch (ForceLevel) {
  910. case USE_NOFORCE:
  911. case USE_LOTS_OF_FORCE:
  912. Rrp.Level = ForceLevel;
  913. break;
  914. case USE_FORCE:
  915. Rrp.Level = USE_NOFORCE;
  916. break;
  917. default:
  918. NetpKdPrint(("[Wksta] Invalid force level %lu should never happen!\n",
  919. ForceLevel));
  920. NetpAssert(FALSE);
  921. }
  922. //
  923. // Tell the redirector to delete the tree connection
  924. //
  925. Rrp.Version = REQUEST_PACKET_VERSION;
  926. RtlCopyLuid(&Rrp.LogonId, LogonId);
  927. status = WsRedirFsControl(
  928. TreeConnection,
  929. FSCTL_LMR_DELETE_CONNECTION,
  930. &Rrp,
  931. sizeof(LMR_REQUEST_PACKET),
  932. NULL,
  933. 0,
  934. NULL
  935. );
  936. //
  937. // Close the connection handle
  938. //
  939. if(status == NERR_Success)
  940. {
  941. (void) NtClose(TreeConnection);
  942. }
  943. return status;
  944. }
  945. BOOL
  946. WsRedirectionPaused(
  947. IN LPTSTR LocalDeviceName
  948. )
  949. /*++
  950. Routine Description:
  951. This function checks to see if the redirection for the print and comm
  952. devices are paused for the system. Since we are only checking a global
  953. flag, there's no reason to protect it with a RESOURCE.
  954. Arguments:
  955. LocalDeviceName - Supplies the name of the local device.
  956. Return Value:
  957. Returns TRUE redirection is paused; FALSE otherwise
  958. --*/
  959. {
  960. if ((STRNICMP(LocalDeviceName, TEXT("LPT"), 3) == 0) ||
  961. (STRNICMP(LocalDeviceName, TEXT("COM"), 3) == 0)) {
  962. //
  963. // Redirection of print and comm devices are paused if
  964. // workstation service is paused.
  965. //
  966. return (WsGlobalData.Status.dwCurrentState == SERVICE_PAUSED);
  967. } else {
  968. //
  969. // Redirection of disk devices cannot be paused.
  970. //
  971. return FALSE;
  972. }
  973. }
  974. VOID
  975. WsPauseOrContinueRedirection(
  976. IN REDIR_OPERATION OperationType
  977. )
  978. /*++
  979. Routine Description:
  980. This function pauses or unpauses (based on OperationType) the redirection
  981. of print or comm devices.
  982. Arguments:
  983. OperationType - Supplies a value that causes redirection to be paused or
  984. continued.
  985. Return Value:
  986. None.
  987. --*/
  988. {
  989. DWORD Index; // Index to user entry in Use Table
  990. PUSE_ENTRY UseEntry;
  991. //
  992. // Lock Use Table
  993. //
  994. if (! RtlAcquireResourceExclusive(&Use.TableResource, TRUE)) {
  995. return;
  996. }
  997. //
  998. // If we want to pause and we are already paused, or if we want to
  999. // continue and we have not paused, just return.
  1000. //
  1001. if ((OperationType == PauseRedirection &&
  1002. WsGlobalData.Status.dwCurrentState == SERVICE_PAUSED) ||
  1003. (OperationType == ContinueRedirection &&
  1004. WsGlobalData.Status.dwCurrentState == SERVICE_RUNNING)) {
  1005. RtlReleaseResource(&Use.TableResource);
  1006. return;
  1007. }
  1008. //
  1009. // Pause or continue for all users
  1010. //
  1011. for (Index = 0; Index < Use.TableSize; Index++) {
  1012. UseEntry = Use.Table[Index].List;
  1013. while (UseEntry != NULL) {
  1014. if ((UseEntry->Local != NULL) &&
  1015. ((STRNICMP(TEXT("LPT"), UseEntry->Local, 3) == 0) ||
  1016. (STRNICMP(TEXT("COM"), UseEntry->Local, 3) == 0))) {
  1017. if (OperationType == PauseRedirection) {
  1018. //
  1019. // Pause the redirection
  1020. //
  1021. //
  1022. // Delete the symbolic link
  1023. //
  1024. WsDeleteSymbolicLink(
  1025. UseEntry->Local,
  1026. UseEntry->TreeConnectStr,
  1027. NULL
  1028. );
  1029. }
  1030. else {
  1031. LPWSTR Session = NULL;
  1032. //
  1033. // Continue the redirection
  1034. //
  1035. if (WsCreateSymbolicLink(
  1036. UseEntry->Local,
  1037. USE_SPOOLDEV, // USE_CHARDEV is just as good
  1038. UseEntry->TreeConnectStr,
  1039. NULL,
  1040. &Session
  1041. ) != NERR_Success) {
  1042. PUSE_ENTRY RestoredEntry = Use.Table[Index].List;
  1043. //
  1044. // Could not continue completely. Delete all
  1045. // symbolic links restored so far
  1046. //
  1047. while (RestoredEntry != UseEntry) {
  1048. if ((UseEntry->Local != NULL) &&
  1049. ((STRNICMP(TEXT("LPT"), UseEntry->Local, 3) == 0) ||
  1050. (STRNICMP(TEXT("COM"), UseEntry->Local, 3) == 0))) {
  1051. WsDeleteSymbolicLink(
  1052. RestoredEntry->Local,
  1053. RestoredEntry->TreeConnectStr,
  1054. Session
  1055. );
  1056. }
  1057. RestoredEntry = RestoredEntry->Next;
  1058. }
  1059. RtlReleaseResource(&Use.TableResource);
  1060. LocalFree(Session);
  1061. return;
  1062. }
  1063. LocalFree(Session);
  1064. }
  1065. }
  1066. UseEntry = UseEntry->Next;
  1067. }
  1068. } // for all users
  1069. if (OperationType == PauseRedirection) {
  1070. WsGlobalData.Status.dwCurrentState = SERVICE_PAUSED;
  1071. }
  1072. else {
  1073. WsGlobalData.Status.dwCurrentState = SERVICE_RUNNING;
  1074. }
  1075. //
  1076. // Use the same resource to protect access to the RedirectionPaused flag
  1077. // in WsGlobalData
  1078. //
  1079. RtlReleaseResource(&Use.TableResource);
  1080. }
  1081. NET_API_STATUS
  1082. WsCreateSymbolicLink(
  1083. IN LPWSTR Local,
  1084. IN DWORD DeviceType,
  1085. IN LPWSTR TreeConnectStr,
  1086. IN PUSE_ENTRY UseList,
  1087. IN OUT LPWSTR *Session
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. This function creates a symbolic link object for the specified local
  1092. device name which is linked to the tree connection name that has a
  1093. format of \Device\LanmanRedirector\Device:\Server\Share.
  1094. NOTE: when LUID Device maps are enabled,
  1095. Must perform the creation outside of exclusively holding the
  1096. Use.TableResource.
  1097. Otherwise, when the shell tries to update the current status of
  1098. a drive letter change, the explorer.exe thread will block while
  1099. trying to acquire the Use.TableResource
  1100. Arguments:
  1101. Local - Supplies the local device name.
  1102. DeviceType - Supplies the shared resource device type.
  1103. TreeConnectStr - Supplies the tree connection name string which is
  1104. the link target of the symbolick link object.
  1105. UseList - Supplies the pointer to the use list.
  1106. Return Value:
  1107. NET_API_STATUS - NERR_Success or reason for failure.
  1108. --*/
  1109. {
  1110. NET_API_STATUS status = NERR_Success;
  1111. WCHAR TempBuf[64];
  1112. DWORD dddFlags;
  1113. //
  1114. // Multiple session support
  1115. //
  1116. *Session = WsReturnSessionPath(Local);
  1117. if( *Session == NULL ) {
  1118. return( GetLastError() );
  1119. }
  1120. if (WsLUIDDeviceMapsEnabled == TRUE) {
  1121. if ((status = WsImpersonateClient()) != NERR_Success) {
  1122. return status;
  1123. }
  1124. }
  1125. //
  1126. // To redirect a comm or print device, we need to see if we have
  1127. // redirected it once before by searching through all existing
  1128. // redirections.
  1129. //
  1130. if ((DeviceType == USE_CHARDEV) || (DeviceType == USE_SPOOLDEV)) {
  1131. PUSE_ENTRY MatchedPointer;
  1132. PUSE_ENTRY BackPointer;
  1133. WsFindLocal(
  1134. UseList,
  1135. Local,
  1136. &MatchedPointer,
  1137. &BackPointer
  1138. );
  1139. if (MatchedPointer != NULL) {
  1140. //
  1141. // Already redirected
  1142. //
  1143. return ERROR_ALREADY_ASSIGNED;
  1144. }
  1145. }
  1146. else {
  1147. if (! QueryDosDeviceW(
  1148. *Session,
  1149. TempBuf,
  1150. 64
  1151. )) {
  1152. if (GetLastError() != ERROR_FILE_NOT_FOUND) {
  1153. //
  1154. // Most likely failure occurred because our output
  1155. // buffer is too small. It still means someone already
  1156. // has an existing symbolic link for this device.
  1157. //
  1158. return ERROR_ALREADY_ASSIGNED;
  1159. }
  1160. //
  1161. // ERROR_FILE_NOT_FOUND (translated from OBJECT_NAME_NOT_FOUND)
  1162. // means it does not exist and we can redirect this device.
  1163. //
  1164. }
  1165. else {
  1166. //
  1167. // QueryDosDevice successfully an existing symbolic link--
  1168. // somebody is already using this device.
  1169. //
  1170. return ERROR_ALREADY_ASSIGNED;
  1171. }
  1172. }
  1173. //
  1174. // Create a symbolic link object to the device we are redirecting
  1175. //
  1176. dddFlags = DDD_RAW_TARGET_PATH | DDD_NO_BROADCAST_SYSTEM;
  1177. if (!DefineDosDeviceW(
  1178. dddFlags,
  1179. *Session,
  1180. TreeConnectStr
  1181. )) {
  1182. DWORD dwError = GetLastError();
  1183. if (WsLUIDDeviceMapsEnabled == TRUE) {
  1184. WsRevertToSelf();
  1185. }
  1186. return dwError;
  1187. }
  1188. else {
  1189. if (WsLUIDDeviceMapsEnabled == TRUE) {
  1190. WsRevertToSelf();
  1191. }
  1192. return NERR_Success;
  1193. }
  1194. }
  1195. VOID
  1196. WsDeleteSymbolicLink(
  1197. IN LPWSTR LocalDeviceName,
  1198. IN LPWSTR TreeConnectStr,
  1199. IN LPWSTR SessionDeviceName
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. This function deletes the symbolic link we had created earlier for
  1204. the device.
  1205. NOTE: when LUID Device maps are enabled,
  1206. Must perform the deletion outside of exclusively holding the
  1207. Use.TableResource.
  1208. Otherwise, when the shell tries to update the current status of
  1209. a drive letter change, the explorer.exe thread will block while
  1210. trying to acquire the Use.TableResource
  1211. Arguments:
  1212. LocalDeviceName - Supplies the local device name string of which the
  1213. symbolic link object is created.
  1214. TreeConnectStr - Supplies a pointer to the Unicode string which
  1215. contains the link target string we want to match and delete.
  1216. Return Value:
  1217. None.
  1218. --*/
  1219. {
  1220. BOOLEAN DeleteSession = FALSE;
  1221. DWORD dddFlags;
  1222. if (LocalDeviceName != NULL ||
  1223. SessionDeviceName != NULL) {
  1224. if (SessionDeviceName == NULL) {
  1225. SessionDeviceName = WsReturnSessionPath(LocalDeviceName);
  1226. if( SessionDeviceName == NULL ) return;
  1227. DeleteSession = TRUE;
  1228. }
  1229. dddFlags = DDD_REMOVE_DEFINITION |
  1230. DDD_RAW_TARGET_PATH |
  1231. DDD_EXACT_MATCH_ON_REMOVE |
  1232. DDD_NO_BROADCAST_SYSTEM;
  1233. if (WsLUIDDeviceMapsEnabled == TRUE) {
  1234. if (WsImpersonateClient() != NERR_Success) {
  1235. return;
  1236. }
  1237. }
  1238. if (! DefineDosDeviceW(
  1239. dddFlags,
  1240. SessionDeviceName,
  1241. TreeConnectStr
  1242. )) {
  1243. #if DBG
  1244. NetpKdPrint(("DefineDosDevice DEL of %ws %ws returned %ld\n",
  1245. LocalDeviceName, TreeConnectStr, GetLastError()));
  1246. #endif
  1247. }
  1248. if (WsLUIDDeviceMapsEnabled == TRUE) {
  1249. WsRevertToSelf();
  1250. }
  1251. }
  1252. if( SessionDeviceName && DeleteSession) {
  1253. LocalFree( SessionDeviceName );
  1254. }
  1255. }
  1256. NET_API_STATUS
  1257. WsUseCheckRemote(
  1258. IN LPTSTR RemoteResource,
  1259. OUT LPTSTR UncName,
  1260. OUT LPDWORD UncNameLength
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This function checks the validity of the remote resource name
  1265. specified to NetUseAdd.
  1266. Arguments:
  1267. RemoteResource - Supplies the remote resource name specified by the API
  1268. caller.
  1269. UncName - Returns the canonicalized remote resource name.
  1270. UncNameLength - Returns the length of the canonicalized name.
  1271. Return Value:
  1272. NET_API_STATUS - NERR_Success or reason for failure.
  1273. --*/
  1274. {
  1275. NET_API_STATUS status;
  1276. DWORD PathType = 0;
  1277. LPTSTR Ptr;
  1278. if ((status = I_NetPathType(
  1279. NULL,
  1280. RemoteResource,
  1281. &PathType,
  1282. 0)) == NERR_Success) {
  1283. //
  1284. // Check for UNC type
  1285. //
  1286. if (PathType != ITYPE_UNC) {
  1287. IF_DEBUG(USE) {
  1288. NetpKdPrint(("[Wksta] WsUseCheckRemote not UNC type\n"));
  1289. }
  1290. return ERROR_INVALID_PARAMETER;
  1291. }
  1292. //
  1293. // Canonicalize the name
  1294. //
  1295. status = I_NetPathCanonicalize(
  1296. NULL,
  1297. RemoteResource,
  1298. UncName,
  1299. (MAX_PATH) * sizeof(TCHAR),
  1300. NULL,
  1301. &PathType,
  1302. 0
  1303. );
  1304. if (status != NERR_Success) {
  1305. IF_DEBUG(USE) {
  1306. NetpKdPrint((
  1307. "[Wksta] WsUseCheckRemote: I_NetPathCanonicalize return %lu\n",
  1308. status
  1309. ));
  1310. }
  1311. return status;
  1312. }
  1313. IF_DEBUG(USE) {
  1314. NetpKdPrint(("[Wksta] WsUseCheckRemote: %ws\n", UncName));
  1315. }
  1316. }
  1317. else {
  1318. NetpKdPrint(("[Wksta] WsUseCheckRemote: I_NetPathType return %lu\n",
  1319. status));
  1320. return status;
  1321. }
  1322. //
  1323. // Detect illegal remote name in the form of \\XXX\YYY\zzz. We assume
  1324. // that the UNC name begins with exactly two leading backslashes.
  1325. //
  1326. if ((Ptr = STRCHR(UncName + 2, TCHAR_BACKSLASH)) == NULL) {
  1327. return ERROR_INVALID_PARAMETER;
  1328. }
  1329. if (!LoadedMRxSmbInsteadOfRdr && STRCHR(Ptr + 1, TCHAR_BACKSLASH) != NULL) {
  1330. //
  1331. // There should not be anymore backslashes
  1332. //
  1333. return ERROR_INVALID_PARAMETER;
  1334. }
  1335. *UncNameLength = STRLEN(UncName);
  1336. return NERR_Success;
  1337. }
  1338. NET_API_STATUS
  1339. WsUseCheckLocal(
  1340. IN LPTSTR LocalDevice,
  1341. OUT LPTSTR Local,
  1342. OUT LPDWORD LocalLength
  1343. )
  1344. /*++
  1345. Routine Description:
  1346. This function checks the validity of the local device name
  1347. specified to NetUseAdd.
  1348. Arguments:
  1349. LocalDevice - Supplies the local device name specified by the API
  1350. caller.
  1351. Local - Returns the canonicalized local device name.
  1352. LocalLength - Returns the length of the canonicalized name.
  1353. Return Value:
  1354. NET_API_STATUS - NERR_Success or reason for failure.
  1355. --*/
  1356. {
  1357. NET_API_STATUS status;
  1358. DWORD PathType = 0;
  1359. if ((status = I_NetPathType(
  1360. NULL,
  1361. LocalDevice,
  1362. &PathType,
  1363. 0)) == NERR_Success) {
  1364. //
  1365. // Check for DEVICE type
  1366. //
  1367. if ((PathType != (ITYPE_DEVICE | ITYPE_DISK)) &&
  1368. (PathType != (ITYPE_DEVICE | ITYPE_LPT)) &&
  1369. (PathType != (ITYPE_DEVICE | ITYPE_COM))) {
  1370. IF_DEBUG(USE) {
  1371. NetpKdPrint(("[Wksta] WsUseCheckLocal not DISK, LPT, or COM type\n"));
  1372. }
  1373. return ERROR_INVALID_PARAMETER;
  1374. }
  1375. //
  1376. // Canonicalize the name
  1377. //
  1378. status = I_NetPathCanonicalize(
  1379. NULL,
  1380. LocalDevice,
  1381. Local,
  1382. (DEVLEN + 1) * sizeof(TCHAR),
  1383. NULL,
  1384. &PathType,
  1385. 0
  1386. );
  1387. if (status != NERR_Success) {
  1388. IF_DEBUG(USE) {
  1389. NetpKdPrint((
  1390. "[Wksta] WsUseCheckLocal: I_NetPathCanonicalize return %lu\n",
  1391. status
  1392. ));
  1393. }
  1394. return status;
  1395. }
  1396. IF_DEBUG(USE) {
  1397. NetpKdPrint(("[Wksta] WsUseCheckLocal: %ws\n", Local));
  1398. }
  1399. }
  1400. else {
  1401. NetpKdPrint(("[Wksta] WsUseCheckLocal: I_NetPathType return %lu\n",
  1402. status));
  1403. return status;
  1404. }
  1405. *LocalLength = STRLEN(Local);
  1406. return NERR_Success;
  1407. }
  1408. LPTSTR
  1409. WsReturnSessionPath(
  1410. IN LPTSTR LocalDeviceName
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. This function returns the per session path to access the
  1415. specific dos device for multiple session support.
  1416. Arguments:
  1417. LocalDeviceName - Supplies the local device name specified by the API
  1418. caller.
  1419. Return Value:
  1420. LPTSTR - Pointer to per session path in newly allocated memory
  1421. by LocalAlloc().
  1422. --*/
  1423. {
  1424. BOOL rc;
  1425. DWORD SessionId;
  1426. CLIENT_ID ClientId;
  1427. LPTSTR SessionDeviceName;
  1428. NET_API_STATUS status;
  1429. if ((status = WsImpersonateAndGetSessionId(&SessionId)) != NERR_Success) {
  1430. return NULL;
  1431. }
  1432. rc = DosPathToSessionPath(
  1433. SessionId,
  1434. LocalDeviceName,
  1435. &SessionDeviceName
  1436. );
  1437. if( !rc ) {
  1438. return NULL;
  1439. }
  1440. return SessionDeviceName;
  1441. }
  1442.