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.

2101 lines
64 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. drprov.c
  5. Abstract:
  6. This module implements the routines required for interaction with network
  7. provider router interface in NT for RDP mini-redirector
  8. Author:
  9. Joy Chik 1/20/2000
  10. --*/
  11. #define TRC_FILE "drprov"
  12. #include "drprov.h"
  13. #include "drdbg.h"
  14. DWORD GLOBAL_DEBUG_FLAGS=0x0;
  15. //
  16. // the RDP mini redirector and provider name. The original constants
  17. // are defined in rdpdr.h
  18. //
  19. // The length does not include the null terminator
  20. //
  21. UNICODE_STRING DrDeviceName =
  22. {RDPDR_DEVICE_NAME_U_LENGTH - sizeof(WCHAR),
  23. RDPDR_DEVICE_NAME_U_LENGTH,
  24. RDPDR_DEVICE_NAME_U};
  25. extern UNICODE_STRING DrProviderName;
  26. //
  27. // Function prototypes defined in drenum.c
  28. //
  29. DWORD DrOpenMiniRdr(HANDLE *DrDeviceHandle);
  30. DWORD DrDeviceControlGetInfo(IN HANDLE FileHandle,
  31. IN ULONG DeviceControlCode,
  32. IN PVOID RequestPacket,
  33. IN ULONG RequestPacketLength,
  34. OUT LPBYTE *OutputBuffer,
  35. IN ULONG PreferedMaximumLength,
  36. IN ULONG BufferHintSize,
  37. OUT PULONG_PTR Information OPTIONAL);
  38. DWORD DrEnumServerInfo(IN PRDPDR_ENUMERATION_HANDLE pEnumHandle,
  39. OUT LPDWORD lpcCount,
  40. OUT LPNETRESOURCEW pBufferResource,
  41. IN OUT LPDWORD lpBufferSize);
  42. DWORD DrEnumShareInfo(IN PRDPDR_ENUMERATION_HANDLE pEnumHandle,
  43. OUT LPDWORD lpcCount,
  44. OUT LPNETRESOURCEW pBufferResource,
  45. IN OUT LPDWORD lpBufferSize);
  46. DWORD DrEnumConnectionInfo(IN PRDPDR_ENUMERATION_HANDLE pEnumHandle,
  47. OUT LPDWORD lpcCount,
  48. OUT LPNETRESOURCEW pBufferResource,
  49. IN OUT LPDWORD lpBufferSize);
  50. BOOL ValidateRemoteName(IN PWCHAR pRemoteName);
  51. DWORD APIENTRY
  52. NPGetCaps(
  53. DWORD nIndex )
  54. /*++
  55. Routine Description:
  56. This routine returns the capabilities of the RDP Mini redirector
  57. network provider implementation
  58. Arguments:
  59. nIndex - category of capabilities desired
  60. Return Value:
  61. the appropriate capabilities
  62. --*/
  63. {
  64. DBGMSG(DBG_TRACE, ("DRPROV: NPGetCaps, index: %d\n", nIndex));
  65. switch (nIndex) {
  66. case WNNC_SPEC_VERSION:
  67. return WNNC_SPEC_VERSION51;
  68. case WNNC_NET_TYPE:
  69. return WNNC_NET_TERMSRV;
  70. case WNNC_DRIVER_VERSION:
  71. #define WNNC_DRIVER(major,minor) (major*0x00010000 + minor)
  72. return (WNNC_DRIVER(RDPDR_MAJOR_VERSION, RDPDR_MINOR_VERSION));
  73. case WNNC_USER:
  74. return WNNC_USR_GETUSER;
  75. case WNNC_CONNECTION:
  76. return (WNNC_CON_GETCONNECTIONS |
  77. WNNC_CON_CANCELCONNECTION |
  78. WNNC_CON_ADDCONNECTION |
  79. WNNC_CON_ADDCONNECTION3);
  80. case WNNC_DIALOG:
  81. return WNNC_DLG_GETRESOURCEINFORMATION;
  82. //return (WNNC_DLG_SEARCHDIALOG |
  83. // WNNC_DLG_FORMATNETNAME);
  84. case WNNC_ADMIN:
  85. return 0;
  86. case WNNC_ENUMERATION:
  87. return (WNNC_ENUM_LOCAL |
  88. WNNC_ENUM_GLOBAL |
  89. WNNC_ENUM_SHAREABLE);
  90. case WNNC_START:
  91. //
  92. // JOYC: Need to figure what we should return here
  93. //
  94. return 1;
  95. default:
  96. return 0;
  97. }
  98. }
  99. DWORD APIENTRY
  100. NPOpenEnum(
  101. DWORD dwScope,
  102. DWORD dwType,
  103. DWORD dwUsage,
  104. LPNETRESOURCE lpNetResource,
  105. LPHANDLE lphEnum )
  106. /*++
  107. Routine Description:
  108. This routine opens a handle for enumeration of resources.
  109. Arguments:
  110. dwScope - the scope of enumeration
  111. dwType - the type of resources to be enumerated
  112. dwUsage - the usage parameter
  113. lpNetResource - a pointer to the desired NETRESOURCE struct.
  114. lphEnum - a pointer for passing back the enumeration handle
  115. Return Value:
  116. WN_SUCCESS if successful, otherwise the appropriate error
  117. --*/
  118. {
  119. DWORD Status = WN_NOT_SUPPORTED;
  120. RDPDR_ENUMERATION_HANDLE *pEnum;
  121. DWORD ConsoleId, CurrentId;
  122. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, dwScope=%d, dwType=%d, dwUsage=%d\n",
  123. dwScope, dwType, dwUsage));
  124. //
  125. // Basic parameter checking, make sure lphEnum is not NULL
  126. //
  127. if (lphEnum != NULL) {
  128. *lphEnum = NULL;
  129. }
  130. else {
  131. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, null lphEnum parameter.\n"));
  132. Status = WN_BAD_VALUE;
  133. goto EXIT;
  134. }
  135. //
  136. // Check if the request comes from console, if so, bail immediately
  137. //
  138. ConsoleId = WTSGetActiveConsoleSessionId();
  139. if (ProcessIdToSessionId(GetCurrentProcessId(), &CurrentId)) {
  140. if (ConsoleId == CurrentId) {
  141. if (!(dwScope == RESOURCE_GLOBALNET && lpNetResource == NULL)) {
  142. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, console request, bail.\n"));
  143. Status = WN_NOT_SUPPORTED;
  144. goto EXIT;
  145. }
  146. }
  147. }
  148. //
  149. // Allocating the enumeration handle
  150. //
  151. *lphEnum = MemAlloc(sizeof(RDPDR_ENUMERATION_HANDLE));
  152. if (*lphEnum == NULL) {
  153. DBGMSG(DBG_ERROR, ("DRPROV: NPOpenEnum, MemAlloc failed for enum handle.\n"));
  154. Status = WN_OUT_OF_MEMORY;
  155. goto EXIT;
  156. }
  157. RtlZeroMemory(*lphEnum, sizeof(RDPDR_ENUMERATION_HANDLE));
  158. if (dwScope == RESOURCE_CONNECTED)
  159. {
  160. //
  161. // we are looking for current uses
  162. //
  163. if (lpNetResource != NULL)
  164. {
  165. DBGMSG(DBG_ERROR, ("DRPROV: NPOpenEnum invalid parameter\n"));
  166. Status = WN_BAD_VALUE;
  167. goto EXIT;
  168. }
  169. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  170. pEnum->dwScope = dwScope;
  171. pEnum->dwType = dwType;
  172. pEnum->dwUsage = dwUsage;
  173. pEnum->enumType = CONNECTION;
  174. pEnum->enumIndex = 0;
  175. Status = WN_SUCCESS;
  176. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_CONNECTED.\n"));
  177. goto EXIT;
  178. }
  179. else if (dwScope == RESOURCE_SHAREABLE)
  180. {
  181. //
  182. // We are looking for shareable resources
  183. // If we're not given a server, return an EMPTY_ENUM
  184. //
  185. if ((lpNetResource != NULL) &&
  186. (lpNetResource->lpRemoteName != NULL) &&
  187. (lpNetResource->lpRemoteName[0] == L'\\') &&
  188. (lpNetResource->lpRemoteName[1] == L'\\'))
  189. {
  190. //
  191. // Check if the lpRemoteName is what we recognize
  192. if (ValidateRemoteName(lpNetResource->lpRemoteName)) {
  193. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  194. pEnum->dwScope = dwScope;
  195. pEnum->dwType = dwType;
  196. pEnum->dwUsage = dwUsage;
  197. pEnum->enumType = SHARE;
  198. pEnum->enumIndex = 0;
  199. pEnum->RemoteName.MaximumLength =
  200. (wcslen(lpNetResource->lpRemoteName) + 1) * sizeof(WCHAR);
  201. pEnum->RemoteName.Buffer =
  202. MemAlloc(pEnum->RemoteName.MaximumLength);
  203. if (pEnum->RemoteName.Buffer) {
  204. pEnum->RemoteName.Length = pEnum->RemoteName.MaximumLength - sizeof(WCHAR);
  205. wcscpy(pEnum->RemoteName.Buffer, lpNetResource->lpRemoteName);
  206. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_SHARABLE for remote name: %ws\n",
  207. lpNetResource->lpRemoteName));
  208. Status = WN_SUCCESS;
  209. goto EXIT;
  210. }
  211. else {
  212. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, MemAlloc failed for RemoteName\n"));
  213. Status = WN_OUT_OF_MEMORY;
  214. goto EXIT;
  215. }
  216. }
  217. else {
  218. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_SHAREABLE, RemoteName: %ws not supported\n",
  219. lpNetResource->lpRemoteName));
  220. Status = WN_NOT_SUPPORTED;
  221. goto EXIT;
  222. }
  223. }
  224. else
  225. {
  226. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  227. pEnum->dwScope = dwScope;
  228. pEnum->dwType = dwType;
  229. pEnum->dwUsage = dwUsage;
  230. pEnum->enumType = EMPTY;
  231. pEnum->enumIndex = 0;
  232. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_SHAREABLE, NetResource empty\n"));
  233. Status = WN_SUCCESS;
  234. goto EXIT;
  235. }
  236. }
  237. else if (dwScope == RESOURCE_GLOBALNET)
  238. {
  239. /* Look for the combination of all bits and substitute "All" for
  240. * them. Ignore bits we don't know about.
  241. */
  242. dwUsage &= (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER);
  243. if ( dwUsage == (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER) )
  244. {
  245. dwUsage = 0 ;
  246. }
  247. /*
  248. * we are looking for global resources out on the net
  249. */
  250. if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL)
  251. {
  252. /*
  253. * at top level, therefore enumerating servers. if user
  254. * asked for connectable, well, there aint none.
  255. */
  256. if (dwUsage == RESOURCEUSAGE_CONNECTABLE)
  257. {
  258. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  259. pEnum->dwScope = dwScope;
  260. pEnum->dwType = dwType;
  261. pEnum->dwUsage = dwUsage;
  262. pEnum->enumType = EMPTY;
  263. pEnum->enumIndex = 0;
  264. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, empty node\n"));
  265. Status = WN_SUCCESS;
  266. goto EXIT;
  267. }
  268. else
  269. {
  270. // return server name, i.e. tsclient
  271. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  272. pEnum->dwScope = dwScope;
  273. pEnum->dwType = dwType;
  274. pEnum->dwUsage = dwUsage;
  275. pEnum->enumType = SERVER;
  276. pEnum->enumIndex = 0;
  277. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, enumerate server name.\n"));
  278. Status = WN_SUCCESS;
  279. goto EXIT;
  280. }
  281. }
  282. else
  283. {
  284. /*
  285. * we are assured of lpRemoteName != NULL.
  286. * things get interesting here. the cases are as follows:
  287. *
  288. * if (dwUsage == 0)
  289. * if have \\ in front
  290. * return shares
  291. * else
  292. * return empty enum
  293. * else if (dwUsage == CONNECTABLE)
  294. * if have \\ in front
  295. * return shares
  296. * else
  297. * empty enum
  298. * else if (dwUsage == CONTAINER)
  299. * if have \\ in front
  300. * empty enum
  301. * else
  302. * return empty enum
  303. *
  304. */
  305. if (((dwUsage == RESOURCEUSAGE_CONNECTABLE) || (dwUsage == 0)) &&
  306. ((lpNetResource->lpRemoteName[0] == L'\\') &&
  307. (lpNetResource->lpRemoteName[1] == L'\\')))
  308. {
  309. /* Confirm that this really is a computer name (i.e., a
  310. * container we can enumerate).
  311. */
  312. if (ValidateRemoteName(lpNetResource->lpRemoteName)) {
  313. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  314. pEnum->dwScope = dwScope;
  315. pEnum->dwType = dwType;
  316. pEnum->dwUsage = dwUsage;
  317. pEnum->enumType = SHARE;
  318. pEnum->enumIndex = 0;
  319. pEnum->RemoteName.MaximumLength =
  320. (wcslen(lpNetResource->lpRemoteName) + 1) * sizeof(WCHAR);
  321. pEnum->RemoteName.Buffer =
  322. MemAlloc(pEnum->RemoteName.MaximumLength);
  323. if (pEnum->RemoteName.Buffer) {
  324. pEnum->RemoteName.Length = pEnum->RemoteName.MaximumLength - sizeof(WCHAR);
  325. wcscpy(pEnum->RemoteName.Buffer, lpNetResource->lpRemoteName);
  326. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET for remote name: %ws\n",
  327. lpNetResource->lpRemoteName));
  328. Status = WN_SUCCESS;
  329. goto EXIT;
  330. }
  331. else {
  332. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, MemAlloc failed for RemoteName\n"));
  333. Status = WN_OUT_OF_MEMORY;
  334. goto EXIT;
  335. }
  336. }
  337. else {
  338. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, RemoteName: %ws not supported\n",
  339. lpNetResource->lpRemoteName));
  340. Status = WN_NOT_SUPPORTED;
  341. goto EXIT;
  342. }
  343. }
  344. else if (((dwUsage == RESOURCEUSAGE_CONTAINER) || (dwUsage == 0)) &&
  345. (lpNetResource->lpRemoteName[0] != L'\\'))
  346. {
  347. // return empty enum.
  348. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  349. pEnum->dwScope = dwScope;
  350. pEnum->dwType = dwType;
  351. pEnum->dwUsage = dwUsage;
  352. pEnum->enumType = EMPTY;
  353. pEnum->enumIndex = 0;
  354. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, empty node\n"));
  355. Status = WN_SUCCESS;
  356. goto EXIT;
  357. }
  358. else if (
  359. // ask for share but aint starting from server
  360. ((dwUsage == RESOURCEUSAGE_CONNECTABLE) &&
  361. (lpNetResource->lpRemoteName[0] != L'\\')) ||
  362. // ask for server but is starting from server
  363. ((dwUsage == RESOURCEUSAGE_CONTAINER) &&
  364. ((lpNetResource->lpRemoteName[0] == L'\\') &&
  365. (lpNetResource->lpRemoteName[1] == L'\\')))
  366. )
  367. {
  368. // return empty
  369. pEnum = (PRDPDR_ENUMERATION_HANDLE)(*lphEnum);
  370. pEnum->dwScope = dwScope;
  371. pEnum->dwType = dwType;
  372. pEnum->dwUsage = dwUsage;
  373. pEnum->enumType = EMPTY;
  374. pEnum->enumIndex = 0;
  375. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, RESOURCE_GLOBALNET, empty node\n"));
  376. Status = WN_SUCCESS;
  377. goto EXIT;
  378. }
  379. else
  380. {
  381. // incorrect dwUsage
  382. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, invalid dwUsage parameter\n"));
  383. Status = WN_BAD_VALUE;
  384. goto EXIT;
  385. }
  386. }
  387. }
  388. else
  389. {
  390. // invalid dwScope
  391. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, invalid dwScope parameter\n"));
  392. Status = WN_BAD_VALUE;
  393. goto EXIT;
  394. }
  395. EXIT:
  396. //
  397. // clean up enumeration handle in failure case
  398. if (Status != WN_SUCCESS && lphEnum != NULL && *lphEnum != NULL) {
  399. MemFree(*lphEnum);
  400. *lphEnum = NULL;
  401. }
  402. DBGMSG(DBG_TRACE, ("DRPROV: NPOpenEnum, return status: %x\n", Status));
  403. return Status;
  404. }
  405. DWORD APIENTRY
  406. NPEnumResource(
  407. HANDLE hEnum,
  408. LPDWORD lpcCount,
  409. LPVOID lpBuffer,
  410. LPDWORD lpBufferSize)
  411. /*++
  412. Routine Description:
  413. This routine uses the handle obtained by a call to NPOpenEnum for
  414. enuerating the connected shares
  415. Arguments:
  416. hEnum - the enumeration handle
  417. lpcCount - the number of resources returned
  418. lpBuffer - the buffere for passing back the entries
  419. lpBufferSize - the size of the buffer
  420. Return Value:
  421. WN_SUCCESS if successful, otherwise the appropriate error
  422. WN_NO_MORE_ENTRIES - if the enumeration has exhausted the entries
  423. WN_MORE_DATA - if nmore data is available
  424. --*/
  425. {
  426. DWORD status = WN_SUCCESS;
  427. LPNETRESOURCEW pBufferResource;
  428. PRDPDR_ENUMERATION_HANDLE pEnumHandle;
  429. pEnumHandle = (PRDPDR_ENUMERATION_HANDLE)hEnum;
  430. pBufferResource = (LPNETRESOURCEW)lpBuffer;
  431. if (lpcCount == NULL || lpBuffer == NULL || lpBufferSize == NULL) {
  432. DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, Invalid parameter(s)\n"));
  433. status = WN_BAD_VALUE;
  434. goto EXIT;
  435. }
  436. if (pEnumHandle != NULL) {
  437. DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, EnumType: %d\n", pEnumHandle->enumType));
  438. if ( pEnumHandle->enumType == SERVER ) {
  439. status = DrEnumServerInfo(pEnumHandle, lpcCount, pBufferResource, lpBufferSize);
  440. goto EXIT;
  441. }
  442. else if ( pEnumHandle->enumType == SHARE ) {
  443. status = DrEnumShareInfo(pEnumHandle, lpcCount, pBufferResource, lpBufferSize);
  444. goto EXIT;
  445. }
  446. else if ( pEnumHandle->enumType == CONNECTION ) {
  447. status = DrEnumConnectionInfo(pEnumHandle, lpcCount, pBufferResource, lpBufferSize);
  448. goto EXIT;
  449. }
  450. else if ( pEnumHandle->enumType == EMPTY) {
  451. status = WN_NO_MORE_ENTRIES;
  452. goto EXIT;
  453. }
  454. else {
  455. DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, invalid enum type\n"));
  456. status = WN_BAD_HANDLE;
  457. goto EXIT;
  458. }
  459. }
  460. else {
  461. DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, NULL enum handle\n"));
  462. status = WN_BAD_HANDLE;
  463. goto EXIT;
  464. }
  465. EXIT:
  466. DBGMSG(DBG_TRACE, ("DRPROV: NPEnumResource, return status: %x\n", status));
  467. return status;
  468. }
  469. DWORD APIENTRY
  470. NPCloseEnum(
  471. HANDLE hEnum )
  472. /*++
  473. Routine Description:
  474. This routine closes the handle for enumeration of resources.
  475. Arguments:
  476. hEnum - the enumeration handle
  477. Return Value:
  478. WN_SUCCESS if successful, otherwise the appropriate error
  479. --*/
  480. {
  481. DWORD Status = WN_SUCCESS;
  482. DBGMSG(DBG_TRACE, ("DRPROV: NPCloseEnum, handle: %p\n", hEnum));
  483. if (hEnum != NULL) {
  484. PRDPDR_ENUMERATION_HANDLE pEnumHandle = (PRDPDR_ENUMERATION_HANDLE)hEnum;
  485. // free the enumeration buffer
  486. if (pEnumHandle->pEnumBuffer != NULL) {
  487. MemFree(pEnumHandle->pEnumBuffer);
  488. }
  489. // free the remote name
  490. if (pEnumHandle->RemoteName.Buffer != NULL) {
  491. MemFree(pEnumHandle->RemoteName.Buffer);
  492. }
  493. // free the enum handle
  494. MemFree(hEnum);
  495. hEnum = NULL;
  496. }
  497. Status = WN_SUCCESS;
  498. return Status;
  499. }
  500. DWORD
  501. OpenConnection(
  502. PUNICODE_STRING pConnectionName,
  503. DWORD Disposition,
  504. DWORD CreateOption,
  505. PFILE_FULL_EA_INFORMATION pEABuffer,
  506. DWORD EABufferLength,
  507. PHANDLE pConnectionHandle )
  508. /*++
  509. Routine Description:
  510. This routine opens the connection. This routine is shared by NpAddConnection
  511. and NPCancelConnection
  512. Arguments:
  513. pConnectionName - the connection name
  514. Disposition - the Open disposition
  515. CreateOption - the create option
  516. pEABuffer - the EA buffer associated with the open
  517. EABufferLength - the EA buffer length
  518. pConnectionHandle - the placeholder for the connection handle
  519. Return Value:
  520. WN_SUCCESS if successful, otherwise the appropriate error
  521. Notes:
  522. --*/
  523. {
  524. NTSTATUS Status;
  525. DWORD NPStatus;
  526. IO_STATUS_BLOCK IoStatusBlock;
  527. OBJECT_ATTRIBUTES ConnectionObjectAttributes;
  528. DBGMSG(DBG_TRACE, ("DRPROV: OpenConnection, connectionName: %ws\n",
  529. pConnectionName->Buffer));
  530. ASSERT(pConnectionName != NULL);
  531. ASSERT(pConnectionHandle != NULL);
  532. InitializeObjectAttributes(
  533. &ConnectionObjectAttributes,
  534. pConnectionName,
  535. OBJ_CASE_INSENSITIVE,
  536. NULL,
  537. NULL);
  538. Status = NtCreateFile(
  539. pConnectionHandle,
  540. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  541. &ConnectionObjectAttributes,
  542. &IoStatusBlock,
  543. NULL,
  544. FILE_ATTRIBUTE_NORMAL,
  545. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  546. Disposition,
  547. CreateOption,
  548. pEABuffer,
  549. EABufferLength);
  550. DBGMSG(DBG_TRACE, ("DRPROV: OpenConnection, NtCreateFile status: %x\n", Status));
  551. if (Status != STATUS_SUCCESS) {
  552. NPStatus = ERROR_BAD_NETPATH;
  553. }
  554. else {
  555. NPStatus = WN_SUCCESS;
  556. }
  557. return NPStatus;
  558. }
  559. DWORD
  560. CreateConnectionName(
  561. PWCHAR pLocalName,
  562. PWCHAR pRemoteName,
  563. PUNICODE_STRING pConnectionName)
  564. /*++
  565. Routine Description:
  566. This routine create connection name from the remote name
  567. Arguments:
  568. pLocalName - the local name for the connection
  569. pRemoteName - the UNC remote name
  570. pConnectionName - the connection name used to talk to mini redirector
  571. Return Value:
  572. WN_SUCCESS if successful, otherwise the appropriate error
  573. Notes:
  574. --*/
  575. {
  576. DWORD status;
  577. DWORD LocalNameLength,RemoteNameLength;
  578. DWORD dwSessionId;
  579. WCHAR pSessionId[16];
  580. WCHAR LocalName[MAX_PATH + 1];
  581. ASSERT(pRemoteName != NULL);
  582. ASSERT(pConnectionName != NULL);
  583. DBGMSG(DBG_TRACE, ("DRPROV: CreateConnectionName, RemoteName: %ws\n",
  584. pRemoteName));
  585. if (pLocalName != NULL) {
  586. DBGMSG(DBG_TRACE, ("DRPROV: CreateConnection Name, LocalName: %ws\n",
  587. pLocalName));
  588. }
  589. //
  590. // The remote name is in the UNC format \\Server\Share. This name
  591. // needs to be translated to an appropriate NT name in order to
  592. // issue the request to the underlying mini redirector to create the
  593. // connection.
  594. //
  595. // The NT style name is of the form
  596. //
  597. // \device\rdpdr\;<DriveLetter>:<sessionid>\Server\Share
  598. //
  599. // The additional ; is required by the new RDR for extensibility.
  600. //
  601. // skip past the first back slash since the name to be appended for the
  602. // NT name does not require this.
  603. pRemoteName++;
  604. RemoteNameLength = wcslen(pRemoteName) * sizeof(WCHAR);
  605. if (pLocalName != NULL) {
  606. // Local name should not be greater than MAX_PATH;
  607. LocalNameLength = wcslen(pLocalName) * sizeof(WCHAR);
  608. if (LocalNameLength <= MAX_PATH * sizeof(WCHAR)) {
  609. wcscpy(LocalName, pLocalName);
  610. }
  611. else {
  612. wcsncpy(LocalName, pLocalName, MAX_PATH);
  613. LocalName[MAX_PATH] = L'\0';
  614. }
  615. // remove the trailing : in localname if there is one
  616. if (LocalName[LocalNameLength/sizeof(WCHAR) - 1] == L':') {
  617. LocalName[LocalNameLength/sizeof(WCHAR) - 1] = L'\0';
  618. LocalNameLength -= sizeof(WCHAR);
  619. }
  620. } else {
  621. LocalNameLength = 0;
  622. }
  623. //
  624. // Get SessionId
  625. //
  626. dwSessionId = NtCurrentPeb()->SessionId;
  627. swprintf(pSessionId, L"%d", dwSessionId);
  628. pConnectionName->MaximumLength = (USHORT)(DrDeviceName.Length +
  629. RemoteNameLength + LocalNameLength +
  630. sizeof(WCHAR) * 3 + // account for \; and :
  631. wcslen(pSessionId) * sizeof(WCHAR) +
  632. sizeof(WCHAR)); // account of terminator null
  633. pConnectionName->Buffer = MemAlloc(pConnectionName->MaximumLength);
  634. if (pConnectionName->Buffer == NULL) {
  635. DBGMSG(DBG_TRACE, ("DRPROV: CreateConnectionName, MemAlloc failed\n"));
  636. status = WN_OUT_OF_MEMORY;
  637. goto EXIT;
  638. }
  639. // Copy the name into the buffer
  640. pConnectionName->Length = 0;
  641. pConnectionName->Buffer[0] = L'\0';
  642. RtlAppendUnicodeToString(pConnectionName, DrDeviceName.Buffer);
  643. RtlAppendUnicodeToString(pConnectionName, L"\\;");
  644. if (LocalNameLength != 0) {
  645. RtlAppendUnicodeToString(pConnectionName, LocalName);
  646. }
  647. RtlAppendUnicodeToString(pConnectionName, L":");
  648. RtlAppendUnicodeToString(pConnectionName, pSessionId);
  649. RtlAppendUnicodeToString(pConnectionName, pRemoteName);
  650. DBGMSG(DBG_TRACE, ("DRPROV: CreateConnectionName, %wZ\n", pConnectionName));
  651. status = WN_SUCCESS;
  652. EXIT:
  653. return status;
  654. }
  655. BOOL ValidateRemoteName(PWCHAR pRemoteName)
  656. /*++
  657. Routine Description:
  658. This routine checks if the remote name belongs to our provider
  659. Arguments:
  660. pRemoteName - the UNC remote name
  661. Return Value:
  662. TRUE if the remote name belongs to our provider, otherwise FALSE
  663. Notes:
  664. --*/
  665. {
  666. BOOL rc = FALSE;
  667. DWORD status;
  668. RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
  669. HANDLE DrDeviceHandle = INVALID_HANDLE_VALUE;
  670. LPBYTE Buffer = NULL;
  671. PRDPDR_SERVER_INFO pServerEntry;
  672. if (DrOpenMiniRdr(&DrDeviceHandle) != WN_SUCCESS) {
  673. //
  674. // MPR doesn't like return device error in this case
  675. // We'll just return 0 entries
  676. //
  677. DBGMSG(DBG_TRACE, ("DRPROV: ValidateRemoteName, DrOpenMiniRdr failed\n"));
  678. DrDeviceHandle = INVALID_HANDLE_VALUE;
  679. goto EXIT;
  680. }
  681. //
  682. // Ask the redirector to enumerate the information of server
  683. // established by the caller.
  684. //
  685. Rrp.SessionId = NtCurrentPeb()->SessionId;
  686. Rrp.Parameters.Get.ResumeHandle = 0;
  687. //
  688. // Make the request to the Redirector
  689. //
  690. status = DrDeviceControlGetInfo(DrDeviceHandle,
  691. FSCTL_DR_ENUMERATE_SERVERS,
  692. &Rrp,
  693. sizeof(RDPDR_REQUEST_PACKET),
  694. (LPBYTE *) &Buffer,
  695. MAXULONG,
  696. 0,
  697. NULL);
  698. if (status == WN_SUCCESS) {
  699. UNICODE_STRING ServerName;
  700. pServerEntry = ((PRDPDR_SERVER_INFO) Buffer);
  701. ServerName.Length = pServerEntry->ServerName.Length;
  702. ServerName.MaximumLength = pServerEntry->ServerName.MaximumLength;
  703. ServerName.Buffer = (PWCHAR)((PCHAR)(pServerEntry) + pServerEntry->ServerName.BufferOffset);
  704. if ((wcslen(pRemoteName) == ServerName.Length / sizeof(WCHAR)) &&
  705. _wcsnicmp(pRemoteName, ServerName.Buffer,
  706. ServerName.Length/sizeof(WCHAR)) == 0) {
  707. rc = TRUE;
  708. }
  709. else {
  710. DBGMSG(DBG_TRACE, ("DRPROV: ValidateRemoteName, remote name not for drprov, %wZ\n",
  711. pRemoteName));
  712. goto EXIT;
  713. }
  714. }
  715. else {
  716. DBGMSG(DBG_TRACE, ("DRENUM: ValidateRemoteName, DrDeviceControlGetInfo failed, %x\n", status));
  717. goto EXIT;
  718. }
  719. EXIT:
  720. if (DrDeviceHandle != INVALID_HANDLE_VALUE) {
  721. CloseHandle(DrDeviceHandle);
  722. }
  723. if (Buffer != NULL) {
  724. MemFree(Buffer);
  725. }
  726. DBGMSG(DBG_TRACE, ("DRPROV: ValidateRemoteName, return, %d\n", rc));
  727. return rc;
  728. }
  729. DWORD APIENTRY
  730. NPAddConnection(
  731. LPNETRESOURCE lpNetResource,
  732. LPWSTR lpPassword,
  733. LPWSTR lpUserName )
  734. /*++
  735. Routine Description:
  736. This routine adds a connection to the list of connections associated
  737. with this network provider
  738. Arguments:
  739. lpNetResource - the NETRESOURCE struct
  740. lpPassword - the password
  741. lpUserName - the user name
  742. Return Value:
  743. WN_SUCCESS if successful, otherwise the appropriate error
  744. Notes:
  745. --*/
  746. {
  747. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection.\n"));
  748. return NPAddConnection3(NULL, lpNetResource, lpPassword, lpUserName, 0);
  749. }
  750. DWORD
  751. TestAddConnection(
  752. LPNETRESOURCE lpNetResource)
  753. /*++
  754. Routine Description:
  755. This routine tests adding a connection to the list of connections associated
  756. with this network provider
  757. Arguments:
  758. lpNetResource - the NETRESOURCE struct
  759. Return Value:
  760. WN_SUCCESS if successful, otherwise the appropriate error
  761. --*/
  762. {
  763. DWORD Status = 0;
  764. UNICODE_STRING ConnectionName;
  765. HANDLE ConnectionHandle = INVALID_HANDLE_VALUE;
  766. PWCHAR pRemoteName;
  767. DBGMSG(DBG_TRACE, ("DRPROV: TestAddConnection\n"));
  768. pRemoteName = lpNetResource->lpRemoteName;
  769. // Create ConnectionName with NULL local name
  770. Status = CreateConnectionName(NULL, pRemoteName, &ConnectionName);
  771. if (Status != WN_SUCCESS) {
  772. DBGMSG(DBG_TRACE, ("DRPROV: TestAddConnection, CreateConnectName failed\n"));
  773. goto EXIT;
  774. }
  775. Status = OpenConnection(
  776. &ConnectionName,
  777. FILE_OPEN,
  778. (FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
  779. NULL,
  780. 0,
  781. &ConnectionHandle);
  782. if (Status != WN_SUCCESS) {
  783. ConnectionHandle = INVALID_HANDLE_VALUE;
  784. goto EXIT;
  785. }
  786. EXIT:
  787. if (ConnectionHandle != INVALID_HANDLE_VALUE) {
  788. NtClose(ConnectionHandle);
  789. ConnectionHandle = INVALID_HANDLE_VALUE;
  790. }
  791. if (ConnectionName.Buffer != NULL) {
  792. MemFree(ConnectionName.Buffer);
  793. ConnectionName.Buffer = NULL;
  794. }
  795. return Status;
  796. }
  797. DWORD APIENTRY
  798. NPAddConnection3(
  799. HWND hwndOwner,
  800. LPNETRESOURCE lpNetResource,
  801. LPWSTR lpPassword,
  802. LPWSTR lpUserName,
  803. DWORD dwFlags )
  804. /*++
  805. Routine Description:
  806. This routine adds a connection to the list of connections associated
  807. with this network provider
  808. Arguments:
  809. hwndOwner - the owner handle
  810. lpNetResource - the NETRESOURCE struct
  811. lpPassword - the password
  812. lpUserName - the user name
  813. dwFlags - flags for the connection
  814. Return Value:
  815. WN_SUCCESS if successful, otherwise the appropriate error
  816. Notes:
  817. // JOYC: do we need to pass credential to the redirector?
  818. // Seems the sessionId verification is enough
  819. --*/
  820. {
  821. DWORD Status = 0;
  822. UNICODE_STRING ConnectionName;
  823. HANDLE ConnectionHandle;
  824. PWCHAR pLocalName,pRemoteName;
  825. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection 3.\n"));
  826. ConnectionName.Buffer = NULL;
  827. ConnectionName.Length = 0;
  828. ConnectionHandle = INVALID_HANDLE_VALUE;
  829. //
  830. // Make sure remote name starts with \\
  831. //
  832. if ((lpNetResource == NULL) ||
  833. (lpNetResource->lpRemoteName == NULL) ||
  834. (lpNetResource->lpRemoteName[0] != L'\\') ||
  835. (lpNetResource->lpRemoteName[1] != L'\\')) {
  836. DBGMSG(DBG_TRACE, ("DRPROV: invalid lpNetResource parameter.\n"));
  837. Status = WN_BAD_NETNAME;
  838. goto EXIT;
  839. }
  840. //
  841. // The remote name is in the UNC format \\Server\Share. This name
  842. // needs to be translated to an appropriate NT name in order to
  843. // issue the request to the underlying mini redirector to create the
  844. // connection.
  845. //
  846. // The NT style name is of the form
  847. //
  848. // \device\rdpdr\;<DriveLetter>:<sessionid>\Server\Share
  849. //
  850. // The additional ; is required by the new RDR for extensibility.
  851. //
  852. // Test if rdpdr provider recognize this remote name or not
  853. Status = TestAddConnection(lpNetResource);
  854. if (Status != WN_SUCCESS) {
  855. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, TestAddConnection failed\n"));
  856. goto EXIT;
  857. }
  858. pLocalName = lpNetResource->lpLocalName;
  859. pRemoteName = lpNetResource->lpRemoteName;
  860. Status = CreateConnectionName(pLocalName, pRemoteName, &ConnectionName);
  861. if (Status != WN_SUCCESS) {
  862. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, CreateConnectName failed\n"));
  863. goto EXIT;
  864. }
  865. if ((Status == WN_SUCCESS) && (pLocalName != NULL)) {
  866. WCHAR TempBuf[64];
  867. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, create dos symbolic link\n"));
  868. if (!QueryDosDeviceW(pLocalName, TempBuf, 64)) {
  869. if (GetLastError() == ERROR_FILE_NOT_FOUND) {
  870. //
  871. // ERROR_FILE_NOT_FOUND (translated from OBJECT_NAME_NOT_FOUND)
  872. // means it does not exist and we can redirect this device.
  873. goto Done;
  874. }
  875. else {
  876. //
  877. // Most likely failure occurred because our output
  878. // buffer is too small. It still means someone already
  879. // has an existing symbolic link for this device.
  880. //
  881. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, DosName already assigned, %ws\n",
  882. pLocalName));
  883. Status = ERROR_ALREADY_ASSIGNED;
  884. goto EXIT;
  885. }
  886. }
  887. else {
  888. //
  889. // QueryDosDevice successfully an existing symbolic link--
  890. // somebody is already using this device.
  891. //
  892. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, DosName already assigned, %ws\n",
  893. pLocalName));
  894. Status = ERROR_ALREADY_ASSIGNED;
  895. goto EXIT;
  896. }
  897. }
  898. Done:
  899. //
  900. // We are not doing anything with username/password
  901. //
  902. Status = OpenConnection(
  903. &ConnectionName,
  904. FILE_OPEN,
  905. (FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
  906. NULL,
  907. 0,
  908. &ConnectionHandle);
  909. if (Status != WN_SUCCESS) {
  910. ConnectionHandle = INVALID_HANDLE_VALUE;
  911. }
  912. else {
  913. //
  914. // Create a symbolic link object to the device we are redirecting
  915. //
  916. if (DefineDosDeviceW(
  917. DDD_RAW_TARGET_PATH |
  918. DDD_NO_BROADCAST_SYSTEM,
  919. pLocalName,
  920. ConnectionName.Buffer)) {
  921. Status = WN_SUCCESS;
  922. }
  923. else {
  924. Status = GetLastError();
  925. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, failed DefineDosDeviceW, %x.\n",
  926. Status));
  927. goto EXIT;
  928. }
  929. }
  930. EXIT:
  931. if (ConnectionHandle != INVALID_HANDLE_VALUE) {
  932. NtClose(ConnectionHandle);
  933. }
  934. if (ConnectionName.Buffer != NULL) {
  935. MemFree(ConnectionName.Buffer);
  936. }
  937. DBGMSG(DBG_TRACE, ("DRPROV: NPAddConnection3, return status: %x\n", Status));
  938. return Status;
  939. }
  940. DWORD APIENTRY
  941. NPCancelConnection(
  942. LPWSTR lpName,
  943. BOOL fForce )
  944. /*++
  945. Routine Description:
  946. This routine cancels ( deletes ) a connection from the list of connections
  947. associated with this network provider
  948. Arguments:
  949. lpName - name of the connection
  950. fForce - forcefully delete the connection
  951. Return Value:
  952. WN_SUCCESS if successful, otherwise the appropriate error
  953. Notes:
  954. --*/
  955. {
  956. BOOL bLocalName = FALSE;
  957. DWORD Status = 0;
  958. NTSTATUS ntStatus;
  959. HANDLE ConnectionHandle;
  960. IO_STATUS_BLOCK IoStatusBlock;
  961. UNICODE_STRING ConnectionName;
  962. WCHAR TargetPath[MAX_PATH + 1];
  963. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection.\n"));
  964. ConnectionName.Buffer = NULL;
  965. ConnectionName.Length = 0;
  966. ConnectionHandle = INVALID_HANDLE_VALUE;
  967. // lpName should contain at least two characters: either two back slashes or dos name
  968. if (lpName == NULL || wcslen(lpName) == 0) {
  969. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, invalid lpName parameter.\n"));
  970. Status = WN_BAD_VALUE;
  971. goto EXIT;
  972. }
  973. // We get the UNC name
  974. if (*lpName == L'\\' && *(lpName + 1) == L'\\') {
  975. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, lpName is UNC name, %ws.\n", *lpName));
  976. bLocalName = FALSE;
  977. // Setup the NT Device Name
  978. Status = CreateConnectionName(NULL, lpName, &ConnectionName);
  979. if (Status != WN_SUCCESS) {
  980. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, CreateConnectName failed\n"));
  981. goto EXIT;
  982. }
  983. }
  984. // We get the local name
  985. else {
  986. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, lpName is local name, %ws.\n", *lpName));
  987. bLocalName = TRUE;
  988. // Find the NT devive path
  989. if (QueryDosDevice(lpName, TargetPath, sizeof(TargetPath)/sizeof(WCHAR) - 1)) {
  990. ConnectionName.Length = wcslen(TargetPath) * sizeof(WCHAR);
  991. ConnectionName.MaximumLength = ConnectionName.Length + sizeof(WCHAR);
  992. ConnectionName.Buffer = TargetPath;
  993. }
  994. else {
  995. Status = WN_BAD_NETNAME;
  996. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, QueryDosDevice failed, %x.\n", Status));
  997. goto EXIT;
  998. }
  999. }
  1000. Status = OpenConnection(
  1001. &ConnectionName,
  1002. FILE_OPEN,
  1003. (FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
  1004. NULL,
  1005. 0,
  1006. &ConnectionHandle);
  1007. if (Status == WN_SUCCESS) {
  1008. // Request the driver to delete the connection entry
  1009. ntStatus = NtFsControlFile(
  1010. ConnectionHandle,
  1011. NULL,
  1012. NULL,
  1013. NULL,
  1014. &IoStatusBlock,
  1015. FSCTL_DR_DELETE_CONNECTION,
  1016. NULL,
  1017. 0,
  1018. NULL,
  1019. 0);
  1020. if (ntStatus == STATUS_SUCCESS) {
  1021. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, Deleting dos symbolic link, %ws\n", lpName));
  1022. if (bLocalName) {
  1023. if (DefineDosDevice(
  1024. DDD_REMOVE_DEFINITION | DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE,
  1025. lpName,
  1026. ConnectionName.Buffer)) {
  1027. Status = WN_SUCCESS;
  1028. goto EXIT;
  1029. }
  1030. else {
  1031. Status = GetLastError();
  1032. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection failed to delete symbolic link, %x.\n",
  1033. Status));
  1034. goto EXIT;
  1035. }
  1036. }
  1037. }
  1038. else {
  1039. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, failed NtFsControlFile, %x\n", ntStatus));
  1040. Status = WN_BAD_NETNAME;
  1041. goto EXIT;
  1042. }
  1043. }
  1044. else {
  1045. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, OpenConnection %wZ failed, %x\n",
  1046. &ConnectionName, Status));
  1047. ConnectionHandle = INVALID_HANDLE_VALUE;
  1048. Status = WN_BAD_NETNAME;
  1049. goto EXIT;
  1050. }
  1051. EXIT:
  1052. if (bLocalName != TRUE && ConnectionName.Buffer != NULL) {
  1053. MemFree(ConnectionName.Buffer);
  1054. }
  1055. if (ConnectionHandle != INVALID_HANDLE_VALUE) {
  1056. NtClose(ConnectionHandle);
  1057. }
  1058. DBGMSG(DBG_TRACE, ("DRPROV: NPCancelConnection, return status: %x\n", Status));
  1059. return Status;
  1060. }
  1061. DWORD APIENTRY
  1062. NPGetConnection(
  1063. LPWSTR lpLocalName,
  1064. LPWSTR lpRemoteName,
  1065. LPDWORD lpBufferSize )
  1066. /*++
  1067. Routine Description:
  1068. This routine returns the information associated with a connection
  1069. Arguments:
  1070. lpLocalName - local name associated with the connection
  1071. lpRemoteName - the remote name associated with the connection
  1072. lpBufferSize - the remote name buffer size
  1073. Return Value:
  1074. WN_SUCCESS if successful, otherwise the appropriate error
  1075. Notes:
  1076. --*/
  1077. {
  1078. DWORD Status = 0;
  1079. NTSTATUS ntStatus;
  1080. HANDLE ConnectionHandle;
  1081. RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
  1082. UNICODE_STRING ConnectionName;
  1083. WCHAR TargetPath[MAX_PATH + 1];
  1084. LPBYTE Buffer = NULL;
  1085. PRDPDR_CONNECTION_INFO ConnectionInfo;
  1086. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection.\n"));
  1087. ConnectionName.Buffer = NULL;
  1088. ConnectionName.Length = 0;
  1089. ConnectionHandle = INVALID_HANDLE_VALUE;
  1090. if (lpLocalName == NULL || lpRemoteName == NULL || lpBufferSize == NULL) {
  1091. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, invalid parameter(s).\n"));
  1092. Status = WN_BAD_VALUE;
  1093. goto EXIT;
  1094. }
  1095. // Find the NT devive path
  1096. if (QueryDosDevice(lpLocalName, TargetPath, sizeof(TargetPath)/sizeof(WCHAR) - 1)) {
  1097. ConnectionName.Length = wcslen(TargetPath) * sizeof(WCHAR);
  1098. ConnectionName.MaximumLength = ConnectionName.Length + sizeof(WCHAR);
  1099. ConnectionName.Buffer = TargetPath;
  1100. }
  1101. else {
  1102. Status = GetLastError();
  1103. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, querydosdevice failed, %x\n", Status));
  1104. goto EXIT;
  1105. }
  1106. // Check if this connection belongs to rdpdr
  1107. if (wcsstr(TargetPath, RDPDR_DEVICE_NAME_U) != NULL) {
  1108. Status = OpenConnection(
  1109. &ConnectionName,
  1110. FILE_OPEN,
  1111. (FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
  1112. NULL,
  1113. 0,
  1114. &ConnectionHandle);
  1115. if (Status == WN_SUCCESS) {
  1116. // Request the driver to retrieve the connection entry info
  1117. Rrp.SessionId = NtCurrentPeb()->SessionId;
  1118. Rrp.Parameters.Get.ResumeHandle = 0;
  1119. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, call DrDeviceControlGetInfo\n"));
  1120. //
  1121. // Make the request to the Redirector
  1122. //
  1123. if (DrDeviceControlGetInfo(
  1124. ConnectionHandle,
  1125. FSCTL_DR_GET_CONNECTION_INFO,
  1126. &Rrp,
  1127. sizeof(RDPDR_REQUEST_PACKET),
  1128. (LPBYTE *) &Buffer,
  1129. MAXULONG,
  1130. 0,
  1131. NULL
  1132. ) == WN_SUCCESS) {
  1133. UNICODE_STRING RemoteName;
  1134. ConnectionInfo = (PRDPDR_CONNECTION_INFO)Buffer;
  1135. RemoteName.Length = ConnectionInfo->RemoteName.Length;
  1136. RemoteName.MaximumLength = ConnectionInfo->RemoteName.MaximumLength;
  1137. RemoteName.Buffer = (PWCHAR)((PCHAR)(ConnectionInfo) +
  1138. ConnectionInfo->RemoteName.BufferOffset);
  1139. if (*lpBufferSize > RemoteName.Length) {
  1140. *lpBufferSize = RemoteName.Length + sizeof(WCHAR);
  1141. RtlCopyMemory(
  1142. lpRemoteName,
  1143. RemoteName.Buffer,
  1144. RemoteName.Length);
  1145. lpRemoteName[RemoteName.Length/sizeof(WCHAR)] = L'\0';
  1146. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, remote name %ws\n", lpRemoteName));
  1147. Status = WN_SUCCESS;
  1148. goto EXIT;
  1149. }
  1150. else {
  1151. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, buffer too small\n"));
  1152. *lpBufferSize = RemoteName.Length + sizeof(WCHAR);
  1153. Status = WN_MORE_DATA;
  1154. goto EXIT;
  1155. }
  1156. }
  1157. else {
  1158. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, DrDeviceControlGetInfo failed\n"));
  1159. Status = WN_BAD_NETNAME;
  1160. goto EXIT;
  1161. }
  1162. }
  1163. else {
  1164. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, OpenConnection failed, %x\n", Status));
  1165. ConnectionHandle = INVALID_HANDLE_VALUE;
  1166. Status = WN_BAD_NETNAME;
  1167. goto EXIT;
  1168. }
  1169. }
  1170. else {
  1171. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, DrDeviceControlGetInfo failed\n"));
  1172. Status = WN_BAD_NETNAME;
  1173. goto EXIT;
  1174. }
  1175. EXIT:
  1176. if (ConnectionHandle != INVALID_HANDLE_VALUE) {
  1177. NtClose(ConnectionHandle);
  1178. }
  1179. if (Buffer != NULL) {
  1180. MemFree(Buffer);
  1181. }
  1182. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection, return status: %x\n", Status));
  1183. return Status;
  1184. }
  1185. DWORD APIENTRY
  1186. NPGetResourceParent(
  1187. LPNETRESOURCE lpNetResource,
  1188. LPVOID lpBuffer,
  1189. LPDWORD lpBufferSize )
  1190. /*++
  1191. Routine Description:
  1192. This routine returns the parent of a given resource
  1193. Arguments:
  1194. lpNetResource - the NETRESOURCE struct
  1195. lpBuffer - the buffer for passing back the parent information
  1196. lpBufferSize - the buffer size
  1197. Return Value:
  1198. WN_NOT_SUPPORTED
  1199. Notes:
  1200. The current sample does not handle this call.
  1201. --*/
  1202. {
  1203. //
  1204. // JOYC: Need to support this?
  1205. //
  1206. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceParent.\n"));
  1207. return WN_NOT_SUPPORTED;
  1208. }
  1209. DWORD APIENTRY
  1210. NPGetResourceInformation(
  1211. LPNETRESOURCE lpNetResource,
  1212. LPVOID lpBuffer,
  1213. LPDWORD lpBufferSize,
  1214. LPWSTR *lplpSystem )
  1215. /*++
  1216. Routine Description:
  1217. This routine returns the information associated net resource
  1218. Arguments:
  1219. lpNetResource - the NETRESOURCE struct
  1220. lpBuffer - the buffer for passing back the resource information
  1221. lpBufferSize - the buffer size
  1222. lplpSystem -
  1223. Return Value:
  1224. Notes:
  1225. --*/
  1226. {
  1227. DWORD Status = 0;
  1228. LPNETRESOURCE pOutNetResource;
  1229. UNICODE_STRING RemoteName;
  1230. UNICODE_STRING SystemPath;
  1231. BOOL fResourceTypeDisk = FALSE ;
  1232. WORD wSlashCount = 0;
  1233. BYTE *BufferResourceStart, *BufferResourceEnd;
  1234. PWCHAR pCurPos;
  1235. DBGMSG(DBG_TRACE, ("DRPROV: NPGetConnection.\n"));
  1236. RemoteName.Buffer = NULL;
  1237. RemoteName.Length = RemoteName.MaximumLength = 0;
  1238. if (lpBuffer == NULL || lpBufferSize == NULL) {
  1239. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, invalid parameter(s).\n"));
  1240. Status = WN_BAD_VALUE;
  1241. goto EXIT;
  1242. }
  1243. pOutNetResource = (LPNETRESOURCE)lpBuffer;
  1244. BufferResourceStart = (PBYTE)lpBuffer;
  1245. BufferResourceEnd = ((PBYTE)(pOutNetResource)) + *lpBufferSize;
  1246. SystemPath.Buffer = NULL;
  1247. SystemPath.Length = SystemPath.MaximumLength = 0;
  1248. //
  1249. // JOYC: Do we need to check if we are the right provider from lpProvider?
  1250. // And the dwType?
  1251. //
  1252. if (lpNetResource == NULL || lpNetResource->lpRemoteName == NULL) {
  1253. if (*lpBufferSize >= sizeof(NETRESOURCEW)) {
  1254. //
  1255. // Handle this as if we are at the root of our provider hierarchy.
  1256. //
  1257. pOutNetResource->dwScope = RESOURCE_GLOBALNET;
  1258. pOutNetResource->dwType = RESOURCETYPE_ANY;
  1259. pOutNetResource->dwDisplayType = RESOURCEDISPLAYTYPE_NETWORK;
  1260. pOutNetResource->dwUsage = RESOURCEUSAGE_CONTAINER;
  1261. pOutNetResource->lpLocalName = NULL;
  1262. pOutNetResource->lpRemoteName = NULL;
  1263. // JOYC: need to set this to our provider?
  1264. pOutNetResource->lpProvider = NULL;
  1265. pOutNetResource->lpComment = NULL;
  1266. *lpBufferSize = sizeof(NETRESOURCEW);
  1267. if (lplpSystem) {
  1268. *lplpSystem = NULL;
  1269. }
  1270. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, NULL remote Name\n"));
  1271. Status = WN_SUCCESS;
  1272. goto EXIT;
  1273. }
  1274. else {
  1275. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, buffer too small.\n"));
  1276. *lpBufferSize = sizeof(NETRESOURCEW);
  1277. Status = WN_MORE_DATA;
  1278. goto EXIT;
  1279. }
  1280. }
  1281. //
  1282. // Find out if we are looking at a \\server, \\server\vol, or
  1283. // \\server\vol\dir . . .
  1284. //
  1285. wSlashCount = 0;
  1286. pCurPos = lpNetResource->lpRemoteName;
  1287. while (*pCurPos != '\0') {
  1288. if (*pCurPos == L'\\') {
  1289. wSlashCount++;
  1290. }
  1291. // Get the system path
  1292. if (wSlashCount == 4) {
  1293. SystemPath.Buffer = pCurPos;
  1294. SystemPath.Length =
  1295. (USHORT) (wcslen(lpNetResource->lpRemoteName) * sizeof(WCHAR) -
  1296. (SystemPath.Buffer - lpNetResource->lpRemoteName) * sizeof(WCHAR));
  1297. SystemPath.MaximumLength = SystemPath.Length + sizeof(WCHAR);
  1298. break;
  1299. }
  1300. pCurPos++;
  1301. }
  1302. if ( wSlashCount > 2 )
  1303. fResourceTypeDisk = TRUE;
  1304. //
  1305. // Open a connection handle to \\server\vol\...
  1306. //
  1307. // Setup remote name
  1308. pCurPos = lpNetResource->lpRemoteName;
  1309. if (SystemPath.Length != 0) {
  1310. RemoteName.Length = (USHORT)((SystemPath.Buffer - pCurPos) * sizeof(WCHAR));
  1311. RemoteName.MaximumLength = RemoteName.Length + sizeof(WCHAR);
  1312. }
  1313. else {
  1314. RemoteName.Length = wcslen(pCurPos) * sizeof(WCHAR);
  1315. RemoteName.MaximumLength = RemoteName.Length + sizeof(WCHAR);
  1316. }
  1317. RemoteName.Buffer = MemAlloc(RemoteName.MaximumLength);
  1318. if (RemoteName.Buffer == NULL) {
  1319. Status = GetLastError();
  1320. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, MemAlloc failed.\n"));
  1321. goto EXIT;
  1322. }
  1323. RtlCopyMemory(RemoteName.Buffer, pCurPos, RemoteName.Length);
  1324. RemoteName.Buffer[RemoteName.Length/sizeof(WCHAR)] = L'\0';
  1325. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, RemoteName, %ws\n", RemoteName.Buffer));
  1326. if (fResourceTypeDisk) {
  1327. UNICODE_STRING ConnectionName;
  1328. HANDLE ConnectionHandle;
  1329. ConnectionName.Buffer = NULL;
  1330. ConnectionName.Length = 0;
  1331. ConnectionHandle = INVALID_HANDLE_VALUE;
  1332. // Setup the NT Device Name
  1333. Status = CreateConnectionName(NULL, RemoteName.Buffer, &ConnectionName);
  1334. if (Status == WN_SUCCESS) {
  1335. Status = OpenConnection(&ConnectionName,
  1336. FILE_OPEN,
  1337. (FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT),
  1338. NULL,
  1339. 0,
  1340. &ConnectionHandle);
  1341. if (ConnectionName.Buffer != NULL) {
  1342. MemFree(ConnectionName.Buffer);
  1343. }
  1344. if (Status == WN_SUCCESS) {
  1345. CloseHandle(ConnectionHandle);
  1346. }
  1347. else {
  1348. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, OpenConnection failed"));
  1349. goto EXIT;
  1350. }
  1351. }
  1352. else {
  1353. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, CreateConnectionName failed\n"));
  1354. goto EXIT;
  1355. }
  1356. }
  1357. else {
  1358. RDPDR_REQUEST_PACKET Rrp; // Redirector request packet
  1359. HANDLE DrDeviceHandle = 0;
  1360. PRDPDR_SERVER_INFO pServerEntry;
  1361. LPBYTE Buffer = NULL;
  1362. UNICODE_STRING ServerName;
  1363. if (DrOpenMiniRdr(&DrDeviceHandle) != WN_SUCCESS) {
  1364. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, failed to Open rdpdr\n"));
  1365. Status = WN_BAD_NETNAME;
  1366. goto EXIT;
  1367. }
  1368. //
  1369. // Ask the redirector to enumerate the information of server
  1370. // established by the caller.
  1371. //
  1372. Rrp.SessionId = NtCurrentPeb()->SessionId;
  1373. Rrp.Parameters.Get.ResumeHandle = 0;
  1374. //
  1375. // Make the request to the Redirector
  1376. //
  1377. Status = DrDeviceControlGetInfo(
  1378. DrDeviceHandle,
  1379. FSCTL_DR_ENUMERATE_SERVERS,
  1380. &Rrp,
  1381. sizeof(RDPDR_REQUEST_PACKET),
  1382. (LPBYTE *) &Buffer,
  1383. MAXULONG,
  1384. 0,
  1385. NULL);
  1386. CloseHandle(DrDeviceHandle);
  1387. if (Status != WN_SUCCESS) {
  1388. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, DrDeviceControlGetInfo failed\n"));
  1389. Status = WN_BAD_NETNAME;
  1390. goto EXIT;
  1391. }
  1392. pServerEntry = ((PRDPDR_SERVER_INFO) Buffer);
  1393. ServerName.Length = pServerEntry->ServerName.Length;
  1394. ServerName.MaximumLength = pServerEntry->ServerName.MaximumLength;
  1395. ServerName.Buffer = (PWCHAR)((PCHAR)(pServerEntry) + pServerEntry->ServerName.BufferOffset);
  1396. if ((RemoteName.Length == ServerName.Length) &&
  1397. _wcsnicmp(RemoteName.Buffer, ServerName.Buffer,
  1398. ServerName.Length/sizeof(WCHAR)) == 0) {
  1399. if (Buffer != NULL) {
  1400. MemFree(Buffer);
  1401. }
  1402. Status = WN_SUCCESS;
  1403. }
  1404. else {
  1405. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, invalid net name, %wZ\n",
  1406. RemoteName));
  1407. if (Buffer != NULL) {
  1408. MemFree(Buffer);
  1409. }
  1410. Status = WN_BAD_NETNAME;
  1411. goto EXIT;
  1412. }
  1413. }
  1414. if (Status == WN_SUCCESS)
  1415. {
  1416. //
  1417. // The resource exists, setup info.
  1418. //
  1419. *lpBufferSize = sizeof(NETRESOURCEW) +
  1420. RemoteName.Length + sizeof(WCHAR) +
  1421. DrProviderName.Length + sizeof(WCHAR) +
  1422. SystemPath.Length + sizeof(WCHAR);
  1423. if ((unsigned) (BufferResourceEnd - BufferResourceStart) > *lpBufferSize) {
  1424. pOutNetResource->dwScope = 0;
  1425. pOutNetResource->dwType = fResourceTypeDisk ?
  1426. RESOURCETYPE_DISK :
  1427. RESOURCETYPE_ANY;
  1428. pOutNetResource->dwDisplayType = fResourceTypeDisk ?
  1429. RESOURCEDISPLAYTYPE_SHARE :
  1430. RESOURCEDISPLAYTYPE_SERVER;
  1431. pOutNetResource->dwUsage = fResourceTypeDisk ?
  1432. RESOURCEUSAGE_CONNECTABLE |
  1433. RESOURCEUSAGE_NOLOCALDEVICE :
  1434. RESOURCEUSAGE_CONTAINER;
  1435. pOutNetResource->lpLocalName = NULL;
  1436. // Setup remote name
  1437. BufferResourceEnd -= RemoteName.Length + sizeof(WCHAR);
  1438. pOutNetResource->lpRemoteName = (PWCHAR) (BufferResourceStart + sizeof(NETRESOURCE));
  1439. RtlCopyMemory(pOutNetResource->lpRemoteName, RemoteName.Buffer,
  1440. RemoteName.Length);
  1441. pOutNetResource->lpRemoteName[RemoteName.Length /
  1442. sizeof(WCHAR)] = L'\0';
  1443. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, RemoteName, %ws\n",
  1444. pOutNetResource->lpRemoteName));
  1445. // Setup provider name
  1446. BufferResourceEnd -= DrProviderName.Length + sizeof(WCHAR);
  1447. pOutNetResource->lpProvider = (PWCHAR) ((PBYTE)(pOutNetResource->lpRemoteName) +
  1448. RemoteName.Length + sizeof(WCHAR));
  1449. RtlCopyMemory(pOutNetResource->lpProvider, DrProviderName.Buffer,
  1450. DrProviderName.Length);
  1451. pOutNetResource->lpProvider[DrProviderName.Length /
  1452. sizeof(WCHAR)] = L'\0';
  1453. pOutNetResource->lpComment = NULL;
  1454. // Setup system path
  1455. if (lplpSystem) {
  1456. if (SystemPath.Length) {
  1457. BufferResourceEnd -= SystemPath.Length + sizeof(WCHAR);
  1458. *lplpSystem = (PWCHAR) ((PBYTE)(pOutNetResource->lpProvider) +
  1459. DrProviderName.Length + sizeof(WCHAR));
  1460. RtlCopyMemory(*lplpSystem, SystemPath.Buffer,
  1461. SystemPath.Length);
  1462. (*lplpSystem)[SystemPath.Length / sizeof(WCHAR)] = L'\0';
  1463. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, SystemPath, %ws\n",
  1464. *lplpSystem));
  1465. }
  1466. else {
  1467. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, SystemPath null\n"));
  1468. *lplpSystem = NULL;
  1469. }
  1470. }
  1471. else {
  1472. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, user doesn't require systempath\n"));
  1473. }
  1474. Status = WN_SUCCESS;
  1475. goto EXIT;
  1476. }
  1477. else {
  1478. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInfo, buffer too small\n"));
  1479. Status = WN_MORE_DATA;
  1480. goto EXIT;
  1481. }
  1482. }
  1483. else {
  1484. DBGMSG(DBG_TRACE, ("DRPROV: NPGetResourceInformation, bad net name.\n"));
  1485. Status = WN_BAD_NETNAME;
  1486. goto EXIT;
  1487. }
  1488. EXIT:
  1489. if (RemoteName.Buffer != NULL) {
  1490. MemFree(RemoteName.Buffer);
  1491. }
  1492. return Status;
  1493. }
  1494. DWORD APIENTRY
  1495. NPGetUser(
  1496. IN LPTSTR lpName,
  1497. OUT LPTSTR lpUserName,
  1498. IN OUT LPDWORD lpBufferSize
  1499. )
  1500. /*++
  1501. Routine Description:
  1502. This function determines the user name that created the connection.
  1503. Arguments:
  1504. lpName - Name of the local drive or the remote name that the user has made
  1505. a connection to. If NULL, return currently logged on user.
  1506. lpUserName - The buffer to be filled in with the requested user name.
  1507. lpBufferSize - Contains the length (in chars not bytes )of the lpUserName
  1508. buffer. If the length is insufficient, this place is used to
  1509. inform the user the actual length needed.
  1510. Return Value:
  1511. WN_SUCCESS - Successful. OR
  1512. The appropriate network error code.
  1513. --*/
  1514. {
  1515. DWORD Status = WN_SUCCESS;
  1516. WCHAR NameBuffer[USERNAMELEN + 1];
  1517. DWORD NumOfChars = USERNAMELEN + 1;
  1518. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser.\n"));
  1519. if (lpUserName == NULL || lpBufferSize == NULL) {
  1520. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, invalid parameter(s)\n"));
  1521. Status = WN_BAD_VALUE;
  1522. goto EXIT;
  1523. }
  1524. //
  1525. // Get the name of the currently logged on user.
  1526. //
  1527. if (!GetUserName( NameBuffer, &(NumOfChars))) {
  1528. Status = GetLastError();
  1529. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, failed to get user name, %x\n", Status));
  1530. goto EXIT;
  1531. }
  1532. //
  1533. // Check to see if the buffer passed in is of the required length.
  1534. //
  1535. if ( *lpBufferSize < NumOfChars ) {
  1536. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, buffer too small.\n"));
  1537. *lpBufferSize = NumOfChars;
  1538. Status = WN_MORE_DATA;
  1539. goto EXIT;
  1540. }
  1541. //
  1542. // Copy the user name.
  1543. //
  1544. wcscpy(lpUserName, NameBuffer);
  1545. EXIT:
  1546. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUser, return status: %x\n", Status));
  1547. return Status;
  1548. }
  1549. DWORD APIENTRY
  1550. NPGetUniversalName(
  1551. LPCWSTR lpLocalPath,
  1552. DWORD dwInfoLevel,
  1553. LPVOID lpBuffer,
  1554. LPDWORD lpBufferSize )
  1555. /*++
  1556. Routine Description:
  1557. This routine returns the information associated net resource
  1558. Arguments:
  1559. lpLocalPath - the local path name
  1560. dwInfoLevel - the desired info level
  1561. lpBuffer - the buffer for the univeral name
  1562. lpBufferSize - the buffer size
  1563. Return Value:
  1564. WN_SUCCESS if successful
  1565. Notes:
  1566. --*/
  1567. {
  1568. DWORD Status = WN_SUCCESS;
  1569. DWORD BufferRequired = 0;
  1570. DWORD UniversalNameLength = 0;
  1571. DWORD RemoteNameLength = 0;
  1572. DWORD RemainingPathLength = 0;
  1573. LPWSTR pDriveLetter,
  1574. pRemainingPath,
  1575. SourceStrings[3];
  1576. WCHAR RemoteName[MAX_PATH],
  1577. LocalPath[MAX_PATH],
  1578. UniversalName[MAX_PATH],
  1579. ReplacedChar;
  1580. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName\n"));
  1581. // parameter checking
  1582. if (dwInfoLevel != UNIVERSAL_NAME_INFO_LEVEL &&
  1583. dwInfoLevel != REMOTE_NAME_INFO_LEVEL) {
  1584. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, bad InfoLevel, %d\n", dwInfoLevel));
  1585. Status = WN_BAD_LEVEL;
  1586. goto EXIT;
  1587. }
  1588. if (lpLocalPath == NULL || lpBuffer == NULL || lpBufferSize == NULL) {
  1589. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, invalid parameter(s)\n"));
  1590. Status = WN_BAD_VALUE;
  1591. goto EXIT;
  1592. }
  1593. // Get the local name
  1594. wcscpy(LocalPath, lpLocalPath);
  1595. pDriveLetter = LocalPath;
  1596. if (pRemainingPath = wcschr(pDriveLetter, L':')) {
  1597. ReplacedChar = *(++pRemainingPath);
  1598. *pRemainingPath = L'\0';
  1599. }
  1600. // Get the remote name by calling NPGetConnection
  1601. if ((Status = NPGetConnection(pDriveLetter, RemoteName, &RemoteNameLength)) != WN_SUCCESS) {
  1602. // MPR expects WN_BAD_LOCALNAME to bypass us.
  1603. if (Status == WN_BAD_NETNAME) {
  1604. Status = WN_BAD_LOCALNAME;
  1605. }
  1606. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, NPGetConnection failed\n"));
  1607. goto EXIT;
  1608. }
  1609. if (pRemainingPath) {
  1610. *pRemainingPath = ReplacedChar;
  1611. }
  1612. wcscpy(UniversalName, RemoteName);
  1613. if (pRemainingPath)
  1614. wcscat(UniversalName, pRemainingPath);
  1615. // Determine if the provided buffer is large enough.
  1616. UniversalNameLength = (wcslen(UniversalName) + 1) * sizeof(WCHAR);
  1617. BufferRequired = UniversalNameLength;
  1618. if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) {
  1619. BufferRequired += sizeof(UNIVERSAL_NAME_INFO);
  1620. }
  1621. else {
  1622. RemoteNameLength = (wcslen(RemoteName) + 1) * sizeof(WCHAR);
  1623. BufferRequired += sizeof(REMOTE_NAME_INFO) + RemoteNameLength;
  1624. if (pRemainingPath) {
  1625. RemainingPathLength = (wcslen(pRemainingPath) + 1) * sizeof(WCHAR);
  1626. BufferRequired += RemainingPathLength;
  1627. }
  1628. }
  1629. if (*lpBufferSize < BufferRequired) {
  1630. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, buffer too small\n"));
  1631. *lpBufferSize = BufferRequired;
  1632. Status = WN_MORE_DATA;
  1633. goto EXIT;
  1634. }
  1635. if (dwInfoLevel == UNIVERSAL_NAME_INFO_LEVEL) {
  1636. LPUNIVERSAL_NAME_INFOW pUniversalNameInfo;
  1637. pUniversalNameInfo = (LPUNIVERSAL_NAME_INFOW)lpBuffer;
  1638. pUniversalNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(UNIVERSAL_NAME_INFOW));
  1639. RtlCopyMemory(
  1640. pUniversalNameInfo->lpUniversalName,
  1641. UniversalName,
  1642. UniversalNameLength);
  1643. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, UniversalName, %ws\n", UniversalName));
  1644. Status = WN_SUCCESS;
  1645. }
  1646. else {
  1647. LPREMOTE_NAME_INFOW pRemoteNameInfo;
  1648. pRemoteNameInfo = (LPREMOTE_NAME_INFOW)lpBuffer;
  1649. pRemoteNameInfo->lpUniversalName = (PWCHAR)((PBYTE)lpBuffer + sizeof(REMOTE_NAME_INFOW));
  1650. pRemoteNameInfo->lpConnectionName = pRemoteNameInfo->lpUniversalName + UniversalNameLength;
  1651. pRemoteNameInfo->lpRemainingPath = pRemoteNameInfo->lpConnectionName + RemoteNameLength;
  1652. RtlCopyMemory(
  1653. pRemoteNameInfo->lpUniversalName,
  1654. UniversalName,
  1655. UniversalNameLength);
  1656. RtlCopyMemory(
  1657. pRemoteNameInfo->lpConnectionName,
  1658. RemoteName,
  1659. RemoteNameLength);
  1660. RtlCopyMemory(
  1661. pRemoteNameInfo->lpRemainingPath,
  1662. pRemainingPath,
  1663. RemainingPathLength);
  1664. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, UniversalName, %ws\n", UniversalName));
  1665. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, RemoteName, %ws\n", RemoteName));
  1666. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, Remaining Path, %ws\n", pRemainingPath));
  1667. Status = WN_SUCCESS;
  1668. }
  1669. EXIT:
  1670. DBGMSG(DBG_TRACE, ("DRPROV: NPGetUniversalName, return status, %x\n", Status));
  1671. return Status;
  1672. }