Source code of Windows XP (NT5)
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.

2966 lines
89 KiB

  1. //*************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation 1998
  4. // All rights reserved
  5. //
  6. // filedb.cxx
  7. //
  8. //*************************************************************
  9. #include "fdeploy.hxx"
  10. #define SAVED_SETTINGS_FILE L"{25537BA6-77A8-11D2-9B6C-0000F8080861}.ini"
  11. HRESULT RsopSidsFromToken(PRSOPTOKEN pRsopToken,
  12. PTOKEN_GROUPS* ppGroups);
  13. FOLDERINFO gUserShellFolders[] =
  14. {
  15. {CSIDL_APPDATA, 17, L"Application Data\\", L"AppData"},
  16. // {CSIDL_COOKIES, 8, L"Cookies\\", L"Cookies"},
  17. {CSIDL_DESKTOPDIRECTORY, 8, L"Desktop\\", L"Desktop"},
  18. {CSIDL_FAVORITES, 10, L"Favorites\\", L"Favorites"},
  19. // {CSIDL_HISTORY, 8, L"History\\", L"History"},
  20. // {0, 15, L"Local Settings\\", NULL}, Has no reg key, no CSIDL
  21. {CSIDL_MYPICTURES, 25, L"My Documents\\My Pictures\\", L"My Pictures"},
  22. {CSIDL_PERSONAL, 13, L"My Documents\\", L"Personal"},
  23. {CSIDL_NETHOOD, 8, L"NetHood\\", L"NetHood"},
  24. {CSIDL_PRINTHOOD, 10, L"PrintHood\\", L"PrintHood"},
  25. // {CSIDL_RECENT, 7, L"Recent\\", L"Recent"},
  26. {CSIDL_SENDTO, 7, L"SendTo\\", L"SendTo"},
  27. {CSIDL_STARTUP, 28, L"Start Menu\\Programs\\Startup\\", L"Startup"},
  28. {CSIDL_PROGRAMS, 20, L"Start Menu\\Programs\\", L"Programs"},
  29. {CSIDL_STARTMENU, 11, L"Start Menu\\", L"Start Menu"},
  30. {CSIDL_TEMPLATES, 10, L"Templates\\", L"Templates"},
  31. // {CSIDL_INTERNET_CACHE, 25, L"Temporary Internet Files\\", L"Cache"},
  32. {0, 0, NULL, NULL }
  33. };
  34. FOLDERINFO gMachineShellFolders[] =
  35. {
  36. {CSIDL_COMMON_APPDATA, 17, L"Application Data\\", L"Common AppData"},
  37. {CSIDL_COMMON_DESKTOPDIRECTORY, 8, L"Desktop\\", L"Common Desktop"},
  38. // {0, 10, L"Documents\\", L"Common Documents\\"}, No shell support
  39. {CSIDL_COMMON_STARTUP, 28, L"Start Menu\\Programs\\Startup\\", L"Common Startup"},
  40. {CSIDL_COMMON_PROGRAMS, 20, L"Start Menu\\Programs\\", L"Common Programs"},
  41. {CSIDL_COMMON_STARTMENU, 11, L"Start Menu\\", L"Common Start Menu"},
  42. {0, 0, NULL, NULL }
  43. };
  44. static DWORD gSchema = 1;
  45. CFileDB::CFileDB()
  46. {
  47. _hUserToken = 0;
  48. _hkRoot = 0;
  49. _pEnvBlock = 0;
  50. _pGroups = 0;
  51. _pwszProfilePath = 0;
  52. _pwszGPTPath = 0;
  53. _GPTPathLen = 0;
  54. _pwszIniFilePath = 0;
  55. _IniFileLen = 0;
  56. _pwszGPOName = 0;
  57. _pwszGPOUniqueName = 0;
  58. _pwszGPOSOMPath = 0;
  59. _pRsopContext = 0;
  60. }
  61. CFileDB::~CFileDB()
  62. {
  63. if ( _pEnvBlock )
  64. DestroyEnvironmentBlock( _pEnvBlock );
  65. if (_pwszProfilePath)
  66. delete _pwszProfilePath;
  67. if (_pwszGPTPath)
  68. delete _pwszGPTPath;
  69. if (_pwszIniFilePath)
  70. delete _pwszIniFilePath;
  71. //
  72. // Note that _pGroups must be freed with LocalFree --
  73. // we are able to free it with delete because we
  74. // have redefined delete to be LocalFree
  75. //
  76. if (_pGroups)
  77. delete (BYTE*) _pGroups;
  78. // _pwszGPOName is not allocated
  79. // _pwszGPOUniqueName is not allocated
  80. // _pwszGPODSPath is not allocated
  81. }
  82. DWORD CFileDB::Initialize (
  83. HANDLE hUserToken,
  84. HKEY hkRoot,
  85. CRsopContext* pRsopContext)
  86. {
  87. BOOL bStatus;
  88. DWORD Status = ERROR_SUCCESS;
  89. ULONG Size;
  90. int CSidl;
  91. WCHAR * pwszSlash;
  92. HRESULT hr;
  93. HANDLE hFind;
  94. WIN32_FIND_DATA FindData;
  95. //set the token
  96. _hUserToken = hUserToken;
  97. //set the root key
  98. _hkRoot = hkRoot;
  99. // set the rsop logging context
  100. _pRsopContext = pRsopContext;
  101. //create an environment block for the user. we need this for expanding
  102. //variables.
  103. if (! _pEnvBlock)
  104. {
  105. if (!CreateEnvironmentBlock ( &_pEnvBlock, _hUserToken, FALSE))
  106. {
  107. Status = GetLastError();
  108. goto InitializeEnd;
  109. }
  110. }
  111. //get the list of group to which the user belongs
  112. _pGroups = 0;
  113. Size = 0;
  114. //
  115. // We may only use the Nt security subsystem api below
  116. // to retrieve groups when we are not in planning mode
  117. //
  118. for (; ! _pRsopContext->IsPlanningModeEnabled() ;)
  119. {
  120. Status = NtQueryInformationToken(
  121. _hUserToken,
  122. TokenGroups,
  123. _pGroups,
  124. Size,
  125. &Size );
  126. if ( STATUS_BUFFER_TOO_SMALL == Status )
  127. {
  128. _pGroups = (PTOKEN_GROUPS) new BYTE [ Size ];
  129. if ( ! _pGroups )
  130. break;
  131. continue;
  132. }
  133. if ( Status != STATUS_SUCCESS )
  134. {
  135. if (_pGroups)
  136. delete [] ((BYTE*) _pGroups);
  137. _pGroups = 0;
  138. }
  139. break;
  140. }
  141. //
  142. // In planning mode, we get our security groups from
  143. // the policy engine's simulated token, not from a real token
  144. //
  145. if ( _pRsopContext->IsPlanningModeEnabled() )
  146. {
  147. DWORD cbSize;
  148. PRSOP_TARGET pRsopTarget;
  149. HRESULT hr;
  150. pRsopTarget = _pRsopContext->_pRsopTarget;
  151. //
  152. // The call below uses RSoP's planning mode "simulated"
  153. // security subsystem to retrieve the sids from the simulated
  154. // token. The function allocates memory in _pGroups that
  155. // must be freed with LocalFree.
  156. //
  157. hr = RsopSidsFromToken(pRsopTarget->pRsopToken, &_pGroups);
  158. Status = HRESULT_CODE(hr);
  159. }
  160. if (ERROR_SUCCESS != Status)
  161. goto InitializeEnd;
  162. //
  163. // Retrieve the local path -- note that we do not need this in planning mode
  164. //
  165. if ( ! _pRsopContext->IsPlanningModeEnabled() )
  166. {
  167. //get the path to our directory under Local Settings.
  168. CSidl = CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE;
  169. hr = SHGetFolderPath( NULL, CSidl, _hUserToken, 0, _pwszLocalPath );
  170. if ( hr != S_OK )
  171. {
  172. //try to get the last error.
  173. if (FACILITY_WIN32 == HRESULT_FACILITY (hr))
  174. {
  175. Status = HRESULT_CODE(hr);
  176. }
  177. else
  178. {
  179. Status = GetLastError();
  180. if (ERROR_SUCCESS == Status)
  181. {
  182. //an error had occurred but nobody called SetLastError
  183. //should not be mistaken as a success.
  184. Status = (DWORD) hr;
  185. }
  186. }
  187. DebugMsg((DM_WARNING, IDS_NO_LOCALAPPDATA, Status));
  188. goto InitializeEnd;
  189. }
  190. pwszSlash = _pwszLocalPath + wcslen( _pwszLocalPath );
  191. wcscat( _pwszLocalPath, L"\\Microsoft\\Windows\\File Deployment" );
  192. Status = ERROR_SUCCESS;
  193. //now create directories as necessary
  194. // Quick check to see if we have necessary local dirs.
  195. hFind = FindFirstFile( _pwszLocalPath, &FindData );
  196. if ( INVALID_HANDLE_VALUE == hFind )
  197. {
  198. do
  199. {
  200. pwszSlash = wcschr( &pwszSlash[1], L'\\' );
  201. if ( pwszSlash )
  202. *pwszSlash = 0;
  203. bStatus = CreateDirectory( _pwszLocalPath, NULL );
  204. if ( ! bStatus && (GetLastError() != ERROR_ALREADY_EXISTS) )
  205. {
  206. Status = GetLastError();
  207. break;
  208. }
  209. if ( pwszSlash )
  210. *pwszSlash = L'\\';
  211. } while ( pwszSlash );
  212. }
  213. else
  214. {
  215. FindClose( hFind );
  216. }
  217. }
  218. InitializeEnd:
  219. return Status;
  220. }
  221. DWORD
  222. CFileDB::Process(
  223. PGROUP_POLICY_OBJECT pGPO,
  224. BOOL bRemove
  225. )
  226. {
  227. WCHAR * pwszGPTIniFilePath;
  228. DWORD Length;
  229. DWORD Status;
  230. DWORD ProcessStatus;
  231. BOOL bStatus;
  232. BOOL bPolicyApplied;
  233. HANDLE hFind;
  234. WIN32_FIND_DATA FindData;
  235. if ( bRemove && _pRsopContext->IsPlanningModeEnabled() )
  236. {
  237. return ERROR_INVALID_PARAMETER;
  238. }
  239. bPolicyApplied = FALSE;
  240. Status = ERROR_SUCCESS;
  241. //first initialize the variables that vary with policies
  242. _bRemove = bRemove;
  243. if ( ! _bRemove )
  244. {
  245. Length = wcslen(pGPO->lpFileSysPath) + wcslen(GPT_SUBDIR) + 1;
  246. if (Length > _GPTPathLen)
  247. {
  248. //we need more memory than has been allocated.
  249. //so get that before proceeding
  250. if (_pwszGPTPath)
  251. delete _pwszGPTPath;
  252. _GPTPathLen = 0; //make sure that this always reflects the correct value
  253. _pwszGPTPath = new WCHAR [Length];
  254. if ( ! _pwszGPTPath )
  255. {
  256. Status = ERROR_OUTOFMEMORY;
  257. goto ProcessEnd;
  258. }
  259. _GPTPathLen = Length; //make sure that this always reflects the correct value
  260. }
  261. wcscpy( _pwszGPTPath, pGPO->lpFileSysPath );
  262. wcscat( _pwszGPTPath, GPT_SUBDIR );
  263. Length += wcslen( INIFILE_NAME );
  264. pwszGPTIniFilePath = (WCHAR *) alloca( Length * sizeof(WCHAR) );
  265. if ( ! pwszGPTIniFilePath )
  266. {
  267. Status = ERROR_OUTOFMEMORY;
  268. goto ProcessEnd;
  269. }
  270. wcscpy( pwszGPTIniFilePath, _pwszGPTPath );
  271. wcscat( pwszGPTIniFilePath, INIFILE_NAME );
  272. //
  273. // Do a quick check to see if we have any file deployment
  274. // for this policy.
  275. //
  276. hFind = FindFirstFile( pwszGPTIniFilePath, &FindData );
  277. if ( INVALID_HANDLE_VALUE == hFind )
  278. {
  279. Status = GetLastError();
  280. goto ProcessEnd;
  281. }
  282. else
  283. {
  284. bPolicyApplied = TRUE;
  285. DebugMsg((DM_VERBOSE, IDS_HASADD_POLICY, pGPO->lpDisplayName));
  286. FindClose( hFind );
  287. }
  288. }
  289. Status = ERROR_SUCCESS;
  290. if ( _pRsopContext->IsPlanningModeEnabled() )
  291. {
  292. Length = wcslen( pwszGPTIniFilePath ) + 1;
  293. }
  294. else
  295. {
  296. Length = wcslen( _pwszLocalPath ) + wcslen( pGPO->szGPOName ) + 6;
  297. }
  298. if (Length > _IniFileLen)
  299. {
  300. //we need more memory than has been allocated
  301. if (_pwszIniFilePath)
  302. delete _pwszIniFilePath;
  303. _IniFileLen = 0; //make sure that this always reflects the current value
  304. _pwszIniFilePath = new WCHAR[Length];
  305. if ( ! _pwszIniFilePath )
  306. {
  307. Status = ERROR_OUTOFMEMORY;
  308. goto ProcessEnd;
  309. }
  310. _IniFileLen = Length; //make sure that this always reflects the current value
  311. }
  312. if ( _pRsopContext->IsPlanningModeEnabled() )
  313. {
  314. wcscpy( _pwszIniFilePath, pwszGPTIniFilePath );
  315. }
  316. else
  317. {
  318. wcscpy( _pwszIniFilePath, _pwszLocalPath );
  319. wcscat( _pwszIniFilePath, L"\\" );
  320. wcscat( _pwszIniFilePath, pGPO->szGPOName );
  321. wcscat( _pwszIniFilePath, L".ini" );
  322. }
  323. if ( _bRemove )
  324. {
  325. hFind = FindFirstFile( _pwszIniFilePath, &FindData );
  326. if ( INVALID_HANDLE_VALUE == hFind )
  327. {
  328. //this error should be ignored since there is nothing we can do.
  329. //the policy has been deleted and the local settings are missing
  330. //so we have no choice but to treat these as if the settings were
  331. //to orphan the folder upon policy removal.
  332. goto ProcessEnd;
  333. }
  334. else
  335. {
  336. bPolicyApplied = TRUE;
  337. DebugMsg((DM_VERBOSE, IDS_HASREMOVE_POLICY, pGPO->lpDisplayName));
  338. FindClose( hFind );
  339. }
  340. }
  341. else if ( ! _pRsopContext->IsPlanningModeEnabled() )
  342. {
  343. bStatus = CopyFile( pwszGPTIniFilePath, _pwszIniFilePath, FALSE );
  344. if ( ! bStatus )
  345. Status = GetLastError();
  346. }
  347. if ( Status != ERROR_SUCCESS )
  348. goto ProcessEnd;
  349. _pwszGPOName = (WCHAR *) pGPO->lpDisplayName;
  350. _pwszGPOUniqueName = (WCHAR *) pGPO->szGPOName;
  351. _pwszGPOSOMPath = ( WCHAR *) pGPO->lpLink;
  352. _pwszGPODSPath = ( WCHAR *) pGPO->lpDSPath;
  353. ProcessStatus = ProcessRedirects();
  354. if ( (ProcessStatus != ERROR_SUCCESS) && (ERROR_SUCCESS == Status) )
  355. Status = ProcessStatus;
  356. ProcessEnd:
  357. if ( Status != ERROR_SUCCESS )
  358. {
  359. gpEvents->Report (
  360. EVENT_FDEPLOY_POLICYPROCESS_FAIL,
  361. 2,
  362. pGPO->lpDisplayName,
  363. StatusToString (Status)
  364. );
  365. }
  366. else if ( bPolicyApplied )
  367. {
  368. DebugMsg((DM_VERBOSE, IDS_PROCESS_GATHER_OK, pGPO->lpDisplayName));
  369. }
  370. return Status;
  371. }
  372. DWORD
  373. CFileDB::ProcessRedirects(void)
  374. {
  375. WCHAR * pwszString = 0;
  376. WCHAR * pwszSectionStrings = 0;
  377. WCHAR * pwszRedirection = 0;
  378. WCHAR wszFolderName[80];
  379. UNICODE_STRING String;
  380. DWORD Flags;
  381. DWORD RedirectStatus;
  382. DWORD Status;
  383. BOOL bStatus;
  384. REDIRECTABLE index;
  385. DWORD RedirStatus;
  386. CRedirectInfo riPolicy [(int) EndRedirectable]; //the redirection info. for this policy
  387. DWORD i;
  388. //first load the localized folder names
  389. for (i = 0, Status = ERROR_SUCCESS; i < (DWORD)EndRedirectable; i++)
  390. {
  391. Status = riPolicy[i].LoadLocalizedNames();
  392. if (ERROR_SUCCESS != Status)
  393. return Status; //bail out if the resource names cannot be loaded.
  394. }
  395. pwszSectionStrings = 0;
  396. bStatus = ReadIniSection( L"FolderStatus", &pwszSectionStrings );
  397. if ( ! bStatus )
  398. {
  399. Status = ERROR_OUTOFMEMORY;
  400. goto ProcessRedirectsEnd;
  401. }
  402. Status = ERROR_SUCCESS;
  403. for ( pwszString = pwszSectionStrings;
  404. *pwszString != 0;
  405. pwszString += lstrlen(pwszString) + 1 )
  406. {
  407. //
  408. // The syntax for each line is :
  409. // foldername=FLAGS
  410. //
  411. //
  412. // First extract the foldername.
  413. //
  414. pwszRedirection = wcschr( pwszString, L'=' );
  415. *pwszRedirection = 0;
  416. wcscpy( wszFolderName, pwszString );
  417. *pwszRedirection++ = L'=';
  418. //
  419. // Now grab the hex FLAGS.
  420. //
  421. String.Buffer = pwszRedirection;
  422. pwszRedirection = wcschr( pwszRedirection, L' ' );
  423. if ( pwszRedirection )
  424. *pwszRedirection = 0;
  425. String.Length = wcslen( String.Buffer ) * sizeof(WCHAR);
  426. String.MaximumLength = String.Length + sizeof(WCHAR);
  427. RtlUnicodeStringToInteger( &String, 16, &Flags );
  428. //just gather the information here.
  429. //actual redirections are performed in ProcessGPO after all the policies
  430. //have been processed.
  431. if (EndRedirectable ==
  432. (index = CRedirectInfo::GetFolderIndex (wszFolderName)))
  433. {
  434. //redirection of this folder is not supported
  435. DebugMsg ((DM_VERBOSE, IDS_REDIR_NOTSUPPORTED, wszFolderName));
  436. }
  437. else
  438. {
  439. //if this is a policy that has been removed and it was decided to
  440. //orphan the contents, we don't even look at it
  441. if (!_bRemove || (Flags & (REDIR_RELOCATEONREMOVE | REDIR_FOLLOW_PARENT)))
  442. {
  443. //if there is a problem in gathering redirection info. for a folder
  444. //quit immediately, or we might end up computing an incorrect
  445. //resultant policy
  446. if (ERROR_SUCCESS != (Status = riPolicy [(int) index].GatherRedirectionInfo (this, Flags, _bRemove)))
  447. goto ProcessRedirectsEnd;
  448. }
  449. }
  450. }
  451. Status = ERROR_SUCCESS;
  452. //now update the data stored in the descendant objects
  453. //this is required because if the descendants follow the parent
  454. //then the settings need to be obtained from the parent
  455. //note that we do not call UpdateDescendant for MyPics here, but in fdeploy.cxx
  456. //for details on why we do this, look at comments in operator= in redir.cxx
  457. riPolicy[(int) Programs].UpdateDescendant();
  458. riPolicy[(int) Startup].UpdateDescendant(); //this call must be made after Programs has been updated
  459. //merge info into the global redirection store
  460. for (i = 0; i < (DWORD) EndRedirectable; i++)
  461. {
  462. if (_bRemove)
  463. gDeletedPolicyResultant[i] = riPolicy[i];
  464. else
  465. gAddedPolicyResultant[i] = riPolicy[i];
  466. }
  467. ProcessRedirectsEnd:
  468. delete pwszSectionStrings;
  469. if ( ERROR_SUCCESS != Status )
  470. {
  471. DebugMsg((DM_VERBOSE, IDS_PROCESSREDIRECTS, Status));
  472. }
  473. else
  474. {
  475. if ( ! _bRemove && _pRsopContext->IsRsopEnabled() )
  476. {
  477. (void) AddRedirectionPolicies(
  478. this,
  479. riPolicy);
  480. }
  481. }
  482. return Status;
  483. }
  484. BOOL
  485. CFileDB::ReadIniSection(
  486. WCHAR * pwszSectionName,
  487. WCHAR ** ppwszStrings,
  488. DWORD * pcchLen
  489. )
  490. {
  491. DWORD Length;
  492. DWORD ReturnLength;
  493. *ppwszStrings = 0;
  494. Length = 256;
  495. for (;;)
  496. {
  497. delete *ppwszStrings;
  498. *ppwszStrings = new WCHAR[Length];
  499. if ( ! *ppwszStrings )
  500. return FALSE;
  501. ReturnLength = GetPrivateProfileSection(
  502. pwszSectionName,
  503. *ppwszStrings,
  504. Length,
  505. _pwszIniFilePath );
  506. if ( ReturnLength != (Length - 2) )
  507. {
  508. if (pcchLen)
  509. {
  510. *pcchLen = ReturnLength;
  511. }
  512. return TRUE;
  513. }
  514. Length *= 2;
  515. }
  516. }
  517. DWORD
  518. CFileDB::GetLocalFilePath(
  519. WCHAR * pwszFolderPath,
  520. WCHAR * wszFullPath
  521. )
  522. {
  523. int CSidl;
  524. DWORD Status;
  525. HRESULT hr;
  526. WCHAR * pwszFolderName;
  527. CSidl = CSIDL_FLAG_MASK; //use a value that is not a valid CSIDL value for any folder.
  528. for (DWORD n = 0; gUserShellFolders[n].FolderName; n++)
  529. {
  530. if (0 == _wcsicmp (pwszFolderPath, gUserShellFolders[n].FolderName))
  531. {
  532. pwszFolderName = gUserShellFolders[n].FolderName;
  533. CSidl = gUserShellFolders[n].CSidl;
  534. break;
  535. }
  536. }
  537. if ( CSIDL_FLAG_MASK != CSidl )
  538. {
  539. hr = SHGetFolderPath( 0, CSidl | CSIDL_FLAG_DONT_VERIFY,
  540. _hUserToken, 0, wszFullPath );
  541. Status = GetWin32ErrFromHResult (hr);
  542. if ( ERROR_SUCCESS != Status )
  543. {
  544. DebugMsg((DM_WARNING, IDS_FOLDERPATH_FAIL, pwszFolderName, Status));
  545. return Status;
  546. }
  547. }
  548. else
  549. return ERROR_INVALID_NAME;
  550. return ERROR_SUCCESS;
  551. }
  552. DWORD
  553. CFileDB::GetPathFromFolderName(
  554. WCHAR * pwszFolderName,
  555. WCHAR * wszFullPath
  556. )
  557. {
  558. int CSidl;
  559. DWORD Status;
  560. HRESULT hr;
  561. CSidl = CSIDL_FLAG_MASK; //use a csidl value that is not valid for any folder
  562. for (DWORD n = 0; gUserShellFolders[n].FolderName; n++)
  563. {
  564. //we subtract 1 from the length because one of the paths is \ terminated
  565. //and the other is not.
  566. if ( _wcsnicmp( pwszFolderName, gUserShellFolders[n].FolderName, gUserShellFolders[n].FolderNameLength - 1 ) == 0 )
  567. {
  568. CSidl = gUserShellFolders[n].CSidl;
  569. break;
  570. }
  571. }
  572. if ( CSIDL_FLAG_MASK != CSidl )
  573. {
  574. hr = SHGetFolderPath( 0, CSidl | CSIDL_FLAG_DONT_VERIFY,
  575. _hUserToken, 0, wszFullPath );
  576. if ( S_OK != hr )
  577. {
  578. DebugMsg((DM_WARNING, IDS_FOLDERPATH_FAIL, pwszFolderName, hr));
  579. return (DWORD) hr;
  580. }
  581. }
  582. else
  583. return ERROR_INVALID_NAME;
  584. return ERROR_SUCCESS;
  585. }
  586. DWORD
  587. CFileDB::CopyGPTFile(
  588. WCHAR * pwszLocalPath,
  589. WCHAR * pwszGPTPath
  590. )
  591. {
  592. DWORD FileAttr;
  593. DWORD Status;
  594. BOOL bStatus;
  595. if ( L'\\' == pwszLocalPath[wcslen(pwszLocalPath)-1] )
  596. {
  597. bStatus = CreateDirectory( pwszLocalPath, NULL );
  598. //
  599. // Note, we leave attributes & security as is if the dir
  600. // already exits.
  601. //
  602. if ( ! bStatus && (ERROR_ALREADY_EXISTS == GetLastError()) )
  603. return ERROR_SUCCESS;
  604. }
  605. else
  606. {
  607. FileAttr = GetFileAttributes( pwszLocalPath );
  608. if ( 0xFFFFFFFF == FileAttr )
  609. return GetLastError();
  610. SetFileAttributes( pwszLocalPath, FileAttr & ~FILE_ATTRIBUTE_READONLY );
  611. bStatus = CopyFile(
  612. pwszGPTPath,
  613. pwszLocalPath,
  614. FALSE );
  615. //
  616. // By default, we set the read only attribute on deployed files. We
  617. // combine this with any existing file attributes on the GPT file.
  618. //
  619. if ( bStatus )
  620. {
  621. FileAttr = GetFileAttributes( pwszGPTPath );
  622. bStatus = (FileAttr != 0xFFFFFFFF);
  623. }
  624. else
  625. {
  626. SetFileAttributes( pwszLocalPath, FileAttr );
  627. }
  628. if ( bStatus )
  629. {
  630. FileAttr |= FILE_ATTRIBUTE_READONLY;
  631. bStatus = SetFileAttributes( pwszLocalPath, FileAttr );
  632. }
  633. }
  634. if ( ! bStatus )
  635. return GetLastError();
  636. return ERROR_SUCCESS;
  637. }
  638. const FOLDERINFO*
  639. CFileDB::FolderInfoFromFolderName(
  640. WCHAR * pwszFolderName
  641. )
  642. {
  643. //
  644. // This method returns the index into global array.
  645. //
  646. if ( _hUserToken )
  647. {
  648. for ( DWORD n = 0; gUserShellFolders[n].FolderName; n++ )
  649. {
  650. if ( _wcsnicmp( pwszFolderName, gUserShellFolders[n].FolderName, gUserShellFolders[n].FolderNameLength - 1 ) == 0 )
  651. return &gUserShellFolders[n];
  652. }
  653. }
  654. else
  655. {
  656. for ( DWORD n = 0; gMachineShellFolders[n].FolderName; n++ )
  657. {
  658. if ( _wcsnicmp( pwszFolderName, gMachineShellFolders[n].FolderName, gMachineShellFolders[n].FolderNameLength - 1 ) == 0 )
  659. return &gMachineShellFolders[n];
  660. }
  661. }
  662. return NULL;
  663. }
  664. int
  665. CFileDB::RegValueCSIDLFromFolderName(
  666. WCHAR * pwszFolderName
  667. )
  668. {
  669. const FOLDERINFO *pFI;
  670. pFI = FolderInfoFromFolderName(pwszFolderName);
  671. if (pFI != NULL)
  672. return pFI->CSidl;
  673. else
  674. return -1; // invalid CSIDL
  675. }
  676. WCHAR *
  677. CFileDB::RegValueNameFromFolderName(
  678. WCHAR * pwszFolderName
  679. )
  680. {
  681. //
  682. // This is used by folder redirection logic. In this case the folder
  683. // name is not '\' terminated, so we subtract one from the folder
  684. // name length.
  685. //
  686. const FOLDERINFO *pFI;
  687. pFI = FolderInfoFromFolderName(pwszFolderName);
  688. if (pFI != NULL)
  689. return pFI->RegValue;
  690. else
  691. return NULL;
  692. }
  693. const WCHAR *
  694. CFileDB::GetLocalStoragePath ()
  695. {
  696. return (LPCWSTR) _pwszLocalPath;
  697. }
  698. DWORD
  699. CFileDB::CopyFileTree(
  700. WCHAR * pwszExistingPath,
  701. WCHAR * pwszNewPath,
  702. WCHAR * pwszIgnoredSubdir,
  703. SHARESTATUS StatusFrom,
  704. SHARESTATUS StatusTo,
  705. BOOL bAllowRdrTimeout,
  706. CCopyFailData * pCopyFailure
  707. )
  708. {
  709. HANDLE hFind;
  710. WIN32_FIND_DATA FindData;
  711. WIN32_FILE_ATTRIBUTE_DATA SourceAttr;
  712. WIN32_FILE_ATTRIBUTE_DATA DestAttr;
  713. WCHAR * wszSource = NULL;
  714. WCHAR * pwszSourceEnd = 0;
  715. WCHAR * wszDest = NULL;
  716. WCHAR * pwszDestEnd = 0;
  717. WCHAR * pwszTempFilename = 0;
  718. DWORD FileAttributes;
  719. DWORD Status;
  720. BOOL bStatus;
  721. BOOL bReuseTempName = FALSE;
  722. int lenSource;
  723. int lenDest;
  724. DWORD StatusCSCDel = ERROR_SUCCESS;
  725. DWORD dwAttr = INVALID_FILE_ATTRIBUTES;
  726. if (! pwszExistingPath || ! pwszNewPath)
  727. return ERROR_PATH_NOT_FOUND;
  728. lenSource = wcslen (pwszExistingPath);
  729. lenDest = wcslen (pwszNewPath);
  730. if (! lenSource || ! lenDest)
  731. return ERROR_PATH_NOT_FOUND;
  732. wszSource = (WCHAR *) alloca (sizeof (WCHAR) * (lenSource + MAX_PATH + 2));
  733. if (NULL == wszSource)
  734. return ERROR_OUTOFMEMORY;
  735. lstrcpy( wszSource, pwszExistingPath );
  736. pwszSourceEnd = wszSource + lenSource;
  737. if (L'\\' != pwszSourceEnd[-1])
  738. *pwszSourceEnd++ = L'\\';
  739. pwszSourceEnd[0] = L'*';
  740. pwszSourceEnd[1] = 0;
  741. wszDest = (WCHAR *) alloca (sizeof (WCHAR) * (lenDest + MAX_PATH + 2));
  742. if (NULL == wszDest)
  743. return ERROR_OUTOFMEMORY;
  744. lstrcpy( wszDest, pwszNewPath );
  745. pwszDestEnd = wszDest + lenDest;
  746. if (L'\\' != pwszDestEnd[-1])
  747. *pwszDestEnd++ = L'\\';
  748. *pwszDestEnd = 0;
  749. hFind = FindFirstFile( wszSource, &FindData );
  750. if ( INVALID_HANDLE_VALUE == hFind )
  751. return ERROR_SUCCESS;
  752. Status = ERROR_SUCCESS;
  753. do
  754. {
  755. lstrcpy( pwszSourceEnd, FindData.cFileName );
  756. lstrcpy( pwszDestEnd, FindData.cFileName );
  757. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  758. {
  759. if ( lstrcmp( FindData.cFileName, L"." ) == 0 ||
  760. lstrcmp( FindData.cFileName, L".." ) == 0 ||
  761. (pwszIgnoredSubdir && lstrcmpi( FindData.cFileName, pwszIgnoredSubdir ) == 0) )
  762. continue;
  763. Status = FullDirCopyW (wszSource, wszDest, FALSE);
  764. if ( ERROR_SUCCESS == Status )
  765. {
  766. if (ERROR_SUCCESS == StatusCSCDel)
  767. {
  768. Status = CopyFileTree( wszSource, wszDest, NULL, StatusFrom, StatusTo, bAllowRdrTimeout, pCopyFailure );
  769. }
  770. else
  771. {
  772. //no point delaying CSCDeletes anymore since we have already failed once.
  773. Status = CopyFileTree (wszSource, wszDest, NULL, StatusFrom, StatusTo, FALSE, pCopyFailure);
  774. }
  775. //copy over the pin info. too
  776. if (ERROR_SUCCESS == Status)
  777. MergePinInfo (wszSource, wszDest, StatusFrom, StatusTo);
  778. }
  779. else
  780. {
  781. pCopyFailure->RegisterFailure (wszSource, wszDest);
  782. DebugMsg((DM_VERBOSE, IDS_DIRCREATE_FAIL, wszDest, Status));
  783. }
  784. }
  785. else
  786. {
  787. Status = ERROR_SUCCESS;
  788. // First check if it is necessary to copy the file over.
  789. bStatus = GetFileAttributesEx( wszSource, GetFileExInfoStandard, &SourceAttr );
  790. if ( bStatus )
  791. {
  792. bStatus = GetFileAttributesEx( wszDest, GetFileExInfoStandard, &DestAttr );
  793. if (bStatus)
  794. {
  795. if (CompareFileTime( &SourceAttr.ftLastWriteTime, &DestAttr.ftLastWriteTime ) <= 0)
  796. {
  797. // The destination is newer or at least as old as the source.
  798. // There is no need to copy. However, we should delete
  799. // the locally cached copy of the file if any since the
  800. // destination is newer.
  801. if (ERROR_SUCCESS == StatusCSCDel)
  802. StatusCSCDel = DeleteCSCFile ( wszSource, bAllowRdrTimeout);
  803. else
  804. DeleteCSCFile ( wszSource, FALSE);
  805. continue;
  806. }
  807. }
  808. else
  809. {
  810. Status = GetLastError();
  811. if (ERROR_PATH_NOT_FOUND == Status ||
  812. ERROR_FILE_NOT_FOUND == Status)
  813. {
  814. // The destination was not found. So we must proceed with the copy.
  815. bStatus = TRUE;
  816. Status = ERROR_SUCCESS;
  817. }
  818. }
  819. }
  820. else
  821. {
  822. // We failed to get the attributes of the source file.
  823. Status = GetLastError();
  824. }
  825. if (ERROR_SUCCESS == Status)
  826. {
  827. //
  828. // If we are here, we need to copy the file over.
  829. // In order to avoid loss of data, we must first copy the file
  830. // over to a temporary file at the destination and then rename
  831. // the file at the destination. This is because if the network
  832. // connection gets dropped during the filecopy operation, then
  833. // we are left with an incomplete file at the destination.
  834. // If we use the real name on the destination directly, then
  835. // the file will be skipped at the next redirection attempt
  836. // because of our last writer wins algorithm. As a result, when
  837. // the redirection succeeds subsequently, we end up with a loss
  838. // of user data. Copying to a temp name and then renaming the
  839. // file prevents this problem from happening because the rename
  840. // operation is atomic.
  841. //
  842. // First check if we need to generate a new temporary filename
  843. // Note: We try to minimize the number of calls to GetTempFilename
  844. // because it can be a very expensive call as it can result in
  845. // multiple CreateFile calls over the network which can be
  846. // especially slow for EFS shares.
  847. //
  848. bReuseTempName = FALSE;
  849. if (NULL != pwszTempFilename && L'\0' != *pwszTempFilename)
  850. {
  851. dwAttr = GetFileAttributes (pwszTempFilename);
  852. if (INVALID_FILE_ATTRIBUTES == dwAttr)
  853. {
  854. Status = GetLastError();
  855. if (ERROR_PATH_NOT_FOUND == Status ||
  856. ERROR_FILE_NOT_FOUND == Status)
  857. {
  858. Status = ERROR_SUCCESS;
  859. bReuseTempName = TRUE;
  860. }
  861. }
  862. }
  863. if (ERROR_SUCCESS == Status && FALSE == bReuseTempName)
  864. {
  865. // We need to generate a new temporary filename.
  866. if (NULL == pwszTempFilename)
  867. {
  868. pwszTempFilename = new WCHAR [MAX_PATH + 1];
  869. if (NULL == pwszTempFilename)
  870. Status = ERROR_OUTOFMEMORY;
  871. }
  872. if (ERROR_SUCCESS == Status)
  873. {
  874. *pwszTempFilename = 0;
  875. *pwszDestEnd = 0;
  876. bStatus = GetTempFileName(wszDest, TEXT("frd"), 0, pwszTempFilename);
  877. *pwszDestEnd = FindData.cFileName[0];
  878. if (!bStatus)
  879. {
  880. Status = GetLastError();
  881. }
  882. }
  883. }
  884. if (ERROR_SUCCESS == Status)
  885. {
  886. // Now we have a temp. filename and we are ready to copy.
  887. Status = FullFileCopyW (wszSource, pwszTempFilename, FALSE);
  888. if (ERROR_SUCCESS == Status)
  889. {
  890. // Now we rename the file at the destination in one atomic
  891. // step. Note however that if the destination file exists
  892. // and has readonly/hidden/system attributes, the MoveFileEx
  893. // API will fail with ERROR_ACCESS_DENIED. So we slap on normal
  894. // attributes on the file before doing the Move. If we fail,
  895. // we restore the attributes.
  896. dwAttr = GetFileAttributes (wszDest);
  897. // Change attributes only if we managed to figure out the
  898. // actual attributes.
  899. if (INVALID_FILE_ATTRIBUTES != dwAttr)
  900. SetFileAttributes (wszDest, FILE_ATTRIBUTE_NORMAL);
  901. if (!MoveFileEx(pwszTempFilename, wszDest, MOVEFILE_REPLACE_EXISTING))
  902. {
  903. Status = GetLastError();
  904. // Restore the attributes of the destination file.
  905. // Provided we changed those in the first place.
  906. if (INVALID_FILE_ATTRIBUTES != dwAttr)
  907. SetFileAttributes (wszDest, dwAttr);
  908. // Also try to delete the temp file because we might still
  909. // be able to do it. But ignore any failures. We are just
  910. // trying to be nice by removing turds.
  911. DeleteFile(pwszTempFilename);
  912. }
  913. }
  914. }
  915. }
  916. if ( Status != ERROR_SUCCESS )
  917. {
  918. pCopyFailure->RegisterFailure (wszSource, wszDest);
  919. switch (Status)
  920. {
  921. case ERROR_INVALID_SECURITY_DESCR:
  922. DebugMsg((DM_VERBOSE, IDS_SETSECURITY_FAIL, wszSource, wszDest));
  923. break;
  924. default:
  925. DebugMsg((DM_VERBOSE, IDS_FILECOPY_FAIL, wszSource, wszDest, Status));
  926. break;
  927. }
  928. }
  929. }
  930. if ( Status != ERROR_SUCCESS )
  931. break;
  932. } while ( FindNextFile( hFind, &FindData ) );
  933. // Some final cleanup before we return.
  934. FindClose( hFind );
  935. if (pwszTempFilename)
  936. {
  937. delete [] pwszTempFilename;
  938. pwszTempFilename = NULL;
  939. }
  940. return Status;
  941. }
  942. DWORD
  943. CFileDB::DeleteFileTree(
  944. WCHAR * pwszPath,
  945. WCHAR * pwszIgnoredSubdir
  946. )
  947. {
  948. HANDLE hFind;
  949. WIN32_FIND_DATA FindData;
  950. WCHAR * wszSource = NULL;
  951. WCHAR * pwszSourceEnd = 0;
  952. DWORD Status;
  953. BOOL bStatus;
  954. int len;
  955. if (!pwszPath)
  956. return ERROR_PATH_NOT_FOUND;
  957. len = wcslen (pwszPath);
  958. if (!len)
  959. return ERROR_PATH_NOT_FOUND;
  960. wszSource = (WCHAR *) alloca (sizeof (WCHAR) * (len + MAX_PATH + 2));
  961. if (NULL == wszSource)
  962. return ERROR_OUTOFMEMORY;
  963. lstrcpy( wszSource, pwszPath );
  964. pwszSourceEnd = wszSource + lstrlen( wszSource );
  965. if (L'\\' != pwszSourceEnd[-1])
  966. *pwszSourceEnd++ = L'\\';
  967. pwszSourceEnd[0] = L'*';
  968. pwszSourceEnd[1] = 0;
  969. hFind = FindFirstFile( wszSource, &FindData );
  970. if ( INVALID_HANDLE_VALUE == hFind )
  971. return ERROR_SUCCESS;
  972. Status = ERROR_SUCCESS;
  973. for (;;)
  974. {
  975. lstrcpy( pwszSourceEnd, FindData.cFileName );
  976. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  977. {
  978. if ( lstrcmp( FindData.cFileName, L"." ) != 0 &&
  979. lstrcmp( FindData.cFileName, L".." ) != 0 &&
  980. (! pwszIgnoredSubdir || lstrcmpi( FindData.cFileName, pwszIgnoredSubdir ) != 0) )
  981. {
  982. SetFileAttributes( wszSource, FILE_ATTRIBUTE_NORMAL );
  983. Status = DeleteFileTree( wszSource, NULL);
  984. if ( ERROR_SUCCESS == Status )
  985. {
  986. if ( ! RemoveDirectory( wszSource ) )
  987. {
  988. Status = GetLastError();
  989. DebugMsg((DM_VERBOSE, IDS_DIRDEL_FAIL, wszSource, Status));
  990. }
  991. }
  992. }
  993. }
  994. else
  995. {
  996. SetFileAttributes( wszSource, FILE_ATTRIBUTE_NORMAL );
  997. bStatus = DeleteFile( wszSource );
  998. if ( ! bStatus )
  999. {
  1000. Status = GetLastError();
  1001. DebugMsg((DM_VERBOSE, IDS_FILEDEL_FAIL, wszSource, Status));
  1002. }
  1003. }
  1004. if ( Status != ERROR_SUCCESS )
  1005. break;
  1006. bStatus = FindNextFile( hFind, &FindData );
  1007. if ( ! bStatus )
  1008. {
  1009. Status = GetLastError();
  1010. if ( ERROR_NO_MORE_FILES == Status )
  1011. Status = ERROR_SUCCESS;
  1012. break;
  1013. }
  1014. }
  1015. FindClose( hFind );
  1016. return Status;
  1017. }
  1018. //note: the bCheckOwner flag: if set to true, then if the directory in question
  1019. // already exists, the function Fails with an ERROR_INVALID_OWNER if the
  1020. // the owner of the existing directory is not the user.
  1021. // bSourceValid indicates if there is a valid path in pwszSource
  1022. DWORD
  1023. CFileDB::CreateRedirectedFolderPath(
  1024. const WCHAR * pwszSource,
  1025. const WCHAR * pwszDest,
  1026. BOOL bSourceValid,
  1027. BOOL bCheckOwner,
  1028. BOOL bMoveContents
  1029. )
  1030. {
  1031. WCHAR * pwszSlash = 0;
  1032. WCHAR * pwszPath = NULL;
  1033. DWORD Status = ERROR_SUCCESS;
  1034. int len;
  1035. WCHAR * pwszSuccess = NULL;
  1036. DWORD dwAttributes;
  1037. //first make a local copy of the destination path to work with.
  1038. //while copying, we actually convert it into an absolute path so
  1039. //that we eliminate any problems with weird paths like
  1040. //\\server\share\..\hello\..\there
  1041. len = wcslen (pwszDest) + 1;
  1042. pwszPath = (WCHAR*) alloca (len * sizeof(WCHAR));
  1043. if (!pwszPath)
  1044. return ERROR_OUTOFMEMORY;
  1045. pwszSuccess = _wfullpath (pwszPath, pwszDest, len);
  1046. if (!pwszSuccess)
  1047. return ERROR_BAD_PATHNAME; //actually _wfullpath rarely fails
  1048. //
  1049. // Will only accept drive based or UNC based paths.
  1050. //
  1051. // A redirect path of just <drive>:\ or \\server\share will be accepted
  1052. // even though this would be a strange choice for redirection.
  1053. //
  1054. // IMPORTANT: also see notes at the beginning of the function
  1055. if ( L':' == pwszPath[1] && L'\\' == pwszPath[2] )
  1056. {
  1057. pwszSlash = &pwszPath[2];
  1058. }
  1059. else if ( L'\\' == pwszPath[0] && L'\\' == pwszPath[1] )
  1060. {
  1061. pwszSlash = wcschr( &pwszPath[2], L'\\' );
  1062. if ( pwszSlash )
  1063. {
  1064. //watch out for '\' terminated paths
  1065. if (L'\0' == pwszSlash[1])
  1066. {
  1067. pwszSlash = 0;
  1068. }
  1069. else //it is at least of the form \\server\share
  1070. {
  1071. pwszSlash = wcschr( &pwszSlash[1], L'\\' );
  1072. //if it is of the form \\server\share, then we allow this path
  1073. //based depending on the ownership checks if any
  1074. if (!pwszSlash)
  1075. return bCheckOwner ? IsUserOwner(pwszPath) : ERROR_SUCCESS;
  1076. //note: we do not have to watch out for the '\' terminated
  1077. //paths here (e.g. \\server\share\) because that will be
  1078. //taken care of below : in -> if (!pwszSlash[1])
  1079. }
  1080. }
  1081. }
  1082. else
  1083. {
  1084. pwszSlash = 0;
  1085. }
  1086. if ( ! pwszSlash )
  1087. return ERROR_BAD_PATHNAME;
  1088. //if it is the root directory of a drive or root of a UNC share
  1089. //we succeed based on ownership checks, if any...
  1090. //but before that, we also need to make sure that the specified path
  1091. //exists or we may end up redirecting to a non-existent location.
  1092. if ( !pwszSlash[1])
  1093. {
  1094. if (0xFFFFFFFF != (dwAttributes = GetFileAttributes(pwszPath)))
  1095. {
  1096. //it exists
  1097. if (! (FILE_ATTRIBUTE_DIRECTORY & dwAttributes))
  1098. {
  1099. return ERROR_DIRECTORY;
  1100. }
  1101. //it exists and is a directory
  1102. return bCheckOwner ? IsUserOwner (pwszPath) : ERROR_SUCCESS;
  1103. }
  1104. else
  1105. {
  1106. return GetLastError();
  1107. }
  1108. }
  1109. //if we are here, it is not the root of a drive or a share.
  1110. //so we might have to do create the destination.
  1111. //First do a quick check to see if the path exists already. this
  1112. //is not only an optimization, but is also necessary for cases
  1113. //where an admin. may want to lock down access to certain folders
  1114. //by pre-creating the folders and putting highly resitrictive ACLs on them
  1115. //in that case, CreateDirectory (later in the code) would fail with
  1116. //ACCESS_DENIED rather than ERROR_ALREADY_EXISTS and the redirection code
  1117. //will bail out even though it is not necessary to.
  1118. if (0xFFFFFFFF != (dwAttributes = GetFileAttributes(pwszPath)))
  1119. {
  1120. //it exists
  1121. if (! (FILE_ATTRIBUTE_DIRECTORY & dwAttributes))
  1122. {
  1123. return ERROR_DIRECTORY;
  1124. }
  1125. //it exists and is a directory
  1126. return bCheckOwner ? IsUserOwner (pwszPath) : ERROR_SUCCESS;
  1127. }
  1128. //the destination has not been pre-created, so we need to do that
  1129. //ourselves
  1130. do
  1131. {
  1132. pwszSlash = wcschr( &pwszSlash[1], L'\\' );
  1133. // Watch out for '\' terminated paths.
  1134. if ( pwszSlash && (L'\0' == pwszSlash[1]) )
  1135. pwszSlash = 0;
  1136. if ( pwszSlash )
  1137. {
  1138. *pwszSlash = 0;
  1139. CreateDirectory( pwszPath, NULL );
  1140. *pwszSlash = L'\\';
  1141. //ignore all errors in the intermediate folders not just
  1142. //ERROR_ALREADY_EXISTS because of folders like
  1143. //\\server\share\dir1\dir2\%username% where the user may not
  1144. //have write access in dir1 but might have so in dir2
  1145. //if the path is invalid we will either discover it at the last
  1146. //dir in the chain or while trying to redirect to the destination
  1147. //retaining the code here just in case...
  1148. //
  1149. /*if ( ! bStatus && (GetLastError() != ERROR_ALREADY_EXISTS) )
  1150. return GetLastError();*/
  1151. }
  1152. else
  1153. {
  1154. //
  1155. // Last dir in the chain. We set security on the last dir in
  1156. // the path to only allow the user & system access if
  1157. // the directory did not already exist.
  1158. //
  1159. if (bCheckOwner)
  1160. {
  1161. Status = CreateFolderWithUserFileSecurity( pwszPath );
  1162. }
  1163. else
  1164. {
  1165. Status = ERROR_SUCCESS;
  1166. if (!CreateDirectory( pwszPath, NULL ))
  1167. Status = GetLastError();
  1168. }
  1169. if ( ERROR_SUCCESS == Status )
  1170. {
  1171. //the extension created the directory, so try to set the user as
  1172. //the owner explicitly because if a member of the local administrators
  1173. //group creates a directory/file, the Administrators group becomes
  1174. //the owner by default. This can cause problems with quota accounting
  1175. //and also if the settings on the redirection policy are changed
  1176. //at a later date. However, since it is not necessary that the
  1177. //we will succeed in setting the owner here, we ignore any failures
  1178. SetUserAsOwner (pwszPath);
  1179. //
  1180. // We want to skip the DACL if we want to apply exclusive ACLs
  1181. // i.e., bCheckOwner is true. Otherwise, we should just copy
  1182. // over all the metadata.
  1183. //
  1184. if (bSourceValid && bMoveContents)
  1185. FullDirCopyW (pwszSource, pwszPath, bCheckOwner);
  1186. return ERROR_SUCCESS;
  1187. }
  1188. else if ( ERROR_ALREADY_EXISTS != Status)
  1189. {
  1190. return Status;
  1191. }
  1192. else
  1193. {
  1194. //the directory already exists
  1195. //start anti-spoofing agent
  1196. //do the ownership check only on the last dir in chain and only
  1197. //if the flags in the ini file tell you to.
  1198. if (bCheckOwner &&
  1199. (ERROR_SUCCESS != (Status = IsUserOwner(pwszPath))))
  1200. {
  1201. DebugMsg ((DM_VERBOSE, IDS_ACL_MISMATCH, pwszPath, Status));
  1202. return Status;
  1203. }
  1204. else
  1205. return ERROR_SUCCESS;
  1206. }
  1207. }
  1208. } while ( pwszSlash );
  1209. return ERROR_SUCCESS;
  1210. }
  1211. DWORD
  1212. CFileDB::SetUserAsOwner(
  1213. WCHAR * pwszPath
  1214. )
  1215. {
  1216. SECURITY_DESCRIPTOR SecDesc;
  1217. PSID pSidUser = 0;
  1218. PTOKEN_USER pTokenUser = 0;
  1219. DWORD Size = 0;
  1220. DWORD Status = ERROR_SUCCESS;
  1221. BOOL bStatus;
  1222. if ( ! _hUserToken )
  1223. return ERROR_SUCCESS;
  1224. for (;;)
  1225. {
  1226. Status = NtQueryInformationToken(
  1227. _hUserToken,
  1228. TokenUser,
  1229. pTokenUser,
  1230. Size,
  1231. &Size );
  1232. if ( STATUS_BUFFER_TOO_SMALL == Status )
  1233. {
  1234. pTokenUser = (PTOKEN_USER) alloca( Size );
  1235. if ( ! pTokenUser )
  1236. return ERROR_OUTOFMEMORY;
  1237. continue;
  1238. }
  1239. break;
  1240. }
  1241. if ( Status != ERROR_SUCCESS )
  1242. return Status;
  1243. Size = RtlLengthSid( pTokenUser->User.Sid );
  1244. pSidUser = (PSID) alloca( Size );
  1245. if ( pSidUser )
  1246. Status = RtlCopySid( Size, pSidUser, pTokenUser->User.Sid );
  1247. else
  1248. Status = ERROR_OUTOFMEMORY;
  1249. if ( Status != ERROR_SUCCESS )
  1250. return Status;
  1251. bStatus = InitializeSecurityDescriptor( &SecDesc, SECURITY_DESCRIPTOR_REVISION );
  1252. if ( bStatus )
  1253. bStatus = SetSecurityDescriptorOwner (&SecDesc, pSidUser, 0);
  1254. if (bStatus)
  1255. bStatus = SetFileSecurity( pwszPath, OWNER_SECURITY_INFORMATION, &SecDesc);
  1256. if ( ! bStatus )
  1257. Status = GetLastError();
  1258. return Status;
  1259. }
  1260. DWORD
  1261. CFileDB::CreateFolderWithUserFileSecurity(
  1262. WCHAR * pwszPath
  1263. )
  1264. {
  1265. SECURITY_DESCRIPTOR SecDesc;
  1266. SID_IDENTIFIER_AUTHORITY AuthorityNT = SECURITY_NT_AUTHORITY;
  1267. SID_IDENTIFIER_AUTHORITY AuthWorld = SECURITY_WORLD_SID_AUTHORITY;
  1268. PSID pSidUser = 0;
  1269. PSID pSidSystem = 0;
  1270. PACL pAcl = 0;
  1271. ACE_HEADER * pAceHeader;
  1272. PTOKEN_USER pTokenUser = 0;
  1273. PSID pSid = 0;
  1274. DWORD AclSize;
  1275. DWORD AceIndex;
  1276. DWORD Size;
  1277. DWORD Status;
  1278. BOOL bStatus;
  1279. if ( ! _hUserToken )
  1280. return ERROR_SUCCESS;
  1281. pSidSystem = 0;
  1282. pTokenUser = 0;
  1283. Size = 0;
  1284. for (;;)
  1285. {
  1286. Status = NtQueryInformationToken(
  1287. _hUserToken,
  1288. TokenUser,
  1289. pTokenUser,
  1290. Size,
  1291. &Size );
  1292. if ( STATUS_BUFFER_TOO_SMALL == Status )
  1293. {
  1294. pTokenUser = (PTOKEN_USER) alloca( Size );
  1295. if ( ! pTokenUser )
  1296. return ERROR_OUTOFMEMORY;
  1297. continue;
  1298. }
  1299. break;
  1300. }
  1301. if ( Status != ERROR_SUCCESS )
  1302. return Status;
  1303. Size = RtlLengthSid( pTokenUser->User.Sid );
  1304. pSidUser = (PSID) alloca( Size );
  1305. if ( pSidUser )
  1306. Status = RtlCopySid( Size, pSidUser, pTokenUser->User.Sid );
  1307. else
  1308. Status = ERROR_OUTOFMEMORY;
  1309. if ( Status != ERROR_SUCCESS )
  1310. return Status;
  1311. bStatus = AllocateAndInitializeSid( &AuthorityNT, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSidSystem);
  1312. if ( ! bStatus )
  1313. {
  1314. Status = GetLastError();
  1315. goto SetUserFileSecurityEnd;
  1316. }
  1317. //
  1318. // Allocate space for the ACL
  1319. //
  1320. AclSize = (GetLengthSid(pSidUser)) +
  1321. (GetLengthSid(pSidSystem)) +
  1322. sizeof(ACL) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)));
  1323. pAcl = (PACL) alloca( AclSize );
  1324. if ( pAcl )
  1325. {
  1326. bStatus = InitializeAcl( pAcl, AclSize, ACL_REVISION );
  1327. if ( ! bStatus )
  1328. Status = GetLastError();
  1329. }
  1330. else
  1331. {
  1332. Status = ERROR_OUTOFMEMORY;
  1333. }
  1334. if ( Status != ERROR_SUCCESS )
  1335. goto SetUserFileSecurityEnd;
  1336. //
  1337. // Add Aces for User, System, and Admin. Non-inheritable ACEs first
  1338. //
  1339. AceIndex = 0;
  1340. bStatus = AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, pSidUser);
  1341. if ( bStatus )
  1342. {
  1343. bStatus = GetAce(pAcl, AceIndex, (void **) &pAceHeader);
  1344. if ( bStatus )
  1345. pAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
  1346. }
  1347. if ( bStatus )
  1348. {
  1349. AceIndex++;
  1350. bStatus = AddAccessAllowedAce(pAcl, ACL_REVISION, FILE_ALL_ACCESS, pSidSystem);
  1351. if ( bStatus )
  1352. {
  1353. bStatus = GetAce(pAcl, AceIndex, (void **) &pAceHeader);
  1354. if ( bStatus )
  1355. pAceHeader->AceFlags |= (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
  1356. }
  1357. }
  1358. if ( ! bStatus )
  1359. {
  1360. Status = GetLastError();
  1361. goto SetUserFileSecurityEnd;
  1362. }
  1363. bStatus = InitializeSecurityDescriptor( &SecDesc, SECURITY_DESCRIPTOR_REVISION );
  1364. if (bStatus)
  1365. SetSecurityDescriptorControl (&SecDesc, SE_DACL_PROTECTED,
  1366. SE_DACL_PROTECTED);
  1367. //SE_DACL_PROTECTED is supported by NTFS5 but not by NTFS4, therefore
  1368. //we ignore any failures in SetSecurityDesciptorControl
  1369. if ( bStatus )
  1370. bStatus = SetSecurityDescriptorDacl( &SecDesc, TRUE, pAcl, FALSE );
  1371. //set the owner explicitly. This is required because if the user is an
  1372. //admin, then when the directory is created, the owner is set to the group
  1373. //administrators, rather than the user
  1374. if ( bStatus )
  1375. {
  1376. bStatus = SetSecurityDescriptorOwner (&SecDesc, pSidUser, 0);
  1377. }
  1378. if ( bStatus )
  1379. {
  1380. SECURITY_ATTRIBUTES sa;
  1381. sa.bInheritHandle = FALSE;
  1382. sa.lpSecurityDescriptor = &SecDesc;
  1383. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  1384. bStatus = CreateDirectory(pwszPath, &sa);
  1385. }
  1386. if ( ! bStatus )
  1387. {
  1388. Status = GetLastError();
  1389. }
  1390. SetUserFileSecurityEnd:
  1391. // The user Sid was allocated on the stack, so there is no need to Free it.
  1392. if (pSidSystem)
  1393. FreeSid( pSidSystem );
  1394. return Status;
  1395. }
  1396. //+--------------------------------------------------------------------------
  1397. //
  1398. // Member: CFileDB::IsUserOwner
  1399. //
  1400. // Synopsis: given a path. this function determines if the user is the
  1401. // the owner of the file/folder
  1402. //
  1403. // Arguments: [in] pwszPath
  1404. //
  1405. // Returns: ERROR_SUCCESS if user is owner
  1406. // otherwise an error code
  1407. //
  1408. // History: 10/6/1998 RahulTh created
  1409. //
  1410. // Notes:
  1411. //
  1412. //---------------------------------------------------------------------------
  1413. DWORD CFileDB::IsUserOwner (const WCHAR * pwszPath)
  1414. {
  1415. BOOL bStatus;
  1416. DWORD Status;
  1417. BOOL bIsMember;
  1418. DWORD dwLengthNeeded;
  1419. PSECURITY_DESCRIPTOR pSecDesc = 0;
  1420. PSID pOwnerSid = 0;
  1421. BOOL bDaclDefaulted;
  1422. //first check if we are on FAT. if we are on FAT, then we simply let
  1423. //succeed since FAT cannot have any ACLs anyway
  1424. Status = IsOnNTFS (pwszPath);
  1425. if (ERROR_NO_SECURITY_ON_OBJECT == Status)
  1426. {
  1427. Status = ERROR_SUCCESS; //we are on FAT
  1428. goto UserOwnerEnd;
  1429. }
  1430. else if (ERROR_SUCCESS != Status)
  1431. goto UserOwnerEnd; //there was some other error
  1432. //else we are on NTFS and ready to rumble!
  1433. //get the owner sid from the folder.
  1434. for (dwLengthNeeded = 0;;)
  1435. {
  1436. bStatus = GetFileSecurity (pwszPath, OWNER_SECURITY_INFORMATION,
  1437. pSecDesc, dwLengthNeeded,
  1438. &dwLengthNeeded);
  1439. if (bStatus)
  1440. break; //we have the security descriptor. we are free to leave.
  1441. //GetFileSecurity failed if we are here
  1442. Status = GetLastError();
  1443. if (ERROR_INSUFFICIENT_BUFFER != Status)
  1444. goto UserOwnerEnd;
  1445. //GetFileSecurity failed due to insufficient memory if we are here.
  1446. pSecDesc = NULL;
  1447. pSecDesc = (PSECURITY_DESCRIPTOR) alloca (dwLengthNeeded);
  1448. if (NULL == pSecDesc)
  1449. {
  1450. Status = ERROR_OUTOFMEMORY;
  1451. goto UserOwnerEnd;
  1452. }
  1453. }
  1454. //now get the owner sid
  1455. bStatus = GetSecurityDescriptorOwner (
  1456. pSecDesc,
  1457. &pOwnerSid,
  1458. &bDaclDefaulted);
  1459. if (!bStatus)
  1460. {
  1461. Status = GetLastError();
  1462. }
  1463. else
  1464. {
  1465. if (!pOwnerSid)
  1466. {
  1467. Status = ERROR_INVALID_OWNER;
  1468. }
  1469. else
  1470. {
  1471. bStatus = CheckTokenMembership (_hUserToken, pOwnerSid, &bIsMember);
  1472. if (!bStatus)
  1473. Status = GetLastError();
  1474. else
  1475. {
  1476. if (bIsMember)
  1477. Status = ERROR_SUCCESS;
  1478. else
  1479. Status = ERROR_INVALID_OWNER;
  1480. }
  1481. }
  1482. }
  1483. UserOwnerEnd:
  1484. return Status;
  1485. }
  1486. //+--------------------------------------------------------------------------
  1487. //
  1488. // Member: CFileDB::GetEnvBlock
  1489. //
  1490. // Synopsis: gets a pointer to the user's environment block
  1491. //
  1492. // Arguments: none.
  1493. //
  1494. // Returns: pointer to the user's environment block.
  1495. // NULL if it is not created yet
  1496. //
  1497. // History: 9/20/1999 RahulTh created
  1498. //
  1499. // Notes:
  1500. //
  1501. //---------------------------------------------------------------------------
  1502. PVOID CFileDB::GetEnvBlock (void)
  1503. {
  1504. return _pEnvBlock;
  1505. }
  1506. //+--------------------------------------------------------------------------
  1507. //
  1508. // Member: CFileDB::GetRsopContext
  1509. //
  1510. // Synopsis: gets a pointer to the rsop logging context
  1511. //
  1512. // Arguments: none.
  1513. //
  1514. // Returns: pointer to the rsop logging context -- never null
  1515. //
  1516. //
  1517. // History: 12/8/1999 adamed created
  1518. //
  1519. // Notes:
  1520. //
  1521. //---------------------------------------------------------------------------
  1522. CRsopContext*
  1523. CFileDB::GetRsopContext()
  1524. {
  1525. return _pRsopContext;
  1526. }
  1527. //member functions and data for class CSavedSettings
  1528. //initialize the class's static variables.
  1529. int CSavedSettings::m_idConstructor = 0;
  1530. CFileDB * CSavedSettings::m_pFileDB = NULL;
  1531. WCHAR * CSavedSettings::m_szSavedSettingsPath = NULL;
  1532. //+--------------------------------------------------------------------------
  1533. //
  1534. // Member: CSavedSettings::ResetStaticMembers
  1535. //
  1536. // Synopsis: resets the static members to their default values.
  1537. //
  1538. // Arguments: none
  1539. //
  1540. // Returns: nothing
  1541. //
  1542. // History: 12/17/2000 RahulTh created
  1543. //
  1544. // Notes: static members of a class, like other global variables are
  1545. // initialized only when the dll is loaded. So if this dll
  1546. // stays loaded across logons, then the fact that the globals
  1547. // have been initialized based on a previous logon can cause
  1548. // problems. Therefore, this function is used to reinitialize
  1549. // the globals.
  1550. //
  1551. //---------------------------------------------------------------------------
  1552. void CSavedSettings::ResetStaticMembers(void)
  1553. {
  1554. //
  1555. // No need to delete it. This usually points to a local variable in
  1556. // ProcessGroupPolicyInternal. So the actual object gets deleted when
  1557. // after each processing. We just need to make sure that it is reflected
  1558. // here.
  1559. //
  1560. m_pFileDB = NULL;
  1561. if (m_szSavedSettingsPath)
  1562. {
  1563. delete [] m_szSavedSettingsPath;
  1564. m_szSavedSettingsPath = NULL;
  1565. }
  1566. // No need to do anything about m_idConstructor
  1567. }
  1568. //+--------------------------------------------------------------------------
  1569. //
  1570. // Member: CSavedSettings
  1571. //
  1572. // Synopsis: default constructor for the class.
  1573. //
  1574. // Arguments:
  1575. //
  1576. // Returns:
  1577. //
  1578. // History: 11/18/1998 RahulTh created
  1579. //
  1580. // Notes:
  1581. //
  1582. //---------------------------------------------------------------------------
  1583. CSavedSettings::CSavedSettings ()
  1584. {
  1585. m_rID = (REDIRECTABLE) m_idConstructor;
  1586. m_idConstructor = (m_idConstructor + 1) % ((int) EndRedirectable);
  1587. m_szLastRedirectedPath = NULL;
  1588. m_szCurrentPath = NULL;
  1589. m_szLastUserName = NULL;
  1590. m_szLastHomedir = NULL;
  1591. m_bIsHomedirRedir = FALSE;
  1592. m_bHomedirChanged = FALSE;
  1593. m_dwFlags = REDIR_DONT_CARE; //this is always a safe default
  1594. m_psid = 0;
  1595. m_bValidGPO = FALSE;
  1596. m_bUserNameChanged = FALSE;
  1597. m_szGPOName[0] = L'\0';
  1598. }
  1599. //+--------------------------------------------------------------------------
  1600. //
  1601. // Member: CSavedSettings::ResetMembers
  1602. //
  1603. // Synopsis: Resets the member variables.
  1604. //
  1605. // Arguments: none.
  1606. //
  1607. // Returns: nothing.
  1608. //
  1609. // History: 12/17/2000 RahulTh created
  1610. //
  1611. // Notes: see ResetStaticMembers.
  1612. //
  1613. //---------------------------------------------------------------------------
  1614. void CSavedSettings::ResetMembers(void)
  1615. {
  1616. if (m_szLastRedirectedPath)
  1617. {
  1618. delete [] m_szLastRedirectedPath;
  1619. m_szLastRedirectedPath = NULL;
  1620. }
  1621. if (m_szCurrentPath)
  1622. {
  1623. delete [] m_szCurrentPath;
  1624. m_szCurrentPath = NULL;
  1625. }
  1626. if (m_szLastUserName)
  1627. {
  1628. delete [] m_szLastUserName;
  1629. m_szLastUserName = NULL;
  1630. }
  1631. if (m_szLastHomedir)
  1632. {
  1633. delete [] m_szLastHomedir;
  1634. m_szLastHomedir = NULL;
  1635. }
  1636. if (m_psid)
  1637. {
  1638. RtlFreeSid (m_psid);
  1639. m_psid = NULL;
  1640. }
  1641. m_bHomedirChanged = FALSE;
  1642. m_dwFlags = REDIR_DONT_CARE; //this is always a safe default
  1643. m_bValidGPO = FALSE;
  1644. m_bUserNameChanged = FALSE;
  1645. m_szGPOName[0] = L'\0';
  1646. // No need to do anything about m_rID.
  1647. }
  1648. //+--------------------------------------------------------------------------
  1649. //
  1650. // Member: ~CSavedSettings
  1651. //
  1652. // Synopsis: default destructor
  1653. //
  1654. // Arguments:
  1655. //
  1656. // Returns:
  1657. //
  1658. // History: 11/18/1998 RahulTh created
  1659. //
  1660. // Notes:
  1661. //
  1662. //---------------------------------------------------------------------------
  1663. CSavedSettings::~CSavedSettings ()
  1664. {
  1665. //free static members if necessary
  1666. if (m_szSavedSettingsPath)
  1667. {
  1668. delete [] m_szSavedSettingsPath;
  1669. m_szSavedSettingsPath = NULL; //this is necessary so that the
  1670. //destructor of the next object does
  1671. //not try to free it again
  1672. }
  1673. //
  1674. // Free other memory allocated for members of this object
  1675. // and reset them.
  1676. //
  1677. ResetMembers();
  1678. }
  1679. //+--------------------------------------------------------------------------
  1680. //
  1681. // Member: Load
  1682. //
  1683. // Synopsis: loads the saved settings into the object for its corresponding
  1684. // folder
  1685. //
  1686. // Arguments: none
  1687. //
  1688. // Returns: ERROR_SUCCESS if successful. otherwise an error code
  1689. //
  1690. // History: 11/18/1998 RahulTh created
  1691. //
  1692. // Notes:
  1693. //
  1694. //---------------------------------------------------------------------------
  1695. DWORD CSavedSettings::Load (CFileDB * pFileDB)
  1696. {
  1697. DWORD Status;
  1698. BOOL bStatus;
  1699. DWORD len;
  1700. //first set the FileDB object if it has not already been set
  1701. if (!m_pFileDB)
  1702. m_pFileDB = pFileDB;
  1703. ASSERT (m_pFileDB);
  1704. //get the name of the file where the last settings have been saved
  1705. //if we haven't already done so.
  1706. if (!m_szSavedSettingsPath)
  1707. {
  1708. len = wcslen (pFileDB->_pwszLocalPath) +
  1709. wcslen (SAVED_SETTINGS_FILE) + 2;
  1710. m_szSavedSettingsPath = (WCHAR *) new WCHAR [len];
  1711. if (!m_szSavedSettingsPath)
  1712. {
  1713. Status = ERROR_OUTOFMEMORY;
  1714. goto LoadEnd;
  1715. }
  1716. wcscpy (m_szSavedSettingsPath, pFileDB->_pwszLocalPath);
  1717. wcscat (m_szSavedSettingsPath, L"\\");
  1718. wcscat (m_szSavedSettingsPath, SAVED_SETTINGS_FILE);
  1719. }
  1720. //do a quick check to see if the file exists
  1721. if (0xFFFFFFFF == GetFileAttributes(m_szSavedSettingsPath))
  1722. Status = LoadDefaultLocal ();
  1723. else
  1724. Status = LoadFromIniFile ();
  1725. LoadEnd:
  1726. return Status;
  1727. }
  1728. //+--------------------------------------------------------------------------
  1729. //
  1730. // Member: GetCurrentPath
  1731. //
  1732. // Synopsis: gets the current path of the folder.
  1733. //
  1734. // Arguments: none
  1735. //
  1736. // Returns: ERROR_SUCCESS if successful
  1737. //
  1738. // History: 11/18/1998 RahulTh created
  1739. //
  1740. // Notes:
  1741. //
  1742. //---------------------------------------------------------------------------
  1743. DWORD CSavedSettings::GetCurrentPath (void)
  1744. {
  1745. DWORD Status = ERROR_SUCCESS;
  1746. WCHAR * pwszValueName = 0;
  1747. DWORD Size;
  1748. WCHAR * pwszProcessedPath = NULL;
  1749. if (m_szCurrentPath)
  1750. {
  1751. delete [] m_szCurrentPath;
  1752. m_szCurrentPath = NULL;
  1753. }
  1754. m_szCurrentPath = new WCHAR [MAX_PATH];
  1755. if (!m_szCurrentPath)
  1756. {
  1757. Status = ERROR_OUTOFMEMORY;
  1758. goto GetCurrentPathEnd;
  1759. }
  1760. m_szCurrentPath[0] = L'\0';
  1761. Status = m_pFileDB->GetPathFromFolderName (
  1762. g_szRelativePathNames[(int)m_rID],
  1763. m_szCurrentPath
  1764. );
  1765. if (((DWORD) S_OK != Status) && //if SHGetFolderPath failed, use the local userprofile path
  1766. ERROR_INVALID_NAME != Status) //the only error from GetPathFromFolderName that is not generated by SHGetFolderPath
  1767. {
  1768. Status = ERROR_SUCCESS;
  1769. wcscpy (m_szCurrentPath, L"%USERPROFILE%\\");
  1770. wcscat (m_szCurrentPath, g_szRelativePathNames[(int)m_rID]);
  1771. }
  1772. else
  1773. {
  1774. // expand the homedir path if applicable.
  1775. if (IsHomedirPath (m_rID, m_szCurrentPath, TRUE))
  1776. {
  1777. Status = ExpandHomeDir (m_rID, m_szCurrentPath, TRUE, &pwszProcessedPath);
  1778. delete [] m_szCurrentPath;
  1779. m_szCurrentPath = NULL;
  1780. if (ERROR_SUCCESS == Status)
  1781. {
  1782. m_szCurrentPath = pwszProcessedPath;
  1783. pwszProcessedPath = NULL;
  1784. }
  1785. }
  1786. }
  1787. if (m_szCurrentPath)
  1788. RemoveEndingSlash( m_szCurrentPath );
  1789. GetCurrentPathEnd:
  1790. return Status;
  1791. }
  1792. //+--------------------------------------------------------------------------
  1793. //
  1794. // Member: ResetLastUserName
  1795. //
  1796. // Synopsis: sets the last user name to the current username
  1797. //
  1798. // Arguments: none.
  1799. //
  1800. // Returns: ERROR_SUCCESS : if there is no error.
  1801. // an error code otherwise.
  1802. //
  1803. // History: 9/15/1999 RahulTh created
  1804. //
  1805. // Notes: the most likely cause of failure for this function -- if at all
  1806. // it happens, will be an out of memory condition.
  1807. //
  1808. //---------------------------------------------------------------------------
  1809. DWORD CSavedSettings::ResetLastUserName (void)
  1810. {
  1811. if (m_szLastUserName)
  1812. {
  1813. delete [] m_szLastUserName;
  1814. m_szLastUserName = NULL;
  1815. }
  1816. m_szLastUserName = new WCHAR [wcslen(gwszUserName) + 1];
  1817. if (!m_szLastUserName)
  1818. return ERROR_OUTOFMEMORY;
  1819. wcscpy (m_szLastUserName, gwszUserName);
  1820. m_bUserNameChanged = FALSE;
  1821. return ERROR_SUCCESS;
  1822. }
  1823. //+--------------------------------------------------------------------------
  1824. //
  1825. // Member: LoadDefaultLocal
  1826. //
  1827. // Synopsis: loads the default local userprofile path and default
  1828. // flags into the object
  1829. //
  1830. // Arguments: none
  1831. //
  1832. // Returns: ERROR_SUCCESS if successful an error code otherwise
  1833. //
  1834. // History: 11/18/1998 RahulTh created
  1835. //
  1836. // Notes: the security group is set to Everyone as you can never
  1837. // cease being a member of the group
  1838. //
  1839. // this function is usually invoked when one can't find
  1840. // the ini file that contains the last saved settings or
  1841. // if the ini file does not contain the corresponding section
  1842. //
  1843. //---------------------------------------------------------------------------
  1844. DWORD CSavedSettings::LoadDefaultLocal (void)
  1845. {
  1846. DWORD Status = ERROR_SUCCESS;
  1847. DWORD len;
  1848. // The default case cannot be homedir redirection.
  1849. // Just make sure that our bool has been properly set.
  1850. m_bIsHomedirRedir = FALSE;
  1851. //set the default flags
  1852. m_dwFlags = REDIR_DONT_CARE;
  1853. //to be on the safe side -- set the default values for all members.
  1854. m_bValidGPO = FALSE;
  1855. m_szGPOName[0] = L'\0';
  1856. //set the last username to be the same as the current username
  1857. //since we load the defaults only when we do not have any data about the
  1858. //last logon (i.e., no per user per machine FR cache
  1859. Status = ResetLastUserName ();
  1860. if (ERROR_SUCCESS != Status)
  1861. goto LoadDefaultsEnd;
  1862. //allocate the sid
  1863. //to be on the safe side, free the sid if it has already been allocated
  1864. if (m_psid)
  1865. {
  1866. RtlFreeSid (m_psid);
  1867. m_psid = NULL;
  1868. }
  1869. Status = AllocateAndInitSidFromString (L"S-1-1-0", &m_psid);
  1870. if (ERROR_SUCCESS != Status)
  1871. {
  1872. m_psid = 0;
  1873. goto LoadDefaultsEnd;
  1874. }
  1875. //get the last redirected path
  1876. //again, to be on the safe side, free any used memory first
  1877. if (m_szLastRedirectedPath)
  1878. {
  1879. delete [] m_szLastRedirectedPath;
  1880. m_szLastRedirectedPath = NULL;
  1881. }
  1882. len = wcslen (L"%USERPROFILE%\\") +
  1883. wcslen (g_szRelativePathNames[(int)m_rID]) + 1;
  1884. m_szLastRedirectedPath = new WCHAR [len];
  1885. if (!m_szLastRedirectedPath)
  1886. {
  1887. Status = ERROR_OUTOFMEMORY;
  1888. goto LoadDefaultsEnd;
  1889. }
  1890. wcscpy (m_szLastRedirectedPath, L"%USERPROFILE%\\");
  1891. wcscat (m_szLastRedirectedPath, g_szRelativePathNames[(int)m_rID]);
  1892. //get the current path
  1893. Status = GetCurrentPath();
  1894. LoadDefaultsEnd:
  1895. return Status;
  1896. }
  1897. //+--------------------------------------------------------------------------
  1898. //
  1899. // Member: LoadFromIniFile
  1900. //
  1901. // Synopsis: this function loads redirection info. from the ini file
  1902. // that contains the last saved settings.
  1903. // file.
  1904. //
  1905. // Arguments: none
  1906. //
  1907. // Returns: ERROR_SUCCESS if everything is successful. an error code otherwise
  1908. //
  1909. // History: 11/18/1998 RahulTh created
  1910. //
  1911. // Notes: if this function cannot find the corresponding section in the
  1912. // ini file, it loads the default local path
  1913. //
  1914. //---------------------------------------------------------------------------
  1915. DWORD CSavedSettings::LoadFromIniFile (void)
  1916. {
  1917. DWORD Status = ERROR_SUCCESS;
  1918. WCHAR pwszDefault[] = L"*";
  1919. WCHAR * pwszReturnedString = NULL;
  1920. WCHAR * pwszProcessedPath = NULL;
  1921. DWORD retVal;
  1922. DWORD Size;
  1923. UNICODE_STRING StringW;
  1924. GUID GPOGuid;
  1925. //
  1926. // If this object contains the MyDocs settings, get the last value
  1927. // of homedir
  1928. //
  1929. if (MyDocs == m_rID || MyPics == m_rID)
  1930. {
  1931. Status = SafeGetPrivateProfileStringW (
  1932. g_szDisplayNames [(int) m_rID],
  1933. L"Homedir",
  1934. pwszDefault,
  1935. &m_szLastHomedir,
  1936. &Size,
  1937. m_szSavedSettingsPath);
  1938. if (ERROR_SUCCESS != Status)
  1939. goto LoadIniEnd;
  1940. if (L'*' == *m_szLastHomedir)
  1941. {
  1942. // The value of homedir at the last redirection was not found.
  1943. delete [] m_szLastHomedir;
  1944. m_szLastHomedir = NULL;
  1945. }
  1946. }
  1947. //first try to get the user name when the user had last logged on.
  1948. Status = SafeGetPrivateProfileStringW (
  1949. g_szDisplayNames [(int) m_rID],
  1950. L"Username",
  1951. pwszDefault,
  1952. &m_szLastUserName,
  1953. &Size,
  1954. m_szSavedSettingsPath);
  1955. if (ERROR_SUCCESS != Status)
  1956. goto LoadIniEnd;
  1957. if (L'*' == *m_szLastUserName)
  1958. {
  1959. //the username field was not found in the ini file. must be an older
  1960. //cache. since we do not have the information, we just use the defaults,
  1961. //i.e. set the current user name as the last user name
  1962. Status = ResetLastUserName();
  1963. if (ERROR_SUCCESS != Status)
  1964. goto LoadIniEnd;
  1965. }
  1966. else
  1967. {
  1968. //we found a user name in the local cache.
  1969. //update the member variable which indicates whether the user name
  1970. //has changed since the last logon.
  1971. if (0 == _wcsicmp (m_szLastUserName, gwszUserName))
  1972. m_bUserNameChanged = FALSE;
  1973. else
  1974. m_bUserNameChanged = TRUE;
  1975. }
  1976. //then try to get the path
  1977. Status = SafeGetPrivateProfileStringW (
  1978. g_szDisplayNames [(int) m_rID],
  1979. L"Path",
  1980. pwszDefault,
  1981. &m_szLastRedirectedPath,
  1982. &Size,
  1983. m_szSavedSettingsPath);
  1984. if (ERROR_SUCCESS != Status)
  1985. goto LoadIniEnd;
  1986. if (L'*' == *m_szLastRedirectedPath) //we could not find the required data.
  1987. {
  1988. //so we go with the defaults
  1989. Status = LoadDefaultLocal();
  1990. goto LoadIniEnd;
  1991. }
  1992. else if (IsHomedirPath (m_rID, m_szLastRedirectedPath, TRUE))
  1993. {
  1994. Status = ExpandHomeDir (m_rID,
  1995. m_szLastRedirectedPath,
  1996. TRUE,
  1997. &pwszProcessedPath,
  1998. m_szLastHomedir
  1999. );
  2000. delete [] m_szLastRedirectedPath;
  2001. if (ERROR_SUCCESS != Status)
  2002. {
  2003. m_szLastRedirectedPath = NULL;
  2004. goto LoadIniEnd;
  2005. }
  2006. else
  2007. {
  2008. m_bIsHomedirRedir = TRUE;
  2009. m_szLastRedirectedPath = pwszProcessedPath;
  2010. pwszProcessedPath = NULL;
  2011. }
  2012. }
  2013. //next try to get the security group
  2014. Status = SafeGetPrivateProfileStringW (
  2015. g_szDisplayNames[(int)m_rID],
  2016. L"Group",
  2017. pwszDefault,
  2018. &pwszReturnedString,
  2019. &Size,
  2020. m_szSavedSettingsPath
  2021. );
  2022. if (ERROR_SUCCESS != Status)
  2023. goto LoadIniEnd;
  2024. if (L'*' == *pwszReturnedString)
  2025. {
  2026. //data was missing, so go with the defaults
  2027. Status = LoadDefaultLocal();
  2028. goto LoadIniEnd;
  2029. }
  2030. if (m_psid)
  2031. {
  2032. RtlFreeSid (m_psid);
  2033. m_psid = NULL;
  2034. }
  2035. Status = AllocateAndInitSidFromString (pwszReturnedString, &m_psid);
  2036. if (ERROR_SUCCESS != Status)
  2037. {
  2038. m_psid = 0;
  2039. goto LoadIniEnd;
  2040. }
  2041. //now get the flags
  2042. Status = SafeGetPrivateProfileStringW (
  2043. g_szDisplayNames[(int)m_rID],
  2044. L"Flags",
  2045. pwszDefault,
  2046. &pwszReturnedString,
  2047. &Size,
  2048. m_szSavedSettingsPath
  2049. );
  2050. if (ERROR_SUCCESS != Status)
  2051. goto LoadIniEnd;
  2052. if (L'*' == *pwszReturnedString)
  2053. {
  2054. Status = LoadDefaultLocal();
  2055. goto LoadIniEnd;
  2056. }
  2057. //now grab the hex flags
  2058. StringW.Buffer = pwszReturnedString;
  2059. StringW.Length = wcslen (pwszReturnedString) * sizeof (WCHAR);
  2060. StringW.MaximumLength = StringW.Length + sizeof(WCHAR);
  2061. RtlUnicodeStringToInteger( &StringW, 16, &m_dwFlags );
  2062. //now get the unique name of the GPO (if any) that was used to redirect the folder
  2063. Status = SafeGetPrivateProfileStringW (
  2064. g_szDisplayNames[(int) m_rID],
  2065. L"GPO",
  2066. pwszDefault,
  2067. &pwszReturnedString,
  2068. &Size,
  2069. m_szSavedSettingsPath
  2070. );
  2071. if (ERROR_SUCCESS != Status)
  2072. goto LoadIniEnd;
  2073. StringW.Length = sizeof (WCHAR) * wcslen (pwszReturnedString);
  2074. StringW.MaximumLength = (USHORT)(sizeof(WCHAR) * Size);
  2075. StringW.Buffer = pwszReturnedString;
  2076. if ((L'*' == *pwszReturnedString) || //there is no valid GPO info., or
  2077. (sizeof(m_szGPOName) <= wcslen(pwszReturnedString)) || //the file has been corrupted. the length of a valid unique name cannot exceed the size of m_szGPO, or
  2078. (STATUS_INVALID_PARAMETER == RtlGUIDFromString (&StringW, &GPOGuid)) //it is not a valid GUID
  2079. )
  2080. {
  2081. //there is no valid GPO info.
  2082. m_bValidGPO = FALSE;
  2083. m_szGPOName[0] = L'\0';
  2084. }
  2085. else
  2086. {
  2087. m_bValidGPO = TRUE;
  2088. wcscpy (m_szGPOName, pwszReturnedString);
  2089. }
  2090. //get the current path.
  2091. Status = GetCurrentPath ();
  2092. LoadIniEnd:
  2093. if (pwszReturnedString)
  2094. delete [] pwszReturnedString;
  2095. if (pwszProcessedPath)
  2096. delete [] pwszProcessedPath;
  2097. return Status;
  2098. }
  2099. //+--------------------------------------------------------------------------
  2100. //
  2101. // Member: NeedsProcessing
  2102. //
  2103. // Synopsis: once the saved settings and the registry values have been
  2104. // loaded, this function determines if we need to look at all the
  2105. // policies. Note that this assumes that the GPO_NOCHANGES flag
  2106. // has already been set by the policy engine
  2107. //
  2108. // Arguments: none
  2109. //
  2110. // Returns: TRUE / FALSE
  2111. //
  2112. // History: 11/18/1998 RahulTh created
  2113. //
  2114. // Notes:
  2115. //
  2116. //---------------------------------------------------------------------------
  2117. BOOL CSavedSettings::NeedsProcessing (void)
  2118. {
  2119. BOOL bStatus;
  2120. DWORD i;
  2121. DWORD Status;
  2122. PTOKEN_GROUPS pGroups;
  2123. WCHAR wszExpandedPath [TARGETPATHLIMIT + 1];
  2124. UNICODE_STRING Path;
  2125. UNICODE_STRING ExpandedPath;
  2126. const WCHAR * pwszCurrentHomedir = NULL;
  2127. WCHAR wszProcessedSource [TARGETPATHLIMIT + 1];
  2128. WCHAR wszProcessedDest [TARGETPATHLIMIT + 1];
  2129. int len;
  2130. //if policy didn't care about the location of the folder at last logon
  2131. //then even if the last redirected path is not the same as the current
  2132. //path, it should not mean that that we need to reprocess the policy
  2133. //when the GPO_NOCHANGES flag has been provided
  2134. if (m_dwFlags & REDIR_DONT_CARE)
  2135. return FALSE;
  2136. //if we are here, policy specified the location of the folder at the
  2137. //the last logon. make sure that the user name has not changed since
  2138. //last logon. If so, we need to process the policies again and move
  2139. //the user's folders accordingly.
  2140. if (m_bUserNameChanged)
  2141. return TRUE;
  2142. //
  2143. // If we are here, the username had not changed, but if the homedir
  2144. // changed, that can affect the path.
  2145. // Note: Here, we cannot use the IsHomedirPath function to determine
  2146. // if this is a homedir redirection since we would have already expanded
  2147. // the path in LoadFromIniFile. Therefore, we must use m_bIsHomedirRedir
  2148. //
  2149. if (m_bIsHomedirRedir)
  2150. {
  2151. //
  2152. // Note: GetHomeDir is an expensive call since it can result
  2153. // in a call to the DS to get the user's home directory. So we try to
  2154. // be as lazy as possible about executing it.
  2155. //
  2156. pwszCurrentHomedir = gUserInfo.GetHomeDir (Status);
  2157. if (ERROR_SUCCESS != Status ||
  2158. ! pwszCurrentHomedir ||
  2159. ! m_szLastHomedir ||
  2160. 0 != lstrcmpi (m_szLastHomedir, pwszCurrentHomedir))
  2161. {
  2162. m_bHomedirChanged = TRUE;
  2163. return TRUE;
  2164. }
  2165. }
  2166. //check if the last redirected path and current path are identical
  2167. if (0 != _wcsicmp(m_szLastRedirectedPath, m_szCurrentPath))
  2168. {
  2169. //the paths are different. we need to do processing
  2170. //even if the policy engine thinks otherwise
  2171. //but sometimes we may have an expanded path in m_szCurrentPath
  2172. //e.g. if some User Shell Folder values are missing. So expand
  2173. //the last redirected path and compare it with the current path
  2174. Path.Length = (wcslen (m_szLastRedirectedPath) + 1) * sizeof (WCHAR);
  2175. Path.MaximumLength = sizeof (m_szLastRedirectedPath);
  2176. Path.Buffer = m_szLastRedirectedPath;
  2177. ExpandedPath.Length = 0;
  2178. ExpandedPath.MaximumLength = sizeof (wszExpandedPath);
  2179. ExpandedPath.Buffer = wszExpandedPath;
  2180. Status = RtlExpandEnvironmentStrings_U (
  2181. m_pFileDB->_pEnvBlock,
  2182. &Path,
  2183. &ExpandedPath,
  2184. NULL
  2185. );
  2186. if (ERROR_SUCCESS != Status)
  2187. return TRUE; //that's our best bet in case of failure
  2188. //
  2189. // Now process the paths so that they do not contain any redundant
  2190. // slashes etc.
  2191. //
  2192. if (NULL == _wfullpath (wszProcessedSource, m_szCurrentPath, MAX_PATH))
  2193. {
  2194. return TRUE;
  2195. }
  2196. else
  2197. {
  2198. //
  2199. // Eliminate any trailing slashes. Note: after going through
  2200. // _wfullpath, there can be at the most one trailing slash
  2201. //
  2202. len = lstrlen (wszProcessedSource);
  2203. if (L'\\' == wszProcessedSource[len-1])
  2204. wszProcessedSource[len - 1] = L'\0';
  2205. }
  2206. if (NULL == _wfullpath (wszProcessedDest, wszExpandedPath, MAX_PATH))
  2207. {
  2208. return TRUE;
  2209. }
  2210. else
  2211. {
  2212. //
  2213. // Eliminate any trailing slashes. Note: after going through
  2214. // _wfullpath, there can be at the most one trailing slash
  2215. //
  2216. len = lstrlen (wszProcessedDest);
  2217. if (L'\\' == wszProcessedDest[len-1])
  2218. wszProcessedDest[len - 1] = L'\0';
  2219. }
  2220. // Now that we have the nice compact paths, we compare them.
  2221. if (0 != _wcsicmp (wszProcessedSource, wszProcessedDest))
  2222. return TRUE;
  2223. }
  2224. return FALSE;
  2225. }
  2226. //+--------------------------------------------------------------------------
  2227. //
  2228. // Member: Save
  2229. //
  2230. // Synopsis: saves settings back to the local settings
  2231. //
  2232. // Arguments: [in] pwszPath : the path to which the folder was redirected
  2233. // [in] dwFlags : the flags that were used for redirection
  2234. // [in] pSid : the Sid of the group that was used for
  2235. // redirection. If this is NULL, then we
  2236. // default to the Sid for everyone : S-1-1-0
  2237. //
  2238. // Returns: ERROR_SUCCESS if everything was successful or an error code.
  2239. //
  2240. // History: 11/20/1998 RahulTh created
  2241. //
  2242. // Notes:
  2243. //
  2244. //---------------------------------------------------------------------------
  2245. DWORD CSavedSettings::Save (const WCHAR * pwszPath, DWORD dwFlags, PSID pSid, const WCHAR * pszGPOName)
  2246. {
  2247. WCHAR * pwszSection = NULL;
  2248. UNICODE_STRING StringW;
  2249. WCHAR pwszFlags [ MAX_PATH ];
  2250. UINT len;
  2251. int homedirInfoLen = 0;
  2252. WCHAR * pszCurr;
  2253. WCHAR pwszSid [ MAX_PATH ];
  2254. DWORD Status;
  2255. BOOL bStatus;
  2256. ULONG ulUserNameInfoLen;
  2257. const WCHAR * wszHomedir = NULL;
  2258. BOOL bSaveHomedir = FALSE;
  2259. //
  2260. // First determine if the homedir value needs to be saved.
  2261. // We need to do this first so that we can add the necessary value to the
  2262. // buffer.
  2263. if (IsHomedirPath (m_rID, pwszPath, TRUE) ||
  2264. IsHomedirPolicyPath (m_rID, pwszPath, TRUE))
  2265. {
  2266. wszHomedir = gUserInfo.GetHomeDir (Status);
  2267. if (ERROR_SUCCESS != Status ||
  2268. ! wszHomedir ||
  2269. L'\0' == *wszHomedir)
  2270. {
  2271. Status = (ERROR_SUCCESS == Status) ? ERROR_BAD_PATHNAME : Status;
  2272. goto SaveSettings_End;
  2273. }
  2274. // If we are here, then we need to save the homedir value
  2275. bSaveHomedir = TRUE;
  2276. homedirInfoLen = wcslen (wszHomedir) + 9; // 8 chars for Homedir=
  2277. // + 1 for the terminating NULL
  2278. }
  2279. //caclulate the # of characters required to store UserName=<username>
  2280. //including the terminating NULL character.
  2281. ulUserNameInfoLen = wcslen (gwszUserName) + 10; //9 chars for Username=
  2282. //+ 1 terminating NULL
  2283. //don't need to calculate the exact length, this will be more than enough
  2284. pwszSection = new WCHAR[sizeof(WCHAR) * ((len = wcslen(pwszPath)) +
  2285. homedirInfoLen +
  2286. 2 * MAX_PATH +
  2287. ulUserNameInfoLen +
  2288. 50)];
  2289. if (NULL == pwszSection)
  2290. {
  2291. Status = ERROR_OUTOFMEMORY;
  2292. goto SaveSettings_End;
  2293. }
  2294. pwszFlags[0] = L'\0';
  2295. StringW.Length = 0;
  2296. StringW.MaximumLength = sizeof (pwszFlags);
  2297. StringW.Buffer = pwszFlags;
  2298. RtlIntegerToUnicodeString (dwFlags, 16, &StringW);
  2299. wcscpy (pwszSection, L"Username=");
  2300. wcscat (pwszSection, gwszUserName);
  2301. pszCurr = pwszSection + ulUserNameInfoLen;
  2302. // Save the homedir value only if the redirection destination is the homedir.
  2303. if (bSaveHomedir)
  2304. {
  2305. wcscpy (pszCurr, L"Homedir=");
  2306. wcscat (pszCurr, wszHomedir);
  2307. pszCurr += homedirInfoLen;
  2308. }
  2309. wcscpy (pszCurr, L"Path=");
  2310. if (IsHomedirPolicyPath (m_rID, pwszPath, TRUE))
  2311. {
  2312. wcscat (pszCurr, &pwszPath[2]);
  2313. pszCurr += 6 + (len - 2);
  2314. }
  2315. else
  2316. {
  2317. wcscat (pszCurr, pwszPath);
  2318. pszCurr += 6 + len;
  2319. }
  2320. wcscpy (pszCurr, L"Flags=");
  2321. wcscat (pszCurr, pwszFlags);
  2322. pszCurr += (7 + StringW.Length/sizeof(WCHAR));
  2323. wcscpy (pszCurr, L"Group=");
  2324. //now we set the sid to everyone (that is the safest) if no sid has been
  2325. //specified or if we are unable to convert the supplied sid into a string.
  2326. Status = ERROR_INVALID_SID; //just some error code
  2327. if (pSid)
  2328. {
  2329. pwszSid [0] = L'\0';
  2330. StringW.Length = 0;
  2331. StringW.MaximumLength = sizeof (pwszSid);
  2332. StringW.Buffer = pwszSid;
  2333. Status = RtlConvertSidToUnicodeString (&StringW, pSid, FALSE);
  2334. }
  2335. if (ERROR_SUCCESS != Status)
  2336. wcscpy (pwszSid, L"S-1-1-0"); //use the sid for everyone if we can't find anything else
  2337. wcscat (pszCurr, pwszSid);
  2338. //add an extra terminating NULL
  2339. pszCurr += (7 + wcslen (pwszSid));
  2340. //add the GPO if there is a valid one.
  2341. if (pszGPOName)
  2342. {
  2343. wcscpy (pszCurr, L"GPO=");
  2344. wcscat (pszCurr, pszGPOName);
  2345. pszCurr += (5 + wcslen (pszGPOName));
  2346. }
  2347. //add an extra null character at the end.
  2348. *pszCurr = L'\0';
  2349. //before writing to the ini file, we must pre-create it in Unicode,
  2350. //otherwise, the WritePrivate* APIs will write the file in ANSI, which
  2351. //will break folder redirection in international/ML builds.
  2352. PrecreateUnicodeIniFile (m_szSavedSettingsPath);
  2353. Status = ERROR_SUCCESS;
  2354. //now we can go ahead and save the section
  2355. //first empty the section
  2356. bStatus = WritePrivateProfileSection (
  2357. g_szDisplayNames[(int) m_rID],
  2358. NULL,
  2359. m_szSavedSettingsPath
  2360. );
  2361. //now write the actual section
  2362. if (bStatus)
  2363. bStatus = WritePrivateProfileSection (
  2364. g_szDisplayNames[(int) m_rID],
  2365. pwszSection,
  2366. m_szSavedSettingsPath
  2367. );
  2368. if (!bStatus)
  2369. Status = GetLastError();
  2370. SaveSettings_End:
  2371. if (pwszSection)
  2372. delete [] pwszSection;
  2373. return Status;
  2374. }
  2375. //+--------------------------------------------------------------------------
  2376. //
  2377. // Member: CSavedSettings::HandleUserNameChange
  2378. //
  2379. // Synopsis: this function handles any changes in the user name that
  2380. // have occurred since the last logon. in case the username has
  2381. // changed since the last logon, this function renames any
  2382. // folders redirected earlier using the %username% variable so
  2383. // that the path that the redirected folder points to is continues
  2384. // to be valid.
  2385. //
  2386. // Arguments: [in] pFileDB : point to the CFileDB object.
  2387. //
  2388. // Returns: ERROR_SUCCESS if everything worked properly
  2389. // an error code otherwise.
  2390. //
  2391. // History: 9/20/1999 RahulTh created
  2392. //
  2393. // Notes: a failed rename is not considered a failure. in this case,
  2394. // an event is logged and the code ensures that redirection
  2395. // is not attempted if there is a simultaneous change in the
  2396. // redirection policies.
  2397. //
  2398. // in this way a failed rename for one folder does not hold up
  2399. // the redirection of other folders which might be independent of
  2400. // this particular folder.
  2401. //---------------------------------------------------------------------------
  2402. DWORD CSavedSettings::HandleUserNameChange (CFileDB * pFileDB,
  2403. CRedirectInfo * pRedir)
  2404. {
  2405. BOOL bStatus;
  2406. DWORD Status = ERROR_SUCCESS;
  2407. DWORD RedirStatus = ERROR_SUCCESS;
  2408. WCHAR wszLastPath [TARGETPATHLIMIT];
  2409. WCHAR wszExpandedSource [TARGETPATHLIMIT];
  2410. WCHAR wszExpandedDest [TARGETPATHLIMIT];
  2411. WCHAR wszRenamePart [TARGETPATHLIMIT];
  2412. WCHAR wszExpandedRenameSource [TARGETPATHLIMIT];
  2413. WCHAR wszExpandedRenameDest [TARGETPATHLIMIT];
  2414. WCHAR * wszTemp = NULL;
  2415. WCHAR * wszEnd = NULL;
  2416. SHARESTATUS SourceStatus;
  2417. SHARESTATUS DestStatus;
  2418. BOOL bRenamePerformed = FALSE;
  2419. if ((! m_bUserNameChanged) ||
  2420. pRedir->WasRedirectionAttempted() ||
  2421. (REDIR_DONT_CARE & m_dwFlags))
  2422. {
  2423. goto HandleUPNChangeEnd;//nothing to do if the username has not changed
  2424. //since the last logon or if the rename has
  2425. //already been attempted. Even if the attempted
  2426. //redirection had failed, it is not fatal.
  2427. //similarly, if policy didn't set the location
  2428. //of the folder last time, we don't care.
  2429. }
  2430. if (Programs == m_rID || //since programs and startup always follow the
  2431. Startup == m_rID //Start Menu, rename of Start Menu handles these
  2432. //folders automatically
  2433. )
  2434. {
  2435. goto HandleUPNChangeEnd;
  2436. }
  2437. //show additional status messages if the verbose status is on.
  2438. DisplayStatusMessage (IDS_REDIR_CALLBACK);
  2439. DebugMsg ((DM_VERBOSE, IDS_UPN_CHANGE, pRedir->GetLocalizedName(), m_szLastUserName, gwszUserName));
  2440. //okay, so there is a change in the user name and policy did care about the
  2441. //the location. check if last path contained the username. if not, we have
  2442. //nothing more to do.
  2443. if (TARGETPATHLIMIT <= wcslen (m_szLastRedirectedPath))
  2444. {
  2445. gpEvents->Report (
  2446. EVENT_FDEPLOY_DESTPATH_TOO_LONG,
  2447. 3,
  2448. pRedir->GetLocalizedName(),
  2449. m_szLastRedirectedPath,
  2450. NumberToString ( TARGETPATHLIMIT )
  2451. );
  2452. pRedir->PreventRedirection (STATUS_BUFFER_TOO_SMALL);
  2453. goto HandleUPNChangeEnd;
  2454. }
  2455. wcscpy (wszLastPath, m_szLastRedirectedPath);
  2456. _wcslwr (wszLastPath);
  2457. wszTemp = wcsstr (wszLastPath, L"%username%");
  2458. if (NULL == wszTemp)
  2459. goto HandleUPNChangeEnd; //there is no %username% string, we are
  2460. //done. no rename is required.
  2461. //get the part that needs to be renamed.
  2462. wcscpy (wszRenamePart, wszLastPath);
  2463. wszEnd = wcschr (wszRenamePart + (wszTemp - wszLastPath), L'\\');
  2464. if (wszEnd)
  2465. *wszEnd = L'\0';
  2466. //get expanded versions of the paths -- using the new username and the old
  2467. //username
  2468. wszTemp = wszLastPath;
  2469. RedirStatus = ExpandPathSpecial (pFileDB, wszLastPath, m_szLastUserName, wszExpandedSource);
  2470. if (ERROR_SUCCESS == RedirStatus)
  2471. {
  2472. RedirStatus = ExpandPathSpecial (pFileDB, wszLastPath, gwszUserName, wszExpandedDest);
  2473. }
  2474. if (ERROR_SUCCESS == RedirStatus)
  2475. {
  2476. wszTemp = wszRenamePart;
  2477. RedirStatus = ExpandPathSpecial (pFileDB, wszRenamePart, m_szLastUserName, wszExpandedRenameSource);
  2478. }
  2479. if (ERROR_SUCCESS == RedirStatus)
  2480. {
  2481. RedirStatus = ExpandPathSpecial (pFileDB, wszRenamePart, gwszUserName, wszExpandedRenameDest);
  2482. }
  2483. if (STATUS_BUFFER_TOO_SMALL == RedirStatus)
  2484. {
  2485. gpEvents->Report (
  2486. EVENT_FDEPLOY_DESTPATH_TOO_LONG,
  2487. 3,
  2488. pRedir->GetLocalizedName(),
  2489. wszTemp,
  2490. NumberToString ( TARGETPATHLIMIT )
  2491. );
  2492. pRedir->PreventRedirection (STATUS_BUFFER_TOO_SMALL);
  2493. goto HandleUPNChangeEnd;
  2494. }
  2495. else if (ERROR_SUCCESS != RedirStatus)
  2496. {
  2497. gpEvents->Report (
  2498. EVENT_FDEPLOY_FOLDER_EXPAND_FAIL,
  2499. 2,
  2500. pRedir->GetLocalizedName(),
  2501. StatusToString ( RedirStatus )
  2502. );
  2503. pRedir->PreventRedirection (RedirStatus);
  2504. goto HandleUPNChangeEnd;
  2505. }
  2506. //get the online/offline status of the shares.
  2507. SourceStatus = GetCSCStatus (wszExpandedRenameSource);
  2508. DestStatus = GetCSCStatus (wszExpandedRenameDest);
  2509. if (ShareOffline == Status || ShareOffline == DestStatus)
  2510. {
  2511. gpEvents->Report (
  2512. EVENT_FDEPLOY_FOLDER_OFFLINE,
  2513. 3,
  2514. pRedir->GetLocalizedName(),
  2515. wszExpandedSource,
  2516. wszExpandedDest
  2517. );
  2518. pRedir->PreventRedirection (ERROR_CSCSHARE_OFFLINE);
  2519. goto HandleUPNChangeEnd;
  2520. }
  2521. //we are finally ready to rename. first make sure that the source exists.
  2522. //sometimes an earlier rename operation might have already renamed this
  2523. //folder
  2524. RedirStatus = ERROR_SUCCESS;
  2525. if (0xFFFFFFFF == GetFileAttributes(wszExpandedRenameSource))
  2526. {
  2527. RedirStatus = GetLastError();
  2528. }
  2529. if (ERROR_FILE_NOT_FOUND != RedirStatus)
  2530. {
  2531. bStatus = MoveFile (wszExpandedRenameSource, wszExpandedRenameDest);
  2532. if (!bStatus)
  2533. {
  2534. RedirStatus = GetLastError();
  2535. gpEvents->Report (
  2536. EVENT_FDEPLOY_REDIRECT_FAIL,
  2537. 4,
  2538. pRedir->GetLocalizedName(),
  2539. StatusToString (RedirStatus),
  2540. wszExpandedSource,
  2541. wszExpandedDest
  2542. );
  2543. pRedir->PreventRedirection (RedirStatus);
  2544. goto HandleUPNChangeEnd;
  2545. }
  2546. }
  2547. //the rename was successful. now rename the CSC cache.
  2548. if (ShareOnline == SourceStatus)
  2549. {
  2550. MoveDirInCSC (wszExpandedSource, wszExpandedDest, NULL, SourceStatus, DestStatus, TRUE, TRUE);
  2551. DeleteCSCShareIfEmpty (wszExpandedSource, SourceStatus);
  2552. }
  2553. bRenamePerformed = TRUE;
  2554. HandleUPNChangeEnd:
  2555. if (m_bUserNameChanged && ERROR_SUCCESS == pRedir->GetRedirStatus())
  2556. {
  2557. UpdateUserNameInCache();
  2558. if (bRenamePerformed)
  2559. {
  2560. gpEvents->Report(
  2561. EVENT_FDEPLOY_FOLDER_REDIRECT,
  2562. 3,
  2563. pRedir->GetLocalizedName(),
  2564. wszExpandedSource,
  2565. wszExpandedDest);
  2566. }
  2567. }
  2568. return Status;
  2569. }
  2570. //+--------------------------------------------------------------------------
  2571. //
  2572. // Member: CSavedSettings::UpdateUserNameInCache
  2573. //
  2574. // Synopsis: updates the user name in the cache with the new username
  2575. //
  2576. // Arguments: none.
  2577. //
  2578. // Returns: ERROR_SUCCESS : if successful.
  2579. // an error code otherwise.
  2580. //
  2581. // History: 9/20/1999 RahulTh created
  2582. //
  2583. // Notes:
  2584. //
  2585. //---------------------------------------------------------------------------
  2586. DWORD CSavedSettings::UpdateUserNameInCache (void)
  2587. {
  2588. BOOL bStatus;
  2589. bStatus = WritePrivateProfileString (
  2590. g_szDisplayNames[(int) m_rID],
  2591. L"UserName",
  2592. gwszUserName,
  2593. m_szSavedSettingsPath
  2594. );
  2595. if (!bStatus)
  2596. return GetLastError();
  2597. return ERROR_SUCCESS;
  2598. }