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.

2581 lines
91 KiB

  1. /*++
  2. Microsoft Windows
  3. Copyright (C) Microsoft Corporation, 1981 - 1998
  4. Module Name:
  5. redir.cxx
  6. Abstract:
  7. This module contains the implementation for the members of the class
  8. CRedirInfo which is used to consolidate redirection information from all
  9. the policies applied to a particular GPO and then finally do the redirection
  10. for the policy with the highest precedence.
  11. Author:
  12. Rahul Thombre (RahulTh) 8/11/1998
  13. Revision History:
  14. 8/11/1998 RahulTh Created this module.
  15. --*/
  16. #include "fdeploy.hxx"
  17. //initialize some global variables
  18. WCHAR * g_szRelativePathNames[] =
  19. {
  20. L"Desktop",
  21. L"My Documents",
  22. L"My Documents\\My Pictures",
  23. L"Start Menu",
  24. L"Start Menu\\Programs",
  25. L"Start Menu\\Programs\\Startup",
  26. L"Application Data"
  27. };
  28. WCHAR * g_szDisplayNames[] =
  29. {
  30. L"Desktop",
  31. L"My Documents",
  32. L"My Pictures",
  33. L"Start Menu",
  34. L"Programs",
  35. L"Startup",
  36. L"Application Data"
  37. };
  38. //above: use the same order and elements as in REDIRECTABLE
  39. //global variables.
  40. const int g_lRedirInfoSize = (int) EndRedirectable;
  41. //static members of the class
  42. int CRedirectInfo::m_idConstructor = 0;
  43. CRedirectInfo gPolicyResultant [g_lRedirInfoSize];
  44. CRedirectInfo gDeletedPolicyResultant [g_lRedirInfoSize];
  45. CRedirectInfo gAddedPolicyResultant [g_lRedirInfoSize];
  46. //+--------------------------------------------------------------------------
  47. //
  48. // Member: CRedirectInfo::CRedirectInfo
  49. //
  50. // Synopsis: Constructor for the class
  51. //
  52. // Arguments:
  53. //
  54. // Returns:
  55. //
  56. // History: 8/11/1998 RahulTh created
  57. //
  58. // Notes:
  59. //
  60. //---------------------------------------------------------------------------
  61. CRedirectInfo::CRedirectInfo ()
  62. {
  63. m_rID = (REDIRECTABLE)(m_idConstructor); //assign IDs sequentially.
  64. m_idConstructor = (m_idConstructor + 1) % ((int)EndRedirectable);
  65. m_pSid = NULL;
  66. m_szLocation = NULL;
  67. m_cbLocSize = 0;
  68. m_szGroupRedirectionData = NULL;
  69. ResetMembers ();
  70. }
  71. //+--------------------------------------------------------------------------
  72. //
  73. // Member: CRedirectInfo::~CRedirectInfo
  74. //
  75. // Synopsis: destructor
  76. //
  77. // Arguments:
  78. //
  79. // Returns:
  80. //
  81. // History: 10/6/1998 RahulTh created
  82. //
  83. // Notes:
  84. //
  85. //---------------------------------------------------------------------------
  86. CRedirectInfo::~CRedirectInfo ()
  87. {
  88. FreeAllocatedMem ();
  89. }
  90. //+--------------------------------------------------------------------------
  91. //
  92. // Member: CRedirectInfo::FreeAllocatedMem
  93. //
  94. // Synopsis: frees memory allocated for member vars.
  95. //
  96. // Arguments: none.
  97. //
  98. // Returns: nothing.
  99. //
  100. // History: 12/17/2000 RahulTh created
  101. //
  102. // Notes:
  103. //
  104. //---------------------------------------------------------------------------
  105. void CRedirectInfo::FreeAllocatedMem (void)
  106. {
  107. if (m_szLocation)
  108. {
  109. delete [] m_szLocation;
  110. m_szLocation = NULL;
  111. m_cbLocSize = 0;
  112. }
  113. if (m_pSid)
  114. {
  115. delete [] ((BYTE *)m_pSid);
  116. m_pSid = NULL;
  117. }
  118. if (m_szGroupRedirectionData)
  119. {
  120. delete [] m_szGroupRedirectionData;
  121. m_szGroupRedirectionData = NULL;
  122. }
  123. }
  124. //+--------------------------------------------------------------------------
  125. //
  126. // Member: CRedirectInfo::ResetMembers
  127. //
  128. // Synopsis: resets the members of the class to their default values.
  129. //
  130. // Arguments: none.
  131. //
  132. // Returns: nothing.
  133. //
  134. // History: 12/17/2000 RahulTh created
  135. //
  136. // Notes: static members of a class, like other global variables are
  137. // initialized only when the dll is loaded. So if this dll
  138. // stays loaded across logons, then the fact that the globals
  139. // have been initialized based on a previous logon can cause
  140. // problems. Therefore, this function is used to reinitialize
  141. // the globals.
  142. //
  143. //---------------------------------------------------------------------------
  144. void CRedirectInfo::ResetMembers(void)
  145. {
  146. FreeAllocatedMem ();
  147. m_iRedirectingGroup = 0;
  148. //defaults. are changed later on based on the state of this object.
  149. m_bFollowsParent = FALSE;
  150. m_bRedirectionAttempted = FALSE;
  151. m_StatusRedir = ERROR_SUCCESS;
  152. m_bValidGPO = FALSE;
  153. m_szGPOName[0] = L'\0';
  154. (void) StringCbCopy(m_szFolderRelativePath, sizeof(m_szFolderRelativePath), g_szRelativePathNames [(int) m_rID]);
  155. (void) StringCbCopy(m_szDisplayName, sizeof(m_szDisplayName), g_szDisplayNames [(int) m_rID]);
  156. m_fDataValid = FALSE;
  157. m_cbLocSize = 256; //start with a random amount
  158. m_szLocation = new WCHAR [m_cbLocSize];
  159. if (m_szLocation)
  160. {
  161. m_szLocation[0] = '\0';
  162. }
  163. else
  164. {
  165. m_cbLocSize = 0; //don't worry right now if memory cannot be allocated here, we will fail later
  166. }
  167. //set the parent and child pointers for the special parent/descendants
  168. m_pChild = NULL; //start with defaults
  169. m_pParent = NULL;
  170. switch (m_rID)
  171. {
  172. case MyDocs:
  173. m_pChild = this - (int) m_rID + (int) MyPics;
  174. m_dwFlags = REDIR_DONT_CARE;
  175. break;
  176. case MyPics:
  177. m_pParent = this - (int) m_rID + (int) MyDocs;
  178. m_dwFlags = REDIR_DONT_CARE;
  179. break;
  180. case StartMenu:
  181. m_pChild = this - (int) m_rID + (int) Programs;
  182. m_dwFlags = REDIR_DONT_CARE;
  183. break;
  184. case Programs:
  185. m_pParent = this - (int) m_rID + (int) StartMenu;
  186. m_pChild = this - (int) m_rID + (int) Startup;
  187. m_dwFlags = REDIR_DONT_CARE;
  188. break;
  189. case Startup:
  190. m_pParent = this - (int) m_rID + (int) Programs;
  191. m_dwFlags = REDIR_DONT_CARE;
  192. break;
  193. case Desktop:
  194. m_pChild = NULL;
  195. m_pParent = NULL;
  196. m_dwFlags = REDIR_DONT_CARE;
  197. break;
  198. case AppData:
  199. m_pChild = NULL;
  200. m_pParent = NULL;
  201. m_dwFlags = REDIR_DONT_CARE;
  202. break;
  203. }
  204. //as a safety mechanism, load localized folder names if ghDllInstance
  205. //has been set. note: ghDllInstance won't be set for global variables
  206. //since their constructors before DllMain. For such variables, the
  207. //localized names have to be called explicitly from some other function
  208. //which is called after DllMain.
  209. if (ghDllInstance)
  210. LoadLocalizedNames();
  211. //
  212. // No need to modify m_rID or m_idConstructor. The construct has already
  213. // taken care of it and touching them might cause undesirable results if
  214. // not done in the proper order. Besides, these don't change across multiple
  215. // sessions.
  216. //
  217. }
  218. //+--------------------------------------------------------------------------
  219. //
  220. // Member: CRedirectInfo::GetFolderIndex
  221. //
  222. // Synopsis: a static member function that, given the name of a special
  223. // folder, returns its id which can be used to locate the
  224. // redirection info. for that particular folder.
  225. //
  226. // Arguments: [in][szFldrName : the name of the folder as stored in fdeploy.ini
  227. //
  228. // Returns: the id of the folder. If the folder is not redirectable, the
  229. // function returns EndRedirectable.
  230. //
  231. // History: 8/11/1998 RahulTh created
  232. //
  233. // Notes:
  234. //
  235. //---------------------------------------------------------------------------
  236. REDIRECTABLE CRedirectInfo::GetFolderIndex (LPCTSTR szFldrName)
  237. {
  238. int i;
  239. for (i = 0; i < (int)EndRedirectable; i++)
  240. {
  241. if (0 == lstrcmpi (szFldrName, g_szDisplayNames[i]))
  242. break; //we have found a match
  243. }
  244. return (REDIRECTABLE)i; //if a match was not found above, i == EndRedirectable
  245. }
  246. //+--------------------------------------------------------------------------
  247. //
  248. // Member: CRedirectInfo::LoadLocalizedNames
  249. //
  250. // Synopsis: loads the localized folder display names and folder relative
  251. // paths from the resources.
  252. //
  253. // Arguments: none.
  254. //
  255. // Returns: ERROR_SUCCESS if the names were successfully loaded.
  256. // an error code describing the cause of the failure otherwise.
  257. //
  258. // History: 5/6/1999 RahulTh created
  259. //
  260. // Notes: we cannot do this in the constructor because ghDllInstance
  261. // is not initialized at that time and therefore LoadString will
  262. // fail. This is because DllMain is called after the constructors.
  263. //
  264. //---------------------------------------------------------------------------
  265. DWORD CRedirectInfo::LoadLocalizedNames (void)
  266. {
  267. UINT DisplayID = 0;
  268. UINT RelpathID = 0;
  269. switch (m_rID)
  270. {
  271. case MyDocs:
  272. DisplayID = RelpathID = IDS_MYDOCS;
  273. break;
  274. case MyPics:
  275. DisplayID = IDS_MYPICS;
  276. RelpathID = IDS_MYPICS_REL;
  277. break;
  278. case StartMenu:
  279. DisplayID = RelpathID = IDS_STARTMENU;
  280. break;
  281. case Programs:
  282. DisplayID = IDS_PROGRAMS;
  283. RelpathID = IDS_PROGRAMS_REL;
  284. break;
  285. case Startup:
  286. DisplayID = IDS_STARTUP;
  287. RelpathID = IDS_STARTUP_REL;
  288. break;
  289. case Desktop:
  290. DisplayID = RelpathID = IDS_DESKTOP;
  291. break;
  292. case AppData:
  293. DisplayID = RelpathID = IDS_APPDATA;
  294. break;
  295. default:
  296. ASSERT("Unknown folder id" && NULL);
  297. break;
  298. }
  299. //now get the localized name of the folder and the localized relative
  300. //path names (w.r.t. the userprofile directory)
  301. m_szLocDisplayName[0] = m_szLocFolderRelativePath[0] = '\0'; //safety
  302. if (!LoadString (ghDllInstance, DisplayID, m_szLocDisplayName, 80))
  303. return GetLastError();
  304. if (DisplayID == RelpathID)
  305. {
  306. return HRESULT_CODE(StringCbCopy(m_szLocFolderRelativePath, sizeof(m_szLocFolderRelativePath), m_szLocDisplayName)); //top level folders
  307. }
  308. else
  309. {
  310. if (LoadString (ghDllInstance, RelpathID, m_szLocFolderRelativePath, 80)) //special descendant folders
  311. {
  312. return ERROR_SUCCESS;
  313. }
  314. else
  315. {
  316. return GetLastError();
  317. }
  318. }
  319. }
  320. //+--------------------------------------------------------------------------
  321. //
  322. // Member: CRedirectInfo::GatherRedirectionInfo
  323. //
  324. // Synopsis: this function gathers redirection info. from the ini file
  325. //
  326. // Arguments: [in] pFileDB : pointer to the CFileDB object that called it
  327. // [in] dwFlags : the flags as obtained from the ini file
  328. // [in] bRemove : whether this is a policy that is being removed
  329. //
  330. // Returns: STATUS_SUCCESS if successful. An error code otherwise.
  331. //
  332. // History: 8/11/1998 RahulTh created
  333. //
  334. // Notes:
  335. //
  336. //---------------------------------------------------------------------------
  337. DWORD CRedirectInfo::GatherRedirectionInfo (CFileDB * pFileDB, DWORD dwFlags, BOOL bRemove)
  338. {
  339. DWORD Status = ERROR_SUCCESS;
  340. HRESULT hr = S_OK;
  341. DWORD len;
  342. BOOL bStatus;
  343. WCHAR * pwszSection = 0;
  344. BOOL bFoundGroup;
  345. WCHAR * pwszString = 0;
  346. WCHAR * pwszSid = 0;
  347. WCHAR * pwszPath = 0;
  348. PSID Sid = NULL;
  349. if (bRemove &&
  350. (!gSavedSettings[m_rID].m_bValidGPO ||
  351. (0 != _wcsicmp (pFileDB->_pwszGPOUniqueName, gSavedSettings[m_rID].m_szGPOName))
  352. )
  353. )
  354. {
  355. DebugMsg((DM_VERBOSE, IDS_IGNORE_DELETEDGPO, pFileDB->_pwszGPOName, pFileDB->_pwszGPOUniqueName, m_szLocDisplayName));
  356. Status = ERROR_SUCCESS;
  357. //set default values on the members just to be on the safe side.
  358. m_fDataValid = FALSE;
  359. m_dwFlags = REDIR_DONT_CARE;
  360. m_bValidGPO = FALSE;
  361. m_szGPOName[0] = L'\0';
  362. goto GatherInfoEnd;
  363. }
  364. //the data is valid. This function is only called when something relevant is found in the ini file.
  365. m_fDataValid = TRUE;
  366. //store the flags
  367. m_dwFlags = dwFlags;
  368. //store the GPO's unique name
  369. if (bRemove)
  370. {
  371. m_bValidGPO = FALSE; //for redirection resulting from a removed GPO, we do not store the GPO name to avoid processing a removal twice
  372. m_szGPOName[0] = L'\0';
  373. }
  374. else
  375. {
  376. m_bValidGPO = TRUE;
  377. (void) StringCbCopy(m_szGPOName, sizeof(m_szGPOName), pFileDB->_pwszGPOUniqueName);
  378. }
  379. //there is nothing to do if policy is not specified for this folder
  380. if (m_dwFlags & REDIR_DONT_CARE)
  381. goto GatherInfoSuccess;
  382. m_bRemove = bRemove;
  383. //also, we can do nothing right now if this is a special descendant folder
  384. //following its parent
  385. if (m_dwFlags & REDIR_FOLLOW_PARENT)
  386. goto GatherInfoSuccess;
  387. //a location has been specified by this policy
  388. if ( ! pFileDB->GetRsopContext()->IsPlanningModeEnabled() )
  389. {
  390. //we must have a list of groups to which the user belongs
  391. //each user must at least have everyone as one of his groups
  392. if (! pFileDB->_pGroups)
  393. goto GatherInfoErr;
  394. }
  395. DWORD cchSectionLen;
  396. bStatus = pFileDB->ReadIniSection (m_szDisplayName, &pwszSection, &cchSectionLen);
  397. if (!bStatus)
  398. goto GatherInfoErr;
  399. bFoundGroup = FALSE;
  400. //
  401. // For rsop, we need to know the list of security groups
  402. // and redirected paths -- we'll copy this information for
  403. // use by the rsop logging code
  404. //
  405. if (pFileDB->GetRsopContext()->IsRsopEnabled())
  406. {
  407. //
  408. // Note that when we do the copy, the size returned
  409. // by ReadIniSection above does not include the null terminator,
  410. // even though thaft character is present, so we must add that character
  411. // to the count ourselves.
  412. //
  413. m_szGroupRedirectionData = new WCHAR[cchSectionLen + 1];
  414. if (m_szGroupRedirectionData)
  415. {
  416. RtlCopyMemory(m_szGroupRedirectionData,
  417. pwszSection,
  418. ( cchSectionLen + 1 ) * sizeof(*pwszSection));
  419. }
  420. else
  421. {
  422. pFileDB->GetRsopContext()->DisableRsop( E_OUTOFMEMORY );
  423. }
  424. }
  425. if ( ! pFileDB->GetRsopContext()->IsReportingModeEnabled() )
  426. {
  427. DWORD iGroup;
  428. iGroup = 0;
  429. for (pwszString = pwszSection;
  430. *pwszString;
  431. pwszString += lstrlen(pwszString) + 1)
  432. {
  433. pwszSid = pwszString;
  434. pwszPath = wcschr (pwszString, L'=');
  435. if (!pwszPath)
  436. continue; //skip any invalid entries
  437. //temporarily break up the sid and the path
  438. *pwszPath++ = L'\0';
  439. if (! *pwszPath)
  440. {
  441. //again an invalid path. restore the = sign and move on
  442. pwszPath[-1] = L'='; //note: we had advanced the pointer above
  443. continue;
  444. }
  445. //the entry is valid
  446. bFoundGroup = GroupInList (pwszSid, pFileDB->_pGroups);
  447. if (bFoundGroup)
  448. {
  449. m_iRedirectingGroup = iGroup;
  450. break; //we have found a group, so break out of the loop
  451. }
  452. else
  453. {
  454. //restore the '=' sign, and try the next group
  455. pwszPath[-1] = L'='; //note: we had advanced the pointer above
  456. }
  457. iGroup++;
  458. }
  459. }
  460. else
  461. {
  462. //
  463. // In reporting mode, we treat every folder as if it applies so
  464. // that we can report on all settings in the GPO
  465. //
  466. bFoundGroup = TRUE;
  467. }
  468. if (!bFoundGroup)
  469. {
  470. //no group was found, so treat this as a don't care
  471. m_dwFlags = REDIR_DONT_CARE;
  472. }
  473. else if ( ! pFileDB->GetRsopContext()->IsReportingModeEnabled() )
  474. {
  475. //first store the sid
  476. if (m_pSid)
  477. delete [] ((BYTE*) m_pSid); //m_pSid is always allocated from our heap, so never use RtlFreeSid
  478. m_pSid = NULL;
  479. if (!m_bRemove)
  480. Status = AllocateAndInitSidFromString (pwszSid, &Sid);
  481. else
  482. Status = AllocateAndInitSidFromString (L"S-1-1-0", &Sid); //if this is a removed policy, we set the SID to Everyone -- so that when we look at the saved settings at a later time, we shouldn't have to process the policy again (see code for NeedsProcessing)
  483. if (ERROR_SUCCESS != Status)
  484. goto GatherInfoEnd;
  485. if (m_pSid)
  486. delete [] ((BYTE*) m_pSid);
  487. Status = MySidCopy (&m_pSid, Sid); //we want to always allocate memory for this sid from our heap
  488. RtlFreeSid (Sid); //cleanup. must take place before the following check
  489. if (ERROR_SUCCESS != Status)
  490. goto GatherInfoEnd;
  491. //we have found a group
  492. DebugMsg ((DM_VERBOSE, IDS_GROUP_MEMBER, pwszSid, pwszPath));
  493. SimplifyPath (pwszPath);
  494. //
  495. // Copy the location
  496. // Use X:\ for paths of the form X: to avoid problems during the file
  497. // copy phase.
  498. //
  499. BOOL bAppendSlash = FALSE;
  500. len = lstrlen (pwszPath);
  501. if (2 == len && L':' == pwszPath[1])
  502. {
  503. bAppendSlash = TRUE;
  504. len++; // Ensure that the extra backslash at the end is accounted for in length calculations.
  505. }
  506. if (m_cbLocSize <= len)
  507. {
  508. //we need to reallocate memory for the location
  509. if (m_cbLocSize)
  510. delete [] m_szLocation;
  511. m_cbLocSize = len + 1; // Add one for the terminating null.
  512. m_szLocation = new TCHAR [m_cbLocSize];
  513. if (!m_szLocation)
  514. {
  515. m_cbLocSize = 0;
  516. goto GatherInfoErr;
  517. }
  518. }
  519. (void) StringCchCopy(m_szLocation, m_cbLocSize, pwszPath);
  520. if (bAppendSlash)
  521. {
  522. (void) StringCchCat(m_szLocation, m_cbLocSize, L"\\");
  523. }
  524. }
  525. GatherInfoSuccess:
  526. DebugMsg ((DM_VERBOSE, IDS_COLLECT_REDIRINFO, m_szLocDisplayName, m_dwFlags));
  527. Status = STATUS_SUCCESS;
  528. goto GatherInfoEnd;
  529. GatherInfoErr:
  530. Status = ERROR_OUTOFMEMORY;
  531. m_fDataValid = FALSE;
  532. m_dwFlags = REDIR_DONT_CARE; //so that these settings will be ignored while merging into global data
  533. DebugMsg ((DM_VERBOSE, IDS_GATHER_FAILURE, Status, m_szLocDisplayName));
  534. GatherInfoEnd:
  535. if (pwszSection)
  536. delete [] pwszSection;
  537. return Status;
  538. }
  539. //+--------------------------------------------------------------------------
  540. //
  541. // Member: CRedirectInfo::WasRedirectionAttempted
  542. //
  543. // Synopsis: indicates whether redirection has already been attempted on
  544. // this folder.
  545. //
  546. // Arguments: none.
  547. //
  548. // Returns: a bool indicating the required status
  549. //
  550. // History: 9/20/1999 RahulTh created
  551. //
  552. // Notes:
  553. //
  554. //---------------------------------------------------------------------------
  555. const BOOL CRedirectInfo::WasRedirectionAttempted (void)
  556. {
  557. return m_bRedirectionAttempted;
  558. }
  559. //+--------------------------------------------------------------------------
  560. //
  561. // Member: CRedirectInfo::GetFolderID
  562. //
  563. // Synopsis: returns the index of this folder in the array of
  564. // redirection candidates
  565. //
  566. // Arguments: none.
  567. //
  568. // Returns: an index into the list of redirected folders
  569. //
  570. // History: 11/20/2001 AdamEd created
  571. //
  572. // Notes:
  573. //
  574. //---------------------------------------------------------------------------
  575. REDIRECTABLE CRedirectInfo::GetFolderID(void)
  576. {
  577. return m_rID;
  578. }
  579. //+--------------------------------------------------------------------------
  580. //
  581. // Member: CRedirectInfo::GetFlags
  582. //
  583. // Synopsis: returns the redirection flags for the folder represented by
  584. // this object
  585. //
  586. // Arguments: none
  587. //
  588. // Returns: the value of the flags
  589. //
  590. // History: 8/12/1998 RahulTh created
  591. //
  592. // Notes:
  593. //
  594. //---------------------------------------------------------------------------
  595. const DWORD CRedirectInfo::GetFlags (void)
  596. {
  597. return m_dwFlags;
  598. }
  599. //+--------------------------------------------------------------------------
  600. //
  601. // Member: CRedirectInfo::GetRedirStatus
  602. //
  603. // Synopsis: retrieves the return code of the redirection operation
  604. //
  605. // Arguments: none
  606. //
  607. // Returns: the member m_StatusRedir
  608. //
  609. // History: 5/3/1999 RahulTh created
  610. //
  611. // Notes:
  612. //
  613. //---------------------------------------------------------------------------
  614. const DWORD CRedirectInfo::GetRedirStatus (void)
  615. {
  616. return m_StatusRedir;
  617. }
  618. //+--------------------------------------------------------------------------
  619. //
  620. // Member: CRedirectInfo::GetLocation
  621. //
  622. // Synopsis: returns the redirection location for the folder represented
  623. // by this object
  624. //
  625. // Arguments: none
  626. //
  627. // Returns: a pointer to the buffer containing the path
  628. //
  629. // History: 8/12/1998 RahulTh created
  630. //
  631. // Notes:
  632. //
  633. //---------------------------------------------------------------------------
  634. LPCTSTR CRedirectInfo::GetLocation (void)
  635. {
  636. return m_szLocation;
  637. }
  638. //+--------------------------------------------------------------------------
  639. //
  640. // Member: CRedirectInfo::GetLocalizedName
  641. //
  642. // Synopsis: returns the localized name of the folder
  643. //
  644. // Arguments: none
  645. //
  646. // Returns: a pointer to the buffer containing the localized name
  647. //
  648. // History: 8/12/1998 RahulTh created
  649. //
  650. // Notes:
  651. //
  652. //---------------------------------------------------------------------------
  653. LPCTSTR CRedirectInfo::GetLocalizedName (void)
  654. {
  655. return m_szLocDisplayName;
  656. }
  657. //+--------------------------------------------------------------------------
  658. //
  659. // Member: CRedirectInfo::Redirect
  660. //
  661. // Synopsis: this function performs the actual redirection for the
  662. // folder represented by this object.
  663. //
  664. // Arguments: [in] hUserToken : handle to the user token
  665. // [in] hKeyRoot : handle to HKCU
  666. // [in] pFileDB : pointer to the CFileDB object from which this
  667. // function was called.
  668. //
  669. // Returns: a DWORD indicating the success/failure code in redirection
  670. //
  671. // History: 8/12/1998 RahulTh created
  672. //
  673. // Notes:
  674. // It is very important to record the return code in m_StatusRedir
  675. // before returning from this function. If we don't do that
  676. // we might end up returning the wrong value to the policy engine
  677. // while attempting to redirect special descendant folders which
  678. // can affect the list of policies obtained at a subsequent logon
  679. // session.
  680. //
  681. //---------------------------------------------------------------------------
  682. DWORD CRedirectInfo::Redirect (HANDLE hUserToken,
  683. HKEY hKeyRoot,
  684. CFileDB* pFileDB)
  685. {
  686. HRESULT hr = S_OK;
  687. SHARESTATUS SourceStatus = NoCSC;
  688. SHARESTATUS DestStatus = NoCSC;
  689. DWORD PinStatus = ERROR_SUCCESS;
  690. WCHAR * wszProcessedPath = NULL;
  691. if (m_bRedirectionAttempted)
  692. {
  693. goto Redir_CleanupAndQuit; //redirection has already been attempted
  694. //and the success / failure code has been
  695. //recorded in m_StatusRedir. Use the same
  696. //error code as the return value as this
  697. //value may not yet have been recorded in
  698. //ProcessGroupPolicy
  699. }
  700. //we shall now attempt to redirect...
  701. m_bRedirectionAttempted = TRUE;
  702. if (m_dwFlags & REDIR_FOLLOW_PARENT)
  703. {
  704. //this is possible only if UpdateDescendant ran out of memory
  705. //which means that we could not derive the folder's redirection
  706. //info. No point trying to log an event since we are out of memory
  707. //anyway. we just try to quit as gracefully as we can.
  708. m_StatusRedir = ERROR_OUTOFMEMORY;
  709. goto Redir_KillChildAndLeave;
  710. }
  711. WCHAR wszExpandedNewPath [TARGETPATHLIMIT];
  712. WCHAR wszExpandedCurrentPath [TARGETPATHLIMIT];
  713. WCHAR wszHackedName [TARGETPATHLIMIT];
  714. WCHAR wszExpandedSavedFolderPath [TARGETPATHLIMIT];
  715. WCHAR wszExpandedNewFolderPath [TARGETPATHLIMIT];
  716. CSavedSettings * pLocalSettings;
  717. BOOL bCurrentPathValid; //indicates if we have been successful in obtaining the current path of the folder.
  718. UNICODE_STRING Path;
  719. UNICODE_STRING ExpandedPath;
  720. //set some defaults.
  721. m_StatusRedir = ERROR_SUCCESS;
  722. bCurrentPathValid = TRUE;
  723. //if the policy cares about the location of the folder, then we must
  724. //expand the path
  725. if (! (m_dwFlags & REDIR_DONT_CARE))
  726. {
  727. //show additional status messages if the verbose status is on.
  728. DisplayStatusMessage (IDS_REDIR_CALLBACK);
  729. if (!m_cbLocSize)
  730. {
  731. m_StatusRedir = ERROR_OUTOFMEMORY;
  732. //we had run out of memory so no point trying to log an event
  733. //we just quit as gracefully as we can.
  734. goto Redir_KillChildAndLeave;
  735. }
  736. if (m_bRemove)
  737. {
  738. m_StatusRedir = HRESULT_CODE(StringCchCopy( m_szLocation, m_cbLocSize, L"%USERPROFILE%\\"));
  739. if ( m_StatusRedir != ERROR_SUCCESS )
  740. {
  741. goto Redir_KillChildAndLeave;
  742. }
  743. m_StatusRedir = HRESULT_CODE(StringCchCat( m_szLocation, m_cbLocSize, m_szLocFolderRelativePath));
  744. if ( m_StatusRedir != ERROR_SUCCESS )
  745. {
  746. goto Redir_KillChildAndLeave;
  747. }
  748. }
  749. // Get the expanded destination path.
  750. // First expand the homedir component, if applicable.
  751. m_StatusRedir = ExpandHomeDirPolicyPath (m_rID,
  752. m_szLocation,
  753. m_bFollowsParent,
  754. &wszProcessedPath);
  755. if (ERROR_SUCCESS == m_StatusRedir)
  756. {
  757. Path.Length = (wcslen (wszProcessedPath) + 1) * sizeof (WCHAR);
  758. Path.MaximumLength = sizeof (wszProcessedPath);
  759. Path.Buffer = wszProcessedPath;
  760. ExpandedPath.Length = 0;
  761. ExpandedPath.MaximumLength = sizeof (wszExpandedNewFolderPath);
  762. ExpandedPath.Buffer = wszExpandedNewFolderPath;
  763. m_StatusRedir = RtlExpandEnvironmentStrings_U (
  764. pFileDB->_pEnvBlock,
  765. &Path,
  766. &ExpandedPath,
  767. NULL
  768. );
  769. if (STATUS_BUFFER_TOO_SMALL == m_StatusRedir)
  770. {
  771. gpEvents->Report (
  772. EVENT_FDEPLOY_DESTPATH_TOO_LONG,
  773. 3,
  774. m_szLocDisplayName,
  775. m_szLocation,
  776. NumberToString ( TARGETPATHLIMIT )
  777. );
  778. goto Redir_KillChildAndLeave;
  779. }
  780. }
  781. if (ERROR_SUCCESS != m_StatusRedir)
  782. {
  783. DebugMsg ((DM_WARNING, IDS_REDIRECT_EXP_FAIL, m_szLocation, m_StatusRedir));
  784. gpEvents->Report (
  785. EVENT_FDEPLOY_FOLDER_EXPAND_FAIL,
  786. 2,
  787. m_szLocDisplayName,
  788. StatusToString ( m_StatusRedir )
  789. );
  790. goto Redir_KillChildAndLeave;
  791. }
  792. }
  793. pLocalSettings = & (gSavedSettings[(int) m_rID]);
  794. if (pLocalSettings->m_dwFlags & REDIR_DONT_CARE)
  795. {
  796. if (m_dwFlags & REDIR_DONT_CARE)
  797. {
  798. pLocalSettings->Save (pLocalSettings->m_szCurrentPath, m_dwFlags, NULL, NULL);
  799. if (MyDocs == m_rID)
  800. {
  801. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot, FALSE);
  802. if ( ERROR_SUCCESS != m_StatusRedir )
  803. {
  804. goto Redir_KillChildAndLeave;
  805. }
  806. }
  807. goto Redir_CleanupAndQuit;
  808. }
  809. DebugMsg ((DM_VERBOSE, IDS_REDIRECT, m_szLocDisplayName, m_szLocation));
  810. //the policy cares about the location of this doc.
  811. //must get the correct syntax for GetLocalFilePath
  812. m_StatusRedir = HRESULT_CODE(StringCchCopy(wszHackedName, TARGETPATHLIMIT, m_szFolderRelativePath));
  813. if ( m_StatusRedir != ERROR_SUCCESS )
  814. {
  815. goto Redir_KillChildAndLeave;
  816. }
  817. m_StatusRedir = HRESULT_CODE(StringCchCat(wszHackedName, TARGETPATHLIMIT, L"\\"));
  818. if ( m_StatusRedir != ERROR_SUCCESS )
  819. {
  820. goto Redir_KillChildAndLeave;
  821. }
  822. m_StatusRedir = pFileDB->GetLocalFilePath (wszHackedName, wszExpandedCurrentPath);
  823. //
  824. // Expand the homedir if necessary. Note: GetLocalFilePath will not
  825. // do it because it calls SHGetFolderPath and HOMESHARE and HOMEPATH
  826. // are not defined at that point.
  827. //
  828. if (ERROR_SUCCESS == m_StatusRedir)
  829. {
  830. m_StatusRedir = ExpandHomeDir (m_rID,
  831. wszExpandedCurrentPath,
  832. TRUE,
  833. &wszProcessedPath,
  834. pLocalSettings->m_bHomedirChanged ? pLocalSettings->m_szLastHomedir : NULL
  835. );
  836. if (ERROR_SUCCESS != m_StatusRedir ||
  837. ! wszProcessedPath ||
  838. TARGETPATHLIMIT <= lstrlen (wszProcessedPath))
  839. {
  840. m_StatusRedir = (ERROR_SUCCESS == m_StatusRedir) ? ERROR_BUFFER_OVERFLOW : m_StatusRedir;
  841. }
  842. else
  843. {
  844. (void) StringCchCopy(wszExpandedCurrentPath, TARGETPATHLIMIT, wszProcessedPath);
  845. }
  846. }
  847. //GetLocalFilePath might fail if SHGetFolderPath fails. SHGetFolderPath
  848. //fails if the registry keys for the folder point to an invalid path and
  849. //there is nothing in the CSC cache for it either. So in this particular
  850. //case, we ignore the failure and treat it as a NO_MOVE. In NO_MOVE, we
  851. //do not require the current path of the folder.
  852. if ((ERROR_SUCCESS != m_StatusRedir) &&
  853. ERROR_INVALID_NAME != m_StatusRedir) //the only possible error from GetLocalFilePath not generated by SHGetFolderPath
  854. {
  855. m_dwFlags &= ~REDIR_MOVE_CONTENTS;
  856. m_StatusRedir = ERROR_SUCCESS;
  857. bCurrentPathValid = FALSE;
  858. (void) StringCchCopy(wszExpandedCurrentPath, TARGETPATHLIMIT, L"???"); //if bCurrentPathValid is FALSE, this string will only be used in logs
  859. }
  860. if (m_StatusRedir != ERROR_SUCCESS)
  861. {
  862. DebugMsg ((DM_WARNING, IDS_REDIRECT_NO_LOCAL, m_szLocDisplayName, m_StatusRedir));
  863. gpEvents->Report (
  864. EVENT_FDEPLOY_FOLDER_EXPAND_FAIL,
  865. 2,
  866. m_szLocDisplayName,
  867. StatusToString ( m_StatusRedir )
  868. );
  869. goto Redir_KillChildAndLeave;
  870. }
  871. //make sure that it is not already redirected
  872. if (bCurrentPathValid && (0 == _wcsicmp (wszExpandedCurrentPath, wszExpandedNewFolderPath)))
  873. {
  874. pLocalSettings->Save (m_szLocation, m_dwFlags, m_pSid, m_bValidGPO ? m_szGPOName : NULL);
  875. if (MyDocs == m_rID)
  876. {
  877. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot,
  878. (m_bRemove || (m_dwFlags & REDIR_DONT_CARE))?FALSE:TRUE);
  879. if ( ERROR_SUCCESS != m_StatusRedir )
  880. {
  881. goto Redir_KillChildAndLeave;
  882. }
  883. }
  884. DebugMsg ((DM_VERBOSE, IDS_REDIRECT_INSYNC, m_szLocDisplayName,
  885. wszExpandedNewFolderPath));
  886. //however, it is possible that the folders have not been pinned.
  887. //e.g. a roaming user who has already been redirected on one machine
  888. //and now logs on to another machine for the first time.
  889. DestStatus = GetCSCStatus (wszExpandedNewFolderPath);
  890. if (ShareOnline == DestStatus)
  891. {
  892. PinStatus = PinIfNecessary (wszExpandedNewFolderPath, DestStatus);
  893. if ( ERROR_SUCCESS != PinStatus )
  894. DebugMsg((DM_VERBOSE, IDS_CSCPIN_FAIL,
  895. m_szLocDisplayName, PinStatus));
  896. CacheDesktopIni (wszExpandedNewFolderPath, DestStatus, PinFile);
  897. }
  898. m_StatusRedir = ERROR_SUCCESS;
  899. goto Redir_CleanupAndQuit;
  900. }
  901. if (g_bCSCEnabled)
  902. {
  903. SourceStatus = bCurrentPathValid ? GetCSCStatus (wszExpandedCurrentPath) : PathLocal;
  904. DestStatus = GetCSCStatus (wszExpandedNewFolderPath);
  905. if (ShareOffline == DestStatus ||
  906. ((m_dwFlags & REDIR_MOVE_CONTENTS) && ShareOffline == SourceStatus))
  907. {
  908. m_StatusRedir = ERROR_CSCSHARE_OFFLINE;
  909. gpEvents->Report (
  910. EVENT_FDEPLOY_FOLDER_OFFLINE,
  911. 3,
  912. m_szLocDisplayName,
  913. wszExpandedCurrentPath,
  914. wszExpandedNewFolderPath
  915. );
  916. goto Redir_KillChildAndLeave;
  917. }
  918. }
  919. DebugMsg (( DM_VERBOSE, IDS_REDIRECT_PREVPATH,
  920. pLocalSettings->m_szCurrentPath,
  921. wszExpandedCurrentPath));
  922. DebugMsg (( DM_VERBOSE, IDS_REDIRECT_NEWPATH, m_szLocation,
  923. wszExpandedNewFolderPath));
  924. m_StatusRedir = PerformRedirection (
  925. pFileDB,
  926. bCurrentPathValid,
  927. wszExpandedCurrentPath,
  928. wszExpandedNewFolderPath,
  929. SourceStatus,
  930. DestStatus,
  931. hUserToken
  932. );
  933. if (ERROR_SUCCESS == m_StatusRedir)
  934. {
  935. if (m_bRemove)
  936. {
  937. if (MyDocs == m_rID)
  938. {
  939. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot, FALSE);
  940. if ( ERROR_SUCCESS != m_StatusRedir )
  941. {
  942. goto Redir_KillChildAndLeave;
  943. }
  944. }
  945. pLocalSettings->Save (m_szLocation, REDIR_DONT_CARE, NULL, NULL);
  946. }
  947. else
  948. {
  949. if (MyDocs == m_rID)
  950. {
  951. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot,
  952. (m_dwFlags & REDIR_DONT_CARE) ? FALSE : TRUE);
  953. if ( ERROR_SUCCESS != m_StatusRedir )
  954. {
  955. goto Redir_KillChildAndLeave;
  956. }
  957. }
  958. pLocalSettings->Save (m_szLocation, m_dwFlags, m_pSid, m_bValidGPO ? m_szGPOName : 0);
  959. }
  960. }
  961. else if (m_pChild && m_pChild->m_bFollowsParent) //if this is a parent whose redirection was unsuccessful, do not redirect the child if it is supposed to follow
  962. {
  963. PreventDescendantRedirection (m_StatusRedir);
  964. }
  965. goto Redir_CleanupAndQuit;
  966. }
  967. //if we are here, it means that the saved settings don't have the
  968. //REDIR_DONT_CARE flag set
  969. if (m_dwFlags & REDIR_DONT_CARE)
  970. {
  971. //the original settings cared about the location of the folder,
  972. //but now no one cares. So remove any redirection restrictions.
  973. if (MyDocs == m_rID)
  974. {
  975. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot, FALSE);
  976. if ( ERROR_SUCCESS != m_StatusRedir )
  977. {
  978. goto Redir_KillChildAndLeave;
  979. }
  980. }
  981. pLocalSettings->Save (pLocalSettings->m_szCurrentPath, m_dwFlags, NULL, NULL);
  982. m_StatusRedir = ERROR_SUCCESS;
  983. goto Redir_CleanupAndQuit;
  984. }
  985. DebugMsg((DM_VERBOSE, IDS_REDIRECT, m_szLocDisplayName, m_szLocation));
  986. // This policy cares about where this folder goes.
  987. //
  988. // So first expand the homedir part if applicable
  989. // use the last value of homedir if the value of homedir has changed.
  990. //
  991. m_StatusRedir = ExpandHomeDir(m_rID,
  992. pLocalSettings->m_szLastRedirectedPath,
  993. TRUE,
  994. &wszProcessedPath,
  995. pLocalSettings->m_bHomedirChanged ? pLocalSettings->m_szLastHomedir : NULL);
  996. if (ERROR_SUCCESS == m_StatusRedir)
  997. {
  998. // Now first expand the saved path, we will use that for redirection
  999. Path.Length = (wcslen (wszProcessedPath) + 1) * sizeof (WCHAR);
  1000. Path.MaximumLength = Path.Length;
  1001. Path.Buffer = wszProcessedPath;
  1002. ExpandedPath.Length = 0;
  1003. ExpandedPath.MaximumLength = sizeof (wszExpandedSavedFolderPath);
  1004. ExpandedPath.Buffer = wszExpandedSavedFolderPath;
  1005. m_StatusRedir = RtlExpandEnvironmentStrings_U (
  1006. pFileDB->_pEnvBlock,
  1007. &Path,
  1008. &ExpandedPath,
  1009. NULL
  1010. );
  1011. if (STATUS_BUFFER_TOO_SMALL == m_StatusRedir)
  1012. {
  1013. gpEvents->Report (
  1014. EVENT_FDEPLOY_DESTPATH_TOO_LONG,
  1015. 3,
  1016. m_szLocDisplayName,
  1017. pLocalSettings->m_szLastRedirectedPath,
  1018. NumberToString ( TARGETPATHLIMIT )
  1019. );
  1020. goto Redir_KillChildAndLeave;
  1021. }
  1022. }
  1023. if (ERROR_SUCCESS != m_StatusRedir)
  1024. {
  1025. DebugMsg ((DM_WARNING, IDS_REDIRECT_EXP_FAIL, pLocalSettings->m_szLastRedirectedPath, m_StatusRedir));
  1026. gpEvents->Report (
  1027. EVENT_FDEPLOY_FOLDER_EXPAND_FAIL,
  1028. 2,
  1029. m_szLocDisplayName,
  1030. StatusToString ( m_StatusRedir )
  1031. );
  1032. goto Redir_KillChildAndLeave;
  1033. }
  1034. //make sure that it is not already redirected to the location.
  1035. if (0 == _wcsicmp (wszExpandedSavedFolderPath, wszExpandedNewFolderPath))
  1036. {
  1037. //the cached path and the path specified by the policy is the same
  1038. //but someone may have messed with the registry, if that is the case
  1039. //we use the path in the registry as the base path
  1040. //must get the correct syntax for GetLocalFilePath
  1041. m_StatusRedir = HRESULT_CODE(StringCchCopy(wszHackedName, TARGETPATHLIMIT, m_szFolderRelativePath));
  1042. if ( m_StatusRedir != ERROR_SUCCESS )
  1043. {
  1044. goto Redir_KillChildAndLeave;
  1045. }
  1046. m_StatusRedir = HRESULT_CODE(StringCchCat(wszHackedName, TARGETPATHLIMIT, L"\\"));
  1047. if ( m_StatusRedir != ERROR_SUCCESS )
  1048. {
  1049. goto Redir_KillChildAndLeave;
  1050. }
  1051. m_StatusRedir = pFileDB->GetLocalFilePath (wszHackedName, wszExpandedCurrentPath);
  1052. //
  1053. // Expand the homedir if necessary. Note: GetLocalFilePath will not
  1054. // do it because it calls SHGetFolderPath and HOMESHARE and HOMEPATH
  1055. // are not defined at that point.
  1056. //
  1057. if (ERROR_SUCCESS == m_StatusRedir)
  1058. {
  1059. m_StatusRedir = ExpandHomeDir (m_rID,
  1060. wszExpandedCurrentPath,
  1061. TRUE,
  1062. &wszProcessedPath,
  1063. pLocalSettings->m_bHomedirChanged ? pLocalSettings->m_szLastHomedir : NULL
  1064. );
  1065. if (ERROR_SUCCESS != m_StatusRedir ||
  1066. ! wszProcessedPath ||
  1067. TARGETPATHLIMIT <= lstrlen (wszProcessedPath))
  1068. {
  1069. m_StatusRedir = (ERROR_SUCCESS == m_StatusRedir) ? ERROR_BUFFER_OVERFLOW : m_StatusRedir;
  1070. }
  1071. else
  1072. {
  1073. (void) StringCchCopy(wszExpandedCurrentPath, TARGETPATHLIMIT, wszProcessedPath);
  1074. }
  1075. }
  1076. //GetLocalFilePath may fail if SHGetFolderPath fails. This
  1077. //would mean that the registry is messed up anyway. Also, move contents
  1078. //no longer makes sense, since the path to which the reg. points to
  1079. //is invalid or worse, the registry key is missing. also, it would
  1080. //imply that there is nothing in the CSC cache
  1081. if ((ERROR_SUCCESS != m_StatusRedir) &&
  1082. ERROR_INVALID_NAME != m_StatusRedir) //the only possible error from GetLocalFilePath not generated by SHGetFolderPath
  1083. {
  1084. m_StatusRedir = ERROR_SUCCESS;
  1085. bCurrentPathValid = FALSE;
  1086. m_dwFlags &= ~REDIR_MOVE_CONTENTS;
  1087. }
  1088. if (m_StatusRedir != ERROR_SUCCESS)
  1089. {
  1090. DebugMsg ((DM_WARNING, IDS_REDIRECT_NO_LOCAL, m_szLocDisplayName, m_StatusRedir));
  1091. gpEvents->Report (
  1092. EVENT_FDEPLOY_FOLDER_EXPAND_FAIL,
  1093. 2,
  1094. m_szLocDisplayName,
  1095. StatusToString ( m_StatusRedir )
  1096. );
  1097. goto Redir_KillChildAndLeave;
  1098. }
  1099. //we have found out the path stored in the registry, so compare it with
  1100. //the saved path
  1101. if (bCurrentPathValid && (0 == _wcsicmp (wszExpandedSavedFolderPath, wszExpandedCurrentPath)))
  1102. {
  1103. //all the paths are identical, so we are fine. save and quit
  1104. pLocalSettings->Save (m_szLocation, m_dwFlags, m_pSid, m_bValidGPO ? m_szGPOName : 0);
  1105. if (MyDocs == m_rID)
  1106. {
  1107. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot,
  1108. (m_bRemove || (m_dwFlags & REDIR_DONT_CARE))?FALSE:TRUE);
  1109. if ( ERROR_SUCCESS != m_StatusRedir )
  1110. {
  1111. goto Redir_KillChildAndLeave;
  1112. }
  1113. }
  1114. DebugMsg ((DM_VERBOSE, IDS_REDIRECT_INSYNC, m_szLocDisplayName,
  1115. wszExpandedNewFolderPath));
  1116. //however, it is possible that the folders have not been pinned.
  1117. //e.g. a roaming user who has already been redirected on one machine
  1118. //and now logs on to another machine for the first time.
  1119. DestStatus = GetCSCStatus (wszExpandedNewFolderPath);
  1120. if (ShareOnline == DestStatus)
  1121. {
  1122. PinStatus = PinIfNecessary (wszExpandedNewFolderPath, DestStatus);
  1123. if ( ERROR_SUCCESS != PinStatus )
  1124. DebugMsg((DM_VERBOSE, IDS_CSCPIN_FAIL,
  1125. m_szLocDisplayName, PinStatus));
  1126. CacheDesktopIni (wszExpandedNewFolderPath, DestStatus, PinFile);
  1127. }
  1128. m_StatusRedir = ERROR_SUCCESS;
  1129. goto Redir_CleanupAndQuit;
  1130. }
  1131. else //somebody has been messing with the registry
  1132. {
  1133. //use the path in the registry as the source path
  1134. //and perform redirection again
  1135. if (bCurrentPathValid)
  1136. (void) StringCchCopy(wszExpandedSavedFolderPath, TARGETPATHLIMIT, wszExpandedCurrentPath);
  1137. else
  1138. (void) StringCchCopy(wszExpandedSavedFolderPath, TARGETPATHLIMIT, L"???");
  1139. //to be on the safe side, since we don't want to use the saved path as the source for redirection
  1140. //if bCurrentPathValid is FALSE, this string will only be used in debug messages and error logs
  1141. }
  1142. }
  1143. if (g_bCSCEnabled)
  1144. {
  1145. SourceStatus = bCurrentPathValid ? GetCSCStatus (wszExpandedSavedFolderPath) : PathLocal;
  1146. DestStatus = GetCSCStatus (wszExpandedNewFolderPath);
  1147. if (ShareOffline == DestStatus ||
  1148. ((m_dwFlags & REDIR_MOVE_CONTENTS) && ShareOffline == SourceStatus))
  1149. {
  1150. m_StatusRedir = ERROR_CSCSHARE_OFFLINE;
  1151. gpEvents->Report (
  1152. EVENT_FDEPLOY_FOLDER_OFFLINE,
  1153. 3,
  1154. m_szLocDisplayName,
  1155. wszExpandedSavedFolderPath,
  1156. wszExpandedNewFolderPath
  1157. );
  1158. goto Redir_KillChildAndLeave;
  1159. }
  1160. }
  1161. DebugMsg (( DM_VERBOSE, IDS_REDIRECT_PREVPATH,
  1162. pLocalSettings->m_szLastRedirectedPath,
  1163. wszExpandedSavedFolderPath));
  1164. DebugMsg (( DM_VERBOSE, IDS_REDIRECT_NEWPATH, m_szLocation,
  1165. wszExpandedNewFolderPath));
  1166. m_StatusRedir = PerformRedirection (
  1167. pFileDB,
  1168. bCurrentPathValid,
  1169. wszExpandedSavedFolderPath,
  1170. wszExpandedNewFolderPath,
  1171. SourceStatus,
  1172. DestStatus,
  1173. hUserToken
  1174. );
  1175. if (ERROR_SUCCESS == m_StatusRedir)
  1176. {
  1177. if (m_bRemove)
  1178. {
  1179. if (MyDocs == m_rID)
  1180. {
  1181. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot, FALSE);
  1182. if ( ERROR_SUCCESS != m_StatusRedir )
  1183. {
  1184. goto Redir_KillChildAndLeave;
  1185. }
  1186. }
  1187. pLocalSettings->Save (m_szLocation, REDIR_DONT_CARE, NULL, NULL);
  1188. }
  1189. else
  1190. {
  1191. if (MyDocs == m_rID)
  1192. {
  1193. m_StatusRedir = RestrictMyDocsRedirection (hUserToken, hKeyRoot,
  1194. (m_dwFlags & REDIR_DONT_CARE)?FALSE:TRUE);
  1195. if ( ERROR_SUCCESS != m_StatusRedir )
  1196. {
  1197. goto Redir_KillChildAndLeave;
  1198. }
  1199. }
  1200. pLocalSettings->Save (m_szLocation, m_dwFlags, m_pSid, m_bValidGPO ? m_szGPOName : 0);
  1201. }
  1202. }
  1203. else if (m_pChild && m_pChild->m_bFollowsParent) //if redirection was unsuccessful and this folder has children, prevent the redirection of the children if they are supposed to follow
  1204. {
  1205. PreventDescendantRedirection (m_StatusRedir);
  1206. }
  1207. goto Redir_CleanupAndQuit;
  1208. //the following code is executed whenever some fatal error occurs
  1209. //and we want to make sure that if this is a dir with a special
  1210. //descendant and the descendant is supposed to follow the parent,
  1211. //then we don't want to attempt redirection for the child.
  1212. Redir_KillChildAndLeave:
  1213. if (ERROR_SUCCESS != m_StatusRedir &&
  1214. (m_pChild && m_pChild->m_bFollowsParent))
  1215. PreventDescendantRedirection (m_StatusRedir);
  1216. Redir_CleanupAndQuit:
  1217. if (wszProcessedPath)
  1218. delete [] wszProcessedPath;
  1219. if ( ERROR_SUCCESS != m_StatusRedir )
  1220. {
  1221. HRESULT hrRsop;
  1222. hrRsop = pFileDB->AddPreservedPolicy( (WCHAR*) m_szDisplayName );
  1223. if ( FAILED( hrRsop ) )
  1224. {
  1225. pFileDB->GetRsopContext()->DisableRsop( hrRsop );
  1226. }
  1227. }
  1228. return m_StatusRedir;
  1229. }
  1230. //+--------------------------------------------------------------------------
  1231. //
  1232. // Member: CRedirectInfo::ShouldSaveExpandedPath
  1233. //
  1234. // Synopsis: Determines whether we need to store the expanded path in the
  1235. // registry or the unexpanded paths. See notes for additional
  1236. // details.
  1237. //
  1238. // Arguments: none.
  1239. //
  1240. // Returns: TRUE : if the expanded path should be stored.
  1241. // FALSE : otherwise.
  1242. //
  1243. // History: 5/1/2001 RahulTh created
  1244. //
  1245. // Notes:
  1246. // If the destination path is a homedir path, store the expanded path
  1247. // in the registry so that if msgina is unable to set the homedir
  1248. // variables and uses the local defaults instead, the shell doesn't
  1249. // end up thinking that MyDocs is local.
  1250. //
  1251. // If the destination path is a different kind of path, then store the
  1252. // expanded path if it has the %username% variable in it. Because if we
  1253. // don't then when a user's UPN changes and the user logs on with the new
  1254. // username, then the shell will expand the path using the new username.
  1255. // Now, normally this won't be a problem because we would have already
  1256. // done the rename operation. However, if for some reason we are
  1257. // not successful in that rename operation (say because we are
  1258. // invoked in limited foreground or because the server is offline)
  1259. // then the rename will not succeed. In this case, the shell will
  1260. // end up creating a new empty folder in that location whenever the
  1261. // user tries to access it. So the next time the user logs on,
  1262. // the new folder is already present and the rename fails with
  1263. // ERROR_ALREADY_EXISTS and we just end up pointing to the new
  1264. // location. The files stay in the old location. Therefore, we must
  1265. // not use the unexpanded path in SHSetFolderPath. However, we must
  1266. // store the unexpanded path in our local cache in order to
  1267. // successfully detect UPN changes.
  1268. //
  1269. // We do not want to store the expanded path unconditionally because
  1270. // in situations where the user is going back to a local location,
  1271. // especially the local userprofile location, we do not want to store
  1272. // the expanded path because it is not device independent and will cause
  1273. // problems for roaming users (e.g. a certain drive may not be available
  1274. // on all the machines so we should keep the path as %userprofile%\...
  1275. // rather than something like E:\Documents & Settings\...)
  1276. //
  1277. //---------------------------------------------------------------------------
  1278. BOOL CRedirectInfo::ShouldSaveExpandedPath(void)
  1279. {
  1280. if (! m_szLocation || L'\0' == m_szLocation[0])
  1281. return FALSE;
  1282. // Detect the homedir case
  1283. if (IsHomedirPolicyPath(m_rID, m_szLocation, TRUE))
  1284. return TRUE;
  1285. //
  1286. // Check if the path contains the username variable.
  1287. // If it does then we should store the expanded paths. However regardless
  1288. // of everything else, if the path begins with %userprofile%, we should
  1289. // never store the expanded path because we will never be guaranteed a
  1290. // device independent path in that case and will run into all sorts of
  1291. // problems.
  1292. //
  1293. _wcslwr (m_szLocation);
  1294. // Compare the beginning of the two strings (the -1 is required to prevent comparing the terminating NULL)
  1295. if (0 == wcsncmp (m_szLocation, L"%userprofile%", sizeof(L"%userprofile%")/sizeof(WCHAR) - 1))
  1296. return FALSE;
  1297. if (wcsstr (m_szLocation, L"%username%"))
  1298. return TRUE;
  1299. //
  1300. // If we are here, we did not meet any of the conditions required for
  1301. // storing the expanded paths. So we should just store the unexpanded paths
  1302. //
  1303. return FALSE;
  1304. }
  1305. //+--------------------------------------------------------------------------
  1306. //
  1307. // Member: CRedirectInfo::PerformRedirection
  1308. //
  1309. // Synopsis: performs the nitty gritty of redirection including copying
  1310. // files, updating the registry, logging events etc.
  1311. //
  1312. // Arguments: [in] pFileDB : the CFileDB structure that is used throughout
  1313. // [in] bSourceValid : if pwszSource contains a valid path
  1314. // [in] pwszSource : source path
  1315. // [in] pwszDest : Destination path
  1316. // [in] StatusFrom : CSC status of the source share
  1317. // [in] StatusTo : CSC status of the destination share
  1318. //
  1319. // Returns: ERROR_SUCCESS if everything was successful. An error code
  1320. // otherwise.
  1321. //
  1322. // History: 11/21/1998 RahulTh created
  1323. // 12/13/2000 RahulTh Special cased homedir redirection to
  1324. // prevent security checks and store expanded
  1325. // paths in the registry (see comments within the function)
  1326. //
  1327. // Notes: this functions expects both shares to be online when it is
  1328. // invoked.
  1329. //
  1330. //---------------------------------------------------------------------------
  1331. DWORD CRedirectInfo::PerformRedirection (CFileDB * pFileDB,
  1332. BOOL bSourceValid,
  1333. WCHAR * pwszSource,
  1334. WCHAR * pwszDest,
  1335. SHARESTATUS StatusFrom,
  1336. SHARESTATUS StatusTo,
  1337. HANDLE hUserToken
  1338. )
  1339. {
  1340. BOOL bCheckOwner;
  1341. BOOL bMoveContents;
  1342. BOOL bIsHomeDirRedirection = FALSE; // Tracks if this is a homedir redirection policy
  1343. DWORD Status;
  1344. int iResultCompare;
  1345. WCHAR * pwszSkipSubdir;
  1346. int csidl;
  1347. BOOL bStatus;
  1348. DWORD PinStatus;
  1349. HRESULT hResult = S_OK;
  1350. CCopyFailData CopyFailure;
  1351. //
  1352. // We need to track if this is a homedir redirection policy because
  1353. // of 2 reasons:
  1354. // 1) In homedir redirection, security checks are skipped.
  1355. // 2) In homedir redirection, the expanded path is stored in the registry. This is
  1356. // to prevent problems that might occur if the homedir variables cannot be
  1357. // set by msgina and end up pointing to the local userprofile. In this case,
  1358. // we do not want the shell to start pointing MyDocs to the local location.
  1359. //
  1360. bIsHomeDirRedirection = IsHomedirPolicyPath(m_rID, m_szLocation, TRUE);
  1361. csidl = pFileDB->RegValueCSIDLFromFolderName (m_szFolderRelativePath);
  1362. // Skip security check for homedir redirection.
  1363. bCheckOwner = ((m_dwFlags & REDIR_SETACLS) && (!bIsHomeDirRedirection)) ? TRUE : FALSE;
  1364. bMoveContents = m_dwFlags & REDIR_MOVE_CONTENTS ? TRUE : FALSE;
  1365. if (bSourceValid)
  1366. {
  1367. Status = ComparePaths (pwszSource, pwszDest, &iResultCompare);
  1368. if (ERROR_SUCCESS != Status)
  1369. {
  1370. //this is very unlikely
  1371. gpEvents->Report (
  1372. EVENT_FDEPLOY_REDIRECT_FAIL,
  1373. 4,
  1374. m_szLocDisplayName,
  1375. StatusToString (Status),
  1376. pwszSource,
  1377. pwszDest
  1378. );
  1379. return Status;
  1380. }
  1381. if (0 == iResultCompare)
  1382. {
  1383. DebugMsg ((DM_VERBOSE, IDS_REDIRECT_INSYNC, m_szLocDisplayName,
  1384. pwszDest));
  1385. //however, it is possible that the folders have not been pinned.
  1386. //e.g. a roaming user who has already been redirected on one machine
  1387. //and now logs on to another machine for the first time.
  1388. if (ShareOnline == StatusTo)
  1389. {
  1390. PinStatus = PinIfNecessary (pwszDest, StatusTo);
  1391. if ( ERROR_SUCCESS != PinStatus )
  1392. DebugMsg((DM_VERBOSE, IDS_CSCPIN_FAIL,
  1393. m_szLocDisplayName, PinStatus));
  1394. CacheDesktopIni (pwszDest, StatusTo, PinFile);
  1395. }
  1396. return ERROR_SUCCESS;
  1397. }
  1398. //it is okay to redirect to a path that is a descendant of the current
  1399. //path if we are not moving contents
  1400. if (bMoveContents && (-1 == iResultCompare))
  1401. {
  1402. gpEvents->Report (
  1403. EVENT_FDEPLOY_REDIRECT_RECURSE,
  1404. 4,
  1405. m_szLocDisplayName,
  1406. m_szLocation,
  1407. pwszSource,
  1408. pwszDest
  1409. );
  1410. return ERROR_REQUEST_ABORTED;
  1411. }
  1412. }
  1413. Status = pFileDB->CreateRedirectedFolderPath (pwszSource, pwszDest,
  1414. bSourceValid,
  1415. bCheckOwner, bMoveContents);
  1416. if (ERROR_SUCCESS != Status)
  1417. {
  1418. gpEvents->Report (
  1419. EVENT_FDEPLOY_FOLDER_CREATE_FAIL,
  1420. 4,
  1421. m_szLocDisplayName,
  1422. StatusToString (Status),
  1423. m_szLocation,
  1424. pwszDest
  1425. );
  1426. return Status;
  1427. }
  1428. //now we know that both the source and destinations paths exist
  1429. //so make sure that they are not the same path in different formats
  1430. //this is an expensive function as it involves creation and deletion of
  1431. //multiple files over the network. so we invoke it only if absolutely
  1432. //necessary
  1433. if (bSourceValid && bMoveContents)
  1434. {
  1435. Status = CheckIdenticalSpecial (pwszSource, pwszDest, &iResultCompare);
  1436. if (ERROR_SUCCESS != Status)
  1437. {
  1438. //this is very unlikely...
  1439. gpEvents->Report (
  1440. EVENT_FDEPLOY_REDIRECT_FAIL,
  1441. 4,
  1442. m_szLocDisplayName,
  1443. StatusToString (Status),
  1444. pwszSource,
  1445. pwszDest
  1446. );
  1447. return Status;
  1448. }
  1449. if (0 == iResultCompare)
  1450. {
  1451. DebugMsg ((DM_VERBOSE, IDS_REDIRECT_INSYNC, m_szLocDisplayName,
  1452. pwszDest));
  1453. //
  1454. // The paths are the same but in different formats (or perhaps
  1455. // through different shares. So at least update the registry to
  1456. // point to the new path.
  1457. //
  1458. hResult = SHSetFolderPath(csidl | CSIDL_FLAG_DONT_UNEXPAND,
  1459. hUserToken,
  1460. 0,
  1461. ShouldSaveExpandedPath() ? pwszDest : m_szLocation);
  1462. Status = GetWin32ErrFromHResult (hResult);
  1463. //
  1464. // This basically should never fail. But do we want to try to delete the
  1465. // copied files if it does? Or the wacked CSC database?
  1466. //
  1467. if ( Status != ERROR_SUCCESS )
  1468. {
  1469. gpEvents->Report(
  1470. EVENT_FDEPLOY_FOLDER_REGSET_FAIL,
  1471. 2,
  1472. m_szLocDisplayName,
  1473. StatusToString( Status ) );
  1474. return Status;
  1475. }
  1476. else
  1477. {
  1478. //we were successul.
  1479. //first, rename the local CSC cache.
  1480. if (m_pChild)
  1481. pwszSkipSubdir = m_pChild->m_szLocDisplayName;
  1482. else
  1483. pwszSkipSubdir = NULL;
  1484. MoveDirInCSC (pwszSource, pwszDest, pwszSkipSubdir,
  1485. StatusFrom, StatusTo, TRUE, TRUE);
  1486. if (g_bCSCEnabled && ShareOnline == StatusFrom)
  1487. {
  1488. DeleteCSCFileTree (pwszSource, pwszSkipSubdir, TRUE);
  1489. DeleteCSCShareIfEmpty (pwszSource, StatusFrom);
  1490. }
  1491. //Also, it is possible that the folders have not been pinned.
  1492. //e.g. a roaming user who has already been redirected on one
  1493. //machine and now logs on to another machine for the first time.
  1494. if (ShareOnline == StatusTo)
  1495. {
  1496. PinStatus = PinIfNecessary (pwszDest, StatusTo);
  1497. if ( ERROR_SUCCESS != PinStatus )
  1498. DebugMsg((DM_VERBOSE, IDS_CSCPIN_FAIL,
  1499. m_szLocDisplayName, PinStatus));
  1500. CacheDesktopIni (pwszDest, StatusTo, PinFile);
  1501. }
  1502. //report this event and return. there is
  1503. //nothing more to be done here.
  1504. gpEvents->Report(
  1505. EVENT_FDEPLOY_FOLDER_REDIRECT,
  1506. 1,
  1507. m_szLocDisplayName );
  1508. return ERROR_SUCCESS;
  1509. }
  1510. }
  1511. }
  1512. if (bSourceValid && bMoveContents)
  1513. {
  1514. DebugMsg ((DM_VERBOSE, IDS_REDIRECT_COPYON, m_szLocDisplayName));
  1515. //
  1516. // Exclude any special descendants when
  1517. // doing file copies and deletes. Similarly for Programs and
  1518. // Startup
  1519. //
  1520. if (m_pChild)
  1521. pwszSkipSubdir = m_pChild->m_szLocDisplayName;
  1522. else
  1523. pwszSkipSubdir = NULL;
  1524. Status = pFileDB->CopyFileTree( pwszSource,
  1525. pwszDest,
  1526. pwszSkipSubdir,
  1527. StatusFrom,
  1528. StatusTo,
  1529. TRUE,
  1530. &CopyFailure );
  1531. //it is necessary to do the following for 2 reasons:
  1532. //(a) the user may have dirty files in the cache. these don't get
  1533. // moved above.
  1534. //(b) the files may have already been moved on the network by the
  1535. // the extension when the user logged on from another machine
  1536. // therefore, the cache on the second machine never gets updated
  1537. //
  1538. //we only try our best to move the files here. Errors are ignored.
  1539. if (ERROR_SUCCESS == Status)
  1540. {
  1541. MoveDirInCSC (pwszSource, pwszDest,
  1542. pwszSkipSubdir,
  1543. StatusFrom, StatusTo, FALSE, TRUE);
  1544. }
  1545. else
  1546. {
  1547. //the copy failed. We might have failed halfway and left the cache
  1548. //in an inconsistent state, so rollback all the cached entries
  1549. MoveDirInCSC (pwszDest, pwszSource, pwszSkipSubdir,
  1550. StatusTo, StatusFrom, TRUE, TRUE);
  1551. }
  1552. if ( ERROR_SUCCESS != Status )
  1553. {
  1554. if (! CopyFailure.IsCopyFailure())
  1555. {
  1556. gpEvents->Report(
  1557. EVENT_FDEPLOY_FOLDER_MOVE_FAIL,
  1558. 5,
  1559. m_szLocDisplayName,
  1560. StatusToString( Status ),
  1561. m_szLocation,
  1562. pwszSource,
  1563. pwszDest );
  1564. }
  1565. else
  1566. {
  1567. gpEvents->Report(
  1568. EVENT_FDEPLOY_FOLDER_COPY_FAIL,
  1569. 7,
  1570. m_szLocDisplayName,
  1571. StatusToString( Status ),
  1572. m_szLocation,
  1573. pwszSource,
  1574. pwszDest,
  1575. CopyFailure.GetSourceName(),
  1576. CopyFailure.GetDestName() );
  1577. }
  1578. return Status;
  1579. }
  1580. }
  1581. else
  1582. {
  1583. DebugMsg((DM_VERBOSE, IDS_REDIRECT_COPYOFF, m_szLocDisplayName));
  1584. }
  1585. //
  1586. // Look at the comments for ShouldSaveExpandedPath() for details on why we
  1587. // sometimes need to store expanded paths.
  1588. //
  1589. hResult = SHSetFolderPath(csidl | CSIDL_FLAG_DONT_UNEXPAND,
  1590. hUserToken,
  1591. 0,
  1592. ShouldSaveExpandedPath() ? pwszDest : m_szLocation);
  1593. Status = GetWin32ErrFromHResult (hResult);
  1594. if ( Status != ERROR_SUCCESS )
  1595. {
  1596. gpEvents->Report(
  1597. EVENT_FDEPLOY_FOLDER_REGSET_FAIL,
  1598. 2,
  1599. m_szLocDisplayName,
  1600. StatusToString( Status ) );
  1601. return Status;
  1602. }
  1603. if (!m_bRemove)
  1604. {
  1605. //
  1606. // hack to work around a shell problem.
  1607. //
  1608. // Pin the folder so that the shell never gets an error when
  1609. // trying to resolve this path. This will prevent it from
  1610. // reverting to a temporary local path.
  1611. //
  1612. // For now just call pin/unpin APIs for any unc style path. Not
  1613. // really much value in checking first to see if the share is
  1614. // cacheable.
  1615. //
  1616. if ( bSourceValid &&
  1617. (L'\\' == pwszSource[0]) &&
  1618. (L'\\' == pwszSource[1]) )
  1619. {
  1620. CSCUnpinFile( pwszSource,
  1621. FLAG_CSC_HINT_COMMAND_ALTER_PIN_COUNT,
  1622. NULL, NULL, NULL );
  1623. CacheDesktopIni (pwszSource, StatusFrom, UnpinFile);
  1624. }
  1625. if ( (L'\\' == pwszDest[0]) &&
  1626. (L'\\' == pwszDest[1]) )
  1627. {
  1628. PinStatus = PinIfNecessary (pwszDest, StatusTo);
  1629. if ( ERROR_SUCCESS != PinStatus )
  1630. DebugMsg((DM_VERBOSE, IDS_CSCPIN_FAIL,
  1631. m_szLocDisplayName, PinStatus));
  1632. CacheDesktopIni (pwszDest, StatusTo, PinFile);
  1633. }
  1634. }
  1635. //the contents were moved. now redirect any special children
  1636. //this ensures that deletions (if any) in the child folders,
  1637. //are performed first. thus deletion of this folder won't fail
  1638. //due to existence of its children within it.
  1639. //should not check for m_pChild->m_bFollowsParent here as
  1640. //the child may currently lie under this folder and if we do
  1641. //not perform the redirection of the child here, we might have
  1642. //problems deleting this folder even when we should not have any
  1643. //problems
  1644. if (m_pChild)
  1645. {
  1646. Status = m_pChild->Redirect (pFileDB->_hUserToken,
  1647. pFileDB->_hkRoot, pFileDB);
  1648. }
  1649. //note : contents of the source should not be deleted if this is a
  1650. // policy removal
  1651. if ( bSourceValid && bMoveContents)
  1652. {
  1653. Status = ERROR_SUCCESS;
  1654. //leave the contents on the server if this is a policy removal.
  1655. //also leave the contents on the server when moving from
  1656. //a network to a local location, so that subsequent redirections
  1657. //from other workstations will get all the contents back to local.
  1658. if (!m_bRemove && (!IsPathLocal(pwszDest) || IsPathLocal(pwszSource)))
  1659. {
  1660. //
  1661. // This could fail because of ACLing. We ignore any failures here.
  1662. //
  1663. DebugMsg((DM_VERBOSE, IDS_REDIRECT_DELETE,
  1664. m_szLocDisplayName, pwszSource));
  1665. Status = pFileDB->DeleteFileTree( pwszSource,
  1666. pwszSkipSubdir
  1667. );
  1668. if ( ERROR_SUCCESS == Status )
  1669. {
  1670. //DeleteFileTree does not remove the top level node passed to it.
  1671. // Delete the top level node only if it is not the user's home
  1672. // directory
  1673. const WCHAR * pwszHomeDir = NULL;
  1674. DWORD dwHomeDirStatus = ERROR_SUCCESS;
  1675. pwszHomeDir = gUserInfo.GetHomeDir(dwHomeDirStatus);
  1676. if (NULL == pwszHomeDir || 0 != lstrcmpi (pwszHomeDir, pwszSource))
  1677. {
  1678. //clear the attributes before deleting.
  1679. SetFileAttributes (pwszSource,
  1680. FILE_ATTRIBUTE_NORMAL);
  1681. if ( ! RemoveDirectory( pwszSource ) )
  1682. {
  1683. Status = GetLastError();
  1684. DebugMsg((DM_VERBOSE, IDS_DIRDEL_FAIL,
  1685. pwszSource, Status));
  1686. }
  1687. }
  1688. }
  1689. if ( Status != ERROR_SUCCESS )
  1690. DebugMsg((DM_WARNING, IDS_REDIRECT_DEL_FAIL,
  1691. pwszSource, m_szLocDisplayName,
  1692. m_szLocation, Status));
  1693. }
  1694. //but we always clean up the CSC cache irrespective of whether it is a
  1695. //policy removal or not because folder redirection should be as transparent
  1696. //to the user as possible and it would be annoying for the user to get
  1697. //CSC notifications for shares that are no longer used as redirection
  1698. //targets.
  1699. if (g_bCSCEnabled && ShareOnline == StatusFrom)
  1700. {
  1701. DeleteCSCFileTree (pwszSource, pwszSkipSubdir, TRUE);
  1702. DeleteCSCShareIfEmpty (pwszSource, StatusFrom);
  1703. }
  1704. }
  1705. gpEvents->Report(
  1706. EVENT_FDEPLOY_FOLDER_REDIRECT,
  1707. 1,
  1708. m_szLocDisplayName );
  1709. return ERROR_SUCCESS;
  1710. }
  1711. //+--------------------------------------------------------------------------
  1712. //
  1713. // Member: PreventRedirection
  1714. //
  1715. // Synopsis: this function prevents the redirection code from attempting
  1716. // redirection. Also prevents redirection of any of the child
  1717. // folders.
  1718. //
  1719. // Arguments: [in] Status : the error code indicating the cause of failure.
  1720. //
  1721. // Returns: nothing. It will always succeed.
  1722. //
  1723. // History: 9/20/1999 RahulTh created
  1724. //
  1725. // Notes: if the pre-processing step that handles the user name change
  1726. // fails for some reason, this function is invoked so that
  1727. // any attempt at applying simultaneous policy changes is thwarted
  1728. //
  1729. //---------------------------------------------------------------------------
  1730. void CRedirectInfo::PreventRedirection (DWORD Status)
  1731. {
  1732. m_bRedirectionAttempted = TRUE;
  1733. m_StatusRedir = Status;
  1734. if (m_pChild)
  1735. PreventDescendantRedirection (Status);
  1736. return;
  1737. }
  1738. //+--------------------------------------------------------------------------
  1739. //
  1740. // Member: PreventDescendantRedirection
  1741. //
  1742. // Synopsis: this function invalidates the data in the children so that
  1743. // the client extension will not try to redirect them
  1744. // this is necessary to prevent redirection of children if the
  1745. // redirection of the parents failed.
  1746. //
  1747. // Arguments: [in] Status : the error code indicating the cause of failure
  1748. //
  1749. // Returns: nothing. it will always succeed.
  1750. //
  1751. // History: 11/21/1998 RahulTh created
  1752. //
  1753. // Notes:
  1754. //
  1755. //---------------------------------------------------------------------------
  1756. void CRedirectInfo::PreventDescendantRedirection (DWORD Status)
  1757. {
  1758. if (! m_pChild) //nothing to do if this is not a parent
  1759. return;
  1760. m_pChild->m_bRedirectionAttempted = TRUE;
  1761. m_pChild->m_StatusRedir = Status;
  1762. //disable Startup too if start menu failed.
  1763. if (StartMenu == m_rID)
  1764. {
  1765. m_pChild->m_pChild->m_bRedirectionAttempted = TRUE;
  1766. m_pChild->m_pChild->m_StatusRedir = Status;
  1767. }
  1768. return;
  1769. }
  1770. //+--------------------------------------------------------------------------
  1771. //
  1772. // Member: CRedirectInfo::UpdateDescendant
  1773. //
  1774. // Synopsis: fills up the internal variables of a descendant object
  1775. // if it is supposed to follow the parent by using the
  1776. // data stored in the parent object
  1777. //
  1778. // Arguments: none
  1779. //
  1780. // Returns: nothing
  1781. //
  1782. // History: 10/6/1998 RahulTh created
  1783. //
  1784. // Notes:
  1785. //
  1786. //---------------------------------------------------------------------------
  1787. DWORD CRedirectInfo::UpdateDescendant (void)
  1788. {
  1789. DWORD len;
  1790. WCHAR * szLoc = NULL;
  1791. DWORD Status;
  1792. Status = ERROR_SUCCESS;
  1793. if (!m_pParent) //this is not a special descendant
  1794. goto UpdateEnd;
  1795. if (!(m_dwFlags & REDIR_FOLLOW_PARENT))
  1796. goto UpdateEnd; //nothing to do. this descendant is not supposed to follow the parent
  1797. if (!m_pParent->m_fDataValid || (m_pParent->m_dwFlags & REDIR_DONT_CARE))
  1798. {
  1799. m_fDataValid = m_pParent->m_fDataValid;
  1800. m_dwFlags = REDIR_DONT_CARE;
  1801. goto UpdateEnd;
  1802. }
  1803. m_fDataValid = m_pParent->m_fDataValid;
  1804. m_bFollowsParent = TRUE;
  1805. //if we are here, policy has been specified for the parent
  1806. len = lstrlen (m_szLocDisplayName) + lstrlen (m_pParent->m_szLocation) + 2; //one extra for the backslash
  1807. if (m_cbLocSize < len)
  1808. {
  1809. //we need to allocate memory
  1810. szLoc = new WCHAR [len];
  1811. if (!szLoc)
  1812. {
  1813. //out of memory. cannot derive info. from parent. will have to ignore this GPO
  1814. DebugMsg((DM_VERBOSE, IDS_DERIVEINFO_ERROR, m_szLocDisplayName));
  1815. m_dwFlags = REDIR_DONT_CARE;
  1816. m_fDataValid = FALSE;
  1817. Status = ERROR_OUTOFMEMORY;
  1818. goto UpdateEnd;
  1819. }
  1820. if (m_cbLocSize)
  1821. delete [] m_szLocation;
  1822. m_szLocation = szLoc;
  1823. m_cbLocSize = len;
  1824. }
  1825. if (m_pSid)
  1826. {
  1827. delete [] ((BYTE*) m_pSid);
  1828. m_pSid = NULL;
  1829. }
  1830. Status = MySidCopy (&m_pSid, m_pParent->m_pSid);
  1831. if ( ERROR_SUCCESS != Status )
  1832. {
  1833. goto UpdateEnd;
  1834. }
  1835. //copy the data (based on code above, the buffer is large enough, so no error checking is needed
  1836. //first get the settings
  1837. m_dwFlags = m_pParent->m_dwFlags & (REDIR_SETACLS | REDIR_MOVE_CONTENTS | REDIR_RELOCATEONREMOVE);
  1838. (void) StringCchCopy(m_szLocation, m_cbLocSize, m_pParent->m_szLocation);
  1839. len = lstrlen (m_szLocation);
  1840. if (len > 0 && L'\\' != m_szLocation[len - 1])
  1841. {
  1842. (void) StringCchCat(m_szLocation, m_cbLocSize, L"\\");
  1843. //add a \ only if the parent's path is not
  1844. //terminated with a \. Otherwise, we will
  1845. //end up with 2 \ in the child's path which
  1846. //will land SHGetFolderPath into trouble
  1847. //after the redirection is done.
  1848. }
  1849. (void) StringCchCat(m_szLocation, m_cbLocSize, m_szLocDisplayName); //use the localized folder name
  1850. m_bRemove = m_pParent->m_bRemove;
  1851. UpdateEnd:
  1852. return Status;
  1853. }
  1854. //+--------------------------------------------------------------------------
  1855. //
  1856. // Member: CRedirectInfo::operator=
  1857. //
  1858. // Synopsis: overloaded assignment operator used for merging
  1859. //
  1860. // Arguments: standard
  1861. //
  1862. // Returns: standard
  1863. //
  1864. // History: 10/6/1998 RahulTh created
  1865. //
  1866. // Notes: DO NOT copy the values of m_bRedirectionAttempted and
  1867. // m_StatusRedir in this function.
  1868. //
  1869. //---------------------------------------------------------------------------
  1870. CRedirectInfo& CRedirectInfo::operator= (const CRedirectInfo& ri)
  1871. {
  1872. WCHAR * szLoc = 0;
  1873. DWORD Status;
  1874. PSID Sid;
  1875. HRESULT hr = S_OK;
  1876. ASSERT (m_rID == ri.m_rID);
  1877. if (!ri.m_fDataValid)
  1878. goto AssignEnd;
  1879. if ((ri.m_dwFlags & REDIR_FOLLOW_PARENT) && MyPics == m_rID)
  1880. {
  1881. m_fDataValid = ri.m_fDataValid;
  1882. m_dwFlags = REDIR_FOLLOW_PARENT;
  1883. m_bRemove = ri.m_bRemove;
  1884. if (m_bValidGPO = ri.m_bValidGPO) //note:this IS an assignment -- not a comparison
  1885. (void) StringCbCopy(m_szGPOName, sizeof(m_szGPOName), ri.m_szGPOName);
  1886. else
  1887. m_szGPOName[0] = L'\0';
  1888. goto AssignEnd;
  1889. }
  1890. else if ((ri.m_dwFlags & (REDIR_DONT_CARE | REDIR_FOLLOW_PARENT)))
  1891. {
  1892. //REDIR_FOLLOW_PARENT will be set only if UpdateDescendant ran out of memory
  1893. //in any case, we will have to ignore the policy
  1894. //note that we have to special case My Pics above because UpdateDescendant
  1895. //is called for My Pics after all the policies have been looked at
  1896. //thus it has not been called at this point yet.
  1897. //the reason we call UpdateDescendant for My Pictures after looking at
  1898. //all the policies because it is possible to specify "Follow My Docs"
  1899. //in one policy and specify the location of My Docs in another policy
  1900. if (!m_fDataValid)
  1901. {
  1902. m_fDataValid = ri.m_fDataValid;
  1903. m_dwFlags = REDIR_DONT_CARE;
  1904. m_bRemove = ri.m_bRemove;
  1905. if (m_bValidGPO = ri.m_bValidGPO) //note: this IS an assignment -- not a comparison
  1906. (void) StringCbCopy(m_szGPOName, sizeof(m_szGPOName), ri.m_szGPOName);
  1907. else
  1908. m_szGPOName[0] = L'\0';
  1909. }
  1910. goto AssignEnd; //ignore. no policy settings for the GPO being merged.
  1911. }
  1912. //note: in the following code... before modifying any of the data
  1913. //we must make sure that we can get memory for all of the members
  1914. //if we fail for even one of them and we have already changed the rest
  1915. //we can run into an inconsistent state. Therefore, we first allocate
  1916. //all the required memory and then actually proceed with the copy.
  1917. Sid = 0;
  1918. Status = MySidCopy (&Sid, ri.m_pSid);
  1919. if (ERROR_SUCCESS != Status)
  1920. {
  1921. DebugMsg ((DM_VERBOSE, IDS_MERGE_FAILURE, m_szLocDisplayName));
  1922. goto AssignEnd;
  1923. }
  1924. if (m_cbLocSize < ri.m_cbLocSize)
  1925. {
  1926. szLoc = new WCHAR [ri.m_cbLocSize];
  1927. if (!szLoc)
  1928. {
  1929. //we could not obtain memory to store the new path.
  1930. //we will have to ignore this policy
  1931. DebugMsg ((DM_VERBOSE, IDS_MERGE_FAILURE, m_szLocDisplayName));
  1932. delete [] ((BYTE*) Sid); //do not do this at the end. The same memory will be used by m_pSid.
  1933. goto AssignEnd;
  1934. }
  1935. if (m_cbLocSize) delete [] m_szLocation;
  1936. m_szLocation = szLoc;
  1937. m_cbLocSize = ri.m_cbLocSize;
  1938. }
  1939. //now we have the required memory, so we won't fail.
  1940. //fill in the data.
  1941. if (m_pSid)
  1942. delete [] ((BYTE*) m_pSid);
  1943. m_pSid = Sid;
  1944. (void) StringCchCopy(m_szLocation, m_cbLocSize, ri.m_szLocation);
  1945. m_dwFlags = ri.m_dwFlags & (REDIR_SETACLS | REDIR_MOVE_CONTENTS | REDIR_RELOCATEONREMOVE);
  1946. m_bRemove = ri.m_bRemove;
  1947. m_bFollowsParent = ri.m_bFollowsParent;
  1948. m_fDataValid = ri.m_fDataValid;
  1949. if (m_bValidGPO = ri.m_bValidGPO) //note: this IS an assignment not a comparison
  1950. (void) StringCbCopy(m_szGPOName, sizeof(m_szGPOName), ri.m_szGPOName);
  1951. else
  1952. m_szGPOName[0] = L'\0';
  1953. AssignEnd:
  1954. return *this;
  1955. }
  1956. //+--------------------------------------------------------------------------
  1957. //
  1958. // Member: CRedirectInfo::ComputeEffectivePolicyRemoval
  1959. //
  1960. // Synopsis: tries to find out if the removal of a user from a group
  1961. // has caused a particular policy to be effectively removed
  1962. // for a particular user.
  1963. //
  1964. // Arguments: [pGPOList] : a list of GPOs still in effect for this user.
  1965. // if a GPO is effectively removed for this user, it
  1966. // has to figure in this list.
  1967. // [pFileDB] : pointer to the file DB structure
  1968. //
  1969. // Returns:
  1970. //
  1971. // History: 2/18/1999 RahulTh created
  1972. //
  1973. // Notes: this also detects cases where a user's group membership may
  1974. // not have changed but the policy no longer specifies any
  1975. // target for this group.
  1976. //
  1977. //---------------------------------------------------------------------------
  1978. DWORD CRedirectInfo::ComputeEffectivePolicyRemoval (
  1979. PGROUP_POLICY_OBJECT pDeletedGPOList,
  1980. PGROUP_POLICY_OBJECT pChangedGPOList,
  1981. CFileDB * pFileDB)
  1982. {
  1983. WCHAR pwszLocalPath[MAX_PATH];
  1984. WCHAR * pwszLocalIniFile = NULL;
  1985. PGROUP_POLICY_OBJECT pGPO;
  1986. WCHAR * pwszGPTIniFilePath = NULL;
  1987. DWORD Length = 0;
  1988. DWORD Status = ERROR_SUCCESS;
  1989. BOOL bStatus;
  1990. HANDLE hFind;
  1991. WIN32_FIND_DATA FindData;
  1992. WCHAR pwszDefault[] = L"*";
  1993. DWORD dwFlags;
  1994. WCHAR * pwszReturnedString = NULL;
  1995. DWORD Size = 0;
  1996. UNICODE_STRING StringW;
  1997. DWORD i;
  1998. PTOKEN_GROUPS pGroups;
  1999. WCHAR pwszSid[MAX_PATH]; //more than enough to store a sid.
  2000. BOOL bGPOInChangedList = FALSE;
  2001. //if the policy resultant is not set to DONT_CARE, it means that even if a
  2002. //policy has been effectively removed due to a group change or removal of a
  2003. //group from the advanced settings, some other policy has taken precedence
  2004. //and as a result, the policy resultant should remain the way it is.
  2005. if (! (m_dwFlags & REDIR_DONT_CARE))
  2006. {
  2007. Status = ERROR_SUCCESS;
  2008. goto CmpEffPolRem_End;
  2009. }
  2010. //there is no valid GPO stored in the per user per machine cache.
  2011. //so we cannot do much.
  2012. if (!gSavedSettings[m_rID].m_bValidGPO)
  2013. {
  2014. Status = ERROR_SUCCESS;
  2015. goto CmpEffPolRem_End;
  2016. }
  2017. //if the location of this folder was not specified by policy at last logon
  2018. //a group change cannot result in an effective policy removal for this folder.
  2019. if (gSavedSettings[m_rID].m_dwFlags & REDIR_DONT_CARE)
  2020. {
  2021. Status = ERROR_SUCCESS;
  2022. goto CmpEffPolRem_End;
  2023. }
  2024. //if we are here, then the folder was last redirected through policy and now
  2025. //either policy does not care, or a group change makes it seem so. If it is
  2026. //the latter, then we have to compute effective policy removal. Also, it is
  2027. //possible that the last policy application was a partial success and
  2028. //therefore a GPO that got deleted did not show up in either the changed
  2029. //GPO list or the deleted GPO list. We have to take into account that case
  2030. //too.
  2031. //first check if the GPO is present in the deleted GPO list.
  2032. for (pGPO = pDeletedGPOList; pGPO; pGPO = pGPO->pNext)
  2033. {
  2034. if (0 == _wcsicmp (gSavedSettings[m_rID].m_szGPOName, pGPO->szGPOName))
  2035. break;
  2036. }
  2037. if (!pGPO)
  2038. {
  2039. //if the policy isn't in the deleted GPO list, check if it is in the
  2040. //changed GPO list. If it isn't then this is a GPO that got deleted but did
  2041. //not show up in any of the lists because it never got fully applied.
  2042. //if it is, then either this is actually a don't care situation or it
  2043. //should be treated as policy removal because there was a group change.
  2044. for (pGPO = pChangedGPOList; pGPO; pGPO = pGPO->pNext)
  2045. {
  2046. if (0 == _wcsicmp (gSavedSettings[m_rID].m_szGPOName, pGPO->szGPOName))
  2047. break;
  2048. }
  2049. if (NULL != pGPO) //it is in the changed GPO list.
  2050. {
  2051. bGPOInChangedList = TRUE;
  2052. //get the path to the ini file on the sysvol.
  2053. Length = wcslen(pGPO->lpFileSysPath) + wcslen(GPT_SUBDIR) + wcslen (INIFILE_NAME) + 1;
  2054. __try {
  2055. pwszGPTIniFilePath = (WCHAR *) alloca( Length * sizeof(WCHAR) );
  2056. } __except(GetExceptionCode() == STATUS_STACK_OVERFLOW) {
  2057. _resetstkoflw();
  2058. pwszGPTIniFilePath = NULL;
  2059. Status = ERROR_OUTOFMEMORY;
  2060. goto CmpEffPolRem_End;
  2061. }
  2062. Status = HRESULT_CODE(StringCchCopy( pwszGPTIniFilePath, Length, pGPO->lpFileSysPath ));
  2063. if ( Status != ERROR_SUCCESS )
  2064. {
  2065. goto CmpEffPolRem_End;
  2066. }
  2067. Status = HRESULT_CODE(StringCchCat( pwszGPTIniFilePath, Length, GPT_SUBDIR ));
  2068. if ( Status != ERROR_SUCCESS )
  2069. {
  2070. goto CmpEffPolRem_End;
  2071. }
  2072. Status = HRESULT_CODE(StringCchCat( pwszGPTIniFilePath, Length, INIFILE_NAME ));
  2073. if ( Status != ERROR_SUCCESS )
  2074. {
  2075. goto CmpEffPolRem_End;
  2076. }
  2077. }
  2078. }
  2079. //get the path to the locally cached copy of the ini file.
  2080. Length = wcslen (pFileDB->_pwszLocalPath) + wcslen (gSavedSettings[m_rID].m_szGPOName) + 6;
  2081. __try {
  2082. pwszLocalIniFile = (WCHAR *) alloca (Length * sizeof (WCHAR));
  2083. } __except(GetExceptionCode() == STATUS_STACK_OVERFLOW) {
  2084. _resetstkoflw();
  2085. pwszLocalIniFile = NULL;
  2086. Status = ERROR_OUTOFMEMORY;
  2087. goto CmpEffPolRem_End;
  2088. }
  2089. Status = HRESULT_CODE(StringCchCopy( pwszLocalIniFile, Length, pFileDB->_pwszLocalPath ));
  2090. if ( Status != ERROR_SUCCESS )
  2091. {
  2092. goto CmpEffPolRem_End;
  2093. }
  2094. Status = HRESULT_CODE(StringCchCat( pwszLocalIniFile, Length, L"\\" ));
  2095. if ( Status != ERROR_SUCCESS )
  2096. {
  2097. goto CmpEffPolRem_End;
  2098. }
  2099. Status = HRESULT_CODE(StringCchCat( pwszLocalIniFile, Length, gSavedSettings[m_rID].m_szGPOName ));
  2100. if ( Status != ERROR_SUCCESS )
  2101. {
  2102. goto CmpEffPolRem_End;
  2103. }
  2104. Status = HRESULT_CODE(StringCchCat( pwszLocalIniFile, Length, L".ini" ));
  2105. if ( Status != ERROR_SUCCESS )
  2106. {
  2107. goto CmpEffPolRem_End;
  2108. }
  2109. Status = ERROR_SUCCESS;
  2110. bStatus = FALSE;
  2111. if (bGPOInChangedList)
  2112. {
  2113. bStatus = CopyFile( pwszLocalIniFile, pwszGPTIniFilePath, FALSE );
  2114. }
  2115. if ( ! bStatus ) // Work off of the locally cached copy.
  2116. {
  2117. //try to use the cached version if any.
  2118. hFind = FindFirstFile( pwszLocalIniFile, &FindData );
  2119. if ( INVALID_HANDLE_VALUE != hFind )
  2120. {
  2121. Status = ERROR_SUCCESS;
  2122. FindClose( hFind );
  2123. }
  2124. else
  2125. {
  2126. Status = GetLastError();
  2127. }
  2128. }
  2129. //we don't have an ini file to work with, so we can't do much but quit.
  2130. if (ERROR_SUCCESS != Status)
  2131. goto CmpEffPolRem_End;
  2132. //now we have an ini file. so read the relevant info. from it.
  2133. //first grab the flags
  2134. Status = SafeGetPrivateProfileStringW (
  2135. L"FolderStatus",
  2136. m_szDisplayName,
  2137. pwszDefault,
  2138. &pwszReturnedString,
  2139. &Size,
  2140. pwszLocalIniFile
  2141. );
  2142. if (ERROR_SUCCESS != Status)
  2143. goto CmpEffPolRem_End;
  2144. if (L'*' == *pwszReturnedString)
  2145. {
  2146. //there are no settings for this folder. Possibly because
  2147. //someone changed the settings on the server.
  2148. //Treat it as a don't care.
  2149. goto CmpEffPolRem_End;
  2150. }
  2151. //now grab the hex flags
  2152. StringW.Buffer = pwszReturnedString;
  2153. StringW.Length = wcslen (pwszReturnedString) * sizeof (WCHAR);
  2154. StringW.MaximumLength = StringW.Length + sizeof(WCHAR);
  2155. RtlUnicodeStringToInteger( &StringW, 16, &dwFlags );
  2156. //if this is a special descendant folder and it is supposed to follow
  2157. //the parent, we might first have to derive its settings from the
  2158. //parent and then proceed.
  2159. if (m_pParent && (dwFlags & REDIR_FOLLOW_PARENT))
  2160. {
  2161. //the check for m_pParent is redundant since non-descendant folders
  2162. //can never have this flag. but this has been added as a safety mechanism
  2163. //against ini file corruption
  2164. //we will have to derive the settings from the parent later on.
  2165. m_dwFlags = REDIR_FOLLOW_PARENT;
  2166. m_fDataValid = TRUE;
  2167. m_bFollowsParent = TRUE;
  2168. m_bRemove = TRUE;
  2169. m_bValidGPO = FALSE; //since this is a removal
  2170. m_szGPOName[0] = L'\0';
  2171. Status = UpdateDescendant(); //derive the settings from the parent
  2172. goto CmpEffPolRem_End;
  2173. }
  2174. if ((dwFlags & REDIR_DONT_CARE) ||
  2175. (m_bFollowsParent && (m_dwFlags & REDIR_DONT_CARE)))
  2176. {
  2177. //the policy has been changed to Don't Care. so it is not a removal.
  2178. //leave everything as is.
  2179. goto CmpEffPolRem_End;
  2180. }
  2181. if (!(dwFlags & REDIR_RELOCATEONREMOVE))
  2182. {
  2183. //the choice is to orphan. so let it stay as don't care.
  2184. goto CmpEffPolRem_End;
  2185. }
  2186. //
  2187. // If the GPO that was used for redirection the last time is not in the
  2188. // changed GPO list, then this is surely a policy removal.
  2189. // otherwise, it can either be a policy removal due to a group change (or
  2190. // a group's policy getting removed from the GPO or it can be just that
  2191. // the policy was changed to Don't care.
  2192. //
  2193. if (bGPOInChangedList)
  2194. {
  2195. //
  2196. // Check if the user is still a member of the group that was used for
  2197. // redirection.
  2198. //
  2199. pGroups = pFileDB->_pGroups;
  2200. for (i = 0, bStatus = FALSE;
  2201. i < pGroups->GroupCount && !bStatus;
  2202. i++
  2203. )
  2204. {
  2205. bStatus = RtlEqualSid (gSavedSettings[m_rID].m_psid, pGroups->Groups[i].Sid);
  2206. }
  2207. if (bStatus) //the user still belongs to that group.
  2208. {
  2209. //so perhaps the policy for this group was removed.
  2210. //make sure that this is the case.
  2211. Status = ERROR_INVALID_SID;
  2212. if (gSavedSettings[m_rID].m_psid)
  2213. {
  2214. pwszSid [0] = L'\0';
  2215. StringW.Length = 0;
  2216. StringW.MaximumLength = sizeof (pwszSid);
  2217. StringW.Buffer = pwszSid;
  2218. Status = RtlConvertSidToUnicodeString (&StringW, gSavedSettings[m_rID].m_psid, FALSE);
  2219. }
  2220. if (ERROR_SUCCESS != Status)
  2221. goto CmpEffPolRem_End;
  2222. Status = SafeGetPrivateProfileStringW (
  2223. m_szDisplayName,
  2224. StringW.Buffer,
  2225. pwszDefault,
  2226. &pwszReturnedString,
  2227. &Size,
  2228. pwszLocalIniFile
  2229. );
  2230. if (ERROR_SUCCESS != Status)
  2231. goto CmpEffPolRem_End;
  2232. if (0 != _wcsicmp(pwszReturnedString, pwszDefault))
  2233. {
  2234. //
  2235. // Policy exists for this folder so leave things the way they are.
  2236. // Ideally this is not possible and one should never enter this
  2237. // code path
  2238. //
  2239. goto CmpEffPolRem_End;
  2240. }
  2241. }
  2242. }
  2243. //
  2244. // If the user is no longer a member of the group, then this is clearly
  2245. // a case where the policy is effectively removed because the user was
  2246. // removed from a group that was used for redirection.
  2247. //
  2248. // At any rate, if we are here, then this is a policy removal so make the
  2249. // appropriate settings
  2250. //
  2251. Size = wcslen(L"%USERPROFILE%\\") + wcslen(m_szLocFolderRelativePath) + 1;
  2252. if (m_cbLocSize && (m_cbLocSize < Size))
  2253. {
  2254. delete [] m_szLocation;
  2255. m_cbLocSize = 0;
  2256. m_szLocation = new WCHAR [Size];
  2257. if (!m_szLocation)
  2258. {
  2259. Status = ERROR_OUTOFMEMORY;
  2260. goto CmpEffPolRem_End;
  2261. }
  2262. m_cbLocSize = Size;
  2263. }
  2264. (void) StringCchCopy(m_szLocation, m_cbLocSize, L"%USERPROFILE%\\");
  2265. (void) StringCchCat(m_szLocation, m_cbLocSize, m_szLocFolderRelativePath);
  2266. m_fDataValid = TRUE;
  2267. m_dwFlags = dwFlags;
  2268. m_bRemove = TRUE;
  2269. m_bValidGPO = FALSE; //since this is a removal.
  2270. m_szGPOName[0] = '\0';
  2271. DebugMsg((DM_VERBOSE, IDS_EFFECTIVE_REMOVE_POLICY, pGPO?pGPO->lpDisplayName:gSavedSettings[m_rID].m_szGPOName, m_szLocDisplayName));
  2272. CmpEffPolRem_End:
  2273. if (pwszReturnedString)
  2274. delete [] pwszReturnedString;
  2275. return Status;
  2276. }
  2277. CRedirectInfo::HasPolicy()
  2278. {
  2279. BOOL bHasExplicitPolicy;
  2280. BOOL bHasPolicy;
  2281. bHasExplicitPolicy = ! ( m_dwFlags & REDIR_DONT_CARE );
  2282. //
  2283. // If this folder appears to be explicitly redirected, we
  2284. // should be sure that its parent isn't explicitly denied,
  2285. // if it is configured to follow the parent
  2286. //
  2287. if ( ( m_dwFlags & REDIR_FOLLOW_PARENT ) && m_pParent && bHasExplicitPolicy )
  2288. {
  2289. bHasPolicy = m_pParent->HasPolicy();
  2290. }
  2291. else
  2292. {
  2293. bHasPolicy = bHasExplicitPolicy;
  2294. }
  2295. return bHasPolicy;
  2296. }