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.

733 lines
24 KiB

  1. //*************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation 1998
  4. // All rights reserved
  5. //
  6. // fdeploy.cxx
  7. //
  8. //*************************************************************
  9. #include "fdeploy.hxx"
  10. #include "rsopdbg.h"
  11. #define ABORT_IF_NECESSARY if (*pbAbort) \
  12. { \
  13. Status = ERROR_REQUEST_ABORTED; \
  14. goto ProcessGPOCleanup; \
  15. }
  16. #define FLUSH_AND_ABORT_IF_NECESSARY if (*pbAbort) \
  17. { \
  18. Status = ERROR_REQUEST_ABORTED; \
  19. goto ProcessGPOFlush; \
  20. }
  21. CDebug dbgRsop( L"Software\\Microsoft\\Windows NT\\CurrentVersion\\winlogon",
  22. L"RsopDebugLevel",
  23. L"gpdas.log",
  24. L"gpdas.bak",
  25. TRUE );
  26. //status callback function
  27. PFNSTATUSMESSAGECALLBACK gpStatusCallback;
  28. //saved per user per machine settings
  29. CSavedSettings gSavedSettings[(int)EndRedirectable];
  30. //if CSC is enabled or not
  31. BOOL g_bCSCEnabled;
  32. // Used for LoadString.
  33. HINSTANCE ghDllInstance = 0;
  34. HINSTANCE ghFileDeployment = 0;
  35. WCHAR gwszStatus[12];
  36. WCHAR gwszNumber[20];
  37. // User info.
  38. CUsrInfo gUserInfo;
  39. const WCHAR * gwszUserName = NULL;
  40. //+--------------------------------------------------------------------------
  41. //
  42. // Function: ReinitGlobals
  43. //
  44. // Synopsis: Reinitializes the global variables that should not carry
  45. // over to the next run of folder redirection.
  46. //
  47. // Arguments: none.
  48. //
  49. // Returns: nothing.
  50. //
  51. // History: 12/17/2000 RahulTh created
  52. //
  53. // Notes: static members of classes and other global variables are
  54. // initialized only when the dll is loaded. So if this dll
  55. // stays loaded across logons, then the fact that the globals
  56. // have been initialized based on a previous logon can cause
  57. // problems. Therefore, this function is used to reinitialize
  58. // the globals.
  59. //
  60. //---------------------------------------------------------------------------
  61. void ReinitGlobals (void)
  62. {
  63. DWORD i;
  64. // First reset the static members of various classes.
  65. CSavedSettings::ResetStaticMembers();
  66. // Now reset members of various global objects.
  67. gUserInfo.ResetMembers();
  68. for (i = 0; i < (DWORD) EndRedirectable; i++)
  69. {
  70. gSavedSettings[i].ResetMembers();
  71. gPolicyResultant[i].ResetMembers();
  72. gAddedPolicyResultant[i].ResetMembers();
  73. gDeletedPolicyResultant[i].ResetMembers();
  74. }
  75. return;
  76. }
  77. extern "C" DWORD WINAPI
  78. ProcessGroupPolicyEx (
  79. DWORD dwFlags,
  80. HANDLE hUserToken,
  81. HKEY hKeyRoot,
  82. PGROUP_POLICY_OBJECT pDeletedGPOList,
  83. PGROUP_POLICY_OBJECT pChangedGPOList,
  84. ASYNCCOMPLETIONHANDLE pHandle,
  85. BOOL* pbAbort,
  86. PFNSTATUSMESSAGECALLBACK pStatusCallback,
  87. IN IWbemServices *pWbemServices,
  88. HRESULT *phrRsopStatus )
  89. {
  90. // Reinitialize all globals that should not get carried over from
  91. // a previous run of folder redirection. This is necessary just in
  92. // case this dll is not unloaded by userenv after each run. Also, we should
  93. // do this before any other processing is done to ensure correct behavior.
  94. ReinitGlobals();
  95. *phrRsopStatus = S_OK;
  96. CRsopContext DiagnosticModeContext( pWbemServices, phrRsopStatus, FDEPLOYEXTENSIONGUID );
  97. return ProcessGroupPolicyInternal (
  98. dwFlags,
  99. hUserToken,
  100. hKeyRoot,
  101. pDeletedGPOList,
  102. pChangedGPOList,
  103. pHandle,
  104. pbAbort,
  105. pStatusCallback,
  106. &DiagnosticModeContext );
  107. }
  108. extern "C" DWORD WINAPI
  109. GenerateGroupPolicy (
  110. IN DWORD dwFlags,
  111. IN BOOL *pbAbort,
  112. IN WCHAR *pwszSite,
  113. IN PRSOP_TARGET pComputerTarget,
  114. IN PRSOP_TARGET pUserTarget )
  115. {
  116. DWORD Status;
  117. // Reinitialize all globals that should not get carried over from
  118. // a previous run of folder redirection. This is necessary just in
  119. // case this dll is not unloaded by userenv after each run. Also, we should
  120. // do this before any other processing is done to ensure correct behavior.
  121. ReinitGlobals();
  122. CRsopContext PlanningModeContext( pUserTarget, FDEPLOYEXTENSIONGUID );
  123. Status = ERROR_SUCCESS;
  124. //
  125. // There is no machine policy, only user --
  126. // process only user policy
  127. //
  128. if ( pUserTarget && pUserTarget->pGPOList )
  129. {
  130. gUserInfo.SetPlanningModeContext( &PlanningModeContext );
  131. Status = ProcessGroupPolicyInternal(
  132. dwFlags,
  133. NULL,
  134. NULL,
  135. NULL,
  136. pUserTarget->pGPOList,
  137. NULL,
  138. pbAbort,
  139. NULL,
  140. &PlanningModeContext);
  141. }
  142. return Status;
  143. }
  144. DWORD ProcessGroupPolicyInternal (
  145. DWORD dwFlags,
  146. HANDLE hUserToken,
  147. HKEY hKeyRoot,
  148. PGROUP_POLICY_OBJECT pDeletedGPOList,
  149. PGROUP_POLICY_OBJECT pChangedGPOList,
  150. ASYNCCOMPLETIONHANDLE pHandle,
  151. BOOL* pbAbort,
  152. PFNSTATUSMESSAGECALLBACK pStatusCallback,
  153. CRsopContext* pRsopContext )
  154. {
  155. BOOL bStatus;
  156. DWORD Status = ERROR_SUCCESS;
  157. DWORD RedirStatus;
  158. CFileDB CurrentDB;
  159. DWORD i;
  160. PGROUP_POLICY_OBJECT pCurrGPO = NULL;
  161. HANDLE hDupToken = NULL;
  162. BOOL fUpdateMyPicsLinks = FALSE;
  163. BOOL fPlanningMode;
  164. BOOL fWriteRsopLog = FALSE;
  165. BOOL bForcedRefresh = FALSE;
  166. gpStatusCallback = pStatusCallback;
  167. fPlanningMode = pRsopContext->IsPlanningModeEnabled();
  168. //
  169. // Even though this extension has indicated its preference for not
  170. // handling machine policies, the admin. might still override these
  171. // preferences through policy. Since, this extension is not designed to
  172. // handled this situation, we need to explicitly check for these cases and
  173. // quit at this point.
  174. //
  175. if (dwFlags & GPO_INFO_FLAG_MACHINE)
  176. {
  177. DebugMsg((DM_VERBOSE, IDS_INVALID_FLAGS));
  178. Status = ERROR_INVALID_FLAGS;
  179. goto ProcessGPOCleanup;
  180. }
  181. //some basic initializations first.
  182. InitDebugSupport();
  183. if ( dwFlags & GPO_INFO_FLAG_VERBOSE )
  184. gDebugLevel |= DL_VERBOSE | DL_EVENTLOG;
  185. gpEvents = new CEvents();
  186. if (!gpEvents)
  187. {
  188. DebugMsg((DM_VERBOSE, IDS_INIT_FAILED));
  189. Status = ERROR_OUTOFMEMORY;
  190. goto ProcessGPOCleanup;
  191. }
  192. gpEvents->Init();
  193. gpEvents->Reference();
  194. DebugMsg((DM_VERBOSE, IDS_PROCESSGPO));
  195. DebugMsg((DM_VERBOSE, IDS_GPO_FLAGS, dwFlags));
  196. ConditionalBreakIntoDebugger();
  197. if ( ! fPlanningMode )
  198. {
  199. bStatus = DuplicateToken (hUserToken,
  200. SecurityImpersonation,
  201. &hDupToken);
  202. if (!bStatus)
  203. {
  204. Status = GetLastError();
  205. gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0);
  206. goto ProcessGPOCleanup;
  207. }
  208. //impersonate the logged on user,
  209. bStatus = ImpersonateLoggedOnUser( hDupToken );
  210. //bail out if impersonation fails
  211. if (!bStatus)
  212. {
  213. gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0);
  214. Status = GetLastError();
  215. goto ProcessGPOCleanup;
  216. }
  217. g_bCSCEnabled = CSCIsCSCEnabled ();
  218. //try to get set ownership privileges. These will be required
  219. //when we copy over ownership information
  220. GetSetOwnerPrivileges (hDupToken);
  221. //get the user name -- this is used for tracking name changes.
  222. gwszUserName = gUserInfo.GetUserName (Status);
  223. if (ERROR_SUCCESS != Status)
  224. {
  225. DebugMsg ((DM_VERBOSE, IDS_GETNAME_FAILED, Status));
  226. gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0);
  227. goto ProcessGPOCleanup;
  228. }
  229. }
  230. //load the localized folder names and relative paths. (also see
  231. //notes before the function LoadLocalizedNames()
  232. Status = LoadLocalizedFolderNames ();
  233. if (ERROR_SUCCESS != Status)
  234. {
  235. gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0);
  236. goto ProcessGPOCleanup;
  237. }
  238. //now initialize those values for the CFileDB object that are going to
  239. //be the same across all the policies
  240. if (ERROR_SUCCESS != (Status = CurrentDB.Initialize(hDupToken, hKeyRoot, pRsopContext )))
  241. {
  242. gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0);
  243. goto ProcessGPOCleanup;
  244. }
  245. if ( ! fPlanningMode )
  246. {
  247. //now load the per user per machine settings saved during the last logon
  248. for (i = 0; i < (DWORD) EndRedirectable; i++)
  249. {
  250. Status = gSavedSettings[i].Load (&CurrentDB);
  251. if (ERROR_SUCCESS != Status)
  252. {
  253. gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0);
  254. goto ProcessGPOCleanup;
  255. }
  256. }
  257. }
  258. //now if the GPO_NOCHANGES flag has been specified, make sure that it is
  259. //okay not to do any processing
  260. bStatus = TRUE;
  261. if ( (dwFlags & GPO_INFO_FLAG_NOCHANGES) &&
  262. !fPlanningMode &&
  263. !( dwFlags & GPO_INFO_FLAG_LOGRSOP_TRANSITION ) )
  264. {
  265. for (bStatus = FALSE, i = 0;
  266. i < (DWORD)EndRedirectable && (!bStatus);
  267. i++)
  268. {
  269. bStatus = fPlanningMode ? TRUE : gSavedSettings[i].NeedsProcessing();
  270. }
  271. }
  272. if (!bStatus) //we are in good shape. No processing is required.
  273. {
  274. Status = ERROR_SUCCESS;
  275. DebugMsg ((DM_VERBOSE, IDS_NOCHANGES));
  276. goto ProcessGPOCleanup;
  277. }
  278. else
  279. {
  280. if ((dwFlags & GPO_INFO_FLAG_BACKGROUND) ||
  281. (dwFlags & GPO_INFO_FLAG_ASYNC_FOREGROUND))
  282. {
  283. //
  284. // Log an event only in the async. foreground case. In all other
  285. // cases just output a debug message. Note: The Background flag
  286. // will be set even in the async. foreground case. So we must
  287. // explicitly make this check against the async. foreground
  288. // flag.
  289. //
  290. if (dwFlags & GPO_INFO_FLAG_ASYNC_FOREGROUND)
  291. {
  292. gpEvents->Report (EVENT_FDEPLOY_POLICY_DELAYED, 0);
  293. }
  294. else
  295. {
  296. DebugMsg ((DM_VERBOSE, IDS_POLICY_DELAYED));
  297. }
  298. Status = ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED;
  299. goto ProcessGPOCleanup;
  300. }
  301. if ( ! fPlanningMode &&
  302. (dwFlags & GPO_INFO_FLAG_NOCHANGES))
  303. {
  304. // a user name or homedir change has occured and no gpo changes occurred,
  305. // so in order to perform RSoP logging, we will need to get our own
  306. // RSoP namespace since the GP engine does not give us the namespace
  307. // if no changes occurred -- we note this below
  308. bForcedRefresh = TRUE;
  309. fWriteRsopLog = TRUE;
  310. }
  311. }
  312. //
  313. // If we have changes or we are in planning mode, enable logging
  314. //
  315. if ( pChangedGPOList || pDeletedGPOList || fPlanningMode )
  316. {
  317. fWriteRsopLog = TRUE;
  318. }
  319. if ( fWriteRsopLog )
  320. {
  321. //
  322. // If RSoP logging should occur in logging mode, initialize
  323. // the rsop context -- this is not necessary in planning mode
  324. //
  325. if ( pRsopContext->IsDiagnosticModeEnabled() )
  326. {
  327. PSID pUserSid;
  328. pUserSid = gpEvents->UserSid();
  329. if ( pUserSid )
  330. {
  331. // This call requires elevated privileges to succeed.
  332. RevertToSelf();
  333. (void) pRsopContext->InitializeContext( pUserSid );
  334. // Re-impersonate the logged on user,
  335. bStatus = ImpersonateLoggedOnUser( hDupToken );
  336. // Bail out if impersonation fails
  337. if (!bStatus)
  338. {
  339. gpEvents->Report (EVENT_FDEPLOY_INIT_FAILED, 0);
  340. Status = GetLastError();
  341. goto ProcessGPOCleanup;
  342. }
  343. }
  344. else
  345. {
  346. pRsopContext->DisableRsop( ERROR_OUTOFMEMORY );
  347. }
  348. }
  349. CurrentDB.InitRsop( pRsopContext, bForcedRefresh );
  350. }
  351. //first process any user name changes.
  352. for (i = 0; i < (DWORD) EndRedirectable; i++)
  353. {
  354. Status = gSavedSettings[i].HandleUserNameChange(
  355. &CurrentDB,
  356. &(gPolicyResultant[i]));
  357. if (ERROR_SUCCESS != Status)
  358. {
  359. // Failure events will be reported while processing the name change
  360. goto ProcessGPOCleanup;
  361. }
  362. }
  363. //first process the deleted GPOs
  364. //we need to do this in reverse, because removed policies are sent
  365. //in reverse, that is the closest policy is sent last. So if you have
  366. //two policies that redirect the same folder and both of them are removed
  367. //simultaneously, then, the code gets the wrong value for the redirection
  368. //destination of the resultant set of removed policies and therefore
  369. //assumes that someone else must have modified it and therefore leaves it
  370. //alone
  371. if (pDeletedGPOList)
  372. {
  373. //go all the way to the end
  374. for (pCurrGPO = pDeletedGPOList; pCurrGPO->pNext; pCurrGPO = pCurrGPO->pNext)
  375. ;
  376. //now pCurrGPO points to the last policy in the removed list, so go at
  377. //it in the reverse order.
  378. for (; pCurrGPO; pCurrGPO = pCurrGPO->pPrev)
  379. {
  380. DebugMsg((DM_VERBOSE, IDS_GPO_NAME, pCurrGPO->szGPOName));
  381. DebugMsg((DM_VERBOSE, IDS_GPO_FILESYSPATH, pCurrGPO->lpFileSysPath));
  382. DebugMsg((DM_VERBOSE, IDS_GPO_DSPATH, pCurrGPO->lpDSPath));
  383. DebugMsg((DM_VERBOSE, IDS_GPO_DISPLAYNAME, pCurrGPO->lpDisplayName));
  384. //if we are unable to process even a single policy, we must abort
  385. //immediately otherwise we may end up with an incorrect resultant
  386. //policy.
  387. if (ERROR_SUCCESS != (Status = CurrentDB.Process (pCurrGPO, TRUE)))
  388. goto ProcessGPOCleanup;
  389. ABORT_IF_NECESSARY
  390. }
  391. }
  392. //update the descendants
  393. gDeletedPolicyResultant[(int) MyPics].UpdateDescendant ();
  394. //now process the other GPOs
  395. for (pCurrGPO = pChangedGPOList; pCurrGPO; pCurrGPO = pCurrGPO->pNext)
  396. {
  397. DebugMsg((DM_VERBOSE, IDS_GPO_NAME, pCurrGPO->szGPOName));
  398. DebugMsg((DM_VERBOSE, IDS_GPO_FILESYSPATH, pCurrGPO->lpFileSysPath));
  399. DebugMsg((DM_VERBOSE, IDS_GPO_DSPATH, pCurrGPO->lpDSPath));
  400. DebugMsg((DM_VERBOSE, IDS_GPO_DISPLAYNAME, pCurrGPO->lpDisplayName));
  401. //if we are unable to process even a single policy, we must abort
  402. //immediately otherwise we may end up with an incorrect resultant
  403. //policy.
  404. if (ERROR_SUCCESS != (Status = CurrentDB.Process (pCurrGPO, FALSE)))
  405. {
  406. goto ProcessGPOCleanup;
  407. }
  408. ABORT_IF_NECESSARY
  409. }
  410. if ( fPlanningMode )
  411. {
  412. goto ProcessGPOCleanup;
  413. }
  414. //now update the My Pics data. UpdateDescendant will derive the settings for
  415. //My Pics from My Docs if it is set to derive its settings from My Docs.
  416. gAddedPolicyResultant[(int) MyPics].UpdateDescendant ();
  417. //now merge the deleted policy resultant and added policy resultants
  418. for (i = 0; i < (DWORD) EndRedirectable; i++)
  419. {
  420. gPolicyResultant[i] = gDeletedPolicyResultant[i];
  421. gPolicyResultant[i] = gAddedPolicyResultant[i];
  422. //check to see if any group membership change has caused a policy to
  423. //be effectively removed for this user.
  424. gPolicyResultant[i].ComputeEffectivePolicyRemoval (pDeletedGPOList,
  425. pChangedGPOList,
  426. &CurrentDB);
  427. }
  428. //do the final redirection
  429. //we ignore errors that might occur in redirection
  430. //so that redirection of other folders is not hampered.
  431. //however, if there is a failure, we save that information
  432. //so that we can inform the group policy engine
  433. if (ERROR_SUCCESS == Status)
  434. {
  435. for (int i = 0; i < (int)EndRedirectable; i++)
  436. {
  437. RedirStatus= gPolicyResultant[i].Redirect(hDupToken, hKeyRoot,
  438. &CurrentDB);
  439. if ((ERROR_SUCCESS != RedirStatus) && (ERROR_SUCCESS == Status))
  440. Status = RedirStatus;
  441. FLUSH_AND_ABORT_IF_NECESSARY //abort if necessary, but first, flush the shell's special folder cache
  442. ///as we may have redirected some folders already.
  443. }
  444. //update shell links to MyPics within MyDocuments if policy specified
  445. //the location of at least one of MyDocs and MyPics and succeeded in
  446. //redirection. For additional details see comments at the beginning of
  447. //the function UpdateMyPicsShellLinks.
  448. if (
  449. (
  450. (!(gPolicyResultant[(int)MyDocs].GetFlags() & REDIR_DONT_CARE)) &&
  451. (ERROR_SUCCESS == gPolicyResultant[(int)MyDocs].GetRedirStatus())
  452. )
  453. ||
  454. (
  455. (!(gPolicyResultant[(int)MyPics].GetFlags() & REDIR_DONT_CARE)) &&
  456. (ERROR_SUCCESS == gPolicyResultant[(int)MyPics].GetRedirStatus())
  457. )
  458. )
  459. {
  460. fUpdateMyPicsLinks = TRUE;
  461. //note:we do not invoke the shell link update function here since
  462. //we need to flush the shell special folder cache or we may not
  463. //get the true current location of MyDocs or MyPics. Therefore,
  464. //the function is actually invoked below.
  465. }
  466. }
  467. else
  468. {
  469. DebugMsg((DM_VERBOSE, IDS_PROCESSREDIRECTS, Status));
  470. }
  471. //
  472. // Do not try to update the link (shell shortcut) in planning mode since
  473. // planning mode takes no real action, just records results
  474. //
  475. if ( fPlanningMode )
  476. {
  477. fUpdateMyPicsLinks = FALSE;
  478. }
  479. //flush the shell's special folder cache. we may have successfully redirected
  480. //some folders by the time we reach here. So it is always a good idea to let
  481. //the shell know about it.
  482. ProcessGPOFlush:
  483. if (fUpdateMyPicsLinks)
  484. UpdateMyPicsShellLinks(hDupToken,
  485. gPolicyResultant[(int)MyPics].GetLocalizedName());
  486. ProcessGPOCleanup: //don't leave any turds behind.
  487. if ( (ERROR_SUCCESS == Status) && !fPlanningMode )
  488. {
  489. //we have successfully applied all the policies, so remove any cached
  490. //ini files for removed policies.
  491. //any errors in deletion are ignored.
  492. DeleteCachedConfigFiles (pDeletedGPOList, &CurrentDB);
  493. }
  494. //we are done, so we stop running as the user
  495. if ( ! fPlanningMode )
  496. {
  497. RevertToSelf();
  498. }
  499. // In logging (aka diagnostic) mode, we need to ensure that
  500. // we reset the saved namespace before logging so that in the
  501. // no changes case where we need to log ( i.e. username / homedir change ),
  502. // we only log rsop data if RSoP was enabled at the last change
  503. if ( fWriteRsopLog )
  504. {
  505. (void) pRsopContext->DeleteSavedNameSpace();
  506. if ( pRsopContext->IsRsopEnabled() )
  507. {
  508. HRESULT hrLog;
  509. hrLog = CurrentDB.WriteRsopLog();
  510. if ( SUCCEEDED( hrLog ) )
  511. {
  512. (void) pRsopContext->SaveNameSpace();
  513. }
  514. }
  515. }
  516. if ( ! fPlanningMode )
  517. {
  518. if (hDupToken)
  519. CloseHandle (hDupToken);
  520. }
  521. if (gpEvents)
  522. gpEvents->Release();
  523. //restore the status message
  524. DisplayStatusMessage (IDS_DEFAULT_CALLBACK);
  525. // CPolicyDatabase::FreeDatabase();
  526. return Status;
  527. }
  528. extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
  529. {
  530. switch (dwReason)
  531. {
  532. case DLL_PROCESS_ATTACH :
  533. ghDllInstance = hInstance;
  534. DisableThreadLibraryCalls(hInstance);
  535. break;
  536. case DLL_PROCESS_DETACH :
  537. break;
  538. }
  539. return TRUE;
  540. }
  541. /////////////////////////////////////////////////////////////////////////////
  542. // DllRegisterServer - Adds entries to the system registry
  543. STDAPI DllRegisterServer(void)
  544. {
  545. DWORD dwDisp;
  546. LONG lResult;
  547. HKEY hKey;
  548. TCHAR EventFile[] = TEXT("%SystemRoot%\\System32\\fdeploy.dll");
  549. TCHAR ParamFile[] = TEXT("%SystemRoot%\\System32\\kernel32.dll");
  550. WCHAR EventSources[] = TEXT("(Folder Redirection,Application)\0" );
  551. DWORD dwTypes = 0x7;
  552. DWORD dwSet = 1;
  553. DWORD dwReset = 0;
  554. //register the dll as an extension of the policy engine
  555. lResult = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
  556. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions\\{25537BA6-77A8-11D2-9B6C-0000F8080861}"),
  557. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,
  558. NULL, &hKey, &dwDisp);
  559. if (lResult != ERROR_SUCCESS)
  560. {
  561. return SELFREG_E_CLASS;
  562. }
  563. RegSetValueEx (hKey, NULL, 0, REG_SZ, (LPBYTE) TEXT("Folder Redirection"),
  564. (lstrlen (TEXT("Folder Redirection")) + 1) * sizeof (TCHAR));
  565. RegSetValueEx (hKey, TEXT("ProcessGroupPolicyEx"), 0, REG_SZ, (LPBYTE)TEXT("ProcessGroupPolicyEx"),
  566. (lstrlen(TEXT("ProcessGroupPolicyEx")) + 1) * sizeof(TCHAR));
  567. RegSetValueEx (hKey, TEXT("DllName"), 0, REG_EXPAND_SZ, (LPBYTE)TEXT("fdeploy.dll"),
  568. (lstrlen(TEXT("fdeploy.dll")) + 1) * sizeof(TCHAR));
  569. RegSetValueEx (hKey, TEXT("NoMachinePolicy"), 0, REG_DWORD,
  570. (LPBYTE)&dwSet, sizeof (dwSet));
  571. RegSetValueEx (hKey, TEXT("NoSlowLink"), 0, REG_DWORD,
  572. (LPBYTE)&dwSet, sizeof (dwSet));
  573. RegSetValueEx (hKey, TEXT("PerUserLocalSettings"), 0, REG_DWORD,
  574. (LPBYTE)&dwSet, sizeof (dwSet));
  575. //we want the folder redirection extension to get loaded each time.
  576. RegSetValueEx (hKey, TEXT("NoGPOListChanges"), 0, REG_DWORD,
  577. (LPBYTE)&dwReset, sizeof (dwReset));
  578. //
  579. // New perf. stuff. We also want to get called in the background and
  580. // async. foreground case.
  581. //
  582. RegSetValueEx (hKey, TEXT("NoBackgroundPolicy"), 0, REG_DWORD,
  583. (LPBYTE)&dwReset, sizeof (dwReset));
  584. RegSetValueEx (hKey, TEXT("GenerateGroupPolicy"), 0, REG_SZ, (LPBYTE)TEXT("GenerateGroupPolicy"),
  585. (lstrlen (TEXT("GenerateGroupPolicy")) + 1) * sizeof(TCHAR));
  586. // Need to register event sources for RSoP
  587. RegSetValueEx (hKey, TEXT("EventSources"), 0, REG_MULTI_SZ, (LPBYTE)EventSources,
  588. sizeof(EventSources) );
  589. RegCloseKey (hKey);
  590. //register the dll as a source for event log messages
  591. lResult = RegCreateKeyEx (HKEY_LOCAL_MACHINE,
  592. TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Folder Redirection"),
  593. 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE,
  594. NULL, &hKey, &dwDisp);
  595. if (lResult != ERROR_SUCCESS)
  596. {
  597. return SELFREG_E_CLASS;
  598. }
  599. RegSetValueEx (hKey, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (LPBYTE) EventFile,
  600. (lstrlen(EventFile) + 1) * sizeof (TCHAR));
  601. RegSetValueEx (hKey, TEXT("ParameterMessageFile"), 0, REG_EXPAND_SZ, (LPBYTE) ParamFile,
  602. (lstrlen(ParamFile) + 1) * sizeof (TCHAR));
  603. RegSetValueEx (hKey, TEXT("TypesSupported"), 0, REG_DWORD, (LPBYTE) &dwTypes,
  604. sizeof(DWORD));
  605. RegCloseKey (hKey);
  606. return S_OK;
  607. }
  608. /////////////////////////////////////////////////////////////////////////////
  609. // DllUnregisterServer - Removes entries from the system registry
  610. STDAPI DllUnregisterServer(void)
  611. {
  612. RegDelnode (HKEY_LOCAL_MACHINE,
  613. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GPExtensions\\{25537BA6-77A8-11D2-9B6C-0000F8080861}"));
  614. RegDelnode (HKEY_LOCAL_MACHINE,
  615. TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\Folder Redirection"));
  616. return S_OK;
  617. }