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.

2239 lines
78 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. davclose.c
  5. Abstract:
  6. This module implements the user mode DAV MiniRedir routines pertaining to
  7. closing of files.
  8. Author:
  9. Rohan Kumar [RohanK] 02-June-1999
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #pragma hdrstop
  14. #include "ntumrefl.h"
  15. #include "usrmddav.h"
  16. #include "global.h"
  17. #include "nodefac.h"
  18. #include "UniUtf.h"
  19. CHAR rgXmlHeader[] = "Content-Type: text/xml; charset=\"utf-8\"";
  20. CHAR rgPropPatchHeader[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><D:propertyupdate xmlns:D=\"DAV:\" xmlns:Z=\"urn:schemas-microsoft-com:\"><D:set><D:prop>";
  21. CHAR rgPropPatchTrailer[] = "</D:prop></D:set></D:propertyupdate>";
  22. CHAR rgCreationTimeTagHeader[] = "<Z:Win32CreationTime>";
  23. CHAR rgCreationTimeTagTrailer[] = "</Z:Win32CreationTime>";
  24. CHAR rgLastAccessTimeTagHeader[] = "<Z:Win32LastAccessTime>";
  25. CHAR rgLastAccessTimeTagTrailer[] = "</Z:Win32LastAccessTime>";
  26. CHAR rgLastModifiedTimeTagHeader[] = "<Z:Win32LastModifiedTime>";
  27. CHAR rgLastModifiedTimeTagTrailer[] = "</Z:Win32LastModifiedTime>";
  28. CHAR rgFileAttributesTagHeader[] = "<Z:Win32FileAttributes>";
  29. CHAR rgFileAttributesTagTrailer[] = "</Z:Win32FileAttributes>";
  30. CHAR rgDummyAttributes[] = "<Z:Dummy>0</Z:Dummy>";
  31. #define MAX_DWORD 0xffffffff
  32. //
  33. // These two functions are used in saving an encrypted file on the server.
  34. //
  35. DWORD
  36. DavReadRawCallback(
  37. PBYTE DataBuffer,
  38. PVOID CallbackContext,
  39. ULONG DataLength
  40. );
  41. BOOL
  42. DavConvertTimeToXml(
  43. IN PCHAR lpTagHeader,
  44. IN DWORD dwHeaderSize,
  45. IN PCHAR lpTagTrailer,
  46. IN DWORD dwTrailerSize,
  47. IN LARGE_INTEGER *lpTime,
  48. OUT PCHAR *lplpBuffer,
  49. IN OUT DWORD *lpdwBufferSize
  50. );
  51. DWORD
  52. DavSetProperties(
  53. PDAV_USERMODE_WORKITEM DavWorkItem,
  54. HINTERNET hDavConnect,
  55. LPWSTR lpPathName,
  56. LPSTR lpPropertiesBuffer
  57. );
  58. DWORD
  59. DavTestProppatch(
  60. PDAV_USERMODE_WORKITEM DavWorkItem,
  61. HINTERNET hDavConnect,
  62. LPWSTR lpPathName
  63. );
  64. extern DWORD
  65. DavSetAclForEncryptedFile(
  66. PWCHAR FilePath
  67. );
  68. //
  69. // Implementation of functions begins here.
  70. //
  71. ULONG
  72. DavFsClose(
  73. PDAV_USERMODE_WORKITEM DavWorkItem
  74. )
  75. /*++
  76. Routine Description:
  77. This routine handles DAV close request that get reflected from the kernel.
  78. Arguments:
  79. DavWorkItem - The buffer that contains the request parameters and options.
  80. Return Value:
  81. The return status for the operation
  82. --*/
  83. {
  84. ULONG WStatus = ERROR_SUCCESS;
  85. NTSTATUS NtStatus = STATUS_SUCCESS;
  86. PWCHAR ServerName = NULL, DirectoryPath = NULL, CanName = NULL;
  87. PWCHAR OpenVerb = NULL;
  88. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  89. BOOL EnCriSec = FALSE, ReturnVal, CallBackContextInitialized = FALSE, fSetDirectoryEntry = FALSE;
  90. PDAV_USERMODE_CLOSE_REQUEST CloseRequest = &(DavWorkItem->CloseRequest);
  91. ULONG ServerID;
  92. PPER_USER_ENTRY PerUserEntry = NULL;
  93. PHASH_SERVER_ENTRY ServerHashEntry = NULL;
  94. HINTERNET DavConnHandle = NULL, DavOpenHandle = NULL;
  95. PBYTE DataBuff = NULL;
  96. LARGE_INTEGER FileSize, ByteOffset;
  97. BY_HANDLE_FILE_INFORMATION FileInfo;
  98. IO_STATUS_BLOCK IoStatusBlock;
  99. HANDLE FileHandle = NULL;
  100. UNICODE_STRING UnicodeFileName;
  101. OBJECT_ATTRIBUTES ObjectAttributes;
  102. static UINT UniqueTempId = 1;
  103. BOOL didImpersonate = FALSE;
  104. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  105. BOOL BStatus = FALSE;
  106. DavPrint((DEBUG_MISC, "DavFsClose: FileName = %ws.\n", CloseRequest->FileName));
  107. DavPrint((DEBUG_MISC, "DavFsClose: Modified = %d.\n", CloseRequest->FileWasModified));
  108. UnicodeFileName.Buffer = NULL;
  109. UnicodeFileName.Length = 0;
  110. UnicodeFileName.MaximumLength = 0;
  111. //
  112. // If any of the time values have changed, then we need to PROPPATCH the
  113. // information back to the server.
  114. //
  115. if ( !CloseRequest->DeleteOnClose &&
  116. ( CloseRequest->fCreationTimeChanged ||
  117. CloseRequest->fLastAccessTimeChanged ||
  118. CloseRequest->fLastModifiedTimeChanged ||
  119. CloseRequest->fFileAttributesChanged ) ) {
  120. fSetDirectoryEntry = TRUE;
  121. }
  122. DavPrint((DEBUG_MISC, "DavFsClose: fSetDirectoryEntry = %x \n", fSetDirectoryEntry));
  123. if ( CloseRequest->isDirectory &&
  124. !CloseRequest->DeleteOnClose &&
  125. !fSetDirectoryEntry ) {
  126. //
  127. // If this is a directory close, then the only reason to contact the
  128. // server is when we are deleting the directory and all the files
  129. // under it. If not, we can return right now.
  130. //
  131. WStatus = ERROR_SUCCESS;
  132. goto EXIT_THE_FUNCTION;
  133. }
  134. if ( !CloseRequest->isDirectory ) {
  135. //
  136. // We need to close the handle only if it was created in the user mode.
  137. //
  138. if ( !CloseRequest->createdInKernel && CloseRequest->Handle ) {
  139. DavPrint((DEBUG_MISC, "DavFsClose: OpenHandle = %08lx.\n", CloseRequest->Handle));
  140. //
  141. // Close the handle that was opened during the Create call.
  142. //
  143. ASSERT((CloseRequest->UserModeKey) == ((PVOID)CloseRequest->Handle));
  144. ReturnVal = CloseHandle(CloseRequest->Handle);
  145. if (!ReturnVal) {
  146. WStatus = GetLastError();
  147. DavPrint((DEBUG_ERRORS,
  148. "DavFsClose/CloseHandle: Return Val = %08lx.\n", WStatus));
  149. } else {
  150. CloseRequest->UserModeKey = NULL;
  151. CloseRequest->Handle = INVALID_HANDLE_VALUE;
  152. }
  153. }
  154. //
  155. // DeleteOnClose FileCreatedLocally FileModified Action
  156. // ------------- ------------------ ------------ -------
  157. // 0 0 0 NOTHING
  158. // 0 0 1 PUT
  159. // 0 1 0 PUT
  160. // 0 1 1 PUT
  161. // 1 0 0 DELETE
  162. // 1 0 1 DELETE
  163. // 1 1 0 NOTHING
  164. // 1 1 1 NOTHING
  165. //
  166. // The FileCreatedLocally no longer matters since we PUT the file
  167. // immediately as soon as we create a local copy to claim the name on
  168. // the server.
  169. //
  170. //
  171. // If this file doesn't have to be deleted, was not created locally and
  172. // was not written to, or direntry not modified, or the file was not
  173. // LOCKed, then we are done.
  174. //
  175. if ( !(CloseRequest->DeleteOnClose) &&
  176. !(CloseRequest->FileWasModified) &&
  177. !(fSetDirectoryEntry) &&
  178. !(CloseRequest->OpaqueLockToken) ) {
  179. goto EXIT_THE_FUNCTION;
  180. }
  181. }
  182. //
  183. // In all other cases (or combinations of the above three booleans), we
  184. // need to go to the server. So, before we procced to decide what to do
  185. // on the server with this file, we need to set up the parameters for the
  186. // WinInet calls.
  187. //
  188. //
  189. // The first character is a '\' which has to be stripped.
  190. //
  191. ServerName = &(CloseRequest->ServerName[1]);
  192. if (!ServerName) {
  193. DavPrint((DEBUG_ERRORS, "DavFsClose: ServerName is NULL.\n"));
  194. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  195. goto EXIT_THE_FUNCTION;
  196. }
  197. DavPrint((DEBUG_MISC, "DavFsClose: ServerName = %ws.\n", ServerName));
  198. ServerID = CloseRequest->ServerID;
  199. DavPrint((DEBUG_MISC, "DavFsClose: ServerID = %d.\n", ServerID));
  200. //
  201. // The first character is a '\' which has to be stripped.
  202. //
  203. DirectoryPath = &(CloseRequest->PathName[1]);
  204. if (!DirectoryPath) {
  205. DavPrint((DEBUG_ERRORS, "DavFsClose: DirectoryPath is NULL.\n"));
  206. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  207. goto EXIT_THE_FUNCTION;
  208. }
  209. DavPrint((DEBUG_MISC, "DavFsClose: DirectoryPath = %ws.\n", DirectoryPath));
  210. //
  211. // The DirectoryPath can contain \ characters. Replace them by / characters.
  212. //
  213. CanName = DirectoryPath;
  214. while (*CanName) {
  215. if (*CanName == L'\\') {
  216. *CanName = L'/';
  217. }
  218. CanName++;
  219. }
  220. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  221. //
  222. // If we have a dummy share name in the DirectoryPath, we need to remove it
  223. // right now before we contact the server.
  224. //
  225. DavRemoveDummyShareFromFileName(DirectoryPath);
  226. //
  227. // We need to call this only if "DAV_USE_WININET_ASYNCHRONOUSLY" has been
  228. // defined. Otherwise, if we are using WinInet synchronously, then we
  229. // would have already done this in the DavWorkerThread function. This
  230. // ultimately gets deleted (the impersonation token that is) in the
  231. // DavAsyncCreateCompletion function.
  232. //
  233. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  234. //
  235. // Set the DavCallBackContext.
  236. //
  237. WStatus = DavFsSetTheDavCallBackContext(DavWorkItem);
  238. if (WStatus != ERROR_SUCCESS) {
  239. DavPrint((DEBUG_ERRORS,
  240. "DavFsClose/DavFsSetTheDavCallBackContext. "
  241. "Error Val = %d\n", WStatus));
  242. goto EXIT_THE_FUNCTION;
  243. }
  244. CallBackContextInitialized = TRUE;
  245. //
  246. // Store the address of the DavWorkItem which serves as a callback in the
  247. // variable CallBackContext. This will now be used in all the async calls
  248. // that follow.
  249. //
  250. CallBackContext = (ULONG_PTR)(DavWorkItem);
  251. #endif
  252. //
  253. // Allocate memory for the INTERNET_ASYNC_RESULT structure.
  254. //
  255. DavWorkItem->AsyncResult = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  256. sizeof(INTERNET_ASYNC_RESULT));
  257. if (DavWorkItem->AsyncResult == NULL) {
  258. WStatus = GetLastError();
  259. DavPrint((DEBUG_ERRORS, "DavFsClose/LocalAlloc. Error Val = %d\n",
  260. WStatus));
  261. goto EXIT_THE_FUNCTION;
  262. }
  263. //
  264. // A User Entry for this user must have been created during the create call
  265. // earlier. The user entry contains the handle used to send an HttpOpen
  266. // request.
  267. //
  268. EnterCriticalSection( &(HashServerEntryTableLock) );
  269. EnCriSec = TRUE;
  270. ReturnVal = DavDoesUserEntryExist(ServerName,
  271. ServerID,
  272. &(CloseRequest->LogonID),
  273. &PerUserEntry,
  274. &ServerHashEntry);
  275. //
  276. // If the following request in the kernel get cancelled even before the
  277. // corresponding usermode thread gets a chance to execute this code, then
  278. // it possible that the VNetRoot (hence the PerUserEntry) and SrvCall get
  279. // finalized before the thread that is handling the create comes here. This
  280. // could happen if this request was the only one for this share and the
  281. // server as well. This is why we need to check if the ServerHashEntry and
  282. // the PerUserEntry are valid before proceeding.
  283. //
  284. if (ReturnVal == FALSE || ServerHashEntry == NULL || PerUserEntry == NULL) {
  285. WStatus = ERROR_CANCELLED;
  286. DavPrint((DEBUG_ERRORS, "DavFsClose: (ServerHashEntry == NULL || PerUserEntry == NULL)\n"));
  287. goto EXIT_THE_FUNCTION;
  288. }
  289. DavWorkItem->AsyncClose.PerUserEntry = PerUserEntry;
  290. DavWorkItem->AsyncClose.ServerHashEntry = ServerHashEntry;
  291. //
  292. // Add a reference to the user entry.
  293. //
  294. PerUserEntry->UserEntryRefCount++;
  295. //
  296. // Since a create had succeeded earlier, the entry must be good.
  297. //
  298. ASSERT(PerUserEntry->UserEntryState == UserEntryInitialized);
  299. ASSERT(PerUserEntry->DavConnHandle != NULL);
  300. DavConnHandle = PerUserEntry->DavConnHandle;
  301. //
  302. // And yes, we obviously have to leave the critical section
  303. // before returning.
  304. //
  305. LeaveCriticalSection( &(HashServerEntryTableLock) );
  306. EnCriSec = FALSE;
  307. if ( !CloseRequest->isDirectory ) {
  308. //
  309. // If the file has to be deleted on close, we need to send a DELETE for
  310. // this file to the server. It does not matter if the file has been
  311. // modified or not.
  312. //
  313. if ( (CloseRequest->DeleteOnClose) ) {
  314. DavWorkItem->DavMinorOperation = DavMinorDeleteFile;
  315. OpenVerb = L"DELETE";
  316. DavWorkItem->AsyncClose.DataBuff = NULL;
  317. } else if (CloseRequest->FileWasModified) {
  318. //
  319. // The file has been changed and needs to be PUT on the server.
  320. //
  321. DavWorkItem->DavMinorOperation = DavMinorPutFile;
  322. OpenVerb = L"PUT";
  323. //
  324. // We need to check if this file is encrypted. If it is, we need to
  325. // BackUp the encrypted file to a temp file and send the BackedUp file
  326. // to the server.
  327. //
  328. if ( !( CloseRequest->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED ) ) {
  329. DavPrint((DEBUG_MISC, "DavFsClose. This is NOT an Encrypted file.\n"));
  330. //
  331. // Create an NT path name for the cached file. This is used in the
  332. // NtCreateFile call below.
  333. //
  334. ReturnVal = RtlDosPathNameToNtPathName_U(CloseRequest->FileName,
  335. &(UnicodeFileName),
  336. NULL,
  337. NULL);
  338. if (!ReturnVal) {
  339. WStatus = ERROR_BAD_PATHNAME;
  340. DavPrint((DEBUG_ERRORS,
  341. "DavFsClose/RtlDosPathNameToNtPathName. "
  342. "Error Val = %d\n", WStatus));
  343. goto EXIT_THE_FUNCTION;
  344. }
  345. InitializeObjectAttributes(&(ObjectAttributes),
  346. &(UnicodeFileName),
  347. OBJ_CASE_INSENSITIVE,
  348. 0,
  349. NULL);
  350. //
  351. // This #if 0 below was added because the NtCreateFile was failing
  352. // with ERROR_ACCESS_DENIED. This is because this file has been
  353. // created in the LocalService's %USERPROFILE% and you need to be
  354. // in the context of the LocalService before calling NtCreateFile.
  355. // By impersonating below we were getting into the context of the
  356. // user and hence the call failed.
  357. //
  358. #if 0
  359. //
  360. // We are running in the context of the Web Client service. Before
  361. // contacting the server below, we need to impersonate the client
  362. // that issued this request.
  363. //
  364. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  365. if (WStatus != ERROR_SUCCESS) {
  366. DavPrint((DEBUG_ERRORS,
  367. "DavFsClose/UMReflectorImpersonate(1). Error Val = %d\n",
  368. WStatus));
  369. goto EXIT_THE_FUNCTION;
  370. }
  371. didImpersonate = TRUE;
  372. #endif
  373. //
  374. // Create a handle to the local file, for reading its attributes and data.
  375. // We read the whole file into a buffer and send it across to the server.
  376. //
  377. NtStatus = NtCreateFile(&(FileHandle),
  378. (SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_READ_DATA),
  379. &(ObjectAttributes),
  380. &(IoStatusBlock),
  381. NULL,
  382. FILE_ATTRIBUTE_NORMAL,
  383. (FILE_SHARE_READ | FILE_SHARE_WRITE),
  384. FILE_OPEN,
  385. (FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT),
  386. NULL,
  387. 0);
  388. if (NtStatus != STATUS_SUCCESS) {
  389. //
  390. // We convert the NtStatus to DOS error here. The Win32
  391. // error code is finally set to an NTSTATUS value in
  392. // the DavFsCreate function just before returning.
  393. //
  394. WStatus = RtlNtStatusToDosError(NtStatus);
  395. FileHandle = NULL;
  396. DavPrint((DEBUG_ERRORS,
  397. "DavFsClose/NtCreateFile(1). Error Val = %08lx\n",
  398. NtStatus));
  399. goto EXIT_THE_FUNCTION;
  400. }
  401. ReturnVal = GetFileInformationByHandle(FileHandle, &(FileInfo));
  402. if (!ReturnVal) {
  403. WStatus = GetLastError();
  404. DavPrint((DEBUG_ERRORS,
  405. "DavFsClose/GetFileInformationByHandle: Return Val = %08lx.\n",
  406. WStatus));
  407. goto EXIT_THE_FUNCTION;
  408. }
  409. if (didImpersonate) {
  410. RevertToSelf();
  411. didImpersonate = FALSE;
  412. }
  413. FileSize.LowPart = FileInfo.nFileSizeLow;
  414. FileSize.HighPart = FileInfo.nFileSizeHigh;
  415. if ( FileSize.QuadPart > (LONGLONG)0 ) {
  416. DataBuff = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, FileSize.LowPart);
  417. if (DataBuff == NULL) {
  418. WStatus = GetLastError();
  419. DavPrint((DEBUG_ERRORS,
  420. "DavFsClose/LocalAlloc. Error Val = %d\n", WStatus));
  421. goto EXIT_THE_FUNCTION;
  422. }
  423. DavWorkItem->AsyncClose.DataBuff = DataBuff;
  424. //
  425. // Start reading at the first byte.
  426. //
  427. ByteOffset.LowPart = 0;
  428. ByteOffset.HighPart = 0;
  429. NtStatus = NtReadFile(FileHandle,
  430. NULL,
  431. NULL,
  432. NULL,
  433. &(IoStatusBlock),
  434. DataBuff,
  435. FileSize.LowPart,
  436. &(ByteOffset),
  437. NULL);
  438. if (NtStatus != STATUS_SUCCESS) {
  439. //
  440. // We convert the NtStatus to DOS error here. The Win32
  441. // error code is finally set to an NTSTATUS value in
  442. // the DavFsCreate function just before returning.
  443. //
  444. WStatus = RtlNtStatusToDosError(NtStatus);
  445. DavPrint((DEBUG_ERRORS,
  446. "DavFsClose/NtReadFile. Error Val = %08lx\n",
  447. NtStatus));
  448. goto EXIT_THE_FUNCTION;
  449. }
  450. DavWorkItem->AsyncClose.DataBuffSizeInBytes = FileSize.LowPart;
  451. NtStatus = NtClose(FileHandle);
  452. FileHandle = NULL;
  453. if (NtStatus != STATUS_SUCCESS) {
  454. //
  455. // We convert the NtStatus to DOS error here. The Win32
  456. // error code is finally set to an NTSTATUS value in
  457. // the DavFsCreate function just before returning.
  458. //
  459. WStatus = RtlNtStatusToDosError(NtStatus);
  460. DavPrint((DEBUG_ERRORS,
  461. "DavFsClose/NtClose. Error Val = %08lx\n",
  462. NtStatus));
  463. goto EXIT_THE_FUNCTION;
  464. }
  465. } else {
  466. DavPrint((DEBUG_MISC, "DavFsClose. Zero Byte File.\n"));
  467. DavWorkItem->AsyncClose.DataBuff = NULL;
  468. }
  469. } else {
  470. DWORD err;
  471. UINT tempErr;
  472. BOOL copyErr;
  473. PVOID RawContext = NULL;
  474. //
  475. // This is an encrypted file. Create a BackUp stream, store it into
  476. // a temp file and PUT the temp file (BLOB) on the server.
  477. //
  478. DavPrint((DEBUG_MISC, "DavFsClose. This is an Encrypted file.\n"));
  479. //
  480. // We loop till we can come up with a FileName in the TEMP directory
  481. // of the user which has not been used.
  482. //
  483. DavPrint((DEBUG_MISC,
  484. "DavFsClose: FileName = %ws\n", CloseRequest->FileName));
  485. //
  486. // If the file was opened as non-encrypted, the local cache file does not have
  487. // the ACL allowing everyone to access. Set the ACL here before impersonating.
  488. //
  489. WStatus = DavSetAclForEncryptedFile(CloseRequest->FileName);
  490. if (WStatus != ERROR_SUCCESS) {
  491. DavPrint((DEBUG_ERRORS,
  492. "DavAsyncClose/DavSetAclForEncryptedFile. Error Val"
  493. " = %d\n", WStatus));
  494. goto EXIT_THE_FUNCTION;
  495. }
  496. //
  497. // We are running in the context of the Web Client service. Before contacting
  498. // the server below, we need to impersonate the client that issued this
  499. // request.
  500. //
  501. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  502. if (WStatus != ERROR_SUCCESS) {
  503. DavPrint((DEBUG_ERRORS,
  504. "DavFsClose/UMReflectorImpersonate(2). Error Val = %d\n",
  505. WStatus));
  506. goto EXIT_THE_FUNCTION;
  507. }
  508. didImpersonate = TRUE;
  509. //
  510. // Open a Raw context to the file.
  511. //
  512. WStatus = OpenEncryptedFileRawW(CloseRequest->FileName, 0, &(RawContext));
  513. if (WStatus != ERROR_SUCCESS) {
  514. DavPrint((DEBUG_ERRORS,
  515. "DavFsClose/OpenEncryptedFileRaw. Error Val = %d %ws\n",
  516. WStatus,CloseRequest->FileName));
  517. goto EXIT_THE_FUNCTION;
  518. }
  519. //
  520. // The extra space prepared for the EFS stream.
  521. //
  522. DavWorkItem->AsyncClose.DataBuffAllocationSize = (CloseRequest->FileSize >> 4) + 0x1000;
  523. if (MAX_DWORD - CloseRequest->FileSize < DavWorkItem->AsyncClose.DataBuffAllocationSize) {
  524. WStatus = ERROR_NO_SYSTEM_RESOURCES;
  525. DavPrint((DEBUG_ERRORS,
  526. "DavFsClose/backup size exceeds MRX_DWORD!"));
  527. goto EXIT_THE_FUNCTION;
  528. }
  529. DavWorkItem->AsyncClose.DataBuffAllocationSize += CloseRequest->FileSize;
  530. DataBuff = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, DavWorkItem->AsyncClose.DataBuffAllocationSize);
  531. if (DataBuff == NULL) {
  532. WStatus = GetLastError();
  533. DavPrint((DEBUG_ERRORS,
  534. "DavFsClose/LocalAlloc. Error Val = %d\n", WStatus));
  535. if (RawContext) {
  536. CloseEncryptedFileRaw(RawContext);
  537. }
  538. goto EXIT_THE_FUNCTION;
  539. }
  540. DavWorkItem->AsyncClose.DataBuff = DataBuff;
  541. DavPrint((DEBUG_MISC,
  542. "DavFsClose: allocate backup buffer %x %x\n",DataBuff,DavWorkItem->AsyncClose.DataBuffAllocationSize));
  543. WStatus = ReadEncryptedFileRaw((PFE_EXPORT_FUNC)DavReadRawCallback,
  544. (PVOID)DavWorkItem,
  545. RawContext);
  546. if (RawContext) {
  547. CloseEncryptedFileRaw(RawContext);
  548. }
  549. if (WStatus != ERROR_SUCCESS) {
  550. DavPrint((DEBUG_ERRORS,
  551. "DavFsClose/ReadEncryptedFileRaw. Error Val = %d\n",
  552. WStatus));
  553. goto EXIT_THE_FUNCTION;
  554. }
  555. if (didImpersonate) {
  556. RevertToSelf();
  557. didImpersonate = FALSE;
  558. }
  559. }
  560. } else {
  561. ASSERT( (fSetDirectoryEntry == TRUE) || (CloseRequest->OpaqueLockToken != NULL) );
  562. //
  563. // If it is only an attribute change, we send the PROPPATCH. If the
  564. // file was LOCKed on Create, we send the UNLOCK request.
  565. //
  566. WStatus = ERROR_SUCCESS;
  567. goto EXIT_THE_FUNCTION;
  568. }
  569. } else {
  570. if (CloseRequest->DeleteOnClose) {
  571. //
  572. // This is a directory and needs to be deleted from the server.
  573. //
  574. DavWorkItem->DavMinorOperation = DavMinorDeleteFile;
  575. OpenVerb = L"DELETE";
  576. DavWorkItem->AsyncClose.DataBuff = NULL;
  577. } else if (fSetDirectoryEntry) {
  578. //
  579. // If this is a directory close, then the only reason to contact the
  580. // server is when we are deleting the directory and all the files
  581. // under it. If not, we can return right now.
  582. //
  583. WStatus = ERROR_SUCCESS;
  584. goto EXIT_THE_FUNCTION;
  585. }
  586. }
  587. //
  588. // We are running in the context of the Web Client service. Before contacting
  589. // the server below, we need to impersonate the client that issued this
  590. // request.
  591. //
  592. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  593. if (WStatus != ERROR_SUCCESS) {
  594. DavPrint((DEBUG_ERRORS,
  595. "DavFsClose/UMReflectorImpersonate(3). Error Val = %d\n",
  596. WStatus));
  597. goto EXIT_THE_FUNCTION;
  598. }
  599. didImpersonate = TRUE;
  600. //
  601. // We now call the DavHttpOpenRequest function.
  602. //
  603. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  604. //
  605. // Convert the unicode object name to UTF-8 URL format.
  606. // Space and other white characters will remain untouched - these should
  607. // be taken care of by wininet calls.
  608. //
  609. BStatus = DavHttpOpenRequestW(DavConnHandle,
  610. OpenVerb,
  611. DirectoryPath,
  612. L"HTTP/1.1",
  613. NULL,
  614. NULL,
  615. INTERNET_FLAG_KEEP_CONNECTION |
  616. INTERNET_FLAG_NO_COOKIES,
  617. CallBackContext,
  618. L"DavFsClose",
  619. &DavOpenHandle);
  620. if(BStatus == FALSE) {
  621. WStatus = GetLastError();
  622. goto EXIT_THE_FUNCTION;
  623. }
  624. if (DavOpenHandle == NULL) {
  625. WStatus = GetLastError();
  626. if (WStatus != ERROR_IO_PENDING) {
  627. DavPrint((DEBUG_ERRORS,
  628. "DavFsClose/DavHttpOpenRequestW. Error Val = %d\n",
  629. WStatus));
  630. }
  631. goto EXIT_THE_FUNCTION;
  632. }
  633. //
  634. // Cache the DavOpenHandle in the DavWorkItem.
  635. //
  636. DavWorkItem->AsyncClose.DavOpenHandle = DavOpenHandle;
  637. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  638. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  639. DavPrint((DEBUG_ERRORS,
  640. "DavFsClose/DavAsyncCommonStates. Error Val = %08lx\n",
  641. WStatus));
  642. }
  643. if (WStatus == ERROR_SUCCESS) {
  644. INTERNET_CACHE_ENTRY_INFOW CEI;
  645. CEI.LastAccessTime.dwLowDateTime = 0;
  646. CEI.LastAccessTime.dwHighDateTime = 0;
  647. SetUrlCacheEntryInfo(CloseRequest->Url,&CEI,CACHE_ENTRY_ACCTIME_FC);
  648. DavPrint((DEBUG_MISC,
  649. "DavFsClose Reset LastAccessTime for %ws\n",CloseRequest->Url));
  650. if (CloseRequest->FileWasModified &&
  651. (CloseRequest->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  652. //
  653. // Reset the LastModifiedTime on URL cache of the encrypted file
  654. // so that the public cache will be updated on the next GET.
  655. //
  656. CEI.LastModifiedTime.dwLowDateTime = 0;
  657. CEI.LastModifiedTime.dwHighDateTime = 0;
  658. SetUrlCacheEntryInfo(CloseRequest->Url,&CEI,CACHE_ENTRY_MODTIME_FC);
  659. DavPrint((DEBUG_MISC,
  660. "DavFsClose Reset LastModifiedTime %ws\n",CloseRequest->Url));
  661. }
  662. }
  663. EXIT_THE_FUNCTION:
  664. if (fSetDirectoryEntry && (WStatus == ERROR_SUCCESS)) {
  665. if (!didImpersonate) {
  666. //
  667. // If we are using WinInet synchronously, then we need to impersonate the
  668. // clients context now. This is becuase the DavSetProperties call below
  669. // contacts the DAV Server and we need to be impersonating the correct
  670. // client when contacting it.
  671. //
  672. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  673. if (WStatus != ERROR_SUCCESS) {
  674. DavPrint((DEBUG_ERRORS,
  675. "DavFsClose/UMReflectorImpersonate(4). Error Val = %d\n",
  676. WStatus));
  677. } else {
  678. didImpersonate = TRUE;
  679. }
  680. }
  681. if (WStatus == ERROR_SUCCESS) {
  682. DavWorkItem->DavMinorOperation = DavMinorProppatchFile;
  683. WStatus = DavSetBasicInformation(DavWorkItem,
  684. DavConnHandle,
  685. DirectoryPath,
  686. CloseRequest->fCreationTimeChanged,
  687. CloseRequest->fLastAccessTimeChanged,
  688. CloseRequest->fLastModifiedTimeChanged,
  689. CloseRequest->fFileAttributesChanged,
  690. &CloseRequest->CreationTime,
  691. &CloseRequest->LastAccessTime,
  692. &CloseRequest->LastModifiedTime,
  693. CloseRequest->dwFileAttributes);
  694. if (WStatus != ERROR_SUCCESS) {
  695. ULONG LogStatus;
  696. DavPrint((DEBUG_ERRORS,
  697. "DavFsClose/DavSetBasicInformation. WStatus = %d\n",
  698. WStatus));
  699. LogStatus = DavFormatAndLogError(DavWorkItem, WStatus);
  700. if (LogStatus != ERROR_SUCCESS) {
  701. DavPrint((DEBUG_ERRORS,
  702. "DavFsClose/DavFomatAndLogError. LogStatus = %d\n",
  703. LogStatus));
  704. }
  705. }
  706. DavPrint((DEBUG_MISC,
  707. "DavFsClose set BasicInformation(2). %d %x %ws\n",
  708. WStatus,CloseRequest->dwFileAttributes,DirectoryPath));
  709. //
  710. // If the PROPPATCH fails, we don't fail the close call. This is
  711. // because the PUT (if one was needed) has suceeded and we reset the
  712. // FileWasModified flag in the FCB based on whether this call succeeds.
  713. // On the final close, we check to see if this flag is set to FALSE
  714. // and pop up a box saying that the "delayed write failed". We
  715. // shouldn't be doing it if the PUT succeeds and the PROPPATCH fails.
  716. // We log an entry in the EventLog (under application) that the
  717. // PROPPATCH has failed though.
  718. //
  719. WStatus = ERROR_SUCCESS;
  720. }
  721. }
  722. //
  723. // If the file was LOCKed on the server on Create, we need to UnLock it
  724. // now. If the UNLOCK fails, we don't fail the close call. Also, we don't
  725. // need to UNLOCK the file if we have already deleted it.
  726. //
  727. if (CloseRequest->OpaqueLockToken && !CloseRequest->DeleteOnClose) {
  728. ULONG UnLockStatus;
  729. if (!didImpersonate) {
  730. //
  731. // If we are using WinInet synchronously, then we need to impersonate
  732. // the clients context now. This is becuase the DavUnLockFile call
  733. // below contacts the DAV Server and we need to be impersonating the
  734. // correct client when contacting it.
  735. //
  736. UnLockStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  737. if (UnLockStatus != ERROR_SUCCESS) {
  738. DavPrint((DEBUG_ERRORS,
  739. "DavFsClose/UMReflectorImpersonate(5). UnLockStatus = %d\n",
  740. UnLockStatus));
  741. } else {
  742. didImpersonate = TRUE;
  743. }
  744. }
  745. UnLockStatus = DavUnLockTheFileOnTheServer(DavWorkItem);
  746. if (UnLockStatus != ERROR_SUCCESS) {
  747. DavPrint((DEBUG_ERRORS,
  748. "DavFsClose/DavUnLockTheFileOnTheServer: UnLockStatus = %08lx\n",
  749. UnLockStatus));
  750. }
  751. }
  752. if (EnCriSec) {
  753. LeaveCriticalSection( &(HashServerEntryTableLock) );
  754. EnCriSec = FALSE;
  755. }
  756. //
  757. // The function RtlDosPathNameToNtPathName_U allocates memory from the
  758. // processes heap. If we did, we need to free it now.
  759. //
  760. if (UnicodeFileName.Buffer != NULL) {
  761. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeFileName.Buffer);
  762. }
  763. //
  764. // If we are using WinInet synchronously, then we should never get back
  765. // ERROR_IO_PENDING from WinInet.
  766. //
  767. ASSERT(WStatus != ERROR_IO_PENDING);
  768. //
  769. // If this thread impersonated a user, we need to revert back.
  770. //
  771. if (didImpersonate) {
  772. RevertToSelf();
  773. }
  774. if (FileHandle != NULL) {
  775. NtClose(FileHandle);
  776. FileHandle = NULL;
  777. }
  778. //
  779. // Set the return status of the operation. This is used by the kernel
  780. // mode routines to figure out the completion status of the user mode
  781. // request. This is done here because the async completion routine that is
  782. // called immediately afterwards needs the status set.
  783. //
  784. if (WStatus != ERROR_SUCCESS) {
  785. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  786. } else {
  787. DavWorkItem->Status = STATUS_SUCCESS;
  788. }
  789. DavAsyncCloseCompletion(DavWorkItem);
  790. return WStatus;
  791. }
  792. DWORD
  793. DavAsyncClose(
  794. PDAV_USERMODE_WORKITEM DavWorkItem,
  795. BOOLEAN CalledByCallBackThread
  796. )
  797. /*++
  798. Routine Description:
  799. This is the callback routine for the close operation.
  800. Arguments:
  801. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  802. CalledByCallbackThread - TRUE, if this function was called by the thread
  803. which picks of the DavWorkItem from the Callback
  804. function. This happens when an Async WinInet call
  805. returns ERROR_IO_PENDING and completes later.
  806. Return Value:
  807. ERROR_SUCCESS or the appropriate error value.
  808. --*/
  809. {
  810. ULONG WStatus = ERROR_SUCCESS;
  811. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem;
  812. BOOL didImpersonate = FALSE;
  813. HINTERNET DavOpenHandle = NULL;
  814. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  815. DavOpenHandle = DavWorkItem->AsyncClose.DavOpenHandle;
  816. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  817. if (CalledByCallBackThread) {
  818. //
  819. // We are running in the context of a worker thread which has different
  820. // credentials than the user that initiated the I/O request. Before
  821. // proceeding further, we should impersonate the user that initiated the
  822. // request.
  823. //
  824. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  825. if (WStatus != ERROR_SUCCESS) {
  826. DavPrint((DEBUG_ERRORS,
  827. "DavAsyncClose/UMReflectorImpersonate. Error Val = %d\n",
  828. WStatus));
  829. goto EXIT_THE_FUNCTION;
  830. }
  831. didImpersonate = TRUE;
  832. //
  833. // Before proceeding further, check to see if the Async operation failed.
  834. // If it did, then cleanup and move on.
  835. //
  836. if ( !DavWorkItem->AsyncResult->dwResult ) {
  837. WStatus = DavWorkItem->AsyncResult->dwError;
  838. //
  839. // If the error we got back is ERROR_INTERNET_FORCE_RETRY, then
  840. // WinInet is trying to authenticate itself with the server. In
  841. // such a scenario this is what happens.
  842. //
  843. // Client ----Request-----> Server
  844. // Server ----AccessDenied-----> Client
  845. // Client----Challenge Me-------> Server
  846. // Server-----Challenge--------> Client
  847. // Client-----Challenge Resp----> Server
  848. //
  849. if (WStatus == ERROR_INTERNET_FORCE_RETRY) {
  850. ASSERT(DavWorkItem->DavOperation == DAV_CALLBACK_HTTP_END);
  851. //
  852. // We need to repeat the HttpSend and HttpEnd request calls.
  853. //
  854. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  855. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  856. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  857. DavPrint((DEBUG_ERRORS,
  858. "DavAsyncClose/DavAsyncCommonStates. Error Val ="
  859. " %08lx\n", WStatus));
  860. }
  861. } else {
  862. DavPrint((DEBUG_ERRORS,
  863. "DavAsyncClose. AsyncFunction failed. Error Val = %d\n",
  864. WStatus));
  865. }
  866. goto EXIT_THE_FUNCTION;
  867. }
  868. }
  869. #else
  870. ASSERT(CalledByCallBackThread == FALSE);
  871. #endif
  872. //
  873. // We return what ever the response code from the Http server was for this
  874. // request.
  875. //
  876. WStatus = DavQueryAndParseResponse(DavOpenHandle);
  877. if (WStatus != ERROR_SUCCESS) {
  878. ULONG LogStatus;
  879. LogStatus = DavFormatAndLogError(DavWorkItem, WStatus);
  880. if (LogStatus != ERROR_SUCCESS) {
  881. DavPrint((DEBUG_ERRORS,
  882. "DavAsyncClose/DavFormatAndLogError. LogStatus = %d\n",
  883. LogStatus));
  884. }
  885. }
  886. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  887. EXIT_THE_FUNCTION:
  888. #endif
  889. //
  890. // If we did impersonate, we need to revert back.
  891. //
  892. if (didImpersonate) {
  893. ULONG RStatus;
  894. RStatus = UMReflectorRevert(UserWorkItem);
  895. if (RStatus != ERROR_SUCCESS) {
  896. DavPrint((DEBUG_ERRORS,
  897. "DavAsyncClose/UMReflectorRevert. Error Val = %d\n",
  898. RStatus));
  899. }
  900. }
  901. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  902. //
  903. // Some resources should not be freed if we are returning ERROR_IO_PENDING
  904. // because they will be used in the callback functions.
  905. //
  906. if ( WStatus != ERROR_IO_PENDING && CalledByCallBackThread ) {
  907. //
  908. // Set the return status of the operation. This is used by the kernel
  909. // mode routines to figure out the completion status of the user mode
  910. // request.
  911. //
  912. if (WStatus != ERROR_SUCCESS) {
  913. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  914. } else {
  915. DavWorkItem->Status = STATUS_SUCCESS;
  916. }
  917. //
  918. // Call the DavAsyncCloseCompletion routine.
  919. //
  920. DavAsyncCloseCompletion(DavWorkItem);
  921. //
  922. // This thread now needs to send the response back to the kernel. It
  923. // does not wait in the kernel (to get another request) after submitting
  924. // the response.
  925. //
  926. UMReflectorCompleteRequest(DavReflectorHandle, UserWorkItem);
  927. } else {
  928. DavPrint((DEBUG_MISC, "DavAsyncClose: Returning ERROR_IO_PENDING.\n"));
  929. }
  930. #endif
  931. return WStatus;
  932. }
  933. VOID
  934. DavAsyncCloseCompletion(
  935. PDAV_USERMODE_WORKITEM DavWorkItem
  936. )
  937. /*++
  938. Routine Description:
  939. This routine handles the Async Close completion. It basically frees up
  940. the resources allocated during the Async Close operation.
  941. Arguments:
  942. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  943. Return Value:
  944. none.
  945. --*/
  946. {
  947. if (DavWorkItem->AsyncClose.DavOpenHandle != NULL) {
  948. BOOL ReturnVal;
  949. ULONG FreeStatus;
  950. HINTERNET DavOpenHandle = DavWorkItem->AsyncClose.DavOpenHandle;
  951. ReturnVal = InternetCloseHandle( DavOpenHandle );
  952. if (!ReturnVal) {
  953. FreeStatus = GetLastError();
  954. DavPrint((DEBUG_ERRORS,
  955. "DavAsyncCloseCompletion/InternetCloseHandle. "
  956. "Error Val = %d\n", FreeStatus));
  957. }
  958. }
  959. if (DavWorkItem->AsyncClose.DataBuff != NULL) {
  960. HLOCAL FreeHandle;
  961. ULONG FreeStatus;
  962. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncClose.DataBuff);
  963. if (FreeHandle != NULL) {
  964. FreeStatus = GetLastError();
  965. DavPrint((DEBUG_ERRORS,
  966. "DavAsyncCloseCompletion/LocalFree. Error Val = %d\n",
  967. FreeStatus));
  968. }
  969. }
  970. if (DavWorkItem->AsyncClose.InternetBuffers != NULL) {
  971. HLOCAL FreeHandle;
  972. ULONG FreeStatus;
  973. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncClose.InternetBuffers);
  974. if (FreeHandle != NULL) {
  975. FreeStatus = GetLastError();
  976. DavPrint((DEBUG_ERRORS,
  977. "DavAsyncCloseCompletion/LocalFree. Error Val = %d\n",
  978. FreeStatus));
  979. }
  980. }
  981. if (DavWorkItem->AsyncResult != NULL) {
  982. HLOCAL FreeHandle;
  983. ULONG FreeStatus;
  984. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncResult);
  985. if (FreeHandle != NULL) {
  986. FreeStatus = GetLastError();
  987. DavPrint((DEBUG_ERRORS,
  988. "DavAsyncCloseCompletion/LocalFree. Error Val = %d\n",
  989. FreeStatus));
  990. }
  991. }
  992. DavFsFinalizeTheDavCallBackContext(DavWorkItem);
  993. //
  994. // We are done with the per user entry, so finalize it.
  995. //
  996. if (DavWorkItem->AsyncClose.PerUserEntry) {
  997. DavFinalizePerUserEntry( &(DavWorkItem->AsyncClose.PerUserEntry) );
  998. }
  999. return;
  1000. }
  1001. DWORD
  1002. DavReadRawCallback(
  1003. PBYTE DataBuffer,
  1004. PVOID CallbackContext,
  1005. ULONG DataLength
  1006. )
  1007. /*++
  1008. Routine Description:
  1009. Call-back function for ReadEncryptedFileRaw(). This function allocate a buffer for
  1010. async close and writes back the data to this buffer specified on because
  1011. ReadEncryptedFileRaw() provides the raw data to this callback function
  1012. which in turn stores it in a backup file. This call-back function is called
  1013. until there is no more data left.
  1014. Arguments:
  1015. DataBuffer - Data to be written.
  1016. CallbackContext - Handle to the Backup file.
  1017. DataLength - Size of the DataBuffer.
  1018. Return Value:
  1019. ERROR_SUCCESS or Win32 Error Code.
  1020. --*/
  1021. {
  1022. DWORD WStatus = ERROR_SUCCESS;
  1023. DWORD BytesWritten = 0;
  1024. BOOL ReturnVal;
  1025. PBYTE PreviousBuffer = NULL;
  1026. ULONG PreviousDataLength = 0;
  1027. PDAV_USERMODE_WORKITEM DavWorkItem = (PDAV_USERMODE_WORKITEM)CallbackContext;
  1028. DavPrint((DEBUG_MISC, "DavReadRawCallback: DataLength = %d\n", DataLength));
  1029. if ( !DataLength ) {
  1030. return WStatus;
  1031. }
  1032. ASSERT(DavWorkItem->AsyncClose.DataBuff != NULL);
  1033. PreviousDataLength = DavWorkItem->AsyncClose.DataBuffSizeInBytes;
  1034. //
  1035. // If the backup size exceeds the pre-allocation size, we have to allocate a bigger buffer.
  1036. //
  1037. if (PreviousDataLength + DataLength > DavWorkItem->AsyncClose.DataBuffAllocationSize) {
  1038. if ((MAX_DWORD - PreviousDataLength < DataLength) ||
  1039. (MAX_DWORD - PreviousDataLength - DataLength < 0x10000)) {
  1040. WStatus = ERROR_NO_SYSTEM_RESOURCES;
  1041. DavPrint((DEBUG_ERRORS,
  1042. "DavReadRawCallback/backup size exceeds MRX_DWORD!"));
  1043. goto EXIT_THE_FUNCTION;
  1044. }
  1045. PreviousBuffer = DavWorkItem->AsyncClose.DataBuff;
  1046. DavWorkItem->AsyncClose.DataBuffAllocationSize = DataLength+PreviousDataLength+0x10000;
  1047. DavWorkItem->AsyncClose.DataBuff = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, DavWorkItem->AsyncClose.DataBuffAllocationSize);
  1048. if (DavWorkItem->AsyncClose.DataBuff == NULL) {
  1049. WStatus = GetLastError();
  1050. DavPrint((DEBUG_ERRORS,
  1051. "DavReadRawCallback/LocalAlloc. Error Val = %d\n", WStatus));
  1052. goto EXIT_THE_FUNCTION;
  1053. }
  1054. RtlCopyMemory(DavWorkItem->AsyncClose.DataBuff,
  1055. PreviousBuffer,
  1056. PreviousDataLength);
  1057. DavPrint((DEBUG_MISC,
  1058. "DavReadRawCallback: allocate a bigger buffer %x %x\n",
  1059. DavWorkItem->AsyncClose.DataBuff,
  1060. DavWorkItem->AsyncClose.DataBuffAllocationSize));
  1061. }
  1062. RtlCopyMemory((PBYTE)(DavWorkItem->AsyncClose.DataBuff + PreviousDataLength),
  1063. DataBuffer,
  1064. DataLength);
  1065. DavWorkItem->AsyncClose.DataBuffSizeInBytes += DataLength;
  1066. DavPrint((DEBUG_MISC, "DavReadRawCallback: Buffer %x DataLength %d\n",
  1067. DavWorkItem->AsyncClose.DataBuff,DavWorkItem->AsyncClose.DataBuffSizeInBytes));
  1068. EXIT_THE_FUNCTION:
  1069. if (PreviousBuffer) {
  1070. LocalFree(PreviousBuffer);
  1071. }
  1072. return WStatus;
  1073. }
  1074. DWORD
  1075. DavSetBasicInformation(
  1076. PDAV_USERMODE_WORKITEM DavWorkItem,
  1077. HINTERNET hDavConnect,
  1078. LPWSTR PathName,
  1079. BOOL fCreationTimeChanged,
  1080. BOOL fLastAccessTimeChanged,
  1081. BOOL fLastModifiedTimeChanged,
  1082. BOOL fFileAttributesChanged,
  1083. IN LARGE_INTEGER *lpCreationTime,
  1084. IN LARGE_INTEGER *lpLastAccessTime,
  1085. IN LARGE_INTEGER *lpLastModifiedTime,
  1086. DWORD dwFileAttributes
  1087. )
  1088. /*++
  1089. Routine Description:
  1090. This routine sets DAV properties on a file or a directory. It formats an XML requests and sends it
  1091. to the server.
  1092. Arguments:
  1093. DavConnectHandle - Server connection.
  1094. CloseRequest - Usemode close request corresponding to the kernelmode close.
  1095. Return Value:
  1096. ERROR_SUCCESS or Win32 Error Code.
  1097. --*/
  1098. {
  1099. CHAR *lpTemp = NULL, Buffer[1024];
  1100. DWORD dwError = ERROR_SUCCESS, dwSizeRemaining, dwTemp;
  1101. BOOL fRet = FALSE;
  1102. BOOL fInfoChange = TRUE;
  1103. DWORD dwOverrideAttribMask = (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_ENCRYPTED |
  1104. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
  1105. FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_READONLY |
  1106. FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY |
  1107. FILE_ATTRIBUTE_DIRECTORY);
  1108. fInfoChange = (fCreationTimeChanged | fLastAccessTimeChanged |
  1109. fLastModifiedTimeChanged | fFileAttributesChanged);
  1110. DavPrint((DEBUG_MISC, "DavSetBasicInformation: Attributes = %x %x\n", dwFileAttributes,fInfoChange));
  1111. //
  1112. // We do not proceed further since there is no information to change. Also,
  1113. // in this case we return SUCCESS back to the caller.
  1114. //
  1115. if(fInfoChange == FALSE) {
  1116. fRet = TRUE;
  1117. dwError = ERROR_SUCCESS;
  1118. goto bailout;
  1119. }
  1120. //
  1121. // If attributes have changed, then verify that the new attributes are in
  1122. // valid combination i.e. If either of following attributes is present:
  1123. // FILE_ATTRIBUTE_ARCHIVE, FILE_ATTRIBUTE_ENCRYPTED,
  1124. // FILE_ATTRIBUTE_HIDDEN, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
  1125. // FILE_ATTRIBUTE_OFFLINE, FILE_ATTRIBUTE_READONLY,
  1126. // FILE_ATTRIBUTE_SYSTEM, FILE_ATTRIBUTE_TEMPORARY, FILE_ATTRIBUTE_DIRECTORY
  1127. // and if FILE_ATTRIBUTE_NORMAL is present, then FILE_ATTRIBUTE_NORMAL
  1128. // should be filtered.
  1129. //
  1130. if (fFileAttributesChanged == TRUE && (dwOverrideAttribMask & dwFileAttributes)) {
  1131. dwFileAttributes &= ~FILE_ATTRIBUTE_NORMAL;
  1132. }
  1133. //
  1134. // If this is a directoy and the attributes being set include
  1135. // FILE_TEMPORARY_FILE then we return ERROR_INVALID_PARAMETER since a
  1136. // directory cannot have this attribute.
  1137. //
  1138. if ( (fFileAttributesChanged) &&
  1139. (dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  1140. (dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY) ) {
  1141. fRet = FALSE;
  1142. SetLastError(ERROR_INVALID_PARAMETER);
  1143. goto bailout;
  1144. }
  1145. dwSizeRemaining = sizeof(rgPropPatchHeader) + sizeof(rgPropPatchTrailer) + 8 +
  1146. ((fCreationTimeChanged)?(INTERNET_RFC1123_BUFSIZE+
  1147. sizeof(rgCreationTimeTagHeader)+
  1148. sizeof(rgCreationTimeTagTrailer)):0)+
  1149. ((fLastAccessTimeChanged)?(INTERNET_RFC1123_BUFSIZE+
  1150. sizeof(rgLastAccessTimeTagHeader)+
  1151. sizeof(rgLastAccessTimeTagTrailer)):0)+
  1152. ((fLastModifiedTimeChanged)?(INTERNET_RFC1123_BUFSIZE+
  1153. sizeof(rgLastModifiedTimeTagHeader)+
  1154. sizeof(rgLastModifiedTimeTagTrailer)):0)+
  1155. ((fFileAttributesChanged)?(8+sizeof(rgFileAttributesTagHeader)+
  1156. sizeof(rgFileAttributesTagTrailer)):0);
  1157. if (dwSizeRemaining > sizeof(Buffer)) {
  1158. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1159. DavPrint((DEBUG_ERRORS, "DavSetBasicInformation: Insufficient buffer %d %d\n", dwSizeRemaining, sizeof(Buffer)));
  1160. }
  1161. memset(Buffer, 0, sizeof(Buffer));
  1162. dwSizeRemaining = sizeof(Buffer);
  1163. lpTemp = Buffer;
  1164. memcpy(lpTemp, rgPropPatchHeader, (sizeof(rgPropPatchHeader)-1));
  1165. lpTemp += (sizeof(rgPropPatchHeader)-1);
  1166. dwSizeRemaining -= (sizeof(rgPropPatchHeader)-1);
  1167. dwTemp = dwSizeRemaining;
  1168. if (fCreationTimeChanged) {
  1169. if (!DavConvertTimeToXml(rgCreationTimeTagHeader, (sizeof(rgCreationTimeTagHeader)-1),
  1170. rgCreationTimeTagTrailer, (sizeof(rgCreationTimeTagTrailer)-1),
  1171. lpCreationTime,
  1172. &lpTemp,
  1173. &dwTemp)) {
  1174. DavPrint((DEBUG_ERRORS, "DavSetBasicInformation: Failed to convert creationtime\n"));
  1175. goto bailout;
  1176. }
  1177. }
  1178. if (fLastAccessTimeChanged)
  1179. {
  1180. if (!DavConvertTimeToXml(rgLastAccessTimeTagHeader, (sizeof(rgLastAccessTimeTagHeader)-1),
  1181. rgLastAccessTimeTagTrailer, (sizeof(rgLastAccessTimeTagTrailer)-1),
  1182. lpLastAccessTime,
  1183. &lpTemp,
  1184. &dwTemp))
  1185. {
  1186. DavPrint((DEBUG_ERRORS, "DavSetBasicInformation: Failed to convert lastaccesstime\n"));
  1187. goto bailout;
  1188. }
  1189. }
  1190. if (fLastModifiedTimeChanged)
  1191. {
  1192. if (!DavConvertTimeToXml(rgLastModifiedTimeTagHeader, (sizeof(rgLastModifiedTimeTagHeader)-1),
  1193. rgLastModifiedTimeTagTrailer, (sizeof(rgLastModifiedTimeTagTrailer)-1),
  1194. lpLastModifiedTime,
  1195. &lpTemp,
  1196. &dwTemp))
  1197. {
  1198. DavPrint((DEBUG_ERRORS, "DavSetBasicInformation: Failed to convert lastmodifiedtime\n"));
  1199. goto bailout;
  1200. }
  1201. }
  1202. if (fFileAttributesChanged)
  1203. {
  1204. memcpy(lpTemp, rgFileAttributesTagHeader, sizeof(rgFileAttributesTagHeader)-1);
  1205. lpTemp += (sizeof(rgFileAttributesTagHeader)-1);
  1206. sprintf(lpTemp, "%8.8x", dwFileAttributes);
  1207. lpTemp += 8;
  1208. memcpy(lpTemp, rgFileAttributesTagTrailer, sizeof(rgFileAttributesTagTrailer)-1);
  1209. lpTemp += (sizeof(rgFileAttributesTagTrailer)-1);
  1210. }
  1211. memcpy(lpTemp, rgPropPatchTrailer, sizeof(rgPropPatchTrailer)-1);
  1212. dwError = DavSetProperties(DavWorkItem, hDavConnect, PathName, Buffer);
  1213. fRet = (dwError == ERROR_SUCCESS);
  1214. if (!fRet) {
  1215. DavPrint((DEBUG_ERRORS,
  1216. "DavSetBasicInformation/DavSetProperties: dwError = %d\n",
  1217. dwError));
  1218. SetLastError(dwError);
  1219. }
  1220. bailout:
  1221. if (!fRet) {
  1222. dwError = GetLastError();
  1223. DavPrint((DEBUG_ERRORS,
  1224. "DavSetBasicInformation: dwError = %x\n", GetLastError()));
  1225. }
  1226. return dwError;
  1227. }
  1228. BOOL
  1229. DavConvertTimeToXml(
  1230. IN PCHAR lpTagHeader,
  1231. IN DWORD dwHeaderSize,
  1232. IN PCHAR lpTagTrailer,
  1233. IN DWORD dwTrailerSize,
  1234. IN LARGE_INTEGER *lpTime,
  1235. OUT PCHAR *lplpBuffer,
  1236. IN OUT DWORD *lpdwBufferSize
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. Creates an xml piece for setting a time property. The format is
  1241. <TagHeader>TimeString in RFC 1123 format<TagTrailer>
  1242. Arguments:
  1243. lpTagHeader tag beginning e.g. <Z:Win32CreationTime>
  1244. dwHeaderSize size of the above header in bytes
  1245. lpTagTrailer tag end e.g. </Z:Win32CreationTime>
  1246. dwTrailerSize size of the trailer in bytes
  1247. lplpBuffer pointer to a buffer pointer. On successful return the pointer is moved ahead.
  1248. lpdwBufferSize contains the passed in buffersize. On successful return, this value
  1249. is reduced by the amount of space consumed in this routine.
  1250. Return Value:
  1251. ERROR_SUCCESS or Win32 Error Code. If the buffersize is not enough, the
  1252. error code is ERROR_INSUFFICIENT_BUFFER and lpdwBufferSize contains the
  1253. amount necessary to succeed.
  1254. --*/
  1255. {
  1256. SYSTEMTIME sSystemTime;
  1257. DWORD cbTimeSize;
  1258. CHAR chTimeBuff[INTERNET_RFC1123_BUFSIZE+4], *lpTemp;
  1259. if(!FileTimeToSystemTime((FILETIME *)lpTime, &sSystemTime))
  1260. {
  1261. return FALSE;
  1262. }
  1263. if(!InternetTimeFromSystemTimeA(&sSystemTime, INTERNET_RFC1123_FORMAT, chTimeBuff, sizeof(chTimeBuff)))
  1264. {
  1265. return FALSE;
  1266. }
  1267. cbTimeSize = strlen(chTimeBuff);
  1268. if (*lpdwBufferSize < (cbTimeSize + dwHeaderSize + dwTrailerSize))
  1269. {
  1270. *lpdwBufferSize = (cbTimeSize + dwHeaderSize + dwTrailerSize);
  1271. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1272. return FALSE;
  1273. }
  1274. // all is well, start copying
  1275. lpTemp = *lplpBuffer;
  1276. // header tag eg: <Z:Win32CreationTime>
  1277. memcpy(lpTemp, lpTagHeader, dwHeaderSize);
  1278. lpTemp += dwHeaderSize;
  1279. // Time in the RFC_1123 format
  1280. memcpy(lpTemp, chTimeBuff, cbTimeSize);
  1281. lpTemp += cbTimeSize;
  1282. // trailer tag eg: </Z:Win32CreationTime>
  1283. memcpy(lpTemp, lpTagTrailer, dwTrailerSize);
  1284. lpTemp += dwTrailerSize;
  1285. // adjust the remainign size and the pointers
  1286. *lpdwBufferSize -= (cbTimeSize + dwHeaderSize + dwTrailerSize);
  1287. *lplpBuffer = lpTemp;
  1288. return TRUE;
  1289. }
  1290. DWORD
  1291. DavParseXmlResponse(
  1292. HINTERNET DavOpenHandle,
  1293. DAV_FILE_ATTRIBUTES *pDavFileAttributesIn,
  1294. DWORD *pNumFileEntries
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. This routine parses the xml response. This is mainly useful for verbs which
  1299. may get back XML response.
  1300. Arguments:
  1301. DavOpenHandle - Handle obtained from HttpOpenRequest. A send is already
  1302. issued on this handle.
  1303. Return Value:
  1304. ERROR_SUCCESS or Win32 Error Code.
  1305. --*/
  1306. {
  1307. DWORD dwError = ERROR_SUCCESS;
  1308. BOOL ReturnVal, readDone;
  1309. PCHAR DataBuff = NULL;
  1310. DWORD NumRead = 0, NumOfFileEntries = 0, TotalDataBytesRead = 0;
  1311. PVOID Ctx1 = NULL, Ctx2 = NULL;
  1312. DAV_FILE_ATTRIBUTES DavFileAttributes, *pDavFileAttributesLocal = NULL;
  1313. DataBuff = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, NUM_OF_BYTES_TO_READ);
  1314. if (DataBuff == NULL) {
  1315. dwError = GetLastError();
  1316. DavPrint((DEBUG_ERRORS,
  1317. "DavParseXmlResponse/LocalAlloc: dwError = %08lx\n",
  1318. dwError));
  1319. goto EXIT_THE_FUNCTION;
  1320. }
  1321. //
  1322. // Read the response and parse it.
  1323. //
  1324. do {
  1325. ReturnVal = InternetReadFile(DavOpenHandle,
  1326. (LPVOID)DataBuff,
  1327. NUM_OF_BYTES_TO_READ,
  1328. &(NumRead));
  1329. if (!ReturnVal) {
  1330. dwError = GetLastError();
  1331. DavPrint((DEBUG_ERRORS,
  1332. "DavParseXmlResponse/InternetReadFile: dwError = "
  1333. "%08lx\n", dwError));
  1334. goto EXIT_THE_FUNCTION;
  1335. }
  1336. DavPrint((DEBUG_MISC, "DavParseXmlResponse: NumRead = %d\n", NumRead));
  1337. //
  1338. // We reject files whose attributes are greater than a certain size
  1339. // (DavFileAttributesLimitInBytes). This is a parameter that can be
  1340. // set in the registry. This is done to avoid attacks by rogue servers.
  1341. //
  1342. TotalDataBytesRead += NumRead;
  1343. if (TotalDataBytesRead > DavFileAttributesLimitInBytes) {
  1344. dwError = ERROR_BAD_NET_RESP;
  1345. DavPrint((DEBUG_ERRORS, "DavParseXmlResponse. FileAttributesSize > %d\n", DavFileAttributesLimitInBytes));
  1346. goto EXIT_THE_FUNCTION;
  1347. }
  1348. readDone = (NumRead == 0) ? TRUE : FALSE;
  1349. dwError = DavPushData(DataBuff, &Ctx1, &Ctx2, NumRead, readDone);
  1350. if (dwError != ERROR_SUCCESS) {
  1351. DavPrint((DEBUG_ERRORS,
  1352. "DavParseXmlResponse/DavPushData."
  1353. " Error Val = %d\n", dwError));
  1354. goto EXIT_THE_FUNCTION;
  1355. }
  1356. if (readDone) {
  1357. break;
  1358. }
  1359. } while ( TRUE );
  1360. if (Ctx2) {
  1361. if (pDavFileAttributesIn) {
  1362. pDavFileAttributesLocal = pDavFileAttributesIn;
  1363. } else {
  1364. pDavFileAttributesLocal = &DavFileAttributes;
  1365. }
  1366. memset(pDavFileAttributesLocal, 0, sizeof(DavFileAttributes));
  1367. InitializeListHead(&(pDavFileAttributesLocal->NextEntry));
  1368. dwError = DavParseData(pDavFileAttributesLocal, Ctx1, Ctx2, &NumOfFileEntries);
  1369. if (dwError != ERROR_SUCCESS) {
  1370. DavPrint((DEBUG_ERRORS,
  1371. "DavParseXmlResponse/DavParseData. "
  1372. "Error Val = %d\n", dwError));
  1373. DavFinalizeFileAttributesList(pDavFileAttributesLocal, FALSE);
  1374. goto EXIT_THE_FUNCTION;
  1375. }
  1376. if (!pDavFileAttributesIn){
  1377. DavFinalizeFileAttributesList(pDavFileAttributesLocal, FALSE);
  1378. }
  1379. DavCloseContext(Ctx1, Ctx2);
  1380. }
  1381. if (pNumFileEntries){
  1382. *pNumFileEntries = NumOfFileEntries;
  1383. }
  1384. dwError = ERROR_SUCCESS;
  1385. EXIT_THE_FUNCTION:
  1386. if (DataBuff) {
  1387. LocalFree(DataBuff);
  1388. DataBuff = NULL;
  1389. }
  1390. return dwError;
  1391. }
  1392. DWORD
  1393. DavSetProperties(
  1394. PDAV_USERMODE_WORKITEM DavWorkItem,
  1395. HINTERNET hDavConnect,
  1396. LPWSTR lpPathName,
  1397. LPSTR lpPropertiesBuffer
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. This routine sets DAV properties on a file or a directory. It formats an XML requests and sends it
  1402. to the server.
  1403. Arguments:
  1404. DavConnectHandle - Server connection.
  1405. CloseRequest - Usemode close request corresponding to the kernelmode close.
  1406. Return Value:
  1407. ERROR_SUCCESS or Win32 Error Code.
  1408. --*/
  1409. {
  1410. DWORD dwError = ERROR_SUCCESS;
  1411. HINTERNET hRequest = NULL;
  1412. BOOL BStatus = FALSE, ReturnVal = FALSE;
  1413. PWCHAR PassportCookie = NULL;
  1414. //
  1415. // Convert the unicode object name to UTF-8 URL format.
  1416. // Space and other white characters will remain untouched - these should
  1417. // be taken care of by wininet calls.
  1418. // This has to be a W API as the name in CloseRequest is unicode.
  1419. //
  1420. BStatus = DavHttpOpenRequestW(hDavConnect,
  1421. L"PROPPATCH",
  1422. lpPathName,
  1423. L"HTTP/1.1",
  1424. NULL,
  1425. NULL,
  1426. INTERNET_FLAG_KEEP_CONNECTION |
  1427. INTERNET_FLAG_NO_COOKIES |
  1428. INTERNET_FLAG_RELOAD,
  1429. 0,
  1430. L"DavSetProperties",
  1431. &hRequest);
  1432. if(BStatus == FALSE) {
  1433. dwError = GetLastError();
  1434. goto EXIT_THE_FUNCTION;
  1435. }
  1436. if (hRequest == NULL) {
  1437. dwError = GetLastError();
  1438. DavPrint((DEBUG_ERRORS,
  1439. "DavSetProperties/DavHttpOpenRequestW. Error Val = %d\n",
  1440. dwError));
  1441. goto EXIT_THE_FUNCTION;
  1442. }
  1443. //
  1444. // If OpaqueLockToken is non-NULL, then we need to add this header
  1445. // to the PROPPATCH request being sent out.
  1446. //
  1447. if (DavWorkItem->WorkItemType == UserModeClose) {
  1448. PDAV_USERMODE_CLOSE_REQUEST CloseRequest = &(DavWorkItem->CloseRequest);
  1449. if (CloseRequest->OpaqueLockToken != NULL) {
  1450. ReturnVal = HttpAddRequestHeadersW(hRequest,
  1451. CloseRequest->OpaqueLockToken,
  1452. -1L,
  1453. HTTP_ADDREQ_FLAG_ADD |
  1454. HTTP_ADDREQ_FLAG_REPLACE );
  1455. if (!ReturnVal) {
  1456. dwError = GetLastError();
  1457. DavPrint((DEBUG_ERRORS,
  1458. "DavSetProperties/HttpAddRequestHeadersW. "
  1459. "Error Val = %d\n", dwError));
  1460. goto EXIT_THE_FUNCTION;
  1461. }
  1462. }
  1463. } else if (DavWorkItem->WorkItemType == UserModeSetFileInformation) {
  1464. PDAV_USERMODE_SETFILEINFORMATION_REQUEST SetFileInformationRequest = &(DavWorkItem->SetFileInformationRequest);
  1465. if (SetFileInformationRequest->OpaqueLockToken != NULL) {
  1466. ReturnVal = HttpAddRequestHeadersW(hRequest,
  1467. SetFileInformationRequest->OpaqueLockToken,
  1468. -1L,
  1469. HTTP_ADDREQ_FLAG_ADD |
  1470. HTTP_ADDREQ_FLAG_REPLACE );
  1471. if (!ReturnVal) {
  1472. dwError = GetLastError();
  1473. DavPrint((DEBUG_ERRORS,
  1474. "DavSetProperties/HttpAddRequestHeadersW. "
  1475. "Error Val = %d\n", dwError));
  1476. goto EXIT_THE_FUNCTION;
  1477. }
  1478. }
  1479. }
  1480. //
  1481. // We need to add the header "translate:f" to tell IIS that it should
  1482. // allow the user to excecute this VERB on the specified path which it
  1483. // would not allow (in some cases) otherwise. Finally, there is a special
  1484. // flag in the metabase to allow for uploading of "dangerous" content
  1485. // (anything that can be run on the server). This is the ScriptSourceAccess
  1486. // flag in the UI or the AccessSource flag in the metabase. You will need
  1487. // to set this bit to true as well as correct NT ACLs in order to be able
  1488. // to upload .exes or anything executable.
  1489. //
  1490. ReturnVal = HttpAddRequestHeadersA(hRequest,
  1491. "translate: f\n",
  1492. -1,
  1493. HTTP_ADDREQ_FLAG_ADD |
  1494. HTTP_ADDREQ_FLAG_REPLACE );
  1495. if (!ReturnVal) {
  1496. dwError = GetLastError();
  1497. DavPrint((DEBUG_ERRORS,
  1498. "DavSetProperties/HttpAddRequestHeadersA. Error Val = %d\n",
  1499. dwError));
  1500. goto EXIT_THE_FUNCTION;
  1501. }
  1502. dwError = DavAttachPassportCookie(DavWorkItem,hRequest,&PassportCookie);
  1503. if (dwError != ERROR_SUCCESS) {
  1504. goto EXIT_THE_FUNCTION;
  1505. }
  1506. dwError = DavInternetSetOption(DavWorkItem,hRequest);
  1507. if (dwError != ERROR_SUCCESS) {
  1508. goto EXIT_THE_FUNCTION;
  1509. }
  1510. ReturnVal = HttpSendRequestA(hRequest,
  1511. rgXmlHeader,
  1512. strlen(rgXmlHeader),
  1513. (LPVOID)lpPropertiesBuffer,
  1514. strlen(lpPropertiesBuffer));
  1515. if (!ReturnVal) {
  1516. dwError = GetLastError();
  1517. DavPrint((DEBUG_ERRORS,
  1518. "DavSetProperties/HttpSendRequestA: Error Val = %d\n",
  1519. dwError));
  1520. goto EXIT_THE_FUNCTION;
  1521. }
  1522. dwError = DavQueryAndParseResponse(hRequest);
  1523. if (dwError != ERROR_SUCCESS) {
  1524. SetLastError(dwError);
  1525. DavPrint((DEBUG_ERRORS,
  1526. "DavSetProperties/DavQueryAndParseResponse: Error Val = %d\n",
  1527. dwError));
  1528. goto EXIT_THE_FUNCTION;
  1529. }
  1530. dwError = DavParseXmlResponse(hRequest, NULL, NULL);
  1531. if (dwError != ERROR_SUCCESS) {
  1532. SetLastError(dwError);
  1533. DavPrint((DEBUG_ERRORS,
  1534. "DavSetProperties/DavParseXmlResponse: dwError = %d\n",
  1535. dwError));
  1536. goto EXIT_THE_FUNCTION;
  1537. }
  1538. EXIT_THE_FUNCTION:
  1539. if (hRequest) {
  1540. InternetCloseHandle(hRequest);
  1541. }
  1542. if (PassportCookie) {
  1543. LocalFree(PassportCookie);
  1544. }
  1545. return dwError;
  1546. }
  1547. DWORD
  1548. DavTestProppatch(
  1549. PDAV_USERMODE_WORKITEM DavWorkItem,
  1550. HINTERNET hDavConnect,
  1551. LPWSTR lpPathName
  1552. )
  1553. /*++
  1554. Routine Description:
  1555. This routine tests whether DAV properties can be set on this root directory.
  1556. Arguments:
  1557. DavConnectHandle - Server connection.
  1558. Return Value:
  1559. ERROR_SUCCESS or Win32 Error Code.
  1560. --*/
  1561. {
  1562. CHAR *lpTemp = NULL, Buffer[1024];
  1563. DWORD dwError = ERROR_SUCCESS, dwSizeRemaining, dwTemp;
  1564. memset(Buffer, 0, sizeof(Buffer));
  1565. dwSizeRemaining = sizeof(Buffer);
  1566. lpTemp = Buffer;
  1567. memcpy(lpTemp, rgPropPatchHeader, (sizeof(rgPropPatchHeader)-1));
  1568. lpTemp += (sizeof(rgPropPatchHeader)-1);
  1569. dwSizeRemaining -= (sizeof(rgPropPatchHeader)-1);
  1570. dwTemp = dwSizeRemaining;
  1571. memcpy(lpTemp, rgDummyAttributes, sizeof(rgDummyAttributes)-1);
  1572. lpTemp += (sizeof(rgDummyAttributes)-1);
  1573. memcpy(lpTemp, rgPropPatchTrailer, sizeof(rgPropPatchTrailer)-1);
  1574. dwError = DavSetProperties(DavWorkItem, hDavConnect, lpPathName, Buffer);
  1575. return dwError;
  1576. }
  1577. DWORD
  1578. DavUnLockTheFileOnTheServer(
  1579. IN PDAV_USERMODE_WORKITEM DavWorkItem
  1580. )
  1581. /*++
  1582. Routine Description:
  1583. This routine is called during create or close when we need to UNLOCK the
  1584. file on the server. We unlock the file when the handle whose create LOCKed
  1585. the file is closed or if the Create failed after LOCKing the file.
  1586. Arguments:
  1587. DavWorkItem - The buffer that contains the request parameters and options.
  1588. Return Value:
  1589. ERROR_SUCCESS or the appropriate error code.
  1590. --*/
  1591. {
  1592. DWORD WStatus = ERROR_SUCCESS;
  1593. HINTERNET DavConnHandle = NULL, DavOpenHandle = NULL;
  1594. PWCHAR LockTokenHeader = NULL, PassportCookie = NULL, UnLockPathName = NULL;
  1595. PWCHAR OpaqueLockToken = NULL;
  1596. ULONG LockTokenHeaderLengthInBytes = 0;
  1597. BOOL BStatus = FALSE, ReturnVal = FALSE;
  1598. PDAV_USERMODE_CLOSE_REQUEST CloseRequest = NULL;
  1599. PDAV_USERMODE_CREATE_RESPONSE CreateResponse = NULL;
  1600. //
  1601. // An UNLOCK request can come from Create or Close Paths.
  1602. // 1. If the Create call in the usermode fails after the file has been
  1603. // LOCKed, it is UNLOCKed before the call is completed.
  1604. // 2. A file that was LOCKed on Create is UNLOCKed when the handle is
  1605. // closed.
  1606. //
  1607. if (DavWorkItem->WorkItemType == UserModeCreate) {
  1608. CreateResponse = &(DavWorkItem->CreateResponse);
  1609. DavConnHandle = DavWorkItem->AsyncCreate.PerUserEntry->DavConnHandle;
  1610. UnLockPathName = DavWorkItem->AsyncCreate.RemPathName;
  1611. OpaqueLockToken = CreateResponse->OpaqueLockToken;
  1612. } else {
  1613. CloseRequest = &(DavWorkItem->CloseRequest);
  1614. ASSERT(DavWorkItem->WorkItemType == UserModeClose);
  1615. ASSERT(CloseRequest->OpaqueLockToken != NULL);
  1616. DavConnHandle = DavWorkItem->AsyncClose.PerUserEntry->DavConnHandle;
  1617. UnLockPathName = &(CloseRequest->PathName[1]);
  1618. OpaqueLockToken = CloseRequest->OpaqueLockToken;
  1619. }
  1620. //
  1621. // Convert the unicode object name to UTF-8 URL format.
  1622. // Space and other white characters will remain untouched - these should
  1623. // be taken care of by wininet calls.
  1624. // This has to be a W API as the name in CloseRequest is unicode.
  1625. //
  1626. BStatus = DavHttpOpenRequestW(DavConnHandle,
  1627. L"UNLOCK",
  1628. UnLockPathName,
  1629. L"HTTP/1.1",
  1630. NULL,
  1631. NULL,
  1632. INTERNET_FLAG_KEEP_CONNECTION |
  1633. INTERNET_FLAG_NO_COOKIES |
  1634. INTERNET_FLAG_RELOAD,
  1635. 0,
  1636. L"DavUnLockTheFileOnTheServer",
  1637. &DavOpenHandle);
  1638. if(BStatus == FALSE) {
  1639. WStatus = GetLastError();
  1640. goto EXIT_THE_FUNCTION;
  1641. }
  1642. if (DavOpenHandle == NULL) {
  1643. WStatus = GetLastError();
  1644. DavPrint((DEBUG_ERRORS,
  1645. "DavUnLockTheFileOnTheServer/DavHttpOpenRequestW. Error Val = %d\n",
  1646. WStatus));
  1647. goto EXIT_THE_FUNCTION;
  1648. }
  1649. //
  1650. // We need to add the header "translate:f" to tell IIS that it should
  1651. // allow the user to excecute this VERB on the specified path which it
  1652. // would not allow (in some cases) otherwise. Finally, there is a special
  1653. // flag in the metabase to allow for uploading of "dangerous" content
  1654. // (anything that can be run on the server). This is the ScriptSourceAccess
  1655. // flag in the UI or the AccessSource flag in the metabase. You will need
  1656. // to set this bit to true as well as correct NT ACLs in order to be able
  1657. // to upload .exes or anything executable. We set this header on all requests
  1658. // that are sent to the server including the UNLOCK request.
  1659. //
  1660. ReturnVal = HttpAddRequestHeadersW(DavOpenHandle,
  1661. L"translate: f\n",
  1662. -1,
  1663. HTTP_ADDREQ_FLAG_ADD |
  1664. HTTP_ADDREQ_FLAG_REPLACE);
  1665. if (!ReturnVal) {
  1666. WStatus = GetLastError();
  1667. DavPrint((DEBUG_ERRORS,
  1668. "DavUnLockTheFileOnTheServer/HttpAddRequestHeadersW. Error Val = %d\n",
  1669. WStatus));
  1670. goto EXIT_THE_FUNCTION;
  1671. }
  1672. WStatus = DavAttachPassportCookie(DavWorkItem, DavOpenHandle, &PassportCookie);
  1673. if (WStatus != ERROR_SUCCESS) {
  1674. DavPrint((DEBUG_ERRORS,
  1675. "DavUnLockTheFileOnTheServer/DavAttachPassportCookie. Error Val = %d\n",
  1676. WStatus));
  1677. goto EXIT_THE_FUNCTION;
  1678. }
  1679. WStatus = DavInternetSetOption(DavWorkItem, DavOpenHandle);
  1680. if (WStatus != ERROR_SUCCESS) {
  1681. DavPrint((DEBUG_ERRORS,
  1682. "DavUnLockTheFileOnTheServer/DavInternetSetOption. Error Val = %d\n",
  1683. WStatus));
  1684. goto EXIT_THE_FUNCTION;
  1685. }
  1686. LockTokenHeaderLengthInBytes = (1 + wcslen(L"Lock-Token: ")) * sizeof(WCHAR);
  1687. if (DavWorkItem->WorkItemType == UserModeCreate) {
  1688. //
  1689. // CreateResponse->OpaqueLockToken has the following format.
  1690. // <opaquelocktoken:sdfsadfsdfdsfd.....>
  1691. // and we need to create a header of the following format.
  1692. // Lock-Token: <opaquelocktoken:sdfsadfsdfdsfd.....>
  1693. //
  1694. LockTokenHeaderLengthInBytes += (wcslen(OpaqueLockToken)) * sizeof(WCHAR);
  1695. LockTokenHeader = LocalAlloc(LPTR, LockTokenHeaderLengthInBytes);
  1696. if (LockTokenHeader == NULL) {
  1697. WStatus = GetLastError();
  1698. DavPrint((DEBUG_ERRORS,
  1699. "DavUnLockTheFileOnTheServer/LocalAlloc. Error Val = %d\n",
  1700. WStatus));
  1701. goto EXIT_THE_FUNCTION;
  1702. }
  1703. wcsncpy(LockTokenHeader, L"Lock-Token: ", wcslen(L"Lock-Token: "));
  1704. wcsncpy((LockTokenHeader + wcslen(L"Lock-Token: ")),
  1705. OpaqueLockToken,
  1706. wcslen(OpaqueLockToken));
  1707. } else {
  1708. //
  1709. // CloseRequest->OpaqueLockToken has the following format.
  1710. // If: (<opaquelocktoken:sdfsadfsdfdsfd.....>)
  1711. // and we need to create a header of the following format.
  1712. // Lock-Token: <opaquelocktoken:sdfsadfsdfdsfd.....>
  1713. //
  1714. //
  1715. // We don't need first 5 chars "If: (" and the last ")" char. So we subtract
  1716. // 6 from the total length of CloseRequest->OpaqueLockToken.
  1717. //
  1718. LockTokenHeaderLengthInBytes += (wcslen(OpaqueLockToken) - 6) * sizeof(WCHAR);
  1719. LockTokenHeader = LocalAlloc(LPTR, LockTokenHeaderLengthInBytes);
  1720. if (LockTokenHeader == NULL) {
  1721. WStatus = GetLastError();
  1722. DavPrint((DEBUG_ERRORS,
  1723. "DavUnLockTheFileOnTheServer/LocalAlloc. Error Val = %d\n",
  1724. WStatus));
  1725. goto EXIT_THE_FUNCTION;
  1726. }
  1727. wcsncpy(LockTokenHeader, L"Lock-Token: ", wcslen(L"Lock-Token: "));
  1728. wcsncpy((LockTokenHeader + wcslen(L"Lock-Token: ")),
  1729. (OpaqueLockToken + wcslen(L"If: (")),
  1730. (wcslen(OpaqueLockToken) - 6));
  1731. }
  1732. DavPrint((DEBUG_MISC,
  1733. "DavUnLockTheFileOnTheServer: LockTokenHeader = %ws\n",
  1734. LockTokenHeader));
  1735. ReturnVal = HttpAddRequestHeadersW(DavOpenHandle,
  1736. LockTokenHeader,
  1737. -1,
  1738. HTTP_ADDREQ_FLAG_ADD |
  1739. HTTP_ADDREQ_FLAG_REPLACE);
  1740. if (!ReturnVal) {
  1741. WStatus = GetLastError();
  1742. DavPrint((DEBUG_ERRORS,
  1743. "DavUnLockTheFileOnTheServer/HttpAddRequestHeadersW. Error Val = %d\n",
  1744. WStatus));
  1745. goto EXIT_THE_FUNCTION;
  1746. }
  1747. RESEND_THE_REQUEST:
  1748. ReturnVal = HttpSendRequestExW(DavOpenHandle,
  1749. NULL,
  1750. NULL,
  1751. HSR_SYNC,
  1752. (ULONG_PTR)0);
  1753. if (!ReturnVal) {
  1754. WStatus = GetLastError();
  1755. DavPrint((DEBUG_ERRORS,
  1756. "DavUnLockTheFileOnTheServer/HttpSendRequestExW. Error Val = %d\n",
  1757. WStatus));
  1758. goto EXIT_THE_FUNCTION;
  1759. }
  1760. ReturnVal = HttpEndRequestW(DavOpenHandle,
  1761. NULL,
  1762. HSR_SYNC,
  1763. (ULONG_PTR)0);
  1764. if (!ReturnVal) {
  1765. WStatus = GetLastError();
  1766. //
  1767. // If the error we got back is ERROR_INTERNET_FORCE_RETRY, then WinInet
  1768. // is trying to authenticate itself with the server. If we get back
  1769. // ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION, WinInet is expecting us to
  1770. // confirm that the redirect needs to be followed. In these scenarios,
  1771. // we need to repeat the HttpSend and HttpEnd request calls.
  1772. //
  1773. if (WStatus == ERROR_INTERNET_FORCE_RETRY || WStatus == ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION) {
  1774. goto RESEND_THE_REQUEST;
  1775. }
  1776. DavPrint((DEBUG_ERRORS,
  1777. "DavUnLockTheFileOnTheServer/HttpEndRequestW. Error Val = %d\n",
  1778. WStatus));
  1779. goto EXIT_THE_FUNCTION;
  1780. }
  1781. WStatus = DavQueryAndParseResponse(DavOpenHandle);
  1782. if (WStatus != ERROR_SUCCESS) {
  1783. DavPrint((DEBUG_ERRORS,
  1784. "DavUnLockTheFileOnTheServer/DavQueryAndParseResponse. WStatus = %d\n",
  1785. WStatus));
  1786. }
  1787. EXIT_THE_FUNCTION:
  1788. if (DavOpenHandle != NULL) {
  1789. InternetCloseHandle(DavOpenHandle);
  1790. DavOpenHandle = NULL;
  1791. }
  1792. if (PassportCookie) {
  1793. LocalFree(PassportCookie);
  1794. PassportCookie = NULL;
  1795. }
  1796. if (LockTokenHeader) {
  1797. LocalFree(LockTokenHeader);
  1798. LockTokenHeader = NULL;
  1799. }
  1800. return WStatus;
  1801. }