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.

3424 lines
82 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. ntstuff.c
  5. Abstract:
  6. entry point and functions exported by cscdll.dll which are specific for nt
  7. Contents:
  8. Author:
  9. Shishir Pardikar
  10. Environment:
  11. Win32 (user-mode) DLL
  12. Revision History:
  13. 11-5-97 created
  14. --*/
  15. #include "pch.h"
  16. #ifdef CSC_ON_NT
  17. #include <winioctl.h>
  18. #include <winwlx.h>
  19. #endif
  20. #include "shdcom.h"
  21. #include "shdsys.h"
  22. #include "reint.h"
  23. #include "utils.h"
  24. #include "resource.h"
  25. #include "strings.h"
  26. // this sets flags in a couple of headers to not include some defs.
  27. #define REINT
  28. #include "lib3.h"
  29. #ifdef CSC_ON_NT
  30. #include "ntioapi.h"
  31. #include "npapi.h"
  32. #include "ntddnfs.h"
  33. #include "dfsfsctl.h"
  34. #define MAX_LOGONS 64
  35. #define FLAG_AGENT_SEC_LOCAL_SYSTEM 0x00000001
  36. typedef struct tagAGENT_SEC AGENT_SEC, *LPAGENT_SEC;
  37. typedef struct tagAGENT_SEC {
  38. LPAGENT_SEC lpASNext; // next in the list !ACHTUNG, this must be the first element
  39. DWORD dwFlags;
  40. HANDLE hDupToken; // thread token
  41. ULONG ulPrincipalID; // ID of this principal in the CSC database
  42. LUID luidAuthId; // auth ID to disambiguate between tokens with the same SID
  43. TOKEN_USER sTokenUser;
  44. }
  45. AGENT_SEC, *LPAGENT_SEC;
  46. //
  47. // Globals/Locals
  48. //
  49. #define REG_VALUE_DISABLE_AGENT L"DisableAgent"
  50. #define REG_VALUE_INACTIVE_AGENT L"InactiveAgent"
  51. #define NT_PREFIX_FOR_UNC L"\\??\\UNC"
  52. #define SHUTDOWN_SLEEP_INTERVAL_MS (1000)
  53. #define SHUTDOWN_WAIT_INTERVAL_MS (60*1000)
  54. BOOL fAgentThreadRunning = FALSE; // agent is running
  55. LPAGENT_SEC vlpASHead = NULL; // head of the security info list for all logged on users
  56. DWORD rgdwCSCSecIndx[MAX_LOGONS];
  57. DWORD dwLogonCount = 0;
  58. HDESK hdesktopUser = NULL; // set at every logon logon, reset at every logon
  59. HDESK hdesktopCur = NULL; // set while reporting events, reset at logoff
  60. _TCHAR vszNTLANMAN[] = _TEXT("ntlanman.dll");
  61. static UNICODE_STRING DfsDriverObjectName =
  62. {
  63. sizeof(DFS_DRIVER_NAME) - sizeof(UNICODE_NULL),
  64. sizeof(DFS_DRIVER_NAME) - sizeof(UNICODE_NULL),
  65. DFS_DRIVER_NAME
  66. };
  67. AssertData;
  68. AssertError;
  69. //
  70. // prototypes
  71. //
  72. BOOL
  73. OkToLaunchAgent(
  74. VOID
  75. );
  76. BOOL
  77. AttachAuthInfoForThread(
  78. HANDLE hTokenInput
  79. );
  80. BOOL
  81. ReleaseAuthInfoForThread(
  82. HANDLE hTokenInput
  83. );
  84. BOOL
  85. ImpersonateALoggedOnUser(
  86. VOID
  87. );
  88. #ifdef __cplusplus
  89. extern "C" {
  90. #endif
  91. DWORD APIENTRY
  92. NPAddConnection3ForCSCAgent(
  93. HWND hwndOwner,
  94. LPNETRESOURCE lpNetResource,
  95. LPTSTR pszPassword,
  96. LPTSTR pszUserName,
  97. DWORD dwFlags,
  98. BOOL *lpfIsDfsConnect
  99. );
  100. DWORD APIENTRY
  101. NPCancelConnectionForCSCAgent (
  102. LPCTSTR szName,
  103. BOOL fForce );
  104. DWORD APIENTRY
  105. NPGetConnectionPerformance(
  106. LPCWSTR lpRemoteName,
  107. LPNETCONNECTINFOSTRUCT lpNetConnectInfo
  108. );
  109. #ifdef __cplusplus
  110. }
  111. #endif
  112. DWORD
  113. WINAPI
  114. MprServiceProc(
  115. IN LPVOID lpvParam
  116. );
  117. //
  118. // functions
  119. //
  120. DWORD WINAPI
  121. WinlogonStartupEvent(
  122. LPVOID lpParam
  123. )
  124. /*++
  125. Routine Description:
  126. The routine is called by winlogon when a user logs on to the system.
  127. Arguments:
  128. none
  129. Returns:
  130. ERROR_SUCCESS if all went well, otherwise the appropriate error code.
  131. Notes:
  132. Because of the way registry is setup for cscdll.dll, winlogon will call this routine
  133. (and all the winlogonXXXEvent routines) on a seperate thread. We get the auth info for
  134. for the localsystem if necessary and attach it in our list of currently logged on users.
  135. NB. This solution works only for interactive logons. This is good enough for V1 of the
  136. product. All the "known" services that log on non-interactively do so as local-system. We
  137. are already keeping the auth-info for local-system. Hence this should cover all the
  138. pricipals running on a system.
  139. Once the agent runs, it runs forever till the system shuts down.
  140. --*/
  141. {
  142. BOOL bResult;
  143. bResult = ProcessIdToSessionId(
  144. GetCurrentProcessId(),
  145. &vdwAgentSessionId);
  146. ReintKdPrint(SECURITY, ("WinlogonStartupEvent\n"));
  147. if (!fAgentThreadRunning)
  148. {
  149. // agent is not yet running
  150. if (OkToLaunchAgent())
  151. {
  152. // registry doesn't disallow from launching the agent
  153. // let us be the localsystem.
  154. // let us also get the winlogon (localsystem) token
  155. if(AttachAuthInfoForThread(NULL))
  156. {
  157. // launch the agent
  158. fAgentThreadRunning = TRUE;
  159. // we will essentially get stuck here for ever
  160. MprServiceProc(NULL);
  161. fAgentThreadRunning = FALSE;
  162. }
  163. else
  164. {
  165. ReintKdPrint(BADERRORS, ("Couldn't get authinfo for self, error=%d\r\n", GetLastError()));
  166. }
  167. }
  168. else
  169. {
  170. ReintKdPrint(BADERRORS, ("Disbaling agent launch\r\n"));
  171. }
  172. }
  173. return ERROR_SUCCESS;
  174. }
  175. DWORD WINAPI
  176. WinlogonLogonEvent(
  177. LPVOID lpParam
  178. )
  179. /*++
  180. Routine Description:
  181. The routine is called by winlogon when a user logs on to the system.
  182. Arguments:
  183. none
  184. Returns:
  185. ERROR_SUCCESS if all went well, otherwise the appropriate error code.
  186. Notes:
  187. Because of the way registry is setup for cscdll.dll, winlogon will call this routine
  188. (and all the winlogonXXXEvent routines) on a seperate thread, impersonated as the
  189. currently logged on user. We get the auth info this guy and also for the localsystem, if
  190. necessary and attach it in our list of currently logged on users.
  191. NB. This solution works only for interactive logons. This is good enough for V1 of the
  192. product. All the "known" services that log on non-interactively do so as local-system. We
  193. are already keeping the auth-info for local-system. Hence this should cover all the
  194. pricipals running on a system.
  195. Once the agent runs, it runs forever till the system shuts down.
  196. --*/
  197. {
  198. DWORD dwError = ERROR_SUCCESS;
  199. PWLX_NOTIFICATION_INFO pWlx = (PWLX_NOTIFICATION_INFO)lpParam;
  200. ReintKdPrint(SECURITY, ("WinlogonLogonEvent\n"));
  201. Assert(pWlx->hToken);
  202. // NTRAID-455262-1/31/2000-shishirp this desktop scheme breaks for HYDRA
  203. EnterAgentCrit();
  204. if (!hdesktopUser)
  205. {
  206. if(!DuplicateHandle( GetCurrentProcess(),
  207. pWlx->hDesktop,
  208. GetCurrentProcess(),
  209. &hdesktopUser,
  210. 0,
  211. FALSE,
  212. DUPLICATE_SAME_ACCESS
  213. ))
  214. {
  215. ReintKdPrint(ALWAYS, ("Failed to dup dekstop handle Error = %d \n", GetLastError()));
  216. }
  217. else
  218. {
  219. ReintKdPrint(INIT, ("dekstop handle = %x \n", hdesktopUser));
  220. }
  221. }
  222. LeaveAgentCrit();
  223. UpdateExclusionList();
  224. UpdateBandwidthConservationList();
  225. InitCSCUI(pWlx->hToken);
  226. // attached to the list of logged on users
  227. if(AttachAuthInfoForThread(pWlx->hToken))
  228. {
  229. if (fAgentThreadRunning)
  230. {
  231. }
  232. }
  233. else
  234. {
  235. dwError = GetLastError();
  236. ReintKdPrint(BADERRORS, ("Failed to get Authentication Info for the thread Error %d, disbaling agent launch\r\n", dwError));
  237. }
  238. return ERROR_SUCCESS;
  239. }
  240. DWORD WINAPI
  241. WinlogonLogoffEvent(
  242. LPVOID lpParam
  243. )
  244. /*++
  245. Routine Description:
  246. The routine is called by winlogon when a user logs off the system.
  247. Arguments:
  248. Returns:
  249. ERROR_SUCCESS if all went well, otherwise the appropriate error code.
  250. Notes:
  251. --*/
  252. {
  253. PWLX_NOTIFICATION_INFO pWlx = (PWLX_NOTIFICATION_INFO)lpParam;
  254. BOOL fLastLogoff = FALSE;
  255. ReintKdPrint(SECURITY, ("WinlogonLogoffEvent\n"));
  256. Assert(pWlx->hToken);
  257. ReleaseAuthInfoForThread(pWlx->hToken);
  258. // only when there is no-one in the queue or the only guy remaining is the system,
  259. // we declare that we are getting logged off.
  260. EnterAgentCrit();
  261. fLastLogoff = ((vlpASHead == NULL)||(vlpASHead->lpASNext == NULL));
  262. LeaveAgentCrit();
  263. if (fLastLogoff)
  264. {
  265. TerminateCSCUI();
  266. if (hdesktopUser)
  267. {
  268. CloseDesktop(hdesktopUser);
  269. hdesktopUser = NULL;
  270. }
  271. }
  272. #if 0
  273. if (fAgentThreadRunning)
  274. {
  275. Assert(vhwndMain);
  276. PostMessage(vhwndMain, WM_QUIT, 0, 0);
  277. }
  278. #endif
  279. ReintKdPrint(SECURITY, ("User logging off \r\n"));
  280. return ERROR_SUCCESS;
  281. }
  282. DWORD WINAPI
  283. WinlogonScreenSaverEvent(
  284. LPVOID lpParam
  285. )
  286. /*++
  287. Routine Description:
  288. Arguments:
  289. Returns:
  290. Notes:
  291. --*/
  292. {
  293. ReintKdPrint(SECURITY, ("WinlogonScreenSaverEvent\n"));
  294. return ERROR_CALL_NOT_IMPLEMENTED;
  295. }
  296. DWORD WINAPI
  297. WinlogonShutdownEvent(
  298. LPVOID lpParam
  299. )
  300. /*++
  301. Routine Description:
  302. Arguments:
  303. Returns:
  304. Notes:
  305. --*/
  306. {
  307. DWORD dwStart, dwCur;
  308. ReintKdPrint(SECURITY, ("WinlogonShutdownEvent\n"));
  309. if (fAgentThreadRunning)
  310. {
  311. ReintKdPrint(MAINLOOP, ("Setting Agent Shtudown \r\n"));
  312. SetAgentShutDownRequest();
  313. dwCur = dwStart = GetTickCount();
  314. // hang out here for sometime to see if he shuts down
  315. for (;;)
  316. {
  317. if (HasAgentShutDown() || ((dwCur < dwStart)||(dwCur > (dwStart+SHUTDOWN_WAIT_INTERVAL_MS))))
  318. {
  319. break;
  320. }
  321. ReintKdPrint(ALWAYS, ("Waiting 1 second for agent to shutdown \r\n"));
  322. // achtung!!! we use sleep becuase at this time the system is shutting down
  323. Sleep(SHUTDOWN_SLEEP_INTERVAL_MS);
  324. dwCur = GetTickCount();
  325. }
  326. }
  327. ReintKdPrint(SECURITY, ("WinlogonShutdownEvent exit\n"));
  328. return ERROR_SUCCESS;
  329. }
  330. DWORD WINAPI
  331. WinlogonLockEvent(
  332. LPVOID lpParam
  333. )
  334. /*++
  335. Routine Description:
  336. Arguments:
  337. Returns:
  338. Notes:
  339. --*/
  340. {
  341. ReintKdPrint(SECURITY, ("Lock \r\n"));
  342. return ERROR_CALL_NOT_IMPLEMENTED;
  343. }
  344. DWORD WINAPI
  345. WinlogonUnlockEvent(
  346. LPVOID lpParam
  347. )
  348. /*++
  349. Routine Description:
  350. Arguments:
  351. Returns:
  352. Notes:
  353. --*/
  354. {
  355. ReintKdPrint(SECURITY, ("Unlock \r\n"));
  356. return ERROR_CALL_NOT_IMPLEMENTED;
  357. }
  358. DWORD WINAPI
  359. WinlogonStartShellEvent(
  360. LPVOID lpParam
  361. )
  362. /*++
  363. Routine Description:
  364. Arguments:
  365. Returns:
  366. Notes:
  367. --*/
  368. {
  369. ReintKdPrint(SECURITY, ("WinlogonStartShellEvent\n"));
  370. UpdateExclusionList();
  371. UpdateBandwidthConservationList();
  372. return ERROR_SUCCESS;
  373. }
  374. BOOL
  375. OkToLaunchAgent(
  376. VOID
  377. )
  378. /*++
  379. Routine Description:
  380. A secret registry way of disabling the agent for testing purposes.
  381. Arguments:
  382. Returns:
  383. Notes:
  384. --*/
  385. {
  386. DWORD dwDisposition;
  387. HKEY hKey = NULL;
  388. BOOL fLaunchAgent = TRUE;
  389. extern BOOL vfAgentQuiet;
  390. #if 0
  391. NT_PRODUCT_TYPE productType;
  392. if( !RtlGetNtProductType( &productType ) ) {
  393. productType = NtProductWinNt;
  394. }
  395. switch ( productType ) {
  396. case NtProductWinNt:
  397. /* WORKSTATION */
  398. ReintKdPrint(INIT, ("Agent:CSC running workstation\r\n"));
  399. break;
  400. case NtProductLanManNt:
  401. case NtProductServer:
  402. /* SERVER */
  403. ReintKdPrint(INIT, ("Agent:CSC running server, disabling CSC\r\n"));
  404. return FALSE;
  405. }
  406. #endif
  407. if (RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  408. REG_KEY_CSC_SETTINGS,
  409. 0,
  410. NULL,
  411. REG_OPTION_NON_VOLATILE,
  412. KEY_READ | KEY_WRITE,
  413. NULL,
  414. &hKey,
  415. &dwDisposition) == ERROR_SUCCESS)
  416. {
  417. // autocheck is always be done on an unclean shutdown
  418. if (RegQueryValueEx(hKey, REG_VALUE_DISABLE_AGENT, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  419. {
  420. fLaunchAgent = FALSE;
  421. ReintKdPrint(BADERRORS, ("Agent:CSC disabled agent launching\r\n"));
  422. }
  423. if (RegQueryValueEx(hKey, REG_VALUE_INACTIVE_AGENT, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
  424. {
  425. vfAgentQuiet = TRUE;
  426. ReintKdPrint(BADERRORS, ("Agent:CSC agent made inactive\r\n"));
  427. }
  428. }
  429. if(hKey)
  430. {
  431. RegCloseKey(hKey);
  432. }
  433. return fLaunchAgent;
  434. }
  435. //
  436. // Security stuff
  437. //
  438. BOOL
  439. AttachAuthInfoForThread(
  440. HANDLE hTokenInput
  441. )
  442. /*++
  443. Routine Description:
  444. This routine is called when we get a logon notification from winlogon. We get this
  445. notification on a thread that is impersonating the user that has logged on.
  446. The routine creates an AGENT_SEC structure for this logged on user. We keep enough
  447. information so that the CSC agent thread can impersonate any of the logged on users.
  448. The agent thread does this in order to make sure that while filling incomplete files
  449. it is impersonating a logged on user, who has read access on the file to be filled.
  450. That way, sparse fills will not generate audits on the server side.
  451. Arguments:
  452. None
  453. Returns:
  454. TRUE if successful
  455. Notes:
  456. We keep AuthenticationID as SIDs are not enough to identify the logged on user because in
  457. case of HYDRA, the same user could get logged in multiple times
  458. The AuthenticationID is guaranteed to be unique for each logon even though the SID is
  459. the same
  460. --*/
  461. {
  462. LPAGENT_SEC lpAS = NULL;
  463. BOOL fRet = FALSE;
  464. HANDLE hDupToken=NULL, hToken=NULL;
  465. DWORD dwSidAndAttributeSize = 0, dwDummy;
  466. TOKEN_STATISTICS sStats;
  467. DWORD dwError;
  468. if (hTokenInput)
  469. {
  470. ReintKdPrint(SECURITY, ("Opening thread token \r\n"));
  471. hToken = hTokenInput;
  472. fRet = TRUE;
  473. #if 0
  474. fRet = OpenThreadToken(
  475. GetCurrentThread(),
  476. TOKEN_DUPLICATE|TOKEN_IMPERSONATE|TOKEN_READ,
  477. FALSE,
  478. &hToken);
  479. #endif
  480. }
  481. else
  482. {
  483. ReintKdPrint(SECURITY, ("Opening process token \r\n"));
  484. fRet = OpenProcessToken(
  485. GetCurrentProcess(),
  486. TOKEN_DUPLICATE|TOKEN_IMPERSONATE|TOKEN_READ,
  487. &hToken);
  488. }
  489. if (fRet)
  490. {
  491. ReintKdPrint(SECURITY, ("Duplicating token \r\n"));
  492. if (DuplicateToken(hToken, SecurityImpersonation, &hDupToken))
  493. {
  494. ReintKdPrint(SECURITY, ("Getting AuthID for the duplicated thread token \r\n"));
  495. if(GetTokenInformation(
  496. hDupToken,
  497. TokenStatistics,
  498. (LPVOID)&sStats,
  499. sizeof(sStats),
  500. &dwSidAndAttributeSize
  501. ))
  502. {
  503. // make a dummy call to find out actually how big a buffer we need
  504. ReintKdPrint(SECURITY, ("Calling to find how much buffer SidAndAttribute needs\r\n"));
  505. GetTokenInformation(
  506. hDupToken,
  507. TokenUser,
  508. (LPVOID)&dwDummy,
  509. 0, // 0 byte buffer
  510. &dwSidAndAttributeSize
  511. );
  512. dwError = GetLastError();
  513. ReintKdPrint(SECURITY, ("Finding buffer size, error=%d\r\n", dwError));
  514. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  515. {
  516. ReintKdPrint(SECURITY, ("SidAndAttribute needs %d bytes\r\n", dwSidAndAttributeSize));
  517. // allocate enough for everything and a little extra
  518. lpAS = (LPAGENT_SEC)LocalAlloc(LPTR, sizeof(AGENT_SEC) + dwSidAndAttributeSize + sizeof(SID_AND_ATTRIBUTES));
  519. if (lpAS)
  520. {
  521. ReintKdPrint(SECURITY, ("Getting SidAndAttribute for the duplicated thread token \r\n"));
  522. if(GetTokenInformation(
  523. hDupToken,
  524. TokenUser,
  525. (LPVOID)&(lpAS->sTokenUser),
  526. dwSidAndAttributeSize,
  527. &dwSidAndAttributeSize
  528. ))
  529. {
  530. ReintKdPrint(SECURITY, ("Success !!!!\r\n"));
  531. // all is well, fill up the info
  532. lpAS->luidAuthId = sStats.AuthenticationId;
  533. lpAS->hDupToken = hDupToken;
  534. lpAS->ulPrincipalID = CSC_INVALID_PRINCIPAL_ID;
  535. if (!hTokenInput)
  536. {
  537. lpAS->dwFlags |= FLAG_AGENT_SEC_LOCAL_SYSTEM;
  538. }
  539. fRet = TRUE;
  540. EnterAgentCrit();
  541. lpAS->lpASNext = vlpASHead;
  542. vlpASHead = lpAS;
  543. LeaveAgentCrit();
  544. }
  545. else
  546. {
  547. ReintKdPrint(BADERRORS, ("Failed to get SidIndex from the database \r\n"));
  548. }
  549. if (!fRet)
  550. {
  551. LocalFree(lpAS);
  552. lpAS = NULL;
  553. }
  554. }
  555. }
  556. }
  557. }
  558. if (!hTokenInput)
  559. {
  560. CloseHandle(hToken);
  561. }
  562. hToken = NULL;
  563. }
  564. if (!fRet)
  565. {
  566. ReintKdPrint(BADERRORS, ("AttachAuthInfoForThread Error %d\r\n", GetLastError()));
  567. }
  568. return fRet;
  569. }
  570. BOOL
  571. ReleaseAuthInfoForThread(
  572. HANDLE hThreadToken
  573. )
  574. /*++
  575. Routine Description:
  576. This routine is called when we get a logoff notification for winlogon. We look at
  577. the current threads to token to get the AuthenticationId for the currently logged on user.
  578. We check our structures to find the one that matches with the AuthId. We remove that
  579. from the list.
  580. Arguments:
  581. None
  582. Returns:
  583. TRUE if successfull
  584. Notes:
  585. We do this based on AuthenticationID rather than the SID because in case of HYDRA, the same
  586. user could get logged in multiple times, so he has the same SID, but the AuthenticationID is
  587. guaranteed to be unique
  588. --*/
  589. {
  590. BOOL fRet = FALSE;
  591. DWORD dwSidAndAttributeSize = 0;
  592. TOKEN_STATISTICS sStats;
  593. LPAGENT_SEC *lplpAS, lpAST;
  594. ReintKdPrint(SECURITY, ("ReleaseAuthInfoForThread: Getting AuthID for the thread token \r\n"));
  595. if(GetTokenInformation(
  596. hThreadToken,
  597. TokenStatistics,
  598. (LPVOID)&sStats,
  599. sizeof(sStats),
  600. &dwSidAndAttributeSize
  601. ))
  602. {
  603. ReintKdPrint(SECURITY, ("ReleaseAuthInfoForThread: looking for the right thread\r\n"));
  604. EnterAgentCrit();
  605. for (lplpAS = &vlpASHead; *lplpAS; lplpAS = &((*lplpAS)->lpASNext))
  606. {
  607. if (!memcmp(&((*lplpAS)->luidAuthId), &(sStats.AuthenticationId), sizeof(LUID)))
  608. {
  609. CloseHandle((*lplpAS)->hDupToken);
  610. lpAST = *lplpAS;
  611. *lplpAS = lpAST->lpASNext;
  612. LocalFree(lpAST);
  613. fRet = TRUE;
  614. ReintKdPrint(SECURITY, ("ReleaseAuthInfoForThread: found him and released\r\n"));
  615. break;
  616. }
  617. }
  618. LeaveAgentCrit();
  619. }
  620. return fRet;
  621. }
  622. BOOL
  623. SetAgentThreadImpersonation(
  624. HSHADOW hDir,
  625. HSHADOW hShadow,
  626. BOOL fWrite
  627. )
  628. /*++
  629. Routine Description:
  630. This routine checks with the database, for the given inode, any of the logged on
  631. users have the desired access. If such a user is found, it impersonates that user.
  632. Arguments:
  633. hDir Parent Inode of the file being accessed
  634. hShadow Inode of the file being accessed
  635. fWrite whether to check for write access, or read access is sufficient
  636. Returns:
  637. TRUE if successfull
  638. Notes:
  639. --*/
  640. {
  641. SECURITYINFO rgsSecurityInfo[CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS];
  642. DWORD dwSize;
  643. LPAGENT_SEC lpAS;
  644. int i;
  645. // for now juts impersonate the logged on user
  646. if (vlpASHead)
  647. {
  648. dwSize = sizeof(rgsSecurityInfo);
  649. if (GetSecurityInfoForCSC(INVALID_HANDLE_VALUE, hDir, hShadow, rgsSecurityInfo, &dwSize))
  650. {
  651. EnterAgentCrit();
  652. for (lpAS = vlpASHead; lpAS; lpAS = lpAS->lpASNext)
  653. {
  654. if (lpAS->ulPrincipalID == CSC_INVALID_PRINCIPAL_ID)
  655. {
  656. if(!FindCreatePrincipalIDFromSID(INVALID_HANDLE_VALUE, lpAS->sTokenUser.User.Sid, GetLengthSid(lpAS->sTokenUser.User.Sid), &(lpAS->ulPrincipalID), TRUE))
  657. {
  658. ReintKdPrint(BADERRORS, ("Failed to get SidIndex from the database \r\n"));
  659. continue;
  660. }
  661. }
  662. Assert(lpAS->ulPrincipalID != CSC_INVALID_PRINCIPAL_ID);
  663. for (i=0;i<CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS;++i)
  664. {
  665. // either the indices match or this is a guest index
  666. if ((rgsSecurityInfo[i].ulPrincipalID == lpAS->ulPrincipalID)||
  667. (rgsSecurityInfo[i].ulPrincipalID == CSC_GUEST_PRINCIPAL_ID))
  668. {
  669. if (rgsSecurityInfo[i].ulPermissions & ((fWrite)?FILE_GENERIC_WRITE:FILE_GENERIC_EXECUTE))
  670. {
  671. goto doneChecking;
  672. }
  673. }
  674. }
  675. }
  676. lpAS = NULL;
  677. doneChecking:
  678. LeaveAgentCrit();
  679. if (!lpAS)
  680. {
  681. ReintKdPrint(SECURITY, ("Couldn't find any user with security info\r\n", GetLastError()));
  682. }
  683. else
  684. {
  685. if (SetThreadToken(NULL, lpAS->hDupToken))
  686. {
  687. return TRUE;
  688. }
  689. else
  690. {
  691. ReintKdPrint(BADERRORS, ("Error %d impersonating the agent\r\n", GetLastError()));
  692. }
  693. }
  694. }
  695. else
  696. {
  697. ReintKdPrint(BADERRORS, ("Couldn't get security info for hShadow=%xh\r\n", hShadow));
  698. }
  699. }
  700. return (FALSE);
  701. }
  702. BOOL
  703. ResetAgentThreadImpersonation(
  704. VOID
  705. )
  706. /*++
  707. Routine Description:
  708. Reverts the agent to
  709. Arguments:
  710. None
  711. Returns:
  712. TRUE if successfull
  713. Notes:
  714. --*/
  715. {
  716. if(!RevertToSelf())
  717. {
  718. ReintKdPrint(BADERRORS, ("Error %d reverting to self\r\n", GetLastError()));
  719. return FALSE;
  720. }
  721. return TRUE;
  722. }
  723. BOOL
  724. ImpersonateALoggedOnUser(
  725. VOID
  726. )
  727. {
  728. LPAGENT_SEC lpAS;
  729. BOOL fRet = FALSE;
  730. EnterAgentCrit();
  731. for (lpAS = vlpASHead; lpAS; lpAS = lpAS->lpASNext)
  732. {
  733. if (lpAS->dwFlags & FLAG_AGENT_SEC_LOCAL_SYSTEM)
  734. {
  735. continue;
  736. }
  737. fRet = SetThreadToken(NULL, lpAS->hDupToken);
  738. }
  739. LeaveAgentCrit();
  740. return (fRet);
  741. }
  742. BOOL
  743. GetCSCPrincipalID(
  744. ULONG *lpPrincipalID
  745. )
  746. /*++
  747. Routine Description:
  748. Arguments:
  749. None
  750. Returns:
  751. TRUE if successful
  752. Notes:
  753. --*/
  754. {
  755. TOKEN_USER *lpTokenUser = NULL;
  756. BOOL fRet = FALSE;
  757. HANDLE hToken=NULL;
  758. DWORD dwSidAndAttributeSize = 0, dwDummy;
  759. TOKEN_STATISTICS sStats;
  760. DWORD dwError=ERROR_SUCCESS;
  761. int i;
  762. SECURITYINFO rgsSecurityInfo[CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS];
  763. *lpPrincipalID = CSC_INVALID_PRINCIPAL_ID;
  764. if(OpenThreadToken(GetCurrentThread(),TOKEN_QUERY,FALSE,&hToken)||
  765. OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken))
  766. {
  767. if(GetTokenInformation(
  768. hToken,
  769. TokenStatistics,
  770. (LPVOID)&sStats,
  771. sizeof(sStats),
  772. &dwSidAndAttributeSize
  773. ))
  774. {
  775. // make a dummy call to find out actually how big a buffer we need
  776. GetTokenInformation(
  777. hToken,
  778. TokenUser,
  779. (LPVOID)&dwDummy,
  780. 0, // 0 byte buffer
  781. &dwSidAndAttributeSize
  782. );
  783. dwError = GetLastError();
  784. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  785. {
  786. // allocate enough for everything and a little extra
  787. lpTokenUser = (TOKEN_USER *)LocalAlloc(LPTR, dwSidAndAttributeSize + sizeof(SID_AND_ATTRIBUTES));
  788. if (lpTokenUser)
  789. {
  790. if(GetTokenInformation(
  791. hToken,
  792. TokenUser,
  793. (LPVOID)(lpTokenUser),
  794. dwSidAndAttributeSize,
  795. &dwSidAndAttributeSize
  796. ))
  797. {
  798. if(FindCreatePrincipalIDFromSID(INVALID_HANDLE_VALUE, lpTokenUser->User.Sid, GetLengthSid(lpTokenUser->User.Sid), lpPrincipalID, FALSE))
  799. {
  800. fRet = TRUE;
  801. }
  802. else
  803. {
  804. dwError = GetLastError();
  805. }
  806. }
  807. else
  808. {
  809. dwError = GetLastError();
  810. }
  811. LocalFree(lpTokenUser);
  812. }
  813. else
  814. {
  815. dwError = GetLastError();
  816. }
  817. }
  818. }
  819. else
  820. {
  821. dwError = GetLastError();
  822. }
  823. CloseHandle(hToken);
  824. hToken = NULL;
  825. if (!fRet)
  826. {
  827. SetLastError(dwError);
  828. }
  829. }
  830. return fRet;
  831. }
  832. BOOL
  833. GetCSCAccessMaskForPrincipal(
  834. unsigned long ulPrincipalID,
  835. HSHADOW hDir,
  836. HSHADOW hShadow,
  837. unsigned long *pulAccessMask
  838. )
  839. {
  840. return GetCSCAccessMaskForPrincipalEx(ulPrincipalID, hDir, hShadow, pulAccessMask, NULL, NULL);
  841. }
  842. BOOL
  843. GetCSCAccessMaskForPrincipalEx(
  844. unsigned long ulPrincipalID,
  845. HSHADOW hDir,
  846. HSHADOW hShadow,
  847. unsigned long *pulAccessMask,
  848. unsigned long *pulActualMaskForUser,
  849. unsigned long *pulActualMaskForGuest
  850. )
  851. /*++
  852. Routine Description:
  853. Arguments:
  854. None
  855. Returns:
  856. TRUE if successful
  857. Notes:
  858. --*/
  859. {
  860. BOOL fRet = FALSE;
  861. DWORD dwDummy,i;
  862. SECURITYINFO rgsSecurityInfo[CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS];
  863. *pulAccessMask &= ~FLAG_CSC_ACCESS_MASK;
  864. if (pulActualMaskForUser)
  865. {
  866. *pulActualMaskForUser = 0;
  867. }
  868. if (pulActualMaskForGuest)
  869. {
  870. *pulActualMaskForGuest = 0;
  871. }
  872. if (ulPrincipalID == CSC_INVALID_PRINCIPAL_ID)
  873. {
  874. DbgPrint("Invalid Principal ID !! \n");
  875. return TRUE;
  876. }
  877. dwDummy = sizeof(rgsSecurityInfo);
  878. if (GetSecurityInfoForCSC(INVALID_HANDLE_VALUE, hDir, hShadow, rgsSecurityInfo, &dwDummy))
  879. {
  880. // ulPrincipalID can be a guest
  881. for (i=0;i<CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS;++i)
  882. {
  883. unsigned long ulCur, ulPermissions;
  884. ulCur = rgsSecurityInfo[i].ulPrincipalID;
  885. ulPermissions = 0;
  886. if (ulCur != CSC_INVALID_PRINCIPAL_ID)
  887. {
  888. // first get the bitmask
  889. if (rgsSecurityInfo[i].ulPermissions & FILE_GENERIC_WRITE)
  890. {
  891. ulPermissions |= FLAG_CSC_WRITE_ACCESS;
  892. }
  893. if (rgsSecurityInfo[i].ulPermissions & FILE_GENERIC_EXECUTE)
  894. {
  895. ulPermissions |= FLAG_CSC_READ_ACCESS;
  896. }
  897. // now shift and OR it in appropriate place
  898. if ((ulCur == ulPrincipalID)&&(ulCur != CSC_GUEST_PRINCIPAL_ID))
  899. {
  900. *pulAccessMask |= (ulPermissions << FLAG_CSC_USER_ACCESS_SHIFT_COUNT);
  901. if (pulActualMaskForUser)
  902. {
  903. *pulActualMaskForUser = rgsSecurityInfo[i].ulPermissions;
  904. }
  905. }
  906. else if (ulCur == CSC_GUEST_PRINCIPAL_ID)
  907. {
  908. *pulAccessMask |= (ulPermissions << FLAG_CSC_GUEST_ACCESS_SHIFT_COUNT);
  909. if (pulActualMaskForGuest)
  910. {
  911. *pulActualMaskForGuest = rgsSecurityInfo[i].ulPermissions;
  912. }
  913. }
  914. else
  915. {
  916. *pulAccessMask |= (ulPermissions << FLAG_CSC_OTHER_ACCESS_SHIFT_COUNT);
  917. }
  918. }
  919. }
  920. fRet = TRUE;
  921. }
  922. return fRet;
  923. }
  924. BOOL
  925. CheckCSCAccessForThread(
  926. HSHADOW hDir,
  927. HSHADOW hShadow,
  928. BOOL fWrite
  929. )
  930. /*++
  931. Routine Description:
  932. Arguments:
  933. None
  934. Returns:
  935. TRUE if successful
  936. Notes:
  937. --*/
  938. {
  939. TOKEN_USER *lpTokenUser = NULL;
  940. BOOL fRet = FALSE;
  941. HANDLE hToken=NULL;
  942. DWORD dwSidAndAttributeSize = 0, dwDummy;
  943. TOKEN_STATISTICS sStats;
  944. DWORD dwError=ERROR_SUCCESS;
  945. int i;
  946. SECURITYINFO rgsSecurityInfo[CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS];
  947. if(OpenThreadToken(GetCurrentThread(),TOKEN_QUERY,FALSE,&hToken)||
  948. OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken))
  949. {
  950. if(GetTokenInformation(
  951. hToken,
  952. TokenStatistics,
  953. (LPVOID)&sStats,
  954. sizeof(sStats),
  955. &dwSidAndAttributeSize
  956. ))
  957. {
  958. // make a dummy call to find out actually how big a buffer we need
  959. GetTokenInformation(
  960. hToken,
  961. TokenUser,
  962. (LPVOID)&dwDummy,
  963. 0, // 0 byte buffer
  964. &dwSidAndAttributeSize
  965. );
  966. dwError = GetLastError();
  967. if (dwError == ERROR_INSUFFICIENT_BUFFER)
  968. {
  969. // allocate enough for everything and a little extra
  970. lpTokenUser = (TOKEN_USER *)LocalAlloc(LPTR, dwSidAndAttributeSize + sizeof(SID_AND_ATTRIBUTES));
  971. if (lpTokenUser)
  972. {
  973. if(GetTokenInformation(
  974. hToken,
  975. TokenUser,
  976. (LPVOID)(lpTokenUser),
  977. dwSidAndAttributeSize,
  978. &dwSidAndAttributeSize
  979. ))
  980. {
  981. ULONG ulPrincipalID;
  982. if(FindCreatePrincipalIDFromSID(INVALID_HANDLE_VALUE, lpTokenUser->User.Sid, GetLengthSid(lpTokenUser->User.Sid), &ulPrincipalID, FALSE))
  983. {
  984. dwDummy = sizeof(rgsSecurityInfo);
  985. if (GetSecurityInfoForCSC(INVALID_HANDLE_VALUE, hDir, hShadow, rgsSecurityInfo, &dwDummy))
  986. {
  987. Assert(ulPrincipalID != CSC_INVALID_PRINCIPAL_ID);
  988. for (i=0;i<CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS;++i)
  989. {
  990. // either the indices match or this is a guest index
  991. if ((rgsSecurityInfo[i].ulPrincipalID == ulPrincipalID)||
  992. (rgsSecurityInfo[i].ulPrincipalID == CSC_GUEST_PRINCIPAL_ID))
  993. {
  994. if (rgsSecurityInfo[i].ulPermissions & ((fWrite)?FILE_GENERIC_WRITE:FILE_GENERIC_EXECUTE))
  995. {
  996. fRet = TRUE;
  997. break;
  998. }
  999. }
  1000. }
  1001. if (!fRet)
  1002. {
  1003. dwError = ERROR_ACCESS_DENIED;
  1004. }
  1005. }
  1006. else
  1007. {
  1008. dwError = GetLastError();
  1009. }
  1010. }
  1011. else
  1012. {
  1013. dwError = GetLastError();
  1014. }
  1015. }
  1016. else
  1017. {
  1018. dwError = GetLastError();
  1019. }
  1020. LocalFree(lpTokenUser);
  1021. }
  1022. else
  1023. {
  1024. dwError = GetLastError();
  1025. }
  1026. }
  1027. }
  1028. else
  1029. {
  1030. dwError = GetLastError();
  1031. }
  1032. CloseHandle(hToken);
  1033. hToken = NULL;
  1034. if (!fRet)
  1035. {
  1036. SetLastError(dwError);
  1037. }
  1038. }
  1039. return fRet;
  1040. }
  1041. #else //CSC_ON_NT
  1042. BOOL
  1043. SetAgentThreadImpersonation(
  1044. HSHADOW hDir,
  1045. HSHADOW hShadow,
  1046. BOOL fWrite
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. NOP for win9x
  1051. Arguments:
  1052. hDir Parent Inode of the file being accessed
  1053. hShadow Inode of the file being accessed
  1054. fWrite whether to check for write access, or read access is sufficient
  1055. Returns:
  1056. TRUE if successfull
  1057. Notes:
  1058. --*/
  1059. {
  1060. return (TRUE);
  1061. }
  1062. BOOL
  1063. ResetAgentThreadImpersonation(
  1064. VOID
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. NOP for win9x
  1069. Arguments:
  1070. None
  1071. Returns:
  1072. TRUE if successfull
  1073. Notes:
  1074. --*/
  1075. {
  1076. return TRUE;
  1077. }
  1078. DWORD WINAPI
  1079. WinlogonStartupEvent(
  1080. LPVOID lpParam
  1081. )
  1082. /*++
  1083. Routine Description:
  1084. Arguments:
  1085. Returns:
  1086. Notes:
  1087. --*/
  1088. {
  1089. return ERROR_CALL_NOT_IMPLEMENTED;
  1090. }
  1091. DWORD WINAPI
  1092. WinlogonLogonEvent(
  1093. LPVOID lpParam
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. Arguments:
  1098. Returns:
  1099. Notes:
  1100. --*/
  1101. {
  1102. return ERROR_CALL_NOT_IMPLEMENTED;
  1103. }
  1104. DWORD WINAPI
  1105. WinlogonLogoffEvent(
  1106. LPVOID lpParam
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. Arguments:
  1111. Returns:
  1112. Notes:
  1113. --*/
  1114. {
  1115. return ERROR_CALL_NOT_IMPLEMENTED;
  1116. }
  1117. DWORD WINAPI
  1118. WinlogonScreenSaverEvent(
  1119. LPVOID lpParam
  1120. )
  1121. /*++
  1122. Routine Description:
  1123. Arguments:
  1124. Returns:
  1125. Notes:
  1126. --*/
  1127. {
  1128. return ERROR_CALL_NOT_IMPLEMENTED;
  1129. }
  1130. DWORD WINAPI
  1131. WinlogonShutdownEvent(
  1132. LPVOID lpParam
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. Arguments:
  1137. Returns:
  1138. Notes:
  1139. --*/
  1140. {
  1141. return ERROR_CALL_NOT_IMPLEMENTED;
  1142. }
  1143. DWORD WINAPI
  1144. WinlogonLockEvent(
  1145. LPVOID lpParam
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. Arguments:
  1150. Returns:
  1151. Notes:
  1152. --*/
  1153. {
  1154. return ERROR_CALL_NOT_IMPLEMENTED;
  1155. }
  1156. DWORD WINAPI
  1157. WinlogonUnlockEvent(
  1158. LPVOID lpParam
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. Arguments:
  1163. Returns:
  1164. Notes:
  1165. --*/
  1166. {
  1167. return ERROR_CALL_NOT_IMPLEMENTED;
  1168. }
  1169. DWORD WINAPI
  1170. WinlogonStartShellEvent(
  1171. LPVOID lpParam
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. Arguments:
  1176. Returns:
  1177. Notes:
  1178. --*/
  1179. {
  1180. return ERROR_CALL_NOT_IMPLEMENTED;
  1181. }
  1182. #endif //CSC_ON_NT
  1183. #ifdef CSC_ON_NT
  1184. DWORD
  1185. DoNetUseAddForAgent(
  1186. IN LPTSTR lptzShareName,
  1187. IN LPTSTR lptzUseName,
  1188. IN LPTSTR lptzDomainName,
  1189. IN LPTSTR lptzUserName,
  1190. IN LPTSTR lptzPassword,
  1191. IN DWORD dwFlags,
  1192. OUT BOOL *lpfIsDfsConnect
  1193. )
  1194. {
  1195. NETRESOURCE sNR;
  1196. memset(&sNR, 0, sizeof(NETRESOURCE));
  1197. sNR.dwType = RESOURCETYPE_DISK;
  1198. sNR.lpRemoteName = lptzShareName;
  1199. sNR.lpLocalName = lptzUseName;
  1200. // return (NPAddConnection3(NULL, &sNR, lptzPassword, lptzUserName, 0));
  1201. try
  1202. {
  1203. return (NPAddConnection3ForCSCAgent(NULL, &sNR, lptzPassword, lptzUserName, dwFlags, lpfIsDfsConnect));
  1204. }
  1205. except(EXCEPTION_EXECUTE_HANDLER)
  1206. {
  1207. ReintKdPrint(BADERRORS, ("Took exception in DoNetUseAddForAgent list \n"));
  1208. return GetLastError();
  1209. }
  1210. }
  1211. DWORD
  1212. PRIVATE
  1213. DWConnectNet(
  1214. _TCHAR *lpServerPath,
  1215. _TCHAR *lpOutDrive,
  1216. _TCHAR *lpDomainName,
  1217. _TCHAR *lpUserName,
  1218. _TCHAR *lpPassword,
  1219. DWORD dwFlags,
  1220. OUT BOOL *lpfIsDfsConnect
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Arguments:
  1225. Returns:
  1226. Notes:
  1227. --*/
  1228. {
  1229. DWORD dwError;
  1230. BOOL fIsDfsConnect = FALSE;
  1231. lpOutDrive[0]='E';
  1232. lpOutDrive[1]=':';
  1233. lpOutDrive[2]=0;
  1234. do{
  1235. if(lpOutDrive[0]=='Z') {
  1236. break;
  1237. }
  1238. if ((dwError =
  1239. DoNetUseAddForAgent(lpServerPath, lpOutDrive, lpDomainName, lpUserName, lpPassword, dwFlags, &fIsDfsConnect))
  1240. ==WN_SUCCESS){
  1241. if (lpfIsDfsConnect)
  1242. {
  1243. *lpfIsDfsConnect = fIsDfsConnect;
  1244. }
  1245. break;
  1246. }
  1247. else if ((dwError == WN_BAD_LOCALNAME)||
  1248. (dwError == WN_ALREADY_CONNECTED)){
  1249. ++lpOutDrive[0];
  1250. continue;
  1251. }
  1252. else{
  1253. break;
  1254. }
  1255. }
  1256. while (TRUE);
  1257. return (dwError);
  1258. }
  1259. DWORD DWDisconnectDriveMappedNet(
  1260. LPTSTR lptzDrive,
  1261. BOOL fForce
  1262. )
  1263. {
  1264. Assert(lptzDrive);
  1265. try
  1266. {
  1267. return NPCancelConnectionForCSCAgent(lptzDrive, fForce);
  1268. }
  1269. except(EXCEPTION_EXECUTE_HANDLER)
  1270. {
  1271. ReintKdPrint(BADERRORS, ("Took exception in DWDisconnectDriveMappedNet list \n"));
  1272. return GetLastError();
  1273. }
  1274. }
  1275. ULONG
  1276. BaseSetLastNTError(
  1277. IN NTSTATUS Status
  1278. )
  1279. /*++
  1280. Routine Description:
  1281. This API sets the "last error value" and the "last error string"
  1282. based on the value of Status. For status codes that don't have
  1283. a corresponding error string, the string is set to null.
  1284. Arguments:
  1285. Status - Supplies the status value to store as the last error value.
  1286. Return Value:
  1287. The corresponding Win32 error code that was stored in the
  1288. "last error value" thread variable.
  1289. --*/
  1290. {
  1291. ULONG dwErrorCode;
  1292. dwErrorCode = RtlNtStatusToDosError( Status );
  1293. SetLastError( dwErrorCode );
  1294. return( dwErrorCode );
  1295. }
  1296. BOOL
  1297. GetWin32InfoForNT(
  1298. _TCHAR * lpFile,
  1299. LPWIN32_FIND_DATA lpFW32
  1300. )
  1301. /*++
  1302. Arguments:
  1303. lpFileName - Supplies the file name of the file to find. The file name
  1304. may contain the DOS wild card characters '*' and '?'.
  1305. lpFindFileData - Supplies a pointer whose type is dependent on the value
  1306. of fInfoLevelId. This buffer returns the appropriate file data.
  1307. Return Value:
  1308. --*/
  1309. {
  1310. HANDLE hFindFile = 0;
  1311. NTSTATUS Status;
  1312. OBJECT_ATTRIBUTES Obja;
  1313. UNICODE_STRING FileName, *pFileName;
  1314. UNICODE_STRING PathName;
  1315. IO_STATUS_BLOCK IoStatusBlock;
  1316. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  1317. struct SEARCH_BUFFER {
  1318. union
  1319. {
  1320. FILE_BOTH_DIR_INFORMATION DirInfo;
  1321. FILE_BASIC_INFORMATION BasicInfo;
  1322. };
  1323. WCHAR Names[MAX_PATH];
  1324. } Buffer;
  1325. BOOLEAN TranslationStatus, fRet = FALSE;
  1326. PVOID FreeBuffer = NULL;
  1327. BOOLEAN EndsInDot;
  1328. LPWIN32_FIND_DATAW FindFileData;
  1329. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  1330. ULONG EaBufferSize = 0;
  1331. FindFileData = lpFW32;
  1332. #if 0
  1333. if (!AllocateEaBuffer(&EaBuffer, &EaBufferSize))
  1334. {
  1335. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1336. return FALSE;
  1337. }
  1338. #endif
  1339. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1340. lpFile,
  1341. &PathName,
  1342. &FileName.Buffer,
  1343. NULL
  1344. );
  1345. if ( !TranslationStatus) {
  1346. SetLastError(ERROR_PATH_NOT_FOUND);
  1347. goto bailout;
  1348. }
  1349. FreeBuffer = PathName.Buffer;
  1350. //
  1351. // If there is a a file portion of this name, determine the length
  1352. // of the name for a subsequent call to NtQueryDirectoryFile.
  1353. //
  1354. if (FileName.Buffer) {
  1355. FileName.Length =
  1356. PathName.Length - (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
  1357. PathName.Length -= (FileName.Length);
  1358. PathName.MaximumLength -= (FileName.Length);
  1359. pFileName = &FileName;
  1360. FileName.MaximumLength = FileName.Length;
  1361. } else {
  1362. pFileName = NULL;
  1363. }
  1364. InitializeObjectAttributes(
  1365. &Obja,
  1366. &PathName,
  1367. 0,
  1368. NULL,
  1369. NULL
  1370. );
  1371. if (pFileName)
  1372. {
  1373. Status = NtCreateFile(
  1374. &hFindFile,
  1375. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  1376. &Obja,
  1377. &IoStatusBlock,
  1378. NULL,
  1379. FILE_ATTRIBUTE_NORMAL,
  1380. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1381. FILE_OPEN,
  1382. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  1383. EaBuffer,
  1384. EaBufferSize
  1385. );
  1386. if ( !NT_SUCCESS(Status) ) {
  1387. ReintKdPrint(ALWAYS, ("GetWin32InfoForNT Failed Status=%x\n", Status));
  1388. BaseSetLastNTError(Status);
  1389. goto bailout;
  1390. }
  1391. //
  1392. // If there is no file part, but we are not looking at a device,
  1393. // then bail.
  1394. //
  1395. DirectoryInfo = &Buffer.DirInfo;
  1396. Status = NtQueryDirectoryFile(
  1397. hFindFile,
  1398. NULL,
  1399. NULL,
  1400. NULL,
  1401. &IoStatusBlock,
  1402. DirectoryInfo,
  1403. sizeof(Buffer),
  1404. FileBothDirectoryInformation,
  1405. TRUE,
  1406. pFileName,
  1407. FALSE
  1408. );
  1409. if ( !NT_SUCCESS(Status) ) {
  1410. ReintKdPrint(ALWAYS, ("Failed Status=%x\n", Status));
  1411. BaseSetLastNTError(Status);
  1412. goto bailout;
  1413. }
  1414. //
  1415. // Attributes are composed of the attributes returned by NT.
  1416. //
  1417. FindFileData->dwFileAttributes = DirectoryInfo->FileAttributes;
  1418. FindFileData->ftCreationTime = *(LPFILETIME)&DirectoryInfo->CreationTime;
  1419. FindFileData->ftLastAccessTime = *(LPFILETIME)&DirectoryInfo->LastAccessTime;
  1420. FindFileData->ftLastWriteTime = *(LPFILETIME)&DirectoryInfo->LastWriteTime;
  1421. FindFileData->nFileSizeHigh = DirectoryInfo->EndOfFile.HighPart;
  1422. FindFileData->nFileSizeLow = DirectoryInfo->EndOfFile.LowPart;
  1423. RtlMoveMemory( FindFileData->cFileName,
  1424. DirectoryInfo->FileName,
  1425. DirectoryInfo->FileNameLength );
  1426. FindFileData->cFileName[DirectoryInfo->FileNameLength >> 1] = UNICODE_NULL;
  1427. RtlMoveMemory( FindFileData->cAlternateFileName,
  1428. DirectoryInfo->ShortName,
  1429. DirectoryInfo->ShortNameLength );
  1430. FindFileData->cAlternateFileName[DirectoryInfo->ShortNameLength >> 1] = UNICODE_NULL;
  1431. //
  1432. // For NTFS reparse points we return the reparse point data tag in dwReserved0.
  1433. //
  1434. if ( DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
  1435. FindFileData->dwReserved0 = DirectoryInfo->EaSize;
  1436. }
  1437. fRet = TRUE;
  1438. }
  1439. else
  1440. {
  1441. Status = NtOpenFile(
  1442. &hFindFile,
  1443. FILE_LIST_DIRECTORY| FILE_READ_EA | FILE_READ_ATTRIBUTES,
  1444. &Obja,
  1445. &IoStatusBlock,
  1446. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1447. FILE_DIRECTORY_FILE
  1448. );
  1449. if ( !NT_SUCCESS(Status) ) {
  1450. ReintKdPrint(ALWAYS, ("GetWin32InfoForNT Failed Status=%x\n", Status));
  1451. BaseSetLastNTError(Status);
  1452. goto bailout;
  1453. }
  1454. Buffer.BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1455. Status = NtQueryInformationFile(
  1456. hFindFile,
  1457. &IoStatusBlock,
  1458. (PVOID)&Buffer.BasicInfo,
  1459. sizeof(Buffer),
  1460. FileBasicInformation
  1461. );
  1462. if ( !NT_SUCCESS(Status) ) {
  1463. ReintKdPrint(ALWAYS, ("GetWin32InfoForNT Failed Status=%x\n", Status));
  1464. BaseSetLastNTError(Status);
  1465. goto bailout;
  1466. }
  1467. FindFileData->dwFileAttributes = Buffer.BasicInfo.FileAttributes;
  1468. FindFileData->ftCreationTime = *(LPFILETIME)&Buffer.BasicInfo.CreationTime;
  1469. FindFileData->ftLastAccessTime = *(LPFILETIME)&Buffer.BasicInfo.LastAccessTime;
  1470. FindFileData->ftLastWriteTime = *(LPFILETIME)&Buffer.BasicInfo.LastWriteTime;
  1471. FindFileData->nFileSizeHigh = 0;
  1472. FindFileData->nFileSizeLow = 0;
  1473. lstrcpy(FindFileData->cFileName, lpFile);
  1474. FindFileData->cAlternateFileName[0] = UNICODE_NULL;
  1475. fRet = TRUE;
  1476. }
  1477. bailout:
  1478. if (FreeBuffer)
  1479. {
  1480. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1481. }
  1482. #if 0
  1483. if (EaBuffer)
  1484. {
  1485. FreeEaBuffer(EaBuffer);
  1486. }
  1487. #endif
  1488. if (hFindFile)
  1489. {
  1490. NtClose(hFindFile);
  1491. }
  1492. return fRet;
  1493. }
  1494. BOOL
  1495. GetConnectionInfoForDriveBasedName(
  1496. _TCHAR * lpName,
  1497. LPDWORD lpdwSpeed
  1498. )
  1499. /*++
  1500. Arguments:
  1501. lpFileName - Supplies the file name of the file to find. The file name
  1502. may contain the DOS wild card characters '*' and '?'.
  1503. lpFindFileData - Supplies a pointer whose type is dependent on the value
  1504. of fInfoLevelId. This buffer returns the appropriate file data.
  1505. Return Value:
  1506. --*/
  1507. {
  1508. HANDLE hFindFile = 0;
  1509. NTSTATUS Status;
  1510. OBJECT_ATTRIBUTES Obja;
  1511. UNICODE_STRING PathName;
  1512. IO_STATUS_BLOCK IoStatusBlock;
  1513. BOOLEAN TranslationStatus, fRet = FALSE;
  1514. LMR_REQUEST_PACKET request;
  1515. PVOID FreeBuffer = NULL;
  1516. USHORT uBuff[4];
  1517. LMR_CONNECTION_INFO_3 ConnectInfo;
  1518. *lpdwSpeed = 0xffffffff;
  1519. if (lstrlen(lpName) <2)
  1520. {
  1521. SetLastError(ERROR_INVALID_PARAMETER);
  1522. return FALSE;
  1523. }
  1524. uBuff[0] = lpName[0];
  1525. uBuff[1] = ':';
  1526. uBuff[2] = '\\';
  1527. uBuff[3] = 0;
  1528. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1529. uBuff,
  1530. &PathName,
  1531. NULL,
  1532. NULL
  1533. );
  1534. if ( !TranslationStatus) {
  1535. SetLastError(ERROR_PATH_NOT_FOUND);
  1536. goto bailout;
  1537. }
  1538. FreeBuffer = PathName.Buffer;
  1539. InitializeObjectAttributes(
  1540. &Obja,
  1541. &PathName,
  1542. 0,
  1543. NULL,
  1544. NULL
  1545. );
  1546. Status = NtCreateFile(
  1547. &hFindFile,
  1548. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  1549. &Obja,
  1550. &IoStatusBlock,
  1551. NULL,
  1552. FILE_ATTRIBUTE_NORMAL,
  1553. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1554. FILE_OPEN,
  1555. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  1556. NULL,
  1557. 0
  1558. );
  1559. if ( !NT_SUCCESS(Status) ) {
  1560. ReintKdPrint(ALWAYS, ("Failed Status=%x\n", Status));
  1561. BaseSetLastNTError(Status);
  1562. goto bailout;
  1563. }
  1564. memcpy(&ConnectInfo, EA_NAME_CSCAGENT, sizeof(EA_NAME_CSCAGENT));
  1565. Status = NtFsControlFile(
  1566. hFindFile, // handle
  1567. NULL, // no event
  1568. NULL, // no APC routine
  1569. NULL, // no APC context
  1570. &IoStatusBlock, // I/O stat blk (set)
  1571. FSCTL_LMR_GET_CONNECTION_INFO, // func code
  1572. NULL,
  1573. 0,
  1574. &ConnectInfo,
  1575. sizeof(ConnectInfo));
  1576. if ( !NT_SUCCESS(Status) ) {
  1577. ReintKdPrint(ALWAYS, ("Failed Status=%x\n", Status));
  1578. BaseSetLastNTError(Status);
  1579. goto bailout;
  1580. }
  1581. *lpdwSpeed = ConnectInfo.Throughput * 8 / 100;
  1582. fRet = TRUE;
  1583. bailout:
  1584. if (FreeBuffer)
  1585. {
  1586. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1587. }
  1588. if (hFindFile)
  1589. {
  1590. NtClose(hFindFile);
  1591. }
  1592. return fRet;
  1593. }
  1594. BOOL
  1595. ReportTransitionToDfs(
  1596. _TCHAR *lptServerName,
  1597. BOOL fOffline,
  1598. DWORD cbLen
  1599. )
  1600. /*++
  1601. Routine Description:
  1602. Parameters:
  1603. Return Value:
  1604. Notes:
  1605. --*/
  1606. {
  1607. ULONG DummyBytesReturned;
  1608. BOOL fRet=FALSE;
  1609. HANDLE hDFS;
  1610. PFILE_FULL_EA_INFORMATION eaBuffer = NULL;
  1611. ULONG eaLength = 0;
  1612. NTSTATUS status;
  1613. OBJECT_ATTRIBUTES objectAttributes;
  1614. IO_STATUS_BLOCK ioStatus;
  1615. PUNICODE_STRING name;
  1616. ACCESS_MASK DesiredAccess;
  1617. if (lptServerName)
  1618. {
  1619. if (cbLen == 0xffffffff)
  1620. {
  1621. cbLen = lstrlen(lptServerName) * sizeof(_TCHAR);
  1622. }
  1623. }
  1624. else
  1625. {
  1626. cbLen = 0;
  1627. }
  1628. name = &DfsDriverObjectName;
  1629. InitializeObjectAttributes(
  1630. &objectAttributes,
  1631. name,
  1632. OBJ_CASE_INSENSITIVE,
  1633. NULL,
  1634. NULL
  1635. );
  1636. //
  1637. // The CSC agent goes offline, and we require that the agent be in admin
  1638. // or system mode, to avoid a non-privileged user from causing us to go
  1639. // offline.
  1640. // To go back online, the check is less stringent, since the online
  1641. // transition is more of a hint and causing an incorrect online
  1642. // indication does not cause wrong results.
  1643. //
  1644. DesiredAccess = (fOffline) ? FILE_WRITE_DATA : 0;
  1645. status = NtCreateFile(
  1646. &hDFS,
  1647. SYNCHRONIZE | DesiredAccess,
  1648. &objectAttributes,
  1649. &ioStatus,
  1650. NULL,
  1651. FILE_ATTRIBUTE_NORMAL,
  1652. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1653. FILE_OPEN_IF,
  1654. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  1655. eaBuffer,
  1656. eaLength
  1657. );
  1658. if (NT_SUCCESS(status))
  1659. {
  1660. status = NtFsControlFile(
  1661. hDFS,
  1662. NULL, // Event,
  1663. NULL, // ApcRoutine,
  1664. NULL, // ApcContext,
  1665. &ioStatus,
  1666. (fOffline)?FSCTL_DFS_CSC_SERVER_OFFLINE:FSCTL_DFS_CSC_SERVER_ONLINE,
  1667. (LPVOID)(lptServerName),
  1668. cbLen,
  1669. NULL,
  1670. 0);
  1671. CloseHandle(hDFS);
  1672. if (NT_SUCCESS(status))
  1673. {
  1674. fRet = TRUE;
  1675. }
  1676. }
  1677. if (!fRet)
  1678. {
  1679. ReintKdPrint(BADERRORS, ("ReportTransitionToDfs failed, Status %x\n", status));
  1680. }
  1681. return fRet;
  1682. }
  1683. BOOL
  1684. UncPathToDfsPath(
  1685. PWCHAR UncPath,
  1686. PWCHAR DfsPath,
  1687. ULONG cbLen)
  1688. {
  1689. BOOL fRet = FALSE;
  1690. HANDLE hDfs;
  1691. NTSTATUS NtStatus;
  1692. OBJECT_ATTRIBUTES ObjectAttributes;
  1693. IO_STATUS_BLOCK IoStatus;
  1694. if (UncPath == NULL)
  1695. goto AllDone;
  1696. InitializeObjectAttributes(
  1697. &ObjectAttributes,
  1698. &DfsDriverObjectName,
  1699. OBJ_CASE_INSENSITIVE,
  1700. NULL,
  1701. NULL);
  1702. NtStatus = NtCreateFile(
  1703. &hDfs,
  1704. SYNCHRONIZE,
  1705. &ObjectAttributes,
  1706. &IoStatus,
  1707. NULL,
  1708. FILE_ATTRIBUTE_NORMAL,
  1709. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1710. FILE_OPEN_IF,
  1711. FILE_CREATE_TREE_CONNECTION | FILE_SYNCHRONOUS_IO_NONALERT,
  1712. NULL,
  1713. 0);
  1714. if (NT_SUCCESS(NtStatus)) {
  1715. NtStatus = NtFsControlFile(
  1716. hDfs,
  1717. NULL, // Event,
  1718. NULL, // ApcRoutine,
  1719. NULL, // ApcContext,
  1720. &IoStatus,
  1721. FSCTL_DFS_GET_SERVER_NAME,
  1722. (PVOID)UncPath,
  1723. wcslen(UncPath) * sizeof(WCHAR),
  1724. (PVOID)DfsPath,
  1725. cbLen);
  1726. CloseHandle(hDfs);
  1727. if (NT_SUCCESS(NtStatus))
  1728. fRet = TRUE;
  1729. }
  1730. AllDone:
  1731. return fRet;
  1732. }
  1733. #else // CSC_ON_NT is not TRUE
  1734. BOOL
  1735. GetWin32InfoForNT(
  1736. _TCHAR * lpFile,
  1737. LPWIN32_FIND_DATA lpFW32
  1738. )
  1739. {
  1740. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1741. return FALSE;
  1742. }
  1743. #endif
  1744. #if 0
  1745. #ifdef CSC_ON_NT
  1746. #define ROUND_UP_COUNT(Count,Pow2) \
  1747. ( ((Count)+(Pow2)-1) & (~((Pow2)-1)) )
  1748. #define ALIGN_WCHAR sizeof(WCHAR)
  1749. // need to include ntxxx.h where the ea is defined
  1750. #define EA_NAME_CSCAGENT "CscAgent"
  1751. ULONG
  1752. BaseSetLastNTError(
  1753. IN NTSTATUS Status
  1754. )
  1755. /*++
  1756. Routine Description:
  1757. This API sets the "last error value" and the "last error string"
  1758. based on the value of Status. For status codes that don't have
  1759. a corresponding error string, the string is set to null.
  1760. Arguments:
  1761. Status - Supplies the status value to store as the last error value.
  1762. Return Value:
  1763. The corresponding Win32 error code that was stored in the
  1764. "last error value" thread variable.
  1765. --*/
  1766. {
  1767. ULONG dwErrorCode;
  1768. dwErrorCode = RtlNtStatusToDosError( Status );
  1769. SetLastError( dwErrorCode );
  1770. return( dwErrorCode );
  1771. }
  1772. BOOL
  1773. AllocateEaBuffer(
  1774. PFILE_FULL_EA_INFORMATION *ppEa,
  1775. ULONG *pEaLength
  1776. )
  1777. {
  1778. FILE_ALLOCATION_INFORMATION AllocationInfo;
  1779. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  1780. ULONG EaBufferSize = 0;
  1781. UCHAR CscAgentEaNameSize;
  1782. DWORD CscAgentEaValue = 0;
  1783. CscAgentEaNameSize = (UCHAR)ROUND_UP_COUNT(
  1784. strlen(EA_NAME_CSCAGENT) +
  1785. sizeof(CHAR),
  1786. ALIGN_WCHAR
  1787. ) - sizeof(CHAR);
  1788. EaBufferSize += FIELD_OFFSET( FILE_FULL_EA_INFORMATION, EaName[0]) +
  1789. CscAgentEaNameSize + sizeof(CHAR) +
  1790. sizeof(CscAgentEaValue);
  1791. EaBuffer = RtlAllocateHeap(
  1792. RtlProcessHeap(),
  1793. 0,
  1794. EaBufferSize);
  1795. memset(EaBuffer, 0, EaBufferSize);
  1796. if (EaBuffer == NULL) {
  1797. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1798. return FALSE;
  1799. }
  1800. strcpy((LPSTR) EaBuffer->EaName, EA_NAME_CSCAGENT);
  1801. EaBuffer->EaNameLength = CscAgentEaNameSize;
  1802. EaBuffer->EaValueLength = sizeof(CscAgentEaValue);
  1803. RtlCopyMemory(
  1804. &EaBuffer->EaName[CscAgentEaNameSize],
  1805. &CscAgentEaValue,
  1806. sizeof(CscAgentEaValue));
  1807. *ppEa = EaBuffer;
  1808. *pEaLength = EaBufferSize;
  1809. return TRUE;
  1810. }
  1811. VOID
  1812. FreeEaBuffer(
  1813. PFILE_FULL_EA_INFORMATION pEa
  1814. )
  1815. {
  1816. RtlFreeHeap(RtlProcessHeap(), 0, pEa);
  1817. }
  1818. BOOL
  1819. CreateFileForAgent(
  1820. PHANDLE h,
  1821. PCWSTR lpFileName,
  1822. ULONG dwDesiredAccess,
  1823. ULONG dwFlagsAndAttributes,
  1824. ULONG dwShareMode,
  1825. ULONG CreateDisposition,
  1826. ULONG CreateFlags
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. This routine opens/creates a file/directory for "only" on the server. The redir
  1831. triggers off of the extended attribute that is sent down to it by this call.
  1832. Arguments:
  1833. None.
  1834. Return Value:
  1835. NTSTATUS - STATUS_SUCCESS or reason for failure.
  1836. --*/
  1837. {
  1838. NTSTATUS Status;
  1839. OBJECT_ATTRIBUTES Obja;
  1840. UNICODE_STRING FileName;
  1841. IO_STATUS_BLOCK IoStatusBlock;
  1842. BOOLEAN TranslationStatus, fRet=FALSE;
  1843. PVOID FreeBuffer=NULL;
  1844. FILE_ALLOCATION_INFORMATION AllocationInfo;
  1845. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  1846. ULONG EaBufferSize = 0;
  1847. if (!AllocateEaBuffer(&EaBuffer, &EaBufferSize))
  1848. {
  1849. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1850. return FALSE;
  1851. }
  1852. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1853. lpFileName,
  1854. &FileName,
  1855. NULL,
  1856. NULL
  1857. );
  1858. if ( !TranslationStatus ) {
  1859. SetLastError(ERROR_INVALID_PARAMETER);
  1860. goto bailout;
  1861. }
  1862. FreeBuffer = FileName.Buffer;
  1863. InitializeObjectAttributes(
  1864. &Obja,
  1865. &FileName,
  1866. OBJ_CASE_INSENSITIVE,
  1867. NULL,
  1868. NULL
  1869. );
  1870. Status = NtCreateFile(
  1871. h,
  1872. (ACCESS_MASK)dwDesiredAccess | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  1873. &Obja,
  1874. &IoStatusBlock,
  1875. NULL,
  1876. dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS),
  1877. dwShareMode,
  1878. CreateDisposition,
  1879. CreateFlags,
  1880. EaBuffer,
  1881. EaBufferSize
  1882. );
  1883. if (Status != STATUS_SUCCESS)
  1884. {
  1885. Assert(fRet == FALSE);
  1886. BaseSetLastNTError(Status);
  1887. }
  1888. else
  1889. {
  1890. fRet = TRUE;
  1891. }
  1892. bailout:
  1893. if (FreeBuffer)
  1894. {
  1895. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  1896. }
  1897. if (EaBuffer)
  1898. {
  1899. FreeEaBuffer(EaBuffer);
  1900. }
  1901. return (fRet);
  1902. }
  1903. BOOL
  1904. AgentDeleteFile(
  1905. PCWSTR lpFileName,
  1906. BOOL fFile
  1907. )
  1908. {
  1909. HANDLE hFile;
  1910. FILE_DISPOSITION_INFORMATION Disposition;
  1911. IO_STATUS_BLOCK IoStatus;
  1912. NTSTATUS Status;
  1913. BOOL fRet = FALSE;
  1914. if (CreateFileForAgent(
  1915. &hFile,
  1916. lpFileName,
  1917. (ACCESS_MASK)DELETE | FILE_READ_ATTRIBUTES,
  1918. FILE_ATTRIBUTE_NORMAL,
  1919. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1920. FILE_OPEN,
  1921. (fFile)?FILE_NON_DIRECTORY_FILE:FILE_DIRECTORY_FILE
  1922. ))
  1923. {
  1924. #undef DeleteFile
  1925. Disposition.DeleteFile = TRUE;
  1926. #define DeleteFile DeleteFileW
  1927. Status = NtSetInformationFile(
  1928. hFile,
  1929. &IoStatus,
  1930. &Disposition,
  1931. sizeof(Disposition),
  1932. FileDispositionInformation
  1933. );
  1934. NtClose(hFile);
  1935. if (Status == STATUS_SUCCESS)
  1936. {
  1937. fRet = TRUE;
  1938. }
  1939. else
  1940. {
  1941. Assert(fRet == FALSE);
  1942. BaseSetLastNTError(Status);
  1943. }
  1944. }
  1945. return fRet;
  1946. }
  1947. BOOL
  1948. AgentSetFileInformation(
  1949. PCWSTR lpFileName,
  1950. DWORD *lpdwFileAttributes,
  1951. FILETIME *lpftLastWriteTime,
  1952. BOOL fFile
  1953. )
  1954. {
  1955. NTSTATUS Status;
  1956. BOOL fRet = FALSE;
  1957. IO_STATUS_BLOCK IoStatus;
  1958. FILE_BASIC_INFORMATION sFileBasicInformation;
  1959. HANDLE hFile;
  1960. if (!CreateFileForAgent(
  1961. &hFile,
  1962. lpFileName,
  1963. (ACCESS_MASK)FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
  1964. FILE_ATTRIBUTE_NORMAL,
  1965. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1966. FILE_OPEN,
  1967. (fFile)?FILE_NON_DIRECTORY_FILE:FILE_DIRECTORY_FILE))
  1968. {
  1969. return FALSE;
  1970. }
  1971. Status = NtQueryInformationFile(
  1972. hFile,
  1973. &IoStatus,
  1974. (PVOID) &sFileBasicInformation,
  1975. sizeof(sFileBasicInformation),
  1976. FileBasicInformation
  1977. );
  1978. if (Status == STATUS_SUCCESS)
  1979. {
  1980. if (lpdwFileAttributes)
  1981. {
  1982. sFileBasicInformation.FileAttributes = *lpdwFileAttributes;
  1983. }
  1984. if (lpftLastWriteTime)
  1985. {
  1986. sFileBasicInformation.LastWriteTime = *(LARGE_INTEGER *)lpftLastWriteTime;
  1987. }
  1988. Status = NtSetInformationFile(
  1989. hFile,
  1990. &IoStatus,
  1991. (PVOID) &sFileBasicInformation,
  1992. sizeof(sFileBasicInformation),
  1993. FileBasicInformation
  1994. );
  1995. }
  1996. NtClose(hFile);
  1997. if (Status == STATUS_SUCCESS)
  1998. {
  1999. fRet = TRUE;
  2000. }
  2001. else
  2002. {
  2003. Assert(fRet == FALSE);
  2004. BaseSetLastNTError(Status);
  2005. }
  2006. return fRet;
  2007. }
  2008. BOOL
  2009. AgentRenameFile(
  2010. _TCHAR *lpFileSrc,
  2011. _TCHAR *lpFileDst
  2012. )
  2013. {
  2014. HANDLE hFile;
  2015. char chBuff[sizeof(FILE_RENAME_INFORMATION) + (MAX_PATH+1) * sizeof(_TCHAR)];
  2016. PFILE_RENAME_INFORMATION pFileRenameInformation;
  2017. IO_STATUS_BLOCK IoStatus;
  2018. NTSTATUS Status;
  2019. BOOL fRet = FALSE;
  2020. memset(chBuff, 0, sizeof(chBuff));
  2021. pFileRenameInformation = (PFILE_RENAME_INFORMATION)chBuff;
  2022. pFileRenameInformation->FileNameLength = lstrlen(lpFileDst) * sizeof(_TCHAR);
  2023. if (pFileRenameInformation->FileNameLength > MAX_PATH * sizeof(_TCHAR))
  2024. {
  2025. SetLastError(ERROR_INVALID_PARAMETER);
  2026. return FALSE;
  2027. }
  2028. pFileRenameInformation->ReplaceIfExists = TRUE;
  2029. memcpy(pFileRenameInformation->FileName, lpFileDst, pFileRenameInformation->FileNameLength);
  2030. if (CreateFileForAgent(
  2031. &hFile,
  2032. lpFileSrc,
  2033. (ACCESS_MASK)DELETE | FILE_READ_ATTRIBUTES,
  2034. FILE_ATTRIBUTE_NORMAL,
  2035. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  2036. FILE_OPEN,
  2037. FILE_NON_DIRECTORY_FILE
  2038. ))
  2039. {
  2040. Status = NtSetInformationFile(
  2041. hFile,
  2042. &IoStatus,
  2043. pFileRenameInformation,
  2044. sizeof(chBuff),
  2045. FileRenameInformation
  2046. );
  2047. NtClose(hFile);
  2048. if (Status == STATUS_SUCCESS)
  2049. {
  2050. fRet = TRUE;
  2051. }
  2052. else
  2053. {
  2054. Assert(fRet == FALSE);
  2055. BaseSetLastNTError(Status);
  2056. }
  2057. }
  2058. return fRet;
  2059. }
  2060. BOOL
  2061. GetWin32Info(
  2062. _TCHAR * lpFile,
  2063. LPWIN32_FIND_DATA lpFW32
  2064. )
  2065. /*++
  2066. Arguments:
  2067. lpFileName - Supplies the file name of the file to find. The file name
  2068. may contain the DOS wild card characters '*' and '?'.
  2069. lpFindFileData - Supplies a pointer whose type is dependent on the value
  2070. of fInfoLevelId. This buffer returns the appropriate file data.
  2071. Return Value:
  2072. --*/
  2073. {
  2074. HANDLE hFindFile = 0;
  2075. NTSTATUS Status;
  2076. OBJECT_ATTRIBUTES Obja;
  2077. UNICODE_STRING FileName, *pFileName;
  2078. UNICODE_STRING PathName;
  2079. IO_STATUS_BLOCK IoStatusBlock;
  2080. PFILE_BOTH_DIR_INFORMATION DirectoryInfo;
  2081. struct SEARCH_BUFFER {
  2082. FILE_BOTH_DIR_INFORMATION DirInfo;
  2083. WCHAR Names[MAX_PATH];
  2084. } Buffer;
  2085. BOOLEAN TranslationStatus, fRet = FALSE;
  2086. PVOID FreeBuffer = NULL;
  2087. BOOLEAN EndsInDot;
  2088. LPWIN32_FIND_DATAW FindFileData;
  2089. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  2090. ULONG EaBufferSize = 0;
  2091. FindFileData = lpFW32;
  2092. if (!AllocateEaBuffer(&EaBuffer, &EaBufferSize))
  2093. {
  2094. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2095. return FALSE;
  2096. }
  2097. TranslationStatus = RtlDosPathNameToNtPathName_U(
  2098. lpFile,
  2099. &PathName,
  2100. &FileName.Buffer,
  2101. NULL
  2102. );
  2103. if ( !TranslationStatus) {
  2104. SetLastError(ERROR_PATH_NOT_FOUND);
  2105. goto bailout;
  2106. }
  2107. FreeBuffer = PathName.Buffer;
  2108. //
  2109. // If there is a a file portion of this name, determine the length
  2110. // of the name for a subsequent call to NtQueryDirectoryFile.
  2111. //
  2112. if (FileName.Buffer) {
  2113. FileName.Length =
  2114. PathName.Length - (USHORT)((ULONG_PTR)FileName.Buffer - (ULONG_PTR)PathName.Buffer);
  2115. PathName.Length -= (FileName.Length+sizeof(WCHAR));
  2116. PathName.MaximumLength -= (FileName.Length+sizeof(WCHAR));
  2117. pFileName = &FileName;
  2118. FileName.MaximumLength = FileName.Length;
  2119. } else {
  2120. pFileName = NULL;
  2121. }
  2122. InitializeObjectAttributes(
  2123. &Obja,
  2124. &PathName,
  2125. 0,
  2126. NULL,
  2127. NULL
  2128. );
  2129. Status = NtCreateFile(
  2130. &hFindFile,
  2131. SYNCHRONIZE | FILE_LIST_DIRECTORY,
  2132. &Obja,
  2133. &IoStatusBlock,
  2134. NULL,
  2135. FILE_ATTRIBUTE_NORMAL,
  2136. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2137. FILE_OPEN,
  2138. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
  2139. EaBuffer,
  2140. EaBufferSize
  2141. );
  2142. if ( !NT_SUCCESS(Status) ) {
  2143. BaseSetLastNTError(Status);
  2144. goto bailout;
  2145. }
  2146. //
  2147. // If there is no file part, but we are not looking at a device,
  2148. // then bail.
  2149. //
  2150. DirectoryInfo = &Buffer.DirInfo;
  2151. if (pFileName)
  2152. {
  2153. Status = NtQueryDirectoryFile(
  2154. hFindFile,
  2155. NULL,
  2156. NULL,
  2157. NULL,
  2158. &IoStatusBlock,
  2159. DirectoryInfo,
  2160. sizeof(Buffer),
  2161. FileBothDirectoryInformation,
  2162. TRUE,
  2163. pFileName,
  2164. FALSE
  2165. );
  2166. }
  2167. else
  2168. {
  2169. Status = NtQueryInformationFile(
  2170. hFindFile,
  2171. &IoStatusBlock,
  2172. DirectoryInfo,
  2173. sizeof(Buffer),
  2174. FileBothDirectoryInformation,
  2175. );
  2176. }
  2177. if ( !NT_SUCCESS(Status) ) {
  2178. BaseSetLastNTError(Status);
  2179. goto bailout;
  2180. }
  2181. //
  2182. // Attributes are composed of the attributes returned by NT.
  2183. //
  2184. FindFileData->dwFileAttributes = DirectoryInfo->FileAttributes;
  2185. FindFileData->ftCreationTime = *(LPFILETIME)&DirectoryInfo->CreationTime;
  2186. FindFileData->ftLastAccessTime = *(LPFILETIME)&DirectoryInfo->LastAccessTime;
  2187. FindFileData->ftLastWriteTime = *(LPFILETIME)&DirectoryInfo->LastWriteTime;
  2188. FindFileData->nFileSizeHigh = DirectoryInfo->EndOfFile.HighPart;
  2189. FindFileData->nFileSizeLow = DirectoryInfo->EndOfFile.LowPart;
  2190. RtlMoveMemory( FindFileData->cFileName,
  2191. DirectoryInfo->FileName,
  2192. DirectoryInfo->FileNameLength );
  2193. FindFileData->cFileName[DirectoryInfo->FileNameLength >> 1] = UNICODE_NULL;
  2194. RtlMoveMemory( FindFileData->cAlternateFileName,
  2195. DirectoryInfo->ShortName,
  2196. DirectoryInfo->ShortNameLength );
  2197. FindFileData->cAlternateFileName[DirectoryInfo->ShortNameLength >> 1] = UNICODE_NULL;
  2198. //
  2199. // For NTFS reparse points we return the reparse point data tag in dwReserved0.
  2200. //
  2201. if ( DirectoryInfo->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
  2202. FindFileData->dwReserved0 = DirectoryInfo->EaSize;
  2203. }
  2204. fRet = TRUE;
  2205. bailout:
  2206. if (FreeBuffer)
  2207. {
  2208. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  2209. }
  2210. if (EaBuffer)
  2211. {
  2212. FreeEaBuffer(EaBuffer);
  2213. }
  2214. if (hFindFile)
  2215. {
  2216. NtClose(hFindFile);
  2217. }
  2218. return fRet;
  2219. }
  2220. BOOL
  2221. AgentGetFileInformation(
  2222. PCWSTR lpFileName,
  2223. DWORD *lpdwFileAttributes,
  2224. FILETIME *lpftLastWriteTime,
  2225. BOOL fFile
  2226. )
  2227. {
  2228. NTSTATUS Status;
  2229. BOOL fRet = FALSE;
  2230. IO_STATUS_BLOCK IoStatus;
  2231. FILE_BASIC_INFORMATION sFileBasicInformation;
  2232. HANDLE hFile;
  2233. if (!CreateFileForAgent(
  2234. &hFile,
  2235. lpFileName,
  2236. (ACCESS_MASK)FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
  2237. FILE_ATTRIBUTE_NORMAL,
  2238. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2239. FILE_OPEN,
  2240. (fFile)?FILE_NON_DIRECTORY_FILE:FILE_DIRECTORY_FILE))
  2241. {
  2242. return FALSE;
  2243. }
  2244. Status = NtQueryInformationFile(
  2245. hFile,
  2246. &IoStatus,
  2247. (PVOID) &sFileBasicInformation,
  2248. sizeof(sFileBasicInformation),
  2249. FileBasicInformation
  2250. );
  2251. if (Status == STATUS_SUCCESS)
  2252. {
  2253. if (lpdwFileAttributes)
  2254. {
  2255. *lpdwFileAttributes = sFileBasicInformation.FileAttributes;
  2256. }
  2257. if (lpftLastWriteTime)
  2258. {
  2259. *(LARGE_INTEGER *)lpftLastWriteTime = sFileBasicInformation.LastWriteTime;
  2260. }
  2261. }
  2262. NtClose(hFile);
  2263. if (Status == STATUS_SUCCESS)
  2264. {
  2265. fRet = TRUE;
  2266. }
  2267. else
  2268. {
  2269. Assert(fRet == FALSE);
  2270. BaseSetLastNTError(Status);
  2271. }
  2272. return fRet;
  2273. }
  2274. DWORD
  2275. PRIVATE
  2276. DoObjectEdit(
  2277. HANDLE hShadowDB,
  2278. _TCHAR * lpDrive,
  2279. LPCOPYPARAMS lpCP,
  2280. LPSHADOWINFO lpSI,
  2281. LPWIN32_FIND_DATA lpFind32Local,
  2282. LPWIN32_FIND_DATA lpFind32Remote,
  2283. int iShadowStatus,
  2284. int iFileStatus,
  2285. int uAction,
  2286. LPCSCPROC lpfnMergeProgress,
  2287. DWORD dwContext
  2288. )
  2289. /*++
  2290. Routine Description:
  2291. Arguments:
  2292. Returns:
  2293. Notes:
  2294. --*/
  2295. {
  2296. HANDLE hfSrc = 0, hfDst = 0;
  2297. HANDLE hDst=0;
  2298. _TCHAR * lpT;
  2299. LONG lOffset=0;
  2300. DWORD dwError=ERROR_REINT_FAILED;
  2301. WIN32_FIND_DATA sFind32Remote;
  2302. DWORD dwTotal = 0, dwRet;
  2303. _TCHAR szSrcName[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10];
  2304. _TCHAR szDstName[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10];
  2305. _TCHAR *lprwBuff = NULL;
  2306. lprwBuff = LocalAlloc(LPTR, FILL_BUF_SIZE_LAN);
  2307. if (!lprwBuff)
  2308. {
  2309. return (ERROR_NOT_ENOUGH_MEMORY);
  2310. }
  2311. lOffset=0;
  2312. // Create \\server\share\foo\00010002 kind of temporary filename
  2313. lstrcpy(szDstName, lpCP->lpServerPath);
  2314. lstrcat(szDstName, lpCP->lpRemotePath);
  2315. lpT = GetLeafPtr(szDstName);
  2316. *lpT = 0; // remove the remote leaf
  2317. lpT = GetLeafPtr(lpCP->lpLocalPath);
  2318. // attach the local leaf
  2319. lstrcat(szDstName, lpT);
  2320. // Let us also create the real name \\server\share\foo\bar
  2321. // we will use this to issue the rename ioctl
  2322. lstrcpy(szSrcName, lpCP->lpServerPath);
  2323. lstrcat(szSrcName, lpCP->lpRemotePath);
  2324. ReintKdPrint(MERGE, ("Reintegrating file %s \r\n", szSrcName));
  2325. if (mShadowDeleted(lpSI->uStatus)){
  2326. ReintKdPrint(MERGE, ("Deleting %s from the share\r\n", szSrcName));
  2327. if (lpFind32Remote)
  2328. {
  2329. if((lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  2330. {
  2331. ReintKdPrint(MERGE, ("DoObjectEdit:attribute conflict on %s \r\n", szSrcName));
  2332. goto bailout;
  2333. }
  2334. if (lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  2335. {
  2336. DWORD dwT = FILE_ATTRIBUTE_NORMAL;
  2337. if(!AgentSetFileInformation(szSrcName, &dwT, NULL, TRUE))
  2338. {
  2339. ReintKdPrint(BADERRORS, ("DoObjectEdit: failed setattribute before delete on %s error=%d\r\n", szSrcName, GetLastError()));
  2340. goto bailout;
  2341. }
  2342. }
  2343. // delete a file
  2344. if(!AgentDeleteFile(szSrcName, TRUE))
  2345. {
  2346. dwError = GetLastError();
  2347. if ((dwError==ERROR_FILE_NOT_FOUND)||
  2348. (dwError==ERROR_PATH_NOT_FOUND)){
  2349. ReintKdPrint(MERGE, ("DoObjectEdit:delete failed %s benign error=%d\r\n", szSrcName, dwError));
  2350. }
  2351. else
  2352. {
  2353. ReintKdPrint(BADERRORS, ("DoObjectEdit:delete failed %s error=%d\r\n", szSrcName, dwError));
  2354. }
  2355. goto bailout;
  2356. }
  2357. }
  2358. ReintKdPrint(MERGE, ("Deleted %s \r\n", szSrcName));
  2359. DeleteShadow(hShadowDB, lpSI->hDir, lpSI->hShadow);
  2360. dwError = NO_ERROR;
  2361. goto bailout;
  2362. }
  2363. if (mShadowDirty(lpSI->uStatus)
  2364. || mShadowLocallyCreated(lpSI->uStatus)){
  2365. ReintKdPrint(MERGE, ("Writing data for %s \r\n", szSrcName));
  2366. hfSrc = CreateFile( lpCP->lpLocalPath,
  2367. GENERIC_READ,
  2368. FILE_SHARE_READ,
  2369. NULL,
  2370. OPEN_EXISTING,
  2371. 0,
  2372. NULL);
  2373. if (hfSrc == INVALID_HANDLE_VALUE)
  2374. {
  2375. ReintKdPrint(BADERRORS, ("DoObjectEdit:failed to open database file %s error=%d\r\n", szDstName, GetLastError()));
  2376. goto bailout;
  2377. }
  2378. if (!CreateFileForAgent(
  2379. &hfDst,
  2380. szDstName,
  2381. GENERIC_READ|GENERIC_WRITE,
  2382. FILE_ATTRIBUTE_NORMAL,
  2383. FILE_SHARE_READ,
  2384. FILE_CREATE,
  2385. FILE_NON_DIRECTORY_FILE))
  2386. {
  2387. ReintKdPrint(BADERRORS, ("DoObjectEdit:failed to create new temp file %s error=%d\r\n", szDstName, GetLastError()));
  2388. goto bailout;
  2389. }
  2390. // let us append
  2391. if((lOffset = SetFilePointer(hfDst, 0, NULL, FILE_END))==0xffffffff) {
  2392. ReintKdPrint(BADERRORS, ("DoObjectEdit:failed to set filepointer on %s error=%d\r\n", szDstName, GetLastError()));
  2393. goto error;
  2394. }
  2395. ReintKdPrint(MERGE, ("Copying back %s to %s%s \r\n"
  2396. , lpCP->lpLocalPath
  2397. , lpCP->lpServerPath
  2398. , lpCP->lpRemotePath
  2399. ));
  2400. lpSI->uStatus &= ~SHADOW_DIRTY;
  2401. SetShadowInfo( hShadowDB, lpSI->hDir, lpSI->hShadow, NULL,
  2402. lpSI->uStatus, SHADOW_FLAGS_ASSIGN);
  2403. do{
  2404. unsigned cbRead;
  2405. if (!ReadFile(hfSrc, lprwBuff, FILL_BUF_SIZE_LAN, &cbRead, NULL)){
  2406. ReintKdPrint(BADERRORS, ("DoObjectEdit:failed to read database file %s error=%d\r\n", szDstName, GetLastError()));
  2407. goto error;
  2408. }
  2409. if (!cbRead) {
  2410. break;
  2411. }
  2412. if(!WriteFile(hfDst, (LPBYTE)lprwBuff, cbRead, &cbRead, NULL)){
  2413. ReintKdPrint(BADERRORS, ("DoObjectEdit:failed to write temp file %s error=%d\r\n", szDstName, GetLastError()));
  2414. goto error;
  2415. }
  2416. dwTotal += cbRead;
  2417. if (lpfnMergeProgress)
  2418. {
  2419. dwRet = (*lpfnMergeProgress)(
  2420. szSrcName,
  2421. lpSI->uStatus,
  2422. lpSI->ulHintFlags,
  2423. lpSI->ulHintPri,
  2424. lpFind32Local,
  2425. CSCPROC_REASON_MORE_DATA,
  2426. cbRead,
  2427. 0,
  2428. dwContext
  2429. );
  2430. if (dwRet != CSCPROC_RETURN_CONTINUE)
  2431. {
  2432. ReintKdPrint(BADERRORS, ("DoObjectEdit: Callback function cancelled the operation\r\n"));
  2433. SetLastError(ERROR_OPERATION_ABORTED);
  2434. goto bailout;
  2435. }
  2436. }
  2437. if (FAbortOperation())
  2438. {
  2439. ReintKdPrint(BADERRORS, ("DoObjectEdit: got an abort command from the redir\r\n"));
  2440. SetLastError(ERROR_OPERATION_ABORTED);
  2441. goto error;
  2442. }
  2443. } while(TRUE);
  2444. CloseHandle(hfSrc);
  2445. hfSrc = 0;
  2446. NtClose(hfDst);
  2447. hfDst = 0;
  2448. // nuke the remote one if it exists
  2449. if (lpFind32Remote){
  2450. DWORD dwT = FILE_ATTRIBUTE_NORMAL;
  2451. if(!AgentSetFileInformation(szSrcName, &dwT, NULL, TRUE)||
  2452. !AgentDeleteFile(szSrcName, TRUE))
  2453. {
  2454. ReintKdPrint(BADERRORS, ("DoObjectEdit: failed to delete file %s error=%d\r\n", szSrcName, GetLastError()));
  2455. goto error;
  2456. }
  2457. }
  2458. if(!AgentRenameFile(szDstName, szSrcName))
  2459. {
  2460. ReintKdPrint(BADERRORS, ("DoObjectEdit: failed to rename file %s to %s error=%d\r\n", szDstName, szSrcName, GetLastError()));
  2461. goto bailout;
  2462. }
  2463. }
  2464. if (mShadowAttribChange(lpSI->uStatus)||mShadowTimeChange(lpSI->uStatus)){
  2465. if(!AgentSetFileInformation(szSrcName, &(lpFind32Local->dwFileAttributes), &(lpFind32Local->ftLastWriteTime), TRUE))
  2466. {
  2467. ReintKdPrint(BADERRORS, ("DoObjectEdit: failed to change attributes on file %s error=%d\r\n", szSrcName, GetLastError()));
  2468. goto bailout;
  2469. }
  2470. }
  2471. // Get the latest timestamps/attributes/LFN/SFN on the file we just copied back
  2472. if (!GetWin32Info(szSrcName, &sFind32Remote)) {
  2473. goto error;
  2474. }
  2475. lpSI->uStatus &= (unsigned long)(~(SHADOW_MODFLAGS));
  2476. SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, &sFind32Remote, lpSI->uStatus, SHADOW_FLAGS_ASSIGN|SHADOW_FLAGS_CHANGE_83NAME);
  2477. dwError = NO_ERROR;
  2478. goto bailout;
  2479. error:
  2480. bailout:
  2481. if (hfSrc) {
  2482. CloseHandle(hfSrc);
  2483. }
  2484. if (hfDst) {
  2485. NtClose(hfDst);
  2486. // if we failed,
  2487. if (dwError != ERROR_SUCCESS)
  2488. {
  2489. DeleteFile(szDstName);
  2490. }
  2491. }
  2492. if (lprwBuff)
  2493. {
  2494. LocalFree(lprwBuff);
  2495. }
  2496. if (dwError == NO_ERROR)
  2497. {
  2498. ReintKdPrint(MERGE, ("Done Reintegration for file %s \r\n", szSrcName));
  2499. }
  2500. else
  2501. {
  2502. dwError = GetLastError();
  2503. ReintKdPrint(MERGE, ("Failed Reintegration for file %s Error = %d\r\n", szSrcName, dwError));
  2504. }
  2505. return (dwError);
  2506. }
  2507. DWORD
  2508. PRIVATE
  2509. DoCreateDir(
  2510. HANDLE hShadowDB,
  2511. _TCHAR * lpDrive,
  2512. LPCOPYPARAMS lpCP,
  2513. LPSHADOWINFO lpSI,
  2514. LPWIN32_FIND_DATA lpFind32Local,
  2515. LPWIN32_FIND_DATA lpFind32Remote,
  2516. int iShadowStatus,
  2517. int iFileStatus,
  2518. int uAction,
  2519. LPCSCPROC lpfnMergeProgress,
  2520. DWORD dwContext
  2521. )
  2522. /*++
  2523. Routine Description:
  2524. Arguments:
  2525. Returns:
  2526. Notes:
  2527. --*/
  2528. {
  2529. DWORD dwError=ERROR_FILE_NOT_FOUND;
  2530. WIN32_FIND_DATA sFind32Remote;
  2531. BOOL fCreateDir = FALSE;
  2532. _TCHAR szSrcName[MAX_PATH+MAX_SERVER_SHARE_NAME_FOR_CSC+10];
  2533. HANDLE hFile;
  2534. // Let us create the real name x:\foo\bar
  2535. lstrcpy(szSrcName, lpCP->lpServerPath);
  2536. lstrcat(szSrcName, lpCP->lpRemotePath);
  2537. ReintKdPrint(MERGE, ("CSC.DoCreateDirectory: Reintegrating directory %s \r\n", szSrcName));
  2538. if(lpFind32Remote &&
  2539. !(lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)){
  2540. if (lpSI->uStatus & SHADOW_REUSED){
  2541. ReintKdPrint(MERGE, ("CSC.DoCreateDirectory: %s is a file on the server, attempting to delete\r\n", szSrcName));
  2542. // we now know that a file by this name has been deleted
  2543. // and a directory has been created in it's place
  2544. // we try to delete the file before creating the directory
  2545. // NB, the other way is not possible because we don't allow directory deletes
  2546. // in disconnected mode
  2547. if (lpFind32Remote->dwFileAttributes & FILE_ATTRIBUTE_READONLY)
  2548. {
  2549. DWORD dwT = FILE_ATTRIBUTE_NORMAL;
  2550. if(!AgentSetFileInformation(szSrcName, &dwT, NULL, TRUE))
  2551. {
  2552. ReintKdPrint(BADERRORS, ("CSC.DoCreateDirectory: failed setattribute before delete on %s error=%d\r\n", szSrcName, GetLastError()));
  2553. goto bailout;
  2554. }
  2555. }
  2556. // delete the remote file before trying to create a directory
  2557. if(!AgentDeleteFile(szSrcName, TRUE))
  2558. {
  2559. dwError = GetLastError();
  2560. if ((dwError==ERROR_FILE_NOT_FOUND)||
  2561. (dwError==ERROR_PATH_NOT_FOUND)){
  2562. ReintKdPrint(MERGE, ("DoCreateDirectory: file delete failed %s benign error=%d\r\n", szSrcName, dwError));
  2563. }
  2564. else
  2565. {
  2566. ReintKdPrint(BADERRORS, ("DoCreateDirectory: file delete failed %s error=%d\r\n", szSrcName, dwError));
  2567. goto bailout;
  2568. }
  2569. }
  2570. }
  2571. if (!CreateFileForAgent(
  2572. &hFile,
  2573. szSrcName,
  2574. (ACCESS_MASK)FILE_READ_ATTRIBUTES|FILE_WRITE_ATTRIBUTES,
  2575. FILE_ATTRIBUTE_NORMAL,
  2576. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2577. FILE_OPEN_IF,
  2578. FILE_DIRECTORY_FILE))
  2579. {
  2580. ReintKdPrint(BADERRORS, ("DoCreateDirectory: failed to create %s error=%d\r\n", szSrcName, GetLastError()));
  2581. goto bailout;
  2582. }
  2583. NtClose(hFile);
  2584. if(!AgentSetFileInformation(szSrcName, &(lpFind32Local->dwFileAttributes), NULL, FALSE))
  2585. {
  2586. ReintKdPrint(BADERRORS, ("DoCreateDirectory: failed to set attributes on %s error=%d\r\n", szSrcName, GetLastError()));
  2587. goto bailout;
  2588. }
  2589. if(!GetWin32Info(szSrcName, &sFind32Remote)){
  2590. ReintKdPrint(BADERRORS, ("DoCreateDirectory: failed to get win32 info for %s error=%d\r\n", szSrcName, GetLastError()));
  2591. goto bailout;
  2592. }
  2593. dwError = NO_ERROR;
  2594. SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, &sFind32Remote, (unsigned)(~SHADOW_MODFLAGS), SHADOW_FLAGS_AND);
  2595. ReintKdPrint(MERGE, ("Created directory %s%s", lpCP->lpServerPath, lpCP->lpRemotePath));
  2596. }
  2597. bailout:
  2598. if (dwError != NO_ERROR)
  2599. {
  2600. dwError = GetLastError();
  2601. ReintKdPrint(MERGE, ("CSC.DoCreateDirectory: Failed Reintegrating directory %s Error = %d \r\n", szSrcName, dwError));
  2602. }
  2603. else
  2604. {
  2605. ReintKdPrint(MERGE, ("CSC.DoCreateDirectory: Done Reintegrating directory %s \r\n", szSrcName));
  2606. }
  2607. return (dwError);
  2608. }
  2609. #endif // ifdef CSC_ON_NT
  2610. #endif // if 0