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.

2702 lines
74 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name :
  4. rdpdyn.c
  5. Abstract:
  6. This module is the dynamic device management component for RDP device
  7. redirection. It exposes an interface that can be opened by device management
  8. user-mode components running in session context.
  9. Need a check in IRP_MJ_CREATE to make sure that we are not being opened
  10. 2x by the same session. This shouldn't be allowed.
  11. Where can I safely use PAGEDPOOL instead of NONPAGEDPOOL.
  12. Author:
  13. tadb
  14. Revision History:
  15. --*/
  16. #include "precomp.hxx"
  17. #define TRC_FILE "rdpdyn"
  18. #include "trc.h"
  19. #define DRIVER
  20. #include "cfg.h"
  21. #include "pnp.h"
  22. #include "stdarg.h"
  23. #include "stdio.h"
  24. // Just shove the typedefs in for the Power Management functions now because I can't
  25. // get the header conflicts resolved.
  26. #ifdef __cplusplus
  27. extern "C" {
  28. #endif // __cplusplus
  29. NTKERNELAPI VOID PoStartNextPowerIrp(IN PIRP Irp);
  30. NTKERNELAPI NTSTATUS PoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
  31. #ifdef __cplusplus
  32. } // extern "C"
  33. #endif // __cplusplus
  34. ////////////////////////////////////////////////////////////////////////
  35. //
  36. // Defines
  37. //
  38. // Calculate the size of a completed RDPDR_PRINTERDEVICE_SUB event.
  39. #define CALCPRINTERDEVICE_SUB_SZ(rec) \
  40. sizeof(RDPDR_PRINTERDEVICE_SUB) + \
  41. (rec)->clientPrinterFields.PnPNameLen + \
  42. (rec)->clientPrinterFields.DriverLen + \
  43. (rec)->clientPrinterFields.PrinterNameLen + \
  44. (rec)->clientPrinterFields.CachedFieldsLen
  45. // Calculate the size of a completed RDPDR_REMOVEDEVICE event.
  46. #define CALCREMOVEDEVICE_SUB_SZ(rec) \
  47. sizeof(RDPDR_REMOVEDEVICE)
  48. // Calculate the size of a completed RDPDR_PORTDEVICE_SUB event.
  49. #define CALCPORTDEVICE_SUB_SZ(rec) \
  50. sizeof(RDPDR_PORTDEVICE_SUB)
  51. // Calculate the size of a completed RDPDR_DRIVEDEVICE_SUB event.
  52. #define CALCDRIVEDEVICE_SUB_SZ(rec) \
  53. sizeof(RDPDR_DRIVEDEVICE_SUB)
  54. #if DBG
  55. #define DEVMGRCONTEXTMAGICNO 0x55445544
  56. // Test defines.
  57. #define TESTDRIVERNAME L"HP LaserJet 4P"
  58. //#define TESTDRIVERNAME L"This driver has no match"
  59. #define TESTPNPNAME L""
  60. #define TESTPRINTERNAME TESTDRIVERNAME
  61. #define TESTDEVICEID 0xfafafafa
  62. // Test port name.
  63. #define TESTPORTNAME L"LPT1"
  64. #endif
  65. ////////////////////////////////////////////////////////////////////////
  66. //
  67. // Internal Typedefs
  68. //
  69. //
  70. // Context for each open by a user-mode device manager component. This
  71. // structure is stored in the FsContext field of the file object.
  72. //
  73. typedef struct tagDEVMGRCONTEXT
  74. {
  75. #if DBG
  76. ULONG magicNo;
  77. #endif
  78. ULONG sessionID;
  79. } DEVMGRCONTEXT, *PDEVMGRCONTEXT;
  80. //
  81. // Non-Opaque Version of Associated Data for a Device Managed by this Module
  82. //
  83. typedef struct tagRDPDYN_DEVICEDATAREC
  84. {
  85. ULONG PortNumber;
  86. UNICODE_STRING SymbolicLinkName;
  87. } RDPDYN_DEVICEDATAREC, *PRDPDYN_DEVICEDATAREC;
  88. typedef struct tagCLIENTMESSAGECONTEXT {
  89. RDPDR_ClientMessageCB *CB;
  90. PVOID ClientData;
  91. } CLIENTMESSAGECONTEXT, *PCLIENTMESSAGECONTEXT;
  92. ////////////////////////////////////////////////////////////////////////
  93. //
  94. // Internal Prototypes
  95. //
  96. #ifdef __cplusplus
  97. extern "C" {
  98. #endif // __cplusplus
  99. // Return the next available printer port number.
  100. NTSTATUS GetNextPrinterPortNumber(
  101. OUT ULONG *portNumber
  102. );
  103. // Handle file object creation by a client of this driver.
  104. NTSTATUS RDPDYN_Create(
  105. IN PDEVICE_OBJECT DeviceObject,
  106. IN PIRP Irp
  107. );
  108. // Handle file object closure by a client of this driver.
  109. NTSTATUS RDPDYN_Close(
  110. IN PDEVICE_OBJECT DeviceObject,
  111. IN PIRP Irp
  112. );
  113. // This routine modifies the file object in preparation for returning STATUS_REPARSE.
  114. NTSTATUS RDPDYN_PrepareForReparse(
  115. PFILE_OBJECT fileObject
  116. );
  117. // Handle IOCTL IRP's.
  118. NTSTATUS RDPDYN_DeviceControl(
  119. IN PDEVICE_OBJECT DeviceObject,
  120. IN PIRP Irp
  121. );
  122. // This routine modifies the file object in preparation for returning STATUS_REPARSE.
  123. NTSTATUS RDPDYN_PrepareForDevMgmt(
  124. PFILE_OBJECT fileObject,
  125. PCWSTR sessionIDStr,
  126. PIRP irp,
  127. PIO_STACK_LOCATION irpStackLocation
  128. );
  129. // Generates a printer announce message for testing.
  130. NTSTATUS RDPDYN_GenerateTestPrintAnnounceMsg(
  131. IN OUT PRDPDR_DEVICE_ANNOUNCE devAnnounceMsg,
  132. IN ULONG devAnnounceMsgSize,
  133. OPTIONAL OUT ULONG *prnAnnounceMsgReqSize
  134. );
  135. // Completely handles IOCTL_RDPDR_GETNEXTDEVMGMTEVENT IRP's.
  136. NTSTATUS RDPDYN_HandleGetNextDevMgmtEventIOCTL(
  137. IN PDEVICE_OBJECT deviceObject,
  138. IN PIRP irp
  139. );
  140. // Handle the cleanup IRP for a file object.
  141. NTSTATUS RDPDYN_Cleanup(
  142. IN PDEVICE_OBJECT DeviceObject,
  143. IN PIRP Irp
  144. );
  145. // Calculate the size of a device management event.
  146. ULONG RDPDYN_DevMgmtEventSize(
  147. IN PVOID devMgmtEvent,
  148. IN ULONG type
  149. );
  150. // Completely handles IOCTL_RDPDR_CLIENTMSG IRP's.
  151. NTSTATUS RDPDYN_HandleClientMsgIOCTL(
  152. IN PDEVICE_OBJECT deviceObject,
  153. IN PIRP pIrp
  154. );
  155. // Complete a pending IRP with a device management event.
  156. NTSTATUS CompleteIRPWithDevMgmtEvent(
  157. IN PDEVICE_OBJECT deviceObject,
  158. IN PIRP pIrp,
  159. IN ULONG eventSize,
  160. IN ULONG eventType,
  161. IN PVOID event,
  162. IN DrDevice *drDevice
  163. );
  164. // Complete a pending IRP with a resize buffer event to the user-mode
  165. // component.
  166. NTSTATUS CompleteIRPWithResizeMsg(
  167. IN PIRP pIrp,
  168. IN ULONG requiredUserBufSize
  169. );
  170. // Format a port description.
  171. void GeneratePortDescription(
  172. IN PCSTR dosPortName,
  173. IN PCWSTR clientName,
  174. IN PWSTR description
  175. );
  176. NTSTATUS NTAPI DrSendMessageToClientCompletion(PVOID Context,
  177. PIO_STATUS_BLOCK IoStatusBlock);
  178. #if DBG
  179. // This is for testing so we can create a new test printer on
  180. // demand from user-mode.
  181. NTSTATUS RDPDYN_HandleDbgAddNewPrnIOCTL(
  182. IN PDEVICE_OBJECT deviceObject,
  183. IN PIRP pIrp
  184. );
  185. // Generates a printer announce message for testing.
  186. void RDPDYN_TracePrintAnnounceMsg(
  187. IN OUT PRDPDR_DEVICE_ANNOUNCE devAnnounceMsg,
  188. IN ULONG sessionID,
  189. IN PCWSTR portName,
  190. IN PCWSTR clientName
  191. );
  192. #endif
  193. // Returns the next pending device management event request for the specified
  194. // session, in the form of an IRP. Note that this function can not be called
  195. // if a spinlock has been acquired.
  196. PIRP GetNextEventRequest(
  197. IN RDPEVNTLIST list,
  198. IN ULONG sessionID
  199. );
  200. #ifdef __cplusplus
  201. } // extern "C"
  202. #endif // __cplusplus
  203. ////////////////////////////////////////////////////////////////////////
  204. //
  205. // Globals
  206. //
  207. // Pointer to the device Object for the minirdr. This global is defined in rdpdr.c.
  208. extern PRDBSS_DEVICE_OBJECT DrDeviceObject;
  209. //
  210. // Global Registry Path for RDPDR.SYS. This global is defined in rdpdr.c.
  211. //
  212. extern UNICODE_STRING DrRegistryPath;
  213. // The Physical Device Object that terminates our DO stack.
  214. PDEVICE_OBJECT RDPDYN_PDO = NULL;
  215. // Manages user-mode component device management events and event requests.
  216. RDPEVNTLIST UserModeEventListMgr = RDPEVNTLIST_INVALID_LIST;
  217. // Remove this check, eventually.
  218. #if DBG
  219. BOOL RDPDYN_StopReceived = FALSE;
  220. BOOL RDPDYN_QueryStopReceived = FALSE;
  221. DWORD RDPDYN_StartCount = 0;
  222. #endif
  223. ////////////////////////////////////////////////////////////////////////
  224. //
  225. // Function Definitions
  226. //
  227. NTSTATUS
  228. RDPDYN_Initialize(
  229. )
  230. /*++
  231. Routine Description:
  232. Init function for this module.
  233. Arguments:
  234. Return Value:
  235. Status
  236. --*/
  237. {
  238. NTSTATUS status;
  239. BEGIN_FN("RDPDYN_Initialize");
  240. //
  241. // Create the user-mode device event manager.
  242. //
  243. TRC_ASSERT(UserModeEventListMgr == RDPEVNTLIST_INVALID_LIST,
  244. (TB, "Initialize called more than 1 time"));
  245. UserModeEventListMgr = RDPEVNTLIST_CreateNewList();
  246. if (UserModeEventListMgr != RDPEVNTLIST_INVALID_LIST) {
  247. status = STATUS_SUCCESS;
  248. }
  249. else {
  250. status = STATUS_UNSUCCESSFUL;
  251. }
  252. //
  253. // Initialize the dynamic port management module.
  254. //
  255. if (status == STATUS_SUCCESS) {
  256. status = RDPDRPRT_Initialize();
  257. }
  258. TRC_NRM((TB, "return status %08X.", status));
  259. return status;
  260. }
  261. NTSTATUS
  262. RDPDYN_Shutdown(
  263. )
  264. /*++
  265. Routine Description:
  266. Shutdown function for this module.
  267. Arguments:
  268. Return Value:
  269. Status
  270. --*/
  271. {
  272. ULONG sessionID;
  273. void *devMgmtEvent;
  274. PIRP pIrp;
  275. ULONG type;
  276. #if DBG
  277. ULONG sz;
  278. #endif
  279. DrDevice *device;
  280. KIRQL oldIrql;
  281. PDRIVER_CANCEL setCancelResult;
  282. BEGIN_FN("RDPDYN_Shutdown");
  283. //
  284. // Clean up any pending device management events and any pending IRP's.
  285. //
  286. TRC_ASSERT(UserModeEventListMgr != RDPEVNTLIST_INVALID_LIST,
  287. (TB, "Invalid list mgr"));
  288. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  289. while (RDPEVNTLLIST_GetFirstSessionID(UserModeEventListMgr, &sessionID)) {
  290. //
  291. // Remove pending IRP's
  292. //
  293. pIrp = (PIRP)RDPEVNTLIST_DequeueRequest(
  294. UserModeEventListMgr,
  295. sessionID
  296. );
  297. while (pIrp != NULL) {
  298. //
  299. // Set the cancel routine to NULL and record the current state.
  300. //
  301. setCancelResult = IoSetCancelRoutine(pIrp, NULL);
  302. //
  303. // Fail the IRP request.
  304. //
  305. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  306. //
  307. // If the IRP is not being canceled.
  308. //
  309. if (setCancelResult != NULL) {
  310. //
  311. // Fail the request.
  312. //
  313. pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  314. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  315. }
  316. //
  317. // Remove the next IRP from the event/request queue.
  318. //
  319. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  320. pIrp = (PIRP)RDPEVNTLIST_DequeueRequest(
  321. UserModeEventListMgr,
  322. sessionID
  323. );
  324. }
  325. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  326. //
  327. // Remove pending device management events.
  328. //
  329. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  330. while (RDPEVNTLIST_DequeueEvent(
  331. UserModeEventListMgr,
  332. sessionID, &type,
  333. &devMgmtEvent,
  334. &device
  335. )) {
  336. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  337. #if DBG
  338. // Zero the free'd event in checked builds.
  339. sz = RDPDYN_DevMgmtEventSize(devMgmtEvent, type);
  340. if (sz > 0) {
  341. RtlZeroMemory(devMgmtEvent, sz);
  342. }
  343. #endif
  344. if (devMgmtEvent != NULL) {
  345. delete devMgmtEvent;
  346. }
  347. // Release the device, if appropriate.
  348. if (device != NULL) {
  349. device->Release();
  350. }
  351. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  352. }
  353. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  354. }
  355. //
  356. // Shut down the dynamic port management module.
  357. //
  358. RDPDRPRT_Shutdown();
  359. return STATUS_SUCCESS;
  360. }
  361. NTSTATUS
  362. RDPDYN_Dispatch(
  363. IN PDEVICE_OBJECT DeviceObject,
  364. IN PIRP Irp
  365. )
  366. /*++
  367. Routine Description:
  368. Handle IRP's for DO's sitting on top of our physical device object.
  369. Arguments:
  370. DeviceObject - Supplies the device object for the packet being processed.
  371. Irp - Supplies the Irp being processed
  372. Return Value:
  373. NTSTATUS - The status for the Irp
  374. --*/
  375. {
  376. PIO_STACK_LOCATION ioStackLocation;
  377. NTSTATUS status;
  378. PRDPDYNDEVICE_EXTENSION deviceExtension;
  379. PDEVICE_OBJECT stackDeviceObject;
  380. BOOLEAN isPowerIRP;
  381. BEGIN_FN("RDPDYN_Dispatch");
  382. //
  383. // Get our location in the IRP stack.
  384. //
  385. ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  386. TRC_NRM((TB, "Major is %08X", ioStackLocation->MajorFunction));
  387. //
  388. // Get our device extension and stack device object.
  389. //
  390. deviceExtension = (PRDPDYNDEVICE_EXTENSION)DeviceObject->DeviceExtension;
  391. TRC_ASSERT(deviceExtension != NULL, (TB, "Invalid device extension."));
  392. if (deviceExtension == NULL) {
  393. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  394. return STATUS_UNSUCCESSFUL;
  395. }
  396. stackDeviceObject = deviceExtension->TopOfStackDeviceObject;
  397. TRC_ASSERT(stackDeviceObject != NULL, (TB, "Invalid device object."));
  398. //
  399. // Function Dispatch Switch
  400. //
  401. isPowerIRP = FALSE;
  402. switch (ioStackLocation->MajorFunction)
  403. {
  404. case IRP_MJ_CREATE:
  405. TRC_NRM((TB, "IRP_MJ_CREATE"));
  406. // RDPDYN_Create handles this completely.
  407. return RDPDYN_Create(DeviceObject, Irp);
  408. case IRP_MJ_CLOSE:
  409. TRC_NRM((TB, "IRP_MJ_CLOSE"));
  410. // RDPDYN_Close handles this completely.
  411. return RDPDYN_Close(DeviceObject, Irp);
  412. case IRP_MJ_CLEANUP:
  413. TRC_NRM((TB, "IRP_MJ_CLEANUP"));
  414. // RDPDYN_Cleanup handles this completely.
  415. return RDPDYN_Cleanup(DeviceObject, Irp);
  416. case IRP_MJ_READ:
  417. // We shouldn't be receiving any read requests.
  418. TRC_ASSERT(FALSE, (TB, "Read requests not supported."));
  419. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  420. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  421. return STATUS_NOT_SUPPORTED;
  422. case IRP_MJ_WRITE:
  423. // We shouldn't be receiving any write requests.
  424. TRC_ASSERT(FALSE, (TB, "Write requests not supported."));
  425. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  426. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  427. return STATUS_NOT_SUPPORTED;
  428. case IRP_MJ_DEVICE_CONTROL:
  429. // RDPDYN_DeviceControl handles this completely.
  430. return RDPDYN_DeviceControl(DeviceObject, Irp);
  431. case IRP_MJ_POWER:
  432. TRC_NRM((TB, "IRP_MJ_POWER"));
  433. isPowerIRP = TRUE;
  434. switch (ioStackLocation->MinorFunction)
  435. {
  436. case IRP_MN_SET_POWER:
  437. Irp->IoStatus.Status = STATUS_SUCCESS;
  438. break;
  439. default:
  440. TRC_NRM((TB, "Unknown Power IRP"));
  441. }
  442. break;
  443. case IRP_MJ_PNP: TRC_NRM((TB, "IRP_MJ_PNP"));
  444. switch (ioStackLocation->MinorFunction)
  445. {
  446. case IRP_MN_START_DEVICE:
  447. #if DBG
  448. // Remove this debug code, eventually.
  449. RDPDYN_StartCount++;
  450. #endif
  451. return(RDPDRPNP_HandleStartDeviceIRP(stackDeviceObject,
  452. ioStackLocation, Irp));
  453. case IRP_MN_STOP_DEVICE:
  454. #if DBG
  455. // Remove this debug code, eventually.
  456. RDPDYN_StopReceived = TRUE;
  457. #endif
  458. TRC_NRM((TB, "IRP_MN_STOP_DEVICE"));
  459. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  460. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  461. return STATUS_UNSUCCESSFUL;
  462. case IRP_MN_REMOVE_DEVICE:
  463. return(RDPDRPNP_HandleRemoveDeviceIRP(DeviceObject,
  464. stackDeviceObject, Irp));
  465. case IRP_MN_QUERY_CAPABILITIES:
  466. TRC_NRM((TB, "IRP_MN_QUERY_CAPABILITIES"));
  467. break;
  468. case IRP_MN_QUERY_ID:
  469. TRC_NRM((TB, "IRP_MN_QUERY_ID"));
  470. break;
  471. case IRP_MN_QUERY_DEVICE_RELATIONS:
  472. TRC_NRM((TB, "IRP_MN_QUERY_DEVICE_RELATIONS"));
  473. switch(ioStackLocation->Parameters.QueryDeviceRelations.Type)
  474. {
  475. case EjectionRelations:
  476. TRC_NRM((TB, "Type==EjectionRelations"));
  477. break;
  478. case BusRelations:
  479. // Note that we need to handle this if we end up kicking out any PDO's.
  480. TRC_NRM((TB, "Type==BusRelations"));
  481. break;
  482. case PowerRelations:
  483. TRC_NRM((TB, "Type==PowerRelations"));
  484. Irp->IoStatus.Status = STATUS_SUCCESS;
  485. break;
  486. case RemovalRelations:
  487. TRC_NRM((TB, "Type==RemovalRelations"));
  488. Irp->IoStatus.Status = STATUS_SUCCESS;
  489. break;
  490. case TargetDeviceRelation:
  491. TRC_NRM((TB, "Type==TargetDeviceRelation"));
  492. break;
  493. default:
  494. TRC_NRM((TB, "Unknown IRP_MN_QUERY_DEVICE_RELATIONS minor type"));
  495. }
  496. break;
  497. case IRP_MN_QUERY_STOP_DEVICE:
  498. #if DBG
  499. // Remove this debug code, eventually.
  500. RDPDYN_QueryStopReceived = TRUE;
  501. #endif
  502. // We will not allow a device to be stopped for load balancing.
  503. TRC_NRM((TB, "IRP_MN_QUERY_STOP_DEVICE"));
  504. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  505. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  506. return STATUS_UNSUCCESSFUL;
  507. case IRP_MN_QUERY_REMOVE_DEVICE:
  508. // We will not allow our device to be removed.
  509. TRC_NRM((TB, "IRP_MN_QUERY_REMOVE_DEVICE"));
  510. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  511. Irp->IoStatus.Information = 0;
  512. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  513. return STATUS_UNSUCCESSFUL;
  514. case IRP_MN_CANCEL_STOP_DEVICE:
  515. TRC_NRM((TB, "IRP_MN_CANCEL_STOP_DEVICE"));
  516. Irp->IoStatus.Status = STATUS_SUCCESS;
  517. break;
  518. case IRP_MN_CANCEL_REMOVE_DEVICE:
  519. TRC_NRM((TB, "IRP_MN_CANCEL_REMOVE_DEVICE"));
  520. Irp->IoStatus.Status = STATUS_SUCCESS;
  521. break;
  522. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
  523. TRC_NRM((TB, "IRP_MN_FILTER_RESOURCE_REQUIREMENTS"));
  524. break;
  525. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  526. TRC_NRM((TB, "IRP_MN_QUERY_PNP_DEVICE_STATE"));
  527. break;
  528. case IRP_MN_QUERY_BUS_INFORMATION:
  529. TRC_NRM((TB, "IRP_MN_QUERY_BUS_INFORMATION"));
  530. break;
  531. default:
  532. TRC_ALT((TB, "Unhandled PnP IRP with minor %08X",
  533. ioStackLocation->MinorFunction));
  534. }
  535. }
  536. //
  537. // By default, pass the IRP down the stack.
  538. //
  539. if (isPowerIRP) {
  540. PoStartNextPowerIrp(Irp);
  541. IoSkipCurrentIrpStackLocation(Irp);
  542. return PoCallDriver(stackDeviceObject, Irp);
  543. }
  544. else {
  545. IoSkipCurrentIrpStackLocation(Irp);
  546. return IoCallDriver(stackDeviceObject,Irp);
  547. }
  548. }
  549. NTSTATUS
  550. RDPDYN_Create(
  551. IN PDEVICE_OBJECT DeviceObject,
  552. IN PIRP Irp
  553. )
  554. /*++
  555. Routine Description:
  556. Entry point for CreateFile calls.
  557. Arguments:
  558. DeviceObject - pointer to our device object.
  559. Return Value:
  560. NT status code
  561. --*/
  562. {
  563. NTSTATUS ntStatus;
  564. PFILE_OBJECT fileObject;
  565. PIO_STACK_LOCATION nextStackLocation;
  566. PIO_STACK_LOCATION currentStackLocation;
  567. ULONG i;
  568. BOOL matches;
  569. WCHAR sessionIDString[]=RDPDYN_SESSIONIDSTRING;
  570. ULONG idStrLen;
  571. WCHAR *sessionIDPtr;
  572. ULONG fnameLength;
  573. BEGIN_FN("RDPDYN_Create");
  574. // Get the current stack location.
  575. currentStackLocation = IoGetCurrentIrpStackLocation(Irp);
  576. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  577. fileObject = currentStackLocation->FileObject;
  578. // Return STATUS_REPARSE with the minirdr DO so it gets opened instead, if
  579. // we have a file name.
  580. if (fileObject->FileName.Length != 0)
  581. {
  582. //
  583. // Find out if the client is trying to open us as the device manager from
  584. // user-mode.
  585. //
  586. // Check for the session identifer string as the first few characters in
  587. // the reference string.
  588. idStrLen = wcslen(sessionIDString);
  589. fnameLength = fileObject->FileName.Length/sizeof(WCHAR);
  590. for (i=0; i<fnameLength && i<idStrLen; i++) {
  591. if (fileObject->FileName.Buffer[i] != sessionIDString[i]) {
  592. break;
  593. }
  594. }
  595. matches = (i == idStrLen);
  596. //
  597. // If the client is trying to open us as the device manager from user-
  598. // mode.
  599. //
  600. if (matches) {
  601. // Prepare the file object for managing device management comms to
  602. // the user-mode component that opened it.
  603. ntStatus = RDPDYN_PrepareForDevMgmt(
  604. fileObject,
  605. &fileObject->FileName.Buffer[idStrLen],
  606. Irp, currentStackLocation
  607. );
  608. }
  609. // Otherwise, we can assume that this create is for a device that is being
  610. // managed by RDPDR and the IFS kit.
  611. else {
  612. // Prepare the file object for reparse.
  613. ntStatus = RDPDYN_PrepareForReparse(fileObject);
  614. }
  615. }
  616. // Otherwise, fail. This should never happen.
  617. else
  618. {
  619. ntStatus = STATUS_UNSUCCESSFUL;
  620. }
  621. // Complete the IO request and return.
  622. Irp->IoStatus.Status = ntStatus;
  623. Irp->IoStatus.Information = 0;
  624. IoCompleteRequest (Irp,
  625. IO_NO_INCREMENT
  626. );
  627. return ntStatus;
  628. }
  629. NTSTATUS
  630. RDPDYN_PrepareForReparse(
  631. PFILE_OBJECT fileObject
  632. )
  633. /*++
  634. Routine Description:
  635. This routine modifies the file object in preparation for returning
  636. STATUS_REPARSE
  637. Arguments:
  638. fileObject - the file object
  639. Return Value:
  640. STATUS_REPARSE if everything is successful
  641. Notes:
  642. --*/
  643. {
  644. NTSTATUS ntStatus;
  645. USHORT rootDeviceNameLength, reparsePathLength,
  646. clientDevicePathLength;
  647. PWSTR pFileNameBuffer = NULL;
  648. ULONG i;
  649. ULONG len;
  650. BOOL clientDevPathMissingSlash;
  651. HANDLE deviceInterfaceKey = INVALID_HANDLE_VALUE;
  652. UNICODE_STRING unicodeStr;
  653. ULONG requiredBytes;
  654. PKEY_VALUE_PARTIAL_INFORMATION keyValueInfo = NULL;
  655. WCHAR *clientDevicePath=L"";
  656. GUID *pPrinterGuid;
  657. UNICODE_STRING symbolicLinkName;
  658. WCHAR *refString;
  659. BEGIN_FN("RDPDYN_PrepareForReparse");
  660. // We are not going to use these fields for storing any contextual
  661. // information.
  662. fileObject->FsContext = NULL;
  663. fileObject->FsContext2 = NULL;
  664. // Compute the number of bytes required to store the root of the device
  665. // path, without the terminator.
  666. rootDeviceNameLength = wcslen(RDPDR_DEVICE_NAME_U) *
  667. sizeof(WCHAR);
  668. //
  669. // Get a pointer to the reference string for the reparse.
  670. //
  671. if (fileObject->FileName.Buffer[0] == L'\\') {
  672. refString = &fileObject->FileName.Buffer[1];
  673. }
  674. else {
  675. refString = &fileObject->FileName.Buffer[0];
  676. }
  677. //
  678. // Resolve the reference name for the device into the symbolic link
  679. // name for the device interface. We can optimize out this
  680. // step and the next one by maintaining an internal table to convert
  681. // from port names to symbolic link names.
  682. //
  683. pPrinterGuid = (GUID *)&DYNPRINT_GUID;
  684. RtlInitUnicodeString(&unicodeStr, refString);
  685. ntStatus=IoRegisterDeviceInterface(
  686. RDPDYN_PDO, pPrinterGuid, &unicodeStr,
  687. &symbolicLinkName
  688. );
  689. if (ntStatus == STATUS_SUCCESS) {
  690. TRC_ERR((TB, "IoRegisterDeviceInterface succeeded."));
  691. //
  692. // Open the registry key for the device being opened.
  693. //
  694. ntStatus = IoOpenDeviceInterfaceRegistryKey(
  695. &symbolicLinkName,
  696. KEY_ALL_ACCESS,
  697. &deviceInterfaceKey
  698. );
  699. RtlFreeUnicodeString(&symbolicLinkName);
  700. }
  701. //
  702. // Get the size of the value info buffer required for the client device
  703. // path for the device being opened.
  704. //
  705. if (ntStatus == STATUS_SUCCESS) {
  706. TRC_NRM((TB, "IoOpenDeviceInterfaceRegistryKey succeeded."));
  707. RtlInitUnicodeString(&unicodeStr, CLIENT_DEVICE_VALUE_NAME);
  708. ntStatus = ZwQueryValueKey(
  709. deviceInterfaceKey,
  710. &unicodeStr,
  711. KeyValuePartialInformation,
  712. NULL, 0,
  713. &requiredBytes
  714. );
  715. }
  716. else {
  717. TRC_NRM((TB, "IoOpenDeviceInterfaceRegistryKey failed: %08X.", ntStatus));
  718. deviceInterfaceKey = INVALID_HANDLE_VALUE;
  719. }
  720. //
  721. // Size the data buffer.
  722. //
  723. if (ntStatus == STATUS_BUFFER_TOO_SMALL) {
  724. keyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)
  725. new(NonPagedPool) BYTE[requiredBytes];
  726. if (keyValueInfo != NULL) {
  727. ntStatus = STATUS_SUCCESS;
  728. }
  729. else {
  730. TRC_NRM((TB, "failed to allocate client device path."));
  731. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  732. }
  733. }
  734. //
  735. // Read the client device path.
  736. //
  737. if (ntStatus == STATUS_SUCCESS) {
  738. ntStatus = ZwQueryValueKey(
  739. deviceInterfaceKey,
  740. &unicodeStr,
  741. KeyValuePartialInformation,
  742. keyValueInfo, requiredBytes,
  743. &requiredBytes
  744. );
  745. }
  746. //
  747. // Allocate the reparsed filename.
  748. //
  749. if (ntStatus == STATUS_SUCCESS) {
  750. TRC_NRM((TB, "ZwQueryValueKey succeeded."));
  751. clientDevicePath = (WCHAR *)keyValueInfo->Data;
  752. // Compute the number of bytes required to store the client device path,
  753. // without the terminator.
  754. clientDevicePathLength = wcslen(clientDevicePath) *
  755. sizeof(WCHAR);
  756. // See if the client device path is prefixed by a '\'
  757. clientDevPathMissingSlash = clientDevicePath[0] != L'\\';
  758. // Get the length (in bytes) of the entire reparsed device path, without the
  759. // terminator.
  760. reparsePathLength = rootDeviceNameLength +
  761. clientDevicePathLength;
  762. if (clientDevPathMissingSlash) {
  763. reparsePathLength += sizeof(WCHAR);
  764. }
  765. pFileNameBuffer = (PWSTR)ExAllocatePoolWithTag(
  766. NonPagedPool,
  767. reparsePathLength + (1 * sizeof(WCHAR)),
  768. RDPDYN_POOLTAG);
  769. if (pFileNameBuffer == NULL) {
  770. TRC_NRM((TB, "failed to allocate reparse buffer."));
  771. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  772. }
  773. }
  774. //
  775. // Assign the reparse string to the IRP's file name for reparse.
  776. //
  777. if (ntStatus == STATUS_SUCCESS) {
  778. // Copy the device name
  779. RtlCopyMemory(
  780. pFileNameBuffer,
  781. RDPDR_DEVICE_NAME_U,
  782. rootDeviceNameLength);
  783. // Make sure we get a '\' between the root device name and
  784. // the device path.
  785. if (clientDevPathMissingSlash) {
  786. pFileNameBuffer[rootDeviceNameLength/sizeof(WCHAR)] = L'\\';
  787. rootDeviceNameLength += sizeof(WCHAR);
  788. }
  789. // Append the client device path to the end of the device name and
  790. // include the client device path's terminator.
  791. RtlCopyMemory(
  792. ((PBYTE)pFileNameBuffer + rootDeviceNameLength),
  793. clientDevicePath, clientDevicePathLength + (1 * sizeof(WCHAR))
  794. );
  795. // Release the IRP's previous file name.
  796. ExFreePool(fileObject->FileName.Buffer);
  797. // Assign the reparse string to the IRP's file name.
  798. fileObject->FileName.Buffer = pFileNameBuffer;
  799. fileObject->FileName.Length = reparsePathLength;
  800. fileObject->FileName.MaximumLength = fileObject->FileName.Length;
  801. ntStatus = STATUS_REPARSE;
  802. } else {
  803. TRC_ERR((TB, "failed with status %08X.", ntStatus));
  804. if (pFileNameBuffer != NULL) {
  805. ExFreePool(pFileNameBuffer);
  806. pFileNameBuffer = NULL;
  807. }
  808. }
  809. TRC_NRM((TB, "device file name after processing %wZ.",
  810. &fileObject->FileName));
  811. //
  812. // Clean up and exit.
  813. //
  814. if (deviceInterfaceKey != INVALID_HANDLE_VALUE) {
  815. ZwClose(deviceInterfaceKey);
  816. }
  817. if (keyValueInfo != NULL) {
  818. delete keyValueInfo;
  819. }
  820. return ntStatus;
  821. }
  822. NTSTATUS
  823. RDPDYN_PrepareForDevMgmt(
  824. PFILE_OBJECT fileObject,
  825. PCWSTR sessionIDStr,
  826. PIRP irp,
  827. PIO_STACK_LOCATION irpStackLocation
  828. )
  829. /*++
  830. Routine Description:
  831. This routine modifies the file object for managing device management comms
  832. with the user-mode component that opened us.
  833. Arguments:
  834. fileObject - the file object.
  835. sessionID - session identifier string.
  836. irp - irp corresponding to the create for this file object.
  837. irpStackLocation - current location in the IRP stack for the create.
  838. Return Value:
  839. STATUS_SUCCESS if everything is successful
  840. Notes:
  841. --*/
  842. {
  843. PDEVMGRCONTEXT context;
  844. ULONG sessionID;
  845. ULONG i;
  846. UNICODE_STRING uncSessionID;
  847. NTSTATUS ntStatus;
  848. ULONG irpSessionId;
  849. BEGIN_FN("RDPDYN_PrepareForDevMgmt");
  850. //
  851. // Security check the IRP to make sure it comes from a thread
  852. // with admin privilege
  853. //
  854. if (!DrIsAdminIoRequest(irp, irpStackLocation)) {
  855. TRC_ALT((TB, "Access denied for non-Admin IRP."));
  856. return STATUS_ACCESS_DENIED;
  857. } else {
  858. TRC_DBG((TB, "Admin IRP accepted."));
  859. }
  860. //
  861. // Convert the session identifier string into a number.
  862. //
  863. RtlInitUnicodeString(&uncSessionID, sessionIDStr);
  864. ntStatus = RtlUnicodeStringToInteger(&uncSessionID, 10, &sessionID);
  865. if (!NT_SUCCESS(ntStatus)) {
  866. return ntStatus;
  867. }
  868. //
  869. // Allocate a context struct so we can remember information about
  870. // which session we were opened from.
  871. //
  872. context = new(NonPagedPool) DEVMGRCONTEXT;
  873. if (context == NULL) {
  874. return STATUS_NO_MEMORY;
  875. }
  876. // Initialize this struct.
  877. #if DBG
  878. context->magicNo = DEVMGRCONTEXTMAGICNO;
  879. #endif
  880. context->sessionID = sessionID;
  881. fileObject->FsContext = context;
  882. // Success.
  883. return STATUS_SUCCESS;
  884. }
  885. NTSTATUS
  886. RDPDYN_Close(
  887. IN PDEVICE_OBJECT DeviceObject,
  888. IN PIRP Irp
  889. )
  890. /*++
  891. Routine Description:
  892. Handle the closure of a file object.
  893. Arguments:
  894. Return Value:
  895. NT status code
  896. --*/
  897. {
  898. NTSTATUS ntStatus;
  899. PFILE_OBJECT fileObject;
  900. PIO_STACK_LOCATION irpStack;
  901. PDEVMGRCONTEXT context;
  902. PIRP pIrp;
  903. KIRQL oldIrql;
  904. PDRIVER_CANCEL setCancelResult;
  905. BEGIN_FN("RDPDYN_Close");
  906. irpStack = IoGetCurrentIrpStackLocation (Irp);
  907. fileObject = irpStack->FileObject;
  908. // Grab our "open" context for this instance of us from the current stack
  909. // location's file object.
  910. context = (PDEVMGRCONTEXT)irpStack->FileObject->FsContext;
  911. TRC_ASSERT(context->magicNo == DEVMGRCONTEXTMAGICNO, (TB, "invalid context"));
  912. //
  913. // Make sure we got all the pending IRP's.
  914. //
  915. TRC_ASSERT(UserModeEventListMgr != NULL, (TB, "RdpDyn EventList is NULL"));
  916. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  917. pIrp = (PIRP)RDPEVNTLIST_DequeueRequest(
  918. UserModeEventListMgr,
  919. context->sessionID
  920. );
  921. while (pIrp != NULL) {
  922. //
  923. // Set the cancel routine to NULL and record the current state.
  924. //
  925. setCancelResult = IoSetCancelRoutine(pIrp, NULL);
  926. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  927. TRC_NRM((TB, "canceling an IRP."));
  928. //
  929. // If the IRP is not being canceled.
  930. //
  931. if (setCancelResult != NULL) {
  932. //
  933. // Fail the request.
  934. //
  935. pIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  936. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  937. }
  938. //
  939. // Get the next one.
  940. //
  941. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  942. pIrp = (PIRP)RDPEVNTLIST_DequeueRequest(
  943. UserModeEventListMgr,
  944. context->sessionID
  945. );
  946. }
  947. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  948. //
  949. // Release our context.
  950. //
  951. delete context;
  952. irpStack->FileObject->FsContext = NULL;
  953. Irp->IoStatus.Status = STATUS_CANCELLED;
  954. Irp->IoStatus.Information = 0;
  955. ntStatus = Irp->IoStatus.Status;
  956. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  957. return ntStatus;
  958. }
  959. NTSTATUS
  960. RDPDYN_Cleanup(
  961. IN PDEVICE_OBJECT DeviceObject,
  962. IN PIRP Irp
  963. )
  964. /*++
  965. Routine Description:
  966. Handle the cleanup IRP for a file object.
  967. Arguments:
  968. Return Value:
  969. NT status code
  970. --*/
  971. {
  972. NTSTATUS ntStatus;
  973. PFILE_OBJECT fileObject;
  974. PIO_STACK_LOCATION irpStack;
  975. PDEVMGRCONTEXT context;
  976. KIRQL oldIrql;
  977. PIRP pIrp;
  978. PDRIVER_CANCEL setCancelResult;
  979. BEGIN_FN("RDPDYN_Cleanup");
  980. irpStack = IoGetCurrentIrpStackLocation (Irp);
  981. fileObject = irpStack->FileObject;
  982. // Grab our "open" context for this instance of us from the current stack
  983. // location's file object.
  984. context = (PDEVMGRCONTEXT)irpStack->FileObject->FsContext;
  985. TRC_ASSERT(context->magicNo == DEVMGRCONTEXTMAGICNO, (TB, "invalid context"));
  986. TRC_NRM((TB, "cancelling IRP's for session %ld.",
  987. context->sessionID));
  988. //
  989. // Remove pending requests (IRP's)
  990. // Nothing to do if event list is NULL
  991. //
  992. TRC_ASSERT(UserModeEventListMgr != NULL, (TB, "RdpDyn EventList is NULL"));
  993. if (UserModeEventListMgr == NULL) {
  994. goto CleanupAndExit;
  995. }
  996. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  997. pIrp = (PIRP)RDPEVNTLIST_DequeueRequest(
  998. UserModeEventListMgr,
  999. context->sessionID
  1000. );
  1001. while (pIrp != NULL) {
  1002. //
  1003. // Set the cancel routine to NULL and record the current state.
  1004. //
  1005. setCancelResult = IoSetCancelRoutine(pIrp, NULL);
  1006. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1007. TRC_NRM((TB, "canceling an IRP."));
  1008. //
  1009. // If the IRP is not being canceled.
  1010. //
  1011. if (setCancelResult != NULL) {
  1012. //
  1013. // Fail the request.
  1014. //
  1015. pIrp->IoStatus.Status = STATUS_CANCELLED;
  1016. pIrp->IoStatus.Information = 0;
  1017. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1018. }
  1019. //
  1020. // Get the next one.
  1021. //
  1022. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1023. pIrp = (PIRP)RDPEVNTLIST_DequeueRequest(
  1024. UserModeEventListMgr,
  1025. context->sessionID
  1026. );
  1027. }
  1028. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1029. CleanupAndExit:
  1030. Irp->IoStatus.Status = STATUS_SUCCESS;
  1031. ntStatus = Irp->IoStatus.Status;
  1032. IoCompleteRequest (Irp,
  1033. IO_NO_INCREMENT
  1034. );
  1035. return ntStatus;
  1036. }
  1037. NTSTATUS
  1038. RDPDYN_DeviceControl(
  1039. IN PDEVICE_OBJECT deviceObject,
  1040. IN PIRP irp
  1041. )
  1042. /*++
  1043. Routine Description:
  1044. Handle IOCTL IRP's.
  1045. Arguments:
  1046. DeviceObject - pointer to the device object for this printer.
  1047. Irp - the IRP.
  1048. Return Value:
  1049. NT status code
  1050. --*/
  1051. {
  1052. PIO_STACK_LOCATION currentStackLocation;
  1053. NTSTATUS ntStatus;
  1054. ULONG controlCode;
  1055. BEGIN_FN("RDPDYN_DeviceControl");
  1056. // Get the current stack location.
  1057. currentStackLocation = IoGetCurrentIrpStackLocation(irp);
  1058. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  1059. //
  1060. // Grab some info. out of the stack location.
  1061. //
  1062. controlCode = currentStackLocation->Parameters.DeviceIoControl.IoControlCode;
  1063. //
  1064. // Dispatch the IOCTL.
  1065. //
  1066. switch(controlCode)
  1067. {
  1068. case IOCTL_RDPDR_GETNEXTDEVMGMTEVENT :
  1069. ntStatus = RDPDYN_HandleGetNextDevMgmtEventIOCTL(deviceObject, irp);
  1070. break;
  1071. case IOCTL_RDPDR_CLIENTMSG :
  1072. ntStatus = RDPDYN_HandleClientMsgIOCTL(deviceObject, irp);
  1073. break;
  1074. #if DBG
  1075. case IOCTL_RDPDR_DBGADDNEWPRINTER :
  1076. // This is for testing so we can create a new test printer on
  1077. // demand from user-mode.
  1078. ntStatus = RDPDYN_HandleDbgAddNewPrnIOCTL(deviceObject, irp);
  1079. break;
  1080. #endif
  1081. default :
  1082. TRC_ASSERT(FALSE, (TB, "RPDR.SYS:Invalid IOCTL %08X.", controlCode));
  1083. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1084. irp->IoStatus.Status = ntStatus;
  1085. irp->IoStatus.Information = 0;
  1086. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1087. }
  1088. return ntStatus;
  1089. }
  1090. NTSTATUS
  1091. RDPDYN_HandleClientMsgIOCTL(
  1092. IN PDEVICE_OBJECT deviceObject,
  1093. IN PIRP pIrp
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. Completely handles IOCTL_RDPDR_CLIENTMSG IRP's.
  1098. Arguments:
  1099. DeviceObject - pointer to our device object.
  1100. currentStackLocation - current location on the IRP stack.
  1101. Return Value:
  1102. NT status code
  1103. --*/
  1104. {
  1105. PIO_STACK_LOCATION currentStackLocation;
  1106. PDEVMGRCONTEXT context;
  1107. NTSTATUS ntStatus;
  1108. ULONG inputLength;
  1109. BEGIN_FN("RDPDYN_HandleClientMsgIOCTL");
  1110. //
  1111. // Get the current stack location.
  1112. //
  1113. currentStackLocation = IoGetCurrentIrpStackLocation(pIrp);
  1114. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  1115. //
  1116. // Grab our "open" context for this instance of use from the current stack
  1117. // location's file object.
  1118. //
  1119. context = (PDEVMGRCONTEXT)currentStackLocation->FileObject->FsContext;
  1120. TRC_NRM((TB, "Requestor session ID %d.",
  1121. context->sessionID ));
  1122. TRC_ASSERT(context->magicNo == DEVMGRCONTEXTMAGICNO, (TB, "invalid context"));
  1123. //
  1124. // Grab some information about the user-mode's buffer off the IRP stack.
  1125. //
  1126. inputLength = currentStackLocation->Parameters.DeviceIoControl.InputBufferLength;
  1127. //
  1128. // Send the message to the client.
  1129. //
  1130. ntStatus = DrSendMessageToSession(
  1131. context->sessionID,
  1132. pIrp->AssociatedIrp.SystemBuffer,
  1133. inputLength,
  1134. NULL, NULL
  1135. );
  1136. if (ntStatus != STATUS_SUCCESS) {
  1137. TRC_ERR((TB, "msg failed."));
  1138. // Fail the IRP request.
  1139. pIrp->IoStatus.Status = ntStatus;
  1140. }
  1141. else {
  1142. TRC_ERR((TB, "msg succeeded."));
  1143. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1144. pIrp->IoStatus.Information = 0;
  1145. }
  1146. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1147. return ntStatus;
  1148. }
  1149. VOID DevMgmtEventRequestIRPCancel(
  1150. IN PDEVICE_OBJECT DeviceObject,
  1151. IN PIRP Irp
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. IRP cancel routine that is attached to device mgmt event request IRP's.
  1156. This routine is called with the cancel spinlock held.
  1157. Arguments:
  1158. DeviceObject - pointer to our device object.
  1159. pIrp - The IRP.
  1160. Return Value:
  1161. NA
  1162. --*/
  1163. {
  1164. PIO_STACK_LOCATION currentStackLocation;
  1165. KIRQL oldIrql;
  1166. ULONG sessionID;
  1167. PDEVMGRCONTEXT context;
  1168. BEGIN_FN("DevMgmtEventRequestIRPCancel");
  1169. //
  1170. // Get the current stack location.
  1171. //
  1172. currentStackLocation = IoGetCurrentIrpStackLocation(Irp);
  1173. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  1174. //
  1175. // Grab our "open" context for this instance of use from the current stack
  1176. // location's file object.
  1177. //
  1178. context = (PDEVMGRCONTEXT)currentStackLocation->FileObject->FsContext;
  1179. //
  1180. // Grab the session ID.
  1181. //
  1182. sessionID = context->sessionID;
  1183. TRC_NRM((TB, "session ID %d.", sessionID));
  1184. TRC_ASSERT(context->magicNo == DEVMGRCONTEXTMAGICNO, (TB, "invalid context"));
  1185. //
  1186. // Wax the current cancel routine pointer.
  1187. //
  1188. IoSetCancelRoutine(Irp, NULL);
  1189. //
  1190. // Release the IRP cancellation spinlock.
  1191. //
  1192. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1193. //
  1194. // Remove the request from the device management list.
  1195. //
  1196. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1197. RDPEVNTLIST_DequeueSpecificRequest(UserModeEventListMgr, sessionID, Irp);
  1198. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1199. //
  1200. // Complete the IRP.
  1201. //
  1202. Irp->IoStatus.Information = 0;
  1203. Irp->IoStatus.Status = STATUS_CANCELLED;
  1204. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1205. TRC_NRM((TB, "DevMgmtEventRequestIRPCancel exiting."));
  1206. }
  1207. NTSTATUS
  1208. RDPDYN_HandleGetNextDevMgmtEventIOCTL(
  1209. IN PDEVICE_OBJECT deviceObject,
  1210. IN PIRP pIrp
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. Completely handles IOCTL_RDPDR_GETNEXTDEVMGMTEVENT IRP's.
  1215. Arguments:
  1216. DeviceObject - pointer to our device object.
  1217. pIrp - The IRP.
  1218. Return Value:
  1219. NT status code
  1220. --*/
  1221. {
  1222. PIO_STACK_LOCATION currentStackLocation;
  1223. NTSTATUS status;
  1224. ULONG outputLength;
  1225. PDEVMGRCONTEXT context;
  1226. ULONG evType;
  1227. PVOID evt;
  1228. DrDevice *drDevice;
  1229. KIRQL oldIrql;
  1230. ULONG sessionID;
  1231. ULONG eventSize;
  1232. ULONG requiredUserBufSize;
  1233. BEGIN_FN("RDPDYN_HandleGetNextDevMgmtEventIOCTL");
  1234. //
  1235. // Get the current stack location.
  1236. //
  1237. currentStackLocation = IoGetCurrentIrpStackLocation(pIrp);
  1238. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  1239. //
  1240. // Grab our "open" context for this instance of use from the current stack
  1241. // location's file object.
  1242. //
  1243. context = (PDEVMGRCONTEXT)currentStackLocation->FileObject->FsContext;
  1244. //
  1245. // Grab the session ID.
  1246. //
  1247. sessionID = context->sessionID;
  1248. TRC_NRM((TB, "Requestor session ID %d.", context->sessionID ));
  1249. TRC_ASSERT(context->magicNo == DEVMGRCONTEXTMAGICNO, (TB, "invalid context"));
  1250. // Grab some information about the user-mode's buffer off the IRP stack.
  1251. outputLength = currentStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
  1252. TRC_ASSERT(UserModeEventListMgr != NULL, (TB, "RdpDyn EventList is NULL"));
  1253. //
  1254. // Lock the device management event list.
  1255. //
  1256. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1257. //
  1258. // See if we have a "device mgmt event pending."
  1259. //
  1260. if (RDPEVNTLIST_PeekNextEvent(
  1261. UserModeEventListMgr,
  1262. sessionID, &evt,
  1263. &evType, &drDevice
  1264. )) {
  1265. //
  1266. // If the pending IRP's pending buffer is large enough for the
  1267. // next event.
  1268. //
  1269. eventSize = RDPDYN_DevMgmtEventSize(evt, evType);
  1270. requiredUserBufSize = eventSize + sizeof(RDPDRDVMGR_EVENTHEADER);
  1271. if (outputLength >= requiredUserBufSize) {
  1272. //
  1273. // Dequeue the next pending event. This better be the one
  1274. // we just peeked at.
  1275. //
  1276. RDPEVNTLIST_DequeueEvent(
  1277. UserModeEventListMgr,
  1278. sessionID, &evType,
  1279. &evt, NULL
  1280. );
  1281. //
  1282. // It's safe to unlock the device management event list now.
  1283. //
  1284. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1285. //
  1286. // Complete the pending IRP.
  1287. //
  1288. status = CompleteIRPWithDevMgmtEvent(
  1289. deviceObject,
  1290. pIrp, eventSize,
  1291. evType, evt, drDevice
  1292. );
  1293. //
  1294. // Release the event.
  1295. //
  1296. if (evt != NULL) {
  1297. delete evt;
  1298. evt = NULL;
  1299. }
  1300. //
  1301. // Release our reference to the device, if we own one.
  1302. //
  1303. if (drDevice != NULL) {
  1304. drDevice->Release();
  1305. }
  1306. }
  1307. //
  1308. // Otherwise, need to send a resize buffer message to the
  1309. // user-mode copmonent.
  1310. //
  1311. else {
  1312. //
  1313. // It's safe to unlock the device management event list now.
  1314. //
  1315. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1316. //
  1317. // Complete the IRP.
  1318. //
  1319. status = CompleteIRPWithResizeMsg(pIrp, requiredUserBufSize);
  1320. }
  1321. }
  1322. //
  1323. // Otherwise, queue the IRP, mark the IRP pending and return.
  1324. //
  1325. else {
  1326. //
  1327. // Queue the request.
  1328. //
  1329. status = RDPEVNTLIST_EnqueueRequest(UserModeEventListMgr,
  1330. context->sessionID, pIrp);
  1331. //
  1332. // Set the cancel routine for the pending IRP.
  1333. //
  1334. if (status == STATUS_SUCCESS) {
  1335. IoMarkIrpPending(pIrp);
  1336. IoSetCancelRoutine(pIrp, DevMgmtEventRequestIRPCancel);
  1337. status = STATUS_PENDING;
  1338. }
  1339. else {
  1340. // Fail the IRP request.
  1341. pIrp->IoStatus.Status = status;
  1342. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1343. }
  1344. //
  1345. // It's safe to unlock the device management event list now.
  1346. //
  1347. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1348. }
  1349. return status;
  1350. }
  1351. void
  1352. RDPDYN_SessionConnected(
  1353. IN ULONG sessionID
  1354. )
  1355. /*++
  1356. Routine Description:
  1357. This function is called when a new session is connected.
  1358. Arguments:
  1359. sessionID - Identifier for removed session.
  1360. Return Value:
  1361. None.
  1362. --*/
  1363. {
  1364. #if DBG
  1365. BOOL result;
  1366. PVOID evt;
  1367. DrDevice *drDevice;
  1368. KIRQL oldIrql;
  1369. ULONG evType;
  1370. #endif
  1371. BEGIN_FN("RDPDYN_SessionConnected");
  1372. TRC_NRM((TB, "Session %ld.", sessionID));
  1373. //
  1374. // Nothing to do if the event list is NULL
  1375. //
  1376. TRC_ASSERT(UserModeEventListMgr != NULL, (TB, "RdpDyn EventList is NULL"));
  1377. if (UserModeEventListMgr == NULL) {
  1378. goto CleanupAndExit;
  1379. }
  1380. #if DBG
  1381. //
  1382. // See if there is still an event in the queue. Really, we should be checking
  1383. // to see if there is more than one event in the queue. This will catch most
  1384. // problems with events not gettin cleaned up on session disconnect.
  1385. //
  1386. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1387. result = RDPEVNTLIST_PeekNextEvent(
  1388. UserModeEventListMgr,
  1389. sessionID, &evt, &evType,
  1390. &drDevice);
  1391. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1392. //
  1393. // The only pending event allowed in the queue, at this point, is
  1394. // a remove client device event. RDPDYN_SessionDisconnected discards
  1395. // all other events.
  1396. //
  1397. if (result) {
  1398. TRC_ASSERT(evType == RDPDREVT_SESSIONDISCONNECT,
  1399. (TB, "Pending non-remove events %x on session connect.", evType));
  1400. }
  1401. #endif
  1402. CleanupAndExit:
  1403. return;
  1404. }
  1405. void
  1406. RDPDYN_SessionDisconnected(
  1407. IN ULONG sessionID
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. This function is called when a session is disconnected from the system.
  1412. Arguments:
  1413. sessionID - Identifier for removed session.
  1414. Return Value:
  1415. None.
  1416. --*/
  1417. {
  1418. void *devMgmtEvent;
  1419. ULONG type;
  1420. BOOL queued;
  1421. KIRQL oldIrql;
  1422. DrDevice *device;
  1423. BEGIN_FN("RDPDYN_SessionDisconnected");
  1424. TRC_NRM((TB, "Session %ld.", sessionID));
  1425. //
  1426. // Remove all pending device management events for this session.
  1427. // Nothing to do if the event list is NULL
  1428. //
  1429. TRC_ASSERT(UserModeEventListMgr != NULL, (TB, "RdpDyn EventList is NULL"));
  1430. if (UserModeEventListMgr == NULL) {
  1431. goto CleanupAndExit;
  1432. }
  1433. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1434. while (RDPEVNTLIST_DequeueEvent(
  1435. UserModeEventListMgr,
  1436. sessionID, &type, &devMgmtEvent,
  1437. &device
  1438. )) {
  1439. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1440. if (devMgmtEvent != NULL) {
  1441. delete devMgmtEvent;
  1442. }
  1443. if (device != NULL) {
  1444. device->Release();
  1445. }
  1446. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1447. }
  1448. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1449. //
  1450. // Dispatch a "session disconnect" event for the session to let user
  1451. // mode know about the event.
  1452. //
  1453. RDPDYN_DispatchNewDevMgmtEvent(
  1454. NULL, sessionID,
  1455. RDPDREVT_SESSIONDISCONNECT,
  1456. NULL
  1457. );
  1458. CleanupAndExit:
  1459. return;
  1460. }
  1461. PIRP
  1462. GetNextEventRequest(
  1463. IN RDPEVNTLIST list,
  1464. IN ULONG sessionID
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. Returns the next pending device management event request for the specified
  1469. session, in the form of an IRP. Note that this function can not be called
  1470. if a spinlock has been acquired.
  1471. Arguments:
  1472. list - Device Management Event and Requeust List
  1473. sessionID - Destination session ID for event.
  1474. Return Value:
  1475. The next pending request (IRP) for the specified session or NULL if there are
  1476. not any IRP's pending.
  1477. --*/
  1478. {
  1479. PIRP pIrp;
  1480. KIRQL oldIrql;
  1481. BOOL done;
  1482. PDRIVER_CANCEL setCancelResult;
  1483. BEGIN_FN("GetNextEventRequest");
  1484. //
  1485. // Loop until we get an IRP that is not currently being cancelled.
  1486. //
  1487. done = FALSE;
  1488. setCancelResult = NULL;
  1489. while (!done) {
  1490. //
  1491. // Dequeue an IRP and take it out of a cancellable state.
  1492. //
  1493. RDPEVNTLIST_Lock(list, &oldIrql);
  1494. pIrp = (PIRP)RDPEVNTLIST_DequeueRequest(list, sessionID);
  1495. if (pIrp != NULL) {
  1496. setCancelResult = IoSetCancelRoutine(pIrp, NULL);
  1497. }
  1498. RDPEVNTLIST_Unlock(list, oldIrql);
  1499. done = (pIrp == NULL) || (setCancelResult != NULL);
  1500. }
  1501. return pIrp;
  1502. }
  1503. NTSTATUS
  1504. RDPDYN_DispatchNewDevMgmtEvent(
  1505. IN PVOID devMgmtEvent,
  1506. IN ULONG sessionID,
  1507. IN ULONG eventType,
  1508. OPTIONAL IN DrDevice *devDevice
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. Dispatch a device management event to the appropriate (session-wise) user-mode
  1513. device manager component. If there are not any event request IRP's pending
  1514. for the specified session, then the event is queued for future dispatch.
  1515. Arguments:
  1516. devMgmtEvent - The event.
  1517. sessionID - Destination session ID for event.
  1518. eventType - Type of event.
  1519. queued - TRUE if the event was queued for future dispatch.
  1520. devDevice - Device object associated with the event. NULL, if not
  1521. specified.
  1522. Return Value:
  1523. STATUS_SUCCESS if successful, error status otherwise.
  1524. --*/
  1525. {
  1526. PIRP pIrp;
  1527. NTSTATUS status;
  1528. KIRQL oldIrql;
  1529. PIO_STACK_LOCATION currentStackLocation;
  1530. ULONG outputLength;
  1531. ULONG eventSize;
  1532. ULONG requiredUserBufSize;
  1533. DrDevice *drDevice = NULL;
  1534. PVOID evt;
  1535. ULONG evType;
  1536. BEGIN_FN("RDPDYN_DispatchNewDevMgmtEvent");
  1537. //
  1538. // Nothing to do if the event list is NULL
  1539. //
  1540. TRC_ASSERT(UserModeEventListMgr != NULL, (TB, "RdpDyn EventList is NULL"));
  1541. if (UserModeEventListMgr == NULL) {
  1542. return STATUS_INVALID_DEVICE_STATE;
  1543. }
  1544. //
  1545. // Ref count the device, if provided.
  1546. //
  1547. if (devDevice != NULL) {
  1548. devDevice->AddRef();
  1549. }
  1550. //
  1551. // Enqueue the new event.
  1552. //
  1553. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1554. status = RDPEVNTLIST_EnqueueEvent(
  1555. UserModeEventListMgr,
  1556. sessionID,
  1557. devMgmtEvent,
  1558. eventType,
  1559. devDevice
  1560. );
  1561. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1562. //
  1563. // If we have an IRP pending for the specified session.
  1564. //
  1565. if (status == STATUS_SUCCESS) {
  1566. pIrp = GetNextEventRequest(UserModeEventListMgr, sessionID);
  1567. }
  1568. else {
  1569. if (devDevice != NULL) {
  1570. devDevice->Release();
  1571. }
  1572. }
  1573. if ((status == STATUS_SUCCESS) && (pIrp != NULL)) {
  1574. TRC_NRM((TB, "found an IRP pending for "
  1575. "session %ld", sessionID));
  1576. //
  1577. // Find out about the pending IRP.
  1578. //
  1579. currentStackLocation = IoGetCurrentIrpStackLocation(pIrp);
  1580. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  1581. outputLength =
  1582. currentStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
  1583. //
  1584. // If we have a pending event.
  1585. //
  1586. RDPEVNTLIST_Lock(UserModeEventListMgr, &oldIrql);
  1587. if (RDPEVNTLIST_PeekNextEvent(
  1588. UserModeEventListMgr,
  1589. sessionID, &evt, &evType,
  1590. &drDevice
  1591. )) {
  1592. //
  1593. // If the pending IRP's pending buffer is large enough for the
  1594. // next event.
  1595. //
  1596. eventSize = RDPDYN_DevMgmtEventSize(evt, evType);
  1597. requiredUserBufSize = eventSize + sizeof(RDPDRDVMGR_EVENTHEADER);
  1598. if (outputLength >= requiredUserBufSize) {
  1599. //
  1600. // Dequeue the next pending event. This better be the one
  1601. // we just peeked at.
  1602. //
  1603. RDPEVNTLIST_DequeueEvent(
  1604. UserModeEventListMgr,
  1605. sessionID, &evType,
  1606. &evt, NULL
  1607. );
  1608. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1609. //
  1610. // Complete the pending IRP.
  1611. //
  1612. status = CompleteIRPWithDevMgmtEvent(
  1613. RDPDYN_PDO, pIrp, eventSize,
  1614. evType, evt,
  1615. drDevice
  1616. );
  1617. //
  1618. // Release the event.
  1619. //
  1620. if (evt != NULL) {
  1621. delete evt;
  1622. evt = NULL;
  1623. }
  1624. //
  1625. // Release our reference to the device, if we own one.
  1626. //
  1627. if (drDevice != NULL) {
  1628. drDevice->Release();
  1629. }
  1630. }
  1631. //
  1632. // Otherwise, need to send a resize buffer message to the
  1633. // user-mode component.
  1634. //
  1635. else {
  1636. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1637. //
  1638. // Complete the IRP.
  1639. //
  1640. status = CompleteIRPWithResizeMsg(pIrp, requiredUserBufSize);
  1641. }
  1642. }
  1643. //
  1644. // Otherwise, we need to requeue the IRP request.
  1645. //
  1646. else {
  1647. status = RDPEVNTLIST_EnqueueRequest(UserModeEventListMgr,
  1648. sessionID, pIrp);
  1649. RDPEVNTLIST_Unlock(UserModeEventListMgr, oldIrql);
  1650. //
  1651. // If we fail here, we need to fail the IRP.
  1652. //
  1653. if (status != STATUS_SUCCESS) {
  1654. pIrp->IoStatus.Status = status;
  1655. pIrp->IoStatus.Information = 0;
  1656. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1657. }
  1658. }
  1659. }
  1660. TRC_NRM((TB, "exit RDPDYN_DispatchNewDevMgmtEvent"));
  1661. return status;
  1662. }
  1663. ULONG
  1664. RDPDYN_DevMgmtEventSize(
  1665. IN PVOID devMgmtEvent,
  1666. IN ULONG type
  1667. )
  1668. /*++
  1669. Routine Description:
  1670. Calculate the size of a device management event. This is more efficient than
  1671. storing the size with each event.
  1672. Arguments:
  1673. devMgmtEvent - Supplies the device object for the packet being processed.
  1674. type - Supplies the Irp being processed
  1675. Return Value:
  1676. The size, in bytes, of the event.
  1677. --*/
  1678. {
  1679. ULONG sz = 0;
  1680. BEGIN_FN("RDPDYN_DevMgmtEventSize");
  1681. switch(type) {
  1682. case RDPDREVT_PRINTERANNOUNCE :
  1683. sz = CALCPRINTERDEVICE_SUB_SZ((PRDPDR_PRINTERDEVICE_SUB)devMgmtEvent);
  1684. break;
  1685. case RDPDREVT_REMOVEDEVICE :
  1686. sz = CALCREMOVEDEVICE_SUB_SZ((PRDPDR_REMOVEDEVICE)devMgmtEvent);
  1687. break;
  1688. case RDPDREVT_PORTANNOUNCE :
  1689. sz = CALCPORTDEVICE_SUB_SZ((PRDPDR_PORTDEVICE_SUB)devMgmtEvent);
  1690. break;
  1691. case RDPDREVT_DRIVEANNOUNCE :
  1692. sz = CALCDRIVEDEVICE_SUB_SZ((PRDPDR_DRIVEDEVICE_SUB)devMgmtEvent);
  1693. break;
  1694. case RDPDREVT_SESSIONDISCONNECT :
  1695. // There is no associated event data.
  1696. sz = 0;
  1697. break;
  1698. default:
  1699. TRC_ASSERT(FALSE, (TB, "Invalid event type"));
  1700. }
  1701. return sz;
  1702. }
  1703. NTSTATUS CompleteIRPWithDevMgmtEvent(
  1704. IN PDEVICE_OBJECT deviceObject,
  1705. IN PIRP pIrp,
  1706. IN ULONG eventSize,
  1707. IN ULONG eventType,
  1708. IN PVOID event,
  1709. IN DrDevice *drDevice
  1710. )
  1711. /*++
  1712. Routine Description:
  1713. Complete a pending IRP with a device management event.
  1714. Arguments:
  1715. deviceObject- Associated Device Object. Must be non-NULL if
  1716. drDevice is non-NULL.
  1717. pIrp - Pending IRP.
  1718. eventSize - Size of event being returned.
  1719. eventType - Event type being returned.
  1720. event - The event being returned.
  1721. drDevice - Device object associated with the IRP.
  1722. Return Value:
  1723. STATUS_SUCCESS on success.
  1724. --*/
  1725. {
  1726. PRDPDRDVMGR_EVENTHEADER msgHeader;
  1727. ULONG bytesReturned;
  1728. void *usrDevMgmtEvent;
  1729. NTSTATUS status;
  1730. BEGIN_FN("CompleteIRPWithDevMgmtEvent");
  1731. //
  1732. // Optional last-minute event completion.
  1733. //
  1734. if (drDevice != NULL) {
  1735. status = drDevice->OnDevMgmtEventCompletion(deviceObject, event);
  1736. }
  1737. else {
  1738. status = STATUS_SUCCESS;
  1739. }
  1740. //
  1741. // Compute the size of the return buffer.
  1742. //
  1743. bytesReturned = eventSize + sizeof(RDPDRDVMGR_EVENTHEADER);
  1744. //
  1745. // Create the message header.
  1746. //
  1747. msgHeader = (PRDPDRDVMGR_EVENTHEADER)pIrp->AssociatedIrp.SystemBuffer;
  1748. msgHeader->EventType = eventType;
  1749. msgHeader->EventLength = eventSize;
  1750. //
  1751. // Copy the device mgmt event over to the user-mode buffer.
  1752. //
  1753. usrDevMgmtEvent = ((PBYTE)pIrp->AssociatedIrp.SystemBuffer +
  1754. sizeof(RDPDRDVMGR_EVENTHEADER));
  1755. if (event != NULL && eventSize > 0) {
  1756. RtlCopyMemory(usrDevMgmtEvent, event, eventSize);
  1757. }
  1758. status = STATUS_SUCCESS;
  1759. pIrp->IoStatus.Status = status;
  1760. pIrp->IoStatus.Information = bytesReturned;
  1761. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1762. TRC_NRM((TB, "exit CompleteIRPWithDevMgmtEvent"));
  1763. return status;
  1764. }
  1765. NTSTATUS
  1766. CompleteIRPWithResizeMsg(
  1767. IN PIRP pIrp,
  1768. IN ULONG requiredUserBufSize
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. Complete a pending IRP with a resize buffer event to the user-mode
  1773. component.
  1774. Return Value:
  1775. STATUS_SUCCESS is returned on success.
  1776. --*/
  1777. {
  1778. PIO_STACK_LOCATION currentStackLocation;
  1779. ULONG outputLength;
  1780. PRDPDR_BUFFERTOOSMALL bufTooSmallMsg;
  1781. PRDPDRDVMGR_EVENTHEADER msgHeader;
  1782. ULONG bytesReturned;
  1783. NTSTATUS status;
  1784. BEGIN_FN("CompleteIRPWithResizeMsg");
  1785. // Get the current stack location.
  1786. currentStackLocation = IoGetCurrentIrpStackLocation(pIrp);
  1787. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  1788. // Grab some stuff off the IRP stack.
  1789. outputLength = currentStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
  1790. //
  1791. // Fail the request if there isn't room for a buffer too small
  1792. // message.
  1793. //
  1794. if (outputLength < (sizeof(RDPDRDVMGR_EVENTHEADER) +
  1795. sizeof(RDPDR_BUFFERTOOSMALL))) {
  1796. TRC_NRM((TB, "CompleteIRPWithResizeMsg no room for header."));
  1797. bytesReturned = 0;
  1798. status = STATUS_INVALID_BUFFER_SIZE;
  1799. }
  1800. else {
  1801. // Create the header.
  1802. msgHeader = (PRDPDRDVMGR_EVENTHEADER)pIrp->AssociatedIrp.SystemBuffer;
  1803. msgHeader->EventType = RDPDREVT_BUFFERTOOSMALL;
  1804. msgHeader->EventLength = sizeof(RDPDR_BUFFERTOOSMALL);
  1805. // Create the buffer too small message.
  1806. bufTooSmallMsg = (PRDPDR_BUFFERTOOSMALL)
  1807. ((PBYTE)pIrp->AssociatedIrp.SystemBuffer +
  1808. sizeof(RDPDRDVMGR_EVENTHEADER));
  1809. bufTooSmallMsg->RequiredSize = requiredUserBufSize;
  1810. // Calculate the number of bytes that we are returning.
  1811. bytesReturned = sizeof(RDPDRDVMGR_EVENTHEADER) +
  1812. sizeof(RDPDR_BUFFERTOOSMALL);
  1813. status = STATUS_SUCCESS;
  1814. }
  1815. //
  1816. // Complete the IRP.
  1817. //
  1818. pIrp->IoStatus.Status = status;
  1819. pIrp->IoStatus.Information = bytesReturned;
  1820. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  1821. TRC_NRM((TB, "exit CompleteIRPWithResizeMsg"));
  1822. return status;
  1823. }
  1824. NTSTATUS
  1825. DrSendMessageToSession(
  1826. IN ULONG SessionId,
  1827. IN PVOID Msg,
  1828. IN DWORD MsgSize,
  1829. OPTIONAL IN RDPDR_ClientMessageCB CB,
  1830. OPTIONAL IN PVOID ClientData
  1831. )
  1832. /*++
  1833. Routine Description:
  1834. Send a message to the client with the specified session ID.
  1835. Arguments:
  1836. SessionId - The session id.
  1837. Msg - The Message
  1838. MsgSize - Size (in bytes) of message.
  1839. CB - Optional callback to be called when the message is completely
  1840. sent.
  1841. ClientData - Optional client-data passed to callback when message is
  1842. completely sent.
  1843. Return Value:
  1844. NTSTATUS - Success/failure indication of the operation
  1845. Notes:
  1846. --*/
  1847. {
  1848. NTSTATUS Status;
  1849. SmartPtr<DrSession> Session;
  1850. PCLIENTMESSAGECONTEXT Context;
  1851. BEGIN_FN("DrSendMessageToSession");
  1852. //
  1853. // Find the client entry.
  1854. //
  1855. if (Sessions->FindSessionById(SessionId, Session)) {
  1856. //
  1857. // Allocate the context for the function call.
  1858. //
  1859. Context = new CLIENTMESSAGECONTEXT;
  1860. if (Context != NULL) {
  1861. TRC_NRM((TB, "sending %ld bytes to server", MsgSize));
  1862. //
  1863. // Set up the context.
  1864. //
  1865. Context->CB = CB;
  1866. Context->ClientData = ClientData;
  1867. Status = Session->SendToClient(Msg, MsgSize,
  1868. DrSendMessageToClientCompletion, FALSE, FALSE, Context);
  1869. } else {
  1870. TRC_ERR((TB, "unable to allocate memory."));
  1871. Status = STATUS_INSUFFICIENT_RESOURCES;
  1872. }
  1873. }
  1874. else {
  1875. Status = STATUS_NOT_FOUND;
  1876. }
  1877. return Status;
  1878. }
  1879. NTSTATUS NTAPI DrSendMessageToClientCompletion(PVOID Context,
  1880. PIO_STATUS_BLOCK IoStatusBlock)
  1881. /*++
  1882. Routine Description:
  1883. IoCompletion APC routine for DrSendMessageToClient.
  1884. Arguments:
  1885. ApcContext - Contains a pointer to the client message context.
  1886. IoStatusBlock - Status information about the operation. The Information
  1887. indicates the actual number of bytes written
  1888. Reserved - Reserved
  1889. Return Value:
  1890. None
  1891. --*/
  1892. {
  1893. PCLIENTMESSAGECONTEXT MsgContext = (PCLIENTMESSAGECONTEXT)Context;
  1894. BEGIN_FN("DrSendMessageToClientCompletion");
  1895. TRC_ASSERT(MsgContext != NULL, (TB, "Message context NULL."));
  1896. TRC_ASSERT(IoStatusBlock != NULL, (TB, "IoStatusBlock NULL."));
  1897. TRC_NRM((TB, "status %lx", IoStatusBlock->Status));
  1898. //
  1899. // Call the client callback if it is defined.
  1900. //
  1901. if (MsgContext->CB != NULL) {
  1902. MsgContext->CB(MsgContext->ClientData, IoStatusBlock->Status);
  1903. }
  1904. //
  1905. // Clean up.
  1906. //
  1907. // delete IoStatusBlock; // I don't think so, not really
  1908. delete Context;
  1909. return STATUS_SUCCESS;
  1910. }
  1911. /*++
  1912. Routine Description:
  1913. Generates a printer announce message for testing.
  1914. Return Value:
  1915. STATUS_INVALID_BUFFER_SIZE is returned if the prnAnnounceEventSize size is
  1916. too small. STATUS_SUCCESS is returned on success.
  1917. --*/
  1918. #if DBG
  1919. void
  1920. RDPDYN_TracePrintAnnounceMsg(
  1921. IN OUT PRDPDR_DEVICE_ANNOUNCE devAnnounceMsg,
  1922. IN ULONG sessionID,
  1923. IN PCWSTR portName,
  1924. IN PCWSTR clientName
  1925. )
  1926. /*++
  1927. Routine Description:
  1928. Trace a printer device announce message.
  1929. Return Value:
  1930. --*/
  1931. {
  1932. PWSTR driverName, printerName;
  1933. PWSTR pnpName;
  1934. PRDPDR_PRINTERDEVICE_ANNOUNCE clientPrinterFields;
  1935. PBYTE pClientPrinterData;
  1936. ULONG sz;
  1937. BEGIN_FN("RDPDYN_TracePrintAnnounceMsg");
  1938. // Check the type.
  1939. TRC_ASSERT(devAnnounceMsg->DeviceType == RDPDR_DTYP_PRINT,
  1940. (TB, "Invalid device type"));
  1941. // Get the address of all data following the base message.
  1942. pClientPrinterData = ((PBYTE)devAnnounceMsg) +
  1943. sizeof(RDPDR_DEVICE_ANNOUNCE) +
  1944. sizeof(RDPDR_PRINTERDEVICE_ANNOUNCE);
  1945. // Get the address of the client printer fields.
  1946. clientPrinterFields = (PRDPDR_PRINTERDEVICE_ANNOUNCE)(((PBYTE)devAnnounceMsg) +
  1947. sizeof(RDPDR_DEVICE_ANNOUNCE));
  1948. sz = clientPrinterFields->PnPNameLen +
  1949. clientPrinterFields->DriverLen +
  1950. clientPrinterFields->PrinterNameLen +
  1951. clientPrinterFields->CachedFieldsLen +
  1952. sizeof(RDPDR_PRINTERDEVICE_ANNOUNCE);
  1953. if (devAnnounceMsg->DeviceDataLength != sz) {
  1954. TRC_ASSERT(FALSE,(TB, "Size integrity questionable in dev announce buf."));
  1955. }
  1956. else {
  1957. // Get the specific fields.
  1958. pnpName = (PWSTR)((clientPrinterFields->PnPNameLen) ? pClientPrinterData : NULL);
  1959. driverName = (PWSTR)((clientPrinterFields->DriverLen) ?
  1960. (pClientPrinterData + clientPrinterFields->PnPNameLen) : NULL);
  1961. printerName = (PWSTR)((clientPrinterFields->PrinterNameLen) ? (pClientPrinterData +
  1962. clientPrinterFields->PnPNameLen +
  1963. clientPrinterFields->DriverLen) : NULL);
  1964. TRC_NRM((TB, "New printer received for session %ld.", sessionID));
  1965. TRC_NRM((TB, "-----------------------------------------"));
  1966. TRC_NRM((TB, "port:\t%ws", portName));
  1967. if (clientPrinterFields->Flags & RDPDR_PRINTER_ANNOUNCE_FLAG_ANSI) {
  1968. TRC_NRM((TB, "driver:\t%s", (PSTR)driverName));
  1969. TRC_NRM((TB, "pnp name:\t%s", (PSTR)pnpName));
  1970. TRC_NRM((TB, "printer name:\t%s", (PSTR)printerName));
  1971. }
  1972. else {
  1973. TRC_NRM((TB, "driver:\t%ws", driverName));
  1974. TRC_NRM((TB, "pnp name:\t%ws", pnpName));
  1975. TRC_NRM((TB, "printer name:\t%ws", printerName));
  1976. }
  1977. TRC_NRM((TB, "client name:\t%ws", clientName));
  1978. TRC_NRM((TB, "-----------------------------------------"));
  1979. TRC_NRM((TB, "exit RDPDYN_TracePrintAnnounceMsg"));
  1980. }
  1981. }
  1982. NTSTATUS
  1983. RDPDYN_GenerateTestPrintAnnounceMsg(
  1984. IN OUT PRDPDR_DEVICE_ANNOUNCE devAnnounceMsg,
  1985. IN ULONG devAnnounceMsgSize,
  1986. OPTIONAL OUT ULONG *prnAnnounceMsgReqSize
  1987. )
  1988. /*++
  1989. Routine Description:
  1990. Generates a printer announce message for testing.
  1991. Return Value:
  1992. STATUS_INVALID_BUFFER_SIZE is returned if the prnAnnounceMsgSize size is
  1993. too small. STATUS_SUCCESS is returned on success.
  1994. --*/
  1995. {
  1996. ULONG requiredSize;
  1997. PBYTE pClientPrinterData;
  1998. PWSTR driverName, printerName;
  1999. PWSTR pnpName;
  2000. PRDPDR_PRINTERDEVICE_ANNOUNCE prnMsg;
  2001. PRDPDR_PRINTERDEVICE_ANNOUNCE clientPrinterFields;
  2002. PBYTE pCachedFields;
  2003. BEGIN_FN("RDPDYN_GenerateTestPrintAnnounceMsg");
  2004. requiredSize = (ULONG)(sizeof(RDPDR_DEVICE_ANNOUNCE) +
  2005. sizeof(RDPDR_PRINTERDEVICE_ANNOUNCE) +
  2006. ((wcslen(TESTDRIVERNAME) + 1) * sizeof(WCHAR)) +
  2007. ((wcslen(TESTPNPNAME) + 1) * sizeof(WCHAR)) +
  2008. ((wcslen(TESTPRINTERNAME) + 1) * sizeof(WCHAR)));
  2009. //
  2010. // Find out if there isn't room in the return buffer for our response.
  2011. //
  2012. if (devAnnounceMsgSize < requiredSize) {
  2013. if (prnAnnounceMsgReqSize != NULL) {
  2014. *prnAnnounceMsgReqSize = requiredSize;
  2015. }
  2016. return STATUS_BUFFER_TOO_SMALL;
  2017. }
  2018. // Type
  2019. devAnnounceMsg->DeviceType = RDPDR_DTYP_PRINT;
  2020. // ID
  2021. devAnnounceMsg->DeviceId = TESTDEVICEID;
  2022. // Get the address of the client printer fields in the device announce
  2023. // message.
  2024. clientPrinterFields = (PRDPDR_PRINTERDEVICE_ANNOUNCE)(((PBYTE)devAnnounceMsg) +
  2025. sizeof(RDPDR_DEVICE_ANNOUNCE));
  2026. // Get the address of all data following the base message.
  2027. pClientPrinterData = ((PBYTE)devAnnounceMsg) +
  2028. sizeof(RDPDR_DEVICE_ANNOUNCE) +
  2029. sizeof(RDPDR_PRINTERDEVICE_ANNOUNCE);
  2030. //
  2031. // Add the PnP Name.
  2032. //
  2033. // The PnP name is the first field.
  2034. pnpName = (PWSTR)pClientPrinterData;
  2035. wcscpy(pnpName, TESTPNPNAME);
  2036. clientPrinterFields->PnPNameLen = ((wcslen(TESTPNPNAME) + 1) * sizeof(WCHAR));
  2037. //
  2038. // Add the Driver Name.
  2039. //
  2040. // The driver name is the second field.
  2041. driverName = (PWSTR)(pClientPrinterData + clientPrinterFields->PnPNameLen);
  2042. wcscpy(driverName, TESTDRIVERNAME);
  2043. clientPrinterFields->DriverLen = ((wcslen(TESTDRIVERNAME) + 1) * sizeof(WCHAR));
  2044. //
  2045. // Add the Printer Name.
  2046. //
  2047. // The driver name is the second field.
  2048. printerName = (PWSTR)(pClientPrinterData +
  2049. clientPrinterFields->PnPNameLen +
  2050. clientPrinterFields->DriverLen);
  2051. wcscpy(printerName, TESTPRINTERNAME);
  2052. clientPrinterFields->PrinterNameLen = ((wcslen(TESTPRINTERNAME) + 1) * sizeof(WCHAR));
  2053. //
  2054. // Add the Cached Fields Len.
  2055. //
  2056. // The cached fields follow everything else.
  2057. /* Don't need this for testing, yet.
  2058. pCachedFields = (PBYTE)(pClientPrinterData + clientPrinterFields->PnPNameLen +
  2059. clientPrinterFields->DriverLen +
  2060. clientPrinterFields->PrinterNameLen);
  2061. */
  2062. clientPrinterFields->CachedFieldsLen = 0;
  2063. //
  2064. // Set to non-ansi for now.
  2065. //
  2066. clientPrinterFields->Flags = 0;
  2067. // Length of all data following deviceFields.
  2068. devAnnounceMsg->DeviceDataLength =
  2069. sizeof(RDPDR_PRINTERDEVICE_ANNOUNCE) +
  2070. clientPrinterFields->PnPNameLen +
  2071. clientPrinterFields->DriverLen +
  2072. clientPrinterFields->PrinterNameLen +
  2073. clientPrinterFields->CachedFieldsLen;
  2074. if (prnAnnounceMsgReqSize != NULL) {
  2075. *prnAnnounceMsgReqSize = requiredSize;
  2076. }
  2077. return STATUS_SUCCESS;
  2078. }
  2079. #endif
  2080. #if DBG
  2081. NTSTATUS
  2082. RDPDYN_HandleDbgAddNewPrnIOCTL(
  2083. IN PDEVICE_OBJECT deviceObject,
  2084. IN PIRP pIrp
  2085. )
  2086. /*++
  2087. Routine Description:
  2088. This is for testing so we can create a new test printer on
  2089. demand from user-mode.
  2090. Arguments:
  2091. DeviceObject - pointer to our device object.
  2092. currentStackLocation - current location on the IRP stack.
  2093. Return Value:
  2094. NT status code
  2095. --*/
  2096. {
  2097. PRDPDR_DEVICE_ANNOUNCE pDevAnnounceMsg;
  2098. ULONG bytesToAlloc;
  2099. PIO_STACK_LOCATION currentStackLocation;
  2100. ULONG requiredSize;
  2101. ULONG bytesReturned = 0;
  2102. PDEVMGRCONTEXT context;
  2103. NTSTATUS ntStatus;
  2104. WCHAR buffer[64]=L"Test Printer";
  2105. UNICODE_STRING referenceString;
  2106. PBYTE tmp;
  2107. BEGIN_FN("RDPDYN_HandleDbgAddNewPrnIOCTL");
  2108. // Get the current stack location.
  2109. currentStackLocation = IoGetCurrentIrpStackLocation(pIrp);
  2110. TRC_ASSERT(currentStackLocation != NULL, (TB, "Invalid stack location."));
  2111. // Grab our "open" context for this instance of us from the current stack
  2112. // location's file object.
  2113. context = (PDEVMGRCONTEXT)currentStackLocation->FileObject->FsContext;
  2114. TRC_ASSERT(context->magicNo == DEVMGRCONTEXTMAGICNO,
  2115. (TB, "invalid context"));
  2116. // Find out how much room we need for the test message.
  2117. RDPDYN_GenerateTestPrintAnnounceMsg(NULL, 0, &requiredSize);
  2118. // Generate the message.
  2119. pDevAnnounceMsg = (PRDPDR_DEVICE_ANNOUNCE)new(NonPagedPool) BYTE[requiredSize];
  2120. if (pDevAnnounceMsg != NULL) {
  2121. RDPDYN_GenerateTestPrintAnnounceMsg(pDevAnnounceMsg, requiredSize, &requiredSize);
  2122. //
  2123. // Announce the new port (just send to session 0 for now).
  2124. //
  2125. RtlInitUnicodeString(&referenceString, buffer);
  2126. //#pragma message(__LOC__"Unit test to add device disabled")
  2127. /*
  2128. //
  2129. // Initialize the client entry struct.
  2130. //
  2131. RtlZeroMemory(&clientEntry, sizeof(clientEntry));
  2132. wcscpy(clientEntry.ClientName, L"DBGTEST");
  2133. clientEntry.SessionId = 0;
  2134. // Note that I am ignoring the returned device data for this test.
  2135. // This is okay, since I never call RDPDYN_RemoveClientDevice(
  2136. ntStatus = RDPDYN_AddClientDevice(
  2137. &clientEntry,
  2138. pDevAnnounceMsg,
  2139. &referenceString,
  2140. &tmp
  2141. );
  2142. */
  2143. // For a test, delete the device next.
  2144. // RDPDYN_RemoveClientDevice(TESTDEVICEID, 0, tmp);
  2145. ntStatus = STATUS_SUCCESS;
  2146. }
  2147. else {
  2148. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2149. }
  2150. pIrp->IoStatus.Status = ntStatus;
  2151. pIrp->IoStatus.Information = 0;
  2152. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  2153. return ntStatus;
  2154. }
  2155. #endif