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.

5607 lines
206 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. davcreat.c
  5. Abstract:
  6. This module implements the user mode DAV miniredir routine(s) pertaining to
  7. creation of files.
  8. Author:
  9. Rohan Kumar [RohanK] 30-March-1999
  10. Revision History:
  11. Notes:
  12. Webdav Service is running in Local Services group. The local cache of the
  13. URL is stored in the Local Services profile directories. These directories
  14. have the ACLs set to allow Local Services and Local System to access.
  15. The encryption is done on the local cache file. Since encrypted file can
  16. only be operated in the user context, We have to impersonate before access
  17. the local cache file. In order to get the access to the file that is created
  18. in the Local Services profile directory in the user's context, we need to
  19. set the ACL to the encrypted file to allow everybody to access it. It won't
  20. result in a security hole because the file is encrypted.
  21. --*/
  22. #include "pch.h"
  23. #pragma hdrstop
  24. #include "ntumrefl.h"
  25. #include "usrmddav.h"
  26. #include "global.h"
  27. #include "nodefac.h"
  28. #include "efsstruc.h" // For EFS Stuff.
  29. #include "UniUtf.h"
  30. #include <sddl.h>
  31. #define SECURITY_WIN32 // needed by security.h
  32. #include <security.h>
  33. #include <secext.h>
  34. #define FILE_SIGNATURE L"ROBS"
  35. #define STREAM_SIGNATURE L"NTFS"
  36. #define DATA_SIGNATURE L"GURE"
  37. BOOL
  38. DavIsThisFileEncrypted(
  39. PVOID DataBuff
  40. );
  41. ULONG
  42. DavCheckSignature(
  43. PVOID Signature
  44. );
  45. DWORD
  46. DavRestoreEncryptedFile(
  47. PWCHAR ExportFile,
  48. PWCHAR ImportFile
  49. );
  50. DWORD
  51. DavWriteRawCallback(
  52. PBYTE DataBuff,
  53. PVOID CallbackContext,
  54. PULONG DataLength
  55. );
  56. DWORD
  57. DavReuseCacheFileIfNotModified(
  58. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  59. );
  60. DWORD
  61. DavCreateUrlCacheEntry(
  62. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  63. );
  64. DWORD
  65. DavCommitUrlCacheEntry(
  66. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  67. );
  68. DWORD
  69. DavSetAclForEncryptedFile(
  70. PWCHAR FilePath
  71. );
  72. DWORD
  73. DavGetUrlCacheEntry(
  74. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  75. );
  76. DWORD
  77. DavAddIfModifiedSinceHeader(
  78. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  79. );
  80. DWORD
  81. DavQueryUrlCacheEntry(
  82. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  83. );
  84. DWORD
  85. DavAsyncCreatePropFind(
  86. PDAV_USERMODE_WORKITEM DavWorkItem
  87. );
  88. DWORD
  89. DavAsyncCreateQueryParentDirectory(
  90. PDAV_USERMODE_WORKITEM DavWorkItem
  91. );
  92. DWORD
  93. DavAsyncCreateGet(
  94. PDAV_USERMODE_WORKITEM DavWorkItem
  95. );
  96. DWORD
  97. DavLockTheFileOnTheServer(
  98. IN PDAV_USERMODE_WORKITEM DavWorkItem
  99. );
  100. //
  101. // The maximum file size that is allowed by the WebDAV Redir. We keep a limit
  102. // on the file size to avoid being attacked by a rogue server. A rogue server
  103. // could keep on sending infinite amount of data which can cause the WebClient
  104. // service to use 100% of the CPU.
  105. //
  106. ULONG DavFileSizeLimitInBytes;
  107. //
  108. // The maximum attributes size that is allowed by the WebDAV Redir. We keep a
  109. // limit on this size to avoid being attacked by a rogue server. A rogue server
  110. // could keep on sending infinite amount of data which can cause the WebClient
  111. // service to use 100% of the CPU. This attribute limit covers all the
  112. // PROPFIND and PROPPATCH responses. For PROPFINDs with Depth 1 we make the
  113. // limit a multiple of DavFileAttributesLimitInBytes (10 times).
  114. //
  115. ULONG DavFileAttributesLimitInBytes;
  116. #define FileCacheExpiryInterval 600000000 // 60 seconds
  117. CHAR rgchIMS[] = "If-Modified-Since";
  118. CHAR rgHttpHeader[] = "Content-Type: text/xml; charset=\"utf-8\"";
  119. CHAR rgLockInfoHeader[] = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><D:lockinfo xmlns:D=\"DAV:\">";
  120. CHAR rgLockInfoTrailer[] = "</D:lockinfo>";
  121. CHAR rgLockScopeHeader[] = "<D:lockscope><D:exclusive/></D:lockscope>";
  122. CHAR rgLockTypeHeader[] = "<D:locktype><D:write/></D:locktype>";
  123. CHAR rgOwnerHeader[] = "<D:owner><D:href>";
  124. CHAR rgOwnerTrailer[] = "</D:href></D:owner>";
  125. //
  126. // Implementation of functions begins here.
  127. //
  128. ULONG
  129. DavFsCreate(
  130. PDAV_USERMODE_WORKITEM DavWorkItem
  131. )
  132. /*++
  133. Routine Description:
  134. This routine handles DAV create/open requests that get reflected from the
  135. kernel.
  136. Arguments:
  137. DavWorkItem - The buffer that contains the request parameters and options.
  138. Return Value:
  139. The return status for the operation
  140. --*/
  141. {
  142. ULONG WStatus = ERROR_SUCCESS;
  143. HINTERNET DavConnHandle;
  144. PWCHAR ServerName = NULL, FileName = NULL, CanName, UrlBuffer = NULL;
  145. PWCHAR CompletePathName, cPtr, FileNameBuff = NULL;
  146. DWORD urlLength = 0, ServerLen, ServerLenInBytes, PathLen, PathLenInBytes;
  147. DWORD FileNameBuffBytes, i = 0, ServerID;
  148. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  149. BOOL ReturnVal, CallBackContextInitialized = FALSE, EnCriSec = FALSE;
  150. BOOL didImpersonate = FALSE;
  151. URL_COMPONENTSW UrlComponents;
  152. PDAV_USERMODE_CREATE_REQUEST CreateRequest;
  153. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  154. PPER_USER_ENTRY PerUserEntry = NULL;
  155. PHASH_SERVER_ENTRY ServerHashEntry = NULL;
  156. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  157. BOOL BStatus = FALSE;
  158. //
  159. // Get the request buffer pointers from the DavWorkItem.
  160. //
  161. CreateRequest = &(DavWorkItem->CreateRequest);
  162. CreateResponse = &(DavWorkItem->CreateResponse);
  163. ServerID = CreateRequest->ServerID;
  164. //
  165. // If the complete path name is NULL, then we have nothing to create.
  166. //
  167. if (CreateRequest->CompletePathName == NULL) {
  168. DavPrint((DEBUG_ERRORS,
  169. "DavFsCreate: ERROR: CompletePathName is NULL.\n"));
  170. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  171. goto EXIT_THE_FUNCTION;
  172. }
  173. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  174. //
  175. // CreateRequest->CompletePathName contains the complete path name.
  176. //
  177. DavPrint((DEBUG_MISC, "DavFsCreate: DavWorkItem = %08lx\n", DavWorkItem));
  178. DavPrint((DEBUG_MISC, "DavFsCreate: CompletePathName: %ws\n", CreateRequest->CompletePathName));
  179. //
  180. // We need to do some name munging, if the create is because of a local
  181. // drive being mapped to a UNC name. The fomat in that case would be
  182. // \;X:0\server\share
  183. //
  184. if ( CreateRequest->CompletePathName[1] == L';') {
  185. CompletePathName = &(CreateRequest->CompletePathName[6]);
  186. } else {
  187. CompletePathName = &(CreateRequest->CompletePathName[1]);
  188. }
  189. //
  190. // Here, we parse the Complete path name and remove the server name and the
  191. // file name from it. We use these to construct the URL for the WinInet
  192. // calls. The complete path name is of the form \server\filename.
  193. // The name ends with a '\0'. Note that the filename could be of the form
  194. // share\foo\bar\duh.txt.
  195. //
  196. // [\;X:0]\server\filename
  197. // ^
  198. // |
  199. // CompletePathName(CPN)
  200. // \server\filename
  201. // ^ ^
  202. // | |
  203. // CPN cPtr
  204. cPtr = wcschr(CompletePathName, '\\');
  205. //
  206. // Length of the server name including the terminating '\0' char.
  207. //
  208. ServerLen = 1 + (((PBYTE)cPtr - (PBYTE)CompletePathName) / sizeof(WCHAR));
  209. ServerLenInBytes = ServerLen * sizeof(WCHAR);
  210. // \server\filename
  211. // ^ ^
  212. // | |
  213. // CPN cPtr
  214. cPtr++;
  215. //
  216. // Length of the server name including the terminating '\0' char.
  217. //
  218. PathLen = 1 + wcslen(cPtr);
  219. PathLenInBytes = PathLen * sizeof(WCHAR);
  220. //
  221. // Allocate the memory and fill in the server name char by char.
  222. //
  223. ServerName = (PWCHAR) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  224. ServerLenInBytes);
  225. if (ServerName == NULL) {
  226. WStatus = GetLastError();
  227. DavPrint((DEBUG_ERRORS,
  228. "DavFsCreate/LocalAlloc. Error Val = %d\n",
  229. WStatus));
  230. goto EXIT_THE_FUNCTION;
  231. }
  232. // \server\filename
  233. // ^^^^^^ ^
  234. // |||||| |
  235. // CPN cPtr
  236. while(CompletePathName[i] != '\\') {
  237. ASSERT(i < ServerLen);
  238. ServerName[i] = CompletePathName[i];
  239. i++;
  240. }
  241. ASSERT((i + 1) == ServerLen);
  242. ServerName[i] = '\0';
  243. //
  244. // Allocate the memory and copy the file name.
  245. //
  246. FileName = (PWCHAR) LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, PathLenInBytes);
  247. if (FileName == NULL) {
  248. WStatus = GetLastError();
  249. DavPrint((DEBUG_ERRORS,
  250. "DavFsCreate/LocalAlloc. Error Val = %d\n",
  251. WStatus));
  252. goto EXIT_THE_FUNCTION;
  253. }
  254. //
  255. // This remaining path name is needed in Async Create Callback function.
  256. //
  257. DavWorkItem->AsyncCreate.RemPathName = FileName;
  258. wcscpy(FileName, cPtr);
  259. CanName = FileName;
  260. //
  261. // The file name can contain \ characters. Replace them by / characters.
  262. //
  263. while (*CanName) {
  264. if (*CanName == L'\\') {
  265. *CanName = L'/';
  266. }
  267. CanName++;
  268. }
  269. //
  270. // Check if this is a stream, if so, bailout right from here.
  271. //
  272. if(wcschr(FileName, L':')) {
  273. WStatus = ERROR_INVALID_NAME;
  274. DavPrint((DEBUG_ERRORS, "DavFsCreate: Streams Not Supported\n"));
  275. goto EXIT_THE_FUNCTION;
  276. }
  277. //
  278. // If we have a dummy share name in the FileName, we need to remove it
  279. // right now before we contact the server.
  280. //
  281. DavRemoveDummyShareFromFileName(FileName);
  282. DavPrint((DEBUG_MISC,
  283. "DavFsCreate: ServerName: %ws, File Name: %ws\n",
  284. ServerName, FileName));
  285. //
  286. // Create the URL to be sent to the server. Initialize the UrlComponents
  287. // structure before making the call.
  288. //
  289. UrlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
  290. UrlComponents.lpszScheme = NULL;
  291. UrlComponents.dwSchemeLength = 0;
  292. UrlComponents.nScheme = INTERNET_SCHEME_HTTP;
  293. UrlComponents.lpszHostName = ServerName;
  294. UrlComponents.dwHostNameLength = wcslen(ServerName);
  295. UrlComponents.nPort = DEFAULT_HTTP_PORT;
  296. UrlComponents.lpszUserName = NULL;
  297. UrlComponents.dwUserNameLength = 0;
  298. UrlComponents.lpszPassword = NULL;
  299. UrlComponents.dwPasswordLength = 0;
  300. UrlComponents.lpszUrlPath = FileName;
  301. UrlComponents.dwUrlPathLength = wcslen(FileName);
  302. UrlComponents.lpszExtraInfo = NULL;
  303. UrlComponents.dwExtraInfoLength = 0;
  304. ReturnVal = InternetCreateUrlW(&(UrlComponents),
  305. 0,
  306. NULL,
  307. &(urlLength));
  308. if (!ReturnVal) {
  309. ULONG urlLengthInWChars = 0;
  310. WStatus = GetLastError();
  311. //
  312. // We pre-allocate the Url buffer on the CreateResponse with the size of
  313. // MAX_PATH * 2. Any Url longer than that will overrun the buffer. The Url
  314. // will be used to update the LastAccessTime of the WinInet cache on rename
  315. // and close later. Note urlLength is the number of bytes.
  316. //
  317. if (urlLength >= MAX_PATH * 4) {
  318. WStatus = ERROR_NO_SYSTEM_RESOURCES;
  319. goto EXIT_THE_FUNCTION;
  320. }
  321. if (WStatus == ERROR_INSUFFICIENT_BUFFER) {
  322. UrlBuffer = (PWCHAR) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT,
  323. urlLength);
  324. if (UrlBuffer != NULL) {
  325. ZeroMemory(UrlBuffer, urlLength);
  326. //
  327. // This UrlBuffer is needed in Async Create Callback function.
  328. // We need to supply the length (4th Parameter) in WChars.
  329. //
  330. DavWorkItem->AsyncCreate.UrlBuffer = UrlBuffer;
  331. urlLengthInWChars = ( urlLength/sizeof(WCHAR) );
  332. ReturnVal = InternetCreateUrlW(&(UrlComponents),
  333. 0,
  334. UrlBuffer,
  335. &(urlLengthInWChars));
  336. if (!ReturnVal) {
  337. WStatus = GetLastError();
  338. DavPrint((DEBUG_ERRORS,
  339. "DavFsCreate/InternetCreateUrl. Error Val = %d\n",
  340. WStatus));
  341. goto EXIT_THE_FUNCTION;
  342. }
  343. } else {
  344. WStatus = GetLastError();
  345. DavPrint((DEBUG_ERRORS,
  346. "DavFsCreate/LocalAlloc. Error Val = %d\n",
  347. WStatus));
  348. goto EXIT_THE_FUNCTION;
  349. }
  350. } else {
  351. DavPrint((DEBUG_ERRORS,
  352. "DavFsCreate/InternetCreateUrl. Error Val = %d\n",
  353. WStatus));
  354. goto EXIT_THE_FUNCTION;
  355. }
  356. }
  357. DavPrint((DEBUG_MISC, "URL: %ws\n", UrlBuffer));
  358. //
  359. // We need to call this only if "DAV_USE_WININET_ASYNCHRONOUSLY" has been
  360. // defined. Otherwise, if we are using WinInet synchronously, then we
  361. // would have already done this in the DavWorkerThread function. This
  362. // ultimately gets deleted (the impersonation token that is) in the
  363. // DavAsyncCreateCompletion function.
  364. //
  365. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  366. //
  367. // Set the DavCallBackContext.
  368. //
  369. WStatus = DavFsSetTheDavCallBackContext(DavWorkItem);
  370. if (WStatus != ERROR_SUCCESS) {
  371. DavPrint((DEBUG_ERRORS,
  372. "DavFsCreate/DavFsSetTheDavCallBackContext. Error Val = %d\n",
  373. WStatus));
  374. goto EXIT_THE_FUNCTION;
  375. }
  376. CallBackContextInitialized = TRUE;
  377. //
  378. // Store the address of the DavWorkItem which serves as a callback in the
  379. // variable CallBackContext. This will now be used in all the async calls
  380. // that follow. This needs to be done only if we are calling the WinInet
  381. // APIs asynchronously.
  382. //
  383. CallBackContext = (ULONG_PTR)(DavWorkItem);
  384. #endif
  385. //
  386. // Allocate memory for the INTERNET_ASYNC_RESULT structure.
  387. //
  388. DavWorkItem->AsyncResult = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  389. sizeof(INTERNET_ASYNC_RESULT));
  390. if (DavWorkItem->AsyncResult == NULL) {
  391. WStatus = GetLastError();
  392. DavPrint((DEBUG_ERRORS,
  393. "DavFsCreate/LocalAlloc. Error Val = %d\n",
  394. WStatus));
  395. goto EXIT_THE_FUNCTION;
  396. }
  397. DavPrint((DEBUG_MISC,
  398. "DavFsCreate: LogonId.LowPart = %d, LogonId.HighPart = %d\n",
  399. CreateRequest->LogonID.LowPart, CreateRequest->LogonID.HighPart));
  400. //
  401. // Find out whether we already have a "InternetConnect" handle to the
  402. // server. One could have been created during the CreateSrvCall process.
  403. // We can check the per user entries hanging off this server to see if an
  404. // entry for this user exists. If it does, use the InternetConnect handle
  405. // to do the HttpOpen. Otherwise, create and entry for this user and add it
  406. // to the list of the per user entries of the server.
  407. //
  408. //
  409. // Now check whether this user has an entry hanging off the server entry in
  410. // the hash table. Obviously, we have to take a lock before accessing the
  411. // server entries of the hash table.
  412. //
  413. EnterCriticalSection( &(HashServerEntryTableLock) );
  414. EnCriSec = TRUE;
  415. ReturnVal = DavDoesUserEntryExist(ServerName,
  416. ServerID,
  417. &(CreateRequest->LogonID),
  418. &PerUserEntry,
  419. &ServerHashEntry);
  420. //
  421. // If the Create request in the kernel get cancelled even before the
  422. // corresponding usermode thread gets a chance to execute this code, then
  423. // it possible that the VNetRoot (hence the PerUserEntry) and SrvCall get
  424. // finalized before the thread that is handling the create comes here. This
  425. // could happen if this request was the only one for this share and the
  426. // server as well. This is why we need to check if the ServerHashEntry and
  427. // the PerUserEntry are valid before proceeding.
  428. //
  429. if (ReturnVal == FALSE || ServerHashEntry == NULL || PerUserEntry == NULL) {
  430. WStatus = ERROR_CANCELLED;
  431. DavPrint((DEBUG_ERRORS, "DavFsCreate: (ServerHashEntry == NULL || PerUserEntry == NULL)\n"));
  432. goto EXIT_THE_FUNCTION;
  433. }
  434. DavWorkItem->AsyncCreate.ServerHashEntry = ServerHashEntry;
  435. DavWorkItem->AsyncCreate.PerUserEntry = PerUserEntry;
  436. //
  437. // Add a reference to the user entry.
  438. //
  439. PerUserEntry->UserEntryRefCount++;
  440. //
  441. // Since a create had succeeded earlier, the entry must be good.
  442. //
  443. ASSERT(PerUserEntry->UserEntryState == UserEntryInitialized);
  444. ASSERT(PerUserEntry->DavConnHandle != NULL);
  445. DavConnHandle = PerUserEntry->DavConnHandle;
  446. //
  447. // And yes, we obviously have to leave the critical section
  448. // before returning.
  449. //
  450. LeaveCriticalSection( &(HashServerEntryTableLock) );
  451. EnCriSec = FALSE;
  452. //
  453. // If we are using WinInet synchronously, then we need to impersonate the
  454. // clients context now. We shouldn't do it before we call CreateUrlCacheEntry
  455. // because that call will fail if the thread is not running in the context
  456. // of the Web Client Service.
  457. //
  458. #ifndef DAV_USE_WININET_ASYNCHRONOUSLY
  459. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  460. if (WStatus != ERROR_SUCCESS) {
  461. DavPrint((DEBUG_ERRORS,
  462. "DavFsCreate/UMReflectorImpersonate. Error Val = %d\n",
  463. WStatus));
  464. goto EXIT_THE_FUNCTION;
  465. }
  466. didImpersonate = TRUE;
  467. #endif
  468. //
  469. // We now call the HttpOpenRequest function and return.
  470. //
  471. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  472. DavPrint((DEBUG_MISC, "DavFsCreate: DavConnHandle = %08lx.\n", DavConnHandle));
  473. DavWorkItem->AsyncCreate.AsyncCreateState = AsyncCreatePropFind;
  474. DavWorkItem->DavMinorOperation = DavMinorQueryInfo;
  475. DavWorkItem->AsyncCreate.DataBuff = NULL;
  476. DavWorkItem->AsyncCreate.didRead = NULL;
  477. DavWorkItem->AsyncCreate.Context1 = NULL;
  478. DavWorkItem->AsyncCreate.Context2 = NULL;
  479. if (CreateRequest->FileInformationCached) {
  480. DavPrint((DEBUG_MISC,
  481. "Cached info %x %x %x %ws\n",
  482. CreateResponse->BasicInformation.FileAttributes,
  483. CreateResponse->StandardInformation.AllocationSize.LowPart,
  484. CreateResponse->StandardInformation.EndOfFile.LowPart,
  485. DavWorkItem->AsyncCreate.UrlBuffer));
  486. }
  487. if ((CreateRequest->FileNotExists) || (CreateRequest->FileInformationCached)) {
  488. FILE_BASIC_INFORMATION BasicInformation = CreateResponse->BasicInformation;
  489. FILE_STANDARD_INFORMATION StandardInformation = CreateResponse->StandardInformation;
  490. RtlZeroMemory(CreateResponse, sizeof(*CreateResponse));
  491. //
  492. // Restore the file information on the create request
  493. //
  494. if (CreateRequest->FileInformationCached) {
  495. CreateResponse->BasicInformation = BasicInformation;
  496. CreateResponse->StandardInformation = StandardInformation;
  497. DavWorkItem->AsyncCreate.doesTheFileExist = TRUE;
  498. }
  499. if (!didImpersonate) {
  500. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  501. if (WStatus != ERROR_SUCCESS) {
  502. DavPrint((DEBUG_ERRORS,
  503. "DavFsCreate/UMReflectorImpersonate. Error Val = %d\n",
  504. WStatus));
  505. goto EXIT_THE_FUNCTION;
  506. }
  507. didImpersonate = TRUE;
  508. }
  509. DavPrint((DEBUG_MISC,
  510. "DavFsCreate skip PROPFIND for %x %x %ws\n",
  511. CreateRequest->FileAttributes,
  512. CreateResponse->BasicInformation.FileAttributes,
  513. DavWorkItem->AsyncCreate.UrlBuffer));
  514. WStatus = DavAsyncCreatePropFind(DavWorkItem);
  515. } else {
  516. RtlZeroMemory(CreateResponse, sizeof(*CreateResponse));
  517. //
  518. // Convert the unicode object name to UTF-8 URL format. Space and other
  519. // white characters will remain untouched. These should be taken care of by
  520. // the wininet calls.
  521. //
  522. BStatus = DavHttpOpenRequestW(DavConnHandle,
  523. L"PROPFIND",
  524. FileName,
  525. L"HTTP/1.1",
  526. NULL,
  527. NULL,
  528. INTERNET_FLAG_KEEP_CONNECTION |
  529. INTERNET_FLAG_RESYNCHRONIZE |
  530. INTERNET_FLAG_NO_COOKIES,
  531. CallBackContext,
  532. L"DavFsCreate",
  533. &(DavWorkItem->AsyncCreate.DavOpenHandle));
  534. if(BStatus == FALSE) {
  535. WStatus = GetLastError();
  536. goto EXIT_THE_FUNCTION;
  537. }
  538. if (DavWorkItem->AsyncCreate.DavOpenHandle == NULL) {
  539. WStatus = GetLastError();
  540. if (WStatus != ERROR_IO_PENDING) {
  541. DavPrint((DEBUG_ERRORS,
  542. "DavFsCreate/HttpOpenRequestW. Error Val = %d.\n",
  543. WStatus));
  544. }
  545. goto EXIT_THE_FUNCTION;
  546. }
  547. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  548. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING && WStatus != ERROR_FILE_NOT_FOUND) {
  549. DavPrint((DEBUG_ERRORS,
  550. "DavFsCreate/DavAsyncCommonStates. Error Val = %08lx\n",
  551. WStatus));
  552. }
  553. }
  554. EXIT_THE_FUNCTION: // Do the necessary cleanup and return.
  555. //
  556. // We could have taken the lock and come down an error path without
  557. // releasing it. If thats the case, then we need to release the lock now.
  558. //
  559. if (EnCriSec) {
  560. LeaveCriticalSection( &(HashServerEntryTableLock) );
  561. EnCriSec = FALSE;
  562. }
  563. if (ServerName != NULL) {
  564. HLOCAL FreeHandle;
  565. ULONG FreeStatus;
  566. FreeHandle = LocalFree((HLOCAL)ServerName);
  567. if (FreeHandle != NULL) {
  568. FreeStatus = GetLastError();
  569. DavPrint((DEBUG_ERRORS, "DavFsCreate/LocalFree. Error Val = %d\n", FreeStatus));
  570. }
  571. }
  572. if (WStatus == ERROR_SUCCESS) {
  573. wcscpy(CreateResponse->Url, DavWorkItem->AsyncCreate.UrlBuffer);
  574. DavPrint((DEBUG_MISC,
  575. "Returned info %x %x %x %ws\n",
  576. CreateResponse->BasicInformation.FileAttributes,
  577. CreateResponse->StandardInformation.AllocationSize.LowPart,
  578. CreateResponse->StandardInformation.EndOfFile.LowPart,
  579. DavWorkItem->AsyncCreate.UrlBuffer));
  580. }
  581. //
  582. // If the Create failed after taking a LOCK on the file, then we need to
  583. // UNLOCK the file before returning.
  584. //
  585. if (WStatus != ERROR_SUCCESS) {
  586. if (CreateResponse->LockWasTakenOnThisCreate) {
  587. ULONG UnLockStatus;
  588. if (!didImpersonate) {
  589. UnLockStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  590. if (UnLockStatus != ERROR_SUCCESS) {
  591. DavPrint((DEBUG_ERRORS,
  592. "DavFsCreate/UMReflectorImpersonate. Error Val = %d\n",
  593. UnLockStatus));
  594. } else {
  595. didImpersonate = TRUE;
  596. }
  597. }
  598. UnLockStatus = DavUnLockTheFileOnTheServer(DavWorkItem);
  599. if (UnLockStatus != ERROR_SUCCESS) {
  600. DavPrint((DEBUG_ERRORS,
  601. "DavFsCreate/DavUnLockTheFileOnTheServer. Error Val = %d\n",
  602. UnLockStatus));
  603. }
  604. CreateResponse->LockWasTakenOnThisCreate = FALSE;
  605. }
  606. }
  607. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  608. //
  609. // Some resources should not be freed if we are returning ERROR_IO_PENDING
  610. // because they will be used in the callback functions.
  611. //
  612. if (WStatus != ERROR_IO_PENDING) {
  613. //
  614. // Set the return status of the operation. This is used by the kernel
  615. // mode routines to figure out the completion status of the user mode
  616. // request.
  617. //
  618. if (WStatus != ERROR_SUCCESS) {
  619. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  620. } else {
  621. DavWorkItem->Status = STATUS_SUCCESS;
  622. }
  623. DavAsyncCreateCompletion(DavWorkItem);
  624. } else {
  625. DavPrint((DEBUG_MISC, "DavFsCreate: Returning ERROR_IO_PENDING.\n"));
  626. }
  627. #else
  628. //
  629. // If we are using WinInet synchronously, then we should never get back
  630. // ERROR_IO_PENDING from WinInet.
  631. //
  632. ASSERT(WStatus != ERROR_IO_PENDING);
  633. //
  634. // If this thread impersonated a user, we need to revert back.
  635. //
  636. if (didImpersonate) {
  637. RevertToSelf();
  638. didImpersonate = FALSE;
  639. }
  640. //
  641. // Set the return status of the operation. This is used by the kernel
  642. // mode routines to figure out the completion status of the user mode
  643. // request. This is done here because the async completion routine that is
  644. // called immediately afterwards needs the status set.
  645. //
  646. if (WStatus != ERROR_SUCCESS) {
  647. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  648. //
  649. // The error cannot map to STATUS_SUCCESS. If it does, we need to
  650. // break here and investigate.
  651. //
  652. if (DavWorkItem->Status == STATUS_SUCCESS) {
  653. DbgBreakPoint();
  654. }
  655. } else {
  656. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  657. CreateResponse = &(DavWorkItem->CreateResponse);
  658. DavWorkItem->Status = STATUS_SUCCESS;
  659. //
  660. // If we suceeded and it was a file and the open was not a pseudo open,
  661. // the handle should be set. Otherwise we screwed up. We should then
  662. // break here and investigate.
  663. //
  664. if ( !(CreateResponse->StandardInformation.Directory) &&
  665. !(CreateResponse->fPsuedoOpen) ) {
  666. if (CreateResponse->Handle == NULL) {
  667. DbgBreakPoint();
  668. }
  669. }
  670. }
  671. DavAsyncCreateCompletion(DavWorkItem);
  672. #endif
  673. return WStatus;
  674. }
  675. DWORD
  676. DavAsyncCreate(
  677. PDAV_USERMODE_WORKITEM DavWorkItem,
  678. BOOLEAN CalledByCallBackThread
  679. )
  680. /*++
  681. Routine Description:
  682. This is the callback routine for the create operation.
  683. Arguments:
  684. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  685. CalledByCallbackThread - TRUE, if this function was called by the thread
  686. which picks of the DavWorkItem from the Callback
  687. function. This happens when an Async WinInet call
  688. returns ERROR_IO_PENDING and completes later.
  689. Return Value:
  690. ERROR_SUCCESS or the appropriate error value.
  691. --*/
  692. {
  693. ULONG WStatus = ERROR_SUCCESS;
  694. NTSTATUS NtStatus = STATUS_SUCCESS;
  695. ULONG NumOfFileEntries = 0;
  696. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  697. BOOL ReturnVal, didImpersonate = FALSE, readDone = FALSE;
  698. BOOL doesTheFileExist = FALSE;
  699. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  700. DWORD toRead = 0, didRead = 0, didWrite = 0;
  701. LPDWORD NumRead = NULL;
  702. PVOID Ctx1 = NULL, Ctx2 = NULL;
  703. PDAV_FILE_ATTRIBUTES DavFileAttributes;
  704. PCHAR DataBuff = NULL;
  705. DWORD DataBuffBytes;
  706. OBJECT_ATTRIBUTES ObjectAttributes;
  707. IO_STATUS_BLOCK IoStatusBlock;
  708. SECURITY_QUALITY_OF_SERVICE QualityOfService;
  709. PDAV_USERMODE_CREATE_REQUEST CreateRequest;
  710. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  711. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  712. PWCHAR pEncryptedCachedFile = NULL;
  713. PDAV_FILE_ATTRIBUTES DavDirectoryAttributes = NULL;
  714. ACCESS_MASK DesiredAccess = 0;
  715. BOOL BStatus = FALSE, fCacheFileReused = FALSE;
  716. //
  717. // Get the request and response buffer pointers from the DavWorkItem.
  718. //
  719. CreateRequest = &(DavWorkItem->CreateRequest);
  720. CreateResponse = &(DavWorkItem->CreateResponse);
  721. CreateResponse->fPsuedoOpen = FALSE;
  722. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  723. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  724. //
  725. // We set the CallbackContext only if we are calling the WinInet APIs
  726. // asynchronously.
  727. //
  728. CallBackContext = (ULONG_PTR)DavWorkItem;
  729. //
  730. // If this function was called by the thread that picked off the DavWorkItem
  731. // from the Callback function, we need to do a few things first. These are
  732. // done below.
  733. //
  734. if (CalledByCallBackThread) {
  735. //
  736. // We are running in the context of a worker thread which has different
  737. // credentials than the user that initiated the I/O request. Before
  738. // proceeding further, we should impersonate the user that initiated the
  739. // request.
  740. //
  741. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  742. if (WStatus != ERROR_SUCCESS) {
  743. DavPrint((DEBUG_ERRORS,
  744. "DavAsyncCreate/UMReflectorImpersonate. Error Val = %d\n",
  745. WStatus));
  746. goto EXIT_THE_FUNCTION;
  747. }
  748. didImpersonate = TRUE;
  749. //
  750. // Before proceeding further, check to see if the Async operation failed.
  751. // If it did, then cleanup and move on.
  752. //
  753. if ( !DavWorkItem->AsyncResult->dwResult ) {
  754. WStatus = DavWorkItem->AsyncResult->dwError;
  755. //
  756. // If the error we got back is ERROR_INTERNET_FORCE_RETRY, then
  757. // WinInet is trying to authenticate itself with the server. In
  758. // such a scenario this is what happens.
  759. //
  760. // Client ----Request-----> Server
  761. // Server ----AccessDenied-----> Client
  762. // Client----Challenge Me-------> Server
  763. // Server-----Challenge--------> Client
  764. // Client-----Challenge Resp----> Server
  765. //
  766. if (WStatus == ERROR_INTERNET_FORCE_RETRY) {
  767. ASSERT(DavWorkItem->DavOperation == DAV_CALLBACK_HTTP_END);
  768. //
  769. // We need to repeat the HttpSend and HttpEnd request calls.
  770. //
  771. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  772. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  773. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  774. DavPrint((DEBUG_ERRORS,
  775. "DavAsyncCreate/DavAsyncCommonStates. Error Val ="
  776. " %08lx\n", WStatus));
  777. }
  778. } else if (WStatus == ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION) {
  779. //
  780. // MSN has this BUG where it returns 302 instead of 404 when
  781. // queried for a file (eg:Desktop.ini) which does not exist at
  782. // the share level.
  783. //
  784. WStatus = ERROR_FILE_NOT_FOUND;
  785. } else {
  786. DavPrint((DEBUG_ERRORS,
  787. "DavAsyncCreate. AsyncFunction failed. Error Val = %d\n",
  788. WStatus));
  789. }
  790. goto EXIT_THE_FUNCTION;
  791. }
  792. }
  793. #else
  794. //
  795. // If we are using synchronous WinInet then we enter this function
  796. // impersonating the client.
  797. //
  798. didImpersonate = TRUE;
  799. ASSERT(CalledByCallBackThread == FALSE);
  800. #endif
  801. switch (DavWorkItem->DavOperation) {
  802. case DAV_CALLBACK_HTTP_END:
  803. case DAV_CALLBACK_HTTP_READ: {
  804. if (DavWorkItem->AsyncCreate.DataBuff == NULL) {
  805. //
  806. // Need to allocate memory for the read buffer.
  807. //
  808. DataBuffBytes = NUM_OF_BYTES_TO_READ;
  809. DataBuff = LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, DataBuffBytes);
  810. if (DataBuff == NULL) {
  811. WStatus = GetLastError();
  812. DavPrint((DEBUG_ERRORS,
  813. "DavAsyncCreate/LocalAlloc. Error Val = %d\n",
  814. WStatus));
  815. goto EXIT_THE_FUNCTION;
  816. }
  817. DavWorkItem->AsyncCreate.DataBuff = DataBuff;
  818. }
  819. if (DavWorkItem->AsyncCreate.didRead == NULL) {
  820. //
  821. // Allocate memory for the DWORD that stores the number of bytes read.
  822. //
  823. NumRead = LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, sizeof(DWORD));
  824. if (NumRead == NULL) {
  825. WStatus = GetLastError();
  826. DavPrint((DEBUG_ERRORS,
  827. "DavAsyncCreate/LocalAlloc. Error Val = %d\n",
  828. WStatus));
  829. goto EXIT_THE_FUNCTION;
  830. }
  831. DavWorkItem->AsyncCreate.didRead = NumRead;
  832. }
  833. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_READ;
  834. DavPrint((DEBUG_MISC,
  835. "DavAsyncCreate: AsyncCreateState = %d\n",
  836. DavWorkItem->AsyncCreate.AsyncCreateState));
  837. DavPrint((DEBUG_MISC,
  838. "DavAsyncCreate: CalledByCallBackThread = %d\n",
  839. CalledByCallBackThread));
  840. //
  841. // When we come here, we could either be doing a PROPFIND or GET on the
  842. // file. The PROPFIND is done to get the file attributes and the GET to
  843. // get the whole file from the server.
  844. //
  845. if (DavWorkItem->AsyncCreate.AsyncCreateState == AsyncCreatePropFind) {
  846. if (DavWorkItem->DavMinorOperation == DavMinorQueryInfo) {
  847. ULONG ResponseStatus;
  848. //
  849. // If the file for which the PROPFIND was done does not exist, then
  850. // we need to Create one or fail, depending on the create options
  851. // specified by the application.
  852. //
  853. //
  854. // Does this file exist ? If the ResponseStatus is not
  855. // ERROR_SUCCESS, then we are sure that the file does not
  856. // exist. But, if it is we cannot be sure that the file exists.
  857. //
  858. ResponseStatus = DavQueryAndParseResponse(DavWorkItem->AsyncCreate.DavOpenHandle);
  859. if (ResponseStatus == ERROR_SUCCESS) {
  860. doesTheFileExist = TRUE;
  861. } else {
  862. //
  863. // Carry on only if http really didn't find it. Bailout if
  864. // there is some other error.
  865. //
  866. if (ResponseStatus == ERROR_FILE_NOT_FOUND) {
  867. doesTheFileExist = FALSE;
  868. } else {
  869. WStatus = ResponseStatus;
  870. goto EXIT_THE_FUNCTION;
  871. }
  872. }
  873. DavWorkItem->AsyncCreate.doesTheFileExist = doesTheFileExist;
  874. DavPrint((DEBUG_MISC,
  875. "DavAsyncCreate: doesTheFileExist = %d\n", doesTheFileExist));
  876. //
  877. // Since the file existed, the next thing we do is read the
  878. // XML response which contains the properties of the file.
  879. //
  880. DavWorkItem->DavMinorOperation = DavMinorReadData;
  881. }
  882. doesTheFileExist = DavWorkItem->AsyncCreate.doesTheFileExist;
  883. if (doesTheFileExist) {
  884. DWORD TotalDataBytesRead = 0;
  885. NumRead = DavWorkItem->AsyncCreate.didRead;
  886. DataBuff = DavWorkItem->AsyncCreate.DataBuff;
  887. Ctx1 = DavWorkItem->AsyncCreate.Context1;
  888. Ctx2 = DavWorkItem->AsyncCreate.Context2;
  889. do {
  890. switch (DavWorkItem->DavMinorOperation) {
  891. case DavMinorReadData:
  892. DavWorkItem->DavMinorOperation = DavMinorPushData;
  893. ReturnVal = InternetReadFile(DavWorkItem->AsyncCreate.DavOpenHandle,
  894. (LPVOID)DataBuff,
  895. NUM_OF_BYTES_TO_READ,
  896. NumRead);
  897. if (!ReturnVal) {
  898. WStatus = GetLastError();
  899. if (WStatus != ERROR_IO_PENDING) {
  900. DavCloseContext(Ctx1, Ctx2);
  901. DavPrint((DEBUG_ERRORS,
  902. "DavAsyncCreate/InternetReadFile. Error Val"
  903. " = %d\n", WStatus));
  904. }
  905. DavPrint((DEBUG_MISC,
  906. "DavAsyncCreate/InternetReadFile(1). "
  907. "ERROR_IO_PENDING.\n"));
  908. goto EXIT_THE_FUNCTION;
  909. }
  910. //
  911. // We reject files whose attributes are greater than a
  912. // certain size (DavFileAttributesLimitInBytes). This
  913. // is a parameter that can be set in the registry. This
  914. // is done to avoid attacks by rogue servers.
  915. //
  916. TotalDataBytesRead += *NumRead;
  917. if (TotalDataBytesRead > DavFileAttributesLimitInBytes) {
  918. WStatus = ERROR_BAD_NET_RESP;
  919. DavPrint((DEBUG_ERRORS, "DavAsyncCreate. FileAttributesSize > %d\n", DavFileAttributesLimitInBytes));
  920. goto EXIT_THE_FUNCTION;
  921. }
  922. //
  923. // Lack of break is intentional.
  924. //
  925. case DavMinorPushData:
  926. DavWorkItem->DavMinorOperation = DavMinorReadData;
  927. didRead = *NumRead;
  928. DavPrint((DEBUG_MISC,
  929. "DavAsyncCreate(1): toRead = %d, didRead = %d.\n",
  930. NUM_OF_BYTES_TO_READ, didRead));
  931. DavPrint((DEBUG_MISC,
  932. "DavAsyncCreate(1): DataBuff = %s\n", DataBuff));
  933. readDone = (didRead == 0) ? TRUE : FALSE;
  934. WStatus = DavPushData(DataBuff, &Ctx1, &Ctx2, didRead, readDone);
  935. if (WStatus != ERROR_SUCCESS) {
  936. DavPrint((DEBUG_ERRORS,
  937. "DavAsyncCreate/DavPushData. Error Val = %d\n",
  938. WStatus));
  939. goto EXIT_THE_FUNCTION;
  940. }
  941. if (DavWorkItem->AsyncCreate.Context1 == NULL) {
  942. DavWorkItem->AsyncCreate.Context1 = Ctx1;
  943. }
  944. if (DavWorkItem->AsyncCreate.Context2 == NULL) {
  945. DavWorkItem->AsyncCreate.Context2 = Ctx2;
  946. }
  947. break;
  948. default:
  949. WStatus = ERROR_INVALID_PARAMETER;
  950. DavPrint((DEBUG_ERRORS,
  951. "DavAsyncCreate. Invalid DavMinorOperation = %d.\n",
  952. DavWorkItem->DavMinorOperation));
  953. goto EXIT_THE_FUNCTION;
  954. break;
  955. }
  956. if (readDone) {
  957. break;
  958. }
  959. } while ( TRUE );
  960. //
  961. // We now need to parse the data.
  962. //
  963. DavFileAttributes = LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  964. sizeof(DAV_FILE_ATTRIBUTES) );
  965. if (DavFileAttributes == NULL) {
  966. DavCloseContext(Ctx1, Ctx2);
  967. WStatus = GetLastError();
  968. DavPrint((DEBUG_ERRORS,
  969. "DavAsyncCreate/LocalAlloc. Error Val = %d\n", WStatus));
  970. goto EXIT_THE_FUNCTION;
  971. }
  972. InitializeListHead( &(DavFileAttributes->NextEntry) );
  973. WStatus = DavParseData(DavFileAttributes, Ctx1, Ctx2, &NumOfFileEntries);
  974. if (WStatus != ERROR_SUCCESS) {
  975. DavFinalizeFileAttributesList(DavFileAttributes, TRUE);
  976. DavFileAttributes = NULL;
  977. DavPrint((DEBUG_ERRORS,
  978. "DavAsyncCreate/DavParseData. Error Val = %d\n",
  979. WStatus));
  980. goto EXIT_THE_FUNCTION;
  981. }
  982. //
  983. // Its possible to get a 207 response for the PROPFIND request
  984. // even if the request failed. In such a case the status value
  985. // in the XML response indicates the error. If this happens,
  986. // set InvalidNode to TRUE.
  987. //
  988. if (DavFileAttributes->InvalidNode) {
  989. WStatus = ERROR_INTERNAL_ERROR;
  990. DavPrint((DEBUG_ERRORS,
  991. "DavAsyncCreate. Invalid Node!! Status = %ws\n",
  992. DavFileAttributes->Status));
  993. DavFinalizeFileAttributesList(DavFileAttributes, TRUE);
  994. DavFileAttributes = NULL;
  995. goto EXIT_THE_FUNCTION;
  996. }
  997. //
  998. // If the file is being created for any kind of write access or
  999. // FILE_SHARE_WRITE is not a part of the shareaccess and the
  1000. // file has already been locked on the server, we need to fail
  1001. // this call with ERROR_LOCK_VIOLATION and copy the name of the
  1002. // LockOwner in the CreateResponse buffer.
  1003. //
  1004. if ( (CreateRequest->DesiredAccess & (GENERIC_WRITE | DELETE | GENERIC_ALL | FILE_WRITE_DATA | FILE_APPEND_DATA)) ||
  1005. !(CreateRequest->ShareAccess & FILE_SHARE_WRITE) ) {
  1006. if (DavFileAttributes->OpaqueLockToken) {
  1007. ASSERT(DavFileAttributes->LockOwner != NULL);
  1008. WStatus = ERROR_LOCK_VIOLATION;
  1009. CreateResponse->FileWasAlreadyLocked = TRUE;
  1010. wcscpy(CreateResponse->LockOwner, DavFileAttributes->LockOwner);
  1011. DavPrint((DEBUG_ERRORS,
  1012. "DavAsyncCreate: fileIsLocked!! LockOwner = %ws\n",
  1013. CreateResponse->LockOwner));
  1014. DavFinalizeFileAttributesList(DavFileAttributes, TRUE);
  1015. DavFileAttributes = NULL;
  1016. goto EXIT_THE_FUNCTION;
  1017. }
  1018. }
  1019. DavPrint((DEBUG_MISC,"DavAsyncCreate: NumOfFileEntries = %d\n", NumOfFileEntries));
  1020. //
  1021. // If this is a directory create and the intention is to delete
  1022. // it, we perform the following checks.
  1023. //
  1024. if ( (DavFileAttributes->isCollection) &&
  1025. (CreateRequest->DesiredAccess & DELETE ||
  1026. CreateRequest->CreateOptions & FILE_DELETE_ON_CLOSE)) {
  1027. PWCHAR CPN1 = NULL;
  1028. BOOL ServerShareDelete = TRUE;
  1029. DWORD wackCount = 0;
  1030. //
  1031. // If the delete is just for \\server\share then we return
  1032. // ERROR_ACCESS_DENIED. CompletePathName has the form
  1033. // \server\share\dir. If its \server\share or \server\share\,
  1034. // we return the error. This is because we do not allow
  1035. // a client to delete a share on the server.
  1036. //
  1037. CPN1 = CreateRequest->CompletePathName;
  1038. while ( *CPN1 != L'\0' ) {
  1039. if ( *CPN1 == L'\\' || *CPN1 == L'/' ) {
  1040. wackCount++;
  1041. if ( (wackCount > 2) && (*(CPN1 + 1) != L'\0') ) {
  1042. ServerShareDelete = FALSE;
  1043. break;
  1044. }
  1045. }
  1046. CPN1++;
  1047. }
  1048. if (ServerShareDelete) {
  1049. DavFinalizeFileAttributesList(DavFileAttributes, TRUE);
  1050. DavFileAttributes = NULL;
  1051. WStatus = ERROR_ACCESS_DENIED;
  1052. DavPrint((DEBUG_ERRORS, "DavAsyncCreate: ServerShareDelete & ERROR_ACCESS_DENIED\n"));
  1053. goto EXIT_THE_FUNCTION;
  1054. }
  1055. //
  1056. // If the directory is not empty, we return the following.
  1057. //
  1058. if (NumOfFileEntries > 1) {
  1059. DavFinalizeFileAttributesList(DavFileAttributes, TRUE);
  1060. DavFileAttributes = NULL;
  1061. WStatus = ERROR_DIR_NOT_EMPTY;
  1062. DavPrint((DEBUG_ERRORS, "DavAsyncCreate: ERROR_DIR_NOT_EMPTY\n"));
  1063. goto EXIT_THE_FUNCTION;
  1064. }
  1065. }
  1066. //
  1067. // During the create call, we only query the attributes for the file
  1068. // or the directory. Hence if the request succeeded, the number of
  1069. // DavFileAttribute entries created should be = 1. If it failed,
  1070. // the NumOfFileEntries == 0. The request could fail even if the
  1071. // response was "HTTP/1.1 207 Multi-Status". The status is returned
  1072. // in the XML response.
  1073. //
  1074. if (NumOfFileEntries != 1) {
  1075. PLIST_ENTRY listEntry = &(DavFileAttributes->NextEntry);
  1076. PDAV_FILE_ATTRIBUTES DavFA = NULL;
  1077. DavPrint((DEBUG_ERRORS,
  1078. "DavAsyncCreate. NumOfFileEntries = %d\n",
  1079. NumOfFileEntries));
  1080. do {
  1081. DavFA = CONTAINING_RECORD(listEntry, DAV_FILE_ATTRIBUTES, NextEntry);
  1082. DavPrint((DEBUG_MISC,
  1083. "DavAsyncCreate. FileName = %ws\n",
  1084. DavFA->FileName));
  1085. listEntry = listEntry->Flink;
  1086. } while ( listEntry != &(DavFileAttributes->NextEntry) );
  1087. DavFinalizeFileAttributesList(DavFileAttributes, TRUE);
  1088. DavFileAttributes = NULL;
  1089. doesTheFileExist = FALSE;
  1090. DavWorkItem->AsyncCreate.doesTheFileExist = FALSE;
  1091. }
  1092. }
  1093. if (doesTheFileExist) {
  1094. //
  1095. // Set the FILE_BASIC_INFORMATION.
  1096. //
  1097. CreateResponse->BasicInformation.CreationTime.HighPart =
  1098. DavFileAttributes->CreationTime.HighPart;
  1099. CreateResponse->BasicInformation.CreationTime.LowPart =
  1100. DavFileAttributes->CreationTime.LowPart;
  1101. CreateResponse->BasicInformation.LastAccessTime.HighPart =
  1102. DavFileAttributes->LastModifiedTime.HighPart;
  1103. CreateResponse->BasicInformation.LastAccessTime.LowPart =
  1104. DavFileAttributes->LastModifiedTime.LowPart;
  1105. CreateResponse->BasicInformation.LastWriteTime.HighPart =
  1106. DavFileAttributes->LastModifiedTime.HighPart;
  1107. CreateResponse->BasicInformation.LastWriteTime.LowPart =
  1108. DavFileAttributes->LastModifiedTime.LowPart;
  1109. CreateResponse->BasicInformation.ChangeTime.HighPart =
  1110. DavFileAttributes->LastModifiedTime.HighPart;
  1111. CreateResponse->BasicInformation.ChangeTime.LowPart =
  1112. DavFileAttributes->LastModifiedTime.LowPart;
  1113. CreateResponse->BasicInformation.FileAttributes = DavFileAttributes->dwFileAttributes;
  1114. DavPrint((DEBUG_MISC,
  1115. "DavAsyncCreate. attributes %x %ws\n",DavFileAttributes->dwFileAttributes,DavWorkItem->AsyncCreate.RemPathName));
  1116. if (DavFileAttributes->isHidden ||
  1117. (DavFileAttributes->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) {
  1118. CreateResponse->BasicInformation.FileAttributes |=
  1119. FILE_ATTRIBUTE_HIDDEN;
  1120. } else {
  1121. CreateResponse->BasicInformation.FileAttributes &=
  1122. ~FILE_ATTRIBUTE_HIDDEN;
  1123. }
  1124. if (DavFileAttributes->isCollection) {
  1125. CreateResponse->BasicInformation.FileAttributes |=
  1126. FILE_ATTRIBUTE_DIRECTORY;
  1127. } else {
  1128. CreateResponse->BasicInformation.FileAttributes &=
  1129. ~FILE_ATTRIBUTE_DIRECTORY;
  1130. }
  1131. //
  1132. // Set the FILE_STANDARD_INFORMATION.
  1133. //
  1134. CreateResponse->StandardInformation.AllocationSize.HighPart =
  1135. DavFileAttributes->FileSize.HighPart;
  1136. CreateResponse->StandardInformation.AllocationSize.LowPart =
  1137. DavFileAttributes->FileSize.LowPart;
  1138. CreateResponse->StandardInformation.EndOfFile.HighPart =
  1139. DavFileAttributes->FileSize.HighPart;
  1140. CreateResponse->StandardInformation.EndOfFile.LowPart =
  1141. DavFileAttributes->FileSize.LowPart;
  1142. CreateResponse->StandardInformation.NumberOfLinks = 0;
  1143. CreateResponse->StandardInformation.DeletePending = 0;
  1144. CreateResponse->StandardInformation.Directory =
  1145. DavFileAttributes->isCollection;
  1146. //
  1147. // We don't need the attributes list any more, so finalize it.
  1148. //
  1149. DavFinalizeFileAttributesList(DavFileAttributes, TRUE);
  1150. DavFileAttributes = NULL;
  1151. //
  1152. // CLose the XML parser contexts.
  1153. //
  1154. DavCloseContext(Ctx1, Ctx2);
  1155. DavWorkItem->AsyncCreate.Context1 = NULL;
  1156. DavWorkItem->AsyncCreate.Context2 = NULL;
  1157. }
  1158. //
  1159. // We are done with the Open handle to PROPFIND. Now we need to GET
  1160. // the file from the server.
  1161. //
  1162. InternetCloseHandle(DavWorkItem->AsyncCreate.DavOpenHandle);
  1163. DavWorkItem->AsyncCreate.DavOpenHandle = NULL;
  1164. ASSERT(didImpersonate);
  1165. WStatus = DavAsyncCreatePropFind(DavWorkItem);
  1166. } else if (DavWorkItem->AsyncCreate.AsyncCreateState == AsyncCreateQueryParentDirectory) {
  1167. ULONG ResponseStatus;
  1168. BOOL doesTheDirectoryExist = FALSE;
  1169. DWORD TotalDataBytesRead = 0;
  1170. //
  1171. // If the parent directory for which the PROPFIND was done do not have encryption flag set,
  1172. // the file will be created normally. Otherwise, the file will be encrypted when created.
  1173. //
  1174. DavPrint((DEBUG_MISC, "AsyncCreateQueryParentDirectory\n"));
  1175. NumRead = DavWorkItem->AsyncCreate.didRead;
  1176. DataBuff = DavWorkItem->AsyncCreate.DataBuff;
  1177. Ctx1 = DavWorkItem->AsyncCreate.Context1;
  1178. Ctx2 = DavWorkItem->AsyncCreate.Context2;
  1179. //
  1180. // Does this file exist ? If the ResponseStatus is not
  1181. // ERROR_SUCCESS, then we are sure that the file does not
  1182. // exist. But, if it is we cannot be sure that the file exists.
  1183. //
  1184. ResponseStatus = DavQueryAndParseResponse(DavWorkItem->AsyncCreate.DavOpenHandle);
  1185. if (ResponseStatus != ERROR_SUCCESS) {
  1186. //
  1187. // If the parent directory does not exist, return error.
  1188. //
  1189. WStatus = ResponseStatus;
  1190. DavPrint((DEBUG_ERRORS,
  1191. "DavAsyncCreate/QueryPDirectory/DavQueryAndParseResponse %x %d\n",WStatus,WStatus));
  1192. goto EXIT_THE_FUNCTION;
  1193. }
  1194. do {
  1195. ReturnVal = InternetReadFile(DavWorkItem->AsyncCreate.DavOpenHandle,
  1196. (LPVOID)DataBuff,
  1197. NUM_OF_BYTES_TO_READ,
  1198. NumRead);
  1199. if (!ReturnVal) {
  1200. WStatus = GetLastError();
  1201. if (WStatus != ERROR_IO_PENDING) {
  1202. DavCloseContext(Ctx1, Ctx2);
  1203. DavPrint((DEBUG_ERRORS,
  1204. "DavAsyncCreate/InternetReadFile. Error Val"
  1205. " = %d\n", WStatus));
  1206. }
  1207. DavPrint((DEBUG_MISC,
  1208. "DavAsyncCreate/InternetReadFile(1). "
  1209. "ERROR_IO_PENDING.\n"));
  1210. goto EXIT_THE_FUNCTION;
  1211. }
  1212. //
  1213. // We reject files whose attributes are greater than a
  1214. // certain size (DavFileAttributesLimitInBytes). This
  1215. // is a parameter that can be set in the registry. This
  1216. // is done to avoid attacks by rogue servers.
  1217. //
  1218. TotalDataBytesRead += *NumRead;
  1219. if (TotalDataBytesRead > DavFileAttributesLimitInBytes) {
  1220. WStatus = ERROR_BAD_NET_RESP;
  1221. DavPrint((DEBUG_ERRORS, "DavAsyncCreate. QueryParentAttributesSize > %d\n", DavFileAttributesLimitInBytes));
  1222. goto EXIT_THE_FUNCTION;
  1223. }
  1224. didRead = *NumRead;
  1225. DavPrint((DEBUG_MISC,
  1226. "DavAsyncCreate(1): toRead = %d, didRead = %d.\n",
  1227. NUM_OF_BYTES_TO_READ, didRead));
  1228. DavPrint((DEBUG_MISC,
  1229. "DavAsyncCreate(1): DataBuff = %s\n", DataBuff));
  1230. readDone = (didRead == 0) ? TRUE : FALSE;
  1231. WStatus = DavPushData(DataBuff, &Ctx1, &Ctx2, didRead, readDone);
  1232. if (WStatus != ERROR_SUCCESS) {
  1233. DavPrint((DEBUG_ERRORS,
  1234. "DavAsyncCreate/DavPushData. Error Val = %d\n",
  1235. WStatus));
  1236. goto EXIT_THE_FUNCTION;
  1237. }
  1238. if (DavWorkItem->AsyncCreate.Context1 == NULL) {
  1239. DavWorkItem->AsyncCreate.Context1 = Ctx1;
  1240. }
  1241. if (DavWorkItem->AsyncCreate.Context2 == NULL) {
  1242. DavWorkItem->AsyncCreate.Context2 = Ctx2;
  1243. }
  1244. } while (!readDone);
  1245. //
  1246. // We now need to parse the data.
  1247. //
  1248. DavDirectoryAttributes = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,sizeof(DAV_FILE_ATTRIBUTES));
  1249. if (DavDirectoryAttributes == NULL) {
  1250. DavCloseContext(Ctx1, Ctx2);
  1251. WStatus = GetLastError();
  1252. DavPrint((DEBUG_ERRORS,
  1253. "DavAsyncCreate/LocalAlloc. Error Val = %d\n", WStatus));
  1254. goto EXIT_THE_FUNCTION;
  1255. }
  1256. InitializeListHead( &(DavDirectoryAttributes->NextEntry) );
  1257. WStatus = DavParseData(DavDirectoryAttributes, Ctx1, Ctx2, &NumOfFileEntries);
  1258. if (WStatus != ERROR_SUCCESS) {
  1259. DavPrint((DEBUG_ERRORS,
  1260. "DavAsyncCreate/DavParseData. Error Val = %d\n",
  1261. WStatus));
  1262. goto EXIT_THE_FUNCTION;
  1263. }
  1264. if ((CreateRequest->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ||
  1265. (DavDirectoryAttributes->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  1266. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1267. DavPrint((DEBUG_MISC,
  1268. "DavAsyncCreate: ParentDirectory Is Encrypted\n"));
  1269. } else {
  1270. DavPrint((DEBUG_MISC,
  1271. "DavAsyncCreate: ParentDirectory Is Not Encrypted\n"));
  1272. }
  1273. DavFinalizeFileAttributesList(DavDirectoryAttributes, TRUE);
  1274. DavDirectoryAttributes = NULL;
  1275. DavCloseContext(Ctx1, Ctx2);
  1276. DavWorkItem->AsyncCreate.Context1 = NULL;
  1277. DavWorkItem->AsyncCreate.Context2 = NULL;
  1278. ASSERT(didImpersonate == TRUE);
  1279. WStatus = DavAsyncCreateQueryParentDirectory(DavWorkItem);
  1280. } else if (DavWorkItem->AsyncCreate.AsyncCreateState == AsyncCreateGet) {
  1281. LARGE_INTEGER ByteOffset;
  1282. ULONG BytesToRead;
  1283. BOOL EncryptedFile = FALSE, ZeroByteFile = FALSE;
  1284. FILE_STANDARD_INFORMATION FileStdInfo;
  1285. ULONG ResponseStatus;
  1286. ResponseStatus = DavQueryAndParseResponse(DavWorkItem->AsyncCreate.DavOpenHandle);
  1287. if (ResponseStatus != ERROR_SUCCESS) {
  1288. WStatus = ResponseStatus;
  1289. DavPrint((DEBUG_ERRORS,
  1290. "DavAsyncCreate(AsyncCreateGet)/DavQueryAndParseResponse: WStatus = %d\n",
  1291. WStatus));
  1292. goto EXIT_THE_FUNCTION;
  1293. }
  1294. //
  1295. // This thread is currently impersonating the client that
  1296. // made this request. Before we call CreateFile, we need to
  1297. // revert back to the context of the Web Client service.
  1298. //
  1299. RevertToSelf();
  1300. didImpersonate = FALSE;
  1301. if (DavReuseCacheFileIfNotModified(DavWorkItem) == ERROR_SUCCESS)
  1302. {
  1303. fCacheFileReused = TRUE;
  1304. }
  1305. if (!fCacheFileReused)
  1306. {
  1307. //
  1308. // Call DavCreateUrlCacheEntry to create an entry in the
  1309. // WinInet's cache.
  1310. //
  1311. WStatus = DavCreateUrlCacheEntry(DavWorkItem);
  1312. if (WStatus != ERROR_SUCCESS) {
  1313. DavPrint((DEBUG_ERRORS,
  1314. "DavAsyncCreate/DavCreateUrlCacheEntry %d\n",
  1315. WStatus));
  1316. goto EXIT_THE_FUNCTION;
  1317. }
  1318. }
  1319. if (DavWorkItem->AsyncCreate.FileHandle == NULL) {
  1320. //
  1321. // Create a handle to the file whose entry was created in the
  1322. // cache.
  1323. //
  1324. FileHandle = CreateFileW(DavWorkItem->AsyncCreate.FileName,
  1325. (GENERIC_READ | GENERIC_WRITE),
  1326. FILE_SHARE_WRITE,
  1327. NULL,
  1328. OPEN_EXISTING,
  1329. FILE_ATTRIBUTE_NORMAL,
  1330. NULL);
  1331. if (FileHandle == INVALID_HANDLE_VALUE) {
  1332. WStatus = GetLastError();
  1333. DavPrint((DEBUG_ERRORS,
  1334. "DavAsyncCreate/CreateFile. Error Val = %d\n",
  1335. WStatus));
  1336. goto EXIT_THE_FUNCTION;
  1337. }
  1338. DavWorkItem->AsyncCreate.FileHandle = FileHandle;
  1339. //
  1340. // Impersonate back again, so that we are in the context of
  1341. // the user who issued this request.
  1342. //
  1343. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  1344. if (WStatus != ERROR_SUCCESS) {
  1345. DavPrint((DEBUG_ERRORS,
  1346. "DavAsyncCreate/UMReflectorImpersonate. "
  1347. "Error Val = %d\n", WStatus));
  1348. goto EXIT_THE_FUNCTION;
  1349. }
  1350. didImpersonate = TRUE;
  1351. }
  1352. FileHandle = DavWorkItem->AsyncCreate.FileHandle;
  1353. DataBuff = DavWorkItem->AsyncCreate.DataBuff;
  1354. NumRead = DavWorkItem->AsyncCreate.didRead;
  1355. if (!fCacheFileReused)
  1356. {
  1357. DWORD TotalDataBytesRead = 0;
  1358. do {
  1359. switch (DavWorkItem->DavMinorOperation) {
  1360. case DavMinorReadData:
  1361. DavWorkItem->DavMinorOperation = DavMinorWriteData;
  1362. ReturnVal = InternetReadFile(DavWorkItem->AsyncCreate.DavOpenHandle,
  1363. (LPVOID)DataBuff,
  1364. NUM_OF_BYTES_TO_READ,
  1365. NumRead);
  1366. if (!ReturnVal) {
  1367. WStatus = GetLastError();
  1368. if (WStatus != ERROR_IO_PENDING) {
  1369. DavPrint((DEBUG_ERRORS,
  1370. "DavAsyncCreate/InternetReadFile. Error Val"
  1371. " = %08lx.\n", WStatus));
  1372. }
  1373. DavPrint((DEBUG_MISC,
  1374. "DavAsyncCreate/InternetReadFile(2). "
  1375. "ERROR_IO_PENDING.\n"));
  1376. goto EXIT_THE_FUNCTION;
  1377. }
  1378. //
  1379. // We reject files which are greater than a certain
  1380. // size (DavFileSizeLimitInBytes). This is a parameter
  1381. // that can be set in the registry. This is done to
  1382. // avoid attacks by rogue servers.
  1383. //
  1384. TotalDataBytesRead += *NumRead;
  1385. if (TotalDataBytesRead > DavFileSizeLimitInBytes) {
  1386. WStatus = ERROR_BAD_NET_RESP;
  1387. DavPrint((DEBUG_ERRORS, "DavAsyncCreate. FileSize > %d\n", DavFileSizeLimitInBytes));
  1388. goto EXIT_THE_FUNCTION;
  1389. }
  1390. //
  1391. // Lack of break is intentional.
  1392. //
  1393. case DavMinorWriteData:
  1394. DavWorkItem->DavMinorOperation = DavMinorReadData;
  1395. didRead = *NumRead;
  1396. DavPrint((DEBUG_MISC,
  1397. "DavAsyncCreate(2): toRead = %d, didRead = %d.\n",
  1398. NUM_OF_BYTES_TO_READ, didRead));
  1399. readDone = (didRead == 0) ? TRUE : FALSE;
  1400. if (readDone) {
  1401. break;
  1402. }
  1403. //
  1404. // This thread is currently impersonating the client that
  1405. // made this request. Before we call WriteFile, we need to
  1406. // revert back to the context of the Web Client service.
  1407. //
  1408. RevertToSelf();
  1409. didImpersonate = FALSE;
  1410. //
  1411. // Write the buffer to the file which has been cached on
  1412. // persistent storage.
  1413. //
  1414. ReturnVal = WriteFile(FileHandle, DataBuff, didRead, &didWrite, NULL);
  1415. if (!ReturnVal) {
  1416. WStatus = GetLastError();
  1417. DavPrint((DEBUG_ERRORS,
  1418. "DavAsyncCreate/WriteFile. Error Val = %d\n", WStatus));
  1419. goto EXIT_THE_FUNCTION;
  1420. }
  1421. ASSERT(didRead == didWrite);
  1422. //
  1423. // Impersonate back again, so that we are in the context of
  1424. // the user who issued this request.
  1425. //
  1426. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  1427. if (WStatus != ERROR_SUCCESS) {
  1428. DavPrint((DEBUG_ERRORS,
  1429. "DavAsyncCreate/UMReflectorImpersonate. "
  1430. "Error Val = %d\n", WStatus));
  1431. goto EXIT_THE_FUNCTION;
  1432. }
  1433. didImpersonate = TRUE;
  1434. break;
  1435. default:
  1436. WStatus = ERROR_INVALID_PARAMETER;
  1437. DavPrint((DEBUG_ERRORS,
  1438. "DavAsyncCreate. Invalid DavMinorOperation = %d.\n",
  1439. DavWorkItem->DavMinorOperation));
  1440. goto EXIT_THE_FUNCTION;
  1441. break;
  1442. }
  1443. if (readDone) {
  1444. break;
  1445. }
  1446. } while ( TRUE );
  1447. }
  1448. //
  1449. // At this point, we have read the entire file.
  1450. // We need to figure out if this is an encrypted file.
  1451. // If it is, we need to RESTORE it, since it was stored as a
  1452. // Backup stream on the server. We read the first 100 bytes of the
  1453. // file to check for the EFS signature.
  1454. //
  1455. //
  1456. // This thread could be currently impersonating the client that made
  1457. // this request. Before we call ReadFile, we need to revert back to
  1458. // the context of the Web Client service.
  1459. //
  1460. if (didImpersonate) {
  1461. RevertToSelf();
  1462. didImpersonate = FALSE;
  1463. }
  1464. //
  1465. // Set the last access time on the URL Cache so that we can avoid
  1466. // a GET on subsequent Create's if the file has not changed on the
  1467. // server.
  1468. //
  1469. if (!fCacheFileReused) {
  1470. //
  1471. // Commit to the cache only if it is not being reused. If it
  1472. // is being reused, it has already been committed on a previous
  1473. // Create.
  1474. //
  1475. WStatus = DavCommitUrlCacheEntry(DavWorkItem);
  1476. if (WStatus != ERROR_SUCCESS) {
  1477. DavPrint((DEBUG_ERRORS,
  1478. "DavAsyncCreate/DavCommitUrlCacheEntry(2). "
  1479. "WStatus = %d\n", WStatus));
  1480. goto EXIT_THE_FUNCTION;
  1481. }
  1482. if (CreateResponse->BasicInformation.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  1483. //
  1484. // Set the ACLs on the file, so that it can be accessed
  1485. // after impersonating the user whoc is creating it.
  1486. //
  1487. WStatus = DavSetAclForEncryptedFile(DavWorkItem->AsyncCreate.FileName);
  1488. if (WStatus != ERROR_SUCCESS) {
  1489. DavPrint((DEBUG_ERRORS,
  1490. "DavAsyncCreate/DavSetAclForEncryptedFile(1). Error Val = %d, FileName = %ws\n",
  1491. WStatus, DavWorkItem->AsyncCreate.FileName));
  1492. goto EXIT_THE_FUNCTION;
  1493. }
  1494. }
  1495. }
  1496. WStatus = DavQueryUrlCacheEntry(DavWorkItem);
  1497. if (WStatus == ERROR_SUCCESS) {
  1498. SYSTEMTIME SystemTime;
  1499. GetSystemTime(&SystemTime);
  1500. SystemTimeToFileTime(
  1501. &SystemTime,
  1502. &((LPINTERNET_CACHE_ENTRY_INFOW)DavWorkItem->AsyncCreate.lpCEI)->LastAccessTime);
  1503. DavPrint((DEBUG_MISC,
  1504. "DavAsyncCreate/SetUrlCacheEntryInfo %u %ws\n",
  1505. ((LPINTERNET_CACHE_ENTRY_INFOW)DavWorkItem->AsyncCreate.lpCEI)->LastAccessTime.dwLowDateTime,
  1506. DavWorkItem->AsyncCreate.UrlBuffer));
  1507. SetUrlCacheEntryInfo(
  1508. DavWorkItem->AsyncCreate.UrlBuffer,
  1509. (LPINTERNET_CACHE_ENTRY_INFOW)DavWorkItem->AsyncCreate.lpCEI,
  1510. CACHE_ENTRY_ACCTIME_FC);
  1511. }
  1512. WStatus = DavAsyncCreateGet(DavWorkItem);
  1513. } else if (DavWorkItem->AsyncCreate.AsyncCreateState == AsyncCreateMkCol) {
  1514. WStatus = DavQueryAndParseResponse(DavWorkItem->AsyncCreate.DavOpenHandle);
  1515. if (WStatus != ERROR_SUCCESS) {
  1516. goto EXIT_THE_FUNCTION;
  1517. }
  1518. WStatus = ERROR_SUCCESS;
  1519. } else {
  1520. ASSERT(DavWorkItem->AsyncCreate.AsyncCreateState == AsyncCreatePut);
  1521. WStatus = DavQueryAndParseResponse(DavWorkItem->AsyncCreate.DavOpenHandle);
  1522. if (WStatus != ERROR_SUCCESS) {
  1523. goto EXIT_THE_FUNCTION;
  1524. }
  1525. //
  1526. // The CreateResponse structure has already been set. All we need to
  1527. // do now is return.
  1528. //
  1529. WStatus = ERROR_SUCCESS;
  1530. }
  1531. }
  1532. break;
  1533. default: {
  1534. WStatus = ERROR_INVALID_PARAMETER;
  1535. DavPrint((DEBUG_ERRORS,
  1536. "DavAsyncCreate: Invalid DavWorkItem->DavOperation = %d.\n",
  1537. DavWorkItem->DavOperation));
  1538. }
  1539. break;
  1540. } // End of switch.
  1541. EXIT_THE_FUNCTION:
  1542. //
  1543. // Free the pEncryptedCachedFile since we have allocated a new file name
  1544. // for the restored encrypted file.
  1545. //
  1546. if (pEncryptedCachedFile) {
  1547. LocalFree(pEncryptedCachedFile);
  1548. }
  1549. if (DavDirectoryAttributes) {
  1550. DavFinalizeFileAttributesList(DavDirectoryAttributes, TRUE);
  1551. DavDirectoryAttributes = NULL;
  1552. }
  1553. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  1554. //
  1555. // If we did impersonate, we need to revert back.
  1556. //
  1557. if (didImpersonate) {
  1558. ULONG RStatus;
  1559. RStatus = UMReflectorRevert(UserWorkItem);
  1560. if (RStatus != ERROR_SUCCESS) {
  1561. DavPrint((DEBUG_ERRORS,
  1562. "DavAsyncCreate/UMReflectorRevert. Error Val = %d\n",
  1563. RStatus));
  1564. }
  1565. }
  1566. //
  1567. // Some resources should not be freed if we are returning ERROR_IO_PENDING
  1568. // because they will be used in the callback functions.
  1569. //
  1570. if ( WStatus != ERROR_IO_PENDING && CalledByCallBackThread ) {
  1571. DavPrint((DEBUG_MISC, "DavAsyncCreate: Leaving!!! WStatus = %08lx\n", WStatus));
  1572. //
  1573. // Set the return status of the operation. This is used by the kernel
  1574. // mode routines to figure out the completion status of the user mode
  1575. // request.
  1576. //
  1577. if (WStatus != ERROR_SUCCESS) {
  1578. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  1579. } else {
  1580. DavWorkItem->Status = STATUS_SUCCESS;
  1581. }
  1582. //
  1583. // Call the AsyncCreateCompletion routine.
  1584. //
  1585. DavAsyncCreateCompletion(DavWorkItem);
  1586. //
  1587. // This thread now needs to send the response back to the kernel. It
  1588. // does not wait in the kernel (to get another request) after submitting
  1589. // the response.
  1590. //
  1591. UMReflectorCompleteRequest(DavReflectorHandle, UserWorkItem);
  1592. }
  1593. if (WStatus == ERROR_IO_PENDING ) {
  1594. DavPrint((DEBUG_MISC, "DavAsyncCreate: Returning ERROR_IO_PENDING.\n"));
  1595. }
  1596. #else
  1597. //
  1598. // If we are using WinInet synchronously, we need to impersonate the client
  1599. // if we somehow reverted in between and failed. This is because we came
  1600. // into this function impersonating a client and the final revert happens
  1601. // in DavFsCreate.
  1602. //
  1603. if ( !didImpersonate ) {
  1604. ULONG IStatus;
  1605. IStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  1606. if (IStatus != ERROR_SUCCESS) {
  1607. DavPrint((DEBUG_ERRORS,
  1608. "DavAsyncCreate/UMReflectorImpersonate. "
  1609. "Error Val = %d\n", IStatus));
  1610. }
  1611. }
  1612. #endif
  1613. return WStatus;
  1614. }
  1615. DWORD
  1616. DavAsyncCreatePropFind(
  1617. PDAV_USERMODE_WORKITEM DavWorkItem
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. This routine handles the Get completion.
  1622. Arguments:
  1623. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  1624. Return Value:
  1625. none.
  1626. --*/
  1627. {
  1628. ULONG WStatus = ERROR_SUCCESS;
  1629. NTSTATUS NtStatus = STATUS_SUCCESS;
  1630. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  1631. BOOL ReturnVal, didImpersonate = TRUE;
  1632. BOOL doesTheFileExist = FALSE;
  1633. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  1634. PDAV_USERMODE_CREATE_REQUEST CreateRequest;
  1635. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  1636. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  1637. PWCHAR ParentDirectoryName = NULL;
  1638. BOOL BStatus = FALSE;
  1639. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  1640. //
  1641. // Get the request and response buffer pointers from the DavWorkItem.
  1642. //
  1643. CreateRequest = &(DavWorkItem->CreateRequest);
  1644. CreateResponse = &(DavWorkItem->CreateResponse);
  1645. CreateResponse->fPsuedoOpen = FALSE;
  1646. doesTheFileExist = DavWorkItem->AsyncCreate.doesTheFileExist;
  1647. DavPrint((DEBUG_MISC,
  1648. "DavAsyncCreatePropFind: DesiredAccess = %x, FileAttributes = %x,"
  1649. "ShareAccess = %x, CreateDisposition = %x, CreateOptions = %x,"
  1650. "FileName = %ws\n",
  1651. CreateRequest->DesiredAccess, CreateRequest->FileAttributes,
  1652. CreateRequest->ShareAccess, CreateRequest->CreateDisposition,
  1653. CreateRequest->CreateOptions, CreateRequest->CompletePathName));
  1654. //
  1655. // We don't support compression of files or directories over the
  1656. // DAV Redir since there is no way to do this with the current status
  1657. // of the protocol (Jan 2001) and hence we filter this flag so that
  1658. // we never set any attributes. Also, for this version ,we are
  1659. // emulating FAT which doesn't support compression. Similarly we don't
  1660. // support the Offline scenario.
  1661. //
  1662. CreateRequest->FileAttributes &= ~(FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_OFFLINE);
  1663. //
  1664. // If this file is a new file (not a directory), then according to
  1665. // functionality expected from CreateFile, FILE_ATTRIBUTE_ARCHIVE
  1666. // should be combined with specified value of attributes.
  1667. //
  1668. if ( (doesTheFileExist == FALSE) &&
  1669. !(CreateRequest->CreateOptions & (FILE_DIRECTORY_FILE)) ) {
  1670. CreateRequest->FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
  1671. }
  1672. //
  1673. // If the file exists, we need to make sure that a few things are
  1674. // right before proceeding further.
  1675. //
  1676. if (doesTheFileExist) {
  1677. //
  1678. // If the dwFileAttributes had the READ_ONLY bit set, then
  1679. // these cannot be TRUE.
  1680. // 1. CreateDisposition cannot be FILE_OVERWRITE_IF or
  1681. // FILE_OVERWRITE or FILE_SUPERSEDE.
  1682. // 2. CreateDisposition cannot be FILE_DELETE_ON_CLOSE.
  1683. // 3. DesiredAccess cannot be GENERIC_ALL or GENERIC_WRITE or
  1684. // FILE_WRITE_DATA or FILE_APPEND_DATA.
  1685. // This is because these intend to overwrite the existing file.
  1686. //
  1687. if ( (CreateResponse->BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) &&
  1688. ( (CreateRequest->CreateDisposition == FILE_OVERWRITE) ||
  1689. (CreateRequest->CreateDisposition == FILE_OVERWRITE_IF) ||
  1690. (CreateRequest->CreateDisposition == FILE_SUPERSEDE) ||
  1691. (CreateRequest->CreateOptions & (FILE_DELETE_ON_CLOSE) ||
  1692. (CreateRequest->DesiredAccess & (GENERIC_ALL | GENERIC_WRITE | FILE_WRITE_DATA | FILE_APPEND_DATA)) ) ) ) {
  1693. DavPrint((DEBUG_MISC,
  1694. "DavAsyncCreatePropFind: Object Mismatch!!! CreateDisposition = "
  1695. "%d, DesiredAccess = %x, dwFileAttributes = %x\n",
  1696. CreateRequest->CreateDisposition,
  1697. CreateRequest->DesiredAccess,
  1698. CreateResponse->BasicInformation.FileAttributes));
  1699. WStatus = ERROR_ACCESS_DENIED; // mismatch
  1700. goto EXIT_THE_FUNCTION;
  1701. }
  1702. //
  1703. // If the file is a directory and the caller supplied
  1704. // FILE_NON_DIRECTORY_FILE as one of the CreateOptions or if the
  1705. // file as a file and the CreateOptions has FILE_DIRECTORY_FILE
  1706. // then we return error. There is no good WIN32 errors for these situations.
  1707. // ERROR_ACCESS_DENIED will cause confusion for EFS.
  1708. //
  1709. if ((CreateRequest->CreateOptions & FILE_DIRECTORY_FILE) &&
  1710. !CreateResponse->StandardInformation.Directory) {
  1711. DavPrint((DEBUG_MISC,
  1712. "DavAsyncCreatePropFind: Object Mismatch!!! CreateOptions = "
  1713. "%x, CreateResponse = %x\n",
  1714. CreateRequest->CreateOptions, CreateResponse->BasicInformation.FileAttributes));
  1715. WStatus = STATUS_NOT_A_DIRECTORY; // mismatch
  1716. goto EXIT_THE_FUNCTION;
  1717. }
  1718. if ((CreateRequest->CreateOptions & FILE_NON_DIRECTORY_FILE) &&
  1719. CreateResponse->StandardInformation.Directory) {
  1720. DavPrint((DEBUG_MISC,
  1721. "DavAsyncCreatePropFind: Object Mismatch!!! CreateOptions = "
  1722. "%x, CreateResponse = %x\n",
  1723. CreateRequest->CreateOptions, CreateResponse->BasicInformation.FileAttributes));
  1724. WStatus = STATUS_FILE_IS_A_DIRECTORY; // mismatch
  1725. goto EXIT_THE_FUNCTION;
  1726. }
  1727. }
  1728. //
  1729. // We LOCK the resource if the following conditions are TRUE.
  1730. // 1. The resource already exists on the server AND,
  1731. // 2. The resource being opened is a file and NOT a directory AND,
  1732. // 3. The SharedMode is 0 (exclusive) OR FILE_SHARE_READ OR the file is
  1733. // being opened for write access.
  1734. //
  1735. if (DavSupportLockingOfFiles) {
  1736. if (doesTheFileExist && !CreateResponse->StandardInformation.Directory) {
  1737. if ( (CreateRequest->ShareAccess == 0) || (CreateRequest->ShareAccess == FILE_SHARE_READ) ||
  1738. (CreateRequest->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE | GENERIC_ALL)) ) {
  1739. WStatus = DavLockTheFileOnTheServer(DavWorkItem);
  1740. if (WStatus != ERROR_SUCCESS) {
  1741. DavPrint((DEBUG_ERRORS,
  1742. "DavAsyncCreatePropFind/DavLockTheFileOnTheServer. WStatus = %08lx\n",
  1743. WStatus));
  1744. goto EXIT_THE_FUNCTION;
  1745. }
  1746. }
  1747. }
  1748. }
  1749. //
  1750. // If the file exists, we need to set the information field if the
  1751. // CreateDisposition is one of the following. This is because the
  1752. // CreateFile API expects these values to be set on return.
  1753. //
  1754. if (doesTheFileExist) {
  1755. switch (CreateRequest->CreateDisposition) {
  1756. case FILE_OVERWRITE:
  1757. case FILE_OVERWRITE_IF:
  1758. DavWorkItem->Information = FILE_OVERWRITTEN;
  1759. break;
  1760. case FILE_SUPERSEDE:
  1761. DavWorkItem->Information = FILE_SUPERSEDED;
  1762. break;
  1763. default:
  1764. DavWorkItem->Information = FILE_OPENED;
  1765. }
  1766. } else {
  1767. DavWorkItem->Information = FILE_CREATED;
  1768. }
  1769. //
  1770. // If the file does not exist on the server, create one locally.
  1771. // Once its closed, we will PUT it on the server. If the file
  1772. // exists on the server, and the CreateDisposition is equal to
  1773. // FILE_OVERWRITE_IF, we create a copy locally and PUT it on the
  1774. // server (overwrite) on close.
  1775. //
  1776. if ( ( !doesTheFileExist ) ||
  1777. ( doesTheFileExist && CreateRequest->CreateDisposition == FILE_OVERWRITE_IF ) ) {
  1778. DWORD NameLength = 0, i;
  1779. BOOL BackSlashFound = FALSE;
  1780. DavPrint((DEBUG_MISC, "DavAsyncCreatePropFind: doesTheFileExist = "
  1781. "%d, CreateDisposition = %d\n",
  1782. doesTheFileExist, CreateRequest->CreateDisposition));
  1783. DavPrint((DEBUG_MISC, "DavAsyncCreatePropFind: CreateOptions = %d\n",
  1784. CreateRequest->CreateOptions));
  1785. //
  1786. // We need to check the CreateDisposition value to figure
  1787. // out what to do next.
  1788. //
  1789. switch (CreateRequest->CreateDisposition) {
  1790. //
  1791. // If FILE_OPEN was specified, we need to return failure
  1792. // since the specified file does not exist.
  1793. //
  1794. case FILE_OPEN:
  1795. WStatus = ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
  1796. DavPrint((DEBUG_MISC,
  1797. "DavAsyncCreatePropFind. CreateDisposition & FILE_OPEN\n"));
  1798. goto EXIT_THE_FUNCTION;
  1799. //
  1800. // If FILE_OVERWRITE was specified, we need to return failure
  1801. // since the specified file does not exist.
  1802. //
  1803. case FILE_OVERWRITE:
  1804. WStatus = ERROR_FILE_NOT_FOUND; // STATUS_OBJECT_NAME_NOT_FOUND;
  1805. DavPrint((DEBUG_MISC,
  1806. "DavAsyncCreatePropFind. CreateDisposition & FILE_OVERWRITE\n"));
  1807. goto EXIT_THE_FUNCTION;
  1808. default:
  1809. break;
  1810. }
  1811. if (CreateRequest->ParentDirInfomationCached ||
  1812. (CreateRequest->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  1813. //
  1814. // Since we already know whether to encrypt the file, we don't need
  1815. // to query the parent directory.
  1816. //
  1817. if (CreateRequest->ParentDirIsEncrypted ||
  1818. (CreateRequest->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  1819. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  1820. }
  1821. BStatus = DavHttpOpenRequestW(DavWorkItem->AsyncCreate.PerUserEntry->DavConnHandle,
  1822. L"PROPFIND",
  1823. L"",
  1824. L"HTTP/1.1",
  1825. NULL,
  1826. NULL,
  1827. INTERNET_FLAG_KEEP_CONNECTION |
  1828. INTERNET_FLAG_NO_COOKIES,
  1829. CallBackContext,
  1830. L"DavAsyncCreatePropFind",
  1831. &(DavWorkItem->AsyncCreate.DavOpenHandle));
  1832. if(BStatus == FALSE) {
  1833. WStatus = GetLastError();
  1834. DavPrint((DEBUG_ERRORS,
  1835. "DavAsyncCreatePropFind/DavHttpOpenRequestW failed %x %d\n",WStatus,WStatus));
  1836. goto EXIT_THE_FUNCTION;
  1837. }
  1838. ASSERT(didImpersonate == TRUE);
  1839. WStatus = DavAsyncCreateQueryParentDirectory(DavWorkItem);
  1840. } else {
  1841. //
  1842. // We need to query the attributes of the parent directory of this new file
  1843. // on the server. If it is encrypted, the new file needs to be encrypted as well.
  1844. //
  1845. DavPrint((DEBUG_MISC,
  1846. "DavAsyncCreatePropFind: Query Parent Directory for %ws\n",DavWorkItem->AsyncCreate.RemPathName));
  1847. NameLength = wcslen(DavWorkItem->AsyncCreate.RemPathName);
  1848. for (i=NameLength;i>0;i--) {
  1849. if (DavWorkItem->AsyncCreate.RemPathName[i] == L'/') {
  1850. BackSlashFound = TRUE;
  1851. break;
  1852. }
  1853. }
  1854. if (!BackSlashFound) {
  1855. DavPrint((DEBUG_ERRORS,
  1856. "DavAsyncCreatePropFind: Invalid file path %ws\n",DavWorkItem->AsyncCreate.RemPathName));
  1857. WStatus = ERROR_INVALID_PARAMETER;
  1858. goto EXIT_THE_FUNCTION;
  1859. }
  1860. ParentDirectoryName = (PWCHAR)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, (i+1)*sizeof(WCHAR));
  1861. if (ParentDirectoryName == NULL) {
  1862. WStatus = GetLastError();
  1863. DavPrint((DEBUG_ERRORS,
  1864. "DavAsyncCreatePropFind/LocalAlloc. Error Val = %d\n",
  1865. WStatus));
  1866. goto EXIT_THE_FUNCTION;
  1867. }
  1868. RtlCopyMemory(ParentDirectoryName,
  1869. DavWorkItem->AsyncCreate.RemPathName,
  1870. i*sizeof(WCHAR));
  1871. DavPrint((DEBUG_MISC,
  1872. "DavAsyncCreatePropFind/ParentDirectoryName %ws\n",ParentDirectoryName));
  1873. //
  1874. // Set the DavOperation and AsyncCreateState values.For PUT
  1875. // the DavMinorOperation value is irrelavant.
  1876. //
  1877. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  1878. DavWorkItem->AsyncCreate.AsyncCreateState = AsyncCreateQueryParentDirectory;
  1879. DavWorkItem->DavMinorOperation = DavMinorQueryInfo;
  1880. //
  1881. // Convert the unicode object name to UTF-8 URL format.
  1882. // Space and other white characters will remain untouched.
  1883. // These should be taken care of by wininet calls.
  1884. //
  1885. BStatus = DavHttpOpenRequestW(DavWorkItem->AsyncCreate.PerUserEntry->DavConnHandle,
  1886. L"PROPFIND",
  1887. ParentDirectoryName,
  1888. L"HTTP/1.1",
  1889. NULL,
  1890. NULL,
  1891. INTERNET_FLAG_KEEP_CONNECTION |
  1892. INTERNET_FLAG_NO_COOKIES,
  1893. CallBackContext,
  1894. L"DavAsyncCreate",
  1895. &(DavWorkItem->AsyncCreate.DavOpenHandle));
  1896. if(BStatus == FALSE) {
  1897. WStatus = GetLastError();
  1898. DavPrint((DEBUG_ERRORS,
  1899. "DavAsyncCreatePropFind/DavHttpOpenRequestW failed %x %d\n",WStatus,WStatus));
  1900. goto EXIT_THE_FUNCTION;
  1901. }
  1902. if (DavWorkItem->AsyncCreate.DavOpenHandle == NULL) {
  1903. WStatus = GetLastError();
  1904. if (WStatus != ERROR_IO_PENDING) {
  1905. DavPrint((DEBUG_ERRORS,
  1906. "DavAsyncCreatePropFind/HttpOpenRequestW"
  1907. ". Error Val = %d\n", WStatus));
  1908. }
  1909. goto EXIT_THE_FUNCTION;
  1910. }
  1911. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  1912. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  1913. DavPrint((DEBUG_ERRORS,
  1914. "DavAsyncCreatePropFind/DavAsyncCommonStates(PUT). "
  1915. "Error Val = %08lx\n", WStatus));
  1916. }
  1917. }
  1918. goto EXIT_THE_FUNCTION;
  1919. } else {
  1920. //
  1921. // The file exists on the server and the value of CreateDisposition !=
  1922. // FILE_OVERWRITE_IF.
  1923. //
  1924. //
  1925. // We return failure if FILE_CREATE was specified since the
  1926. // file already exists.
  1927. //
  1928. if (CreateRequest->CreateDisposition == FILE_CREATE) {
  1929. WStatus = ERROR_ALREADY_EXISTS; // STATUS_OBJECT_NAME_COLLISION
  1930. DavPrint((DEBUG_ERRORS,
  1931. "DavAsyncCreate. CreateDisposition & FILE_CREATE\n"));
  1932. goto EXIT_THE_FUNCTION;
  1933. }
  1934. }
  1935. //
  1936. // If "FILE_DELETE_ON_CLOSE" flag was specified as one of
  1937. // the CreateOptions, then we need to remember this and
  1938. // delete this file on close.
  1939. //
  1940. if (CreateRequest->CreateOptions & FILE_DELETE_ON_CLOSE) {
  1941. DavPrint((DEBUG_MISC,
  1942. "DavAsyncCreatePropFind: FileName: %ws. FILE_DELETE_ON_CLOSE.\n",
  1943. DavWorkItem->AsyncCreate.RemPathName));
  1944. CreateResponse->DeleteOnClose = TRUE;
  1945. }
  1946. //
  1947. // In some cases, we don't need to do a GET.
  1948. //
  1949. if (CreateResponse->StandardInformation.Directory) {
  1950. //
  1951. // We do not need to GET a directory.
  1952. //
  1953. goto EXIT_THE_FUNCTION;
  1954. } else if (!(CreateResponse->BasicInformation.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  1955. (CreateRequest->DesiredAccess &
  1956. ~(SYNCHRONIZE | DELETE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES)) == 0 ) {
  1957. //
  1958. // If we don't need to GET the file from the server because the
  1959. // user doesn't intend to manipulate the data, we return right
  1960. // now. We call such an open a Pseudo open.Set the fPsuedoOpen
  1961. // field to TRUE in the CreateResponse.
  1962. //
  1963. CreateResponse->fPsuedoOpen = TRUE;
  1964. goto EXIT_THE_FUNCTION;
  1965. } else {
  1966. if (didImpersonate) {
  1967. RevertToSelf();
  1968. didImpersonate = FALSE;
  1969. }
  1970. DavQueryUrlCacheEntry(DavWorkItem);
  1971. if (DavWorkItem->AsyncCreate.lpCEI) {
  1972. SYSTEMTIME SystemTime;
  1973. FILETIME CurrentFileTime;
  1974. FILETIME LastAccessTime;
  1975. LARGE_INTEGER Difference;
  1976. LPINTERNET_CACHE_ENTRY_INFOW lpCEI = (LPINTERNET_CACHE_ENTRY_INFOW)DavWorkItem->AsyncCreate.lpCEI;
  1977. LastAccessTime = ((LPINTERNET_CACHE_ENTRY_INFOW)DavWorkItem->AsyncCreate.lpCEI)->LastAccessTime;
  1978. GetSystemTime(&SystemTime);
  1979. SystemTimeToFileTime(&SystemTime,&CurrentFileTime);
  1980. Difference.QuadPart = *((LONGLONG *)(&CurrentFileTime)) - *((LONGLONG *)(&LastAccessTime));
  1981. //
  1982. // If the local cache has not timed out, we don't need to query the server
  1983. //
  1984. if (Difference.QuadPart < FileCacheExpiryInterval) {
  1985. DavPrint((DEBUG_MISC,
  1986. "DavAsyncCreatePropFind/Skip GET %u %u %u %ws\n",
  1987. CurrentFileTime.dwLowDateTime,
  1988. LastAccessTime.dwLowDateTime,
  1989. Difference.LowPart,
  1990. DavWorkItem->AsyncCreate.UrlBuffer));
  1991. ASSERT(DavWorkItem->AsyncCreate.FileName == NULL);
  1992. DavWorkItem->AsyncCreate.FileName = LocalAlloc(LPTR, (lstrlen(lpCEI->lpszLocalFileName)+1)*sizeof(WCHAR));
  1993. if (DavWorkItem->AsyncCreate.FileName) {
  1994. wcscpy(DavWorkItem->CreateResponse.FileName, lpCEI->lpszLocalFileName);
  1995. wcscpy(DavWorkItem->AsyncCreate.FileName, lpCEI->lpszLocalFileName);
  1996. ASSERT(DavWorkItem->AsyncCreate.FileHandle == NULL);
  1997. //
  1998. // Create a handle to the file whose entry was created in
  1999. // the cache.
  2000. //
  2001. DavWorkItem->AsyncCreate.FileHandle = CreateFileW(DavWorkItem->AsyncCreate.FileName,
  2002. (GENERIC_READ | GENERIC_WRITE),
  2003. FILE_SHARE_WRITE,
  2004. NULL,
  2005. OPEN_EXISTING,
  2006. FILE_ATTRIBUTE_NORMAL,
  2007. NULL);
  2008. if (DavWorkItem->AsyncCreate.FileHandle == INVALID_HANDLE_VALUE) {
  2009. WStatus = GetLastError();
  2010. DavPrint((DEBUG_ERRORS,
  2011. "DavAsyncCreatePropFind/CreateFile. Error Val = %d\n",
  2012. WStatus));
  2013. goto EXIT_THE_FUNCTION;
  2014. }
  2015. WStatus = DavAsyncCreateGet(DavWorkItem);
  2016. didImpersonate = TRUE;
  2017. goto EXIT_THE_FUNCTION;
  2018. } else {
  2019. WStatus = GetLastError();
  2020. DavPrint((DEBUG_ERRORS,
  2021. "DavAsyncCreatePropFind/CreateFile. Error Val = %d\n",
  2022. WStatus));
  2023. goto EXIT_THE_FUNCTION;
  2024. }
  2025. }
  2026. }
  2027. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2028. if (WStatus != ERROR_SUCCESS) {
  2029. DavPrint((DEBUG_ERRORS,
  2030. "DavAsyncCreatePropFind/UMReflectorImpersonate. Error Val = %d\n",
  2031. WStatus));
  2032. goto EXIT_THE_FUNCTION;
  2033. }
  2034. didImpersonate = TRUE;
  2035. }
  2036. //
  2037. // PROPFIND is done. Now we need to do a GET.
  2038. //
  2039. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  2040. DavWorkItem->AsyncCreate.AsyncCreateState = AsyncCreateGet;
  2041. DavWorkItem->DavMinorOperation = DavMinorReadData;
  2042. //
  2043. // Convert the unicode object name to UTF-8 URL format.
  2044. // Space and other white characters will remain untouched - these
  2045. // should be taken care of by wininet calls.
  2046. //
  2047. BStatus = DavHttpOpenRequestW(DavWorkItem->AsyncCreate.PerUserEntry->DavConnHandle,
  2048. L"GET",
  2049. DavWorkItem->AsyncCreate.RemPathName,
  2050. L"HTTP/1.1",
  2051. NULL,
  2052. NULL,
  2053. INTERNET_FLAG_KEEP_CONNECTION |
  2054. INTERNET_FLAG_RELOAD |
  2055. INTERNET_FLAG_NO_CACHE_WRITE |
  2056. INTERNET_FLAG_NO_COOKIES,
  2057. CallBackContext,
  2058. L"DavAsyncCreate",
  2059. &(DavWorkItem->AsyncCreate.DavOpenHandle));
  2060. if(BStatus == FALSE) {
  2061. WStatus = GetLastError();
  2062. goto EXIT_THE_FUNCTION;
  2063. }
  2064. if (DavWorkItem->AsyncCreate.DavOpenHandle == NULL) {
  2065. WStatus = GetLastError();
  2066. if (WStatus != ERROR_IO_PENDING) {
  2067. DavPrint((DEBUG_ERRORS,
  2068. "DavAsyncCreatePropFind/HttpOpenRequest. Error Val = %d\n",
  2069. WStatus));
  2070. }
  2071. goto EXIT_THE_FUNCTION;
  2072. }
  2073. ASSERT(didImpersonate);
  2074. RevertToSelf();
  2075. didImpersonate = FALSE;
  2076. // try to add if-modified-since header. don't sweat it if we fail
  2077. DavAddIfModifiedSinceHeader(DavWorkItem);
  2078. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2079. if (WStatus != ERROR_SUCCESS) {
  2080. DavPrint((DEBUG_ERRORS,
  2081. "DavAsyncCreate/UMReflectorImpersonate. Error Val = %d\n",
  2082. WStatus));
  2083. goto EXIT_THE_FUNCTION;
  2084. }
  2085. didImpersonate = TRUE;
  2086. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  2087. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  2088. DavPrint((DEBUG_ERRORS,
  2089. "DavAsyncCreatePropFind/DavAsyncCommonStates. "
  2090. "Error Val(GET) = %08lx\n", WStatus));
  2091. }
  2092. EXIT_THE_FUNCTION:
  2093. if (ParentDirectoryName) {
  2094. LocalFree(ParentDirectoryName);
  2095. }
  2096. //
  2097. // Impersonate back again, so that we are in the context of
  2098. // the user who issued this request.
  2099. //
  2100. if (!didImpersonate) {
  2101. ULONG LocalStatus;
  2102. LocalStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2103. if (LocalStatus != ERROR_SUCCESS) {
  2104. DavPrint((DEBUG_ERRORS,
  2105. "DavAsyncCreatePropFind/UMReflectorImpersonate. "
  2106. "Error Val = %d\n", LocalStatus));
  2107. if (WStatus == ERROR_SUCCESS) {
  2108. WStatus = LocalStatus;
  2109. }
  2110. }
  2111. }
  2112. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_FILE_NOT_FOUND) {
  2113. DavPrint((DEBUG_ERRORS,"DavAsyncCreatePropFind return %x\n", WStatus));
  2114. }
  2115. return WStatus;
  2116. }
  2117. DWORD
  2118. DavAsyncCreateQueryParentDirectory(
  2119. PDAV_USERMODE_WORKITEM DavWorkItem
  2120. )
  2121. /*++
  2122. Routine Description:
  2123. This routine handles the Get completion.
  2124. Arguments:
  2125. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  2126. Return Value:
  2127. none.
  2128. --*/
  2129. {
  2130. ULONG WStatus = ERROR_SUCCESS;
  2131. NTSTATUS NtStatus = STATUS_SUCCESS;
  2132. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  2133. BOOL ReturnVal, didImpersonate = TRUE;
  2134. BOOL doesTheFileExist = FALSE;
  2135. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  2136. OBJECT_ATTRIBUTES ObjectAttributes;
  2137. IO_STATUS_BLOCK IoStatusBlock;
  2138. SECURITY_QUALITY_OF_SERVICE QualityOfService;
  2139. PDAV_USERMODE_CREATE_REQUEST CreateRequest;
  2140. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  2141. UNICODE_STRING UnicodeFileName;
  2142. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  2143. ACCESS_MASK DesiredAccess = 0;
  2144. BOOL BStatus = FALSE, ShouldEncrypt = FALSE;
  2145. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  2146. UnicodeFileName.Buffer = NULL;
  2147. UnicodeFileName.Length = 0;
  2148. UnicodeFileName.MaximumLength = 0;
  2149. //
  2150. // Get the request and response buffer pointers from the DavWorkItem.
  2151. //
  2152. CreateRequest = &(DavWorkItem->CreateRequest);
  2153. CreateResponse = &(DavWorkItem->CreateResponse);
  2154. if (CreateResponse->BasicInformation.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  2155. ShouldEncrypt = TRUE;
  2156. }
  2157. //
  2158. // If this is a create of a new directory, then we need to
  2159. // send a MKCOL to the server to create this new directory.
  2160. // If this is a create of a file, then the create
  2161. // options will have FILE_DIRECTORY_FILE set.
  2162. //
  2163. if ( !(CreateRequest->CreateOptions & FILE_DIRECTORY_FILE) ) {
  2164. //
  2165. // This Create is for a file.
  2166. // This thread is currently impersonating the client that
  2167. // made this request. Before we call DavDavCreateUrlCacheEntry,
  2168. // we need to revert back to the context of the Web Client
  2169. // service.
  2170. //
  2171. RevertToSelf();
  2172. didImpersonate = FALSE;
  2173. //
  2174. // Call DavCreateUrlCacheEntry to create an entry in the
  2175. // WinInet's cache.
  2176. //
  2177. WStatus = DavCreateUrlCacheEntry(DavWorkItem);
  2178. if (WStatus != ERROR_SUCCESS) {
  2179. DavPrint((DEBUG_ERRORS,
  2180. "DavAsyncCreate/DavCreateUrlCacheEntry(1). "
  2181. "WStatus = %d\n", WStatus));
  2182. goto EXIT_THE_FUNCTION;
  2183. }
  2184. //
  2185. // Call DavCommitUrlCacheEntry to commit (pin) the entry
  2186. // created above in the WinInet's cache.
  2187. //
  2188. WStatus = DavCommitUrlCacheEntry(DavWorkItem);
  2189. if (WStatus != ERROR_SUCCESS) {
  2190. DavPrint((DEBUG_ERRORS,
  2191. "DavAsyncCreate/DavCommitUrlCacheEntry(1). "
  2192. "WStatus = %d\n", WStatus));
  2193. goto EXIT_THE_FUNCTION;
  2194. }
  2195. if (ShouldEncrypt) {
  2196. //
  2197. // if the file will be encrypted, we set the ACL to allow everyone to access. This
  2198. // is because the thread needs to be impersonated to do encrypt the file in the user's
  2199. // context. The URL cache in created in the Local System's context which won't be
  2200. // accessiable to the user if the ACL is not set.
  2201. //
  2202. WStatus = DavSetAclForEncryptedFile(DavWorkItem->AsyncCreate.FileName);
  2203. if (WStatus != ERROR_SUCCESS) {
  2204. DavPrint((DEBUG_ERRORS,
  2205. "DavAsyncCreate/DavSetAclForEncryptedFile(2). Error Val = %d, FileName = %ws\n",
  2206. WStatus, DavWorkItem->AsyncCreate.FileName));
  2207. goto EXIT_THE_FUNCTION;
  2208. }
  2209. }
  2210. //
  2211. // Impersonate back again, so that we are in the context of
  2212. // the user who issued this request.
  2213. //
  2214. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2215. if (WStatus != ERROR_SUCCESS) {
  2216. DavPrint((DEBUG_ERRORS,
  2217. "DavAsyncCreate/QueryPDirectory/UMReflectorImpersonate. "
  2218. "Error Val = %d\n", WStatus));
  2219. goto EXIT_THE_FUNCTION;
  2220. }
  2221. didImpersonate = TRUE;
  2222. //
  2223. // This file exists on the server, but this create operation
  2224. // has FILE_OVERWRITE_IF as its CreateDisposition. So, we
  2225. // can create this file locally overwrite the one on the
  2226. // server on close.
  2227. //
  2228. if (CreateRequest->CreateDisposition == FILE_OVERWRITE_IF) {
  2229. DavPrint((DEBUG_MISC,
  2230. "DavAsyncCreate/QueryPDirectory: FileName: %ws. ExistsAndOverWriteIf = TRUE\n",
  2231. DavWorkItem->AsyncCreate.FileName));
  2232. ASSERT(CreateRequest->CreateDisposition == FILE_OVERWRITE_IF);
  2233. CreateResponse->ExistsAndOverWriteIf = TRUE;
  2234. }
  2235. //
  2236. // If "FILE_DELETE_ON_CLOSE" flag was specified as one of
  2237. // the CreateOptions, then we need to remember this and
  2238. // delete this file on close.
  2239. //
  2240. if (CreateRequest->CreateOptions & FILE_DELETE_ON_CLOSE) {
  2241. DavPrint((DEBUG_MISC,
  2242. "DavAsyncCreate/QueryPDirectory: FileName: %ws. DeleteOnClose = TRUE\n",
  2243. DavWorkItem->AsyncCreate.FileName));
  2244. CreateResponse->DeleteOnClose = TRUE;
  2245. }
  2246. //
  2247. // Create the file handle to be returned back to the kernel.
  2248. //
  2249. QualityOfService.Length = sizeof(QualityOfService);
  2250. QualityOfService.ImpersonationLevel = CreateRequest->ImpersonationLevel;
  2251. QualityOfService.ContextTrackingMode = FALSE;
  2252. QualityOfService.EffectiveOnly = (BOOLEAN)
  2253. (CreateRequest->SecurityFlags & DAV_SECURITY_EFFECTIVE_ONLY);
  2254. //
  2255. // Create an NT path name for the cached file. This is used in the
  2256. // NtCreateFile call below.
  2257. //
  2258. ReturnVal = RtlDosPathNameToNtPathName_U(DavWorkItem->AsyncCreate.FileName,
  2259. &UnicodeFileName,
  2260. NULL,
  2261. NULL);
  2262. if (!ReturnVal) {
  2263. WStatus = ERROR_BAD_PATHNAME;
  2264. DavPrint((DEBUG_ERRORS,
  2265. "DavAsyncCreate/QueryPDirectory/RtlDosPathNameToNtPathName. "
  2266. "Error Val = %d\n", WStatus));
  2267. goto EXIT_THE_FUNCTION;
  2268. }
  2269. InitializeObjectAttributes(&ObjectAttributes,
  2270. &UnicodeFileName,
  2271. OBJ_CASE_INSENSITIVE,
  2272. 0,
  2273. NULL);
  2274. if (CreateRequest->SecurityDescriptor != NULL) {
  2275. ObjectAttributes.SecurityDescriptor = CreateRequest->SecurityDescriptor;
  2276. }
  2277. ObjectAttributes.SecurityQualityOfService = &QualityOfService;
  2278. //
  2279. // If CreateRequest->CreateDisposition == FILE_CREATE, then
  2280. // the NtCreateFile operation below will fail because we
  2281. // have already created the file with the CreateUrlCacheEntry
  2282. // call. So we change the value to FILE_OPEN_IF.
  2283. //
  2284. if (CreateRequest->CreateDisposition == FILE_CREATE) {
  2285. CreateRequest->CreateDisposition = FILE_OPEN_IF;
  2286. }
  2287. if (ShouldEncrypt) {
  2288. //
  2289. // The file is encrypted in the user's context
  2290. //
  2291. BStatus = EncryptFile(DavWorkItem->AsyncCreate.FileName);
  2292. if (BStatus) {
  2293. DavPrint((DEBUG_MISC,
  2294. "DavAsyncCreate: Local cache is encrypted %wZ\n",
  2295. &UnicodeFileName));
  2296. CreateResponse->LocalFileIsEncrypted = TRUE;
  2297. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  2298. } else {
  2299. WStatus = GetLastError();
  2300. DavPrint((DEBUG_ERRORS,
  2301. "DavAsyncCreate/QueryPDirectory/EncryptFile. Error Val = %d\n",
  2302. WStatus));
  2303. goto EXIT_THE_FUNCTION;
  2304. }
  2305. } else {
  2306. DavPrint((DEBUG_MISC,
  2307. "DavAsyncCreate: Local cache is not encrypted %wZ\n",
  2308. &UnicodeFileName));
  2309. //
  2310. // This thread is currently impersonating the client that
  2311. // made this request. Before we call NtCreateFile, we need
  2312. // to revert back to the context of the Web Client service.
  2313. //
  2314. RevertToSelf();
  2315. didImpersonate = FALSE;
  2316. }
  2317. //
  2318. // We use FILE_SHARE_VALID_FLAGS for share access because RDBSS
  2319. // checks this for us. Moreover, we delay the close after the final
  2320. // close happens and this could cause problems. Consider the scenario.
  2321. // 1. Open with NO share access.
  2322. // 2. We create a local handle with this share access.
  2323. // 3. The app closes the handle. We delay the close and keep the local
  2324. // handle.
  2325. // 4. Another open comes with any share access. This will be
  2326. // conflicting share access since the first one was done with no
  2327. // share access. This should succeed since the previous open has
  2328. // been closed from the app and the I/O systems point of view.
  2329. // 5. It will not if we have created the local handle with the share
  2330. // access which came with the first open.
  2331. // Therefore we need to pass FILE_SHARE_VALID_FLAGS while creating
  2332. // the local handle.
  2333. //
  2334. //
  2335. // We have FILE_NO_INTERMEDIATE_BUFFERING ORed with the CreateOptions
  2336. // the user specified, becuase we don't want the underlying file system
  2337. // to create another cache map. This way all the I/O that comes to us
  2338. // will directly go to the disk. BUG 128843 in the Windows RAID database
  2339. // explains some deadlock scenarios that could happen with PagingIo if
  2340. // we don't do this. Also since we supply the FILE_NO_INTERMEDIATE_BUFFERING
  2341. // option we filter out the FILE_APPEND_DATA from the DesiredAccess flags
  2342. // since the filesystem expects this.
  2343. //
  2344. //
  2345. // We also always create the file with DesiredAccess ORed with FILE_WRITE_DATA
  2346. // if either FILE_READ_DATA or FILE_EXECUTE was specified because there
  2347. // can be situations where we get write IRPs on a FILE_OBJECT which was
  2348. // not opened with Write Access and was only opened with FILE_READ_DATA
  2349. // or FILE_EXECUTE. This is BUG 284557. To get around the problem, we do
  2350. // this.
  2351. //
  2352. //
  2353. // We filter the FILE_ATTRIBUTE_READONLY attribute during the create.
  2354. // This is done because we store the READ_ONLY bit in the FCB and do
  2355. // the checks at the RDBSS level before going to the local filesystem.
  2356. // Also, since some of our creates open the file with FILE_WRITE_DATA,
  2357. // if someone creates a read_only file and we stamp the read_only
  2358. // attribute on the local file then all subsequent creates will fail
  2359. // since we always ask for Write access to the underlying file as
  2360. // explained above.
  2361. //
  2362. DesiredAccess = (CreateRequest->DesiredAccess & ~(FILE_APPEND_DATA));
  2363. if ( DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE) ) {
  2364. DesiredAccess |= (FILE_WRITE_DATA);
  2365. }
  2366. NtStatus = NtCreateFile(&(FileHandle),
  2367. DesiredAccess,
  2368. &ObjectAttributes,
  2369. &IoStatusBlock,
  2370. &CreateRequest->AllocationSize,
  2371. (CreateRequest->FileAttributes & ~FILE_ATTRIBUTE_READONLY),
  2372. FILE_SHARE_VALID_FLAGS,
  2373. CreateRequest->CreateDisposition,
  2374. (CreateRequest->CreateOptions | FILE_NO_INTERMEDIATE_BUFFERING),
  2375. CreateRequest->EaBuffer,
  2376. CreateRequest->EaLength);
  2377. if (NtStatus != STATUS_SUCCESS) {
  2378. //
  2379. // We convert the NtStatus to DOS error here. The Win32
  2380. // error code is finally set to an NTSTATUS value in
  2381. // the DavFsCreate function just before returning.
  2382. //
  2383. WStatus = RtlNtStatusToDosError(NtStatus);
  2384. DavPrint((DEBUG_ERRORS,
  2385. "DavAsyncCreate/QueryPDirectory/NtCreateFile(1). Error Val = "
  2386. "%08lx\n", NtStatus));
  2387. CreateResponse->Handle = NULL;
  2388. CreateResponse->UserModeKey = NULL;
  2389. goto EXIT_THE_FUNCTION;
  2390. }
  2391. DavPrint((DEBUG_MISC, "DavAsyncCreate/QueryPDirectory: DavWorkItem = %08lx.\n",
  2392. DavWorkItem));
  2393. DavPrint((DEBUG_MISC, "DavAsyncCreate/QueryPDirectory: FileHandle = %08lx.\n",
  2394. FileHandle));
  2395. CreateResponse->Handle = FileHandle;
  2396. CreateResponse->UserModeKey = (PVOID)FileHandle;
  2397. //
  2398. // If the file already exists on the server, then we don't
  2399. // need to create it and are done.
  2400. //
  2401. if (DavWorkItem->AsyncCreate.doesTheFileExist) {
  2402. DavPrint((DEBUG_MISC,
  2403. "DavAsyncCreate/QueryPDirectory: doesTheFileExist == TRUE\n"));
  2404. WStatus = ERROR_SUCCESS;
  2405. goto EXIT_THE_FUNCTION;
  2406. } else {
  2407. SYSTEMTIME CurrentSystemTime, NewSystemTime;
  2408. FILETIME CurrentFileTime;
  2409. BOOL ConvertTime = FALSE;
  2410. LARGE_INTEGER CurrentTime;
  2411. WCHAR chTimeBuff[INTERNET_RFC1123_BUFSIZE + 4];
  2412. //
  2413. // This file may have been created locally and does not exist
  2414. // on the server. We need to remember this information and
  2415. // set attributes on this file on the server on close.
  2416. //
  2417. if (CreateRequest->FileAttributes != 0) {
  2418. CreateResponse->NewFileCreatedAndSetAttributes = TRUE;
  2419. //
  2420. // Copy the attributes in the CreateResponse. These
  2421. // will get PROPPATCHED to the server on Close.
  2422. //
  2423. CreateResponse->BasicInformation.FileAttributes = CreateRequest->FileAttributes;
  2424. if (ShouldEncrypt) {
  2425. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  2426. }
  2427. }
  2428. DavPrint((DEBUG_MISC,
  2429. "DavAsyncCreate/QueryPDirectory NewFileCreatedAndSetAttributes %x %x %ws\n",
  2430. CreateRequest->FileAttributes,
  2431. CreateResponse->BasicInformation.FileAttributes,
  2432. DavWorkItem->AsyncCreate.FileName));
  2433. //
  2434. // We also need to set the FILE_BASIC_INFORMATION time values to
  2435. // the current time. We get the systemtime, convert it into the
  2436. // RFC1123 format and then convert the format back into systemtime.
  2437. // We do this because on close when we PROPPATCH these times we send
  2438. // them in the RFC1123 format. Since the least count of this format is
  2439. // seconds, some data is lost when we convert the LARGE_INTEGER to
  2440. // RFC1123 format and back. So, we lose this data right now to be
  2441. // consistent. To give an example about the loss, see below.
  2442. // CreationTime.LowPart = 802029d0, CreationTime.HighPart = 1c0def1
  2443. // maps to "Thu, 17 May 2001 16:50:38 GMT"
  2444. // And "Thu, 17 May 2001 16:50:38 GMT" is what we get back when we do a
  2445. // PROPFIND which converts back into
  2446. // CreationTime.LowPart = 7fdc4300, CreationTime.HighPart = 1c0def1
  2447. // Note that the LowPart is different. So, the values in the name cache
  2448. // and the server will be different. To avoid this inconsistency we lose
  2449. // this data by doing the conversion right away.
  2450. //
  2451. GetSystemTime( &(CurrentSystemTime) );
  2452. RtlZeroMemory(chTimeBuff, sizeof(chTimeBuff));
  2453. ConvertTime = InternetTimeFromSystemTimeW(&(CurrentSystemTime),
  2454. INTERNET_RFC1123_FORMAT,
  2455. chTimeBuff,
  2456. sizeof(chTimeBuff));
  2457. if (ConvertTime) {
  2458. ConvertTime = InternetTimeToSystemTimeW(chTimeBuff, &(NewSystemTime), 0);
  2459. if (ConvertTime) {
  2460. ConvertTime = SystemTimeToFileTime( &(NewSystemTime), &(CurrentFileTime) );
  2461. if (ConvertTime) {
  2462. CreateResponse->PropPatchTheTimeValues = TRUE;
  2463. CurrentTime.LowPart = CurrentFileTime.dwLowDateTime;
  2464. CurrentTime.HighPart = CurrentFileTime.dwHighDateTime;
  2465. CreateResponse->BasicInformation.CreationTime.QuadPart = CurrentTime.QuadPart;
  2466. CreateResponse->BasicInformation.LastAccessTime.QuadPart = CurrentTime.QuadPart;
  2467. CreateResponse->BasicInformation.LastWriteTime.QuadPart = CurrentTime.QuadPart;
  2468. CreateResponse->BasicInformation.ChangeTime.QuadPart = CurrentTime.QuadPart;
  2469. }
  2470. }
  2471. }
  2472. //
  2473. // If the above conversion from systemtime to RFC1123 format and then
  2474. // back to systemtime from RFc1123 format failed then we go ahead and
  2475. // convert the systemtime to filetime and use that.
  2476. //
  2477. if (!ConvertTime) {
  2478. ConvertTime = SystemTimeToFileTime( &(CurrentSystemTime), &(CurrentFileTime) );
  2479. if (ConvertTime) {
  2480. CreateResponse->PropPatchTheTimeValues = TRUE;
  2481. CurrentTime.LowPart = CurrentFileTime.dwLowDateTime;
  2482. CurrentTime.HighPart = CurrentFileTime.dwHighDateTime;
  2483. CreateResponse->BasicInformation.CreationTime.QuadPart = CurrentTime.QuadPart;
  2484. CreateResponse->BasicInformation.LastAccessTime.QuadPart = CurrentTime.QuadPart;
  2485. CreateResponse->BasicInformation.LastWriteTime.QuadPart = CurrentTime.QuadPart;
  2486. CreateResponse->BasicInformation.ChangeTime.QuadPart = CurrentTime.QuadPart;
  2487. } else {
  2488. //
  2489. // This is not a fatal error. We can still continie with the
  2490. // Create call.
  2491. //
  2492. DavPrint((DEBUG_ERRORS,
  2493. "DavAsyncCreateQueryParentDirectory/SystemTimeToFileTime(1): %x\n",
  2494. GetLastError()));
  2495. }
  2496. }
  2497. }
  2498. //
  2499. // We are done with the Open handle to PROPFIND.
  2500. // Now we need to create the directory on the server.
  2501. //
  2502. if (DavWorkItem->AsyncCreate.DavOpenHandle) {
  2503. InternetCloseHandle(DavWorkItem->AsyncCreate.DavOpenHandle);
  2504. DavWorkItem->AsyncCreate.DavOpenHandle = NULL;
  2505. }
  2506. //
  2507. // We need to "PUT" this new file on the server.
  2508. //
  2509. DavPrint((DEBUG_MISC, "DavAsyncCreate/QueryPDirectory: PUT New File\n"));
  2510. //
  2511. // If we are not currently impersonating, we need to impersonate back
  2512. // again, so that we are in the context of the user who issued this
  2513. // request.
  2514. //
  2515. if (didImpersonate == FALSE) {
  2516. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2517. if (WStatus != ERROR_SUCCESS) {
  2518. DavPrint((DEBUG_ERRORS,
  2519. "DavAsyncCreate/QueryPDirectory/UMReflectorImpersonate. "
  2520. "Error Val = %d\n", WStatus));
  2521. goto EXIT_THE_FUNCTION;
  2522. }
  2523. didImpersonate = TRUE;
  2524. }
  2525. //
  2526. // Set the DavOperation and AsyncCreateState values.For PUT
  2527. // the DavMinorOperation value is irrelavant.
  2528. //
  2529. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  2530. DavWorkItem->AsyncCreate.AsyncCreateState = AsyncCreatePut;
  2531. //
  2532. // Convert the unicode object name to UTF-8 URL format.
  2533. // Space and other white characters will remain untouched.
  2534. // These should be taken care of by wininet calls.
  2535. //
  2536. BStatus = DavHttpOpenRequestW(DavWorkItem->AsyncCreate.PerUserEntry->DavConnHandle,
  2537. L"PUT",
  2538. DavWorkItem->AsyncCreate.RemPathName,
  2539. L"HTTP/1.1",
  2540. NULL,
  2541. NULL,
  2542. INTERNET_FLAG_KEEP_CONNECTION |
  2543. INTERNET_FLAG_NO_COOKIES,
  2544. CallBackContext,
  2545. L"QueryPDirectory",
  2546. &(DavWorkItem->AsyncCreate.DavOpenHandle));
  2547. if(BStatus == FALSE) {
  2548. WStatus = GetLastError();
  2549. DavPrint((DEBUG_ERRORS,"DavAsyncCreate/QueryPDirectory/DavHttpOpenRequestW error: %x\n",WStatus));
  2550. goto EXIT_THE_FUNCTION;
  2551. }
  2552. if (DavWorkItem->AsyncCreate.DavOpenHandle == NULL) {
  2553. WStatus = GetLastError();
  2554. if (WStatus != ERROR_IO_PENDING) {
  2555. DavPrint((DEBUG_ERRORS,
  2556. "DavAsyncCreate/QueryPDirectory/HttpOpenRequestW"
  2557. ". Error Val = %d\n", WStatus));
  2558. }
  2559. goto EXIT_THE_FUNCTION;
  2560. }
  2561. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  2562. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  2563. DavPrint((DEBUG_ERRORS,
  2564. "DavAsyncCreate/QueryPDirectory/DavAsyncCommonStates(PUT). "
  2565. "Error Val = %08lx\n", WStatus));
  2566. }
  2567. //
  2568. // We LOCK the resource if the following conditions are TRUE.
  2569. // 1. The resource already exists on the server AND,
  2570. // 2. The resource being opened is a file and NOT a directory AND,
  2571. // 3. The SharedMode is 0 (exclusive) OR FILE_SHARE_READ OR the file is
  2572. // being opened for write access.
  2573. //
  2574. if (DavSupportLockingOfFiles) {
  2575. if ( (CreateRequest->ShareAccess == 0) || (CreateRequest->ShareAccess == FILE_SHARE_READ) ||
  2576. (CreateRequest->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE | GENERIC_ALL)) ) {
  2577. WStatus = DavLockTheFileOnTheServer(DavWorkItem);
  2578. if (WStatus != ERROR_SUCCESS) {
  2579. DavPrint((DEBUG_ERRORS,
  2580. "DavAsyncCreateQueryParentDirectory/DavLockTheFileOnTheServer. WStatus = %08lx\n",
  2581. WStatus));
  2582. goto EXIT_THE_FUNCTION;
  2583. }
  2584. }
  2585. }
  2586. goto EXIT_THE_FUNCTION;
  2587. } else {
  2588. SYSTEMTIME CurrentSystemTime, NewSystemTime;
  2589. FILETIME CurrentFileTime;
  2590. BOOL ConvertTime = FALSE;
  2591. LARGE_INTEGER CurrentTime;
  2592. WCHAR chTimeBuff[INTERNET_RFC1123_BUFSIZE + 4];
  2593. //
  2594. // We are done with the Open handle to PROPFIND.
  2595. // Now we need to create the directory on the server.
  2596. //
  2597. InternetCloseHandle(DavWorkItem->AsyncCreate.DavOpenHandle);
  2598. DavWorkItem->AsyncCreate.DavOpenHandle = NULL;
  2599. //
  2600. // This Create is for a Directory. We need to send an
  2601. // MKCOL to the server.
  2602. //
  2603. DavPrint((DEBUG_MISC, "DavAsyncCreate/QueryPDirectory: Create Directory\n"));
  2604. //
  2605. // Set the DavOperation and AsyncCreateState values.
  2606. // For MKCOL the DavMinorOperation value is irrelavant.
  2607. //
  2608. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  2609. DavWorkItem->AsyncCreate.AsyncCreateState = AsyncCreateMkCol;
  2610. //
  2611. // The data is parsed. We now need to set the file attributes in the
  2612. // response buffer.
  2613. //
  2614. CreateResponse->BasicInformation.FileAttributes = CreateRequest->FileAttributes;
  2615. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
  2616. CreateResponse->StandardInformation.Directory = TRUE;
  2617. //
  2618. // Since we are creating a new directory we need to PROPPATCH the
  2619. // attributes on the directory that is getting created below on close.
  2620. //
  2621. CreateResponse->NewFileCreatedAndSetAttributes = TRUE;
  2622. if (ShouldEncrypt) {
  2623. DavPrint((DEBUG_MISC,
  2624. "DavAsyncCreate: New directory is encrypted\n"));
  2625. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  2626. }
  2627. //
  2628. // We also need to set the FILE_BASIC_INFORMATION time values to
  2629. // the current time. We get the systemtime, convert it into the
  2630. // RFC1123 format and then convert the format back into systemtime.
  2631. // We do this because on close when we PROPPATCH these times we send
  2632. // them in the RFC1123 format. Since the least count of this format is
  2633. // seconds, some data is lost when we convert the LARGE_INTEGER to
  2634. // RFC1123 format and back. So, we lose this data right now to be
  2635. // consistent. To give an example about the loss, see below.
  2636. // CreationTime.LowPart = 802029d0, CreationTime.HighPart = 1c0def1
  2637. // maps to "Thu, 17 May 2001 16:50:38 GMT"
  2638. // And "Thu, 17 May 2001 16:50:38 GMT" is what we get back when we do a
  2639. // PROPFIND which converts back into
  2640. // CreationTime.LowPart = 7fdc4300, CreationTime.HighPart = 1c0def1
  2641. // Note that the LowPart is different. So, the values in the name cache
  2642. // and the server will be different. To avoid this inconsistency we lose
  2643. // this data by doing the conversion right away.
  2644. //
  2645. GetSystemTime( &(CurrentSystemTime) );
  2646. RtlZeroMemory(chTimeBuff, sizeof(chTimeBuff));
  2647. ConvertTime = InternetTimeFromSystemTimeW(&(CurrentSystemTime),
  2648. INTERNET_RFC1123_FORMAT,
  2649. chTimeBuff,
  2650. sizeof(chTimeBuff));
  2651. if (ConvertTime) {
  2652. ConvertTime = InternetTimeToSystemTimeW(chTimeBuff, &(NewSystemTime), 0);
  2653. if (ConvertTime) {
  2654. ConvertTime = SystemTimeToFileTime( &(NewSystemTime), &(CurrentFileTime) );
  2655. if (ConvertTime) {
  2656. CreateResponse->PropPatchTheTimeValues = TRUE;
  2657. CurrentTime.LowPart = CurrentFileTime.dwLowDateTime;
  2658. CurrentTime.HighPart = CurrentFileTime.dwHighDateTime;
  2659. CreateResponse->BasicInformation.CreationTime.QuadPart = CurrentTime.QuadPart;
  2660. CreateResponse->BasicInformation.LastAccessTime.QuadPart = CurrentTime.QuadPart;
  2661. CreateResponse->BasicInformation.LastWriteTime.QuadPart = CurrentTime.QuadPart;
  2662. CreateResponse->BasicInformation.ChangeTime.QuadPart = CurrentTime.QuadPart;
  2663. }
  2664. }
  2665. }
  2666. //
  2667. // If the above conversion from systemtime to RFC1123 format and then
  2668. // back to systemtime from RFc1123 format failed then we go ahead and
  2669. // convert the systemtime to filetime and use that.
  2670. //
  2671. if (!ConvertTime) {
  2672. ConvertTime = SystemTimeToFileTime( &(CurrentSystemTime), &(CurrentFileTime) );
  2673. if (ConvertTime) {
  2674. CreateResponse->PropPatchTheTimeValues = TRUE;
  2675. CurrentTime.LowPart = CurrentFileTime.dwLowDateTime;
  2676. CurrentTime.HighPart = CurrentFileTime.dwHighDateTime;
  2677. CreateResponse->BasicInformation.CreationTime.QuadPart = CurrentTime.QuadPart;
  2678. CreateResponse->BasicInformation.LastAccessTime.QuadPart = CurrentTime.QuadPart;
  2679. CreateResponse->BasicInformation.LastWriteTime.QuadPart = CurrentTime.QuadPart;
  2680. CreateResponse->BasicInformation.ChangeTime.QuadPart = CurrentTime.QuadPart;
  2681. } else {
  2682. //
  2683. // This is not a fatal error. We can still continie with the
  2684. // Create call.
  2685. //
  2686. DavPrint((DEBUG_ERRORS,
  2687. "DavAsyncCreateQueryParentDirectory/SystemTimeToFileTime(2): %x\n",
  2688. GetLastError()));
  2689. }
  2690. }
  2691. //
  2692. // Convert the unicode object name to UTF-8 URL format.
  2693. // Space and other white characters will remain untouched.
  2694. // These should be taken care of by wininet calls.
  2695. //
  2696. BStatus = DavHttpOpenRequestW(DavWorkItem->AsyncCreate.PerUserEntry->DavConnHandle,
  2697. L"MKCOL",
  2698. DavWorkItem->AsyncCreate.RemPathName,
  2699. L"HTTP/1.1",
  2700. NULL,
  2701. NULL,
  2702. INTERNET_FLAG_KEEP_CONNECTION |
  2703. INTERNET_FLAG_NO_COOKIES,
  2704. CallBackContext,
  2705. L"QueryPDirectory",
  2706. &(DavWorkItem->AsyncCreate.DavOpenHandle ));
  2707. if(BStatus == FALSE) {
  2708. WStatus = GetLastError();
  2709. goto EXIT_THE_FUNCTION;
  2710. }
  2711. if (DavWorkItem->AsyncCreate.DavOpenHandle == NULL) {
  2712. WStatus = GetLastError();
  2713. if (WStatus != ERROR_IO_PENDING) {
  2714. DavPrint((DEBUG_ERRORS,
  2715. "DavAsyncCreate/QueryPDirectory/HttpOpenRequestW"
  2716. ". Error Val = %d\n", WStatus));
  2717. }
  2718. goto EXIT_THE_FUNCTION;
  2719. }
  2720. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  2721. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  2722. DavPrint((DEBUG_ERRORS,
  2723. "DavAsyncCreate/QueryPDirectory/DavAsyncCommonStates(MKCOL). "
  2724. "Error Val = %08lx\n", WStatus));
  2725. }
  2726. goto EXIT_THE_FUNCTION;
  2727. }
  2728. EXIT_THE_FUNCTION:
  2729. //
  2730. // The function RtlDosPathNameToNtPathName_U allocates memory from the
  2731. // processes heap. If we did, we need to free it now.
  2732. //
  2733. if (UnicodeFileName.Buffer != NULL) {
  2734. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeFileName.Buffer);
  2735. }
  2736. if (!didImpersonate) {
  2737. ULONG LocalStatus;
  2738. //
  2739. // Impersonate back again, so that we are in the context of
  2740. // the user who issued this request.
  2741. //
  2742. LocalStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2743. if (LocalStatus != ERROR_SUCCESS) {
  2744. DavPrint((DEBUG_ERRORS,
  2745. "DavAsyncCreate/QueryPDirectory/UMReflectorImpersonate. "
  2746. "Error Val = %d\n", LocalStatus));
  2747. if (WStatus == ERROR_SUCCESS) {
  2748. WStatus = LocalStatus;
  2749. }
  2750. }
  2751. }
  2752. return WStatus;
  2753. }
  2754. DWORD
  2755. DavAsyncCreateGet(
  2756. PDAV_USERMODE_WORKITEM DavWorkItem
  2757. )
  2758. /*++
  2759. Routine Description:
  2760. This routine handles the Get completion.
  2761. Arguments:
  2762. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  2763. Return Value:
  2764. none.
  2765. --*/
  2766. {
  2767. ULONG WStatus = ERROR_SUCCESS;
  2768. NTSTATUS NtStatus = STATUS_SUCCESS;
  2769. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  2770. BOOL ReturnVal, didImpersonate = FALSE;
  2771. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  2772. OBJECT_ATTRIBUTES ObjectAttributes;
  2773. IO_STATUS_BLOCK IoStatusBlock;
  2774. SECURITY_QUALITY_OF_SERVICE QualityOfService;
  2775. PDAV_USERMODE_CREATE_REQUEST CreateRequest;
  2776. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  2777. UNICODE_STRING UnicodeFileName;
  2778. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  2779. PWCHAR pEncryptedCachedFile = NULL;
  2780. ACCESS_MASK DesiredAccess = 0;
  2781. BOOL EncryptedFile = FALSE;
  2782. FILE_STANDARD_INFORMATION FileStdInfo;
  2783. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  2784. UnicodeFileName.Buffer = NULL;
  2785. UnicodeFileName.Length = 0;
  2786. UnicodeFileName.MaximumLength = 0;
  2787. //
  2788. // Get the request and response buffer pointers from the DavWorkItem.
  2789. //
  2790. CreateRequest = &(DavWorkItem->CreateRequest);
  2791. CreateResponse = &(DavWorkItem->CreateResponse);
  2792. CreateResponse->fPsuedoOpen = FALSE;
  2793. if (CreateResponse->BasicInformation.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  2794. //
  2795. // This file is encrypted. We need to restore the file. For doing this
  2796. // we need to create another entry in the WinInet cache in which the
  2797. // file will be restored.
  2798. //
  2799. DavPrint((DEBUG_MISC, "DavAsyncCreateGet: This is an Encrypted File.\n"));
  2800. EncryptedFile = TRUE;
  2801. //
  2802. // Save the encrypted file name.
  2803. //
  2804. pEncryptedCachedFile = DavWorkItem->AsyncCreate.FileName;
  2805. DavWorkItem->AsyncCreate.FileName = NULL;
  2806. WStatus = DavCreateUrlCacheEntry(DavWorkItem);
  2807. if (WStatus != ERROR_SUCCESS) {
  2808. DavPrint((DEBUG_ERRORS,
  2809. "DavAsyncCreateGet/CreateUrlCacheEntry. Error Val = %d\n",
  2810. WStatus));
  2811. goto EXIT_THE_FUNCTION;
  2812. }
  2813. DavPrint((DEBUG_MISC, "DavAsyncCreateGet: EncryptedCachedFile = %ws\n", pEncryptedCachedFile));
  2814. DavPrint((DEBUG_MISC, "DavAsyncCreateGet: NewFileName = %ws\n", DavWorkItem->AsyncCreate.FileName));
  2815. WStatus = DavSetAclForEncryptedFile(DavWorkItem->AsyncCreate.FileName);
  2816. if (WStatus != ERROR_SUCCESS) {
  2817. DavPrint((DEBUG_ERRORS,
  2818. "DavAsyncCreate/DavSetAclForEncryptedFile(3). Error Val = %d, FileName = %ws\n",
  2819. WStatus, DavWorkItem->AsyncCreate.FileName));
  2820. goto EXIT_THE_FUNCTION;
  2821. }
  2822. if (DavWorkItem->AsyncCreate.FileHandle != NULL) {
  2823. //
  2824. // Close the opened file handle since we don't need it anymore. We
  2825. // close the file after setting the ACLs so that the file won't be
  2826. // scavenged by WinInet by any chance.
  2827. //
  2828. ReturnVal = CloseHandle(DavWorkItem->AsyncCreate.FileHandle);
  2829. if (!ReturnVal) {
  2830. WStatus = GetLastError();
  2831. DavPrint((DEBUG_ERRORS,
  2832. "DavAsyncCreateGet/CloseHandle. Error Val = %d\n", WStatus));
  2833. goto EXIT_THE_FUNCTION;
  2834. }
  2835. DavWorkItem->AsyncCreate.FileHandle = NULL;
  2836. }
  2837. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2838. if (WStatus != ERROR_SUCCESS) {
  2839. DavPrint((DEBUG_ERRORS,
  2840. "DavAsyncCreateGet/UMReflectorImpersonate. "
  2841. "Error Val = %d\n", WStatus));
  2842. goto EXIT_THE_FUNCTION;
  2843. }
  2844. didImpersonate = TRUE;
  2845. WStatus = DavRestoreEncryptedFile(pEncryptedCachedFile, DavWorkItem->AsyncCreate.FileName);
  2846. if (WStatus != ERROR_SUCCESS) {
  2847. DavPrint((DEBUG_ERRORS,
  2848. "DavAsyncCreateGet/DavRestoreEncryptedFile. Error Val"
  2849. " = %d %x %x\n",
  2850. WStatus,
  2851. CreateRequest->FileAttributes,
  2852. CreateResponse->BasicInformation.FileAttributes));
  2853. goto EXIT_THE_FUNCTION;
  2854. }
  2855. //
  2856. // Copy the "new" file name in the response buffer.
  2857. //
  2858. wcscpy(CreateResponse->FileName, DavWorkItem->AsyncCreate.FileName);
  2859. CreateResponse->LocalFileIsEncrypted = TRUE;
  2860. //
  2861. // Don't commit the restored EFS file so that the next open will still
  2862. // see the file in the back up format and the EFS header.
  2863. //
  2864. } else {
  2865. if (DavWorkItem->AsyncCreate.FileHandle != NULL) {
  2866. //
  2867. // Close the opened file handle since we don't need it anymore.
  2868. //
  2869. ReturnVal = CloseHandle(DavWorkItem->AsyncCreate.FileHandle);
  2870. if (!ReturnVal) {
  2871. WStatus = GetLastError();
  2872. DavPrint((DEBUG_ERRORS,
  2873. "DavAsyncCreateGet/CloseHandle. Error Val = %d\n", WStatus));
  2874. goto EXIT_THE_FUNCTION;
  2875. }
  2876. DavWorkItem->AsyncCreate.FileHandle = NULL;
  2877. }
  2878. //
  2879. // If the file already exists, encryption can only be taken place if the
  2880. // CreateDisposition is not FILE_SUPERSEDE, FILE_OVERWRITE or
  2881. // FILE_OVERWRITE_IF.
  2882. //
  2883. if ((CreateRequest->FileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  2884. ((CreateRequest->CreateDisposition == FILE_SUPERSEDE) ||
  2885. (CreateRequest->CreateDisposition == FILE_OVERWRITE) ||
  2886. (CreateRequest->CreateDisposition == FILE_OVERWRITE_IF))) {
  2887. WStatus = DavSetAclForEncryptedFile(DavWorkItem->AsyncCreate.FileName);
  2888. if (WStatus != ERROR_SUCCESS) {
  2889. DavPrint((DEBUG_ERRORS,
  2890. "DavAsyncCreate/DavSetAclForEncryptedFile(4). Error Val = %d, FileName = %ws\n",
  2891. WStatus, DavWorkItem->AsyncCreate.FileName));
  2892. goto EXIT_THE_FUNCTION;
  2893. }
  2894. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  2895. if (WStatus != ERROR_SUCCESS) {
  2896. DavPrint((DEBUG_ERRORS,
  2897. "DavAsyncCreateGet/UMReflectorImpersonate. "
  2898. "Error Val = %d\n", WStatus));
  2899. goto EXIT_THE_FUNCTION;
  2900. }
  2901. didImpersonate = TRUE;
  2902. //
  2903. // The file is encrypted in the user's context
  2904. //
  2905. if (EncryptFile(DavWorkItem->AsyncCreate.FileName)) {
  2906. DavPrint((DEBUG_MISC,
  2907. "DavAsyncCreate: Local cache is encrypted %wZ\n",
  2908. &UnicodeFileName));
  2909. CreateResponse->LocalFileIsEncrypted = TRUE;
  2910. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  2911. } else {
  2912. WStatus = GetLastError();
  2913. DavPrint((DEBUG_ERRORS,
  2914. "DavAsyncCreate/QueryPDirectory/EncryptFile. Error Val = %d\n",
  2915. WStatus));
  2916. goto EXIT_THE_FUNCTION;
  2917. }
  2918. CreateRequest->FileAttributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
  2919. CreateResponse->BasicInformation.FileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  2920. CreateResponse->LocalFileIsEncrypted = TRUE;
  2921. }
  2922. }
  2923. #ifdef WEBCLIENT_SUPPORTS_BACKUP_RESTORE_FOR_EFS
  2924. //
  2925. // Enable the Backup/Restore privilege on the thread for the encrypted file
  2926. // so that Backup/Restore operation can be done to the file even if the
  2927. // the thread is not impersonated to the owner of the file.
  2928. //
  2929. if (EncryptedFile) {
  2930. PTOKEN_PRIVILEGES pPrevPriv = NULL;
  2931. DWORD cbPrevPriv = sizeof(TOKEN_PRIVILEGES);
  2932. BYTE rgbNewPriv[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
  2933. PTOKEN_PRIVILEGES pNewPriv = (PTOKEN_PRIVILEGES)rgbNewPriv;
  2934. HANDLE hToken = 0;
  2935. for (;;) {
  2936. if (!OpenThreadToken(GetCurrentThread(),
  2937. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  2938. FALSE,
  2939. &hToken)) {
  2940. DbgPrint("OpenThreadToken failed %d\n", GetLastError());
  2941. break;
  2942. // need to close the hToken at the end.
  2943. }
  2944. // set up the new priviledge state
  2945. memset(rgbNewPriv, 0, sizeof(rgbNewPriv));
  2946. pNewPriv->PrivilegeCount = 1;
  2947. if(!LookupPrivilegeValueW(NULL, SE_SECURITY_NAME,
  2948. &(pNewPriv->Privileges[0].Luid))) {
  2949. DbgPrint("LookupPrivilegeValueW failed \n");
  2950. break;
  2951. }
  2952. pNewPriv->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  2953. pNewPriv->Privileges[0].Luid = RtlConvertLongToLuid(SE_RESTORE_PRIVILEGE);
  2954. // alloc for the previous state
  2955. pPrevPriv = (PTOKEN_PRIVILEGES)LocalAlloc(LMEM_ZEROINIT,sizeof(TOKEN_PRIVILEGES));
  2956. if (!pPrevPriv) {
  2957. DbgPrint("LocalAlloc for Adjust token failed \n");
  2958. break;
  2959. }
  2960. // adjust the priviledge and get the previous state
  2961. if (!AdjustTokenPrivileges(hToken,
  2962. FALSE,
  2963. pNewPriv,
  2964. cbPrevPriv,
  2965. (PTOKEN_PRIVILEGES)pPrevPriv,
  2966. &cbPrevPriv)) {
  2967. DbgPrint("AdjustTokenPrivileges failed %d\n", GetLastError());
  2968. break;
  2969. }
  2970. DbgPrint("AdjustTokenPrivileges succeeded\n")
  2971. break;
  2972. }
  2973. if (pPrevPriv) {
  2974. LocalFree(pPrevPriv);
  2975. }
  2976. }
  2977. #endif
  2978. //
  2979. // Create the file handle to be returned back to the kernel.
  2980. //
  2981. QualityOfService.Length = sizeof(QualityOfService);
  2982. QualityOfService.ImpersonationLevel = CreateRequest->ImpersonationLevel;
  2983. QualityOfService.ContextTrackingMode = FALSE;
  2984. QualityOfService.EffectiveOnly = (BOOLEAN)(CreateRequest->SecurityFlags & DAV_SECURITY_EFFECTIVE_ONLY);
  2985. //
  2986. // Create an NT path name for the cached file. This is used in the
  2987. // NtCreateFile call below.
  2988. //
  2989. ReturnVal = RtlDosPathNameToNtPathName_U(DavWorkItem->AsyncCreate.FileName,
  2990. &UnicodeFileName,
  2991. NULL,
  2992. NULL);
  2993. if (!ReturnVal) {
  2994. WStatus = ERROR_BAD_PATHNAME;
  2995. DavPrint((DEBUG_ERRORS,
  2996. "DavAsyncCreateGet/RtlDosPathNameToNtPathName. "
  2997. "Error Val = %d\n", WStatus));
  2998. goto EXIT_THE_FUNCTION;
  2999. }
  3000. InitializeObjectAttributes(&ObjectAttributes,
  3001. &UnicodeFileName,
  3002. OBJ_CASE_INSENSITIVE,
  3003. 0,
  3004. NULL);
  3005. if (CreateRequest->SecurityDescriptor != NULL) {
  3006. ObjectAttributes.SecurityDescriptor = CreateRequest->SecurityDescriptor;
  3007. }
  3008. ObjectAttributes.SecurityQualityOfService = &QualityOfService;
  3009. //
  3010. // We use FILE_SHARE_VALID_FLAGS for share access because RDBSS
  3011. // checks this for us. Moreover, we delay the close after the final
  3012. // close happens and this could cause problems. Consider the scenario.
  3013. // 1. Open with NO share access.
  3014. // 2. We create a local handle with this share access.
  3015. // 3. The app closes the handle. We delay the close and keep the local
  3016. // handle.
  3017. // 4. Another open comes with any share access. This will be
  3018. // conflicting share access since the first one was done with no
  3019. // share access. This should succeed since the previous open has
  3020. // been closed from the app and the I/O systems point of view.
  3021. // 5. It will not if we have created the local handle with the share
  3022. // access which came with the first open.
  3023. // Therefore we need to pass FILE_SHARE_VALID_FLAGS while creating
  3024. // the local handle.
  3025. //
  3026. //
  3027. // We have FILE_NO_INTERMEDIATE_BUFFERING ORed with the CreateOptions
  3028. // the user specified, becuase we don't want the underlying file system
  3029. // to create another cache map. This way all the I/O that comes to us
  3030. // will directly go to the disk. BUG 128843 in the Windows RAID database
  3031. // explains some deadlock scenarios that could happen with PagingIo if
  3032. // we don't do this. Also since we supply the FILE_NO_INTERMEDIATE_BUFFERING
  3033. // option we filter out the FILE_APPEND_DATA from the DesiredAccess flags
  3034. // since the filesystem expects this.
  3035. //
  3036. //
  3037. // We also always create the file with DesiredAccess ORed with FILE_WRITE_DATA
  3038. // if either FILE_READ_DATA or FILE_EXECUTE was specified because there can
  3039. // be situations where we get write IRPs on a FILE_OBJECT which was not
  3040. // opened with Write Access and was only opened with FILE_READ_DATA or
  3041. // FILE_EXECUTE. This is BUG 284557. To get around the problem, we do this.
  3042. //
  3043. //
  3044. // We filter the FILE_ATTRIBUTE_READONLY attribute during the create.
  3045. // This is done because we store the READ_ONLY bit in the FCB and do
  3046. // the checks at the RDBSS level before going to the local filesystem.
  3047. // Also, since some of our creates open the file with FILE_WRITE_DATA,
  3048. // if someone creates a read_only file and we stamp the read_only
  3049. // attribute on the local file then all subsequent creates will fail
  3050. // since we always ask for Write access to the underlying file as
  3051. // explained above.
  3052. //
  3053. //
  3054. // We add to the DesiredAccess FILE_READ_ATTRIBUTES since we read the
  3055. // attributes of this file since the file size value we got from the server
  3056. // could be different from the GET Content-Length.
  3057. //
  3058. //
  3059. // We need to remove the ACCESS_SYSTEM_SECURITY which will prevent us from
  3060. // opening the file in the LocalService context even if the file is created
  3061. // in LocalService context.
  3062. //
  3063. DesiredAccess = (CreateRequest->DesiredAccess & ~(FILE_APPEND_DATA | ACCESS_SYSTEM_SECURITY));
  3064. DesiredAccess |= (FILE_READ_ATTRIBUTES);
  3065. if ( DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE) ) {
  3066. DesiredAccess |= (FILE_WRITE_DATA);
  3067. }
  3068. NtStatus = NtCreateFile(&(FileHandle),
  3069. DesiredAccess,
  3070. &ObjectAttributes,
  3071. &IoStatusBlock,
  3072. &CreateRequest->AllocationSize,
  3073. (CreateRequest->FileAttributes & ~FILE_ATTRIBUTE_READONLY),
  3074. FILE_SHARE_VALID_FLAGS,
  3075. CreateRequest->CreateDisposition,
  3076. (CreateRequest->CreateOptions | FILE_NO_INTERMEDIATE_BUFFERING),
  3077. CreateRequest->EaBuffer,
  3078. CreateRequest->EaLength);
  3079. if (NtStatus != STATUS_SUCCESS) {
  3080. //
  3081. // We convert the NtStatus to DOS error here. The Win32
  3082. // error code is finally set to an NTSTATUS value in
  3083. // the DavFsCreate function just before returning.
  3084. //
  3085. WStatus = RtlNtStatusToDosError(NtStatus);
  3086. DavPrint((DEBUG_ERRORS,
  3087. "DavAsyncCreateGet/NtCreateFile(2). Error Val = "
  3088. "%x %x %x %x %x %x %x %x %ws\n",
  3089. NtStatus,
  3090. CreateRequest->ImpersonationLevel,
  3091. CreateRequest->SecurityFlags,
  3092. CreateRequest->SecurityDescriptor,
  3093. DesiredAccess,
  3094. CreateRequest->FileAttributes,
  3095. CreateRequest->CreateDisposition,
  3096. CreateRequest->CreateOptions,
  3097. DavWorkItem->AsyncCreate.FileName));
  3098. CreateResponse->Handle = NULL;
  3099. CreateResponse->UserModeKey = NULL;
  3100. FileHandle = INVALID_HANDLE_VALUE;
  3101. goto EXIT_THE_FUNCTION;
  3102. }
  3103. //
  3104. // We don't impersonate back the client as yet since we might need
  3105. // to call NtQueryInformationFile next (if the file is encrypted)
  3106. // which requires us to be in the context of the Web Client Service.
  3107. //
  3108. DavPrint((DEBUG_MISC, "DavAsyncCreateGet(2): FileHandle = %08lx\n", FileHandle));
  3109. //
  3110. // We query the StandardInformation of the file to find out if the FileSize
  3111. // returned by PROPFIND is different from the content-length returned by GET.
  3112. //
  3113. NtStatus = NtQueryInformationFile(FileHandle,
  3114. &(IoStatusBlock),
  3115. &(FileStdInfo),
  3116. sizeof(FILE_STANDARD_INFORMATION),
  3117. FileStandardInformation);
  3118. if (NtStatus != STATUS_SUCCESS) {
  3119. //
  3120. // We convert the NtStatus to DOS error here. The Win32
  3121. // error code is finally set to an NTSTATUS value in
  3122. // the DavFsCreate function just before returning.
  3123. //
  3124. WStatus = RtlNtStatusToDosError(NtStatus);
  3125. NtClose(FileHandle);
  3126. DavPrint((DEBUG_ERRORS,
  3127. "DavAsyncCreateGet/NtQueryInformationFile. Error Val "
  3128. "= %08lx\n", NtStatus));
  3129. CreateResponse->Handle = NULL;
  3130. CreateResponse->UserModeKey = NULL;
  3131. FileHandle = INVALID_HANDLE_VALUE;
  3132. goto EXIT_THE_FUNCTION;
  3133. }
  3134. //
  3135. // The FileSize returned by PROPFIND is different from the the amount of
  3136. // data that GET returned. Server screwup. We reset the filesize and the
  3137. // allocationsize to match the underlying file. For encrypted files these
  3138. // values will be different because PROPFIND returns the size of the backup
  3139. // blob which is different from the size of the restored file.
  3140. //
  3141. if (!EncryptedFile && FileStdInfo.EndOfFile.QuadPart != CreateResponse->StandardInformation.EndOfFile.QuadPart) {
  3142. //
  3143. // Reset the FileSize and AllocationSize info in the response to the
  3144. // FileSize and AllocationSize of the underlying file.
  3145. //
  3146. DavPrint((DEBUG_DEBUG,
  3147. "DavAsyncCreate: FileSizes Different!! CPN = %ws, "
  3148. "FileStdInfo.EndOfFile.HighPart = %x, "
  3149. "FileStdInfo.EndOfFile.LowPart = %x, "
  3150. "CreateResponse.EndOfFile.HighPart = %x, "
  3151. "CreateResponse.EndOfFile.LowPart = %x\n",
  3152. CreateRequest->CompletePathName,
  3153. FileStdInfo.EndOfFile.HighPart, FileStdInfo.EndOfFile.LowPart,
  3154. CreateResponse->StandardInformation.EndOfFile.HighPart,
  3155. CreateResponse->StandardInformation.EndOfFile.LowPart));
  3156. CreateResponse->StandardInformation.EndOfFile.QuadPart = FileStdInfo.EndOfFile.QuadPart;
  3157. CreateResponse->StandardInformation.AllocationSize.QuadPart = FileStdInfo.AllocationSize.QuadPart;
  3158. }
  3159. //
  3160. // If the File was encrypted, we need to reset the file size in the response
  3161. // buffer.
  3162. //
  3163. if (EncryptedFile) {
  3164. //
  3165. // Set the new AllocationSize and EndOfFile values.
  3166. //
  3167. CreateResponse->StandardInformation.AllocationSize.QuadPart = FileStdInfo.AllocationSize.QuadPart;
  3168. CreateResponse->StandardInformation.EndOfFile.QuadPart = FileStdInfo.EndOfFile.QuadPart;
  3169. }
  3170. CreateResponse->Handle = FileHandle;
  3171. CreateResponse->UserModeKey = (PVOID)FileHandle;
  3172. EXIT_THE_FUNCTION:
  3173. //
  3174. // The function RtlDosPathNameToNtPathName_U allocates memory from the
  3175. // processes heap. If we did, we need to free it now.
  3176. //
  3177. if (UnicodeFileName.Buffer != NULL) {
  3178. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeFileName.Buffer);
  3179. }
  3180. //
  3181. // Impersonate back again, so that we are in the context of
  3182. // the user who issued this request.
  3183. //
  3184. if (!didImpersonate) {
  3185. ULONG LocalStatus;
  3186. LocalStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  3187. if (LocalStatus != ERROR_SUCCESS) {
  3188. DavPrint((DEBUG_ERRORS,
  3189. "DavAsyncCreateGet/UMReflectorImpersonate. "
  3190. "Error Val = %d\n", LocalStatus));
  3191. if (WStatus == ERROR_SUCCESS) {
  3192. WStatus = LocalStatus;
  3193. }
  3194. }
  3195. didImpersonate = TRUE;
  3196. }
  3197. return WStatus;
  3198. }
  3199. VOID
  3200. DavAsyncCreateCompletion(
  3201. PDAV_USERMODE_WORKITEM DavWorkItem
  3202. )
  3203. /*++
  3204. Routine Description:
  3205. This routine handles the Create completion. It basically frees up the
  3206. resources allocated during the Create operation.
  3207. Arguments:
  3208. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  3209. Return Value:
  3210. none.
  3211. --*/
  3212. {
  3213. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  3214. CreateResponse = &(DavWorkItem->CreateResponse);
  3215. if (DavWorkItem->AsyncCreate.RemPathName != NULL) {
  3216. HLOCAL FreeHandle;
  3217. ULONG FreeStatus;
  3218. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncCreate.RemPathName);
  3219. if (FreeHandle != NULL) {
  3220. FreeStatus = GetLastError();
  3221. DavPrint((DEBUG_ERRORS,
  3222. "DavAsyncCreateCompletion/LocalFree(1). Error Val = %d\n",
  3223. FreeStatus));
  3224. }
  3225. }
  3226. if (DavWorkItem->AsyncCreate.UrlBuffer != NULL) {
  3227. HLOCAL FreeHandle;
  3228. ULONG FreeStatus;
  3229. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncCreate.UrlBuffer);
  3230. if (FreeHandle != NULL) {
  3231. FreeStatus = GetLastError();
  3232. DavPrint((DEBUG_ERRORS,
  3233. "DavAsyncCreateCompletion/LocalFree(2). Error Val = %d\n",
  3234. FreeStatus));
  3235. }
  3236. }
  3237. if (DavWorkItem->AsyncCreate.DataBuff != NULL) {
  3238. HLOCAL FreeHandle;
  3239. ULONG FreeStatus;
  3240. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncCreate.DataBuff);
  3241. if (FreeHandle != NULL) {
  3242. FreeStatus = GetLastError();
  3243. DavPrint((DEBUG_ERRORS,
  3244. "DavAsyncCreateCompletion/LocalFree(3). Error Val = %d\n",
  3245. FreeStatus));
  3246. }
  3247. }
  3248. if (DavWorkItem->AsyncCreate.didRead != NULL) {
  3249. HLOCAL FreeHandle;
  3250. ULONG FreeStatus;
  3251. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncCreate.didRead);
  3252. if (FreeHandle != NULL) {
  3253. FreeStatus = GetLastError();
  3254. DavPrint((DEBUG_ERRORS,
  3255. "DavAsyncCreateCompletion/LocalFree(4). Error Val = %d\n",
  3256. FreeStatus));
  3257. }
  3258. }
  3259. if (DavWorkItem->AsyncCreate.FileName != NULL) {
  3260. HLOCAL FreeHandle;
  3261. ULONG FreeStatus;
  3262. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncCreate.FileName);
  3263. if (FreeHandle != NULL) {
  3264. FreeStatus = GetLastError();
  3265. DavPrint((DEBUG_ERRORS,
  3266. "DavAsyncCreateCompletion/LocalFree(5). Error Val = %d\n",
  3267. FreeStatus));
  3268. }
  3269. }
  3270. if (DavWorkItem->AsyncCreate.FileHandle != NULL) {
  3271. BOOL ReturnVal;
  3272. ULONG CloseStatus;
  3273. ReturnVal = CloseHandle(DavWorkItem->AsyncCreate.FileHandle);
  3274. if (!ReturnVal) {
  3275. CloseStatus = GetLastError();
  3276. DavPrint((DEBUG_ERRORS,
  3277. "DavAsyncCreateCompletion/CloseHandle. "
  3278. "Error Val = %d\n", CloseStatus));
  3279. }
  3280. }
  3281. if (DavWorkItem->AsyncCreate.DavOpenHandle != NULL) {
  3282. BOOL ReturnVal;
  3283. ULONG FreeStatus;
  3284. ReturnVal = InternetCloseHandle( DavWorkItem->AsyncCreate.DavOpenHandle );
  3285. if (!ReturnVal) {
  3286. FreeStatus = GetLastError();
  3287. DavPrint((DEBUG_ERRORS,
  3288. "DavAsyncCreateCompletion/InternetCloseHandle. "
  3289. "Error Val = %d\n", FreeStatus));
  3290. }
  3291. }
  3292. if (DavWorkItem->AsyncCreate.lpCEI != NULL) {
  3293. HLOCAL FreeHandle;
  3294. ULONG FreeStatus;
  3295. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncCreate.lpCEI);
  3296. if (FreeHandle != NULL) {
  3297. FreeStatus = GetLastError();
  3298. DavPrint((DEBUG_ERRORS,
  3299. "DavAsyncCreateCompletion/LocalFree(6). Error Val = %d\n",
  3300. FreeStatus));
  3301. }
  3302. DavWorkItem->AsyncCreate.lpCEI = NULL;
  3303. }
  3304. if (DavWorkItem->AsyncResult != NULL) {
  3305. HLOCAL FreeHandle;
  3306. ULONG FreeStatus;
  3307. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncResult);
  3308. if (FreeHandle != NULL) {
  3309. FreeStatus = GetLastError();
  3310. DavPrint((DEBUG_ERRORS,
  3311. "DavAsyncCreateCompletion/LocalFree(7). Error Val = %d\n",
  3312. FreeStatus));
  3313. }
  3314. }
  3315. //
  3316. // If we did not succeed, but landed up creating a handle to the local file,
  3317. // we need to close that now.
  3318. //
  3319. if (DavWorkItem->Status != ERROR_SUCCESS) {
  3320. if (CreateResponse->Handle != NULL) {
  3321. NtClose(CreateResponse->Handle);
  3322. CreateResponse->Handle = NULL;
  3323. CreateResponse->UserModeKey = NULL;
  3324. }
  3325. }
  3326. //
  3327. // The callback context should not be finalized if we are returning
  3328. // ERROR_IO_PENDING.
  3329. //
  3330. DavFsFinalizeTheDavCallBackContext(DavWorkItem);
  3331. //
  3332. // We are done with the per user entry, so finalize it.
  3333. //
  3334. if (DavWorkItem->AsyncCreate.PerUserEntry) {
  3335. DavFinalizePerUserEntry( &(DavWorkItem->AsyncCreate.PerUserEntry) );
  3336. }
  3337. return;
  3338. }
  3339. BOOL
  3340. DavIsThisFileEncrypted(
  3341. PVOID DataBuff
  3342. )
  3343. /*++
  3344. Routine Description:
  3345. This routine checks the buffer supplied to see if it matches the first few
  3346. bytes of a BackedUp encrypted file.
  3347. Arguments:
  3348. DataBuff - The buffer to be checked.
  3349. Return Value:
  3350. TRUE - DataBuff matches the first few bytes of a BackedUp encrypted file.
  3351. FALSE - It does not.
  3352. --*/
  3353. {
  3354. if ( SIG_EFS_FILE != DavCheckSignature((char *)DataBuff + sizeof(ULONG)) ||
  3355. SIG_EFS_STREAM != DavCheckSignature((char *)DataBuff +
  3356. sizeof(EFSEXP_FILE_HEADER) +
  3357. sizeof(ULONG)) ||
  3358. SIG_EFS_DATA != DavCheckSignature((char *)DataBuff +
  3359. sizeof(EFSEXP_FILE_HEADER) +
  3360. sizeof(EFSEXP_STREAM_HEADER) +
  3361. sizeof(USHORT) +
  3362. sizeof(ULONG)) ||
  3363. EFS_STREAM_ID != *((USHORT *)((char *)DataBuff +
  3364. sizeof(EFSEXP_FILE_HEADER) +
  3365. sizeof(EFSEXP_STREAM_HEADER))) ||
  3366. EFS_EXP_FORMAT_CURRENT_VERSION != ((PEFSEXP_FILE_HEADER)DataBuff)->VersionID ) {
  3367. //
  3368. // Signature does not match.
  3369. //
  3370. return FALSE;
  3371. } else {
  3372. return TRUE;
  3373. }
  3374. }
  3375. ULONG
  3376. DavCheckSignature(
  3377. PVOID Signature
  3378. )
  3379. /*++
  3380. Routine Description:
  3381. This routine returns the signature type.
  3382. Arguments:
  3383. Signature - Signature string.
  3384. Return Value:
  3385. The type of signature. SIG_NO_MATCH for bogus signature.
  3386. --*/
  3387. {
  3388. if ( !memcmp( Signature, FILE_SIGNATURE, SIG_LENGTH ) ) {
  3389. return SIG_EFS_FILE;
  3390. }
  3391. if ( !memcmp( Signature, STREAM_SIGNATURE, SIG_LENGTH ) ) {
  3392. return SIG_EFS_STREAM;
  3393. }
  3394. if ( !memcmp( Signature, DATA_SIGNATURE, SIG_LENGTH ) ) {
  3395. return SIG_EFS_DATA;
  3396. }
  3397. return SIG_NO_MATCH;
  3398. }
  3399. DWORD
  3400. DavRestoreEncryptedFile(
  3401. PWCHAR ExportFile,
  3402. PWCHAR ImportFile
  3403. )
  3404. /*++
  3405. Routine Description:
  3406. This function performs the restoration of encrypted files. In other words
  3407. the import operation of the exported file by calling the appropriate EFS
  3408. APIs.
  3409. Arguments:
  3410. ExportFile - The File containing the backup.
  3411. ImportFile - The File with the restored data.
  3412. Return Value:
  3413. Returned value of the EFS APIs.
  3414. --*/
  3415. {
  3416. DWORD WStatus = ERROR_SUCCESS;
  3417. HANDLE RawImport = INVALID_HANDLE_VALUE;
  3418. PVOID RawContext = NULL;
  3419. DavPrint((DEBUG_MISC,
  3420. "DavRestoreEncryptedFile: ExportFile = %ws, ImportFile = %ws\n",
  3421. ExportFile, ImportFile));
  3422. RawImport = CreateFileW(ExportFile,
  3423. (GENERIC_WRITE | GENERIC_READ),
  3424. 0, // Exclusive access.
  3425. NULL,
  3426. OPEN_EXISTING,
  3427. FILE_ATTRIBUTE_ARCHIVE,
  3428. NULL);
  3429. if (RawImport == INVALID_HANDLE_VALUE) {
  3430. WStatus = GetLastError();
  3431. DavPrint((DEBUG_ERRORS,
  3432. "DavRestoreEncryptedFile/CreateFileW. Error Val = %d %ws\n",
  3433. WStatus,ExportFile));
  3434. goto EXIT_THE_FUNCTION;
  3435. }
  3436. //
  3437. // Open a raw context to the file.
  3438. //
  3439. WStatus = OpenEncryptedFileRawW(ImportFile, CREATE_FOR_IMPORT, &(RawContext));
  3440. if (WStatus != ERROR_SUCCESS) {
  3441. DavPrint((DEBUG_ERRORS,
  3442. "DavRestoreEncryptedFile/OpenEncryptedFileRaw. Error Val = %d %ws\n",
  3443. WStatus,ImportFile));
  3444. goto EXIT_THE_FUNCTION;
  3445. }
  3446. WStatus = WriteEncryptedFileRaw((PFE_IMPORT_FUNC)DavWriteRawCallback,
  3447. (PVOID)RawImport,
  3448. RawContext);
  3449. if (WStatus == RPC_X_PIPE_DISCIPLINE_ERROR) {
  3450. WStatus = ERROR_ACCESS_DENIED;
  3451. }
  3452. if (WStatus != ERROR_SUCCESS) {
  3453. DavPrint((DEBUG_ERRORS,
  3454. "DavRestoreEncryptedFile/WriteEncryptedFileRaw. Error Val = %d %ws\n",
  3455. WStatus,ImportFile));
  3456. }
  3457. EXIT_THE_FUNCTION:
  3458. if (RawImport != INVALID_HANDLE_VALUE) {
  3459. CloseHandle(RawImport);
  3460. }
  3461. if (RawContext) {
  3462. CloseEncryptedFileRaw(RawContext);
  3463. }
  3464. return WStatus;
  3465. }
  3466. DWORD
  3467. DavWriteRawCallback(
  3468. PBYTE DataBuff,
  3469. PVOID CallbackContext,
  3470. PULONG DataLength
  3471. )
  3472. /*++
  3473. Routine Description:
  3474. Call-back function for WriteEncryptedFileRaw() called in Restore(). This
  3475. function reads the backed up data from the backup file, and provides it to
  3476. WriteEncryptedFileRaw() through this callback function which in turn
  3477. transforms the raw data back to its original form. This call-back function
  3478. is called until all the data content has been read.
  3479. Arguments:
  3480. DataBuffer - Data to be read.
  3481. CallbackContext - Handle to the Backup file.
  3482. DataLength - Size of the DataBuffer.
  3483. Return Value:
  3484. Returned value of the operation.
  3485. --*/
  3486. {
  3487. DWORD WStatus = ERROR_SUCCESS;
  3488. BOOL ReturnVal;
  3489. DWORD BytesRead = 0;
  3490. DavPrint((DEBUG_MISC, "DavWriteRawCallback: DataLength = %d\n", *DataLength));
  3491. //
  3492. // Restore the file's content with the information stored in the temporary
  3493. // location.
  3494. //
  3495. ReturnVal = ReadFile((HANDLE)CallbackContext,
  3496. DataBuff,
  3497. *DataLength,
  3498. &(BytesRead),
  3499. NULL);
  3500. if ( !ReturnVal ) {
  3501. WStatus = GetLastError();
  3502. DavPrint((DEBUG_ERRORS,
  3503. "DavWriteRawCallback/ReadFile. Error Val = %d\n", WStatus));
  3504. }
  3505. DavPrint((DEBUG_MISC, "DavWriteRawCallback: BytesRead = %d\n", BytesRead));
  3506. *DataLength = BytesRead;
  3507. return WStatus;
  3508. }
  3509. DWORD
  3510. DavReuseCacheFileIfNotModified(
  3511. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  3512. )
  3513. /*++
  3514. Routine Description:
  3515. If we get an NOT-MODIFIED response, then we just get the filename from wininet and use it
  3516. Arguments:
  3517. pDavWorkItem - The buffer that contains the request parameters and options.
  3518. Return Value:
  3519. ERROR_SUCCESS or the appropriate error code.
  3520. --*/
  3521. {
  3522. DWORD dwError = ERROR_SUCCESS;
  3523. PWCHAR pFileNameBuff = NULL;
  3524. DWORD dwBufferSize = 0, dwStatus = 0;
  3525. LPINTERNET_CACHE_ENTRY_INFOW lpCEI = NULL;
  3526. lpCEI = (LPINTERNET_CACHE_ENTRY_INFOW)pDavWorkItem->AsyncCreate.lpCEI;
  3527. if (!pDavWorkItem->AsyncCreate.lpCEI) {
  3528. return ERROR_FILE_NOT_FOUND;
  3529. }
  3530. dwBufferSize = sizeof(dwStatus);
  3531. if (!HttpQueryInfoW(pDavWorkItem->AsyncCreate.DavOpenHandle,
  3532. (HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER),
  3533. (LPVOID)&dwStatus,
  3534. &dwBufferSize,
  3535. NULL)) {
  3536. return GetLastError();
  3537. }
  3538. if (dwStatus == HTTP_STATUS_NOT_MODIFIED) {
  3539. pFileNameBuff = LocalAlloc(LPTR, (lstrlen(lpCEI->lpszLocalFileName) + 1) * sizeof(WCHAR));
  3540. if (pFileNameBuff) {
  3541. dwError = ERROR_SUCCESS;
  3542. pDavWorkItem->AsyncCreate.FileName = pFileNameBuff;
  3543. if (!InternetCloseHandle(pDavWorkItem->AsyncCreate.DavOpenHandle)) {
  3544. dwError = GetLastError();
  3545. LocalFree(pFileNameBuff);
  3546. pFileNameBuff = NULL;
  3547. pDavWorkItem->AsyncCreate.FileName = NULL;
  3548. } else {
  3549. pDavWorkItem->AsyncCreate.DavOpenHandle = NULL;
  3550. wcscpy(pDavWorkItem->CreateResponse.FileName, lpCEI->lpszLocalFileName);
  3551. wcscpy(pDavWorkItem->AsyncCreate.FileName, lpCEI->lpszLocalFileName);
  3552. }
  3553. goto EXIT_THE_FUNCTION;
  3554. }
  3555. } else {
  3556. dwError = ERROR_FILE_NOT_FOUND;
  3557. }
  3558. EXIT_THE_FUNCTION:
  3559. return dwError;
  3560. }
  3561. DWORD
  3562. DavCreateUrlCacheEntry(
  3563. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  3564. )
  3565. /*++
  3566. Routine Description:
  3567. This routine creates an entry for a file in the WinInet's cache.
  3568. Arguments:
  3569. pDavWorkItem - The buffer that contains the request parameters and options.
  3570. Return Value:
  3571. ERROR_SUCCESS or the appropriate error code.
  3572. --*/
  3573. {
  3574. DWORD dwError = ERROR_SUCCESS;
  3575. PWCHAR pFileExt = NULL;
  3576. PWCHAR pFileNameBuff = NULL;
  3577. BOOL ReturnVal = FALSE;
  3578. //
  3579. // Get the file extension. For now we assume that the extension follows the
  3580. // last '.' char. We do a ++ after the call to wcsrchr to go past the '.'.
  3581. // If '.' itself is the last char, the extension is NULL.
  3582. //
  3583. if ( *(pDavWorkItem->AsyncCreate.RemPathName) ) {
  3584. pFileExt = ( pDavWorkItem->AsyncCreate.RemPathName + (wcslen(pDavWorkItem->AsyncCreate.RemPathName) - 1) );
  3585. while (pFileExt != pDavWorkItem->AsyncCreate.RemPathName) {
  3586. if ( *pFileExt == L'.' || *pFileExt == L'/' || *pFileExt == L'\\' ) {
  3587. break;
  3588. }
  3589. pFileExt--;
  3590. }
  3591. if ( pFileExt != pDavWorkItem->AsyncCreate.RemPathName && *pFileExt == L'.' && *(pFileExt + 1) != '\0' ) {
  3592. pFileExt++;
  3593. DavPrint((DEBUG_MISC, "DavCreateUrlCacheEntry. FileExt: %ws\n", pFileExt));
  3594. } else {
  3595. pFileExt = NULL;
  3596. DavPrint((DEBUG_MISC, "DavCreateUrlCacheEntry. No FileExt.\n"));
  3597. }
  3598. } else {
  3599. pFileExt = NULL;
  3600. DavPrint((DEBUG_MISC, "DavCreateUrlCacheEntry. No FileExt.\n"));
  3601. }
  3602. DavPrint((DEBUG_MISC, "DavCreateUrlCacheEntry. pFileExt: %ws\n", pFileExt));
  3603. //
  3604. // Allocate memory for pFileNameBuff.
  3605. //
  3606. pFileNameBuff = LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT, MAX_PATH * sizeof(WCHAR));
  3607. if (pFileNameBuff == NULL) {
  3608. dwError = GetLastError();
  3609. DavPrint((DEBUG_ERRORS,
  3610. "DavCreateUrlCacheEntry/LocalAlloc. Error Val = %d\n",
  3611. dwError));
  3612. goto EXIT_THE_FUNCTION;
  3613. }
  3614. //
  3615. // Create a file name for the URL in the cache.
  3616. //
  3617. ReturnVal = CreateUrlCacheEntryW(pDavWorkItem->AsyncCreate.UrlBuffer,
  3618. 0,
  3619. pFileExt,
  3620. pFileNameBuff,
  3621. 0);
  3622. //
  3623. // The CreateUrlCacheEntry API call may fail with GetLastError() =
  3624. // ERROR_FILENAME_EXCED_RANGE for long extension names. In such a scenario
  3625. // we make the call again with the file extension set to NULL.
  3626. //
  3627. if (!ReturnVal && pFileExt != NULL) {
  3628. DavPrint((DEBUG_ERRORS,
  3629. "DavCreateUrlCacheEntry/CreateUrlCacheEntry(1). Error Val = %d\n",
  3630. GetLastError()));
  3631. //
  3632. // Another attempt to create a file name for the URL in the cache with
  3633. // no extension name.
  3634. //
  3635. pFileExt = NULL;
  3636. ReturnVal = CreateUrlCacheEntryW(pDavWorkItem->AsyncCreate.UrlBuffer,
  3637. 0,
  3638. NULL,
  3639. pFileNameBuff,
  3640. 0);
  3641. }
  3642. //
  3643. // If we've failed the both the calls, then we return the failure.
  3644. //
  3645. if (!ReturnVal) {
  3646. dwError = GetLastError();
  3647. DavPrint((DEBUG_ERRORS,
  3648. "DavCreateUrlCacheEntry/CreateUrlCacheEntry(2). Error Val = %d %ws\n",
  3649. dwError, pDavWorkItem->AsyncCreate.FileName));
  3650. goto EXIT_THE_FUNCTION;
  3651. }
  3652. pDavWorkItem->AsyncCreate.FileName = pFileNameBuff;
  3653. DavPrint((DEBUG_MISC,
  3654. "DavCreateUrlCacheEntry: FileName = %ws\n",
  3655. pDavWorkItem->AsyncCreate.FileName));
  3656. //
  3657. // Copy the file name in the response buffer.
  3658. //
  3659. wcscpy(pDavWorkItem->CreateResponse.FileName, pDavWorkItem->AsyncCreate.FileName);
  3660. EXIT_THE_FUNCTION:
  3661. //
  3662. // If we did not succeed then we need to free up the memory allocated for
  3663. // pFileNameBuff (if we did allocate at all).
  3664. //
  3665. if (dwError != ERROR_SUCCESS) {
  3666. if (pFileNameBuff != NULL) {
  3667. LocalFree(pFileNameBuff);
  3668. pDavWorkItem->AsyncCreate.FileName = NULL;
  3669. }
  3670. }
  3671. return dwError;
  3672. }
  3673. WCHAR wszEtagHeader[] = L"ETag: ";
  3674. #define CONST_TEN_MINUTES ((LONGLONG)10 * 60 * 10000000)
  3675. DWORD
  3676. DavCommitUrlCacheEntry(
  3677. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  3678. )
  3679. /*++
  3680. Routine Description:
  3681. This routine commits (pins) the entry for a file in the WinInet's cache.
  3682. This entry would have been created using DavCreateUrlCacheEntry.
  3683. Arguments:
  3684. pDavWorkItem - The buffer that contains the request parameters and options.
  3685. Return Value:
  3686. ERROR_SUCCESS or the appropriate error code.
  3687. --*/
  3688. {
  3689. DWORD dwTemp, dwIndex;
  3690. SYSTEMTIME sSystemTime;
  3691. BOOL fRet= FALSE, fHasEtag = FALSE;
  3692. FILETIME ExTime, LmTime;
  3693. char chEtagBuff[1024];
  3694. dwTemp = sizeof(SYSTEMTIME);
  3695. dwIndex = 0;
  3696. //
  3697. // If the expiry time is available in the OpenHandle, get it.
  3698. //
  3699. if( !HttpQueryInfo(pDavWorkItem->AsyncCreate.DavOpenHandle,
  3700. (HTTP_QUERY_EXPIRES | HTTP_QUERY_FLAG_SYSTEMTIME),
  3701. &sSystemTime,
  3702. &dwTemp,
  3703. &dwIndex)
  3704. ||
  3705. !SystemTimeToFileTime(&sSystemTime, &ExTime) ) {
  3706. SYSTEMTIME sSysT;
  3707. GetSystemTime(&sSysT);
  3708. SystemTimeToFileTime(&sSysT, &ExTime);
  3709. *(LONGLONG *)&ExTime += CONST_TEN_MINUTES;
  3710. }
  3711. dwTemp = sizeof(SYSTEMTIME);
  3712. dwIndex = 0;
  3713. //
  3714. // If the last modified time is available in the OpenHandle, get it.
  3715. //
  3716. if( !HttpQueryInfo(pDavWorkItem->AsyncCreate.DavOpenHandle,
  3717. (HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME),
  3718. &sSystemTime,
  3719. &dwTemp,
  3720. &dwIndex)
  3721. ||
  3722. !SystemTimeToFileTime(&sSystemTime, &LmTime) ) {
  3723. LmTime.dwLowDateTime = 0;
  3724. LmTime.dwHighDateTime = 0;
  3725. }
  3726. #if 0
  3727. dwIndex = 0;
  3728. memcpy(chEtagBuff, wszEtagHeader, sizeof(wszEtagHeader)-2);
  3729. dwTemp = sizeof(chEtagBuff)-(sizeof(wszEtagHeader)-2);
  3730. if( HttpQueryInfo(pDavWorkItem->AsyncCreate.DavOpenHandle,
  3731. HTTP_QUERY_ETAG,
  3732. ( chEtagBuff + sizeof(wszEtagHeader) - 2 ),
  3733. &dwTemp,
  3734. &dwIndex) ) {
  3735. fHasEtag = TRUE;
  3736. dwTemp += sizeof(wszEtagHeader)-2;
  3737. DavPrint((DEBUG_ERRORS,
  3738. "DavCreateUrlCacheEntry/CreateUrlCacheEntry. Etag %s\n",
  3739. chEtagBuff));
  3740. }
  3741. #endif
  3742. //
  3743. // Close the DavOpenHandle. This needs to be done, otherwise the commit
  3744. // below will fail with SHARING_VIOLATON as WinInet has a cached file open.
  3745. //
  3746. fRet = InternetCloseHandle(pDavWorkItem->AsyncCreate.DavOpenHandle);
  3747. if (!fRet) {
  3748. DavPrint((DEBUG_ERRORS,
  3749. "DavCommitUrlCacheEntry/InternetCloseHandle = %d\n",
  3750. GetLastError()));
  3751. goto bailout;
  3752. }
  3753. pDavWorkItem->AsyncCreate.DavOpenHandle = NULL;
  3754. fRet = CommitUrlCacheEntryW(pDavWorkItem->AsyncCreate.UrlBuffer,
  3755. pDavWorkItem->AsyncCreate.FileName,
  3756. ExTime,
  3757. LmTime,
  3758. STICKY_CACHE_ENTRY,
  3759. (fHasEtag ? ((LPWSTR)chEtagBuff) : NULL),
  3760. (fHasEtag ? dwTemp : 0),
  3761. NULL,
  3762. NULL);
  3763. if (!fRet) {
  3764. DavPrint((DEBUG_ERRORS,
  3765. "DavCommitUrlCacheEntry/CommitUrlCacheEntryW = %d\n",
  3766. GetLastError()));
  3767. }
  3768. bailout:
  3769. if (!fRet) {
  3770. return GetLastError();
  3771. } else {
  3772. return ERROR_SUCCESS;
  3773. }
  3774. }
  3775. DWORD
  3776. DavSetAclForEncryptedFile(
  3777. PWCHAR FilePath
  3778. )
  3779. /*++
  3780. Routine Description:
  3781. This routine set the ACLs on the file that allows everybody to access it.
  3782. Arguments:
  3783. FilePath - The path of the file.
  3784. Return Value:
  3785. ERROR_SUCCESS or the appropriate error code.
  3786. --*/
  3787. {
  3788. DWORD status = NO_ERROR;
  3789. DWORD cb = 0;
  3790. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  3791. //
  3792. // Initialize the Security Descriptor with the ACL allowing everybody to
  3793. // access the file.
  3794. //
  3795. if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(L"D:(A;;GAGRGWGX;;;WD)",
  3796. SDDL_REVISION_1,
  3797. &SecurityDescriptor,
  3798. &cb)) {
  3799. status = GetLastError();
  3800. DavPrint((DEBUG_ERRORS,
  3801. "DavSetAclForEncryptedFile/ConvertStringSecurityDescriptorToSecurityDescriptorW = %d\n",
  3802. status));
  3803. goto EXIT_THE_FUNCTION;
  3804. }
  3805. //
  3806. // Put the DACL onto the file.
  3807. //
  3808. if (!SetFileSecurity(FilePath,
  3809. DACL_SECURITY_INFORMATION,
  3810. SecurityDescriptor)) {
  3811. status = GetLastError();
  3812. DavPrint((DEBUG_ERRORS,
  3813. "DavSetAclForEncryptedFile/SetFileSecurity = %d\n",
  3814. status));
  3815. }
  3816. EXIT_THE_FUNCTION:
  3817. if (SecurityDescriptor) {
  3818. LocalFree(SecurityDescriptor);
  3819. }
  3820. return status;
  3821. }
  3822. DWORD
  3823. DavQueryUrlCacheEntry(
  3824. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  3825. )
  3826. /*++
  3827. Routine Description:
  3828. This routine is called to Create a entry in the WinInet cache for the
  3829. given URL.
  3830. Arguments:
  3831. pDavWorkItem - The buffer that contains the request parameters and options.
  3832. Return Value:
  3833. ERROR_SUCCESS or the appropriate error code.
  3834. --*/
  3835. {
  3836. DWORD dwError = ERROR_SUCCESS;
  3837. DWORD cbCEI = 0, count = 0;
  3838. LPINTERNET_CACHE_ENTRY_INFOW lpCEI = NULL;
  3839. if (pDavWorkItem->AsyncCreate.lpCEI != NULL) {
  3840. return ERROR_SUCCESS;
  3841. }
  3842. cbCEI = ( sizeof(INTERNET_CACHE_ENTRY_INFOW) + (MAX_PATH * 2) );
  3843. do {
  3844. lpCEI = LocalAlloc(LPTR, cbCEI);
  3845. if (!lpCEI) {
  3846. dwError = GetLastError();
  3847. break;
  3848. }
  3849. ++count;
  3850. if ( !GetUrlCacheEntryInfo(pDavWorkItem->AsyncCreate.UrlBuffer, lpCEI, &cbCEI) ) {
  3851. if ((dwError = GetLastError()) == ERROR_INSUFFICIENT_BUFFER) {
  3852. LocalFree(lpCEI);
  3853. lpCEI = NULL;
  3854. } else {
  3855. DavPrint((DEBUG_MISC,
  3856. "DavQueryUrlCacheEntry/GetUrlCacheEntryInfo: dwError = %d, UrlBuffer = %ws\n",
  3857. dwError, pDavWorkItem->AsyncCreate.UrlBuffer));
  3858. break;
  3859. }
  3860. } else {
  3861. dwError = ERROR_SUCCESS;
  3862. break;
  3863. }
  3864. } while (count < 2);
  3865. if (dwError == ERROR_SUCCESS) {
  3866. pDavWorkItem->AsyncCreate.lpCEI = lpCEI;
  3867. } else {
  3868. //
  3869. // If some error occurred in adding the header, set the correct error
  3870. // code.
  3871. //
  3872. dwError = GetLastError();
  3873. if (lpCEI) {
  3874. LocalFree(lpCEI);
  3875. lpCEI = NULL;
  3876. }
  3877. }
  3878. return dwError;
  3879. }
  3880. DWORD
  3881. DavAddIfModifiedSinceHeader(
  3882. IN PDAV_USERMODE_WORKITEM pDavWorkItem
  3883. )
  3884. /*++
  3885. Routine Description:
  3886. This routine is called to add the If-Modified-Since header to the request
  3887. being sent to the server.
  3888. Arguments:
  3889. pDavWorkItem - The buffer that contains the request parameters and options.
  3890. Return Value:
  3891. ERROR_SUCCESS or the appropriate error code.
  3892. --*/
  3893. {
  3894. DWORD dwError = ERROR_SUCCESS;
  3895. DWORD cbCEI = 0, count = 0;
  3896. LPINTERNET_CACHE_ENTRY_INFOW lpCEI = NULL;
  3897. CHAR chBuff[(sizeof(rgchIMS) + INTERNET_RFC1123_BUFSIZE + 5)];
  3898. SYSTEMTIME systemtime;
  3899. if (pDavWorkItem->AsyncCreate.lpCEI == NULL) {
  3900. DavQueryUrlCacheEntry(pDavWorkItem);
  3901. }
  3902. lpCEI = pDavWorkItem->AsyncCreate.lpCEI;
  3903. if ((lpCEI != NULL) &&
  3904. ((lpCEI->LastModifiedTime.dwLowDateTime != 0) ||
  3905. (lpCEI->LastModifiedTime.dwHighDateTime != 0)) &&
  3906. FileTimeToSystemTime((CONST FILETIME *)&(lpCEI->LastModifiedTime), &systemtime)) {
  3907. memcpy(chBuff, rgchIMS, (sizeof(rgchIMS) - 1));
  3908. chBuff[((sizeof(rgchIMS)) - 1)] = ':';
  3909. chBuff[sizeof(rgchIMS)] = ' ';
  3910. if (InternetTimeFromSystemTimeA((CONST SYSTEMTIME *)&systemtime,
  3911. INTERNET_RFC1123_FORMAT,
  3912. &chBuff[(sizeof(rgchIMS) + 1)],
  3913. (sizeof(chBuff) - sizeof(rgchIMS) - 2))) {
  3914. HttpAddRequestHeadersA(pDavWorkItem->AsyncCreate.DavOpenHandle,
  3915. chBuff,
  3916. lstrlenA(chBuff),
  3917. (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
  3918. }
  3919. }
  3920. return dwError;
  3921. }
  3922. DWORD
  3923. DavLockTheFileOnTheServer(
  3924. IN PDAV_USERMODE_WORKITEM DavWorkItem
  3925. )
  3926. /*++
  3927. Routine Description:
  3928. This routine is called during the create when we need to LOCK the file on
  3929. the server. This is done to provide consistency so that users do not
  3930. overwrite each others data.
  3931. IMPORTANT!! Its important to note that if we fail to LOCK the file on the
  3932. server because the DAV server doesn't support LOCKs, we do not fail the
  3933. create call. This is because according to the DAV RFC, a server is not
  3934. required to support LOCKs. So, if the server returns 405 (Method not
  3935. allowed), this function will return ERROR_SUCCESS back to the caller.
  3936. Arguments:
  3937. DavWorkItem - The buffer that contains the request parameters and options.
  3938. Return Value:
  3939. ERROR_SUCCESS or the appropriate error code.
  3940. --*/
  3941. {
  3942. DWORD WStatus = ERROR_SUCCESS;
  3943. HINTERNET DavOpenHandle = NULL;
  3944. BOOL BStatus = FALSE, ReturnVal = FALSE, readDone = FALSE, fileIsLocked = FALSE;
  3945. PWCHAR PassportCookie = NULL;
  3946. PCHAR LockRequestBuffer = NULL, lpTemp = NULL, DataBuff = NULL;
  3947. PCHAR UserNameBuffer = NULL;
  3948. ULONG LockRequestBufferLength = 0, ResponseStatus = 0, UserNameSize = 0;
  3949. DAV_FILE_ATTRIBUTES DavFileAttributes;
  3950. PVOID Ctx1 = NULL, Ctx2 = NULL;
  3951. DWORD NumRead = 0, NumOfFileEntries = 0, TotalDataBytesRead = 0;
  3952. PDAV_USERMODE_CREATE_RESPONSE CreateResponse;
  3953. DavPrint((DEBUG_MISC,
  3954. "DavLockTheFileOnTheServer. Locking File: %ws\n",
  3955. DavWorkItem->AsyncCreate.RemPathName));
  3956. //
  3957. // Get the UserName of the user in whose context this LOCK is being
  3958. // issued. The first GetUserNameExA call is to get the number of chars
  3959. // necessary to hold the UserName. The return value is ERROR_MORE_DATA
  3960. // and not ERROR_INSUFFICIENT_BUFFER if the buffer passed in is not of
  3961. // sufficient length.
  3962. //
  3963. ReturnVal = GetUserNameExA(NameSamCompatible, UserNameBuffer, &UserNameSize);
  3964. if (!ReturnVal) {
  3965. WStatus = GetLastError();
  3966. if (WStatus != ERROR_MORE_DATA) {
  3967. DavPrint((DEBUG_ERRORS,
  3968. "DavLockTheFileOnTheServer/GetUserNameExA(1). Error Val = %d\n",
  3969. WStatus));
  3970. goto EXIT_THE_FUNCTION;
  3971. }
  3972. }
  3973. UserNameBuffer = LocalAlloc(LPTR, UserNameSize * sizeof(CHAR));
  3974. if (UserNameBuffer == NULL) {
  3975. WStatus = GetLastError();
  3976. DavPrint((DEBUG_ERRORS,
  3977. "DavLockTheFileOnTheServer/LocalAlloc. Error Val = %d\n",
  3978. WStatus));
  3979. goto EXIT_THE_FUNCTION;
  3980. }
  3981. ReturnVal = GetUserNameExA(NameSamCompatible, UserNameBuffer, &UserNameSize);
  3982. if (!ReturnVal) {
  3983. WStatus = GetLastError();
  3984. DavPrint((DEBUG_ERRORS,
  3985. "DavLockTheFileOnTheServer/GetUserNameExA(2). Error Val = %d\n",
  3986. WStatus));
  3987. goto EXIT_THE_FUNCTION;
  3988. }
  3989. DavPrint((DEBUG_MISC,
  3990. "DavLockTheFileOnTheServer. UserNameBuffer: %s\n",
  3991. UserNameBuffer));
  3992. //
  3993. // Allocate the buffer big enough to hold the entire XML LOCK request
  3994. // that has to be sent to the server.
  3995. //
  3996. LockRequestBufferLength = strlen(rgLockInfoHeader);
  3997. LockRequestBufferLength += strlen(rgLockInfoTrailer);
  3998. LockRequestBufferLength += strlen(rgLockScopeHeader);
  3999. LockRequestBufferLength += strlen(rgLockTypeHeader);
  4000. LockRequestBufferLength += strlen(rgOwnerHeader);
  4001. LockRequestBufferLength += strlen(rgOwnerTrailer);
  4002. LockRequestBufferLength += strlen(UserNameBuffer);
  4003. LockRequestBufferLength += 1; // for the final \0 char.
  4004. LockRequestBufferLength = LockRequestBufferLength * sizeof(CHAR);
  4005. LockRequestBuffer = LocalAlloc(LPTR, LockRequestBufferLength);
  4006. if (LockRequestBuffer == NULL) {
  4007. WStatus = GetLastError();
  4008. DavPrint((DEBUG_ERRORS,
  4009. "DavLockTheFileOnTheServer/DavHttpOpenRequestW. Error Val = %d\n",
  4010. WStatus));
  4011. goto EXIT_THE_FUNCTION;
  4012. }
  4013. //
  4014. // Format the XML LOCK request that needs to be sent to the server.
  4015. //
  4016. memset(LockRequestBuffer, 0, sizeof(LockRequestBuffer));
  4017. lpTemp = LockRequestBuffer;
  4018. memcpy(lpTemp, rgLockInfoHeader, (sizeof(rgLockInfoHeader) - 1));
  4019. lpTemp += (sizeof(rgLockInfoHeader) - 1);
  4020. memcpy(lpTemp, rgLockScopeHeader, (sizeof(rgLockScopeHeader) - 1));
  4021. lpTemp += (sizeof(rgLockScopeHeader) - 1);
  4022. memcpy(lpTemp, rgLockTypeHeader, (sizeof(rgLockTypeHeader) - 1));
  4023. lpTemp += (sizeof(rgLockTypeHeader) - 1);
  4024. memcpy(lpTemp, rgOwnerHeader, (sizeof(rgOwnerHeader) - 1));
  4025. lpTemp += (sizeof(rgOwnerHeader) - 1);
  4026. memcpy(lpTemp, UserNameBuffer, (strlen(UserNameBuffer) * sizeof(CHAR)));
  4027. lpTemp += (strlen(UserNameBuffer) * sizeof(CHAR));
  4028. memcpy(lpTemp, rgOwnerTrailer, (sizeof(rgOwnerTrailer) - 1));
  4029. lpTemp += (sizeof(rgOwnerTrailer) - 1);
  4030. memcpy(lpTemp, rgLockInfoTrailer, (sizeof(rgLockInfoTrailer) - 1));
  4031. //
  4032. // Convert the unicode object name to UTF-8 URL format.
  4033. // Space and other white characters will remain untouched - these should
  4034. // be taken care of by wininet calls.
  4035. // This has to be a W API as the name in CloseRequest is unicode.
  4036. //
  4037. BStatus = DavHttpOpenRequestW(DavWorkItem->AsyncCreate.PerUserEntry->DavConnHandle,
  4038. L"LOCK",
  4039. DavWorkItem->AsyncCreate.RemPathName,
  4040. L"HTTP/1.1",
  4041. NULL,
  4042. NULL,
  4043. INTERNET_FLAG_KEEP_CONNECTION |
  4044. INTERNET_FLAG_NO_COOKIES |
  4045. INTERNET_FLAG_RELOAD,
  4046. 0,
  4047. L"DavLockTheFileOnTheServer",
  4048. &DavOpenHandle);
  4049. if(BStatus == FALSE) {
  4050. WStatus = GetLastError();
  4051. goto EXIT_THE_FUNCTION;
  4052. }
  4053. if (DavOpenHandle == NULL) {
  4054. WStatus = GetLastError();
  4055. DavPrint((DEBUG_ERRORS,
  4056. "DavLockTheFileOnTheServer/DavHttpOpenRequestW. Error Val = %d\n",
  4057. WStatus));
  4058. goto EXIT_THE_FUNCTION;
  4059. }
  4060. //
  4061. // We need to add the header "translate:f" to tell IIS that it should
  4062. // allow the user to excecute this VERB on the specified path which it
  4063. // would not allow (in some cases) otherwise. Finally, there is a special
  4064. // flag in the metabase to allow for uploading of "dangerous" content
  4065. // (anything that can be run on the server). This is the ScriptSourceAccess
  4066. // flag in the UI or the AccessSource flag in the metabase. You will need
  4067. // to set this bit to true as well as correct NT ACLs in order to be able
  4068. // to upload .exes or anything executable. We set this header on all requests
  4069. // that are sent to the server including the LOCK request.
  4070. //
  4071. ReturnVal = HttpAddRequestHeadersA(DavOpenHandle,
  4072. "translate: f\n",
  4073. -1,
  4074. HTTP_ADDREQ_FLAG_ADD |
  4075. HTTP_ADDREQ_FLAG_REPLACE);
  4076. if (!ReturnVal) {
  4077. WStatus = GetLastError();
  4078. DavPrint((DEBUG_ERRORS,
  4079. "DavLockTheFileOnTheServer/HttpAddRequestHeadersA. Error Val = %d\n",
  4080. WStatus));
  4081. goto EXIT_THE_FUNCTION;
  4082. }
  4083. WStatus = DavAttachPassportCookie(DavWorkItem, DavOpenHandle, &PassportCookie);
  4084. if (WStatus != ERROR_SUCCESS) {
  4085. DavPrint((DEBUG_ERRORS,
  4086. "DavLockTheFileOnTheServer/DavAttachPassportCookie. Error Val = %d\n",
  4087. WStatus));
  4088. goto EXIT_THE_FUNCTION;
  4089. }
  4090. WStatus = DavInternetSetOption(DavWorkItem, DavOpenHandle);
  4091. if (WStatus != ERROR_SUCCESS) {
  4092. DavPrint((DEBUG_ERRORS,
  4093. "DavLockTheFileOnTheServer/DavInternetSetOption. Error Val = %d\n",
  4094. WStatus));
  4095. goto EXIT_THE_FUNCTION;
  4096. }
  4097. //
  4098. // Request the LOCK on this resource for an hour. We will have to refresh
  4099. // the LOCK request if we need to keep the LOCK request for more than an
  4100. // hour.
  4101. //
  4102. ReturnVal = HttpAddRequestHeadersA(DavOpenHandle,
  4103. "Timeout: Second-3600\n",
  4104. -1L,
  4105. HTTP_ADDREQ_FLAG_ADD |
  4106. HTTP_ADDREQ_FLAG_REPLACE);
  4107. if (!ReturnVal) {
  4108. WStatus = GetLastError();
  4109. DavPrint((DEBUG_ERRORS,
  4110. "DavLockTheFileOnTheServer/HttpAddRequestHeadersA. Error Val = %d\n",
  4111. WStatus));
  4112. goto EXIT_THE_FUNCTION;
  4113. }
  4114. ReturnVal = HttpSendRequestA(DavOpenHandle,
  4115. rgHttpHeader,
  4116. strlen(rgHttpHeader),
  4117. (LPVOID)LockRequestBuffer,
  4118. strlen(LockRequestBuffer));
  4119. if (!ReturnVal) {
  4120. WStatus = GetLastError();
  4121. DavPrint((DEBUG_ERRORS,
  4122. "DavLockTheFileOnTheServer/HttpSendRequestA: Error Val = %d\n",
  4123. WStatus));
  4124. goto EXIT_THE_FUNCTION;
  4125. }
  4126. WStatus = DavQueryAndParseResponseEx(DavOpenHandle, &ResponseStatus);
  4127. if (WStatus != ERROR_SUCCESS) {
  4128. //
  4129. // If the server doesn't support the LOCK operation, we do not fail the
  4130. // create call.
  4131. //
  4132. if (ResponseStatus == HTTP_STATUS_NOT_SUPPORTED) {
  4133. WStatus = ERROR_SUCCESS;
  4134. goto EXIT_THE_FUNCTION;
  4135. } else if (ResponseStatus == DAV_STATUS_LOCKED) {
  4136. //
  4137. // If the return status from the server was 423 (the file is locked
  4138. // by someone else) then we still need to parse the XML response
  4139. // to find out who the owner of the LOCK is. This information is
  4140. // displayed to the user.
  4141. //
  4142. DavPrint((DEBUG_ERRORS,
  4143. "DavLockTheFileOnTheServer/DavQueryAndParseResponseEx: Error Val = %d\n",
  4144. WStatus));
  4145. fileIsLocked = TRUE;
  4146. } else {
  4147. SetLastError(WStatus);
  4148. DavPrint((DEBUG_ERRORS,
  4149. "DavLockTheFileOnTheServer/DavQueryAndParseResponseEx: Error Val = %d\n",
  4150. WStatus));
  4151. goto EXIT_THE_FUNCTION;
  4152. }
  4153. }
  4154. DataBuff = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, NUM_OF_BYTES_TO_READ);
  4155. if (DataBuff == NULL) {
  4156. WStatus = GetLastError();
  4157. DavPrint((DEBUG_ERRORS,
  4158. "DavLockTheFileOnTheServer/LocalAlloc(2): WStatus = %08lx\n",
  4159. WStatus));
  4160. goto EXIT_THE_FUNCTION;
  4161. }
  4162. //
  4163. // Read the response and parse it.
  4164. //
  4165. do {
  4166. ReturnVal = InternetReadFile(DavOpenHandle,
  4167. (LPVOID)DataBuff,
  4168. NUM_OF_BYTES_TO_READ,
  4169. &(NumRead));
  4170. if (!ReturnVal) {
  4171. WStatus = GetLastError();
  4172. DavPrint((DEBUG_ERRORS,
  4173. "DavLockTheFileOnTheServer/InternetReadFile: WStatus = "
  4174. "%08lx\n", WStatus));
  4175. goto EXIT_THE_FUNCTION;
  4176. }
  4177. DavPrint((DEBUG_MISC, "DavLockTheFileOnTheServer: NumRead = %d\n", NumRead));
  4178. //
  4179. // We reject files whose attributes are greater than a
  4180. // certain size (DavFileAttributesLimitInBytes). This
  4181. // is a parameter that can be set in the registry. This
  4182. // is done to avoid attacks by rogue servers.
  4183. //
  4184. TotalDataBytesRead += NumRead;
  4185. if (TotalDataBytesRead > DavFileAttributesLimitInBytes) {
  4186. WStatus = ERROR_BAD_NET_RESP;
  4187. DavPrint((DEBUG_ERRORS, "DavLockTheFileOnTheServer. LockResponseSize > %d\n", DavFileAttributesLimitInBytes));
  4188. goto EXIT_THE_FUNCTION;
  4189. }
  4190. readDone = (NumRead == 0) ? TRUE : FALSE;
  4191. WStatus = DavPushData(DataBuff, &Ctx1, &Ctx2, NumRead, readDone);
  4192. if (WStatus != ERROR_SUCCESS) {
  4193. DavPrint((DEBUG_ERRORS,
  4194. "DavLockTheFileOnTheServer/DavPushData. WStatus = %d\n",
  4195. WStatus));
  4196. goto EXIT_THE_FUNCTION;
  4197. }
  4198. if (readDone) {
  4199. break;
  4200. }
  4201. } while ( TRUE );
  4202. memset(&DavFileAttributes, 0, sizeof(DavFileAttributes));
  4203. InitializeListHead( &(DavFileAttributes.NextEntry) );
  4204. WStatus = DavParseData(&DavFileAttributes, Ctx1, Ctx2, &NumOfFileEntries);
  4205. if (WStatus != ERROR_SUCCESS) {
  4206. DavPrint((DEBUG_ERRORS,
  4207. "DavLockTheFileOnTheServer/DavParseData. WStatus = %d\n",
  4208. WStatus));
  4209. DavFinalizeFileAttributesList(&DavFileAttributes, FALSE);
  4210. goto EXIT_THE_FUNCTION;
  4211. }
  4212. CreateResponse = &(DavWorkItem->CreateResponse);
  4213. //
  4214. // Copy the LockOwner value if the file is already LOCKed on the server and
  4215. // this LOCK request failed with 423 OR the OpaqueLockToken and LockTimeout
  4216. // values if the LOCK was successfully taken on this file.
  4217. //
  4218. CreateResponse->FileWasAlreadyLocked = FALSE;
  4219. CreateResponse->LockWasTakenOnThisCreate = FALSE;
  4220. if (fileIsLocked) {
  4221. WStatus = ERROR_LOCK_VIOLATION;
  4222. //
  4223. // If the DavFileAttributes.LockOwner is NULL, it means that the
  4224. // XML response from the server was bogus. In such a case, we just
  4225. // fail the request with ERROR_LOCK_VIOLATION.
  4226. //
  4227. if (DavFileAttributes.LockOwner) {
  4228. CreateResponse->FileWasAlreadyLocked = TRUE;
  4229. if ( wcslen(DavFileAttributes.LockOwner) <= (256 + 256) ) {
  4230. wcscpy(CreateResponse->LockOwner, DavFileAttributes.LockOwner);
  4231. DavPrint((DEBUG_MISC,
  4232. "DavLockTheFileOnTheServer: fileIsLocked!! LockOwner = %ws\n",
  4233. CreateResponse->LockOwner));
  4234. }
  4235. }
  4236. } else {
  4237. CreateResponse->LockWasTakenOnThisCreate = TRUE;
  4238. if ( wcslen(DavFileAttributes.OpaqueLockToken) < MAX_PATH ) {
  4239. wcscpy(CreateResponse->OpaqueLockToken, DavFileAttributes.OpaqueLockToken);
  4240. CreateResponse->LockTimeout = DavFileAttributes.LockTimeout;
  4241. DavPrint((DEBUG_MISC,
  4242. "DavLockTheFileOnTheServer: OpaqueLockToken = %ws, LockTimeout = %dsec\n",
  4243. CreateResponse->OpaqueLockToken, CreateResponse->LockTimeout));
  4244. } else {
  4245. WStatus = ERROR_INVALID_PARAMETER;
  4246. DavPrint((DEBUG_ERRORS,
  4247. "DavLockTheFileOnTheServer: OpaqueLockToken > MAX_PATH. WStatus = %d\n",
  4248. WStatus));
  4249. }
  4250. }
  4251. DavFinalizeFileAttributesList(&DavFileAttributes, FALSE);
  4252. DavCloseContext(Ctx1, Ctx2);
  4253. EXIT_THE_FUNCTION:
  4254. if (DavOpenHandle != NULL) {
  4255. InternetCloseHandle(DavOpenHandle);
  4256. DavOpenHandle = NULL;
  4257. }
  4258. if (PassportCookie) {
  4259. LocalFree(PassportCookie);
  4260. PassportCookie = NULL;
  4261. }
  4262. if (LockRequestBuffer) {
  4263. LocalFree(LockRequestBuffer);
  4264. LockRequestBuffer = NULL;
  4265. }
  4266. if (DataBuff) {
  4267. LocalFree(DataBuff);
  4268. DataBuff = NULL;
  4269. }
  4270. return WStatus;
  4271. }
  4272. DWORD
  4273. DavFsLockRefresh(
  4274. PDAV_USERMODE_WORKITEM DavWorkItem
  4275. )
  4276. /*++
  4277. Routine Description:
  4278. This routine handles LOCK refresh requests that get reflected from the
  4279. kernel.
  4280. Arguments:
  4281. DavWorkItem - The buffer that contains the request parameters and options.
  4282. Return Value:
  4283. The return status for the operation
  4284. --*/
  4285. {
  4286. ULONG WStatus = ERROR_SUCCESS;
  4287. HINTERNET DavConnHandle = NULL, DavOpenHandle = NULL;
  4288. PDAV_USERMODE_LOCKREFRESH_REQUEST LockRefreshRequest = NULL;
  4289. PDAV_USERMODE_LOCKREFRESH_RESPONSE LockRefreshResponse = NULL;
  4290. BOOL BStatus = FALSE, ReturnVal = FALSE, readDone = FALSE;
  4291. PPER_USER_ENTRY PerUserEntry = NULL;
  4292. PHASH_SERVER_ENTRY ServerHashEntry = NULL;
  4293. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  4294. PWCHAR ServerName = NULL, PathName = NULL, CanName = NULL, PassportCookie = NULL;
  4295. DAV_FILE_ATTRIBUTES DavFileAttributes;
  4296. PVOID Ctx1 = NULL, Ctx2 = NULL;
  4297. DWORD NumRead = 0, NumOfFileEntries = 0, TotalDataBytesRead = 0;
  4298. BOOL didImpersonate = FALSE;
  4299. BOOLEAN EnCriSec = FALSE, didITakeAPUEReference = FALSE;
  4300. PCHAR DataBuff = NULL;
  4301. LockRefreshRequest = &(DavWorkItem->LockRefreshRequest);
  4302. LockRefreshResponse = &(DavWorkItem->LockRefreshResponse);
  4303. ServerName = &(LockRefreshRequest->ServerName[1]);
  4304. PathName = &(LockRefreshRequest->PathName[1]);
  4305. //
  4306. // The PathName can contain \ characters. Replace them by / characters.
  4307. //
  4308. CanName = PathName;
  4309. while (*CanName) {
  4310. if (*CanName == L'\\') {
  4311. *CanName = L'/';
  4312. }
  4313. CanName++;
  4314. }
  4315. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  4316. //
  4317. // A User Entry for this user must have been created during the create call
  4318. // earlier. The user entry contains the handle used to send an HttpOpen
  4319. // request.
  4320. //
  4321. EnterCriticalSection( &(HashServerEntryTableLock) );
  4322. EnCriSec = TRUE;
  4323. ReturnVal = DavDoesUserEntryExist(ServerName,
  4324. LockRefreshRequest->ServerID,
  4325. &(LockRefreshRequest->LogonID),
  4326. &PerUserEntry,
  4327. &ServerHashEntry);
  4328. //
  4329. // If the following request in the kernel get cancelled even before the
  4330. // corresponding usermode thread gets a chance to execute this code, then
  4331. // it possible that the VNetRoot (hence the PerUserEntry) and SrvCall get
  4332. // finalized before the thread that is handling the create comes here. This
  4333. // could happen if this request was the only one for this share and the
  4334. // server as well. This is why we need to check if the ServerHashEntry and
  4335. // the PerUserEntry are valid before proceeding.
  4336. //
  4337. if (ReturnVal == FALSE || ServerHashEntry == NULL || PerUserEntry == NULL) {
  4338. WStatus = ERROR_CANCELLED;
  4339. DavPrint((DEBUG_ERRORS, "DavFsLockRefresh: (ServerHashEntry == NULL || PerUserEntry == NULL)\n"));
  4340. goto EXIT_THE_FUNCTION;
  4341. }
  4342. DavWorkItem->ServerUserEntry.PerUserEntry = PerUserEntry;
  4343. //
  4344. // Add a reference to the user entry and set didITakeAPUEReference to TRUE.
  4345. //
  4346. PerUserEntry->UserEntryRefCount++;
  4347. didITakeAPUEReference = TRUE;
  4348. //
  4349. // Since a create had succeeded earlier, the entry must be good.
  4350. //
  4351. ASSERT(PerUserEntry->UserEntryState == UserEntryInitialized);
  4352. ASSERT(PerUserEntry->DavConnHandle != NULL);
  4353. //
  4354. // And yes, we obviously have to leave the critical section before
  4355. // returning.
  4356. //
  4357. LeaveCriticalSection( &(HashServerEntryTableLock) );
  4358. EnCriSec = FALSE;
  4359. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  4360. if (WStatus != ERROR_SUCCESS) {
  4361. DavPrint((DEBUG_ERRORS,
  4362. "DavFsLockRefresh/UMReflectorImpersonate. Error Val = %d\n",
  4363. WStatus));
  4364. goto EXIT_THE_FUNCTION;
  4365. }
  4366. didImpersonate = TRUE;
  4367. //
  4368. // Convert the unicode object name to UTF-8 URL format.
  4369. // Space and other white characters will remain untouched - these should
  4370. // be taken care of by wininet calls.
  4371. // This has to be a W API as the name in CloseRequest is unicode.
  4372. //
  4373. BStatus = DavHttpOpenRequestW(PerUserEntry->DavConnHandle,
  4374. L"LOCK",
  4375. PathName,
  4376. L"HTTP/1.1",
  4377. NULL,
  4378. NULL,
  4379. INTERNET_FLAG_KEEP_CONNECTION |
  4380. INTERNET_FLAG_NO_COOKIES |
  4381. INTERNET_FLAG_RELOAD,
  4382. 0,
  4383. L"DavFsLockRefresh",
  4384. &DavOpenHandle);
  4385. if(BStatus == FALSE) {
  4386. WStatus = GetLastError();
  4387. goto EXIT_THE_FUNCTION;
  4388. }
  4389. if (DavOpenHandle == NULL) {
  4390. WStatus = GetLastError();
  4391. DavPrint((DEBUG_ERRORS,
  4392. "DavFsLockRefresh/DavHttpOpenRequestW. Error Val = %d\n",
  4393. WStatus));
  4394. goto EXIT_THE_FUNCTION;
  4395. }
  4396. //
  4397. // We need to add the header "translate:f" to tell IIS that it should
  4398. // allow the user to excecute this VERB on the specified path which it
  4399. // would not allow (in some cases) otherwise. Finally, there is a special
  4400. // flag in the metabase to allow for uploading of "dangerous" content
  4401. // (anything that can be run on the server). This is the ScriptSourceAccess
  4402. // flag in the UI or the AccessSource flag in the metabase. You will need
  4403. // to set this bit to true as well as correct NT ACLs in order to be able
  4404. // to upload .exes or anything executable. We set this header on all requests
  4405. // that are sent to the server including the LOCK request.
  4406. //
  4407. ReturnVal = HttpAddRequestHeadersW(DavOpenHandle,
  4408. L"translate: f\n",
  4409. -1,
  4410. HTTP_ADDREQ_FLAG_ADD |
  4411. HTTP_ADDREQ_FLAG_REPLACE);
  4412. if (!ReturnVal) {
  4413. WStatus = GetLastError();
  4414. DavPrint((DEBUG_ERRORS,
  4415. "DavFsLockRefresh/HttpAddRequestHeadersW. Error Val = %d\n",
  4416. WStatus));
  4417. goto EXIT_THE_FUNCTION;
  4418. }
  4419. WStatus = DavAttachPassportCookie(DavWorkItem, DavOpenHandle, &PassportCookie);
  4420. if (WStatus != ERROR_SUCCESS) {
  4421. DavPrint((DEBUG_ERRORS,
  4422. "DavFsLockRefresh/DavAttachPassportCookie. Error Val = %d\n",
  4423. WStatus));
  4424. goto EXIT_THE_FUNCTION;
  4425. }
  4426. WStatus = DavInternetSetOption(DavWorkItem, DavOpenHandle);
  4427. if (WStatus != ERROR_SUCCESS) {
  4428. DavPrint((DEBUG_ERRORS,
  4429. "DavFsLockRefresh/DavInternetSetOption. Error Val = %d\n",
  4430. WStatus));
  4431. goto EXIT_THE_FUNCTION;
  4432. }
  4433. //
  4434. // Request the LOCK on this resource for an hour. We will have to refresh
  4435. // the LOCK request if we need to keep the LOCK request for more than an
  4436. // hour.
  4437. //
  4438. ReturnVal = HttpAddRequestHeadersW(DavOpenHandle,
  4439. L"Timeout: Second-3600\n",
  4440. -1L,
  4441. HTTP_ADDREQ_FLAG_ADD |
  4442. HTTP_ADDREQ_FLAG_REPLACE);
  4443. if (!ReturnVal) {
  4444. WStatus = GetLastError();
  4445. DavPrint((DEBUG_ERRORS,
  4446. "DavFsLockRefresh/HttpAddRequestHeadersW. Error Val = %d\n",
  4447. WStatus));
  4448. goto EXIT_THE_FUNCTION;
  4449. }
  4450. ASSERT(LockRefreshRequest->OpaqueLockToken != NULL);
  4451. ReturnVal = HttpAddRequestHeadersW(DavOpenHandle,
  4452. LockRefreshRequest->OpaqueLockToken,
  4453. -1L,
  4454. HTTP_ADDREQ_FLAG_ADD |
  4455. HTTP_ADDREQ_FLAG_REPLACE );
  4456. if (!ReturnVal) {
  4457. WStatus = GetLastError();
  4458. DavPrint((DEBUG_ERRORS,
  4459. "DavFsLockRefresh/HttpAddRequestHeadersW. Error Val = %d\n",
  4460. WStatus));
  4461. goto EXIT_THE_FUNCTION;
  4462. }
  4463. RESEND_THE_REQUEST:
  4464. ReturnVal = HttpSendRequestExW(DavOpenHandle,
  4465. NULL,
  4466. NULL,
  4467. HSR_SYNC,
  4468. (ULONG_PTR)0);
  4469. if (!ReturnVal) {
  4470. WStatus = GetLastError();
  4471. DavPrint((DEBUG_ERRORS,
  4472. "DavFsLockRefresh/HttpSendRequestExW. Error Val = %d\n",
  4473. WStatus));
  4474. goto EXIT_THE_FUNCTION;
  4475. }
  4476. ReturnVal = HttpEndRequestW(DavOpenHandle,
  4477. NULL,
  4478. HSR_SYNC,
  4479. (ULONG_PTR)0);
  4480. if (!ReturnVal) {
  4481. WStatus = GetLastError();
  4482. //
  4483. // If the error we got back is ERROR_INTERNET_FORCE_RETRY, then WinInet
  4484. // is trying to authenticate itself with the server. If we get back
  4485. // ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION, WinInet is expecting us to
  4486. // confirm that the redirect needs to be followed. In these scenarios,
  4487. // we need to repeat the HttpSend and HttpEnd request calls.
  4488. //
  4489. if (WStatus == ERROR_INTERNET_FORCE_RETRY || WStatus == ERROR_HTTP_REDIRECT_NEEDS_CONFIRMATION) {
  4490. goto RESEND_THE_REQUEST;
  4491. }
  4492. DavPrint((DEBUG_ERRORS,
  4493. "DavFsLockRefresh/HttpEndRequestW. Error Val = %d\n",
  4494. WStatus));
  4495. goto EXIT_THE_FUNCTION;
  4496. }
  4497. WStatus = DavQueryAndParseResponse(DavOpenHandle);
  4498. if (WStatus != ERROR_SUCCESS) {
  4499. DavPrint((DEBUG_ERRORS,
  4500. "DavFsLockRefresh/DavQueryAndParseResponse. WStatus = %d\n",
  4501. WStatus));
  4502. }
  4503. DataBuff = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, NUM_OF_BYTES_TO_READ);
  4504. if (DataBuff == NULL) {
  4505. WStatus = GetLastError();
  4506. DavPrint((DEBUG_ERRORS,
  4507. "DavFsLockRefresh/LocalAlloc: WStatus = %08lx\n",
  4508. WStatus));
  4509. goto EXIT_THE_FUNCTION;
  4510. }
  4511. //
  4512. // Read the response and parse it.
  4513. //
  4514. do {
  4515. ReturnVal = InternetReadFile(DavOpenHandle,
  4516. (LPVOID)DataBuff,
  4517. NUM_OF_BYTES_TO_READ,
  4518. &(NumRead));
  4519. if (!ReturnVal) {
  4520. WStatus = GetLastError();
  4521. DavPrint((DEBUG_ERRORS,
  4522. "DavFsLockRefresh/InternetReadFile: WStatus = %08lx\n",
  4523. WStatus));
  4524. goto EXIT_THE_FUNCTION;
  4525. }
  4526. DavPrint((DEBUG_MISC, "DavFsLockRefresh: NumRead = %d\n", NumRead));
  4527. //
  4528. // We reject files whose attributes are greater than a certain size
  4529. // (DavFileAttributesLimitInBytes). This is a parameter that can be
  4530. // set in the registry. This is done to avoid attacks by rogue servers.
  4531. //
  4532. TotalDataBytesRead += NumRead;
  4533. if (TotalDataBytesRead > DavFileAttributesLimitInBytes) {
  4534. WStatus = ERROR_BAD_NET_RESP;
  4535. DavPrint((DEBUG_ERRORS, "DavFsLockRefresh. LockResponseSize > %d\n", DavFileAttributesLimitInBytes));
  4536. goto EXIT_THE_FUNCTION;
  4537. }
  4538. readDone = (NumRead == 0) ? TRUE : FALSE;
  4539. WStatus = DavPushData(DataBuff, &Ctx1, &Ctx2, NumRead, readDone);
  4540. if (WStatus != ERROR_SUCCESS) {
  4541. DavPrint((DEBUG_ERRORS,
  4542. "DavFsLockRefresh/DavPushData. WStatus = %d\n",
  4543. WStatus));
  4544. goto EXIT_THE_FUNCTION;
  4545. }
  4546. if (readDone) {
  4547. break;
  4548. }
  4549. } while ( TRUE );
  4550. memset(&DavFileAttributes, 0, sizeof(DavFileAttributes));
  4551. InitializeListHead( &(DavFileAttributes.NextEntry) );
  4552. WStatus = DavParseData(&DavFileAttributes, Ctx1, Ctx2, &NumOfFileEntries);
  4553. if (WStatus != ERROR_SUCCESS) {
  4554. DavPrint((DEBUG_ERRORS,
  4555. "DavFsLockRefresh/DavParseData. WStatus = %d\n",
  4556. WStatus));
  4557. DavFinalizeFileAttributesList(&DavFileAttributes, FALSE);
  4558. goto EXIT_THE_FUNCTION;
  4559. }
  4560. //
  4561. // Get the NewTimeoutValue returned by the server.
  4562. //
  4563. LockRefreshResponse->NewTimeOutInSec = DavFileAttributes.LockTimeout;
  4564. DavFinalizeFileAttributesList(&DavFileAttributes, FALSE);
  4565. DavCloseContext(Ctx1, Ctx2);
  4566. EXIT_THE_FUNCTION:
  4567. if (DavOpenHandle != NULL) {
  4568. InternetCloseHandle(DavOpenHandle);
  4569. DavOpenHandle = NULL;
  4570. }
  4571. //
  4572. // If didITakeAPUEReference is TRUE we need to remove the reference we
  4573. // took on the PerUserEntry.
  4574. //
  4575. if (didITakeAPUEReference) {
  4576. DavFinalizePerUserEntry( &(DavWorkItem->ServerUserEntry.PerUserEntry) );
  4577. }
  4578. if (PassportCookie) {
  4579. LocalFree(PassportCookie);
  4580. PassportCookie = NULL;
  4581. }
  4582. if (DataBuff) {
  4583. LocalFree(DataBuff);
  4584. DataBuff = NULL;
  4585. }
  4586. //
  4587. // If this thread impersonated a user, we need to revert back.
  4588. //
  4589. if (didImpersonate) {
  4590. RevertToSelf();
  4591. didImpersonate = FALSE;
  4592. }
  4593. return WStatus;
  4594. }