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.

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