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.

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