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.

1156 lines
38 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. rename.c
  5. Abstract:
  6. This module implements the user mode DAV miniredir routine(s) pertaining to
  7. the ReName call.
  8. Author:
  9. Rohan Kumar [RohanK] 20-Jan-2000
  10. Revision History:
  11. --*/
  12. #include "pch.h"
  13. #pragma hdrstop
  14. #include "ntumrefl.h"
  15. #include "usrmddav.h"
  16. #include "global.h"
  17. #include "UniUtf.h"
  18. #include "nodefac.h"
  19. VOID
  20. DavAsyncSetFileInformationCompletion(
  21. PDAV_USERMODE_WORKITEM DavWorkItem
  22. );
  23. ULONG
  24. DavFsReName(
  25. PDAV_USERMODE_WORKITEM DavWorkItem
  26. )
  27. /*++
  28. Routine Description:
  29. This routine handles ReName requests for the DAV Mini-Redir that get
  30. reflected from the kernel.
  31. Arguments:
  32. DavWorkItem - The buffer that contains the request parameters and options.
  33. Return Value:
  34. The return status for the operation
  35. --*/
  36. {
  37. ULONG WStatus = ERROR_SUCCESS;
  38. PDAV_USERMODE_RENAME_REQUEST DavReNameRequest = NULL;
  39. PWCHAR ServerName = NULL, OldPathName = NULL, NewPathName = NULL;
  40. PWCHAR UtfServerName = NULL, UtfNewPathName = NULL;
  41. ULONG UtfServerNameLength = 0, UtfNewPathNameLength = 0;
  42. PWCHAR UrlBuffer = NULL, HeaderBuff = NULL, CanName = NULL;
  43. ULONG HeaderLength = 0, HeaderLengthInBytes = 0;
  44. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  45. BOOL EnCriSec = FALSE, ReturnVal, CallBackContextInitialized = FALSE;
  46. ULONG ServerID = 0, urlLength = 0, TagLen = 0, convLen = 0;
  47. PPER_USER_ENTRY PerUserEntry = NULL;
  48. PHASH_SERVER_ENTRY ServerHashEntry = NULL;
  49. HINTERNET DavConnHandle = NULL, DavOpenHandle = NULL;
  50. URL_COMPONENTSW UrlComponents;
  51. BOOL didImpersonate = FALSE, BStatus = FALSE;
  52. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  53. //
  54. // Get the request buffer pointer from the DavWorkItem.
  55. //
  56. DavReNameRequest = &(DavWorkItem->ReNameRequest);
  57. //
  58. // The first character is a '\' which has to be stripped from the
  59. // ServerName.
  60. //
  61. ServerName = &(DavReNameRequest->ServerName[1]);
  62. if ( !ServerName && ServerName[0] != L'\0' ) {
  63. DavPrint((DEBUG_ERRORS, "DavFsReName: ServerName is NULL.\n"));
  64. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  65. goto EXIT_THE_FUNCTION;
  66. }
  67. DavPrint((DEBUG_MISC, "DavFsReName: ServerName = %ws.\n", ServerName));
  68. ServerID = DavReNameRequest->ServerID;
  69. DavPrint((DEBUG_MISC, "DavFsReName: ServerID = %d.\n", ServerID));
  70. //
  71. // The first character is a '\' which has to be stripped from the
  72. // OldPathName.
  73. //
  74. OldPathName = &(DavReNameRequest->OldPathName[1]);
  75. if ( !OldPathName ) {
  76. DavPrint((DEBUG_ERRORS, "DavFsReName: OldPathName is NULL.\n"));
  77. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  78. goto EXIT_THE_FUNCTION;
  79. }
  80. //
  81. // The file name can contain \ characters. Replace them by / characters.
  82. //
  83. CanName = OldPathName;
  84. while (*CanName) {
  85. if (*CanName == L'\\') {
  86. *CanName = L'/';
  87. }
  88. CanName++;
  89. }
  90. DavPrint((DEBUG_MISC, "DavFsReName: OldPathName = %ws.\n", OldPathName));
  91. //
  92. // The first character is a '\' which has to be stripped from the
  93. // NewPathName.
  94. //
  95. NewPathName = &(DavReNameRequest->NewPathName[1]);
  96. if ( !NewPathName ) {
  97. DavPrint((DEBUG_ERRORS, "DavFsReName: NewPathName is NULL.\n"));
  98. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  99. goto EXIT_THE_FUNCTION;
  100. }
  101. //
  102. // The file name can contain \ characters. Replace them by / characters.
  103. //
  104. CanName = NewPathName;
  105. while (*CanName) {
  106. if (*CanName == L'\\') {
  107. *CanName = L'/';
  108. }
  109. CanName++;
  110. }
  111. DavPrint((DEBUG_MISC, "DavFsReName: NewPathName = %ws.\n", NewPathName));
  112. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  113. //
  114. // If we are using WinInet synchronously, then we need to impersonate the
  115. // clients context now.
  116. //
  117. #ifndef DAV_USE_WININET_ASYNCHRONOUSLY
  118. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  119. if (WStatus != ERROR_SUCCESS) {
  120. DavPrint((DEBUG_ERRORS,
  121. "DavFsReName/UMReflectorImpersonate. Error Val = %d\n",
  122. WStatus));
  123. goto EXIT_THE_FUNCTION;
  124. }
  125. didImpersonate = TRUE;
  126. #endif
  127. //
  128. // If we have a dummy share name in the OldPathName and the NewPathName, we
  129. // need to remove it right now before we contact the server.
  130. //
  131. DavRemoveDummyShareFromFileName(OldPathName);
  132. DavRemoveDummyShareFromFileName(NewPathName);
  133. //
  134. // We need to convert the ServerName and the NewPathName into the UTF-8
  135. // format before we call into the InternetCreateUrlW function. This is
  136. // because if the localized Unicode characters are passed into this
  137. // function it converts them into ?. For example all the chinese unicode
  138. // characters will be converted into ?s.
  139. //
  140. UtfServerNameLength = WideStrToUtfUrlStr(ServerName, (wcslen(ServerName) + 1), NULL, 0);
  141. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  142. WStatus = GetLastError();
  143. DavPrint((DEBUG_ERRORS,
  144. "DavFsReName/WideStrToUtfUrlStr(1). Error Val = %d\n", WStatus));
  145. goto EXIT_THE_FUNCTION;
  146. }
  147. UtfServerName = LocalAlloc(LPTR, UtfServerNameLength * sizeof(WCHAR));
  148. if (UtfServerName == NULL) {
  149. WStatus = GetLastError();
  150. DavPrint((DEBUG_ERRORS,
  151. "DavFsReName/LocalAlloc. Error Val = %d\n", WStatus));
  152. goto EXIT_THE_FUNCTION;
  153. }
  154. UtfServerNameLength = WideStrToUtfUrlStr(ServerName, (wcslen(ServerName) + 1), UtfServerName, UtfServerNameLength);
  155. if (GetLastError() != ERROR_SUCCESS) {
  156. WStatus = GetLastError();
  157. DavPrint((DEBUG_ERRORS,
  158. "DavFsReName/WideStrToUtfUrlStr(2). Error Val = %d\n", WStatus));
  159. goto EXIT_THE_FUNCTION;
  160. }
  161. UtfNewPathNameLength = WideStrToUtfUrlStr(NewPathName, (wcslen(NewPathName) + 1), NULL, 0);
  162. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  163. WStatus = GetLastError();
  164. DavPrint((DEBUG_ERRORS,
  165. "DavFsReName/WideStrToUtfUrlStr(3). Error Val = %d\n", WStatus));
  166. goto EXIT_THE_FUNCTION;
  167. }
  168. UtfNewPathName = LocalAlloc(LPTR, UtfNewPathNameLength * sizeof(WCHAR));
  169. if (UtfNewPathName == NULL) {
  170. WStatus = GetLastError();
  171. DavPrint((DEBUG_ERRORS,
  172. "DavFsReName/LocalAlloc. Error Val = %d\n", WStatus));
  173. goto EXIT_THE_FUNCTION;
  174. }
  175. UtfNewPathNameLength = WideStrToUtfUrlStr(NewPathName, (wcslen(NewPathName) + 1), UtfNewPathName, UtfNewPathNameLength);
  176. if (GetLastError() != ERROR_SUCCESS) {
  177. WStatus = GetLastError();
  178. DavPrint((DEBUG_ERRORS,
  179. "DavFsReName/WideStrToUtfUrlStr(4). Error Val = %d\n", WStatus));
  180. goto EXIT_THE_FUNCTION;
  181. }
  182. //
  183. // Create the URL with the NewPathName to be sent to the server. Initialize
  184. // the UrlComponents structure before making the call.
  185. //
  186. UrlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
  187. UrlComponents.lpszScheme = NULL;
  188. UrlComponents.dwSchemeLength = 0;
  189. UrlComponents.nScheme = INTERNET_SCHEME_HTTP;
  190. UrlComponents.lpszHostName = UtfServerName;
  191. UrlComponents.dwHostNameLength = wcslen(UtfServerName);
  192. UrlComponents.nPort = DEFAULT_HTTP_PORT;
  193. UrlComponents.lpszUserName = NULL;
  194. UrlComponents.dwUserNameLength = 0;
  195. UrlComponents.lpszPassword = NULL;
  196. UrlComponents.dwPasswordLength = 0;
  197. UrlComponents.lpszUrlPath = UtfNewPathName;
  198. UrlComponents.dwUrlPathLength = wcslen(UtfNewPathName);
  199. UrlComponents.lpszExtraInfo = NULL;
  200. UrlComponents.dwExtraInfoLength = 0;
  201. ReturnVal = InternetCreateUrlW(&(UrlComponents),
  202. 0,
  203. NULL,
  204. &(urlLength));
  205. if (!ReturnVal) {
  206. ULONG urlLengthInWChars = 0;
  207. WStatus = GetLastError();
  208. if (WStatus == ERROR_INSUFFICIENT_BUFFER) {
  209. UrlBuffer = (PWCHAR) LocalAlloc (LMEM_FIXED | LMEM_ZEROINIT,
  210. urlLength);
  211. if (UrlBuffer != NULL) {
  212. ZeroMemory(UrlBuffer, urlLength);
  213. urlLengthInWChars = ( urlLength/sizeof(WCHAR) );
  214. ReturnVal = InternetCreateUrlW(&(UrlComponents),
  215. 0,
  216. UrlBuffer,
  217. &(urlLengthInWChars));
  218. if (!ReturnVal) {
  219. WStatus = GetLastError();
  220. DavPrint((DEBUG_ERRORS,
  221. "DavFsReName/InternetCreateUrl. Error Val = %d\n",
  222. WStatus));
  223. goto EXIT_THE_FUNCTION;
  224. }
  225. } else {
  226. WStatus = GetLastError();
  227. DavPrint((DEBUG_ERRORS,
  228. "DavFsReName/LocalAlloc. Error Val = %d\n", WStatus));
  229. goto EXIT_THE_FUNCTION;
  230. }
  231. } else {
  232. DavPrint((DEBUG_ERRORS,
  233. "DavFsReName/InternetCreateUrl. Error Val = %d\n",
  234. WStatus));
  235. goto EXIT_THE_FUNCTION;
  236. }
  237. }
  238. DavPrint((DEBUG_MISC, "DavFsReName: URL: %ws\n", UrlBuffer));
  239. //
  240. // We now need to create the Destination header that we will add to the
  241. // request to be sent to the server. This header has the following format.
  242. // "Destination: URL"
  243. //
  244. TagLen = wcslen(L"Destination: ");
  245. convLen = wcslen(UrlBuffer);
  246. HeaderLength = TagLen + convLen;
  247. HeaderLengthInBytes = ( (1 + HeaderLength) * sizeof(WCHAR) );
  248. HeaderBuff = (PWCHAR) LocalAlloc(LPTR, HeaderLengthInBytes);
  249. if (HeaderBuff == NULL) {
  250. WStatus = GetLastError();
  251. DavPrint((DEBUG_ERRORS,
  252. "DavFsReName/LocalAlloc. Error Val = %d\n", WStatus));
  253. goto EXIT_THE_FUNCTION;
  254. }
  255. wcscpy(HeaderBuff, L"Destination: ");
  256. wcscpy(&(HeaderBuff[TagLen]), UrlBuffer);
  257. DavWorkItem->AsyncReName.HeaderBuff = HeaderBuff;
  258. DavPrint((DEBUG_MISC, "DavFsReName: HeaderBuff: %ws\n", HeaderBuff));
  259. //
  260. // We need to call this only if "DAV_USE_WININET_ASYNCHRONOUSLY" has been
  261. // defined. Otherwise, if we are using WinInet synchronously, then we
  262. // would have already done this in the DavWorkerThread function. This
  263. // ultimately gets deleted (the impersonation token that is) in the
  264. // DavAsyncCreateCompletion function.
  265. //
  266. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  267. //
  268. // Set the DavCallBackContext.
  269. //
  270. WStatus = DavFsSetTheDavCallBackContext(DavWorkItem);
  271. if (WStatus != ERROR_SUCCESS) {
  272. DavPrint((DEBUG_ERRORS,
  273. "DavFsReName/DavFsSetTheDavCallBackContext. Error Val = %d\n",
  274. WStatus));
  275. goto EXIT_THE_FUNCTION;
  276. }
  277. CallBackContextInitialized = TRUE;
  278. //
  279. // Store the address of the DavWorkItem which serves as a callback in the
  280. // variable CallBackContext. This will now be used in all the async calls
  281. // that follow.
  282. //
  283. CallBackContext = (ULONG_PTR)(DavWorkItem);
  284. #endif
  285. //
  286. // Allocate memory for the INTERNET_ASYNC_RESULT structure.
  287. //
  288. DavWorkItem->AsyncResult = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT,
  289. sizeof(INTERNET_ASYNC_RESULT));
  290. if (DavWorkItem->AsyncResult == NULL) {
  291. WStatus = GetLastError();
  292. DavPrint((DEBUG_ERRORS,
  293. "DavFsReName/LocalAlloc. Error Val = %d\n", WStatus));
  294. goto EXIT_THE_FUNCTION;
  295. }
  296. //
  297. // A User Entry for this user must have been created during the create call
  298. // earlier. The user entry contains the handle used to send an HttpOpen
  299. // request.
  300. //
  301. EnterCriticalSection( &(HashServerEntryTableLock) );
  302. EnCriSec = TRUE;
  303. ReturnVal = DavDoesUserEntryExist(ServerName,
  304. ServerID,
  305. &(DavReNameRequest->LogonID),
  306. &PerUserEntry,
  307. &ServerHashEntry);
  308. //
  309. // If the following request in the kernel get cancelled even before the
  310. // corresponding usermode thread gets a chance to execute this code, then
  311. // it possible that the VNetRoot (hence the PerUserEntry) and SrvCall get
  312. // finalized before the thread that is handling the create comes here. This
  313. // could happen if this request was the only one for this share and the
  314. // server as well. This is why we need to check if the ServerHashEntry and
  315. // the PerUserEntry are valid before proceeding.
  316. //
  317. if (ReturnVal == FALSE || ServerHashEntry == NULL || PerUserEntry == NULL) {
  318. WStatus = ERROR_CANCELLED;
  319. DavPrint((DEBUG_ERRORS, "DavFsReName: (ServerHashEntry == NULL || PerUserEntry == NULL)\n"));
  320. goto EXIT_THE_FUNCTION;
  321. }
  322. DavWorkItem->AsyncReName.ServerHashEntry = ServerHashEntry;
  323. DavWorkItem->AsyncReName.PerUserEntry = PerUserEntry;
  324. //
  325. // Add a reference to the user entry.
  326. //
  327. PerUserEntry->UserEntryRefCount++;
  328. //
  329. // Since a create had succeeded earlier, the entry must be good.
  330. //
  331. ASSERT(PerUserEntry->UserEntryState == UserEntryInitialized);
  332. ASSERT(PerUserEntry->DavConnHandle != NULL);
  333. DavConnHandle = PerUserEntry->DavConnHandle;
  334. //
  335. // And yes, we obviously have to leave the critical section
  336. // before returning.
  337. //
  338. LeaveCriticalSection( &(HashServerEntryTableLock) );
  339. EnCriSec = FALSE;
  340. //
  341. // We now call the HttpOpenRequest function and return.
  342. //
  343. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  344. //
  345. // Convert the unicode directory path to UTF-8 URL format.
  346. // Space and other white characters will remain untouched - these should
  347. // be taken care of by wininet calls.
  348. //
  349. BStatus = DavHttpOpenRequestW(DavConnHandle,
  350. L"MOVE",
  351. OldPathName,
  352. L"HTTP/1.1",
  353. NULL,
  354. NULL,
  355. INTERNET_FLAG_KEEP_CONNECTION |
  356. INTERNET_FLAG_NO_COOKIES,
  357. CallBackContext,
  358. L"DavFsReName",
  359. &DavOpenHandle);
  360. if(BStatus == FALSE) {
  361. WStatus = GetLastError();
  362. goto EXIT_THE_FUNCTION;
  363. }
  364. if (DavOpenHandle == NULL) {
  365. WStatus = GetLastError();
  366. if (WStatus != ERROR_IO_PENDING) {
  367. DavPrint((DEBUG_ERRORS,
  368. "DavFsReName/HttpOpenRequest. Error Val = %d\n",
  369. WStatus));
  370. }
  371. goto EXIT_THE_FUNCTION;
  372. }
  373. //
  374. // Cache the DavOpenHandle in the DavWorkItem.
  375. //
  376. DavWorkItem->AsyncReName.DavOpenHandle = DavOpenHandle;
  377. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  378. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  379. DavPrint((DEBUG_ERRORS,
  380. "DavFsReName/DavAsyncCommonStates. Error Val = %08lx\n",
  381. WStatus));
  382. }
  383. EXIT_THE_FUNCTION: // Do the necessary cleanup and return.
  384. //
  385. // We could have taken the lock and come down an error path without
  386. // releasing it. If thats the case, then we need to release the lock now.
  387. //
  388. if (EnCriSec) {
  389. LeaveCriticalSection( &(HashServerEntryTableLock) );
  390. EnCriSec = FALSE;
  391. }
  392. if (UrlBuffer != NULL) {
  393. HLOCAL FreeHandle;
  394. ULONG FreeStatus;
  395. FreeHandle = LocalFree((HLOCAL)UrlBuffer);
  396. if (FreeHandle != NULL) {
  397. FreeStatus = GetLastError();
  398. DavPrint((DEBUG_ERRORS,
  399. "DavFsRename/LocalFree. Error Val = %d\n", FreeStatus));
  400. }
  401. }
  402. if (UtfServerName != NULL) {
  403. LocalFree(UtfServerName);
  404. UtfServerName = NULL;
  405. }
  406. if (UtfNewPathName != NULL) {
  407. LocalFree(UtfNewPathName);
  408. UtfNewPathName = NULL;
  409. }
  410. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  411. //
  412. // Some resources should not be freed if we are returning ERROR_IO_PENDING
  413. // because they will be used in the callback functions.
  414. //
  415. if (WStatus != ERROR_IO_PENDING) {
  416. //
  417. // Set the return status of the operation. This is used by the kernel
  418. // mode routines to figure out the completion status of the user mode
  419. // request.
  420. //
  421. if (WStatus != ERROR_SUCCESS) {
  422. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  423. } else {
  424. DavWorkItem->Status = STATUS_SUCCESS;
  425. }
  426. DavAsyncReNameCompletion(DavWorkItem);
  427. } else {
  428. DavPrint((DEBUG_MISC, "DavFsReName: Returning ERROR_IO_PENDING.\n"));
  429. }
  430. #else
  431. //
  432. // If we are using WinInet synchronously, then we should never get back
  433. // ERROR_IO_PENDING from WinInet.
  434. //
  435. ASSERT(WStatus != ERROR_IO_PENDING);
  436. //
  437. // If this thread impersonated a user, we need to revert back.
  438. //
  439. if (didImpersonate) {
  440. RevertToSelf();
  441. }
  442. //
  443. // Set the return status of the operation. This is used by the kernel
  444. // mode routines to figure out the completion status of the user mode
  445. // request. This is done here because the async completion routine that is
  446. // called immediately afterwards needs the status set.
  447. //
  448. if (WStatus != ERROR_SUCCESS) {
  449. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  450. } else {
  451. INTERNET_CACHE_ENTRY_INFOW CEI;
  452. CEI.LastAccessTime.dwLowDateTime = 0;
  453. CEI.LastAccessTime.dwHighDateTime = 0;
  454. SetUrlCacheEntryInfo(DavReNameRequest->Url,&CEI,CACHE_ENTRY_ACCTIME_FC);
  455. DavPrint((DEBUG_MISC,
  456. "DavFsRename Reset LastAccessTime for %ws\n",DavReNameRequest->Url));
  457. DavWorkItem->Status = STATUS_SUCCESS;
  458. }
  459. DavAsyncReNameCompletion(DavWorkItem);
  460. #endif
  461. return WStatus;
  462. }
  463. DWORD
  464. DavAsyncReName(
  465. PDAV_USERMODE_WORKITEM DavWorkItem,
  466. BOOLEAN CalledByCallBackThread
  467. )
  468. /*++
  469. Routine Description:
  470. This is the callback routine for the ReName operation.
  471. Arguments:
  472. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  473. CalledByCallbackThread - TRUE, if this function was called by the thread
  474. which picks of the DavWorkItem from the Callback
  475. function. This happens when an Async WinInet call
  476. returns ERROR_IO_PENDING and completes later.
  477. Return Value:
  478. ERROR_SUCCESS or the appropriate error value.
  479. --*/
  480. {
  481. ULONG WStatus = ERROR_SUCCESS;
  482. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem;
  483. BOOL didImpersonate = FALSE;
  484. HINTERNET DavOpenHandle = NULL;
  485. ULONG HttpResponseStatus = 0;
  486. PCHAR DataBuff = NULL;
  487. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  488. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  489. if (CalledByCallBackThread) {
  490. //
  491. // We are running in the context of a worker thread which has different
  492. // credentials than the user that initiated the I/O request. Before
  493. // proceeding further, we should impersonate the user that initiated the
  494. // request.
  495. //
  496. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  497. if (WStatus != ERROR_SUCCESS) {
  498. DavPrint((DEBUG_ERRORS,
  499. "DavAsyncReName/UMReflectorImpersonate. Error Val = %d\n",
  500. WStatus));
  501. goto EXIT_THE_FUNCTION;
  502. }
  503. didImpersonate = TRUE;
  504. //
  505. // Before proceeding further, check to see if the Async operation failed.
  506. // If it did, then cleanup and move on.
  507. //
  508. if ( !DavWorkItem->AsyncResult->dwResult ) {
  509. WStatus = DavWorkItem->AsyncResult->dwError;
  510. //
  511. // If the error we got back is ERROR_INTERNET_FORCE_RETRY, then
  512. // WinInet is trying to authenticate itself with the server. In
  513. // such a scenario this is what happens.
  514. //
  515. // Client ----Request-----> Server
  516. // Server ----AccessDenied-----> Client
  517. // Client----Challenge Me-------> Server
  518. // Server-----Challenge--------> Client
  519. // Client-----Challenge Resp----> Server
  520. //
  521. if (WStatus == ERROR_INTERNET_FORCE_RETRY) {
  522. ASSERT(DavWorkItem->DavOperation == DAV_CALLBACK_HTTP_END);
  523. //
  524. // We need to repeat the HttpSend and HttpEnd request calls.
  525. //
  526. DavWorkItem->DavOperation = DAV_CALLBACK_HTTP_OPEN;
  527. WStatus = DavAsyncCommonStates(DavWorkItem, FALSE);
  528. if (WStatus != ERROR_SUCCESS && WStatus != ERROR_IO_PENDING) {
  529. DavPrint((DEBUG_ERRORS,
  530. "DavAsyncReName/DavAsyncCommonStates. Error Val ="
  531. " %08lx\n", WStatus));
  532. }
  533. } else {
  534. DavPrint((DEBUG_ERRORS,
  535. "DavAsyncReName. AsyncFunction failed. Error Val = %d\n",
  536. WStatus));
  537. }
  538. goto EXIT_THE_FUNCTION;
  539. }
  540. }
  541. #else
  542. ASSERT(CalledByCallBackThread == FALSE);
  543. #endif
  544. DavOpenHandle = DavWorkItem->AsyncReName.DavOpenHandle;
  545. WStatus = DavQueryAndParseResponseEx(DavOpenHandle, &(HttpResponseStatus));
  546. if (WStatus != ERROR_SUCCESS) {
  547. //
  548. // The MOVE request that was sent to the server failed.
  549. // If the response status is HTTP_STATUS_PRECOND_FAILED then it means
  550. // that we tried to rename a file to a file which already exists and
  551. // ReplaceIfExists (sent by the caller) was FALSE. In such a case we
  552. // return ERROR_ALREADY_EXISTS.
  553. //
  554. if (HttpResponseStatus == HTTP_STATUS_PRECOND_FAILED) {
  555. WStatus = ERROR_ALREADY_EXISTS;
  556. } else {
  557. WStatus = ERROR_UNABLE_TO_MOVE_REPLACEMENT;
  558. }
  559. DavPrint((DEBUG_ERRORS,
  560. "DavAsyncReName/DavQueryAndParseResponse. WStatus = %d, HttpResponseStatus = %d\n",
  561. WStatus, HttpResponseStatus));
  562. }
  563. //
  564. // If we get back a 207 (DAV_MULTI_STATUS) as the response, we need to
  565. // parse the returned XML and see if the status code was 200. If it
  566. // wasn't it means that the MOVE failed.
  567. //
  568. if (HttpResponseStatus == DAV_MULTI_STATUS) {
  569. DWORD NumRead = 0, NumOfFileEntries = 0, TotalDataBytesRead = 0;
  570. BOOL ReturnVal = FALSE, readDone = FALSE;
  571. DAV_FILE_ATTRIBUTES DavFileAttributes;
  572. PVOID Ctx1 = NULL, Ctx2 = NULL;
  573. DataBuff = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, NUM_OF_BYTES_TO_READ);
  574. if (DataBuff == NULL) {
  575. WStatus = GetLastError();
  576. DavPrint((DEBUG_ERRORS,
  577. "DavAsyncReName/LocalAlloc: WStatus = %08lx\n",
  578. WStatus));
  579. goto EXIT_THE_FUNCTION;
  580. }
  581. //
  582. // Read the response and parse it.
  583. //
  584. do {
  585. ReturnVal = InternetReadFile(DavOpenHandle,
  586. (LPVOID)DataBuff,
  587. NUM_OF_BYTES_TO_READ,
  588. &(NumRead));
  589. if (!ReturnVal) {
  590. WStatus = GetLastError();
  591. DavPrint((DEBUG_ERRORS,
  592. "DavAsyncReName/InternetReadFile: WStatus = %08lx\n",
  593. WStatus));
  594. goto EXIT_THE_FUNCTION;
  595. }
  596. DavPrint((DEBUG_MISC, "DavAsyncReName: NumRead = %d\n", NumRead));
  597. //
  598. // We reject files whose attributes are greater than a
  599. // certain size (DavFileAttributesLimitInBytes). This
  600. // is a parameter that can be set in the registry. This
  601. // is done to avoid attacks by rogue servers.
  602. //
  603. TotalDataBytesRead += NumRead;
  604. if (TotalDataBytesRead > DavFileAttributesLimitInBytes) {
  605. WStatus = ERROR_BAD_NET_RESP;
  606. DavPrint((DEBUG_ERRORS, "DavAsyncReName. FileAttributesSize > %d\n", DavFileAttributesLimitInBytes));
  607. goto EXIT_THE_FUNCTION;
  608. }
  609. readDone = (NumRead == 0) ? TRUE : FALSE;
  610. WStatus = DavPushData(DataBuff, &Ctx1, &Ctx2, NumRead, readDone);
  611. if (WStatus != ERROR_SUCCESS) {
  612. DavPrint((DEBUG_ERRORS,
  613. "DavAsyncReName/DavPushData. WStatus = %d\n",
  614. WStatus));
  615. goto EXIT_THE_FUNCTION;
  616. }
  617. if (readDone) {
  618. break;
  619. }
  620. } while ( TRUE );
  621. memset(&DavFileAttributes, 0, sizeof(DavFileAttributes));
  622. InitializeListHead( &(DavFileAttributes.NextEntry) );
  623. WStatus = DavParseData(&DavFileAttributes, Ctx1, Ctx2, &NumOfFileEntries);
  624. if (WStatus != ERROR_SUCCESS) {
  625. DavPrint((DEBUG_ERRORS,
  626. "DavAsyncReName/DavParseData. WStatus = %d\n",
  627. WStatus));
  628. DavFinalizeFileAttributesList(&DavFileAttributes, FALSE);
  629. goto EXIT_THE_FUNCTION;
  630. }
  631. if (DavFileAttributes.InvalidNode) {
  632. WStatus = ERROR_SHARING_VIOLATION;
  633. }
  634. DavFinalizeFileAttributesList(&DavFileAttributes, FALSE);
  635. DavCloseContext(Ctx1, Ctx2);
  636. }
  637. EXIT_THE_FUNCTION:
  638. //
  639. // If we did impersonate, we need to revert back.
  640. //
  641. if (didImpersonate) {
  642. ULONG RStatus;
  643. RStatus = UMReflectorRevert(UserWorkItem);
  644. if (RStatus != ERROR_SUCCESS) {
  645. DavPrint((DEBUG_ERRORS,
  646. "DavAsyncReName/UMReflectorRevert. Error Val = %d\n",
  647. RStatus));
  648. }
  649. }
  650. if (DataBuff != NULL) {
  651. LocalFree(DataBuff);
  652. DataBuff = NULL;
  653. }
  654. #ifdef DAV_USE_WININET_ASYNCHRONOUSLY
  655. //
  656. // Some resources should not be freed if we are returning ERROR_IO_PENDING
  657. // because they will be used in the callback functions.
  658. //
  659. if ( WStatus != ERROR_IO_PENDING && CalledByCallBackThread ) {
  660. //
  661. // Set the return status of the operation. This is used by the kernel
  662. // mode routines to figure out the completion status of the user mode
  663. // request.
  664. //
  665. if (WStatus != ERROR_SUCCESS) {
  666. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  667. } else {
  668. DavWorkItem->Status = STATUS_SUCCESS;
  669. }
  670. //
  671. // Call the DavAsyncReNameCompletion routine.
  672. //
  673. DavAsyncReNameCompletion(DavWorkItem);
  674. //
  675. // This thread now needs to send the response back to the kernel. It
  676. // does not wait in the kernel (to get another request) after submitting
  677. // the response.
  678. //
  679. UMReflectorCompleteRequest(DavReflectorHandle, UserWorkItem);
  680. } else {
  681. DavPrint((DEBUG_MISC, "DavAsyncReName: Returning ERROR_IO_PENDING.\n"));
  682. }
  683. #endif
  684. return WStatus;
  685. }
  686. VOID
  687. DavAsyncReNameCompletion(
  688. PDAV_USERMODE_WORKITEM DavWorkItem
  689. )
  690. /*++
  691. Routine Description:
  692. This routine handles the ReName completion. It basically frees up the
  693. resources allocated during the ReName operation.
  694. Arguments:
  695. DavWorkItem - The DAV_USERMODE_WORKITEM value.
  696. Return Value:
  697. none.
  698. --*/
  699. {
  700. if (DavWorkItem->AsyncReName.DavOpenHandle != NULL) {
  701. BOOL ReturnVal;
  702. ULONG FreeStatus;
  703. HINTERNET DavOpenHandle = DavWorkItem->AsyncReName.DavOpenHandle;
  704. ReturnVal = InternetCloseHandle( DavOpenHandle );
  705. if (!ReturnVal) {
  706. FreeStatus = GetLastError();
  707. DavPrint((DEBUG_ERRORS,
  708. "DavAsyncReNameCompletion/InternetCloseHandle. Error Val "
  709. "= %d\n", FreeStatus));
  710. }
  711. }
  712. if (DavWorkItem->AsyncReName.HeaderBuff != NULL) {
  713. HLOCAL FreeHandle;
  714. ULONG FreeStatus;
  715. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncReName.HeaderBuff);
  716. if (FreeHandle != NULL) {
  717. FreeStatus = GetLastError();
  718. DavPrint((DEBUG_ERRORS,
  719. "DavAsyncReNameCompletion/LocalFree. Error Val = %d\n",
  720. FreeStatus));
  721. }
  722. }
  723. if (DavWorkItem->AsyncResult != NULL) {
  724. HLOCAL FreeHandle;
  725. ULONG FreeStatus;
  726. FreeHandle = LocalFree((HLOCAL)DavWorkItem->AsyncResult);
  727. if (FreeHandle != NULL) {
  728. FreeStatus = GetLastError();
  729. DavPrint((DEBUG_ERRORS,
  730. "DavAsyncReNameCompletion/LocalFree. Error Val = %d\n",
  731. FreeStatus));
  732. }
  733. }
  734. DavFsFinalizeTheDavCallBackContext(DavWorkItem);
  735. //
  736. // We are done with the per user entry, so finalize it.
  737. //
  738. if (DavWorkItem->AsyncReName.PerUserEntry) {
  739. DavFinalizePerUserEntry( &(DavWorkItem->AsyncReName.PerUserEntry) );
  740. }
  741. return;
  742. }
  743. ULONG
  744. DavFsSetFileInformation(
  745. PDAV_USERMODE_WORKITEM DavWorkItem
  746. )
  747. /*++
  748. Routine Description:
  749. This routine handles SetFileInformation requests for the DAV Mini-Redir that get
  750. reflected from the kernel.
  751. Arguments:
  752. DavWorkItem - The buffer that contains the request parameters and options.
  753. Return Value:
  754. The return status for the operation
  755. --*/
  756. {
  757. ULONG WStatus = ERROR_SUCCESS;
  758. NTSTATUS NtStatus = STATUS_SUCCESS;
  759. PWCHAR ServerName = NULL, DirectoryPath = NULL, CanName = NULL;
  760. PWCHAR OpenVerb = NULL;
  761. ULONG_PTR CallBackContext = (ULONG_PTR)0;
  762. BOOL EnCriSec = FALSE, ReturnVal, CallBackContextInitialized = FALSE, fSetDirectoryEntry = FALSE;
  763. PDAV_USERMODE_SETFILEINFORMATION_REQUEST SetFileInformationRequest = &(DavWorkItem->SetFileInformationRequest);
  764. ULONG ServerID;
  765. PPER_USER_ENTRY PerUserEntry = NULL;
  766. PHASH_SERVER_ENTRY ServerHashEntry = NULL;
  767. HINTERNET DavConnHandle, DavOpenHandle;
  768. PBYTE DataBuff = NULL;
  769. LARGE_INTEGER FileSize, ByteOffset;
  770. BY_HANDLE_FILE_INFORMATION FileInfo;
  771. IO_STATUS_BLOCK IoStatusBlock;
  772. HANDLE FileHandle;
  773. OBJECT_ATTRIBUTES ObjectAttributes;
  774. static UINT UniqueTempId = 1;
  775. BOOL didImpersonate = FALSE;
  776. PUMRX_USERMODE_WORKITEM_HEADER UserWorkItem = NULL;
  777. BOOLEAN didITakeAPUEReference = FALSE;
  778. //
  779. // The first character is a '\' which has to be stripped.
  780. //
  781. ServerName = &(SetFileInformationRequest->ServerName[1]);
  782. if (!ServerName) {
  783. DavPrint((DEBUG_ERRORS, "DavFsSetFileInformation: ServerName is NULL.\n"));
  784. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  785. goto EXIT_THE_FUNCTION;
  786. }
  787. DavPrint((DEBUG_MISC, "DavFsSetFileInformation: ServerName = %ws.\n", ServerName));
  788. ServerID = SetFileInformationRequest->ServerID;
  789. DavPrint((DEBUG_MISC, "DavFsSetFileInformation: ServerID = %d.\n", ServerID));
  790. //
  791. // The first character is a '\' which has to be stripped.
  792. //
  793. DirectoryPath = &(SetFileInformationRequest->PathName[1]);
  794. if (!DirectoryPath) {
  795. DavPrint((DEBUG_ERRORS, "DavFsSetFileInformation: DirectoryPath is NULL.\n"));
  796. WStatus = ERROR_INVALID_PARAMETER; // STATUS_INVALID_PARAMETER;
  797. goto EXIT_THE_FUNCTION;
  798. }
  799. DavPrint((DEBUG_MISC, "DavFsSetFileInformation: DirectoryPath = %ws.\n", DirectoryPath));
  800. //
  801. // The DirectoryPath can contain \ characters. Replace them by / characters.
  802. //
  803. CanName = DirectoryPath;
  804. while (*CanName) {
  805. if (*CanName == L'\\') {
  806. *CanName = L'/';
  807. }
  808. CanName++;
  809. }
  810. UserWorkItem = (PUMRX_USERMODE_WORKITEM_HEADER)DavWorkItem;
  811. //
  812. // If we have a dummy share name in the DirectoryPath, we need to remove it
  813. // right now before we contact the server.
  814. //
  815. DavRemoveDummyShareFromFileName(DirectoryPath);
  816. //
  817. // A User Entry for this user must have been created during the create call
  818. // earlier. The user entry contains the handle used to send an HttpOpen
  819. // request.
  820. //
  821. EnterCriticalSection( &(HashServerEntryTableLock) );
  822. EnCriSec = TRUE;
  823. ReturnVal = DavDoesUserEntryExist(ServerName,
  824. ServerID,
  825. &(SetFileInformationRequest->LogonID),
  826. &PerUserEntry,
  827. &ServerHashEntry);
  828. //
  829. // If the following request in the kernel get cancelled even before the
  830. // corresponding usermode thread gets a chance to execute this code, then
  831. // it possible that the VNetRoot (hence the PerUserEntry) and SrvCall get
  832. // finalized before the thread that is handling the create comes here. This
  833. // could happen if this request was the only one for this share and the
  834. // server as well. This is why we need to check if the ServerHashEntry and
  835. // the PerUserEntry are valid before proceeding.
  836. //
  837. if (ReturnVal == FALSE || ServerHashEntry == NULL || PerUserEntry == NULL) {
  838. WStatus = ERROR_CANCELLED;
  839. DavPrint((DEBUG_ERRORS, "DavFsSetFileInformation: (ServerHashEntry == NULL || PerUserEntry == NULL)\n"));
  840. goto EXIT_THE_FUNCTION;
  841. }
  842. DavWorkItem->ServerUserEntry.PerUserEntry = PerUserEntry;
  843. //
  844. // Add a reference to the user entry and set didITakeAPUEReference to TRUE.
  845. //
  846. PerUserEntry->UserEntryRefCount++;
  847. didITakeAPUEReference = TRUE;
  848. //
  849. // Since a create had succeeded earlier, the entry must be good.
  850. //
  851. ASSERT(PerUserEntry->UserEntryState == UserEntryInitialized);
  852. ASSERT(PerUserEntry->DavConnHandle != NULL);
  853. //
  854. // And yes, we obviously have to leave the critical section
  855. // before returning.
  856. //
  857. LeaveCriticalSection( &(HashServerEntryTableLock) );
  858. EnCriSec = FALSE;
  859. WStatus = UMReflectorImpersonate(UserWorkItem, DavWorkItem->ImpersonationHandle);
  860. if (WStatus != ERROR_SUCCESS) {
  861. DavPrint((DEBUG_ERRORS,
  862. "DavFsSetFileInformation/UMReflectorImpersonate. Error Val = %d\n",
  863. WStatus));
  864. goto EXIT_THE_FUNCTION;
  865. }
  866. didImpersonate = TRUE;
  867. DavWorkItem->DavMinorOperation = DavMinorProppatchFile;
  868. WStatus = DavSetBasicInformation(DavWorkItem,
  869. PerUserEntry->DavConnHandle,
  870. DirectoryPath,
  871. SetFileInformationRequest->fCreationTimeChanged,
  872. SetFileInformationRequest->fLastAccessTimeChanged,
  873. SetFileInformationRequest->fLastModifiedTimeChanged,
  874. SetFileInformationRequest->fFileAttributesChanged,
  875. &SetFileInformationRequest->FileBasicInformation.CreationTime,
  876. &SetFileInformationRequest->FileBasicInformation.LastAccessTime,
  877. &SetFileInformationRequest->FileBasicInformation.LastWriteTime,
  878. SetFileInformationRequest->FileBasicInformation.FileAttributes);
  879. if (WStatus != ERROR_SUCCESS) {
  880. ULONG LogStatus;
  881. DavPrint((DEBUG_ERRORS,
  882. "DavFsSetFileInformation/DavSetBasicInformation. WStatus = %d\n",
  883. WStatus));
  884. LogStatus = DavFormatAndLogError(DavWorkItem, WStatus);
  885. if (LogStatus != ERROR_SUCCESS) {
  886. DavPrint((DEBUG_ERRORS,
  887. "DavFsSetFileInformation/DavFormatAndLogError. LogStatus = %d\n",
  888. LogStatus));
  889. }
  890. }
  891. RevertToSelf();
  892. didImpersonate = FALSE;
  893. EXIT_THE_FUNCTION:
  894. if (EnCriSec) {
  895. LeaveCriticalSection( &(HashServerEntryTableLock) );
  896. EnCriSec = FALSE;
  897. }
  898. //
  899. // If didITakeAPUEReference is TRUE we need to remove the reference we
  900. // took on the PerUserEntry.
  901. //
  902. if (didITakeAPUEReference) {
  903. DavFinalizePerUserEntry( &(DavWorkItem->ServerUserEntry.PerUserEntry) );
  904. }
  905. //
  906. // If we are using WinInet synchronously, then we should never get back
  907. // ERROR_IO_PENDING from WinInet.
  908. //
  909. ASSERT(WStatus != ERROR_IO_PENDING);
  910. //
  911. // If this thread impersonated a user, we need to revert back.
  912. //
  913. if (didImpersonate) {
  914. RevertToSelf();
  915. }
  916. //
  917. // Set the return status of the operation. This is used by the kernel
  918. // mode routines to figure out the completion status of the user mode
  919. // request. This is done here because the async completion routine that is
  920. // called immediately afterwards needs the status set.
  921. //
  922. if (WStatus != ERROR_SUCCESS) {
  923. DavWorkItem->Status = DavMapErrorToNtStatus(WStatus);
  924. } else {
  925. DavWorkItem->Status = STATUS_SUCCESS;
  926. }
  927. DavFsFinalizeTheDavCallBackContext(DavWorkItem);
  928. return WStatus;
  929. }