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.

2975 lines
116 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name :
  4. drive.cpp
  5. Author :
  6. JoyC 11/1/1999
  7. Abstract:
  8. Drive Device object handles one redirected drive
  9. Revision History:
  10. --*/
  11. #include "precomp.hxx"
  12. #define TRC_FILE "drive"
  13. #include "trc.h"
  14. #if DBG
  15. extern UCHAR IrpNames[IRP_MJ_MAXIMUM_FUNCTION + 1][40];
  16. #endif // DBG
  17. DrDrive::DrDrive(SmartPtr<DrSession> &Session, ULONG DeviceType, ULONG DeviceId,
  18. PUCHAR PreferredDosName) : DrDevice(Session, DeviceType, DeviceId, PreferredDosName)
  19. {
  20. BEGIN_FN("DrDrive::DrDrive");
  21. SetClassName("DrDrive");
  22. TRC_NRM((TB, "Create drive object = %p", this));
  23. }
  24. BOOL DrDrive::ShouldCreateDevice()
  25. {
  26. BEGIN_FN("DrDrive::ShouldCreateDevice");
  27. //
  28. // Check if the device name is valid
  29. //
  30. if (!_Session->DisableDriveMapping()) {
  31. return IsDeviceNameValid();
  32. }
  33. return FALSE;
  34. }
  35. BOOL DrDrive::IsDeviceNameValid()
  36. {
  37. BEGIN_FN("DrDrive::IsDeviceNameValid");
  38. BOOL fRet = TRUE;
  39. int i, Len;
  40. //
  41. // Our device name is valid only if
  42. // the first char contains a character between A-Z.
  43. // and the 2nd char is NULL.
  44. //
  45. // For Mac client, drive name can have up to 7 characters and
  46. // valid characters are: [a-z], [A-Z], [0-9], '-', '_' and ' '
  47. //
  48. Len = strlen((CHAR*)_PreferredDosName);
  49. if ((Len <= 7) && (Len >= 1)) {
  50. for (i=0; i<Len; i++) {
  51. if(((_PreferredDosName[i] < 'A') || (_PreferredDosName[i] > 'Z')) &&
  52. ((_PreferredDosName[i] < 'a') || (_PreferredDosName[i] > 'z')) &&
  53. ((_PreferredDosName[i] < '0') || (_PreferredDosName[i] > '9')) &&
  54. (_PreferredDosName[i] != '-') &&
  55. (_PreferredDosName[i] != '_') &&
  56. (_PreferredDosName[i] != ' ')) {
  57. fRet = FALSE;
  58. break;
  59. }
  60. }
  61. }
  62. else {
  63. fRet = FALSE;
  64. }
  65. //
  66. // This assert should never fire for drive redirection
  67. //
  68. ASSERT(fRet);
  69. return fRet;
  70. }
  71. NTSTATUS DrDrive::Initialize(PRDPDR_DEVICE_ANNOUNCE DeviceAnnounce, ULONG Length)
  72. {
  73. NTSTATUS Status;
  74. UNICODE_STRING DriveName;
  75. WCHAR DriveNameBuff[PREFERRED_DOS_NAME_SIZE];
  76. INT len;
  77. BEGIN_FN("DrDrive::Initialize");
  78. Status = DrDevice::Initialize(DeviceAnnounce, Length);
  79. if (ShouldCreateDevice()) {
  80. if (!NT_ERROR(Status)) {
  81. DriveName.MaximumLength = sizeof(DriveNameBuff);
  82. DriveName.Length = 0;
  83. DriveName.Buffer = &DriveNameBuff[0];
  84. memset(&DriveNameBuff, 0, sizeof(DriveNameBuff));
  85. ASSERT(_PreferredDosName != NULL);
  86. len = strlen((char *)_PreferredDosName);
  87. len = ConvertToAndFromWideChar(0, DriveName.Buffer,
  88. DriveName.MaximumLength, (char *)_PreferredDosName,
  89. len, TRUE);
  90. if (len != -1) {
  91. //
  92. // We need just the drive letter portion
  93. //
  94. DriveName.Length = (USHORT)len;
  95. TRC_NRM((TB, "New drive: %wZ", &DriveName));
  96. } else {
  97. TRC_ERR((TB, "Error converting DriveName"));
  98. return STATUS_UNSUCCESSFUL;
  99. }
  100. //
  101. // Request the user mode notify dll to create UNC connection
  102. // for redirected client drives
  103. //
  104. Status = CreateDrive(DeviceAnnounce, DriveName.Buffer);
  105. }
  106. }
  107. else {
  108. Status = STATUS_SUCCESS;
  109. }
  110. return Status;
  111. }
  112. NTSTATUS DrDrive::CreateDrive(PRDPDR_DEVICE_ANNOUNCE devAnnounceMsg, PWCHAR DriveName)
  113. {
  114. NTSTATUS Status;
  115. ULONG driveAnnounceEventReqSize;
  116. PRDPDR_DRIVEDEVICE_SUB driveAnnounceEvent;
  117. BEGIN_FN("DrDrive::CreateDrive");
  118. ASSERT(DriveName != NULL);
  119. //
  120. // Allocate the drive device announce buffer.
  121. //
  122. Status = CreateDriveAnnounceEvent(devAnnounceMsg, NULL, 0, L"",
  123. &driveAnnounceEventReqSize);
  124. ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
  125. if( Status != STATUS_BUFFER_TOO_SMALL) {
  126. goto CleanUpAndReturn;
  127. }
  128. driveAnnounceEvent = (PRDPDR_DRIVEDEVICE_SUB)new(NonPagedPool)
  129. BYTE[driveAnnounceEventReqSize];
  130. if (driveAnnounceEvent == NULL) {
  131. TRC_ERR((TB, "Unable to allocate driveAnnounceEvent"));
  132. Status = STATUS_NO_MEMORY;
  133. goto CleanUpAndReturn;
  134. }
  135. //
  136. // Create the drive anounce message.
  137. //
  138. Status = CreateDriveAnnounceEvent(devAnnounceMsg, driveAnnounceEvent,
  139. driveAnnounceEventReqSize, DriveName, NULL);
  140. if (Status != STATUS_SUCCESS) {
  141. delete driveAnnounceEvent;
  142. #if DBG
  143. driveAnnounceEvent = NULL;
  144. #endif
  145. goto CleanUpAndReturn;
  146. }
  147. //
  148. // Dispatch the event to the associated session.
  149. //
  150. Status = RDPDYN_DispatchNewDevMgmtEvent(
  151. driveAnnounceEvent,
  152. _Session->GetSessionId(),
  153. RDPDREVT_DRIVEANNOUNCE,
  154. NULL
  155. );
  156. CleanUpAndReturn:
  157. return Status;
  158. }
  159. NTSTATUS DrDrive::CreateDriveAnnounceEvent(
  160. IN PRDPDR_DEVICE_ANNOUNCE devAnnounceMsg,
  161. IN OUT PRDPDR_DRIVEDEVICE_SUB driveAnnounceEvent,
  162. IN ULONG driveAnnounceEventSize,
  163. IN PCWSTR driveName,
  164. OPTIONAL OUT ULONG *driveAnnounceEventReqSize
  165. )
  166. /*++
  167. Routine Description:
  168. Generate a RDPDR_DRIVEDEVICE_SUB event from a client-sent
  169. RDPDR_DEVICE_ANNOUNCE message.
  170. Arguments:
  171. devAnnounceMsg - Device announce message received from client.
  172. driveAnnounceEvent - Buffer for receiving finished drive announce event.
  173. driveAnnounceEventSize - Size of driveAnnounceEvent buffer.
  174. driveName - Name of local drive to be associated with
  175. client-side drive device.
  176. driveAnnounceEventReqSize - Returned required size of driveAnnounceMsg buffer.
  177. Return Value:
  178. STATUS_INVALID_BUFFER_SIZE is returned if the driveAnnounceEventSize size is
  179. too small. STATUS_SUCCESS is returned on success.
  180. --*/
  181. {
  182. ULONG requiredSize;
  183. ULONG sz;
  184. BEGIN_FN("DrDrive::CreateDriveAnnounceEvent");
  185. // Make sure the client-sent device announce message is a drive announce
  186. // message.
  187. TRC_ASSERT(devAnnounceMsg->DeviceType == RDPDR_DTYP_FILESYSTEM,
  188. (TB, "file system device expected"));
  189. //
  190. // Make sure that the device datalengths we got from the client
  191. // doesn't exceed what we expect
  192. //
  193. if (!DR_CHECK_DEVICEDATALEN(devAnnounceMsg, RDPDR_DRIVEDEVICE_SUB)) {
  194. return STATUS_INVALID_PARAMETER;
  195. }
  196. //
  197. // Calculate the number of bytes needed in the output buffer.
  198. //
  199. requiredSize = sizeof(RDPDR_DRIVEDEVICE_SUB) + devAnnounceMsg->DeviceDataLength;
  200. if (driveAnnounceEventSize < requiredSize) {
  201. if (driveAnnounceEventReqSize != NULL) {
  202. *driveAnnounceEventReqSize = requiredSize;
  203. }
  204. return STATUS_BUFFER_TOO_SMALL;
  205. }
  206. //
  207. // Add the data to the output buffer.
  208. //
  209. // Drive Name.
  210. TRC_ASSERT(wcslen(driveName)+1 <= RDPDR_MAXPORTNAMELEN,
  211. (TB, "drive name too long"));
  212. wcscpy(driveAnnounceEvent->driveName, driveName);
  213. // Client Name (UNC server name).
  214. #if 0
  215. TRC_ASSERT(wcslen(_Session->GetClientName())+1 <= RDPDR_MAX_COMPUTER_NAME_LENGTH,
  216. (TB, "Client name too long"));
  217. wcscpy(driveAnnounceEvent->clientName, _Session->GetClientName());
  218. #endif
  219. wcscpy(driveAnnounceEvent->clientName, DRUNCSERVERNAME_U);
  220. // Client-received device announce message.
  221. RtlCopyMemory(&driveAnnounceEvent->deviceFields, devAnnounceMsg,
  222. sizeof(RDPDR_DEVICE_ANNOUNCE) +
  223. devAnnounceMsg->DeviceDataLength);
  224. wcscpy(driveAnnounceEvent->clientDisplayName, _Session->GetClientDisplayName());
  225. // Return the size.
  226. if (driveAnnounceEventReqSize != NULL) {
  227. *driveAnnounceEventReqSize = requiredSize;
  228. }
  229. TRC_NRM((TB, "exit CreateDriveAnnounceEvent."));
  230. return STATUS_SUCCESS;
  231. }
  232. VOID DrDrive::Remove()
  233. {
  234. PRDPDR_REMOVEDEVICE deviceRemoveEventPtr = NULL;
  235. BEGIN_FN("DrDrive::Remove");
  236. //
  237. // Create and dispatch the remove device event.
  238. //
  239. deviceRemoveEventPtr = new(NonPagedPool) RDPDR_REMOVEDEVICE;
  240. if (deviceRemoveEventPtr != NULL) {
  241. //
  242. // Dispatch it.
  243. //
  244. deviceRemoveEventPtr->deviceID = _DeviceId;
  245. RDPDYN_DispatchNewDevMgmtEvent(
  246. deviceRemoveEventPtr,
  247. _Session->GetSessionId(),
  248. RDPDREVT_REMOVEDEVICE,
  249. NULL
  250. );
  251. }
  252. else {
  253. TRC_ERR((TB, "Unable to allocate %ld bytes for remove event",
  254. sizeof(RDPDR_REMOVEDEVICE)));
  255. }
  256. }
  257. NTSTATUS DrDrive::QueryDirectory(IN OUT PRX_CONTEXT RxContext)
  258. {
  259. NTSTATUS Status = STATUS_SUCCESS;
  260. RxCaptureFcb;
  261. RxCaptureFobx;
  262. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  263. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  264. SmartPtr<DrSession> Session = _Session;
  265. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  266. SmartPtr<DrFile> FileObj = pFile;
  267. PRDPDR_IOREQUEST_PACKET pIoPacket;
  268. ULONG cbPacketSize;
  269. BOOL bTemplateEndsDOT = FALSE;
  270. FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
  271. PUNICODE_STRING DirectoryName = GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext);
  272. PUNICODE_STRING QueryTemplate = &(capFobx->UnicodeQueryTemplate);
  273. BEGIN_FN("DrDrive:QueryDirectory");
  274. //
  275. // Make sure it's okay to access the Client at this time
  276. // This is an optimization, we don't need to acquire the spin lock,
  277. // because it is okay if we're not, we'll just catch it later
  278. //
  279. ASSERT(RxContext != NULL);
  280. ASSERT(RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL);
  281. ASSERT(Session != NULL);
  282. if (!Session->IsConnected()) {
  283. return STATUS_DEVICE_NOT_CONNECTED;
  284. }
  285. if (FileObj == NULL) {
  286. return STATUS_DEVICE_NOT_CONNECTED;
  287. }
  288. //
  289. // Make sure the device is still enabled
  290. //
  291. if (_DeviceStatus != dsAvailable) {
  292. TRC_ALT((TB, "Tried to query client directory information while not "
  293. "available. State: %ld", _DeviceStatus));
  294. return STATUS_DEVICE_NOT_CONNECTED;
  295. }
  296. TRC_DBG((TB, "QueryDirectory information class = %x", FileInformationClass));
  297. //
  298. // Check what file information class it is requesting
  299. //
  300. switch (FileInformationClass) {
  301. case FileDirectoryInformation:
  302. case FileFullDirectoryInformation:
  303. case FileBothDirectoryInformation:
  304. case FileNamesInformation:
  305. // let client handle these
  306. break;
  307. default:
  308. TRC_DBG((TB, "Unhandled FileInformationClass=%x", FileInformationClass));
  309. return STATUS_INVALID_PARAMETER;
  310. }
  311. //
  312. // Build the querydir packet and send it to the client
  313. //
  314. if (RxContext->QueryDirectory.InitialQuery) {
  315. LONG index;
  316. ASSERT(DirectoryName->Length != 0);
  317. ASSERT(QueryTemplate->Length != 0);
  318. //
  319. // Account for 3 extra characters
  320. // 1) We append string null terminator to the end
  321. // 2) add \ between directory name and query template
  322. // 3) need to translate template ending < to *.
  323. //
  324. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) + DirectoryName->Length +
  325. capFobx->UnicodeQueryTemplate.Length + sizeof(WCHAR) * 3;
  326. //
  327. // Query template translation back into win32 format
  328. // Look filefind.c from base\win32\client for the original translation
  329. //
  330. TRC_DBG((TB, "QueryTemplate before %wZ\n", QueryTemplate));
  331. if (QueryTemplate->Buffer[QueryTemplate->Length/sizeof(WCHAR) - 1] == DOS_STAR) {
  332. bTemplateEndsDOT = TRUE;
  333. QueryTemplate->Buffer[QueryTemplate->Length/sizeof(WCHAR) - 1] = L'*';
  334. }
  335. for (index = QueryTemplate->Length/sizeof(WCHAR) - 1; index >= 0; index--) {
  336. if (index && QueryTemplate->Buffer[index] == L'.' &&
  337. QueryTemplate->Buffer[index - 1] == DOS_STAR) {
  338. QueryTemplate->Buffer[index - 1] = L'*';
  339. }
  340. if (QueryTemplate->Buffer[index] == DOS_QM) {
  341. QueryTemplate->Buffer[index] = L'?';
  342. }
  343. if (index && (QueryTemplate->Buffer[index] == L'?' ||
  344. QueryTemplate->Buffer[index] == L'*') &&
  345. QueryTemplate->Buffer[index - 1] == DOS_DOT) {
  346. QueryTemplate->Buffer[index - 1] = L'.';
  347. }
  348. }
  349. TRC_DBG((TB, "QueryTemplate after %wZ, bTemplateEndsDOT=%x\n", QueryTemplate,
  350. bTemplateEndsDOT));
  351. }
  352. else {
  353. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET);
  354. }
  355. pIoPacket = (PRDPDR_IOREQUEST_PACKET)new(PagedPool) BYTE[cbPacketSize];
  356. if (pIoPacket) {
  357. memset(pIoPacket, 0, cbPacketSize);
  358. pIoPacket->Header.Component = RDPDR_CTYP_CORE;
  359. pIoPacket->Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  360. pIoPacket->IoRequest.DeviceId = _DeviceId;
  361. pIoPacket->IoRequest.FileId = FileObj->GetFileId();
  362. pIoPacket->IoRequest.MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
  363. pIoPacket->IoRequest.MinorFunction = IRP_MN_QUERY_DIRECTORY;
  364. pIoPacket->IoRequest.Parameters.QueryDir.FileInformationClass =
  365. (RDP_FILE_INFORMATION_CLASS)FileInformationClass;
  366. pIoPacket->IoRequest.Parameters.QueryDir.InitialQuery =
  367. RxContext->QueryDirectory.InitialQuery;
  368. if (RxContext->QueryDirectory.InitialQuery) {
  369. //
  370. // This is in the format of <DirectoryName>\<QueryTemplate>\0
  371. //
  372. RtlCopyMemory(pIoPacket + 1, DirectoryName->Buffer, DirectoryName->Length);
  373. if (((PWCHAR)(pIoPacket + 1))[DirectoryName->Length / sizeof(WCHAR) - 1] != L'\\') {
  374. ((PWCHAR)(pIoPacket + 1))[DirectoryName->Length / sizeof(WCHAR)] = L'\\';
  375. RtlCopyMemory((PBYTE)(pIoPacket + 1) + DirectoryName->Length + sizeof(WCHAR),
  376. QueryTemplate->Buffer, QueryTemplate->Length);
  377. pIoPacket->IoRequest.Parameters.QueryDir.PathLength = DirectoryName->Length +
  378. QueryTemplate->Length + sizeof(WCHAR);
  379. }
  380. else {
  381. RtlCopyMemory((PBYTE)(pIoPacket + 1) + DirectoryName->Length,
  382. QueryTemplate->Buffer, QueryTemplate->Length);
  383. pIoPacket->IoRequest.Parameters.QueryDir.PathLength = DirectoryName->Length +
  384. QueryTemplate->Length;
  385. cbPacketSize -= sizeof(WCHAR);
  386. }
  387. //
  388. // Add . for the query template if it ends like *.
  389. //
  390. if (bTemplateEndsDOT) {
  391. ((PWCHAR)(pIoPacket + 1))[pIoPacket->IoRequest.Parameters.QueryDir.PathLength
  392. / sizeof(WCHAR)] = L'.';
  393. pIoPacket->IoRequest.Parameters.QueryDir.PathLength += sizeof(WCHAR);
  394. }
  395. else {
  396. cbPacketSize -= sizeof(WCHAR);
  397. }
  398. //
  399. // Path length includes the null terminator
  400. //
  401. pIoPacket->IoRequest.Parameters.QueryDir.PathLength += sizeof(WCHAR);
  402. // The pIoPacket is already zero'd. So, no need to null terminate it
  403. } else {
  404. //
  405. // This is not the first query, so we should already have the file
  406. // handle open
  407. //
  408. pIoPacket->IoRequest.Parameters.QueryDir.PathLength = 0;
  409. }
  410. Status = SendIoRequest(RxContext, pIoPacket, cbPacketSize,
  411. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  412. delete pIoPacket;
  413. }
  414. else {
  415. Status = STATUS_INSUFFICIENT_RESOURCES;
  416. }
  417. return Status;
  418. }
  419. NTSTATUS DrDrive::NotifyChangeDirectory(IN OUT PRX_CONTEXT RxContext)
  420. {
  421. NTSTATUS Status = STATUS_SUCCESS;
  422. RxCaptureFcb;
  423. RxCaptureFobx;
  424. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  425. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  426. SmartPtr<DrSession> Session = _Session;
  427. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  428. SmartPtr<DrFile> FileObj = pFile;
  429. RDPDR_IOREQUEST_PACKET IoPacket;
  430. ULONG cbPacketSize;
  431. PLOWIO_CONTEXT pLowIoContext = &RxContext->LowIoContext;
  432. BEGIN_FN("DrDrive:NotifyChangeDirectory");
  433. //
  434. // Make sure it's okay to access the Client at this time
  435. // This is an optimization, we don't need to acquire the spin lock,
  436. // because it is okay if we're not, we'll just catch it later
  437. //
  438. ASSERT(RxContext != NULL);
  439. ASSERT(RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL);
  440. ASSERT(Session != NULL);
  441. if (COMPARE_VERSION(Session->GetClientVersion().Minor,
  442. Session->GetClientVersion().Major, 4, 1) < 0) {
  443. TRC_ALT((TB, "Failing NotifyChangeDirectory for client that doesn't support it"));
  444. return STATUS_NOT_IMPLEMENTED;
  445. }
  446. if (!Session->IsConnected()) {
  447. return STATUS_DEVICE_NOT_CONNECTED;
  448. }
  449. if (FileObj == NULL) {
  450. return STATUS_DEVICE_NOT_CONNECTED;
  451. }
  452. //
  453. // Make sure the device is still enabled
  454. //
  455. if (_DeviceStatus != dsAvailable) {
  456. TRC_ALT((TB, "Tried to query client directory change notify information while not "
  457. "available. State: %ld", _DeviceStatus));
  458. return STATUS_DEVICE_NOT_CONNECTED;
  459. }
  460. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET);
  461. memset(&IoPacket, 0, cbPacketSize);
  462. IoPacket.Header.Component = RDPDR_CTYP_CORE;
  463. IoPacket.Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  464. IoPacket.IoRequest.DeviceId = _DeviceId;
  465. IoPacket.IoRequest.FileId = FileObj->GetFileId();
  466. IoPacket.IoRequest.MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
  467. IoPacket.IoRequest.MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
  468. IoPacket.IoRequest.Parameters.NotifyChangeDir.WatchTree =
  469. pLowIoContext->ParamsFor.NotifyChangeDirectory.WatchTree;
  470. IoPacket.IoRequest.Parameters.NotifyChangeDir.CompletionFilter =
  471. pLowIoContext->ParamsFor.NotifyChangeDirectory.CompletionFilter;
  472. Status = SendIoRequest(RxContext, &IoPacket, cbPacketSize,
  473. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  474. return Status;
  475. }
  476. NTSTATUS DrDrive::QueryVolumeInfo(IN OUT PRX_CONTEXT RxContext)
  477. {
  478. NTSTATUS Status = STATUS_SUCCESS;
  479. RxCaptureFcb;
  480. RxCaptureFobx;
  481. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  482. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  483. SmartPtr<DrSession> Session = _Session;
  484. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  485. SmartPtr<DrFile> FileObj = pFile;
  486. RDPDR_IOREQUEST_PACKET IoPacket;
  487. FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
  488. BEGIN_FN("DrDrive:QueryVolumeInfo");
  489. //
  490. // Make sure it's okay to access the Client at this time
  491. // This is an optimization, we don't need to acquire the spin lock,
  492. // because it is okay if we're not, we'll just catch it later
  493. //
  494. ASSERT(RxContext != NULL);
  495. ASSERT(RxContext->MajorFunction == IRP_MJ_QUERY_VOLUME_INFORMATION);
  496. ASSERT(Session != NULL);
  497. if (!Session->IsConnected()) {
  498. return STATUS_DEVICE_NOT_CONNECTED;
  499. }
  500. if (FileObj == NULL) {
  501. return STATUS_DEVICE_NOT_CONNECTED;
  502. }
  503. //
  504. // Make sure the device is still enabled
  505. //
  506. if (_DeviceStatus != dsAvailable) {
  507. TRC_ALT((TB, "Tried to query client device volume information while not "
  508. "available. State: %ld", _DeviceStatus));
  509. return STATUS_DEVICE_NOT_CONNECTED;
  510. }
  511. TRC_DBG((TB, "QueryVolume information class = %x", FsInformationClass));
  512. switch (FsInformationClass) {
  513. case FileFsVolumeInformation:
  514. //case FileFsLabelInformation:
  515. // Smb seems to handle query label information, but i think
  516. // this is only for set label info. We'll see if we should
  517. // actually handle query label information.
  518. // query label can be achieved through volume information
  519. case FileFsSizeInformation:
  520. case FileFsAttributeInformation:
  521. // let client handle these
  522. break;
  523. case FileFsDeviceInformation:
  524. {
  525. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  526. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  527. if (sizeof(FILE_FS_DEVICE_INFORMATION) <= *pLengthRemaining) {
  528. PFILE_FS_DEVICE_INFORMATION UsersBuffer =
  529. (PFILE_FS_DEVICE_INFORMATION) RxContext->Info.Buffer;
  530. UsersBuffer->Characteristics = FILE_REMOTE_DEVICE;
  531. UsersBuffer->DeviceType = FILE_DEVICE_DISK;
  532. *pLengthRemaining -= (sizeof(FILE_FS_DEVICE_INFORMATION));
  533. return STATUS_SUCCESS;
  534. }
  535. else {
  536. FILE_FS_DEVICE_INFORMATION UsersBuffer;
  537. UsersBuffer.Characteristics = FILE_REMOTE_DEVICE;
  538. UsersBuffer.DeviceType = FILE_DEVICE_DISK;
  539. RtlCopyMemory(RxContext->Info.Buffer, &UsersBuffer, *pLengthRemaining);
  540. *pLengthRemaining = 0;
  541. return STATUS_BUFFER_OVERFLOW;
  542. }
  543. }
  544. case FileFsFullSizeInformation:
  545. TRC_DBG((TB, "Unhandled FsInformationClass=%x", FsInformationClass));
  546. return STATUS_NOT_IMPLEMENTED;
  547. default:
  548. TRC_DBG((TB, "Unhandled FsInformationClass=%x", FsInformationClass));
  549. return STATUS_NOT_IMPLEMENTED;
  550. }
  551. memset(&IoPacket, 0, sizeof(IoPacket));
  552. IoPacket.Header.Component = RDPDR_CTYP_CORE;
  553. IoPacket.Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  554. IoPacket.IoRequest.DeviceId = _DeviceId;
  555. IoPacket.IoRequest.FileId = FileObj->GetFileId();
  556. IoPacket.IoRequest.MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
  557. IoPacket.IoRequest.MinorFunction = 0;
  558. IoPacket.IoRequest.Parameters.QueryVolume.FsInformationClass =
  559. (RDP_FS_INFORMATION_CLASS)FsInformationClass;
  560. Status = SendIoRequest(RxContext, &IoPacket, sizeof(IoPacket),
  561. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  562. return Status;
  563. }
  564. NTSTATUS DrDrive::SetVolumeInfo(IN OUT PRX_CONTEXT RxContext)
  565. {
  566. NTSTATUS Status = STATUS_SUCCESS;
  567. RxCaptureFcb;
  568. RxCaptureFobx;
  569. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  570. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  571. SmartPtr<DrSession> Session = _Session;
  572. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  573. SmartPtr<DrFile> FileObj = pFile;
  574. PRDPDR_IOREQUEST_PACKET pIoPacket;
  575. ULONG cbPacketSize = 0;
  576. FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
  577. BEGIN_FN("DrDrive:SetVolumeInfo");
  578. //
  579. // Make sure it's okay to access the Client at this time
  580. // This is an optimization, we don't need to acquire the spin lock,
  581. // because it is okay if we're not, we'll just catch it later
  582. //
  583. ASSERT(RxContext != NULL);
  584. ASSERT(RxContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION);
  585. ASSERT(Session != NULL);
  586. if (!Session->IsConnected()) {
  587. RxContext->IoStatusBlock.Information = 0;
  588. return STATUS_DEVICE_NOT_CONNECTED;
  589. }
  590. if (FileObj == NULL) {
  591. return STATUS_DEVICE_NOT_CONNECTED;
  592. }
  593. //
  594. // Make sure the device is still enabled
  595. //
  596. if (_DeviceStatus != dsAvailable) {
  597. TRC_ALT((TB, "Tried to set client device volume information while not "
  598. "available. State: %ld", _DeviceStatus));
  599. return STATUS_DEVICE_NOT_CONNECTED;
  600. }
  601. //
  602. // Check buffer length
  603. //
  604. if (RxContext->Info.Length == 0) {
  605. RxContext->IoStatusBlock.Information = 0;
  606. return STATUS_SUCCESS;
  607. }
  608. TRC_DBG((TB, "SetVolume Information class = %x", FsInformationClass));
  609. switch (FsInformationClass) {
  610. case FileFsLabelInformation:
  611. {
  612. PFILE_FS_LABEL_INFORMATION pRxBuffer =
  613. (PFILE_FS_LABEL_INFORMATION) RxContext->Info.Buffer;
  614. //
  615. // REVIEW: Find out why Info.Length has the extra 2 bytes
  616. // It doesn't seem to put string null terminator to it
  617. //
  618. if ((ULONG)RxContext->Info.Length == FIELD_OFFSET(FILE_FS_LABEL_INFORMATION,
  619. VolumeLabel) + pRxBuffer->VolumeLabelLength + sizeof(WCHAR)) {
  620. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) +
  621. RxContext->Info.Length;
  622. // Make sure that label is null terminiated
  623. pRxBuffer->VolumeLabel[pRxBuffer->VolumeLabelLength/sizeof(WCHAR)] = L'\0';
  624. }
  625. else {
  626. TRC_ERR((TB, "Invalid Volume label info"));
  627. return STATUS_INVALID_PARAMETER;
  628. }
  629. // Let client handle this
  630. break;
  631. }
  632. default:
  633. TRC_DBG((TB, "Unhandled FsInformationClass=%x", FsInformationClass));
  634. return STATUS_NOT_SUPPORTED;
  635. }
  636. pIoPacket = (PRDPDR_IOREQUEST_PACKET)new(PagedPool) BYTE[cbPacketSize];
  637. if (pIoPacket != NULL) {
  638. memset(pIoPacket, 0, cbPacketSize);
  639. pIoPacket->Header.Component = RDPDR_CTYP_CORE;
  640. pIoPacket->Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  641. pIoPacket->IoRequest.DeviceId = _DeviceId;
  642. pIoPacket->IoRequest.FileId = FileObj->GetFileId();
  643. pIoPacket->IoRequest.MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
  644. pIoPacket->IoRequest.MinorFunction = 0;
  645. pIoPacket->IoRequest.Parameters.SetVolume.FsInformationClass =
  646. (RDP_FS_INFORMATION_CLASS)FsInformationClass;
  647. pIoPacket->IoRequest.Parameters.SetVolume.Length = RxContext->Info.Length;
  648. RtlCopyMemory(pIoPacket + 1, RxContext->Info.Buffer, RxContext->Info.Length);
  649. Status = SendIoRequest(RxContext, pIoPacket, cbPacketSize,
  650. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  651. delete pIoPacket;
  652. } else {
  653. Status = STATUS_INSUFFICIENT_RESOURCES;
  654. }
  655. return Status;
  656. }
  657. NTSTATUS DrDrive::QueryFileInfo(IN OUT PRX_CONTEXT RxContext)
  658. {
  659. NTSTATUS Status = STATUS_SUCCESS;
  660. RxCaptureFcb;
  661. RxCaptureFobx;
  662. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  663. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  664. SmartPtr<DrSession> Session = _Session;
  665. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  666. SmartPtr<DrFile> FileObj = pFile;
  667. RDPDR_IOREQUEST_PACKET IoPacket;
  668. FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
  669. BEGIN_FN("DrDrive:QueryFileInfo");
  670. //
  671. // Make sure it's okay to access the Client at this time
  672. // This is an optimization, we don't need to acquire the spin lock,
  673. // because it is okay if we're not, we'll just catch it later
  674. //
  675. ASSERT(RxContext != NULL);
  676. ASSERT(RxContext->MajorFunction == IRP_MJ_QUERY_INFORMATION);
  677. ASSERT(Session != NULL);
  678. if (!Session->IsConnected()) {
  679. return STATUS_DEVICE_NOT_CONNECTED;
  680. }
  681. if (FileObj == NULL) {
  682. return STATUS_DEVICE_NOT_CONNECTED;
  683. }
  684. //
  685. // Make sure the device is still enabled
  686. //
  687. if (_DeviceStatus != dsAvailable) {
  688. TRC_ALT((TB, "Tried to query client file information while not "
  689. "available. State: %ld", _DeviceStatus));
  690. return STATUS_DEVICE_NOT_CONNECTED;
  691. }
  692. TRC_DBG((TB, "QueryFile information class = %x", FileInformationClass));
  693. switch (FileInformationClass) {
  694. case FileBasicInformation:
  695. case FileStandardInformation:
  696. case FileAttributeTagInformation:
  697. // let client handle these
  698. break;
  699. case FileEaInformation:
  700. {
  701. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  702. // Should check buffer length
  703. if (sizeof(FILE_EA_INFORMATION) <= *pLengthRemaining) {
  704. ((PFILE_EA_INFORMATION)(RxContext->Info.Buffer))->EaSize = 0;
  705. *pLengthRemaining -= sizeof(FILE_EA_INFORMATION);
  706. return STATUS_SUCCESS;
  707. }
  708. else {
  709. return STATUS_BUFFER_OVERFLOW;
  710. }
  711. }
  712. case FileAllocationInformation:
  713. case FileEndOfFileInformation:
  714. case FileAlternateNameInformation:
  715. case FileStreamInformation:
  716. case FileCompressionInformation:
  717. TRC_DBG((TB, "Unhandled FileInformationClass=%x", FileInformationClass));
  718. return STATUS_NOT_IMPLEMENTED;
  719. case FileInternalInformation:
  720. {
  721. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  722. PFILE_INTERNAL_INFORMATION UsersBuffer =
  723. (PFILE_INTERNAL_INFORMATION)RxContext->Info.Buffer;
  724. if (sizeof(FILE_INTERNAL_INFORMATION) <= *pLengthRemaining) {
  725. UsersBuffer->IndexNumber.QuadPart = (ULONG_PTR)capFcb;
  726. *pLengthRemaining -= sizeof(FILE_INTERNAL_INFORMATION);
  727. return STATUS_SUCCESS;
  728. }
  729. else {
  730. return STATUS_BUFFER_OVERFLOW;
  731. }
  732. }
  733. default:
  734. TRC_DBG((TB, "Unhandled FileInformationClass=%x", FileInformationClass));
  735. return STATUS_INVALID_PARAMETER;
  736. }
  737. memset(&IoPacket, 0, sizeof(IoPacket));
  738. IoPacket.Header.Component = RDPDR_CTYP_CORE;
  739. IoPacket.Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  740. IoPacket.IoRequest.DeviceId = _DeviceId;
  741. IoPacket.IoRequest.FileId = FileObj->GetFileId();
  742. IoPacket.IoRequest.MajorFunction = IRP_MJ_QUERY_INFORMATION;
  743. IoPacket.IoRequest.MinorFunction = 0;
  744. IoPacket.IoRequest.Parameters.QueryFile.FileInformationClass =
  745. (RDP_FILE_INFORMATION_CLASS)FileInformationClass;
  746. Status = SendIoRequest(RxContext, &IoPacket, sizeof(IoPacket),
  747. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  748. return Status;
  749. }
  750. NTSTATUS DrDrive::SetFileInfo(IN OUT PRX_CONTEXT RxContext)
  751. {
  752. NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
  753. RxCaptureFcb;
  754. RxCaptureFobx;
  755. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  756. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  757. SmartPtr<DrSession> Session = _Session;
  758. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  759. SmartPtr<DrFile> FileObj = pFile;
  760. PRDPDR_IOREQUEST_PACKET pIoPacket;
  761. ULONG cbPacketSize = 0;
  762. FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
  763. BOOLEAN bBufferRepackage = FALSE;
  764. BEGIN_FN("DrDrive:SetFileInfo");
  765. //
  766. // Make sure it's okay to access the Client at this time
  767. // This is an optimization, we don't need to acquire the spin lock,
  768. // because it is okay if we're not, we'll just catch it later
  769. //
  770. ASSERT(RxContext != NULL);
  771. ASSERT(RxContext->MajorFunction == IRP_MJ_SET_INFORMATION);
  772. ASSERT(Session != NULL);
  773. if (!Session->IsConnected()) {
  774. RxContext->IoStatusBlock.Information = 0;
  775. return STATUS_DEVICE_NOT_CONNECTED;
  776. }
  777. if (FileObj == NULL) {
  778. return STATUS_DEVICE_NOT_CONNECTED;
  779. }
  780. //
  781. // Make sure the device is still enabled
  782. //
  783. if (_DeviceStatus != dsAvailable) {
  784. TRC_ALT((TB, "Tried to set client device file information while not "
  785. "available. State: %ld", _DeviceStatus));
  786. return STATUS_DEVICE_NOT_CONNECTED;
  787. }
  788. //
  789. // Check buffer length
  790. //
  791. if (RxContext->Info.Length == 0) {
  792. RxContext->IoStatusBlock.Information = 0;
  793. return STATUS_SUCCESS;
  794. }
  795. TRC_DBG((TB, "SetFile information class=%x", FileInformationClass));
  796. switch (FileInformationClass) {
  797. case FileBasicInformation:
  798. {
  799. if (sizeof(FILE_BASIC_INFORMATION) == RxContext->Info.Length) {
  800. if (RxContext->Info.Length == sizeof(RDP_FILE_BASIC_INFORMATION)) {
  801. bBufferRepackage = FALSE;
  802. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) + RxContext->Info.Length;
  803. }
  804. else {
  805. bBufferRepackage = TRUE;
  806. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) +
  807. sizeof(RDP_FILE_BASIC_INFORMATION);
  808. }
  809. }
  810. else {
  811. TRC_ERR((TB, "Invalid FileBasicInformation buffer"));
  812. return STATUS_INVALID_PARAMETER;
  813. }
  814. break;
  815. }
  816. case FileEndOfFileInformation:
  817. {
  818. if (sizeof(FILE_END_OF_FILE_INFORMATION) == RxContext->Info.Length) {
  819. bBufferRepackage = FALSE;
  820. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) + RxContext->Info.Length;
  821. }
  822. else {
  823. TRC_ERR((TB, "Invalid FileEndOfFileInformation buffer"));
  824. return STATUS_INVALID_PARAMETER;
  825. }
  826. break;
  827. }
  828. case FileDispositionInformation:
  829. {
  830. if (sizeof(FILE_DISPOSITION_INFORMATION) == RxContext->Info.Length) {
  831. if (((PFILE_DISPOSITION_INFORMATION)(RxContext->Info.Buffer))->DeleteFile) {
  832. bBufferRepackage = FALSE;
  833. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET);
  834. }
  835. else {
  836. //
  837. // We shouldn't get this if the DeleteFile flag is not on
  838. //
  839. ASSERT(FALSE);
  840. return STATUS_SUCCESS;
  841. }
  842. }
  843. else {
  844. TRC_ERR((TB, "Invalid FileDispositionInformation buffer"));
  845. return STATUS_INVALID_PARAMETER;
  846. }
  847. break;
  848. }
  849. case FileRenameInformation:
  850. {
  851. PFILE_RENAME_INFORMATION pRenameInformation =
  852. (PFILE_RENAME_INFORMATION)RxContext->Info.Buffer;
  853. if ((ULONG)(RxContext->Info.Length) == FIELD_OFFSET(FILE_RENAME_INFORMATION,
  854. FileName) + pRenameInformation->FileNameLength) {
  855. if ((ULONG)(RxContext->Info.Length) == FIELD_OFFSET(RDP_FILE_RENAME_INFORMATION,
  856. FileName) + pRenameInformation->FileNameLength) {
  857. bBufferRepackage = FALSE;
  858. //
  859. // Add string null terminator to the filename
  860. //
  861. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) + RxContext->Info.Length + sizeof(WCHAR);
  862. }
  863. else {
  864. bBufferRepackage = TRUE;
  865. //
  866. // Add string null terminator to the filename
  867. //
  868. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) +
  869. FIELD_OFFSET(RDP_FILE_RENAME_INFORMATION,
  870. FileName) + pRenameInformation->FileNameLength + sizeof(WCHAR);
  871. }
  872. }
  873. else {
  874. TRC_ERR((TB, "Bad buffer info for FileRenameInformation class, InfoBuffer length=%x, "
  875. "FileName Length=%x", RxContext->Info.Length, pRenameInformation->FileNameLength));
  876. return STATUS_INVALID_PARAMETER;
  877. }
  878. break;
  879. }
  880. case FileAllocationInformation:
  881. {
  882. TRC_NRM((TB, "Get FileAllocationInfomation"));
  883. if (sizeof(FILE_ALLOCATION_INFORMATION) == RxContext->Info.Length) {
  884. bBufferRepackage = FALSE;
  885. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) + RxContext->Info.Length;
  886. }
  887. else {
  888. TRC_ERR((TB, "Invalid FileAllocationInformation buffer"));
  889. return STATUS_INVALID_PARAMETER;
  890. }
  891. break;
  892. }
  893. case FileLinkInformation:
  894. case FileAttributeTagInformation:
  895. TRC_DBG((TB, "Unhandled FileInformationClass=%x", FileInformationClass));
  896. return STATUS_NOT_IMPLEMENTED;
  897. default:
  898. TRC_DBG((TB, "Unhandled FileInformationClass=%x", FileInformationClass));
  899. return STATUS_INVALID_PARAMETER;
  900. }
  901. pIoPacket = (PRDPDR_IOREQUEST_PACKET)new(PagedPool) BYTE[cbPacketSize];
  902. if (pIoPacket != NULL) {
  903. memset(pIoPacket, 0, cbPacketSize);
  904. pIoPacket->Header.Component = RDPDR_CTYP_CORE;
  905. pIoPacket->Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  906. pIoPacket->IoRequest.DeviceId = _DeviceId;
  907. pIoPacket->IoRequest.FileId = FileObj->GetFileId();
  908. pIoPacket->IoRequest.MajorFunction = IRP_MJ_SET_INFORMATION;
  909. pIoPacket->IoRequest.MinorFunction = 0;
  910. pIoPacket->IoRequest.Parameters.SetFile.FileInformationClass =
  911. (RDP_FILE_INFORMATION_CLASS)FileInformationClass;
  912. if (cbPacketSize > sizeof(RDPDR_IOREQUEST_PACKET)) {
  913. if (!bBufferRepackage) {
  914. pIoPacket->IoRequest.Parameters.SetFile.Length = RxContext->Info.Length;
  915. RtlCopyMemory(pIoPacket + 1, RxContext->Info.Buffer, RxContext->Info.Length);
  916. }
  917. else {
  918. switch (FileInformationClass) {
  919. case FileBasicInformation:
  920. {
  921. PFILE_BASIC_INFORMATION pRxFileInfo =
  922. (PFILE_BASIC_INFORMATION) RxContext->Info.Buffer;
  923. PRDP_FILE_BASIC_INFORMATION pRdpFileInfo =
  924. (PRDP_FILE_BASIC_INFORMATION) (pIoPacket + 1);
  925. pIoPacket->IoRequest.Parameters.SetFile.Length =
  926. sizeof(RDP_FILE_BASIC_INFORMATION);
  927. pRdpFileInfo->ChangeTime.QuadPart = pRxFileInfo->ChangeTime.QuadPart;
  928. pRdpFileInfo->CreationTime.QuadPart = pRxFileInfo->CreationTime.QuadPart;
  929. pRdpFileInfo->FileAttributes = pRxFileInfo->FileAttributes;
  930. pRdpFileInfo->LastAccessTime.QuadPart = pRxFileInfo->LastAccessTime.QuadPart;
  931. pRdpFileInfo->LastWriteTime.QuadPart = pRxFileInfo->LastWriteTime.QuadPart;
  932. break;
  933. }
  934. case FileRenameInformation:
  935. {
  936. PFILE_RENAME_INFORMATION pRxFileInfo =
  937. (PFILE_RENAME_INFORMATION) RxContext->Info.Buffer;
  938. PRDP_FILE_RENAME_INFORMATION pRdpFileInfo =
  939. (PRDP_FILE_RENAME_INFORMATION) (pIoPacket + 1);
  940. pIoPacket->IoRequest.Parameters.SetFile.Length =
  941. cbPacketSize - sizeof(RDPDR_IOREQUEST_PACKET);
  942. pRdpFileInfo->ReplaceIfExists = pRxFileInfo->ReplaceIfExists;
  943. // Always force the client to setup the root directory.
  944. pRdpFileInfo->RootDirectory = 0;
  945. pRdpFileInfo->FileNameLength = pRxFileInfo->FileNameLength + sizeof(WCHAR);
  946. RtlCopyMemory(pRdpFileInfo->FileName, pRxFileInfo->FileName,
  947. pRxFileInfo->FileNameLength);
  948. break;
  949. }
  950. }
  951. }
  952. }
  953. Status = SendIoRequest(RxContext, pIoPacket, cbPacketSize,
  954. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  955. delete pIoPacket;
  956. } else {
  957. Status = STATUS_INSUFFICIENT_RESOURCES;
  958. }
  959. return Status;
  960. }
  961. NTSTATUS DrDrive::QuerySdInfo(IN OUT PRX_CONTEXT RxContext)
  962. {
  963. NTSTATUS Status = STATUS_SUCCESS;
  964. RxCaptureFcb;
  965. RxCaptureFobx;
  966. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  967. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  968. SmartPtr<DrSession> Session = _Session;
  969. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  970. SmartPtr<DrFile> FileObj = pFile;
  971. RDPDR_IOREQUEST_PACKET IoPacket;
  972. BEGIN_FN("DrDrive:QuerySdInfo");
  973. return STATUS_INVALID_DEVICE_REQUEST;
  974. //
  975. // Make sure it's okay to access the Client at this time
  976. // This is an optimization, we don't need to acquire the spin lock,
  977. // because it is okay if we're not, we'll just catch it later
  978. //
  979. ASSERT(RxContext != NULL);
  980. ASSERT(RxContext->MajorFunction == IRP_MJ_QUERY_SECURITY);
  981. ASSERT(Session != NULL);
  982. //
  983. // Return not supported if the client doesn't support query security
  984. //
  985. if (!(Session->GetClientCapabilitySet().GeneralCap.ioCode1 & RDPDR_IRP_MJ_QUERY_SECURITY)) {
  986. TRC_DBG((TB, "QuerySdInfo not supported"));
  987. Status = STATUS_NOT_SUPPORTED;
  988. return Status;
  989. }
  990. if (!Session->IsConnected()) {
  991. return STATUS_DEVICE_NOT_CONNECTED;
  992. }
  993. if (FileObj == NULL) {
  994. return STATUS_DEVICE_NOT_CONNECTED;
  995. }
  996. //
  997. // Make sure the device is still enabled
  998. //
  999. if (_DeviceStatus != dsAvailable) {
  1000. TRC_ALT((TB, "Tried to query client security information while not "
  1001. "available. State: %ld", _DeviceStatus));
  1002. return STATUS_DEVICE_NOT_CONNECTED;
  1003. }
  1004. memset(&IoPacket, 0, sizeof(IoPacket));
  1005. IoPacket.Header.Component = RDPDR_CTYP_CORE;
  1006. IoPacket.Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  1007. IoPacket.IoRequest.DeviceId = _DeviceId;
  1008. IoPacket.IoRequest.FileId = FileObj->GetFileId();
  1009. IoPacket.IoRequest.MajorFunction = IRP_MJ_QUERY_SECURITY;
  1010. IoPacket.IoRequest.MinorFunction = 0;
  1011. IoPacket.IoRequest.Parameters.QuerySd.SecurityInformation =
  1012. RxContext->QuerySecurity.SecurityInformation;
  1013. Status = SendIoRequest(RxContext, &IoPacket, sizeof(IoPacket),
  1014. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  1015. return Status;
  1016. }
  1017. NTSTATUS DrDrive::SetSdInfo(IN OUT PRX_CONTEXT RxContext)
  1018. {
  1019. NTSTATUS Status = STATUS_SUCCESS;
  1020. RxCaptureFcb;
  1021. RxCaptureFobx;
  1022. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1023. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  1024. SmartPtr<DrSession> Session = _Session;
  1025. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  1026. SmartPtr<DrFile> FileObj = pFile;
  1027. PRDPDR_IOREQUEST_PACKET IoPacket;
  1028. ULONG SdLength = RtlLengthSecurityDescriptor(RxContext->SetSecurity.SecurityDescriptor);
  1029. ULONG cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) + SdLength;
  1030. BEGIN_FN("DrDrive:SetFileInfo");
  1031. return STATUS_INVALID_DEVICE_REQUEST;
  1032. //
  1033. // Make sure it's okay to access the Client at this time
  1034. // This is an optimization, we don't need to acquire the spin lock,
  1035. // because it is okay if we're not, we'll just catch it later
  1036. //
  1037. ASSERT(RxContext != NULL);
  1038. ASSERT(RxContext->MajorFunction == IRP_MJ_SET_SECURITY);
  1039. ASSERT(Session != NULL);
  1040. //
  1041. // Return not supported if the client doesn't support query security
  1042. //
  1043. if (!(Session->GetClientCapabilitySet().GeneralCap.ioCode1 & RDPDR_IRP_MJ_SET_SECURITY)) {
  1044. TRC_DBG((TB, "SetSdInfo not supported"));
  1045. Status = STATUS_NOT_SUPPORTED;
  1046. return Status;
  1047. }
  1048. if (!Session->IsConnected()) {
  1049. return STATUS_DEVICE_NOT_CONNECTED;
  1050. }
  1051. if (FileObj == NULL) {
  1052. return STATUS_DEVICE_NOT_CONNECTED;
  1053. }
  1054. //
  1055. // Make sure the device is still enabled
  1056. //
  1057. if (_DeviceStatus != dsAvailable) {
  1058. TRC_ALT((TB, "Tried to set client device security information while not "
  1059. "available. State: %ld", _DeviceStatus));
  1060. return STATUS_DEVICE_NOT_CONNECTED;
  1061. }
  1062. IoPacket = (PRDPDR_IOREQUEST_PACKET)new(PagedPool) BYTE[cbPacketSize];
  1063. if (IoPacket != NULL) {
  1064. IoPacket->Header.Component = RDPDR_CTYP_CORE;
  1065. IoPacket->Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  1066. IoPacket->IoRequest.DeviceId = _DeviceId;
  1067. IoPacket->IoRequest.FileId = FileObj->GetFileId();
  1068. IoPacket->IoRequest.MajorFunction = IRP_MJ_SET_SECURITY;
  1069. IoPacket->IoRequest.MinorFunction = 0;
  1070. IoPacket->IoRequest.Parameters.SetSd.SecurityInformation =
  1071. RxContext->SetSecurity.SecurityInformation;
  1072. IoPacket->IoRequest.Parameters.SetSd.Length = SdLength;
  1073. RtlCopyMemory(IoPacket + 1,RxContext->SetSecurity.SecurityDescriptor, SdLength);
  1074. Status = SendIoRequest(RxContext, IoPacket, cbPacketSize,
  1075. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  1076. delete IoPacket;
  1077. } else {
  1078. Status = STATUS_INSUFFICIENT_RESOURCES;
  1079. }
  1080. return Status;
  1081. }
  1082. NTSTATUS DrDrive::Locks(IN OUT PRX_CONTEXT RxContext)
  1083. {
  1084. NTSTATUS Status = STATUS_SUCCESS;
  1085. RxCaptureFcb;
  1086. RxCaptureFobx;
  1087. RxCaptureRequestPacket;
  1088. RxCaptureParamBlock;
  1089. PMRX_NET_ROOT NetRoot = capFcb->pNetRoot;
  1090. PMRX_SRV_CALL SrvCall = NetRoot->pSrvCall;
  1091. SmartPtr<DrSession> Session = _Session;
  1092. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  1093. SmartPtr<DrFile> FileObj = pFile;
  1094. PRDPDR_IOREQUEST_PACKET pIoPacket;
  1095. ULONG cbPacketSize = 0;
  1096. ULONG NumLocks = 0;
  1097. BEGIN_FN("DrDrive::Locks");
  1098. //
  1099. // Make sure it's okay to access the Client at this time
  1100. // This is an optimization, we don't need to acquire the spin lock,
  1101. // because it is okay if we're not, we'll just catch it later
  1102. //
  1103. ASSERT(RxContext != NULL);
  1104. ASSERT(Session != NULL);
  1105. // We can be called from Major function other than Lock Control
  1106. // For example, on Cleanup to unlock all the locks.
  1107. // ASSERT(RxContext->MajorFunction == IRP_MJ_LOCK_CONTROL);
  1108. if (!Session->IsConnected()) {
  1109. return STATUS_DEVICE_NOT_CONNECTED;
  1110. }
  1111. if (FileObj == NULL) {
  1112. return STATUS_DEVICE_NOT_CONNECTED;
  1113. }
  1114. //
  1115. // Make sure the device is still enabled
  1116. //
  1117. if (_DeviceStatus != dsAvailable) {
  1118. TRC_ALT((TB, "Tried to lock client device file which is not "
  1119. "available. State: %ld", _DeviceStatus));
  1120. return STATUS_DEVICE_NOT_CONNECTED;
  1121. }
  1122. switch (RxContext->LowIoContext.Operation) {
  1123. case LOWIO_OP_SHAREDLOCK:
  1124. case LOWIO_OP_EXCLUSIVELOCK:
  1125. case LOWIO_OP_UNLOCK:
  1126. NumLocks = 1;
  1127. break;
  1128. case LOWIO_OP_UNLOCK_MULTIPLE:
  1129. {
  1130. PLOWIO_LOCK_LIST LockList;
  1131. LockList = RxContext->LowIoContext.ParamsFor.Locks.LockList;
  1132. while (LockList) {
  1133. NumLocks++;
  1134. LockList = LockList->Next;
  1135. }
  1136. break;
  1137. }
  1138. }
  1139. cbPacketSize = sizeof(RDPDR_IOREQUEST_PACKET) +
  1140. NumLocks * sizeof(RDP_LOCK_INFO);
  1141. pIoPacket = (PRDPDR_IOREQUEST_PACKET)new(PagedPool) BYTE[cbPacketSize];
  1142. if (pIoPacket) {
  1143. unsigned i;
  1144. PRDP_LOCK_INFO pLockInfo = (PRDP_LOCK_INFO) (pIoPacket + 1);
  1145. memset(pIoPacket, 0, sizeof(pIoPacket));
  1146. pIoPacket->Header.Component = RDPDR_CTYP_CORE;
  1147. pIoPacket->Header.PacketId = DR_CORE_DEVICE_IOREQUEST;
  1148. pIoPacket->IoRequest.DeviceId = _DeviceId;
  1149. pIoPacket->IoRequest.FileId = FileObj->GetFileId();
  1150. pIoPacket->IoRequest.MajorFunction = IRP_MJ_LOCK_CONTROL;
  1151. pIoPacket->IoRequest.MinorFunction = 0;
  1152. pIoPacket->IoRequest.Parameters.Locks.Operation =
  1153. RxContext->LowIoContext.Operation;
  1154. pIoPacket->IoRequest.Parameters.Locks.Flags =
  1155. (capPARAMS->Flags & SL_FAIL_IMMEDIATELY) ? SL_FAIL_IMMEDIATELY: 0;
  1156. pIoPacket->IoRequest.Parameters.Locks.NumLocks = NumLocks;
  1157. if (NumLocks == 1) {
  1158. pLockInfo->LengthLow =
  1159. ((LONG)((LONGLONG)(RxContext->LowIoContext.ParamsFor.Locks.Length)
  1160. & 0xffffffff));
  1161. pLockInfo->LengthHigh =
  1162. ((LONG)((LONGLONG)(RxContext->LowIoContext.ParamsFor.Locks.Length)
  1163. >> 32));
  1164. pLockInfo->OffsetLow =
  1165. ((LONG)((LONGLONG)(RxContext->LowIoContext.ParamsFor.Locks.ByteOffset)
  1166. & 0xffffffff));
  1167. pLockInfo->OffsetHigh =
  1168. ((LONG)((LONGLONG)(RxContext->LowIoContext.ParamsFor.Locks.ByteOffset)
  1169. >> 32));
  1170. }
  1171. else {
  1172. PLOWIO_LOCK_LIST LockList;
  1173. LockList = RxContext->LowIoContext.ParamsFor.Locks.LockList;
  1174. for (i = 0; i < NumLocks; i++) {
  1175. pLockInfo->LengthLow =
  1176. ((LONG)((LONGLONG)(LockList->Length) & 0xffffffff));
  1177. pLockInfo->LengthHigh =
  1178. ((LONG)((LONGLONG)(LockList->Length) >> 32));
  1179. pLockInfo->OffsetLow =
  1180. ((LONG)((LONGLONG)(LockList->ByteOffset) & 0xffffffff));
  1181. pLockInfo->OffsetHigh =
  1182. ((LONG)((LONGLONG)(LockList->ByteOffset) >> 32));
  1183. pLockInfo++;
  1184. LockList = LockList->Next;
  1185. }
  1186. }
  1187. Status = SendIoRequest(RxContext, pIoPacket, cbPacketSize,
  1188. (BOOLEAN)!BooleanFlagOn(RxContext->Flags,RX_CONTEXT_FLAG_ASYNC_OPERATION));
  1189. TRC_NRM((TB, "IoRequestWrite returned to DrRead: %lx", Status));
  1190. delete pIoPacket;
  1191. }
  1192. else {
  1193. Status = STATUS_INSUFFICIENT_RESOURCES;
  1194. }
  1195. return Status;
  1196. }
  1197. NTSTATUS DrDrive::OnDirectoryControlCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  1198. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  1199. {
  1200. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  1201. BEGIN_FN("DrDrive::OnDirectoryControlCompletion");
  1202. if (Context->_MinorFunction == IRP_MN_QUERY_DIRECTORY ||
  1203. Context->_MinorFunction == 0) {
  1204. return OnQueryDirectoryCompletion(CompletionPacket, cbPacket,
  1205. DoDefaultRead, Exchange);
  1206. }
  1207. else if (Context->_MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) {
  1208. return OnNotifyChangeDirectoryCompletion(CompletionPacket, cbPacket,
  1209. DoDefaultRead, Exchange);
  1210. }
  1211. else {
  1212. ASSERT(FALSE);
  1213. if (Context->_RxContext != NULL) {
  1214. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1215. } else {
  1216. DiscardBusyExchange(Exchange);
  1217. }
  1218. *DoDefaultRead = FALSE;
  1219. return STATUS_DEVICE_PROTOCOL_ERROR;
  1220. }
  1221. }
  1222. NTSTATUS DrDrive::OnQueryDirectoryCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  1223. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  1224. {
  1225. PRX_CONTEXT RxContext;
  1226. PVOID pData = CompletionPacket->IoCompletion.Parameters.QueryDir.Buffer;
  1227. ULONG cbWantData; // Amount of actual Read data in this packet
  1228. ULONG cbHaveData; // Amount of data available so far
  1229. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  1230. NTSTATUS Status;
  1231. BEGIN_FN("DrDrive::OnQueryDirectoryCompletion");
  1232. //
  1233. // Even if the IO was cancelled we need to correctly parse
  1234. // this data.
  1235. //
  1236. // Check to make sure this is up to size before accessing
  1237. // further portions of the packet
  1238. //
  1239. RxContext = Context->_RxContext;
  1240. if (cbPacket < (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  1241. IoCompletion.Parameters.QueryDir.Buffer)) {
  1242. //
  1243. // Bad packet. Bad. We've already claimed the RxContext in the
  1244. // atlas. Complete it as unsuccessful. Then shutdown the channel
  1245. // as this is a Bad Client.
  1246. //
  1247. TRC_ERR((TB, "Detected bad client query directory packet"));
  1248. if (RxContext != NULL) {
  1249. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1250. } else {
  1251. DiscardBusyExchange(Exchange);
  1252. }
  1253. //
  1254. // No point in starting a default read or anything, what with the
  1255. // channel being shut down and all.
  1256. //
  1257. *DoDefaultRead = FALSE;
  1258. return STATUS_DEVICE_PROTOCOL_ERROR;
  1259. }
  1260. //
  1261. // Calculate how much data is available immediately and how much data
  1262. // is coming
  1263. //
  1264. if (NT_SUCCESS(CompletionPacket->IoCompletion.IoStatus)) {
  1265. //
  1266. // Successful IO at the client end
  1267. //
  1268. TRC_DBG((TB, "Successful Read at the client end"));
  1269. TRC_DBG((TB, "Read Length: 0x%d, DataCopied 0x%d",
  1270. CompletionPacket->IoCompletion.Parameters.QueryDir.Length,
  1271. Context->_DataCopied));
  1272. cbWantData = CompletionPacket->IoCompletion.Parameters.QueryDir.Length -
  1273. Context->_DataCopied;
  1274. cbHaveData = cbPacket - (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  1275. IoCompletion.Parameters.QueryDir.Buffer);
  1276. if (cbHaveData > cbWantData) {
  1277. //
  1278. // Sounds like a bad client to me
  1279. //
  1280. TRC_ERR((TB, "QueryDir returned more data than "
  1281. "advertised cbHaveData 0x%d cbWantData 0x%d",
  1282. cbHaveData, cbWantData));
  1283. if (RxContext != NULL) {
  1284. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1285. } else {
  1286. DiscardBusyExchange(Exchange);
  1287. }
  1288. *DoDefaultRead = FALSE;
  1289. return STATUS_DEVICE_PROTOCOL_ERROR;
  1290. }
  1291. if (RxContext != NULL) { // And not drexchCancelled
  1292. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  1293. SmartPtr<DrFile> FileObj = pFile;
  1294. ASSERT(FileObj != NULL);
  1295. TRC_DBG((TB, "Copying data for Query Directory"));
  1296. if (cbHaveData < cbWantData || Context->_DataCopied) {
  1297. if (FileObj->GetBufferSize() < CompletionPacket->IoCompletion.Parameters.QueryDir.Length) {
  1298. if (!FileObj->AllocateBuffer(CompletionPacket->IoCompletion.Parameters.QueryDir.Length)) {
  1299. CompleteBusyExchange(Exchange, STATUS_INSUFFICIENT_RESOURCES, 0);
  1300. *DoDefaultRead = FALSE;
  1301. return STATUS_INSUFFICIENT_RESOURCES;
  1302. }
  1303. }
  1304. RtlCopyMemory(FileObj->GetBuffer() + Context->_DataCopied, pData, cbHaveData);
  1305. //
  1306. // Keep track of how much data we've copied in case this is a
  1307. // multi chunk completion
  1308. //
  1309. Context->_DataCopied += cbHaveData;
  1310. }
  1311. }
  1312. if (cbHaveData == cbWantData) {
  1313. //
  1314. // There is exactly as much data as we need to satisfy the read,
  1315. // I like it.
  1316. //
  1317. if (RxContext != NULL) {
  1318. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  1319. SmartPtr<DrFile> FileObj = pFile;
  1320. FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
  1321. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  1322. PBYTE pBuffer;
  1323. ULONG BufferLength;
  1324. if (!Context->_DataCopied) {
  1325. pBuffer = (PBYTE) pData;
  1326. }
  1327. else {
  1328. pBuffer = FileObj->GetBuffer();
  1329. }
  1330. BufferLength = CompletionPacket->IoCompletion.Parameters.QueryDir.Length;
  1331. switch (FileInformationClass) {
  1332. case FileDirectoryInformation:
  1333. {
  1334. PFILE_DIRECTORY_INFORMATION pRxBuffer = (PFILE_DIRECTORY_INFORMATION)
  1335. (RxContext->Info.Buffer);
  1336. PRDP_FILE_DIRECTORY_INFORMATION pRetBuffer =
  1337. (PRDP_FILE_DIRECTORY_INFORMATION)pBuffer;
  1338. if (BufferLength >= FIELD_OFFSET(RDP_FILE_DIRECTORY_INFORMATION, FileName)) {
  1339. if (*pLengthRemaining >= FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName)) {
  1340. pRxBuffer->AllocationSize.QuadPart = pRetBuffer->AllocationSize.QuadPart;
  1341. pRxBuffer->ChangeTime.QuadPart = pRetBuffer->ChangeTime.QuadPart;
  1342. pRxBuffer->CreationTime.QuadPart = pRetBuffer->CreationTime.QuadPart;
  1343. pRxBuffer->EndOfFile.QuadPart = pRetBuffer->EndOfFile.QuadPart;
  1344. pRxBuffer->FileAttributes = pRetBuffer->FileAttributes;
  1345. pRxBuffer->FileIndex = pRetBuffer->FileIndex;
  1346. pRxBuffer->FileNameLength = pRetBuffer->FileNameLength;
  1347. pRxBuffer->LastAccessTime.QuadPart = pRetBuffer->LastAccessTime.QuadPart;
  1348. pRxBuffer->LastWriteTime.QuadPart = pRetBuffer->LastWriteTime.QuadPart;
  1349. pRxBuffer->NextEntryOffset = pRetBuffer->NextEntryOffset;
  1350. *pLengthRemaining -= (FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName));
  1351. if ((ULONG)*pLengthRemaining >= pRxBuffer->FileNameLength) {
  1352. if (BufferLength ==
  1353. FIELD_OFFSET(RDP_FILE_DIRECTORY_INFORMATION, FileName) +
  1354. pRxBuffer->FileNameLength) {
  1355. RtlCopyMemory(pRxBuffer->FileName, pRetBuffer->FileName,
  1356. pRxBuffer->FileNameLength);
  1357. *pLengthRemaining -= pRxBuffer->FileNameLength;
  1358. }
  1359. else {
  1360. TRC_ERR((TB, "Directory Information is invalid"));
  1361. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1362. *DoDefaultRead = TRUE;
  1363. return STATUS_DEVICE_PROTOCOL_ERROR;
  1364. }
  1365. }
  1366. else {
  1367. TRC_ERR((TB, "Directory Information, RxBuffer overflows"));
  1368. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1369. *DoDefaultRead = TRUE;
  1370. return STATUS_SUCCESS;
  1371. }
  1372. }
  1373. else {
  1374. TRC_ERR((TB, "Directory Information, RxBuffer overflows"));
  1375. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1376. *DoDefaultRead = TRUE;
  1377. return STATUS_SUCCESS;
  1378. }
  1379. }
  1380. else {
  1381. TRC_ERR((TB, "Directory Information, Bad data length"));
  1382. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1383. *DoDefaultRead = TRUE;
  1384. return STATUS_DEVICE_PROTOCOL_ERROR;
  1385. }
  1386. }
  1387. break;
  1388. case FileFullDirectoryInformation:
  1389. {
  1390. PFILE_FULL_DIR_INFORMATION pRxBuffer = (PFILE_FULL_DIR_INFORMATION)
  1391. (RxContext->Info.Buffer);
  1392. PRDP_FILE_FULL_DIR_INFORMATION pRetBuffer =
  1393. (PRDP_FILE_FULL_DIR_INFORMATION) pBuffer;
  1394. if (BufferLength >= FIELD_OFFSET(RDP_FILE_FULL_DIR_INFORMATION, FileName)) {
  1395. if (*pLengthRemaining >= FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName)) {
  1396. pRxBuffer->AllocationSize.QuadPart = pRetBuffer->AllocationSize.QuadPart;
  1397. pRxBuffer->ChangeTime.QuadPart = pRetBuffer->ChangeTime.QuadPart;
  1398. pRxBuffer->CreationTime.QuadPart = pRetBuffer->CreationTime.QuadPart;
  1399. pRxBuffer->EaSize = pRetBuffer->EaSize;
  1400. pRxBuffer->EndOfFile.QuadPart = pRetBuffer->EndOfFile.QuadPart;
  1401. pRxBuffer->FileAttributes = pRetBuffer->FileAttributes;
  1402. pRxBuffer->FileIndex = pRetBuffer->FileIndex;
  1403. pRxBuffer->FileNameLength = pRetBuffer->FileNameLength;
  1404. pRxBuffer->LastAccessTime.QuadPart = pRetBuffer->LastAccessTime.QuadPart;
  1405. pRxBuffer->LastWriteTime.QuadPart = pRetBuffer->LastWriteTime.QuadPart;
  1406. pRxBuffer->NextEntryOffset = pRetBuffer->NextEntryOffset;
  1407. *pLengthRemaining -= (FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileName));
  1408. if ((ULONG)*pLengthRemaining >= pRxBuffer->FileNameLength) {
  1409. if (BufferLength ==
  1410. FIELD_OFFSET(RDP_FILE_FULL_DIR_INFORMATION, FileName) +
  1411. pRxBuffer->FileNameLength) {
  1412. RtlCopyMemory(pRxBuffer->FileName, pRetBuffer->FileName,
  1413. pRxBuffer->FileNameLength);
  1414. *pLengthRemaining -= pRxBuffer->FileNameLength;
  1415. }
  1416. else {
  1417. TRC_ERR((TB, "Directory Full Information is invalid"));
  1418. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1419. *DoDefaultRead = TRUE;
  1420. return STATUS_DEVICE_PROTOCOL_ERROR;
  1421. }
  1422. }
  1423. else {
  1424. TRC_ERR((TB, "Directory Full Information, RxBuffer overflows"));
  1425. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1426. *DoDefaultRead = TRUE;
  1427. return STATUS_SUCCESS;
  1428. }
  1429. }
  1430. else {
  1431. TRC_ERR((TB, "Directory Full Information, RxBuffer overflows"));
  1432. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1433. *DoDefaultRead = TRUE;
  1434. return STATUS_SUCCESS;
  1435. }
  1436. }
  1437. else {
  1438. TRC_ERR((TB, "Directory Full Information, bad data length"));
  1439. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1440. *DoDefaultRead = TRUE;
  1441. return STATUS_DEVICE_PROTOCOL_ERROR;
  1442. }
  1443. }
  1444. break;
  1445. case FileBothDirectoryInformation:
  1446. {
  1447. PFILE_BOTH_DIR_INFORMATION pRxBuffer = (PFILE_BOTH_DIR_INFORMATION)
  1448. (RxContext->Info.Buffer);
  1449. PRDP_FILE_BOTH_DIR_INFORMATION pRetBuffer =
  1450. (PRDP_FILE_BOTH_DIR_INFORMATION) pBuffer;
  1451. if (BufferLength >= FIELD_OFFSET(RDP_FILE_BOTH_DIR_INFORMATION, FileName)) {
  1452. if (*pLengthRemaining >= FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName)) {
  1453. pRxBuffer->AllocationSize.QuadPart = pRetBuffer->AllocationSize.QuadPart;
  1454. pRxBuffer->ChangeTime.QuadPart = pRetBuffer->ChangeTime.QuadPart;
  1455. pRxBuffer->CreationTime.QuadPart = pRetBuffer->CreationTime.QuadPart;
  1456. pRxBuffer->EaSize = pRetBuffer->EaSize;
  1457. pRxBuffer->EndOfFile.QuadPart = pRetBuffer->EndOfFile.QuadPart;
  1458. pRxBuffer->FileAttributes = pRetBuffer->FileAttributes;
  1459. pRxBuffer->FileIndex = pRetBuffer->FileIndex;
  1460. pRxBuffer->FileNameLength = pRetBuffer->FileNameLength;
  1461. pRxBuffer->LastAccessTime.QuadPart = pRetBuffer->LastAccessTime.QuadPart;
  1462. pRxBuffer->LastWriteTime.QuadPart = pRetBuffer->LastWriteTime.QuadPart;
  1463. pRxBuffer->NextEntryOffset = pRetBuffer->NextEntryOffset;
  1464. pRxBuffer->ShortNameLength = pRetBuffer->ShortNameLength;
  1465. RtlCopyMemory(pRxBuffer->ShortName, pRetBuffer->ShortName,
  1466. sizeof(pRxBuffer->ShortName));
  1467. *pLengthRemaining -= (FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileName));
  1468. if ((ULONG)*pLengthRemaining >= pRxBuffer->FileNameLength) {
  1469. if ((BufferLength ==
  1470. FIELD_OFFSET(RDP_FILE_BOTH_DIR_INFORMATION, FileName) +
  1471. pRxBuffer->FileNameLength) &&
  1472. (pRxBuffer->ShortNameLength <= sizeof(pRxBuffer->ShortName))) {
  1473. RtlCopyMemory(pRxBuffer->FileName, pRetBuffer->FileName,
  1474. pRxBuffer->FileNameLength);
  1475. *pLengthRemaining -= pRxBuffer->FileNameLength;
  1476. }
  1477. else {
  1478. TRC_ERR((TB, "Directory Both Information is invalid"));
  1479. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1480. *DoDefaultRead = TRUE;
  1481. return STATUS_DEVICE_PROTOCOL_ERROR;
  1482. }
  1483. }
  1484. else {
  1485. TRC_ERR((TB, "Directory Both Information, RxBuffer overflows"));
  1486. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1487. *DoDefaultRead = TRUE;
  1488. return STATUS_SUCCESS;
  1489. }
  1490. }
  1491. else {
  1492. TRC_ERR((TB, "Directory Both Information, RxBuffer overflows"));
  1493. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1494. *DoDefaultRead = TRUE;
  1495. return STATUS_SUCCESS;
  1496. }
  1497. }
  1498. else {
  1499. TRC_ERR((TB, "Directory Both Information, bad data length"));
  1500. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1501. *DoDefaultRead = TRUE;
  1502. return STATUS_DEVICE_PROTOCOL_ERROR;
  1503. }
  1504. }
  1505. break;
  1506. case FileNamesInformation:
  1507. {
  1508. PFILE_NAMES_INFORMATION pRxBuffer = (PFILE_NAMES_INFORMATION)
  1509. (RxContext->Info.Buffer);
  1510. PRDP_FILE_NAMES_INFORMATION pRetBuffer =
  1511. (PRDP_FILE_NAMES_INFORMATION) pBuffer;
  1512. if (BufferLength >= FIELD_OFFSET(RDP_FILE_NAMES_INFORMATION, FileName)) {
  1513. if (*pLengthRemaining >= FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName)) {
  1514. pRxBuffer->FileIndex = pRetBuffer->FileIndex;
  1515. pRxBuffer->FileNameLength = pRetBuffer->FileNameLength;
  1516. pRxBuffer->NextEntryOffset = pRetBuffer->NextEntryOffset;
  1517. *pLengthRemaining -= (FIELD_OFFSET(FILE_NAMES_INFORMATION, FileName));
  1518. if ((ULONG)*pLengthRemaining >= pRxBuffer->FileNameLength) {
  1519. if (BufferLength ==
  1520. FIELD_OFFSET(RDP_FILE_NAMES_INFORMATION, FileName) +
  1521. pRxBuffer->FileNameLength) {
  1522. RtlCopyMemory(pRxBuffer->FileName, pRetBuffer->FileName,
  1523. pRxBuffer->FileNameLength);
  1524. *pLengthRemaining -= pRxBuffer->FileNameLength;
  1525. } else {
  1526. TRC_ERR((TB, "Directory Names Information is invalid"));
  1527. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1528. *DoDefaultRead = TRUE;
  1529. return STATUS_DEVICE_PROTOCOL_ERROR;
  1530. }
  1531. } else {
  1532. TRC_ERR((TB, "Directory Names Information, RxBuffer overflows"));
  1533. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1534. *DoDefaultRead = TRUE;
  1535. return STATUS_SUCCESS;
  1536. }
  1537. } else {
  1538. TRC_ERR((TB, "Directory Names Information, RxBuffer overflows"));
  1539. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1540. *DoDefaultRead = TRUE;
  1541. return STATUS_SUCCESS;
  1542. }
  1543. } else {
  1544. TRC_ERR((TB, "Directory Names Information, bad data length"));
  1545. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1546. *DoDefaultRead = TRUE;
  1547. return STATUS_DEVICE_PROTOCOL_ERROR;
  1548. }
  1549. }
  1550. break;
  1551. default:
  1552. TRC_ERR((TB, "Directory Information Class is invalid"));
  1553. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1554. *DoDefaultRead = TRUE;
  1555. return STATUS_DEVICE_PROTOCOL_ERROR;
  1556. }
  1557. CompleteBusyExchange(Exchange,
  1558. CompletionPacket->IoCompletion.IoStatus,
  1559. CompletionPacket->IoCompletion.Parameters.QueryDir.Length);
  1560. } else {
  1561. DiscardBusyExchange(Exchange);
  1562. }
  1563. //
  1564. // Go with a default channel read now
  1565. //
  1566. *DoDefaultRead = TRUE;
  1567. return STATUS_SUCCESS;
  1568. } else {
  1569. //
  1570. // We don't have all the data yet, release the DrExchange and
  1571. // read more data
  1572. //
  1573. MarkIdle(Exchange);
  1574. _Session->GetExchangeManager().ReadMore(
  1575. (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  1576. IoCompletion.Parameters.QueryDir.Buffer));
  1577. *DoDefaultRead = FALSE;
  1578. return STATUS_SUCCESS;
  1579. }
  1580. } else {
  1581. //
  1582. // Unsuccessful IO at the client end
  1583. //
  1584. TRC_DBG((TB, "Unsuccessful Read at the client end"));
  1585. if (cbPacket >= sizeof(RDPDR_IOCOMPLETION_PACKET)) {
  1586. if (RxContext != NULL) {
  1587. CompleteBusyExchange(Exchange,
  1588. CompletionPacket->IoCompletion.IoStatus,
  1589. 0);
  1590. }
  1591. else {
  1592. DiscardBusyExchange(Exchange);
  1593. }
  1594. *DoDefaultRead = TRUE;
  1595. return STATUS_SUCCESS;
  1596. } else {
  1597. TRC_ERR((TB, "Query directory returned invalid data "));
  1598. if (RxContext != NULL) {
  1599. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1600. } else {
  1601. DiscardBusyExchange(Exchange);
  1602. }
  1603. *DoDefaultRead = FALSE;
  1604. return STATUS_DEVICE_PROTOCOL_ERROR;
  1605. }
  1606. }
  1607. }
  1608. NTSTATUS DrDrive::OnNotifyChangeDirectoryCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  1609. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  1610. {
  1611. PRX_CONTEXT RxContext;
  1612. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  1613. BEGIN_FN("DrDrive::OnNotifyChangeDirectoryCompletion");
  1614. RxContext = Context->_RxContext;
  1615. if (RxContext != NULL) {
  1616. ASSERT(RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL);
  1617. TRC_NRM((TB, "Irp: %s, Completion Status: %lx",
  1618. IrpNames[RxContext->MajorFunction],
  1619. CompletionPacket->IoCompletion.IoStatus));
  1620. RxContext->InformationToReturn = 0;
  1621. RxContext->StoredStatus = CompletionPacket->IoCompletion.IoStatus;
  1622. CompleteBusyExchange(Exchange, CompletionPacket->IoCompletion.IoStatus, 0);
  1623. } else {
  1624. //
  1625. // Was cancelled but Context wasn't cleaned up
  1626. //
  1627. DiscardBusyExchange(Exchange);
  1628. }
  1629. return STATUS_SUCCESS;
  1630. }
  1631. NTSTATUS DrDrive::OnQueryVolumeInfoCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  1632. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  1633. {
  1634. PRX_CONTEXT RxContext;
  1635. PVOID pData = CompletionPacket->IoCompletion.Parameters.QueryVolume.Buffer;
  1636. ULONG cbWantData; // Amount of actual Read data in this packet
  1637. ULONG cbHaveData; // Amount of data available so far
  1638. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  1639. NTSTATUS Status;
  1640. BEGIN_FN("DrDrive::OnQueryVolumeInfoCompletion");
  1641. //
  1642. // Even if the IO was cancelled we need to correctly parse
  1643. // this data.
  1644. //
  1645. // Check to make sure this is up to size before accessing
  1646. // further portions of the packet
  1647. //
  1648. RxContext = Context->_RxContext;
  1649. if (cbPacket < (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  1650. IoCompletion.Parameters.QueryVolume.Buffer)) {
  1651. //
  1652. // Bad packet. Bad. We've already claimed the RxContext in the
  1653. // atlas. Complete it as unsuccessful. Then shutdown the channel
  1654. // as this is a Bad Client.
  1655. //
  1656. TRC_ERR((TB, "Detected bad client query volume packet"));
  1657. if (RxContext != NULL) {
  1658. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1659. } else {
  1660. DiscardBusyExchange(Exchange);
  1661. }
  1662. //
  1663. // No point in starting a default read or anything, what with the
  1664. // channel being shut down and all.
  1665. //
  1666. *DoDefaultRead = FALSE;
  1667. return STATUS_DEVICE_PROTOCOL_ERROR;
  1668. }
  1669. //
  1670. // Calculate how much data is available immediately and how much data
  1671. // is coming
  1672. //
  1673. if (NT_SUCCESS(CompletionPacket->IoCompletion.IoStatus)) {
  1674. //
  1675. // Successful IO at the client end
  1676. //
  1677. TRC_DBG((TB, "Successful Read at the client end"));
  1678. TRC_DBG((TB, "Read Length: 0x%d, DataCopied 0x%d",
  1679. CompletionPacket->IoCompletion.Parameters.QueryVolume.Length,
  1680. Context->_DataCopied));
  1681. cbWantData = CompletionPacket->IoCompletion.Parameters.QueryVolume.Length -
  1682. Context->_DataCopied;
  1683. cbHaveData = cbPacket - (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  1684. IoCompletion.Parameters.QueryVolume.Buffer);
  1685. if (cbHaveData > cbWantData) {
  1686. //
  1687. // Sounds like a bad client to me
  1688. //
  1689. TRC_ERR((TB, "Query volume returned more data than "
  1690. "advertised cbHaveData 0x%d cbWantData 0x%d",
  1691. cbHaveData, cbWantData));
  1692. if (RxContext != NULL) {
  1693. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1694. } else {
  1695. DiscardBusyExchange(Exchange);
  1696. }
  1697. *DoDefaultRead = FALSE;
  1698. return STATUS_DEVICE_PROTOCOL_ERROR;
  1699. }
  1700. if (RxContext != NULL) { // And not drexchCancelled
  1701. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  1702. SmartPtr<DrFile> FileObj = pFile;
  1703. ASSERT(FileObj != NULL);
  1704. TRC_DBG((TB, "Copying data for Query Volume"));
  1705. if (cbHaveData < cbWantData || Context->_DataCopied) {
  1706. if (FileObj->GetBufferSize() < CompletionPacket->IoCompletion.Parameters.QueryVolume.Length) {
  1707. if (!FileObj->AllocateBuffer(CompletionPacket->IoCompletion.Parameters.QueryVolume.Length)) {
  1708. CompleteBusyExchange(Exchange, STATUS_INSUFFICIENT_RESOURCES, 0);
  1709. *DoDefaultRead = FALSE;
  1710. return STATUS_INSUFFICIENT_RESOURCES;
  1711. }
  1712. }
  1713. RtlCopyMemory(FileObj->GetBuffer() + Context->_DataCopied, pData, cbHaveData);
  1714. //
  1715. // Keep track of how much data we've copied in case this is a
  1716. // multi chunk completion
  1717. //
  1718. Context->_DataCopied += cbHaveData;
  1719. }
  1720. }
  1721. if (cbHaveData == cbWantData) {
  1722. if (RxContext != NULL) {
  1723. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  1724. SmartPtr<DrFile> FileObj = pFile;
  1725. FS_INFORMATION_CLASS FsInformationClass = RxContext->Info.FsInformationClass;
  1726. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  1727. PBYTE pBuffer;
  1728. ULONG BufferLength;
  1729. //
  1730. // There is exactly as much data as we need to satisfy the read,
  1731. // I like it.
  1732. //
  1733. if (!Context->_DataCopied) {
  1734. pBuffer = (PBYTE) pData;
  1735. } else {
  1736. pBuffer = FileObj->GetBuffer();
  1737. }
  1738. BufferLength = CompletionPacket->IoCompletion.Parameters.QueryVolume.Length;
  1739. switch (FsInformationClass) {
  1740. case FileFsVolumeInformation:
  1741. {
  1742. PFILE_FS_VOLUME_INFORMATION pRxBuffer = (PFILE_FS_VOLUME_INFORMATION)
  1743. (RxContext->Info.Buffer);
  1744. PRDP_FILE_FS_VOLUME_INFORMATION pRetBuffer =
  1745. (PRDP_FILE_FS_VOLUME_INFORMATION) pBuffer;
  1746. if (BufferLength >= FIELD_OFFSET(RDP_FILE_FS_VOLUME_INFORMATION, VolumeLabel)) {
  1747. if (*pLengthRemaining >= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel)) {
  1748. pRxBuffer->SupportsObjects = pRetBuffer->SupportsObjects;
  1749. pRxBuffer->VolumeCreationTime.QuadPart = pRetBuffer->VolumeCreationTime.QuadPart;
  1750. pRxBuffer->VolumeSerialNumber = pRetBuffer->VolumeSerialNumber;
  1751. pRxBuffer->VolumeLabelLength = pRetBuffer->VolumeLabelLength;
  1752. *pLengthRemaining -= (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel));
  1753. if ((ULONG)*pLengthRemaining >= pRxBuffer->VolumeLabelLength) {
  1754. if (BufferLength ==
  1755. FIELD_OFFSET(RDP_FILE_FS_VOLUME_INFORMATION, VolumeLabel) +
  1756. pRxBuffer->VolumeLabelLength) {
  1757. RtlCopyMemory(pRxBuffer->VolumeLabel, pRetBuffer->VolumeLabel,
  1758. pRxBuffer->VolumeLabelLength);
  1759. *pLengthRemaining -= pRxBuffer->VolumeLabelLength;
  1760. } else {
  1761. TRC_ERR((TB, "Volume Information is invalid"));
  1762. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1763. *DoDefaultRead = TRUE;
  1764. return STATUS_DEVICE_PROTOCOL_ERROR;
  1765. }
  1766. } else {
  1767. TRC_NRM((TB, "Volume Information, RxBuffer overflows"));
  1768. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1769. *DoDefaultRead = TRUE;
  1770. return STATUS_SUCCESS;
  1771. }
  1772. } else {
  1773. TRC_ERR((TB, "Volume Information, RxBuffer overflows"));
  1774. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1775. *DoDefaultRead = TRUE;
  1776. return STATUS_SUCCESS;
  1777. }
  1778. } else {
  1779. TRC_ERR((TB, "Volume Information, bad data length"));
  1780. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1781. *DoDefaultRead = TRUE;
  1782. return STATUS_DEVICE_PROTOCOL_ERROR;
  1783. }
  1784. }
  1785. break;
  1786. case FileFsSizeInformation:
  1787. {
  1788. PFILE_FS_SIZE_INFORMATION pRxBuffer = (PFILE_FS_SIZE_INFORMATION)
  1789. (RxContext->Info.Buffer);
  1790. PRDP_FILE_FS_SIZE_INFORMATION pRetBuffer =
  1791. (PRDP_FILE_FS_SIZE_INFORMATION) pBuffer;
  1792. if (BufferLength == sizeof(RDP_FILE_FS_SIZE_INFORMATION)) {
  1793. if (*pLengthRemaining >= sizeof(FILE_FS_SIZE_INFORMATION)) {
  1794. pRxBuffer->AvailableAllocationUnits.QuadPart =
  1795. pRetBuffer->AvailableAllocationUnits.QuadPart;
  1796. pRxBuffer->BytesPerSector = pRetBuffer->BytesPerSector;
  1797. pRxBuffer->SectorsPerAllocationUnit = pRetBuffer->SectorsPerAllocationUnit;
  1798. pRxBuffer->TotalAllocationUnits.QuadPart =
  1799. pRetBuffer->TotalAllocationUnits.QuadPart;
  1800. *pLengthRemaining -= (sizeof(FILE_FS_SIZE_INFORMATION));
  1801. } else {
  1802. TRC_ERR((TB, "Volume Size Information, RxBuffer overflows"));
  1803. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1804. *DoDefaultRead = TRUE;
  1805. return STATUS_SUCCESS;
  1806. }
  1807. } else {
  1808. TRC_ERR((TB, "Volume Size Information, bad data length"));
  1809. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1810. *DoDefaultRead = TRUE;
  1811. return STATUS_DEVICE_PROTOCOL_ERROR;
  1812. }
  1813. }
  1814. break;
  1815. case FileFsFullSizeInformation:
  1816. {
  1817. PFILE_FS_FULL_SIZE_INFORMATION pRxBuffer = (PFILE_FS_FULL_SIZE_INFORMATION)
  1818. (RxContext->Info.Buffer);
  1819. PRDP_FILE_FS_FULL_SIZE_INFORMATION pRetBuffer =
  1820. (PRDP_FILE_FS_FULL_SIZE_INFORMATION) pBuffer;
  1821. if (BufferLength == sizeof(RDP_FILE_FS_FULL_SIZE_INFORMATION)) {
  1822. if (*pLengthRemaining >= sizeof(FILE_FS_FULL_SIZE_INFORMATION)) {
  1823. pRxBuffer->ActualAvailableAllocationUnits.QuadPart =
  1824. pRetBuffer->ActualAvailableAllocationUnits.QuadPart;
  1825. pRxBuffer->BytesPerSector = pRetBuffer->BytesPerSector;
  1826. pRxBuffer->SectorsPerAllocationUnit = pRetBuffer->SectorsPerAllocationUnit;
  1827. pRxBuffer->TotalAllocationUnits.QuadPart =
  1828. pRetBuffer->TotalAllocationUnits.QuadPart;
  1829. pRxBuffer->CallerAvailableAllocationUnits.QuadPart =
  1830. pRetBuffer->CallerAvailableAllocationUnits.QuadPart;
  1831. *pLengthRemaining -= (sizeof(FILE_FS_FULL_SIZE_INFORMATION));
  1832. } else {
  1833. TRC_ERR((TB, "Volume Size Information, RxBuffer overflows"));
  1834. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1835. *DoDefaultRead = TRUE;
  1836. return STATUS_SUCCESS;
  1837. }
  1838. } else {
  1839. TRC_ERR((TB, "Volume Size Information, bad data length"));
  1840. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1841. *DoDefaultRead = TRUE;
  1842. return STATUS_DEVICE_PROTOCOL_ERROR;
  1843. }
  1844. }
  1845. break;
  1846. case FileFsAttributeInformation:
  1847. {
  1848. PFILE_FS_ATTRIBUTE_INFORMATION pRxBuffer = (PFILE_FS_ATTRIBUTE_INFORMATION)
  1849. (RxContext->Info.Buffer);
  1850. PRDP_FILE_FS_ATTRIBUTE_INFORMATION pRetBuffer =
  1851. (PRDP_FILE_FS_ATTRIBUTE_INFORMATION) pBuffer;
  1852. if (BufferLength >= FIELD_OFFSET(RDP_FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName)) {
  1853. if (*pLengthRemaining >= FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName)) {
  1854. pRxBuffer->FileSystemAttributes = pRetBuffer->FileSystemAttributes;
  1855. pRxBuffer->MaximumComponentNameLength = pRetBuffer->MaximumComponentNameLength;
  1856. pRxBuffer->FileSystemNameLength = pRetBuffer->FileSystemNameLength;
  1857. *pLengthRemaining -= (FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName));
  1858. if ((ULONG)*pLengthRemaining >= pRxBuffer->FileSystemNameLength) {
  1859. if (BufferLength ==
  1860. FIELD_OFFSET(RDP_FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName) +
  1861. pRxBuffer->FileSystemNameLength) {
  1862. RtlCopyMemory(pRxBuffer->FileSystemName, pRetBuffer->FileSystemName,
  1863. pRxBuffer->FileSystemNameLength);
  1864. *pLengthRemaining -= pRxBuffer->FileSystemNameLength;
  1865. } else {
  1866. TRC_ERR((TB, "Volume Attributes Information is invalid"));
  1867. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1868. *DoDefaultRead = TRUE;
  1869. return STATUS_DEVICE_PROTOCOL_ERROR;
  1870. }
  1871. } else {
  1872. TRC_ERR((TB, "Volume Attributes Information, RxBuffer overflows"));
  1873. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1874. *DoDefaultRead = TRUE;
  1875. return STATUS_SUCCESS;
  1876. }
  1877. } else {
  1878. TRC_ERR((TB, "Volume Attributes Information, RxBuffer overflows"));
  1879. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  1880. *DoDefaultRead = TRUE;
  1881. return STATUS_SUCCESS;
  1882. }
  1883. } else {
  1884. TRC_ERR((TB, "Volume Attributes Information, bad data length"));
  1885. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1886. *DoDefaultRead = TRUE;
  1887. return STATUS_DEVICE_PROTOCOL_ERROR;
  1888. }
  1889. }
  1890. break;
  1891. default:
  1892. TRC_ERR((TB, "Volume Information Class is invalid"));
  1893. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1894. *DoDefaultRead = TRUE;
  1895. return STATUS_DEVICE_PROTOCOL_ERROR;
  1896. }
  1897. CompleteBusyExchange(Exchange,
  1898. CompletionPacket->IoCompletion.IoStatus,
  1899. CompletionPacket->IoCompletion.Parameters.QueryVolume.Length);
  1900. } else {
  1901. DiscardBusyExchange(Exchange);
  1902. }
  1903. //
  1904. // Go with a default channel read now
  1905. //
  1906. *DoDefaultRead = TRUE;
  1907. return STATUS_SUCCESS;
  1908. } else {
  1909. //
  1910. // We don't have all the data yet, release the DrExchange and
  1911. // read more data
  1912. //
  1913. MarkIdle(Exchange);
  1914. _Session->GetExchangeManager().ReadMore(
  1915. (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  1916. IoCompletion.Parameters.QueryVolume.Buffer));
  1917. *DoDefaultRead = FALSE;
  1918. return STATUS_SUCCESS;
  1919. }
  1920. } else {
  1921. //
  1922. // Unsuccessful IO at the client end
  1923. //
  1924. TRC_DBG((TB, "Unsuccessful Read at the client end"));
  1925. if (cbPacket >= sizeof(RDPDR_IOCOMPLETION_PACKET)) {
  1926. if (RxContext != NULL) {
  1927. CompleteBusyExchange(Exchange,
  1928. CompletionPacket->IoCompletion.IoStatus, 0);
  1929. }
  1930. else {
  1931. DiscardBusyExchange(Exchange);
  1932. }
  1933. *DoDefaultRead = TRUE;
  1934. return STATUS_SUCCESS;
  1935. } else {
  1936. TRC_ERR((TB, "Query volume returned invalid data "));
  1937. if (RxContext != NULL) {
  1938. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1939. } else {
  1940. DiscardBusyExchange(Exchange);
  1941. }
  1942. *DoDefaultRead = FALSE;
  1943. return STATUS_DEVICE_PROTOCOL_ERROR;
  1944. }
  1945. }
  1946. }
  1947. NTSTATUS DrDrive::OnSetVolumeInfoCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  1948. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  1949. {
  1950. PRX_CONTEXT RxContext;
  1951. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  1952. BEGIN_FN("DrDrive::OnSetVolumeInfoCompletion");
  1953. RxContext = Context->_RxContext;
  1954. if (RxContext != NULL) {
  1955. ASSERT(RxContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION);
  1956. TRC_NRM((TB, "Irp: %s, Completion Status: %lx",
  1957. IrpNames[RxContext->MajorFunction],
  1958. RxContext->IoStatusBlock.Status));
  1959. CompleteBusyExchange(Exchange, CompletionPacket->IoCompletion.IoStatus, 0);
  1960. } else {
  1961. //
  1962. // Was cancelled but Context wasn't cleaned up
  1963. //
  1964. DiscardBusyExchange(Exchange);
  1965. }
  1966. return STATUS_SUCCESS;
  1967. }
  1968. NTSTATUS DrDrive::OnQueryFileInfoCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  1969. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  1970. {
  1971. PRX_CONTEXT RxContext;
  1972. PVOID pData = CompletionPacket->IoCompletion.Parameters.QueryFile.Buffer;
  1973. ULONG cbWantData; // Amount of actual Read data in this packet
  1974. ULONG cbHaveData; // Amount of data available so far
  1975. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  1976. NTSTATUS Status;
  1977. BEGIN_FN("DrDrive::OnQueryFileInfoCompletion");
  1978. //
  1979. // Even if the IO was cancelled we need to correctly parse
  1980. // this data.
  1981. //
  1982. // Check to make sure this is up to size before accessing
  1983. // further portions of the packet
  1984. //
  1985. RxContext = Context->_RxContext;
  1986. if (cbPacket < (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  1987. IoCompletion.Parameters.QueryFile.Buffer)) {
  1988. //
  1989. // Bad packet. Bad. We've already claimed the RxContext in the
  1990. // atlas. Complete it as unsuccessful. Then shutdown the channel
  1991. // as this is a Bad Client.
  1992. //
  1993. TRC_ERR((TB, "Detected bad client read packet"));
  1994. if (RxContext != NULL) {
  1995. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  1996. } else {
  1997. DiscardBusyExchange(Exchange);
  1998. }
  1999. //
  2000. // No point in starting a default read or anything, what with the
  2001. // channel being shut down and all.
  2002. //
  2003. *DoDefaultRead = FALSE;
  2004. return STATUS_DEVICE_PROTOCOL_ERROR;
  2005. }
  2006. //
  2007. // Calculate how much data is available immediately and how much data
  2008. // is coming
  2009. //
  2010. if (NT_SUCCESS(CompletionPacket->IoCompletion.IoStatus)) {
  2011. //
  2012. // Successful IO at the client end
  2013. //
  2014. TRC_DBG((TB, "Successful Read at the client end"));
  2015. TRC_DBG((TB, "Read Length: 0x%d, DataCopied 0x%d",
  2016. CompletionPacket->IoCompletion.Parameters.QueryFile.Length,
  2017. Context->_DataCopied));
  2018. cbWantData = CompletionPacket->IoCompletion.Parameters.QueryFile.Length -
  2019. Context->_DataCopied;
  2020. cbHaveData = cbPacket - (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  2021. IoCompletion.Parameters.QueryFile.Buffer);
  2022. if (cbHaveData > cbWantData) {
  2023. //
  2024. // Sounds like a bad client to me
  2025. //
  2026. TRC_ERR((TB, "Query file returned more data than "
  2027. "advertised cbHaveData 0x%d cbWantData 0x%d",
  2028. cbHaveData, cbWantData));
  2029. if (RxContext != NULL) {
  2030. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2031. } else {
  2032. DiscardBusyExchange(Exchange);
  2033. }
  2034. *DoDefaultRead = FALSE;
  2035. return STATUS_DEVICE_PROTOCOL_ERROR;
  2036. }
  2037. if (RxContext != NULL) { // And not drexchCancelled
  2038. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  2039. SmartPtr<DrFile> FileObj = pFile;
  2040. ASSERT(FileObj != NULL);
  2041. TRC_DBG((TB, "Copying data for Query File"));
  2042. if (cbHaveData < cbWantData || Context->_DataCopied) {
  2043. if (FileObj->GetBufferSize() < CompletionPacket->IoCompletion.Parameters.QueryFile.Length) {
  2044. if (!FileObj->AllocateBuffer(CompletionPacket->IoCompletion.Parameters.QueryFile.Length)) {
  2045. CompleteBusyExchange(Exchange, STATUS_INSUFFICIENT_RESOURCES, 0);
  2046. *DoDefaultRead = FALSE;
  2047. return STATUS_INSUFFICIENT_RESOURCES;
  2048. }
  2049. }
  2050. RtlCopyMemory(FileObj->GetBuffer() + Context->_DataCopied, pData, cbHaveData);
  2051. //
  2052. // Keep track of how much data we've copied in case this is a
  2053. // multi chunk completion
  2054. //
  2055. Context->_DataCopied += cbHaveData;
  2056. }
  2057. }
  2058. if (cbHaveData == cbWantData) {
  2059. //
  2060. // There is exactly as much data as we need to satisfy the read,
  2061. // I like it.
  2062. //
  2063. if (RxContext != NULL) {
  2064. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  2065. SmartPtr<DrFile> FileObj = pFile;
  2066. FILE_INFORMATION_CLASS FileInformationClass = RxContext->Info.FileInformationClass;
  2067. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  2068. PBYTE pBuffer;
  2069. ULONG BufferLength;
  2070. if (!Context->_DataCopied) {
  2071. pBuffer = (PBYTE) pData;
  2072. }
  2073. else {
  2074. pBuffer = FileObj->GetBuffer();
  2075. }
  2076. BufferLength = CompletionPacket->IoCompletion.Parameters.QueryDir.Length;
  2077. switch (FileInformationClass) {
  2078. case FileBasicInformation:
  2079. {
  2080. PFILE_BASIC_INFORMATION pRxBuffer = (PFILE_BASIC_INFORMATION)
  2081. (RxContext->Info.Buffer);
  2082. PRDP_FILE_BASIC_INFORMATION pRetBuffer =
  2083. (PRDP_FILE_BASIC_INFORMATION) pBuffer;
  2084. if (BufferLength == sizeof(RDP_FILE_BASIC_INFORMATION)) {
  2085. if (*pLengthRemaining >= sizeof(FILE_BASIC_INFORMATION)) {
  2086. pRxBuffer->ChangeTime.QuadPart = pRetBuffer->ChangeTime.QuadPart;
  2087. pRxBuffer->CreationTime.QuadPart = pRetBuffer->CreationTime.QuadPart;
  2088. pRxBuffer->FileAttributes = pRetBuffer->FileAttributes;
  2089. pRxBuffer->LastAccessTime.QuadPart =
  2090. pRetBuffer->LastAccessTime.QuadPart;
  2091. pRxBuffer->LastWriteTime.QuadPart =
  2092. pRetBuffer->LastWriteTime.QuadPart;
  2093. *pLengthRemaining -= (sizeof(FILE_BASIC_INFORMATION));
  2094. } else {
  2095. TRC_ERR((TB, "File Basic Information, RxBuffer overflows"));
  2096. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  2097. *DoDefaultRead = TRUE;
  2098. return STATUS_SUCCESS;
  2099. }
  2100. } else {
  2101. TRC_ERR((TB, "File Basic Information, bad data length"));
  2102. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2103. *DoDefaultRead = TRUE;
  2104. return STATUS_DEVICE_PROTOCOL_ERROR;
  2105. }
  2106. }
  2107. break;
  2108. case FileStandardInformation:
  2109. {
  2110. PFILE_STANDARD_INFORMATION pRxBuffer = (PFILE_STANDARD_INFORMATION)
  2111. (RxContext->Info.Buffer);
  2112. PRDP_FILE_STANDARD_INFORMATION pRetBuffer =
  2113. (PRDP_FILE_STANDARD_INFORMATION) pBuffer;
  2114. if (BufferLength == sizeof(RDP_FILE_STANDARD_INFORMATION)) {
  2115. if (*pLengthRemaining >= sizeof(FILE_STANDARD_INFORMATION)) {
  2116. pRxBuffer->AllocationSize.QuadPart = pRetBuffer->AllocationSize.QuadPart;
  2117. pRxBuffer->DeletePending = pRetBuffer->DeletePending;
  2118. pRxBuffer->Directory = pRetBuffer->Directory;
  2119. pRxBuffer->EndOfFile.QuadPart =
  2120. pRetBuffer->EndOfFile.QuadPart;
  2121. pRxBuffer->NumberOfLinks = pRetBuffer->NumberOfLinks;
  2122. *pLengthRemaining -= (sizeof(FILE_STANDARD_INFORMATION));
  2123. } else {
  2124. TRC_ERR((TB, "File Standard Information, RxBuffer overflows"));
  2125. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  2126. *DoDefaultRead = TRUE;
  2127. return STATUS_SUCCESS;
  2128. }
  2129. } else {
  2130. TRC_ERR((TB, "File Standard Information, bad data length"));
  2131. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2132. *DoDefaultRead = TRUE;
  2133. return STATUS_DEVICE_PROTOCOL_ERROR;
  2134. }
  2135. }
  2136. break;
  2137. case FileAttributeTagInformation:
  2138. {
  2139. PFILE_ATTRIBUTE_TAG_INFORMATION pRxBuffer = (PFILE_ATTRIBUTE_TAG_INFORMATION)
  2140. (RxContext->Info.Buffer);
  2141. PRDP_FILE_ATTRIBUTE_TAG_INFORMATION pRetBuffer =
  2142. (PRDP_FILE_ATTRIBUTE_TAG_INFORMATION) pBuffer;
  2143. if (BufferLength == sizeof(RDP_FILE_ATTRIBUTE_TAG_INFORMATION)) {
  2144. if (*pLengthRemaining >= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) {
  2145. pRxBuffer->FileAttributes = pRetBuffer->FileAttributes;
  2146. pRxBuffer->ReparseTag = pRetBuffer->ReparseTag;
  2147. *pLengthRemaining -= (sizeof(FILE_ATTRIBUTE_TAG_INFORMATION));
  2148. } else {
  2149. TRC_ERR((TB, "File Attribute Tag Information, RxBuffer overflows"));
  2150. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, 0);
  2151. *DoDefaultRead = TRUE;
  2152. return STATUS_SUCCESS;
  2153. }
  2154. } else {
  2155. TRC_ERR((TB, "File Attribute Tag Information, bad data length"));
  2156. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2157. *DoDefaultRead = TRUE;
  2158. return STATUS_DEVICE_PROTOCOL_ERROR;
  2159. }
  2160. }
  2161. break;
  2162. default:
  2163. TRC_ERR((TB, "File Information Class is invalid"));
  2164. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2165. *DoDefaultRead = TRUE;
  2166. return STATUS_DEVICE_PROTOCOL_ERROR;
  2167. }
  2168. CompleteBusyExchange(Exchange,
  2169. CompletionPacket->IoCompletion.IoStatus,
  2170. CompletionPacket->IoCompletion.Parameters.QueryFile.Length);
  2171. } else {
  2172. DiscardBusyExchange(Exchange);
  2173. }
  2174. //
  2175. // Go with a default channel read now
  2176. //
  2177. *DoDefaultRead = TRUE;
  2178. return STATUS_SUCCESS;
  2179. } else {
  2180. //
  2181. // We don't have all the data yet, release the DrExchange and
  2182. // read more data
  2183. //
  2184. MarkIdle(Exchange);
  2185. _Session->GetExchangeManager().ReadMore(
  2186. (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  2187. IoCompletion.Parameters.QueryFile.Buffer));
  2188. *DoDefaultRead = FALSE;
  2189. return STATUS_SUCCESS;
  2190. }
  2191. } else {
  2192. //
  2193. // Unsuccessful IO at the client end
  2194. //
  2195. TRC_DBG((TB, "Unsuccessful Read at the client end"));
  2196. if (cbPacket >= sizeof(RDPDR_IOCOMPLETION_PACKET)) {
  2197. if (RxContext != NULL) {
  2198. CompleteBusyExchange(Exchange,
  2199. CompletionPacket->IoCompletion.IoStatus, 0);
  2200. }
  2201. else {
  2202. DiscardBusyExchange(Exchange);
  2203. }
  2204. *DoDefaultRead = TRUE;
  2205. return STATUS_SUCCESS;
  2206. } else {
  2207. TRC_ERR((TB, "Query file returned invalid data "));
  2208. if (RxContext != NULL) {
  2209. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2210. } else {
  2211. DiscardBusyExchange(Exchange);
  2212. }
  2213. *DoDefaultRead = FALSE;
  2214. return STATUS_DEVICE_PROTOCOL_ERROR;
  2215. }
  2216. }
  2217. }
  2218. NTSTATUS DrDrive::OnSetFileInfoCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  2219. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  2220. {
  2221. PRX_CONTEXT RxContext;
  2222. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  2223. BEGIN_FN("DrDrive::OnSetFileInfoCompletion");
  2224. RxContext = Context->_RxContext;
  2225. if (RxContext != NULL) {
  2226. ASSERT(RxContext->MajorFunction == IRP_MJ_SET_INFORMATION);
  2227. TRC_NRM((TB, "Irp: %s, Completion Status: %lx",
  2228. IrpNames[RxContext->MajorFunction],
  2229. RxContext->IoStatusBlock.Status));
  2230. CompleteBusyExchange(Exchange, CompletionPacket->IoCompletion.IoStatus, 0);
  2231. } else {
  2232. //
  2233. // Was cancelled but Context wasn't cleaned up
  2234. //
  2235. DiscardBusyExchange(Exchange);
  2236. }
  2237. return STATUS_SUCCESS;
  2238. }
  2239. NTSTATUS DrDrive::OnQuerySdInfoCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  2240. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  2241. {
  2242. PRX_CONTEXT RxContext;
  2243. PVOID pData = CompletionPacket->IoCompletion.Parameters.QuerySd.Buffer;
  2244. ULONG cbWantData; // Amount of actual Read data in this packet
  2245. ULONG cbHaveData; // Amount of data available so far
  2246. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  2247. NTSTATUS Status;
  2248. PVOID pv;
  2249. BEGIN_FN("DrDrive::OnQuerySdInfoCompletion");
  2250. //
  2251. // Even if the IO was cancelled we need to correctly parse
  2252. // this data.
  2253. //
  2254. // Check to make sure this is up to size before accessing
  2255. // further portions of the packet
  2256. //
  2257. RxContext = Context->_RxContext;
  2258. if (cbPacket < (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  2259. IoCompletion.Parameters.QuerySd.Buffer)) {
  2260. //
  2261. // Bad packet. Bad. We've already claimed the RxContext in the
  2262. // atlas. Complete it as unsuccessful. Then shutdown the channel
  2263. // as this is a Bad Client.
  2264. //
  2265. TRC_ERR((TB, "Detected bad client read packet"));
  2266. if (RxContext != NULL) {
  2267. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2268. } else {
  2269. DiscardBusyExchange(Exchange);
  2270. }
  2271. //
  2272. // No point in starting a default read or anything, what with the
  2273. // channel being shut down and all.
  2274. //
  2275. *DoDefaultRead = FALSE;
  2276. return STATUS_DEVICE_PROTOCOL_ERROR;
  2277. }
  2278. //
  2279. // Calculate how much data is available immediately and how much data
  2280. // is coming
  2281. //
  2282. if (NT_SUCCESS(CompletionPacket->IoCompletion.IoStatus)) {
  2283. //
  2284. // Successful IO at the client end
  2285. //
  2286. TRC_DBG((TB, "Successful Read at the client end"));
  2287. TRC_DBG((TB, "Read Length: 0x%d, DataCopied 0x%d",
  2288. CompletionPacket->IoCompletion.Parameters.QuerySd.Length,
  2289. Context->_DataCopied));
  2290. cbWantData = CompletionPacket->IoCompletion.Parameters.QuerySd.Length -
  2291. Context->_DataCopied;
  2292. cbHaveData = cbPacket - (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  2293. IoCompletion.Parameters.QuerySd.Buffer);
  2294. if (cbHaveData > cbWantData) {
  2295. //
  2296. // Sounds like a bad client to me
  2297. //
  2298. TRC_ERR((TB, "Read returned more data than "
  2299. "advertised cbHaveData 0x%d cbWantData 0x%d",
  2300. cbHaveData, cbWantData));
  2301. if (RxContext != NULL) {
  2302. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2303. } else {
  2304. DiscardBusyExchange(Exchange);
  2305. }
  2306. *DoDefaultRead = FALSE;
  2307. return STATUS_DEVICE_PROTOCOL_ERROR;
  2308. }
  2309. if (RxContext != NULL) { // And not drexchCancelled
  2310. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  2311. SmartPtr<DrFile> FileObj = pFile;
  2312. ASSERT(FileObj != NULL);
  2313. TRC_DBG((TB, "Copying data for Query File"));
  2314. if (cbHaveData < cbWantData || Context->_DataCopied) {
  2315. if (FileObj->GetBufferSize() < CompletionPacket->IoCompletion.Parameters.QueryFile.Length) {
  2316. if (!FileObj->AllocateBuffer(CompletionPacket->IoCompletion.Parameters.QueryFile.Length)) {
  2317. CompleteBusyExchange(Exchange, STATUS_INSUFFICIENT_RESOURCES, 0);
  2318. *DoDefaultRead = FALSE;
  2319. return STATUS_INSUFFICIENT_RESOURCES;
  2320. }
  2321. }
  2322. RtlCopyMemory(FileObj->GetBuffer() + Context->_DataCopied, pData, cbHaveData);
  2323. //
  2324. // Keep track of how much data we've copied in case this is a
  2325. // multi chunk completion
  2326. //
  2327. Context->_DataCopied += cbHaveData;
  2328. }
  2329. }
  2330. if (cbHaveData == cbWantData) {
  2331. //
  2332. // There is exactly as much data as we need to satisfy the read,
  2333. // I like it.
  2334. //
  2335. if (RxContext != NULL) {
  2336. DrFile *pFile = (DrFile *)RxContext->pFobx->Context2;
  2337. SmartPtr<DrFile> FileObj = pFile;
  2338. PBYTE pBuffer;
  2339. ULONG BufferLength = CompletionPacket->IoCompletion.Parameters.QuerySd.Length;
  2340. PBYTE RxBuffer = (PBYTE)(RxContext->Info.Buffer);
  2341. PLONG pLengthRemaining = &RxContext->Info.LengthRemaining;
  2342. if (!Context->_DataCopied) {
  2343. pBuffer = (PBYTE) pData;
  2344. }
  2345. else {
  2346. pBuffer = FileObj->GetBuffer();
  2347. }
  2348. PSECURITY_DESCRIPTOR SelfRelativeSd = (PSECURITY_DESCRIPTOR)pBuffer;
  2349. ULONG SdLength = RtlLengthSecurityDescriptor(SelfRelativeSd);
  2350. if (BufferLength == SdLength) {
  2351. if (*pLengthRemaining >= (LONG)SdLength) {
  2352. RtlCopyMemory(RxBuffer, SelfRelativeSd, SdLength);
  2353. *pLengthRemaining -= SdLength;
  2354. }
  2355. else {
  2356. TRC_ERR((TB, "File Security Information, RxBuffer overflows"));
  2357. RxContext->InformationToReturn = SdLength;
  2358. RxContext->StoredStatus = STATUS_BUFFER_OVERFLOW;
  2359. CompleteBusyExchange(Exchange, STATUS_BUFFER_OVERFLOW, SdLength);
  2360. *DoDefaultRead = TRUE;
  2361. return STATUS_SUCCESS;
  2362. }
  2363. }
  2364. else {
  2365. TRC_ERR((TB, "File Security Information, bad data length"));
  2366. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2367. *DoDefaultRead = TRUE;
  2368. return STATUS_DEVICE_PROTOCOL_ERROR;
  2369. }
  2370. CompleteBusyExchange(Exchange,
  2371. CompletionPacket->IoCompletion.IoStatus,
  2372. CompletionPacket->IoCompletion.Parameters.QuerySd.Length);
  2373. } else {
  2374. DiscardBusyExchange(Exchange);
  2375. }
  2376. //
  2377. // Go with a default channel read now
  2378. //
  2379. *DoDefaultRead = TRUE;
  2380. return STATUS_SUCCESS;
  2381. } else {
  2382. //
  2383. // We don't have all the data yet, release the DrExchange and
  2384. // read more data
  2385. //
  2386. MarkIdle(Exchange);
  2387. _Session->GetExchangeManager().ReadMore(
  2388. (ULONG)FIELD_OFFSET(RDPDR_IOCOMPLETION_PACKET,
  2389. IoCompletion.Parameters.QuerySd.Buffer));
  2390. *DoDefaultRead = FALSE;
  2391. return STATUS_SUCCESS;
  2392. }
  2393. } else {
  2394. //
  2395. // Unsuccessful IO at the client end
  2396. //
  2397. TRC_DBG((TB, "Unsuccessful Read at the client end"));
  2398. if (cbPacket >= sizeof(RDPDR_IOCOMPLETION_PACKET)) {
  2399. if (RxContext != NULL) {
  2400. CompleteBusyExchange(Exchange,
  2401. CompletionPacket->IoCompletion.IoStatus,
  2402. 0);
  2403. }
  2404. else {
  2405. DiscardBusyExchange(Exchange);
  2406. }
  2407. *DoDefaultRead = TRUE;
  2408. return STATUS_SUCCESS;
  2409. } else {
  2410. TRC_ERR((TB, "Read returned invalid data "));
  2411. if (RxContext != NULL) {
  2412. CompleteBusyExchange(Exchange, STATUS_DEVICE_PROTOCOL_ERROR, 0);
  2413. } else {
  2414. DiscardBusyExchange(Exchange);
  2415. }
  2416. *DoDefaultRead = FALSE;
  2417. return STATUS_DEVICE_PROTOCOL_ERROR;
  2418. }
  2419. }
  2420. }
  2421. NTSTATUS DrDrive::OnSetSdInfoCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  2422. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  2423. {
  2424. PRX_CONTEXT RxContext;
  2425. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  2426. BEGIN_FN("DrDrive::OnSetSdInfoCompletion");
  2427. RxContext = Context->_RxContext;
  2428. if (RxContext != NULL) {
  2429. ASSERT(RxContext->MajorFunction == IRP_MJ_SET_SECURITY);
  2430. TRC_NRM((TB, "Irp: %s, Completion Status: %lx",
  2431. IrpNames[RxContext->MajorFunction],
  2432. RxContext->IoStatusBlock.Status));
  2433. CompleteBusyExchange(Exchange, CompletionPacket->IoCompletion.IoStatus, 0);
  2434. } else {
  2435. //
  2436. // Was cancelled but Context wasn't cleaned up
  2437. //
  2438. DiscardBusyExchange(Exchange);
  2439. }
  2440. return STATUS_SUCCESS;
  2441. }
  2442. NTSTATUS DrDrive::OnLocksCompletion(PRDPDR_IOCOMPLETION_PACKET CompletionPacket, ULONG cbPacket,
  2443. BOOL *DoDefaultRead, SmartPtr<DrExchange> Exchange)
  2444. {
  2445. PRX_CONTEXT RxContext;
  2446. DrIoContext *Context = (DrIoContext *)Exchange->_Context;
  2447. BEGIN_FN("DrDrive::OnLocksCompletion");
  2448. RxContext = Context->_RxContext;
  2449. if (RxContext != NULL) {
  2450. ASSERT(RxContext->MajorFunction == IRP_MJ_LOCK_CONTROL);
  2451. TRC_NRM((TB, "Irp: %s, Completion Status: %lx",
  2452. IrpNames[RxContext->MajorFunction],
  2453. RxContext->IoStatusBlock.Status));
  2454. CompleteBusyExchange(Exchange, CompletionPacket->IoCompletion.IoStatus, 0);
  2455. } else {
  2456. //
  2457. // Was cancelled but Context wasn't cleaned up
  2458. //
  2459. DiscardBusyExchange(Exchange);
  2460. }
  2461. return STATUS_SUCCESS;
  2462. }