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.

1504 lines
45 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. drioctl.cpp
  5. Abstract:
  6. This module implements IOCTL handling specific to the Dr (as opposed to
  7. the devices it redirects). This includes rdpwsx notification for clients
  8. coming and going, and start/stop service requests.
  9. Environment:
  10. Kernel mode
  11. --*/
  12. #include "precomp.hxx"
  13. #define TRC_FILE "drioctl"
  14. #include "trc.h"
  15. #include <kernutil.h>
  16. #include <rdpdr.h>
  17. #include <rdpnp.h>
  18. #define DR_STARTABLE 0
  19. #define DR_STARTING 1
  20. #define DR_STARTED 2
  21. extern PRDBSS_DEVICE_OBJECT DrDeviceObject;
  22. #define RxNetNameTable (*(DrDeviceObject->pRxNetNameTable))
  23. LONG DrStartStatus = DR_STARTABLE;
  24. NTSTATUS
  25. DrDevFcbXXXControlFile (
  26. IN OUT PRX_CONTEXT RxContext
  27. )
  28. /*++
  29. Routine Description:
  30. This routine handles all the device FCB related FSCTL's in the mini rdr.
  31. Which is to say this handles IOCTLs for this driver instead of what we're
  32. redirecting.
  33. Arguments:
  34. RxContext - Describes the Fsctl and Context.
  35. Return Value:
  36. a valid NTSTATUS code.
  37. Notes:
  38. --*/
  39. {
  40. NTSTATUS Status = STATUS_SUCCESS;
  41. RxCaptureFobx;
  42. UCHAR MajorFunctionCode = RxContext->MajorFunction;
  43. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  44. ULONG ControlCode = LowIoContext->ParamsFor.FsCtl.FsControlCode;
  45. BEGIN_FN("DrDevFcbXXXControlFile");
  46. switch (MajorFunctionCode) {
  47. case IRP_MJ_FILE_SYSTEM_CONTROL:
  48. {
  49. switch (LowIoContext->ParamsFor.FsCtl.MinorFunction) {
  50. case IRP_MN_USER_FS_REQUEST:
  51. switch (ControlCode) {
  52. case FSCTL_DR_ENUMERATE_CONNECTIONS:
  53. {
  54. Status = DrEnumerateConnections(RxContext);
  55. }
  56. break;
  57. case FSCTL_DR_ENUMERATE_SHARES:
  58. {
  59. Status = DrEnumerateShares(RxContext);
  60. }
  61. break;
  62. case FSCTL_DR_ENUMERATE_SERVERS:
  63. {
  64. Status = DrEnumerateServers(RxContext);
  65. }
  66. break;
  67. case FSCTL_DR_GET_CONNECTION_INFO:
  68. if (capFobx) {
  69. Status = DrGetConnectionInfo(RxContext);
  70. }
  71. else {
  72. Status = STATUS_INVALID_DEVICE_REQUEST;
  73. }
  74. break;
  75. case FSCTL_DR_DELETE_CONNECTION:
  76. if (capFobx) {
  77. Status = DrDeleteConnection(RxContext, &RxContext->PostRequest);
  78. }
  79. else {
  80. Status = STATUS_INVALID_DEVICE_REQUEST;
  81. }
  82. break;
  83. default:
  84. Status = STATUS_INVALID_DEVICE_REQUEST;
  85. RxContext->pFobx = NULL;
  86. }
  87. break;
  88. default : //minor function != IRP_MN_USER_FS_REQUEST
  89. Status = STATUS_INVALID_DEVICE_REQUEST;
  90. RxContext->pFobx = NULL;
  91. }
  92. } // FSCTL case
  93. break;
  94. case IRP_MJ_DEVICE_CONTROL:
  95. switch (LowIoContext->ParamsFor.FsCtl.IoControlCode) {
  96. case IOCTL_CHANNEL_CONNECT:
  97. Status = DrOnSessionConnect(RxContext);
  98. break;
  99. case IOCTL_CHANNEL_DISCONNECT:
  100. Status = DrOnSessionDisconnect(RxContext);
  101. break;
  102. default:
  103. Status = STATUS_INVALID_DEVICE_REQUEST;
  104. RxContext->pFobx = NULL;
  105. }
  106. break;
  107. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  108. {
  109. // warning C4065: switch statement contains 'default' but no 'case' labels
  110. //switch (ControlCode) {
  111. //default :
  112. Status = STATUS_INVALID_DEVICE_REQUEST;
  113. RxContext->pFobx = NULL;
  114. //}
  115. }
  116. break;
  117. default:
  118. TRC_ASSERT(FALSE, (TB, "unimplemented major function"));
  119. Status = STATUS_INVALID_DEVICE_REQUEST;
  120. RxContext->pFobx = NULL;
  121. }
  122. TRC_NRM((TB, "MRxIfsDevFcb st,info=%08lx,%08lx",
  123. Status,RxContext->InformationToReturn));
  124. return(Status);
  125. }
  126. NTSTATUS
  127. DrOnSessionConnect(
  128. IN OUT PRX_CONTEXT RxContext
  129. )
  130. /*++
  131. Routine Description:
  132. Called when we a session is connected for the first time. Searches the
  133. list of virtual channels for our channel name, and opens the channel if
  134. it is found.
  135. Arguments:
  136. RxContext - Context information about the IOCTL call
  137. Return Value:
  138. STATUS_SUCCESS - Successful operation
  139. STATUS_INSUFFICIENT_RESOURCES - Out of memory
  140. --*/
  141. {
  142. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  143. PCHANNEL_CONNECT_IN ConnectIn =
  144. (PCHANNEL_CONNECT_IN)LowIoContext->ParamsFor.FsCtl.pInputBuffer;
  145. PCHANNEL_CONNECT_OUT ConnectOut =
  146. (PCHANNEL_CONNECT_OUT)LowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  147. PCHANNEL_CONNECT_DEF Channels = (PCHANNEL_CONNECT_DEF)(ConnectIn + 1);
  148. BEGIN_FN("DrOnSessionConnect");
  149. __try {
  150. ProbeForRead(ConnectIn, sizeof(CHANNEL_CONNECT_IN), sizeof(BYTE));
  151. ProbeForWrite(ConnectOut, sizeof(CHANNEL_CONNECT_OUT), sizeof(BYTE));
  152. TRC_ASSERT(ConnectIn != NULL, (TB, "ConnectIn != NULL"));
  153. TRC_NRM((TB, "Session ID %ld", ConnectIn->hdr.sessionID));
  154. //
  155. // Basic parameter validation
  156. //
  157. if ((LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) ||
  158. (LowIoContext->ParamsFor.FsCtl.InputBufferLength < sizeof(CHANNEL_CONNECT_IN)) ||
  159. (LowIoContext->ParamsFor.FsCtl.OutputBufferLength < sizeof(UINT_PTR)) ||
  160. (LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL)) {
  161. TRC_ERR((TB, "Received invalid pramater for SessionCreate IOCTL"));
  162. return STATUS_INVALID_PARAMETER;
  163. }
  164. //
  165. // Make sure the Minirdr is started
  166. //
  167. DrStartMinirdr(RxContext);
  168. ASSERT(Sessions != NULL);
  169. Sessions->OnConnect(ConnectIn, ConnectOut);
  170. // While we may have sadly failed somewhere along the way, if we want
  171. // rdpwsx to save our context out, we must return STATUS_SUCCESS
  172. return STATUS_SUCCESS;
  173. }
  174. __except (EXCEPTION_EXECUTE_HANDLER)
  175. {
  176. TRC_NRM((TB, "Error accessing buffer in DrOnSessionConnect"));
  177. return GetExceptionCode();
  178. }
  179. }
  180. NTSTATUS
  181. DrOnSessionDisconnect(
  182. IN OUT PRX_CONTEXT RxContext
  183. )
  184. /*++
  185. Routine Description:
  186. Called when we a session is ended. Searches the list of clients, and
  187. initiates a shutdown of each of those information sets.
  188. Arguments:
  189. RxContext - Context information about the IOCTL call
  190. Return Value:
  191. STATUS_SUCCESS - Successful operation
  192. STATUS_INSUFFICIENT_RESOURCES - Out of memory
  193. --*/
  194. {
  195. NTSTATUS Status = STATUS_SUCCESS;
  196. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  197. PCHANNEL_DISCONNECT_IN DisconnectIn =
  198. (PCHANNEL_DISCONNECT_IN)LowIoContext->ParamsFor.FsCtl.pInputBuffer;
  199. PCHANNEL_DISCONNECT_OUT DisconnectOut =
  200. (PCHANNEL_DISCONNECT_OUT)LowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  201. BEGIN_FN("DrOnSessionDisconnect");
  202. __try {
  203. ProbeForRead(DisconnectIn, sizeof(CHANNEL_DISCONNECT_IN), sizeof(BYTE));
  204. ProbeForWrite(DisconnectOut, sizeof(CHANNEL_DISCONNECT_OUT), sizeof(BYTE));
  205. //
  206. // Basic parameter validation
  207. //
  208. if ((LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL) ||
  209. (LowIoContext->ParamsFor.FsCtl.InputBufferLength < sizeof(CHANNEL_DISCONNECT_IN)) ||
  210. (LowIoContext->ParamsFor.FsCtl.OutputBufferLength < sizeof(UINT_PTR)) ||
  211. (LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL)) {
  212. TRC_ERR((TB, "Received invalid pramater for SessionClose IOCTL"));
  213. return STATUS_INVALID_PARAMETER;
  214. }
  215. ASSERT(Sessions != NULL);
  216. Sessions->OnDisconnect(DisconnectIn, DisconnectOut);
  217. // While we may have sadly failed somewhere along the way, if we want
  218. // rdpwsx to save our context out, we must return STATUS_SUCCESS
  219. return STATUS_SUCCESS;
  220. }
  221. __except (EXCEPTION_EXECUTE_HANDLER)
  222. {
  223. TRC_NRM((TB, "Error accessing buffer in DrOnSessionDisconnect"));
  224. return GetExceptionCode();
  225. }
  226. }
  227. VOID
  228. DrStartMinirdr(
  229. PRX_CONTEXT RxContext
  230. )
  231. /*++
  232. Routine Description:
  233. We use this to start the minirdr. Checks if the work is needed and
  234. kicks off a system thread if we need to.
  235. Arguments:
  236. None
  237. Return Value:
  238. None
  239. --*/
  240. {
  241. NTSTATUS Status;
  242. HANDLE ThreadHandle;
  243. PVOID Thread = NULL;
  244. BEGIN_FN("DrStartMinirdr");
  245. //
  246. // Make sure it needs to be started, and start it if we can
  247. //
  248. if (InterlockedCompareExchange(&DrStartStatus, DR_STARTING, DR_STARTABLE) == DR_STARTABLE) {
  249. //
  250. // We need to call RxStartMinirdr from the system process
  251. //
  252. Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, NULL,
  253. NULL, NULL, DrStartMinirdrWorker, RxContext);
  254. //
  255. // Get a pointer to the thread
  256. //
  257. if (NT_SUCCESS(Status)) {
  258. Status = ObReferenceObjectByHandle(ThreadHandle,
  259. THREAD_ALL_ACCESS, NULL, KernelMode, &Thread, NULL);
  260. ZwClose(ThreadHandle);
  261. }
  262. //
  263. // Wait on the thread pointer
  264. //
  265. if (NT_SUCCESS(Status)) {
  266. KeWaitForSingleObject(Thread, UserRequest, KernelMode, FALSE, NULL);
  267. ObfDereferenceObject(Thread);
  268. }
  269. }
  270. }
  271. VOID
  272. DrStartMinirdrWorker(
  273. IN PVOID StartContext
  274. )
  275. /*++
  276. Routine Description:
  277. We use this to start the minirdr. Checks if the work is needed and
  278. kicks off a system thread if we need to.
  279. Arguments:
  280. None
  281. Return Value:
  282. None
  283. --*/
  284. {
  285. NTSTATUS Status;
  286. PRX_CONTEXT RxContext2;
  287. PRX_CONTEXT RxContext = (PRX_CONTEXT)StartContext;
  288. BEGIN_FN("DrStartMinirdrWorker");
  289. RxContext2 = RxCreateRxContext(
  290. NULL,
  291. RxContext->RxDeviceObject,
  292. RX_CONTEXT_FLAG_IN_FSP);
  293. //
  294. // Start Redirecting
  295. //
  296. if (RxContext2 != NULL) {
  297. Status = RxStartMinirdr(RxContext2, &RxContext2->PostRequest);
  298. TRC_NRM((TB, "RxStartMinirdr returned: %lx", Status));
  299. RxDereferenceAndDeleteRxContext(RxContext2);
  300. } else {
  301. Status = STATUS_INSUFFICIENT_RESOURCES;
  302. }
  303. if (NT_SUCCESS(Status)) {
  304. InterlockedExchange(&DrStartStatus, DR_STARTED);
  305. } else {
  306. InterlockedCompareExchange(&DrStartStatus, DR_STARTABLE,
  307. DR_STARTING);
  308. }
  309. PsTerminateSystemThread(Status);
  310. }
  311. NTSTATUS
  312. DrDeleteConnection (
  313. IN PRX_CONTEXT RxContext,
  314. OUT PBOOLEAN PostToFsp
  315. )
  316. /*++
  317. Routine Description:
  318. This routine deletes a single vnetroot.
  319. Arguments:
  320. IN PRX_CONTEXT RxContext - Describes the Fsctl and Context.
  321. Return Value:
  322. NTSTATUS
  323. --*/
  324. {
  325. NTSTATUS Status;
  326. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  327. RxCaptureFobx;
  328. PNET_ROOT NetRoot;
  329. PV_NET_ROOT VNetRoot;
  330. BEGIN_FN("DrDeleteConnection");
  331. BOOLEAN Wait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT);
  332. TRC_NRM((TB, "Request DrDeleteConnection"));
  333. if (!Wait) {
  334. TRC_NRM((TB, "WAIT flag is not on for DeleteConnection"));
  335. //just post right now!
  336. *PostToFsp = TRUE;
  337. return STATUS_PENDING;
  338. }
  339. __try
  340. {
  341. if (NodeType(capFobx)==RDBSS_NTC_V_NETROOT) {
  342. VNetRoot = (PV_NET_ROOT)capFobx;
  343. NetRoot = (PNET_ROOT)((PMRX_V_NET_ROOT)VNetRoot->pNetRoot);
  344. } else {
  345. TRC_ASSERT((FALSE), (TB, "Not VNet Root"));
  346. try_return(Status = STATUS_INVALID_DEVICE_REQUEST);
  347. }
  348. Status = RxFinalizeConnection(NetRoot,VNetRoot,TRUE);
  349. TRC_NRM((TB, "RxFinalizeConnection returned %lx", Status));
  350. try_return(Status);
  351. try_exit:NOTHING;
  352. }
  353. __except (EXCEPTION_EXECUTE_HANDLER)
  354. {
  355. TRC_NRM((TB, "Error accessing capFobx in DrDeleteConnection"));
  356. }
  357. return Status;
  358. }
  359. BOOLEAN
  360. DrPackStringIntoInfoBuffer(
  361. IN OUT PRDPDR_UNICODE_STRING String,
  362. IN PUNICODE_STRING Source,
  363. IN PCHAR BufferStart,
  364. IN OUT PCHAR * BufferEnd,
  365. IN ULONG BufferDisplacement,
  366. IN OUT PULONG TotalBytes
  367. )
  368. /*
  369. Routine Description:
  370. This code copies a string to the end of the buffer IF THERE'S ROOM. the buffer
  371. displacement is used to map the buffer back into the user's space in case we
  372. have posted.
  373. Arguments:
  374. Return Value:
  375. */
  376. {
  377. LONG size;
  378. BEGIN_FN("DrPackStringIntoInfoBuffer");
  379. TRC_ASSERT((BufferStart <= *BufferEnd),
  380. (TB, "Invalid BufferStart %p, Buffer End %p", BufferStart, *BufferEnd));
  381. //
  382. // is there room for the string?
  383. //
  384. size = Source->Length;
  385. if ((*BufferEnd - BufferStart) < size) {
  386. String->Length = 0;
  387. return FALSE;
  388. } else {
  389. //
  390. // Copy the source string to the end of the buffer and store
  391. // the buffer pointer in output string accordingly
  392. //
  393. String->Length = Source->Length;
  394. String->MaximumLength = Source->Length;
  395. *BufferEnd -= size;
  396. if (TotalBytes != NULL) { *TotalBytes += size; }
  397. RtlCopyMemory(*BufferEnd, Source->Buffer, size);
  398. String->BufferOffset = (LONG)((LONG_PTR)((PCHAR)(*BufferEnd) - (PCHAR)(BufferStart)));
  399. String->BufferOffset = String->BufferOffset - BufferDisplacement;
  400. return TRUE;
  401. }
  402. }
  403. BOOLEAN
  404. DrPackConnectEntry (
  405. IN OUT PRX_CONTEXT RxContext,
  406. IN OUT PCHAR *BufferStart,
  407. IN OUT PCHAR *BufferEnd,
  408. IN PV_NET_ROOT VNetRoot,
  409. IN OUT ULONG BufferDisplacement,
  410. OUT PULONG TotalBytesNeeded
  411. )
  412. /*++
  413. Routine Description:
  414. This routine packs a connectlistentry into the buffer provided updating
  415. all relevant pointers. The way that this works is that constant length stuff is
  416. copied to the front of the buffer and variable length stuff to the end. The
  417. "start and end" pointers are updated. You have to calculate the totalbytes correctly
  418. no matter what but a last can be setup incompletely as long as you return false.
  419. the way that this works is that it calls down into the minirdr on the devfcb
  420. interface. it calls down twice and passes a structure back and forth thru the
  421. context to maintain state.
  422. Arguments:
  423. IN OUT PCHAR *BufferStart - Supplies the output buffer.
  424. Updated to point to the next buffer
  425. IN OUT PCHAR *BufferEnd - Supplies the end of the buffer. Updated to
  426. point before the start of the strings being packed.
  427. IN PVNET_ROOT NetRoot - Supplies the VNetRoot to enumerate.
  428. IN OUT PULONG TotalBytesNeeded - Updated to account for the length of this
  429. entry
  430. Return Value:
  431. BOOLEAN - True if the entry was successfully packed into the buffer.
  432. --*/
  433. {
  434. NTSTATUS Status;
  435. BOOLEAN ReturnValue = TRUE;
  436. UNICODE_STRING Name;
  437. ULONG BufferSize;
  438. PRDPDR_CONNECTION_INFO ConnectionInfo = (PRDPDR_CONNECTION_INFO)*BufferStart;
  439. PNET_ROOT NetRoot = (PNET_ROOT)(((PMRX_V_NET_ROOT)VNetRoot)->pNetRoot);
  440. PUNICODE_STRING VNetRootName = &VNetRoot->PrefixEntry.Prefix;
  441. PCHAR ConnectEntryStart;
  442. BEGIN_FN("DrPackConnectEntry");
  443. //
  444. // We want the connection name to have string null terminator
  445. //
  446. Name.Buffer = (PWCHAR)RxAllocatePoolWithTag(NonPagedPool,
  447. MAX_PATH, DR_POOLTAG);
  448. if ( Name.Buffer == NULL ) {
  449. return FALSE;
  450. }
  451. BufferSize = sizeof(RDPDR_CONNECTION_INFO);
  452. ConnectEntryStart = *BufferStart;
  453. __try {
  454. //
  455. // Account for the constant length stuff
  456. //
  457. *BufferStart = ((PCHAR)*BufferStart) + BufferSize;
  458. *TotalBytesNeeded += BufferSize;
  459. //
  460. // Initialize the name to "\" then add in the rest of the connection name
  461. //
  462. Name.Length = NetRoot->PrefixEntry.Prefix.Length + sizeof(WCHAR);
  463. Name.MaximumLength = Name.Length;
  464. ASSERT(Name.Length <= MAX_PATH);
  465. Name.Buffer[0] = L'\\';
  466. RtlCopyMemory(&Name.Buffer[1], NetRoot->PrefixEntry.Prefix.Buffer,
  467. NetRoot->PrefixEntry.Prefix.Length);
  468. //
  469. // Update the total number of bytes needed for this structure.
  470. //
  471. *TotalBytesNeeded += Name.Length;
  472. if (*BufferStart > *BufferEnd) {
  473. try_return(ReturnValue = FALSE);
  474. }
  475. if ((*BufferEnd - *BufferStart) < Name.Length) {
  476. ConnectionInfo->RemoteName.Length = 0;
  477. try_return( ReturnValue = FALSE);
  478. }
  479. else if (!DrPackStringIntoInfoBuffer(
  480. &ConnectionInfo->RemoteName,
  481. &Name,
  482. ConnectEntryStart,
  483. BufferEnd,
  484. BufferDisplacement,
  485. NULL)) {
  486. try_return( ReturnValue = FALSE);
  487. }
  488. //
  489. // Setup the local name
  490. //
  491. if (VNetRootName->Buffer[2] != L':') {
  492. Name.Buffer[0] = towupper(VNetRootName->Buffer[2]);
  493. Name.Buffer[1] = L':';
  494. Name.Buffer[2] = L'\0';
  495. Name.Length = sizeof(WCHAR) * 2;
  496. Name.MaximumLength = Name.Length;
  497. //
  498. // Update the total number of bytes needed for this structure.
  499. //
  500. *TotalBytesNeeded += Name.Length;
  501. if (*BufferStart > *BufferEnd) {
  502. try_return(ReturnValue = FALSE);
  503. }
  504. if ((*BufferEnd - *BufferStart) < Name.Length) {
  505. ConnectionInfo->LocalName.Length = 0;
  506. try_return( ReturnValue = FALSE);
  507. }
  508. else if (!DrPackStringIntoInfoBuffer(
  509. &ConnectionInfo->LocalName,
  510. &Name,
  511. ConnectEntryStart,
  512. BufferEnd,
  513. BufferDisplacement,
  514. NULL)) {
  515. try_return( ReturnValue = FALSE);
  516. }
  517. }
  518. else {
  519. ConnectionInfo->LocalName.Length = 0;
  520. ConnectionInfo->LocalName.BufferOffset = 0;
  521. }
  522. ConnectionInfo->ResumeKey = NetRoot->SerialNumberForEnum;
  523. ConnectionInfo->SharedResourceType = NetRoot->DeviceType;
  524. ConnectionInfo->ConnectionStatus = NetRoot->MRxNetRootState;
  525. ConnectionInfo->NumberFilesOpen = NetRoot->NumberOfSrvOpens;
  526. //TRC_NRM((TB, "PackConnection data---> Remote Local Type Key Status Numfiles %wZ %wZ %08lx %08lx %08lx %08lx\n",
  527. // &(ConnectionInfo->RemoteName),
  528. // ConnectionInfo->LocalName.BufferOffset ? &Name : NULL,
  529. // ConnectionInfo->SharedResourceType,
  530. // ConnectionInfo->ResumeKey,
  531. // ConnectionInfo->ConnectionStatus,
  532. // ConnectionInfo->NumberFilesOpen));
  533. try_exit:
  534. RxFreePool(Name.Buffer);
  535. }
  536. __except (EXCEPTION_EXECUTE_HANDLER) {
  537. RxFreePool(Name.Buffer);
  538. return FALSE;
  539. }
  540. return ReturnValue;
  541. }
  542. NTSTATUS
  543. DrEnumerateConnections (
  544. IN PRX_CONTEXT RxContext
  545. )
  546. /*++
  547. Routine Description:
  548. This routine enumerates the connections on minirdr.
  549. Arguments:
  550. IN PRX_CONTEXT RxContext - Describes the Fsctl and Context
  551. Return Value:
  552. NTSTATUS
  553. --*/
  554. {
  555. NTSTATUS Status = STATUS_SUCCESS;
  556. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  557. PRDPDR_REQUEST_PACKET InputBuffer = (PRDPDR_REQUEST_PACKET)(LowIoContext->ParamsFor.FsCtl.pInputBuffer);
  558. PCHAR OriginalOutputBuffer = (PCHAR)(LowIoContext->ParamsFor.FsCtl.pOutputBuffer);
  559. ULONG OutputBufferLength = LowIoContext->ParamsFor.FsCtl.OutputBufferLength;
  560. ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
  561. PCHAR OutputBuffer;
  562. ULONG BufferDisplacement;
  563. ULONG ResumeHandle;
  564. PCHAR BufferStart;
  565. PCHAR BufferEnd;
  566. PCHAR PreviousBufferStart;
  567. PLIST_ENTRY ListEntry;
  568. ULONG SessionId, IrpSessionId;
  569. BOOLEAN TableLockHeld = FALSE;
  570. BEGIN_FN("DrEnumerateConnections");
  571. OutputBuffer = (PCHAR)RxMapUserBuffer( RxContext, RxContext->CurrentIrp );
  572. BufferDisplacement = (ULONG)(OutputBuffer - OriginalOutputBuffer);
  573. BufferStart = OutputBuffer;
  574. BufferEnd = OutputBuffer + OutputBufferLength;
  575. Status = IoGetRequestorSessionId(RxContext->CurrentIrp, &IrpSessionId);
  576. if (!NT_SUCCESS(Status)) {
  577. return STATUS_INVALID_DEVICE_REQUEST;
  578. }
  579. if (InputBuffer == NULL || OutputBuffer == NULL) {
  580. return STATUS_INVALID_PARAMETER;
  581. }
  582. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  583. TRC_ASSERT((BufferDisplacement == 0),
  584. (TB, "Request mode is not kernel, non zero Displacement"));
  585. __try {
  586. ProbeForWrite(InputBuffer,InputBufferLength,sizeof(UCHAR));
  587. ProbeForWrite(OutputBuffer,OutputBufferLength,sizeof(UCHAR));
  588. }
  589. __except (EXCEPTION_EXECUTE_HANDLER) {
  590. return STATUS_INVALID_PARAMETER;
  591. }
  592. }
  593. __try {
  594. if (InputBufferLength < sizeof(RDPDR_REQUEST_PACKET)) {
  595. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  596. }
  597. ResumeHandle = InputBuffer->Parameters.Get.ResumeHandle;
  598. SessionId = InputBuffer->SessionId;
  599. if (SessionId != IrpSessionId) {
  600. try_return(Status = STATUS_INVALID_PARAMETER);
  601. }
  602. InputBuffer->Parameters.Get.EntriesRead = 0;
  603. InputBuffer->Parameters.Get.TotalEntries = 0;
  604. InputBuffer->Parameters.Get.TotalBytesNeeded = 0;
  605. RxAcquirePrefixTableLockExclusive(&RxNetNameTable, TRUE);
  606. TableLockHeld = TRUE;
  607. if (IsListEmpty(&RxNetNameTable.MemberQueue)) {
  608. try_return(Status = STATUS_SUCCESS);
  609. }
  610. //must do the list forwards!
  611. ListEntry = RxNetNameTable.MemberQueue.Flink;
  612. for (;ListEntry != &RxNetNameTable.MemberQueue;) {
  613. PVOID Container;
  614. PRX_PREFIX_ENTRY PrefixEntry;
  615. PNET_ROOT NetRoot;
  616. PV_NET_ROOT VNetRoot;
  617. PUNICODE_STRING VNetRootName;
  618. PrefixEntry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, MemberQLinks);
  619. ListEntry = ListEntry->Flink;
  620. TRC_ASSERT((NodeType(PrefixEntry) == RDBSS_NTC_PREFIX_ENTRY),
  621. (TB, "Invalid PrefixEntry type"));
  622. Container = PrefixEntry->ContainingRecord;
  623. switch (NodeType(Container)) {
  624. case RDBSS_NTC_NETROOT :
  625. continue;
  626. case RDBSS_NTC_SRVCALL :
  627. continue;
  628. case RDBSS_NTC_V_NETROOT :
  629. VNetRoot = (PV_NET_ROOT)Container;
  630. NetRoot = (PNET_ROOT)(((PMRX_V_NET_ROOT)VNetRoot)->pNetRoot);
  631. VNetRootName = &VNetRoot->PrefixEntry.Prefix;
  632. TRC_NRM((TB, "SerialNum: %x, VNetRootName = %wZ, Condition = %d, SessionId = %d, IsExplicit = %d",
  633. VNetRoot->SerialNumberForEnum,
  634. VNetRootName,
  635. VNetRoot->Condition,
  636. VNetRoot->SessionId,
  637. VNetRoot->IsExplicitConnection));
  638. if ((VNetRoot->SerialNumberForEnum >= ResumeHandle) &&
  639. (VNetRoot->Condition == Condition_Good) &&
  640. (SessionId == VNetRoot->SessionId) &&
  641. (VNetRoot->IsExplicitConnection == TRUE)) {
  642. break;
  643. } else {
  644. continue;
  645. }
  646. default:
  647. continue;
  648. }
  649. InputBuffer->Parameters.Get.TotalEntries ++ ;
  650. PreviousBufferStart = BufferStart;
  651. if (DrPackConnectEntry(RxContext,
  652. &BufferStart,
  653. &BufferEnd,
  654. VNetRoot,
  655. BufferDisplacement,
  656. &InputBuffer->Parameters.Get.TotalBytesNeeded)) {
  657. InputBuffer->Parameters.Get.EntriesRead ++ ;
  658. } else {
  659. // We want to continue the enumeration even pack connection
  660. // entry failed, because we want to enumerate the total bytes
  661. // needed and inform the user mode program
  662. Status = STATUS_BUFFER_TOO_SMALL;
  663. continue;
  664. }
  665. }
  666. try_return(Status);
  667. try_exit:
  668. if (TableLockHeld) {
  669. RxReleasePrefixTableLock( &RxNetNameTable );
  670. TableLockHeld = FALSE;
  671. }
  672. }
  673. __except (EXCEPTION_EXECUTE_HANDLER) {
  674. if (TableLockHeld) {
  675. RxReleasePrefixTableLock( &RxNetNameTable );
  676. TableLockHeld = FALSE;
  677. }
  678. return STATUS_INVALID_PARAMETER;
  679. }
  680. return Status;
  681. }
  682. NTSTATUS
  683. DrGetConnectionInfo (
  684. IN PRX_CONTEXT RxContext
  685. )
  686. /*++
  687. Routine Description:
  688. This routine gets the connection info for a single vnetroot.
  689. There is some happiness here about the output buffer. What happens is that we
  690. pick up the output buffer in the usual way. However, there are all sorts of
  691. pointers in the return structure and these pointers must obviously be in terms
  692. of the original process. so, if we post then we have to apply a fixup!
  693. Arguments:
  694. IN PRX_CONTEXT RxContext - Describes the Fsctl and Context
  695. Return Value:
  696. STATUS_SUCCESS if successful
  697. --*/
  698. {
  699. NTSTATUS Status = STATUS_SUCCESS;
  700. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  701. RxCaptureFobx;
  702. PRDPDR_REQUEST_PACKET InputBuffer = (PRDPDR_REQUEST_PACKET)LowIoContext->ParamsFor.FsCtl.pInputBuffer;
  703. PCHAR OriginalOutputBuffer = (PCHAR)LowIoContext->ParamsFor.FsCtl.pOutputBuffer;
  704. ULONG OutputBufferLength = LowIoContext->ParamsFor.FsCtl.OutputBufferLength;
  705. ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
  706. PCHAR OutputBuffer;
  707. ULONG BufferDisplacement;
  708. PCHAR BufferStart;
  709. PCHAR OriginalBufferStart;
  710. PCHAR BufferEnd;
  711. BOOLEAN TableLockHeld = FALSE;
  712. PNET_ROOT NetRoot;
  713. PV_NET_ROOT VNetRoot;
  714. BEGIN_FN("DrGetConnectionInfo");
  715. OutputBuffer = (PCHAR)RxMapUserBuffer( RxContext, RxContext->CurrentIrp );
  716. BufferDisplacement = (ULONG)(OutputBuffer - OriginalOutputBuffer);
  717. BufferStart = OutputBuffer;
  718. OriginalBufferStart = BufferStart;
  719. BufferEnd = OutputBuffer+OutputBufferLength;
  720. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  721. TRC_ASSERT((BufferDisplacement == 0),
  722. (TB, "Request mode is not kernel, non zero Displacement"));
  723. __try {
  724. ProbeForWrite(InputBuffer,InputBufferLength,sizeof(UCHAR));
  725. ProbeForWrite(OutputBuffer,OutputBufferLength,sizeof(UCHAR));
  726. }
  727. __except(EXCEPTION_EXECUTE_HANDLER) {
  728. return STATUS_INVALID_PARAMETER;
  729. }
  730. }
  731. __try {
  732. TRC_ASSERT((NodeType(capFobx)==RDBSS_NTC_V_NETROOT), (TB, "Invalid Node type"));
  733. VNetRoot = (PV_NET_ROOT)capFobx;
  734. NetRoot = (PNET_ROOT)((PMRX_V_NET_ROOT)VNetRoot->pNetRoot);
  735. if (NetRoot == NULL) {
  736. try_return(Status = STATUS_ALREADY_DISCONNECTED);
  737. }
  738. if (InputBufferLength < sizeof(RDPDR_REQUEST_PACKET)) {
  739. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  740. }
  741. InputBuffer->Parameters.Get.TotalEntries = 1;
  742. InputBuffer->Parameters.Get.TotalBytesNeeded = 0;
  743. RxAcquirePrefixTableLockExclusive( &RxNetNameTable, TRUE);
  744. TableLockHeld = TRUE;
  745. if (DrPackConnectEntry(RxContext,
  746. &BufferStart,
  747. &BufferEnd,
  748. VNetRoot,
  749. BufferDisplacement,
  750. &InputBuffer->Parameters.Get.TotalBytesNeeded)) {
  751. InputBuffer->Parameters.Get.EntriesRead = 1;
  752. try_return(Status = STATUS_SUCCESS);
  753. } else {
  754. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  755. }
  756. try_exit:
  757. if (TableLockHeld) {
  758. RxReleasePrefixTableLock( &RxNetNameTable );
  759. TableLockHeld = FALSE;
  760. }
  761. }
  762. __except(EXCEPTION_EXECUTE_HANDLER) {
  763. if (TableLockHeld) {
  764. RxReleasePrefixTableLock( &RxNetNameTable );
  765. TableLockHeld = FALSE;
  766. }
  767. return STATUS_INVALID_PARAMETER;
  768. }
  769. return Status;
  770. }
  771. BOOLEAN
  772. DrPackShareEntry (
  773. IN OUT PRX_CONTEXT RxContext,
  774. IN OUT PCHAR *BufferStart,
  775. IN OUT PCHAR *BufferEnd,
  776. IN DrDevice* Device,
  777. IN OUT ULONG BufferDisplacement,
  778. OUT PULONG TotalBytesNeeded
  779. )
  780. /*++
  781. Routine Description:
  782. This routine packs a sharelistentry into the buffer provided updating
  783. all relevant pointers. The way that this works is that constant length stuff is
  784. copied to the front of the buffer and variable length stuff to the end. The
  785. "start and end" pointers are updated. You have to calculate the totalbytes correctly
  786. no matter what but a last can be setup incompletely as long as you return false.
  787. the way that this works is that it calls down into the minirdr on the devfcb
  788. interface. it calls down twice and passes a structure back and forth thru the
  789. context to maintain state.
  790. Arguments:
  791. IN OUT PCHAR *BufferStart - Supplies the output buffer.
  792. Updated to point to the next buffer
  793. IN OUT PCHAR *BufferEnd - Supplies the end of the buffer. Updated to
  794. point before the start of the strings being packed.
  795. IN PNET_ROOT NetRoot - Supplies the NetRoot to enumerate.
  796. IN OUT PULONG TotalBytesNeeded - Updated to account for the length of this
  797. entry
  798. Return Value:
  799. BOOLEAN - True if the entry was successfully packed into the buffer.
  800. --*/
  801. {
  802. NTSTATUS Status;
  803. BOOLEAN ReturnValue = TRUE;
  804. UNICODE_STRING ShareName; // Buffer to hold the packed name
  805. PUCHAR DeviceDosName;
  806. ULONG BufferSize;
  807. PRDPDR_SHARE_INFO ShareInfo = (PRDPDR_SHARE_INFO)*BufferStart;
  808. PCHAR ShareEntryStart;
  809. BEGIN_FN("DrPackShareEntry");
  810. //
  811. // We want the connection name to have string null terminator
  812. //
  813. ShareName.Buffer = (PWCHAR)RxAllocatePoolWithTag(NonPagedPool,
  814. MAX_PATH * sizeof(WCHAR), DR_POOLTAG);
  815. if ( ShareName.Buffer == NULL ) {
  816. return FALSE;
  817. }
  818. BufferSize = sizeof(RDPDR_SHARE_INFO);
  819. ShareEntryStart = *BufferStart;
  820. __try {
  821. unsigned len, devicelen, i;
  822. *BufferStart = ((PCHAR)*BufferStart) + BufferSize;
  823. *TotalBytesNeeded += BufferSize;
  824. //
  825. // Initialize the name to "\\" then add in the rest
  826. //
  827. wcscpy(ShareName.Buffer, L"\\\\");
  828. #if 0
  829. wcscat(ServerName.Buffer, Session->GetClientName());
  830. #endif
  831. wcscat(ShareName.Buffer, DRUNCSERVERNAME_U);
  832. wcscat(ShareName.Buffer, L"\\");
  833. DeviceDosName = Device->GetDeviceDosName();
  834. len = wcslen(ShareName.Buffer);
  835. devicelen = strlen((char *)DeviceDosName);
  836. for (i = 0; i < devicelen; i++) {
  837. ShareName.Buffer[i + len] = (WCHAR) DeviceDosName[i];
  838. }
  839. ShareName.Buffer[i + len] = L'\0';
  840. ShareName.Length = wcslen(ShareName.Buffer) * sizeof(WCHAR);
  841. ShareName.MaximumLength = ShareName.Length;
  842. ASSERT(ShareName.Length < MAX_PATH);
  843. //
  844. // Update the total number of bytes needed for this structure.
  845. //
  846. *TotalBytesNeeded += ShareName.MaximumLength;
  847. if (*BufferStart > *BufferEnd) {
  848. try_return( ReturnValue = FALSE);
  849. }
  850. ShareInfo->ResumeKey = Device->GetDeviceId();
  851. ShareInfo->SharedResourceType = RxDeviceType(DISK);
  852. if ((*BufferEnd - *BufferStart) < ShareName.Length) {
  853. ShareInfo->ShareName.Length = 0;
  854. try_return( ReturnValue = FALSE);
  855. }
  856. else if (!DrPackStringIntoInfoBuffer(
  857. &ShareInfo->ShareName,
  858. &ShareName,
  859. ShareEntryStart,
  860. BufferEnd,
  861. BufferDisplacement,
  862. NULL)) {
  863. try_return( ReturnValue = FALSE);
  864. }
  865. try_exit:
  866. RxFreePool(ShareName.Buffer);
  867. }
  868. __except(EXCEPTION_EXECUTE_HANDLER) {
  869. RxFreePool(ShareName.Buffer);
  870. return FALSE;
  871. }
  872. return ReturnValue;
  873. }
  874. NTSTATUS
  875. DrEnumerateShares (
  876. IN PRX_CONTEXT RxContext
  877. )
  878. /*++
  879. Routine Description:
  880. This routine enumerates the connections on all minirdrs. we may have to do
  881. it by minirdr.
  882. Arguments:
  883. IN PRX_CONTEXT RxContext - Describes the Fsctl and Context
  884. Return Value:
  885. NTSTATUS
  886. --*/
  887. {
  888. NTSTATUS Status = STATUS_SUCCESS;
  889. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  890. PRDPDR_REQUEST_PACKET InputBuffer = (PRDPDR_REQUEST_PACKET)(LowIoContext->ParamsFor.FsCtl.pInputBuffer);
  891. PCHAR OriginalOutputBuffer = (PCHAR)(LowIoContext->ParamsFor.FsCtl.pOutputBuffer);
  892. ULONG OutputBufferLength = LowIoContext->ParamsFor.FsCtl.OutputBufferLength;
  893. ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
  894. PCHAR OutputBuffer;
  895. ULONG BufferDisplacement;
  896. ULONG ResumeHandle;
  897. PCHAR BufferStart;
  898. PCHAR BufferEnd;
  899. PCHAR PreviousBufferStart;
  900. ULONG SessionId;
  901. SmartPtr<DrSession> Session;
  902. BOOLEAN TableLockHeld = FALSE;
  903. BEGIN_FN("DrEnumerateShares");
  904. OutputBuffer = (PCHAR)RxMapUserBuffer( RxContext, RxContext->CurrentIrp );
  905. BufferDisplacement = (ULONG)(OutputBuffer - OriginalOutputBuffer);
  906. BufferStart = OutputBuffer;
  907. BufferEnd = OutputBuffer+OutputBufferLength;
  908. if (InputBuffer == NULL || OutputBuffer == NULL) {
  909. return STATUS_INVALID_PARAMETER;
  910. }
  911. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  912. TRC_ASSERT((BufferDisplacement == 0),
  913. (TB, "Request mode is not kernel, non zero Displacement"));
  914. __try {
  915. ProbeForWrite(InputBuffer,InputBufferLength,sizeof(UCHAR));
  916. ProbeForWrite(OutputBuffer,OutputBufferLength,sizeof(UCHAR));
  917. }
  918. __except(EXCEPTION_EXECUTE_HANDLER) {
  919. return STATUS_INVALID_PARAMETER;
  920. }
  921. }
  922. __try {
  923. if (InputBufferLength < sizeof(RDPDR_REQUEST_PACKET)) {
  924. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  925. }
  926. ResumeHandle = InputBuffer->Parameters.Get.ResumeHandle;
  927. SessionId = InputBuffer->SessionId;
  928. InputBuffer->Parameters.Get.EntriesRead = 0;
  929. InputBuffer->Parameters.Get.TotalEntries = 0;
  930. InputBuffer->Parameters.Get.TotalBytesNeeded = 0;
  931. if (Sessions->FindSessionById(SessionId, Session)) {
  932. DrDevice *DeviceEnum;
  933. ListEntry *ListEnum;
  934. Session->GetDevMgr().GetDevList().LockShared();
  935. TableLockHeld = TRUE;
  936. ListEnum = Session->GetDevMgr().GetDevList().First();
  937. while (ListEnum != NULL) {
  938. DeviceEnum = (DrDevice *)ListEnum->Node();
  939. ASSERT(DeviceEnum->IsValid());
  940. if ((DeviceEnum->IsAvailable()) &&
  941. (DeviceEnum->GetDeviceType() == RDPDR_DTYP_FILESYSTEM)) {
  942. InputBuffer->Parameters.Get.TotalEntries ++ ;
  943. PreviousBufferStart = BufferStart;
  944. if (DrPackShareEntry(RxContext,
  945. &BufferStart,
  946. &BufferEnd,
  947. DeviceEnum,
  948. BufferDisplacement,
  949. &InputBuffer->Parameters.Get.TotalBytesNeeded)) {
  950. InputBuffer->Parameters.Get.EntriesRead ++ ;
  951. } else {
  952. Status = STATUS_BUFFER_TOO_SMALL;
  953. }
  954. }
  955. ListEnum = Session->GetDevMgr().GetDevList().Next(ListEnum);
  956. }
  957. Session->GetDevMgr().GetDevList().Unlock();
  958. TableLockHeld = FALSE;
  959. }
  960. try_return(Status);
  961. try_exit:
  962. if (TableLockHeld) {
  963. Session->GetDevMgr().GetDevList().Unlock();
  964. TableLockHeld = FALSE;
  965. }
  966. }
  967. __except(EXCEPTION_EXECUTE_HANDLER) {
  968. if (TableLockHeld) {
  969. Session->GetDevMgr().GetDevList().Unlock();
  970. TableLockHeld = FALSE;
  971. }
  972. return STATUS_INVALID_PARAMETER;
  973. }
  974. return Status;
  975. }
  976. BOOLEAN
  977. DrPackServerEntry (
  978. IN OUT PRX_CONTEXT RxContext,
  979. IN OUT PCHAR *BufferStart,
  980. IN OUT PCHAR *BufferEnd,
  981. IN DrSession* Session,
  982. IN OUT ULONG BufferDisplacement,
  983. OUT PULONG TotalBytesNeeded
  984. )
  985. /*++
  986. Routine Description:
  987. This routine packs a serverlistentry into the buffer provided updating
  988. all relevant pointers. The way that this works is that constant length stuff is
  989. copied to the front of the buffer and variable length stuff to the end. The
  990. "start and end" pointers are updated. You have to calculate the totalbytes correctly
  991. no matter what but a last can be setup incompletely as long as you return false.
  992. the way that this works is that it calls down into the minirdr on the devfcb
  993. interface. it calls down twice and passes a structure back and forth thru the
  994. context to maintain state.
  995. Arguments:
  996. IN OUT PCHAR *BufferStart - Supplies the output buffer.
  997. Updated to point to the next buffer
  998. IN OUT PCHAR *BufferEnd - Supplies the end of the buffer. Updated to
  999. point before the start of the strings being packed.
  1000. IN PNET_ROOT NetRoot - Supplies the NetRoot to enumerate.
  1001. IN OUT PULONG TotalBytesNeeded - Updated to account for the length of this
  1002. entry
  1003. Return Value:
  1004. BOOLEAN - True if the entry was successfully packed into the buffer.
  1005. --*/
  1006. {
  1007. NTSTATUS Status;
  1008. BOOLEAN ReturnValue = TRUE;
  1009. UNICODE_STRING ServerName; // Buffer to hold the packed name
  1010. ULONG BufferSize;
  1011. PRDPDR_SERVER_INFO ServerInfo = (PRDPDR_SERVER_INFO)*BufferStart;
  1012. PCHAR ServerEntryStart;
  1013. BEGIN_FN("DrPackServerEntry");
  1014. //
  1015. // We want the connection name to have string null terminator
  1016. //
  1017. ServerName.Buffer = (PWCHAR)RxAllocatePoolWithTag(NonPagedPool,
  1018. MAX_PATH * sizeof(WCHAR), DR_POOLTAG);
  1019. if (ServerName.Buffer == NULL ) {
  1020. return FALSE;
  1021. }
  1022. BufferSize = sizeof(RDPDR_SERVER_INFO);
  1023. ServerEntryStart = *BufferStart;
  1024. __try {
  1025. *BufferStart = ((PCHAR)*BufferStart) + BufferSize;
  1026. *TotalBytesNeeded += BufferSize;
  1027. //
  1028. // Initialize the name to "\" then add in the rest
  1029. //
  1030. wcscpy(ServerName.Buffer , L"\\\\");
  1031. #if 0
  1032. wcscat(ServerName.Buffer, Session->GetClientName());
  1033. #endif
  1034. wcscat(ServerName.Buffer, DRUNCSERVERNAME_U);
  1035. ServerName.Length = wcslen(ServerName.Buffer) * sizeof(WCHAR);
  1036. ServerName.MaximumLength = ServerName.Length;
  1037. //
  1038. // Update the total number of bytes needed for this structure.
  1039. //
  1040. *TotalBytesNeeded += ServerName.MaximumLength;
  1041. if (*BufferStart > *BufferEnd) {
  1042. try_return( ReturnValue = FALSE);
  1043. }
  1044. ServerInfo->ResumeKey = 0;
  1045. if ((*BufferEnd - *BufferStart) < ServerName.Length) {
  1046. ServerInfo->ServerName.Length = 0;
  1047. try_return( ReturnValue = FALSE);
  1048. }
  1049. else if (!DrPackStringIntoInfoBuffer(
  1050. &ServerInfo->ServerName,
  1051. &ServerName,
  1052. ServerEntryStart,
  1053. BufferEnd,
  1054. BufferDisplacement,
  1055. NULL)) {
  1056. try_return( ReturnValue = FALSE);
  1057. }
  1058. try_exit:
  1059. RxFreePool(ServerName.Buffer);
  1060. }
  1061. __except(EXCEPTION_EXECUTE_HANDLER) {
  1062. RxFreePool(ServerName.Buffer);
  1063. return FALSE;
  1064. }
  1065. return ReturnValue;
  1066. }
  1067. NTSTATUS
  1068. DrEnumerateServers (
  1069. IN PRX_CONTEXT RxContext
  1070. )
  1071. /*++
  1072. Routine Description:
  1073. This routine enumerates the server name on minirdr for a session.
  1074. Arguments:
  1075. IN PRX_CONTEXT RxContext - Describes the Fsctl and Context
  1076. Return Value:
  1077. NTSTATUS
  1078. --*/
  1079. {
  1080. NTSTATUS Status = STATUS_SUCCESS;
  1081. PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
  1082. PRDPDR_REQUEST_PACKET InputBuffer = (PRDPDR_REQUEST_PACKET)(LowIoContext->ParamsFor.FsCtl.pInputBuffer);
  1083. PCHAR OriginalOutputBuffer = (PCHAR)(LowIoContext->ParamsFor.FsCtl.pOutputBuffer);
  1084. ULONG OutputBufferLength = LowIoContext->ParamsFor.FsCtl.OutputBufferLength;
  1085. ULONG InputBufferLength = LowIoContext->ParamsFor.FsCtl.InputBufferLength;
  1086. PCHAR OutputBuffer;
  1087. ULONG BufferDisplacement;
  1088. ULONG ResumeHandle;
  1089. PCHAR BufferStart;
  1090. PCHAR BufferEnd;
  1091. PCHAR PreviousBufferStart;
  1092. ULONG SessionId;
  1093. BOOLEAN TableLockHeld = FALSE;
  1094. SmartPtr<DrSession> Session;
  1095. BEGIN_FN("DrEnumerateServers");
  1096. OutputBuffer = (PCHAR)RxMapUserBuffer( RxContext, RxContext->CurrentIrp );
  1097. BufferDisplacement = (ULONG)(OutputBuffer - OriginalOutputBuffer);
  1098. BufferStart = OutputBuffer;
  1099. BufferEnd = OutputBuffer+OutputBufferLength;
  1100. if (InputBuffer == NULL || OutputBuffer == NULL) {
  1101. return STATUS_INVALID_PARAMETER;
  1102. }
  1103. if (RxContext->CurrentIrp->RequestorMode != KernelMode) {
  1104. TRC_ASSERT((BufferDisplacement == 0),
  1105. (TB, "Request mode is not kernel, non zero Displacement"));
  1106. __try {
  1107. ProbeForWrite(InputBuffer,InputBufferLength,sizeof(UCHAR));
  1108. ProbeForWrite(OutputBuffer,OutputBufferLength,sizeof(UCHAR));
  1109. }
  1110. __except(EXCEPTION_EXECUTE_HANDLER) {
  1111. return STATUS_INVALID_PARAMETER;
  1112. }
  1113. }
  1114. __try {
  1115. if (InputBufferLength < sizeof(RDPDR_REQUEST_PACKET)) {
  1116. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  1117. }
  1118. ResumeHandle = InputBuffer->Parameters.Get.ResumeHandle;
  1119. SessionId = InputBuffer->SessionId;
  1120. InputBuffer->Parameters.Get.EntriesRead = 0;
  1121. InputBuffer->Parameters.Get.TotalEntries = 0;
  1122. InputBuffer->Parameters.Get.TotalBytesNeeded = 0;
  1123. if (Sessions->FindSessionById(SessionId, Session)) {
  1124. InputBuffer->Parameters.Get.TotalEntries ++ ;
  1125. PreviousBufferStart = BufferStart;
  1126. if (DrPackServerEntry(RxContext,
  1127. &BufferStart,
  1128. &BufferEnd,
  1129. Session,
  1130. BufferDisplacement,
  1131. &InputBuffer->Parameters.Get.TotalBytesNeeded)) {
  1132. InputBuffer->Parameters.Get.EntriesRead ++ ;
  1133. Status = STATUS_SUCCESS;
  1134. }
  1135. else {
  1136. Status = STATUS_BUFFER_TOO_SMALL;
  1137. }
  1138. }
  1139. try_return(Status);
  1140. try_exit:NOTHING;
  1141. }
  1142. __except(EXCEPTION_EXECUTE_HANDLER) {
  1143. return STATUS_INVALID_PARAMETER;
  1144. }
  1145. return Status;
  1146. }