gpt.c
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 326k
Category:

Windows Develop

Development Platform:

Visual C++

  1. //*************************************************************
  2. //
  3. //  Group Policy Support
  4. //
  5. //  Microsoft Confidential
  6. //  Copyright (c) Microsoft Corporation 1997-1998
  7. //  All rights reserved
  8. //
  9. //*************************************************************
  10. #include "uenv.h"
  11. #define GPO_LPARAM_FLAG_DELETE         0x00000001
  12. //
  13. // Structures
  14. //
  15. typedef struct _GPEXT {
  16.     LPTSTR         lpDisplayName;            // Display name
  17.     LPTSTR         lpKeyName;                // Extension name
  18.     LPTSTR         lpDllName;                // Dll name
  19.     LPSTR          lpFunctionName;           // Entry point name
  20.     HANDLE         hInstance;                // Handle to dll
  21.     PFNPROCESSGROUPPOLICY  pEntryPoint;      // Entry point for ProcessGPO
  22.     DWORD          dwNoMachPolicy;           // Mach policy setting
  23.     DWORD          dwNoUserPolicy;           // User policy setting
  24.     DWORD          dwNoSlowLink;             // Slow link setting
  25.     DWORD          dwNoBackgroundPolicy;     // Background policy setting
  26.     DWORD          dwNoGPOChanges;           // GPO changes setting
  27.     DWORD          dwUserLocalSetting;       // Per user per machine setting
  28.     DWORD          dwRequireRegistry;        // RequireSuccReg setting
  29.     DWORD          dwEnableAsynch;           // Enable asynchronous processing setting
  30.     DWORD          dwLinkTransition;         // Link speed transition setting
  31.     DWORD          dwMaxChangesInterval;     // Max interval (mins) for which NoGpoChanges is adhered to
  32.     BOOL           bRegistryExt;             // Is this the psuedo reg extension ?
  33.     BOOL           bSkipped;                 // Should processing be skipped for this extension ?
  34.     BOOL           bHistoryProcessing;       // Is processing needed to clean up cached Gpos ?
  35.     DWORD          dwSlowLinkPrev;           // Slow link when policy applied previously ?
  36.     GUID           guid;                     // Guid of extension
  37.     struct _GPEXT *pNext;                    // Singly linked list pointer
  38. } GPEXT, *LPGPEXT;
  39. typedef struct _EXTLIST {
  40.     GUID             guid;                   // Extension guid
  41.     struct _EXTLIST *pNext;                  // Singly linked list pointer
  42. } EXTLIST, *LPEXTLIST;
  43. typedef struct _EXTFILTERLIST {
  44.     PGROUP_POLICY_OBJECT   lpGPO;            // GPO
  45.     LPEXTLIST              lpExtList;        // List of extension guids that apply to lpGPO
  46.     struct _EXTFILTERLIST *pNext;            // Singly linked list pointer
  47. } EXTFILTERLIST, *LPEXTFILTERLIST;
  48. typedef struct _GPOINFO {
  49.     DWORD                    dwFlags;
  50.     INT                      iMachineRole;
  51.     HANDLE                   hToken;
  52.     HANDLE                   hEvent;
  53.     HKEY                     hKeyRoot;
  54.     BOOL                     bXferToExtList;     // Has the ownership been transferred from lpGPOList to lpExtFilterList ?
  55.     LPEXTFILTERLIST          lpExtFilterList;    // List of extensions to be filtered, cardinality is same as GetGPOList's list
  56.     PGROUP_POLICY_OBJECT     lpGPOList;          // Filtered GPO List, can vary from one extension to next
  57.     LPTSTR                   lpwszSidUser;       // Sid of user in string form
  58.     HANDLE                   hTriggerEvent;
  59.     HANDLE                   hNotifyEvent;
  60.     HANDLE                   hCritSection;
  61.     LPGPEXT                  lpExtensions;
  62.     BOOL                     bMemChanged;          // Has security group membership has changed ?
  63.     BOOL                     bUserLocalMemChanged; // Has membership changed on per user local basis ?
  64.     BOOL                     bSidChanged;          // Has the Sid changed since the last policy run?
  65.     PFNSTATUSMESSAGECALLBACK pStatusCallback;
  66. } GPOINFO, *LPGPOINFO;
  67. typedef struct _GPINFOHANDLE
  68. {
  69.     LPGPOINFO pGPOInfo;
  70. } GPINFOHANDLE, *LPGPINFOHANDLE;
  71. typedef struct _DNENTRY {
  72.     LPTSTR                pwszDN;            // Distinguished name
  73.     union {
  74.         PGROUP_POLICY_OBJECT  pDeferredGPO;  // GPO corresponding to this DN
  75.         struct _DNENTRY *     pDeferredOU;   // OU correspdonding to this DN
  76.     };
  77.     PLDAPMessage          pOUMsg;            // Message for evaluating deferred OU
  78.     GPO_LINK              gpoLink;           // Type of GPO
  79.     struct _DNENTRY *     pNext;             // Singly linked list pointer
  80. } DNENTRY;
  81. typedef struct _LDAPQUERY {
  82.     LPTSTR              pwszDomain;          // Domain of subtree search
  83.     LPTSTR              pwszFilter;          // Ldap filter for search
  84.     DWORD               cbAllocLen;          // Allocated size of pwszFilter in bytes
  85.     DWORD               cbLen;               // Size of pwszFilter currently used in bytes
  86.     PLDAP               pLdapHandle;         // Ldap bind handle
  87.     BOOL                bOwnLdapHandle;      // Does this struct own pLdapHandle ?
  88.     PLDAPMessage        pMessage;            // Ldap message handle
  89.     DNENTRY *           pDnEntry;            // Distinguished name entry
  90.     struct _LDAPQUERY * pNext;               // Singly linked list pointer
  91. } LDAPQUERY;
  92. //
  93. // Verison number for the registry file format
  94. //
  95. #define REGISTRY_FILE_VERSION       1
  96. //
  97. // File signature
  98. //
  99. #define REGFILE_SIGNATURE  0x67655250
  100. //
  101. // Default refresh rate (minutes)
  102. //
  103. // Client machines will refresh every 90 minutes
  104. // Domain controllers will refresh every 5 minutes
  105. //
  106. #define GP_DEFAULT_REFRESH_RATE      90
  107. #define GP_DEFAULT_REFRESH_RATE_DC    5
  108. //
  109. // Default refresh rate max offset
  110. //
  111. // To prevent many clients from querying policy at the exact same
  112. // time, a random amount is added to the refresh rate.  In the
  113. // default case, a number between 0 and 30 will be added to
  114. // 180 to determine when the next background refresh will occur
  115. //
  116. #define GP_DEFAULT_REFRESH_RATE_OFFSET    30
  117. #define GP_DEFAULT_REFRESH_RATE_OFFSET_DC  0
  118. //
  119. // Max keyname size
  120. //
  121. #define MAX_KEYNAME_SIZE         2048
  122. #define MAX_VALUENAME_SIZE        512
  123. //
  124. // Max time to wait for the network to start (in ms)
  125. //
  126. #define MAX_WAIT_TIME            120000
  127. //
  128. // Extension registry path
  129. //
  130. #define GP_EXTENSIONS   TEXT("Software\Microsoft\Windows NT\CurrentVersion\Winlogon\GPExtensions")
  131. //
  132. // Path for extension preference policies
  133. //
  134. #define GP_EXTENSIONS_POLICIES   TEXT("Software\Policies\Microsoft\Windows\Group Policy\%s")
  135. //
  136. // Group Policy Object option flags
  137. //
  138. // Note, this was taken from sdkincgpedit.h
  139. //
  140. #define GPO_OPTION_DISABLE_USER     0x00000001  // The user portion of this GPO is disabled
  141. #define GPO_OPTION_DISABLE_MACHINE  0x00000002  // The machine portion of this GPO is disabled
  142. //
  143. // Generic access mappings
  144. //
  145. const
  146. ACCESS_MASK
  147. GENERIC_READ_MAPPING =    ((STANDARD_RIGHTS_READ)     | 
  148.                            (ACTRL_DS_LIST)            | 
  149.                            (ACTRL_DS_READ_PROP)       | 
  150.                            (ACTRL_DS_LIST_OBJECT));
  151. const
  152. ACCESS_MASK
  153. GENERIC_EXECUTE_MAPPING = ((STANDARD_RIGHTS_EXECUTE)  | 
  154.                            (ACTRL_DS_LIST));
  155. const
  156. ACCESS_MASK
  157. GENERIC_WRITE_MAPPING =   ((STANDARD_RIGHTS_WRITE)    | 
  158.                            (ACTRL_DS_SELF)            | 
  159.                            (ACTRL_DS_WRITE_PROP));
  160. const
  161. ACCESS_MASK
  162. GENERIC_ALL_MAPPING =     ((STANDARD_RIGHTS_REQUIRED) | 
  163.                            (ACTRL_DS_CREATE_CHILD)    | 
  164.                            (ACTRL_DS_DELETE_CHILD)    | 
  165.                            (ACTRL_DS_DELETE_TREE)     | 
  166.                            (ACTRL_DS_READ_PROP)       | 
  167.                            (ACTRL_DS_WRITE_PROP)      | 
  168.                            (ACTRL_DS_LIST)            | 
  169.                            (ACTRL_DS_LIST_OBJECT)     | 
  170.                            (ACTRL_DS_CONTROL_ACCESS)  | 
  171.                            (ACTRL_DS_SELF));
  172. //
  173. // DS Object class types
  174. //
  175. TCHAR szDSClassAny[]    = TEXT("(objectClass=*)");
  176. TCHAR szDSClassGPO[]    = TEXT("groupPolicyContainer");
  177. TCHAR szDSClassSite[]   = TEXT("site");
  178. TCHAR szDSClassDomain[] = TEXT("domainDNS");
  179. TCHAR szDSClassOU[]     = TEXT("organizationalUnit");
  180. TCHAR szObjectClass[]   = TEXT("objectClass");
  181. //
  182. // Extension name properties
  183. //
  184. #define GPO_MACHEXTENSION_NAMES   L"gPCMachineExtensionNames"
  185. #define GPO_USEREXTENSION_NAMES   L"gPCUserExtensionNames"
  186. #define GPO_FUNCTIONALITY_VERSION L"gPCFunctionalityVersion"
  187. TCHAR wszKerberos[] = TEXT("Kerberos");
  188. #define POLICY_GUID_PATH            TEXT("Software\Microsoft\Windows NT\CurrentVersion\PolicyGuid")
  189. //
  190. // Global flags for Gpo shutdown processing. These are accessed outside
  191. // the lock because its value is either 0 or 1. Even if there is a race,
  192. // all it means is that shutdown will start one iteration later.
  193. //
  194. BOOL g_bStopMachGPOProcessing = FALSE;
  195. BOOL g_bStopUserGPOProcessing = FALSE;
  196. //
  197. // Critical section for handling concurrent, asynchronous completion
  198. //
  199. CRITICAL_SECTION g_GPOCS;
  200. //
  201. // Global pointers for maintaining asynchronous completion context
  202. //
  203. LPGPINFOHANDLE g_pMachGPInfo = 0;
  204. LPGPINFOHANDLE g_pUserGPInfo = 0;
  205. //
  206. // Status UI critical section, callback, and proto-types
  207. //
  208. CRITICAL_SECTION g_StatusCallbackCS;
  209. PFNSTATUSMESSAGECALLBACK g_pStatusMessageCallback = NULL;
  210. DWORD UserPolicyCallback (BOOL bVerbose, LPWSTR lpMessage);
  211. DWORD MachinePolicyCallback (BOOL bVerbose, LPWSTR lpMessage);
  212. //
  213. // Function proto-types
  214. //
  215. DWORD WINAPI GPOThread (LPGPOINFO lpGPOInfo);
  216. BOOL ProcessGPOs (LPGPOINFO lpGPOInfo);
  217. DWORD WINAPI PolicyChangedThread (BOOL bMachine);
  218. BOOL ResetPolicies (LPGPOINFO lpGPOInfo, LPTSTR lpArchive);
  219. BOOL SetupGPOFilter (LPGPOINFO lpGPOInfo );
  220. void FilterGPOs( LPGPEXT lpExt, LPGPOINFO lpGPOInfo );
  221. void FreeLists( LPGPOINFO lpGPOInfo );
  222. void FreeExtList(LPEXTLIST pExtList );
  223. BOOL CheckGPOs (LPGPEXT lpExt, LPGPOINFO lpGPOInfo, DWORD dwTime, BOOL *pbProcessGPOs,
  224.                 BOOL *pbNoChanges, PGROUP_POLICY_OBJECT *ppDeletedGPOList);
  225. BOOL CheckForChangedSid( LPGPOINFO lpGPOInfo );
  226. BOOL CheckForSkippedExtensions( LPGPOINFO lpGPOInfo );
  227. BOOL ReadGPExtensions( LPGPOINFO lpGPOInfo );
  228. BOOL LoadGPExtension (LPGPEXT lpExt);
  229. BOOL UnloadGPExtensions (LPGPOINFO lpGPOInfo);
  230. BOOL WriteStatus( TCHAR *lpExtName, LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUser, DWORD dwStatus, DWORD dwTime, DWORD dwSlowLink );
  231. BOOL ReadStatus( TCHAR *lpExtName, LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUser, DWORD *pdwStatus, DWORD *pdwTime, DWORD *pdwSlowlink );
  232. DWORD ProcessGPOList (LPGPEXT lpExt, LPGPOINFO lpGPOInfo, PGROUP_POLICY_OBJECT pDeletedGPOList,
  233.                      PGROUP_POLICY_OBJECT pChangedGPOList, BOOL bNoChanges,
  234.                      ASYNCCOMPLETIONHANDLE pAsyncHandle );
  235. BOOL ProcessGPORegistryPolicy (LPGPOINFO lpGPOInfo, PGROUP_POLICY_OBJECT pChangedGPOList);
  236. BOOL SaveGPOList (TCHAR *pszExtName, LPGPOINFO lpGPOInfo,
  237.                   HKEY hKeyRootMach, LPTSTR lpwszSidUser, BOOL bShadow, PGROUP_POLICY_OBJECT lpGPOList);
  238. BOOL AddGPO (PGROUP_POLICY_OBJECT * lpGPOList, DWORD dwOptions, DWORD dwVersion,
  239.              LPTSTR lpDSPath, LPTSTR lpFileSysPath, LPTSTR lpDisplayName,
  240.              LPTSTR lpGPOName, LPTSTR lpExtensions, GPO_LINK GPOLink, LPTSTR lpLink, LPARAM lParam, BOOL bFront,
  241.              BOOL bBlock, BOOL bVerbose);
  242. BOOL RefreshDisplay (LPGPOINFO lpGPOInfo);
  243. DWORD IsSlowLink (HKEY hKeyRoot, LPTSTR lpDCAddress, BOOL *bSlow);
  244. BOOL GetGPOInfo (DWORD dwFlags, LPTSTR lpHostName, LPTSTR lpDNName,
  245.                  LPCTSTR lpComputerName, PGROUP_POLICY_OBJECT *lpGPOList,
  246.                  PNETAPI32_API pNetAPI32, BOOL bMachineTokenOk);
  247. void WINAPI ShutdownGPOProcessing( BOOL bMachine );
  248. void DebugPrintGPOList( LPGPOINFO lpGPOInfo );
  249. typedef BOOL (*PFNREGFILECALLBACK)(LPGPOINFO lpGPOInfo, LPTSTR lpKeyName,
  250.                                    LPTSTR lpValueName, DWORD dwType,
  251.                                    DWORD dwDataLength, LPBYTE lpData);
  252. BOOL ParseRegistryFile (LPGPOINFO lpGPOInfo, LPTSTR lpRegistry,
  253.                         PFNREGFILECALLBACK pfnRegFileCallback,
  254.                         HANDLE hArchive);
  255. BOOL ExtensionHasPerUserLocalSetting( LPTSTR pszExtension, HKEY hKeyRoot );
  256. void CheckGroupMembership( LPGPOINFO lpGPOInfo, HANDLE hToken, BOOL *pbMemChanged, BOOL *pbUserLocalMemChanged );
  257. BOOL ReadMembershipList( LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUser, PTOKEN_GROUPS pGroups );
  258. void SaveMembershipList( LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUser, PTOKEN_GROUPS pGroups );
  259. BOOL GroupInList( LPTSTR lpSid, PTOKEN_GROUPS pGroups );
  260. DWORD GetCurTime();
  261. DWORD GetDomainControllerInfo(  PNETAPI32_API pNetAPI32, LPTSTR szDomainName,
  262.                                 ULONG ulFlags, HKEY hKeyRoot, PDOMAIN_CONTROLLER_INFO* ppInfo,
  263.                                 BOOL* pfSlow );
  264. PLDAP GetMachineDomainDS( PNETAPI32_API pNetApi32, PLDAP_API pLdapApi );
  265. HANDLE GetMachineToken();
  266. NTSTATUS CallDFS(LPWSTR lpDomainName, LPWSTR lpDCName);
  267. //*************************************************************
  268. //
  269. //  ApplyGroupPolicy()
  270. //
  271. //  Purpose:    Processes group policy
  272. //
  273. //  Parameters: dwFlags         -  Processing flags
  274. //              hToken          -  Token (user or machine)
  275. //              hEvent          -  Termination event for background thread
  276. //              hKeyRoot        -  Root registry key (HKCU or HKLM)
  277. //              pStatusCallback -  Callback function for display status messages
  278. //
  279. //  Return:     Thread handle if successful
  280. //              NULL if an error occurs
  281. //
  282. //*************************************************************
  283. HANDLE WINAPI ApplyGroupPolicy (DWORD dwFlags, HANDLE hToken, HANDLE hEvent,
  284.                                 HKEY hKeyRoot, PFNSTATUSMESSAGECALLBACK pStatusCallback)
  285. {
  286.     HANDLE hThread = NULL;
  287.     DWORD dwThreadID;
  288.     LPGPOINFO lpGPOInfo = NULL;
  289.     SECURITY_DESCRIPTOR sd;
  290.     SECURITY_ATTRIBUTES sa;
  291.     //
  292.     // Verbose output
  293.     //
  294.     DebugMsg((DM_VERBOSE, TEXT("ApplyGroupPolicy: Entering. Flags = %x"), dwFlags));
  295.     //
  296.     // Save the status UI callback function
  297.     //
  298.     EnterCriticalSection (&g_StatusCallbackCS);
  299.     g_pStatusMessageCallback = pStatusCallback;
  300.     LeaveCriticalSection (&g_StatusCallbackCS);
  301.     //
  302.     // Allocate a GPOInfo structure to work with.
  303.     //
  304.     lpGPOInfo = (LPGPOINFO) LocalAlloc (LPTR, sizeof(GPOINFO));
  305.     if (!lpGPOInfo) {
  306.         DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to alloc lpGPOInfo (%d)."),
  307.                  GetLastError()));
  308.         LogEvent (TRUE, IDS_FAILED_ALLOCATION, GetLastError());
  309.         goto Exit;
  310.     }
  311.     lpGPOInfo->dwFlags = dwFlags;
  312.     lpGPOInfo->hToken = hToken;
  313.     lpGPOInfo->hEvent = hEvent;
  314.     lpGPOInfo->hKeyRoot = hKeyRoot;
  315.     if (dwFlags & GP_MACHINE) {
  316.         lpGPOInfo->pStatusCallback = MachinePolicyCallback;
  317.     } else {
  318.         lpGPOInfo->pStatusCallback = UserPolicyCallback;
  319.     }
  320.     //
  321.     // Create an event so other processes can trigger policy
  322.     // to be applied immediately
  323.     //
  324.     InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
  325.     SetSecurityDescriptorDacl (
  326.                     &sd,
  327.                     TRUE,                           // Dacl present
  328.                     NULL,                           // NULL Dacl
  329.                     FALSE                           // Not defaulted
  330.                     );
  331.     sa.lpSecurityDescriptor = &sd;
  332.     sa.bInheritHandle = FALSE;
  333.     sa.nLength = sizeof(sa);
  334.     lpGPOInfo->hTriggerEvent = CreateEvent (&sa, FALSE, FALSE,
  335.                                             (dwFlags & GP_MACHINE) ?
  336.                                             MACHINE_POLICY_REFRESH_EVENT : USER_POLICY_REFRESH_EVENT);
  337.     //
  338.     // Create the notification event
  339.     //
  340.     lpGPOInfo->hNotifyEvent = CreateEvent (&sa, TRUE, FALSE,
  341.                                            (dwFlags & GP_MACHINE) ?
  342.                                            MACHINE_POLICY_APPLIED_EVENT : USER_POLICY_APPLIED_EVENT);
  343.     //
  344.     // Initilialize shutdown gpo processing support
  345.     //
  346.     if ( dwFlags & GP_MACHINE )
  347.         g_bStopMachGPOProcessing = FALSE;
  348.     else
  349.         g_bStopUserGPOProcessing = FALSE;
  350.     //
  351.     // Process the GPOs
  352.     //
  353.     ProcessGPOs(lpGPOInfo);
  354.     //
  355.     // If requested, create a background thread to keep updating
  356.     // the profile from the gpos
  357.     //
  358.     if (lpGPOInfo->dwFlags & GP_BACKGROUND_REFRESH) {
  359.         //
  360.         // Create a thread which sleeps and processes GPOs
  361.         //
  362.         hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) GPOThread,
  363.                                 (LPVOID) lpGPOInfo, CREATE_SUSPENDED, &dwThreadID);
  364.         if (!hThread) {
  365.             DebugMsg((DM_WARNING, TEXT("ApplyGroupPolicy: Failed to create background thread (%d)."),
  366.                      GetLastError()));
  367.             goto Exit;
  368.         }
  369.         SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);
  370.         lpGPOInfo->pStatusCallback = NULL;
  371.         ResumeThread (hThread);
  372.         //
  373.         // Reset the status UI callback function
  374.         //
  375.         EnterCriticalSection (&g_StatusCallbackCS);
  376.         g_pStatusMessageCallback = NULL;
  377.         LeaveCriticalSection (&g_StatusCallbackCS);
  378.         DebugMsg((DM_VERBOSE, TEXT("ApplyGroupPolicy: Leaving successfully.")));
  379.         return hThread;
  380.     }
  381.     DebugMsg((DM_VERBOSE, TEXT("ApplyGroupPolicy: Background refresh not requested.  Leaving successfully.")));
  382.     hThread = (HANDLE) 1;
  383. Exit:
  384.     EnterCriticalSection( &g_GPOCS );
  385.     if ( dwFlags & GP_MACHINE ) {
  386.         if ( g_pMachGPInfo )
  387.             LocalFree( g_pMachGPInfo );
  388.         g_pMachGPInfo = 0;
  389.     } else {
  390.         if ( g_pUserGPInfo )
  391.             LocalFree( g_pUserGPInfo );
  392.         g_pUserGPInfo = 0;
  393.     }
  394.     LeaveCriticalSection( &g_GPOCS );
  395.     if (lpGPOInfo) {
  396.         if (lpGPOInfo->hTriggerEvent) {
  397.             CloseHandle (lpGPOInfo->hTriggerEvent);
  398.         }
  399.         if (lpGPOInfo->hNotifyEvent) {
  400.             CloseHandle (lpGPOInfo->hNotifyEvent);
  401.         }
  402.         if (lpGPOInfo->lpwszSidUser)
  403.             DeleteSidString( lpGPOInfo->lpwszSidUser );
  404.         LocalFree (lpGPOInfo);
  405.     }
  406.     //
  407.     // Reset the status UI callback function
  408.     //
  409.     EnterCriticalSection (&g_StatusCallbackCS);
  410.     g_pStatusMessageCallback = NULL;
  411.     LeaveCriticalSection (&g_StatusCallbackCS);
  412.     return hThread;
  413. }
  414. //*************************************************************
  415. //
  416. //  GPOThread()
  417. //
  418. //  Purpose:    Background thread for GPO processing.
  419. //
  420. //  Parameters: lpGPOInfo   - GPO info
  421. //
  422. //  Return:     0
  423. //
  424. //*************************************************************
  425. DWORD WINAPI GPOThread (LPGPOINFO lpGPOInfo)
  426. {
  427.     HINSTANCE hInst;
  428.     HKEY hKey;
  429.     HANDLE hHandles[3] = {NULL, NULL, NULL};
  430.     DWORD dwType, dwSize, dwResult;
  431.     DWORD dwTimeout, dwOffset;
  432.     BOOL bSetBkGndFlag;
  433.     TCHAR szEventName[60];
  434.     LARGE_INTEGER DueTime;
  435.     hInst = LoadLibrary (TEXT("userenv.dll"));
  436.     hHandles[0] = lpGPOInfo->hEvent;
  437.     hHandles[1] = lpGPOInfo->hTriggerEvent;
  438.     while (TRUE) {
  439.         //
  440.         // Initialize
  441.         //
  442.         if (lpGPOInfo->dwFlags & GP_MACHINE) {
  443.             if (lpGPOInfo->iMachineRole == 3) {
  444.                 dwTimeout = GP_DEFAULT_REFRESH_RATE_DC;
  445.                 dwOffset = GP_DEFAULT_REFRESH_RATE_OFFSET_DC;
  446.             } else {
  447.                 dwTimeout = GP_DEFAULT_REFRESH_RATE;
  448.                 dwOffset = GP_DEFAULT_REFRESH_RATE_OFFSET;
  449.             }
  450.         } else {
  451.             dwTimeout = GP_DEFAULT_REFRESH_RATE;
  452.             dwOffset = GP_DEFAULT_REFRESH_RATE_OFFSET;
  453.         }
  454.         //
  455.         // Query for the refresh timer value and max offset
  456.         //
  457.         if (RegOpenKeyEx (lpGPOInfo->hKeyRoot,
  458.                           SYSTEM_POLICIES_KEY,
  459.                           0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  460.             if ((lpGPOInfo->iMachineRole == 3) && (lpGPOInfo->dwFlags & GP_MACHINE)) {
  461.                 dwSize = sizeof(dwTimeout);
  462.                 RegQueryValueEx (hKey,
  463.                                  TEXT("GroupPolicyRefreshTimeDC"),
  464.                                  NULL,
  465.                                  &dwType,
  466.                                  (LPBYTE) &dwTimeout,
  467.                                  &dwSize);
  468.                 dwSize = sizeof(dwOffset);
  469.                 RegQueryValueEx (hKey,
  470.                                  TEXT("GroupPolicyRefreshTimeOffsetDC"),
  471.                                  NULL,
  472.                                  &dwType,
  473.                                  (LPBYTE) &dwOffset,
  474.                                  &dwSize);
  475.             } else {
  476.                 dwSize = sizeof(dwTimeout);
  477.                 RegQueryValueEx (hKey,
  478.                                  TEXT("GroupPolicyRefreshTime"),
  479.                                  NULL,
  480.                                  &dwType,
  481.                                  (LPBYTE) &dwTimeout,
  482.                                  &dwSize);
  483.                 dwSize = sizeof(dwOffset);
  484.                 RegQueryValueEx (hKey,
  485.                                  TEXT("GroupPolicyRefreshTimeOffset"),
  486.                                  NULL,
  487.                                  &dwType,
  488.                                  (LPBYTE) &dwOffset,
  489.                                  &dwSize);
  490.             }
  491.             RegCloseKey (hKey);
  492.         }
  493.         //
  494.         // Limit the timeout to once every 64800 minutes (45 days)
  495.         //
  496.         if (dwTimeout >= 64800) {
  497.             dwTimeout = 64800;
  498.         }
  499.         //
  500.         // Convert seconds to milliseconds
  501.         //
  502.         dwTimeout =  dwTimeout * 60 * 1000;
  503.         //
  504.         // Limit the offset to 1440 minutes (24 hours)
  505.         //
  506.         if (dwOffset >= 1440) {
  507.             dwOffset = 1440;
  508.         }
  509.         //
  510.         // Special case 0 milliseconds to be 7 seconds
  511.         //
  512.         if (dwTimeout == 0) {
  513.             dwTimeout = 7000;
  514.         } else {
  515.             //
  516.             // If there is an offset, pick a random number
  517.             // from 0 to dwOffset and then add it to the timeout
  518.             //
  519.             if (dwOffset) {
  520.                 dwOffset = GetTickCount() % dwOffset;
  521.                 dwOffset = dwOffset * 60 * 1000;
  522.                 dwTimeout += dwOffset;
  523.             }
  524.         }
  525.         //
  526.         // Setup the timer
  527.         //
  528.         if (dwTimeout >= 60000) {
  529.             DebugMsg((DM_VERBOSE, TEXT("GPOThread:  Next refresh will happen in %d minutes"),
  530.                      ((dwTimeout / 1000) / 60)));
  531.         } else {
  532.             DebugMsg((DM_VERBOSE, TEXT("GPOThread:  Next refresh will happen in %d seconds"),
  533.                      (dwTimeout / 1000)));
  534.         }
  535.         wsprintf (szEventName, TEXT("userenv: refresh timer for %d:%d"),
  536.                   GetCurrentProcessId(), GetCurrentThreadId());
  537.         hHandles[2] = CreateWaitableTimer (NULL, TRUE, szEventName);
  538.         if (hHandles[2] == NULL) {
  539.             DebugMsg((DM_WARNING, TEXT("GPOThread: CreateWaitableTimer failed with error %d"),
  540.                      GetLastError()));
  541.             LogEvent (TRUE, IDS_FAILED_TIMER, TEXT("CreateWaitableTimer"), GetLastError());
  542.             break;
  543.         }
  544.         DueTime.QuadPart = UInt32x32To64(10000, dwTimeout);
  545.         DueTime.QuadPart *= -1;
  546.         if (!SetWaitableTimer (hHandles[2], &DueTime, 0, NULL, 0, FALSE)) {
  547.             DebugMsg((DM_WARNING, TEXT("GPOThread: Failed to set timer with error %d"),
  548.                      GetLastError()));
  549.             LogEvent (TRUE, IDS_FAILED_TIMER, TEXT("SetWaitableTimer"), GetLastError());
  550.             break;
  551.         }
  552.         dwResult = WaitForMultipleObjects (3, hHandles, FALSE, INFINITE);
  553.         
  554.         if ( (dwResult - WAIT_OBJECT_0) == 0 )
  555.         {
  556.             //
  557.             // for machine policy thread, this is a shutdown.
  558.             // for user policy thread, this is a logoff.
  559.             //
  560.             break;
  561.         }
  562.         else if ( dwResult == WAIT_FAILED )
  563.         {
  564.             LogEvent (TRUE, IDS_FAILED_TIMER, TEXT("WaitForMultipleObjects"), GetLastError());
  565.             break;
  566.         }
  567.         //
  568.         // Check if we should set the background flag.  We offer this
  569.         // option for the test team's automation tests.  They need to
  570.         // simulate logon / boot policy without actually logging on or
  571.         // booting the machine.
  572.         //
  573.         bSetBkGndFlag = TRUE;
  574.         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  575.                           WINLOGON_KEY,
  576.                           0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  577.             dwSize = sizeof(bSetBkGndFlag);
  578.             RegQueryValueEx (hKey,
  579.                              TEXT("SetGroupPolicyBackgroundFlag"),
  580.                              NULL,
  581.                              &dwType,
  582.                              (LPBYTE) &bSetBkGndFlag,
  583.                              &dwSize);
  584.             RegCloseKey (hKey);
  585.         }
  586.         lpGPOInfo->dwFlags &= ~GP_REGPOLICY_CPANEL;
  587.         lpGPOInfo->dwFlags &= ~GP_SLOW_LINK;
  588.         lpGPOInfo->dwFlags &= ~GP_VERBOSE;
  589.         lpGPOInfo->dwFlags &= ~GP_BACKGROUND_THREAD;
  590.         //
  591.         // Set the background thread flag so components known
  592.         // when they are being called from the background thread
  593.         // vs the main thread.
  594.         //
  595.         if (bSetBkGndFlag) {
  596.             lpGPOInfo->dwFlags |= GP_BACKGROUND_THREAD;
  597.         }
  598.         ProcessGPOs(lpGPOInfo);
  599.         CloseHandle (hHandles[2]);
  600.         hHandles[2] = NULL;
  601.     }
  602.     //
  603.     // Cleanup
  604.     //
  605.     if (hHandles[2]) {
  606.         CloseHandle (hHandles[2]);
  607.     }
  608.     if (lpGPOInfo->hTriggerEvent) {
  609.         CloseHandle (lpGPOInfo->hTriggerEvent);
  610.     }
  611.     if (lpGPOInfo->hNotifyEvent) {
  612.         CloseHandle (lpGPOInfo->hNotifyEvent);
  613.     }
  614.     EnterCriticalSection( &g_GPOCS );
  615.     if ( lpGPOInfo->dwFlags & GP_MACHINE ) {
  616.        if ( g_pMachGPInfo )
  617.            LocalFree( g_pMachGPInfo );
  618.        g_pMachGPInfo = 0;
  619.     } else {
  620.         if ( g_pUserGPInfo )
  621.             LocalFree( g_pUserGPInfo );
  622.         g_pUserGPInfo = 0;
  623.      }
  624.     LeaveCriticalSection( &g_GPOCS );
  625.     if (lpGPOInfo->lpwszSidUser)
  626.         DeleteSidString( lpGPOInfo->lpwszSidUser );
  627.     LocalFree (lpGPOInfo);
  628.     FreeLibraryAndExitThread (hInst, 0);
  629.     return 0;
  630. }
  631. //*************************************************************
  632. //
  633. //  GPOExceptionFilter()
  634. //
  635. //  Purpose:    Exception filter when procssing GPO extensions
  636. //
  637. //  Parameters: pExceptionPtrs - Pointer to exception pointer
  638. //
  639. //  Returns:    EXCEPTION_EXECUTE_HANDLER
  640. //
  641. //*************************************************************
  642. LONG GPOExceptionFilter( PEXCEPTION_POINTERS pExceptionPtrs )
  643. {
  644.     PEXCEPTION_RECORD pExr = pExceptionPtrs->ExceptionRecord;
  645.     PCONTEXT pCxr = pExceptionPtrs->ContextRecord;
  646.     DebugMsg(( DM_WARNING, L"GPOExceptionFilter: Caught exception 0x%x, exr = 0x%x, cxr = 0x%xn",
  647.               pExr->ExceptionCode, pExr, pCxr ));
  648.     DmAssert( ! L"Caught unhandled exception when processing group policy extension" );
  649.     return EXCEPTION_EXECUTE_HANDLER;
  650. }
  651. //*************************************************************
  652. //
  653. //  ProcessGPOs()
  654. //
  655. //  Purpose:    Processes GPOs
  656. //
  657. //  Parameters: lpGPOInfo   -   GPO information
  658. //
  659. //  Return:     TRUE if successful
  660. //              FALSE if an error occurs
  661. //
  662. //*************************************************************
  663. BOOL ProcessGPOs (LPGPOINFO lpGPOInfo)
  664. {
  665.     BOOL bRetVal = FALSE;
  666.     DWORD dwThreadID;
  667.     HANDLE hThread;
  668.     DWORD dwType, dwSize, dwResult;
  669.     HKEY hKey;
  670.     BOOL bResult;
  671.     PDOMAIN_CONTROLLER_INFO pDCI = NULL;
  672.     LPTSTR lpDomain = NULL;
  673.     LPTSTR lpName = NULL;
  674.     LPTSTR lpDomainDN = NULL;
  675.     LPTSTR lpComputerName;
  676.     PGROUP_POLICY_OBJECT lpGPO = NULL;
  677.     PGROUP_POLICY_OBJECT lpGPOTemp;
  678.     BOOL bAllSkipped;
  679.     LPGPEXT lpExt;
  680.     LPGPINFOHANDLE pGPHandle = NULL;
  681.     ASYNCCOMPLETIONHANDLE pAsyncHandle = 0;
  682.     HANDLE hOldToken;
  683.     UINT uExtensionCount = 0;
  684.     PNETAPI32_API pNetAPI32;
  685.     DWORD dwUserPolicyMode = 0;
  686.     DWORD dwCurrentTime = 0;
  687.     INT iRole;
  688.     BOOL bSlow;
  689.     //
  690.     // Allow debugging level to be changed dynamically between
  691.     // policy refreshes.
  692.     //
  693.     InitDebugSupport( FALSE );
  694.     //
  695.     // Debug spew
  696.     //
  697.     if (lpGPOInfo->dwFlags & GP_MACHINE) {
  698.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  699.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  700.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:  Starting computer Group Policy processing...")));
  701.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  702.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  703.     } else {
  704.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  705.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  706.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs: Starting user Group Policy processing...")));
  707.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  708.         DebugMsg(( DM_VERBOSE, TEXT("ProcessGPOs:")));
  709.     }
  710.     //
  711.     // Check if we should be verbose to the event log
  712.     //
  713.     if (CheckForVerbosePolicy()) {
  714.         lpGPOInfo->dwFlags |= GP_VERBOSE;
  715.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs:  Verbose output to eventlog requested.")));
  716.     }
  717.     if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  718.         if (lpGPOInfo->dwFlags & GP_MACHINE) {
  719.             LogEvent (FALSE, IDS_START_MACHINE_POLICY);
  720.         } else {
  721.             LogEvent (FALSE, IDS_START_USER_POLICY);
  722.         }
  723.     }
  724.     //
  725.     // Claim the critical section
  726.     //
  727.     lpGPOInfo->hCritSection = EnterCriticalPolicySection((lpGPOInfo->dwFlags & GP_MACHINE));
  728.     if (!lpGPOInfo->hCritSection) {
  729.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to claim the policy critical section with %d."),
  730.                  GetLastError()));
  731.         LogEvent (TRUE, IDS_FAILED_CRITICAL_SECTION, GetLastError());
  732.         goto Exit;
  733.     }
  734.     //
  735.     // Set the security on the Group Policy registry key
  736.     //
  737.     if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
  738.                           lpGPOInfo->hKeyRoot,
  739.                           TEXT("Software\Microsoft\Windows\CurrentVersion\Group Policy"))) {
  740.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to secure reg key.")));
  741.     }
  742.     //
  743.     // Load netapi32
  744.     //
  745.     pNetAPI32 = LoadNetAPI32();
  746.     if (!pNetAPI32) {
  747.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs:  Failed to load netapi32 with %d."),
  748.                  GetLastError()));
  749.         LogEvent (TRUE, IDS_FAILED_NETAPI32, GetLastError());
  750.         goto Exit;
  751.     }
  752.     //
  753.     // Get the role of this computer
  754.     //
  755.     if (!GetMachineRole (&iRole)) {
  756.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs:  Failed to get the role of the computer.")));
  757.         LogEvent (TRUE, IDS_FAILED_ROLE);
  758.         goto Exit;
  759.     }
  760.     lpGPOInfo->iMachineRole = iRole;
  761.     DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs:  Machine role is %d."), iRole));
  762.     if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  763.         switch (iRole) {
  764.             case 0:
  765.                 LogEvent (FALSE, IDS_ROLE_STANDALONE);
  766.                 break;
  767.             case 1:
  768.                 LogEvent (FALSE, IDS_ROLE_DOWNLEVEL_DOMAIN);
  769.                 break;
  770.             default:
  771.                 LogEvent (FALSE, IDS_ROLE_DS_DOMAIN);
  772.                 break;
  773.         }
  774.     }
  775.     //
  776.     // If we are going to apply policy from the DS, query for the user's
  777.     // DN name, domain name, etc
  778.     //
  779.     if (lpGPOInfo->dwFlags & GP_APPLY_DS_POLICY) {
  780.         //
  781.         // Query for the user's domain name
  782.         //
  783.         if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
  784.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to impersonate user")));
  785.             goto Exit;
  786.         }
  787.         lpDomain = MyGetDomainName ();
  788.         RevertToUser(&hOldToken);
  789.         if (!lpDomain) {
  790.             dwResult = GetLastError();
  791.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: MyGetDomainName failed with %d."),
  792.                      dwResult));
  793.             goto Exit;
  794.         }
  795.         //
  796.         // Query for the DS server name
  797.         //
  798.         dwResult = GetDomainControllerInfo( pNetAPI32,
  799.                                             lpDomain,
  800.                                             DS_DIRECTORY_SERVICE_REQUIRED | DS_IS_FLAT_NAME
  801.                                             | DS_RETURN_DNS_NAME |
  802.                                             ((lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD) ? DS_BACKGROUND_ONLY : 0),
  803.                                             lpGPOInfo->hKeyRoot,
  804.                                             &pDCI,
  805.                                             &bSlow );
  806.         if (dwResult != ERROR_SUCCESS) {
  807.             if ((dwResult == ERROR_BAD_NETPATH) ||
  808.                 (dwResult == ERROR_NETWORK_UNREACHABLE) ||
  809.                 (dwResult == ERROR_NO_SUCH_DOMAIN)) {
  810.                 //
  811.                 // couldn't find DC. Nothing more we can do, abort
  812.                 //
  813.                 DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: The DC for domain %s is not available"),
  814.                          lpDomain));
  815.             } else {
  816.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: DSGetDCName failed with %d."),
  817.                          dwResult));
  818.                 LogEvent (TRUE, IDS_FAILED_DSNAME, dwResult);
  819.             }
  820.             goto Exit;
  821.         } else {
  822.             //
  823.             // success, slow link?
  824.             //
  825.             if (bSlow) {
  826.                 lpGPOInfo->dwFlags |= GP_SLOW_LINK;
  827.                 if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  828.                     LogEvent (FALSE, IDS_SLOWLINK);
  829.                 }
  830.                 DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: A slow link was detected.")));
  831.             }
  832.         }
  833.         //
  834.         // Get the user's DN name
  835.         //
  836.         if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
  837.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to impersonate user")));
  838.             goto Exit;
  839.         }
  840.         lpName = MyGetUserName (NameFullyQualifiedDN);
  841.         RevertToUser(&hOldToken);
  842.         if (!lpName) {
  843.             dwResult = GetLastError();
  844.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: MyGetUserName failed with %d."),
  845.                      dwResult));
  846.             LogEvent (TRUE, IDS_FAILED_USERNAME, dwResult);
  847.             goto Exit;
  848.         }
  849.         lpDomainDN = pDCI->DomainName;
  850.         if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  851.             LogEvent (FALSE, IDS_USERNAME, lpName);
  852.             LogEvent (FALSE, IDS_DOMAINNAME, lpDomain);
  853.             LogEvent (FALSE, IDS_DCNAME, pDCI->DomainControllerName);
  854.         }
  855.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs:  User name is:  %s, Domain name is:  %s"),
  856.              lpName, lpDomain));
  857.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Domain controller is:  %s  Domain DN is %s"),
  858.                  pDCI->DomainControllerName, lpDomainDN));
  859.         if (!(lpGPOInfo->dwFlags & GP_MACHINE)) {
  860.             CallDFS(pDCI->DomainName, pDCI->DomainControllerName);
  861.         }
  862.         //
  863.         // Save the DC name in the registry for future reference
  864.         //
  865.         if (RegOpenKeyEx (lpGPOInfo->hKeyRoot,
  866.                           TEXT("Software\Microsoft\Windows\CurrentVersion\Group Policy\History"),
  867.                           0, KEY_WRITE, &hKey) == ERROR_SUCCESS) {
  868.             dwSize = (lstrlen(pDCI->DomainControllerName) + 1) * sizeof(TCHAR);
  869.             RegSetValueEx (hKey, TEXT("DCName"), 0, REG_SZ,
  870.                            (LPBYTE) pDCI->DomainControllerName, dwSize);
  871.             RegCloseKey (hKey);
  872.         }
  873.     }
  874.     //
  875.     // Read the group policy extensions from the registry
  876.     //
  877.     if ( !ReadGPExtensions( lpGPOInfo ) ) {
  878.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: ReadGPExtensions failed.")));
  879.         LogEvent (TRUE, IDS_READ_EXT_FAILED );
  880.         goto Exit;
  881.     }
  882.     //
  883.     // Get the user policy mode if appropriate
  884.     //
  885.     if (!(lpGPOInfo->dwFlags & GP_MACHINE)) {
  886.         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  887.                           SYSTEM_POLICIES_KEY,
  888.                           0, KEY_READ, &hKey) == ERROR_SUCCESS) {
  889.             dwSize = sizeof(dwUserPolicyMode);
  890.             RegQueryValueEx (hKey,
  891.                              TEXT("UserPolicyMode"),
  892.                              NULL,
  893.                              &dwType,
  894.                              (LPBYTE) &dwUserPolicyMode,
  895.                              &dwSize);
  896.             RegCloseKey (hKey);
  897.         }
  898.         if (dwUserPolicyMode > 0) {
  899.             if (!(lpGPOInfo->dwFlags & GP_APPLY_DS_POLICY)) {
  900.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Loopback is not allowed for downlevel or local user accounts.  Loopback will be disabled.")));
  901.                 LogEvent (FALSE, IDS_LOOPBACK_DISABLED1);
  902.                 dwUserPolicyMode = 0;
  903.             }
  904.             if (dwUserPolicyMode > 0) {
  905.                 if (lpGPOInfo->iMachineRole < 2) {
  906.                     DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Loopback is not allowed on machines joined to a downlevel domain or running standalone.  Loopback will be disabled.")));
  907.                     LogEvent (TRUE, IDS_LOOPBACK_DISABLED2);
  908.                     dwUserPolicyMode = 0;
  909.                 }
  910.             }
  911.         }
  912.     }
  913.     //
  914.     // Check if user's sid has changed
  915.     //
  916.     if ( !CheckForChangedSid( lpGPOInfo ) ) {
  917.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Check for changed sid failed")));
  918.         goto Exit;
  919.     }
  920.     if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
  921.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to impersonate user")));
  922.         LogEvent (TRUE, IDS_FAILED_IMPERSONATE, GetLastError() );
  923.         goto Exit;
  924.     }
  925.     //
  926.     // Check if any extensions can be skipped. If there is ever a case where
  927.     // all extensions can be skipped, then exit successfully right after this check.
  928.     // Currently RegistryExtension is always run unless there are no GPO changes,
  929.     // but the GPO changes check is done much later.
  930.     //
  931.     if ( !CheckForSkippedExtensions( lpGPOInfo ) ) {
  932.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Checking extensions for skipping failed")));
  933.         //
  934.         // LogEvent() is called by CheckForSkippedExtensions()
  935.         //
  936.         goto Exit;
  937.     }
  938.     //
  939.     // Query for the GPO list based upon the mode
  940.     //
  941.     // 0 is normal
  942.     // 1 is merge.  Merge user list + machine list
  943.     // 2 is replace.  use machine list instead of user list
  944.     //
  945.     if (dwUserPolicyMode == 0) {
  946.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Calling GetGPOInfo for normal policy mode")));
  947.         bResult = GetGPOInfo ((lpGPOInfo->dwFlags & GP_MACHINE) ? GPO_LIST_FLAG_MACHINE : 0,
  948.                               lpDomainDN, lpName, NULL, &lpGPOInfo->lpGPOList, pNetAPI32, TRUE);
  949.         if (!bResult) {
  950.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed.")));
  951.             LogEvent (TRUE, IDS_GPO_QUERY_FAILED);
  952.         }
  953.     } else if (dwUserPolicyMode == 2) {
  954.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Calling GetGPOInfo for replacement user policy mode")));
  955.         lpComputerName = MyGetComputerName (NameFullyQualifiedDN);
  956.     
  957.         if (lpComputerName) {
  958.     
  959.             PDOMAIN_CONTROLLER_INFO pDCInfo;
  960.             DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Using computer name %s for query."), lpComputerName));
  961.     
  962.             dwResult = pNetAPI32->pfnDsGetDcName(   0,
  963.                                                     0,
  964.                                                     0,
  965.                                                     0,
  966.                                                     DS_DIRECTORY_SERVICE_REQUIRED |
  967.                                                     ((lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD) ? DS_BACKGROUND_ONLY : 0),
  968.                                                     &pDCInfo);
  969.             if ( dwResult == 0 )
  970.             {
  971.                     bResult = GetGPOInfo (0, pDCInfo->DomainName, lpComputerName, NULL,
  972.                                           &lpGPOInfo->lpGPOList, pNetAPI32, FALSE);
  973.                     if (!bResult) {
  974.                         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed.")));
  975.                         LogEvent (TRUE, IDS_GPO_QUERY_FAILED);
  976.                     }
  977.     
  978.                 pNetAPI32->pfnNetApiBufferFree( pDCInfo );
  979.             }
  980.             else
  981.             {
  982.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer domain name with %d"),
  983.                              GetLastError()));
  984.                 LogEvent (TRUE, IDS_NO_MACHINE_DOMAIN, lpComputerName, GetLastError() );
  985.                 bResult = FALSE;
  986.             }
  987.             LocalFree (lpComputerName);
  988.         } else {
  989.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer name with %d"),
  990.                          GetLastError()));
  991.             LogEvent (TRUE, IDS_FAILED_MACHINENAME, GetLastError());
  992.             bResult = FALSE;
  993.         }
  994.     } else {
  995.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Calling GetGPOInfo for merging user policy mode")));
  996.         lpComputerName = MyGetComputerName (NameFullyQualifiedDN);
  997.         if (lpComputerName) {
  998.             lpGPOInfo->lpGPOList = NULL;
  999.             bResult = GetGPOInfo (0, lpDomainDN, lpName, NULL,
  1000.                                       &lpGPOInfo->lpGPOList, pNetAPI32, FALSE);
  1001.             if (bResult) {
  1002.                 PDOMAIN_CONTROLLER_INFO pDCInfo;
  1003.         
  1004.                 DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Using computer name %s for query."), lpComputerName));
  1005.                 lpGPO = NULL;
  1006.                 dwResult = pNetAPI32->pfnDsGetDcName(   0,
  1007.                                                         0,
  1008.                                                         0,
  1009.                                                         0,
  1010.                                                         DS_DIRECTORY_SERVICE_REQUIRED |
  1011.                                                         ((lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD) ? DS_BACKGROUND_ONLY : 0),
  1012.                                                         &pDCInfo);
  1013.                 if ( dwResult == 0 )
  1014.                 {
  1015.                     bResult = GetGPOInfo (0, pDCInfo->DomainName, lpComputerName, NULL,
  1016.                                       &lpGPO, pNetAPI32, FALSE);
  1017.                     if (bResult) {
  1018.                         if (lpGPOInfo->lpGPOList && lpGPO) {
  1019.     
  1020.                             DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Both user and machine lists are defined.  Merging them together.")));
  1021.                             //
  1022.                             // Need to merge the lists together
  1023.                             //
  1024.     
  1025.                             lpGPOTemp = lpGPOInfo->lpGPOList;
  1026.                             while (lpGPOTemp->pNext) {
  1027.                                 lpGPOTemp = lpGPOTemp->pNext;
  1028.                             }
  1029.                             lpGPOTemp->pNext = lpGPO;
  1030.                         } else if (!lpGPOInfo->lpGPOList && lpGPO) {
  1031.     
  1032.                             DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Only machine list is defined.")));
  1033.                             lpGPOInfo->lpGPOList = lpGPO;
  1034.     
  1035.                         } else {
  1036.     
  1037.                             DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Only user list is defined.")));
  1038.                         }
  1039.     
  1040.                     } else {
  1041.                         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed for computer name.")));
  1042.                         LogEvent (TRUE, IDS_GPO_QUERY_FAILED);
  1043.                     }
  1044.                     pNetAPI32->pfnNetApiBufferFree( pDCInfo );
  1045.                 }
  1046.             else
  1047.             {
  1048.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer domain name with %d"),
  1049.                          GetLastError()));
  1050.                 LogEvent (TRUE, IDS_NO_MACHINE_DOMAIN, lpComputerName, GetLastError());
  1051.                 bResult = FALSE;
  1052.             }
  1053.                     
  1054.             } else {
  1055.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: GetGPOInfo failed for user name.")));
  1056.                 LogEvent (TRUE, IDS_GPO_QUERY_FAILED);
  1057.             }
  1058.             LocalFree (lpComputerName);
  1059.         } else {
  1060.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to get the computer name with %d"),
  1061.                          GetLastError()));
  1062.             LogEvent (TRUE, IDS_FAILED_MACHINENAME, GetLastError());
  1063.             bResult = FALSE;
  1064.         }
  1065.     }
  1066.     if (!RevertToUser(&hOldToken)) {
  1067.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to revert to self")));
  1068.     }
  1069.     if (!bResult) {
  1070.         goto Exit;
  1071.     }
  1072.     bResult = SetupGPOFilter( lpGPOInfo );
  1073.     if (!bResult) {
  1074.         DebugMsg((DM_WARNING, TEXT("ProcessGPOs: SetupGPOFilter failed.")));
  1075.         LogEvent (TRUE, IDS_SETUP_GPOFILTER_FAILED);
  1076.         goto Exit;
  1077.     }
  1078.     //
  1079.     // Need to check if the security group membership has changed the first time around
  1080.     //
  1081.     if ( !(lpGPOInfo->dwFlags & GP_BACKGROUND_THREAD) ) {
  1082.         if ((lpGPOInfo->dwFlags & GP_MACHINE) && (lpGPOInfo->dwFlags & GP_APPLY_DS_POLICY)) {
  1083.         
  1084.             HANDLE hLocToken=NULL;
  1085.             //
  1086.             // if it is machine policy processing, get the machine token so that we can check
  1087.             // security group membership using the right token. This causes GetMachineToken to be called twice
  1088.             // but moving it to the beginning requires too much change.
  1089.             //
  1090.             
  1091.             hLocToken = GetMachineToken();            
  1092.             if (hLocToken) {
  1093.                 CheckGroupMembership( lpGPOInfo, hLocToken, &lpGPOInfo->bMemChanged, &lpGPOInfo->bUserLocalMemChanged);            
  1094.                 CloseHandle(hLocToken);
  1095.             } 
  1096.             else {
  1097.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs:  Failed to get the machine token with  %d"), GetLastError()));
  1098.                 goto Exit;
  1099.             }
  1100.         }
  1101.         else {
  1102.             //
  1103.             // In the user case just use the token passed in
  1104.             //
  1105.             
  1106.             CheckGroupMembership( lpGPOInfo, lpGPOInfo->hToken, &lpGPOInfo->bMemChanged, &lpGPOInfo->bUserLocalMemChanged);
  1107.         }        
  1108.     }
  1109.     
  1110.     
  1111.     DebugPrintGPOList( lpGPOInfo );
  1112.     //================================================================
  1113.     //
  1114.     // Now walk through the list of extensions
  1115.     //
  1116.     //================================================================
  1117.     EnterCriticalSection( &g_GPOCS );
  1118.     pGPHandle = (LPGPINFOHANDLE) LocalAlloc( LPTR, sizeof(GPINFOHANDLE) );
  1119.     //
  1120.     // Continue even if pGPHandle is 0, because all it means is that async completions (if any)
  1121.     // will fail. Remove old asynch completion context.
  1122.     //
  1123.     if ( pGPHandle )
  1124.         pGPHandle->pGPOInfo = lpGPOInfo;
  1125.     if ( lpGPOInfo->dwFlags & GP_MACHINE ) {
  1126.         if ( g_pMachGPInfo )
  1127.             LocalFree( g_pMachGPInfo );
  1128.         g_pMachGPInfo = pGPHandle;
  1129.     } else {
  1130.         if ( g_pUserGPInfo )
  1131.             LocalFree( g_pUserGPInfo );
  1132.         g_pUserGPInfo = pGPHandle;
  1133.     }
  1134.     LeaveCriticalSection( &g_GPOCS );
  1135.     pAsyncHandle = (ASYNCCOMPLETIONHANDLE) pGPHandle;
  1136.     dwCurrentTime = GetCurTime();
  1137.     lpExt = lpGPOInfo->lpExtensions;
  1138.     //
  1139.     // Before going in, get the thread token and reset the thread token in case
  1140.     // one of the extensions hit an exception.
  1141.     //
  1142.     
  1143.     if (!OpenThreadToken (GetCurrentThread(), TOKEN_IMPERSONATE | TOKEN_READ,
  1144.                           TRUE, &hOldToken)) {
  1145.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: OpenThreadToken failed with error %d, assuming thread is not impersonating"), GetLastError()));
  1146.         hOldToken = NULL;
  1147.     }
  1148.         
  1149.     while ( lpExt ) {
  1150.         BOOL bProcessGPOs, bNoChanges, bUsePerUserLocalSetting;
  1151.         PGROUP_POLICY_OBJECT pDeletedGPOList;
  1152.         DWORD dwRet;
  1153.         //
  1154.         // Check for early shutdown or user logoff
  1155.         //
  1156.         if ( (lpGPOInfo->dwFlags & GP_MACHINE) && g_bStopMachGPOProcessing
  1157.              || !(lpGPOInfo->dwFlags & GP_MACHINE) && g_bStopUserGPOProcessing ) {
  1158.             DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Aborting GPO processing due to machine shutdown or logoff")));
  1159.             LogEvent (TRUE, IDS_GPO_PROC_STOPPED);
  1160.             break;
  1161.         }
  1162.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: -----------------------")));
  1163.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Processing extension %s"),
  1164.                  lpExt->lpDisplayName));
  1165.         if ( lpExt->bSkipped ) {
  1166.             DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s skipped with flags 0x%x."),
  1167.                       lpExt->lpDisplayName, lpGPOInfo->dwFlags));
  1168.             if (lpGPOInfo->dwFlags & GP_VERBOSE)
  1169.                 LogEvent (FALSE, IDS_EXT_SKIPPED, lpExt->lpDisplayName, lpGPOInfo->dwFlags);
  1170.             lpExt = lpExt->pNext;
  1171.             continue;
  1172.         }
  1173.         //
  1174.         // Reset lpGPOInfo->lpGPOList based on extension filter list. If the extension
  1175.         // is being called to do delete processing on the history then the current GpoList
  1176.         // is null.
  1177.         //
  1178.         if ( lpExt->bHistoryProcessing ) {
  1179.             DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s is being called to do delete processing on cached history."),
  1180.                       lpExt->lpDisplayName));
  1181.             lpGPOInfo->lpGPOList = NULL;
  1182.         }
  1183.         else
  1184.             FilterGPOs( lpExt, lpGPOInfo );
  1185.         DebugPrintGPOList( lpGPOInfo );
  1186.         if ( !CheckGPOs( lpExt, lpGPOInfo, dwCurrentTime,
  1187.                          &bProcessGPOs, &bNoChanges, &pDeletedGPOList ) ) {
  1188.             DebugMsg((DM_WARNING, TEXT("ProcessGPOs: CheckGPOs failed.")));
  1189.             lpExt = lpExt->pNext;
  1190.             continue;
  1191.         }
  1192.         if ( bProcessGPOs ) {
  1193.             if ( pDeletedGPOList == NULL && lpGPOInfo->lpGPOList == NULL ) {
  1194.                 DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s skipped because both deleted and changed GPO lists are empty."),
  1195.                           lpExt->lpDisplayName ));
  1196.                 if (lpGPOInfo->dwFlags & GP_VERBOSE)
  1197.                     LogEvent (FALSE, IDS_EXT_HAS_EMPTY_LISTS, lpExt->lpDisplayName);
  1198.                 lpExt = lpExt->pNext;
  1199.                 continue;
  1200.             }
  1201.             if ( lpExt->dwEnableAsynch ) {
  1202.                 //
  1203.                 // Save now to shadow area to avoid race between thread that returns from
  1204.                 // ProcessGPOList and the thread that does ProcessGroupPolicyCompleted and
  1205.                 // reads from shadow area.
  1206.                 //
  1207.                 SaveGPOList( lpExt->lpKeyName, lpGPOInfo,
  1208.                              HKEY_LOCAL_MACHINE,
  1209.                              bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : NULL,
  1210.                              TRUE, lpGPOInfo->lpGPOList );
  1211.             }
  1212.             dwRet = E_FAIL;
  1213.             __try {
  1214.                 dwRet = ProcessGPOList( lpExt, lpGPOInfo, pDeletedGPOList,
  1215.                                         lpGPOInfo->lpGPOList, bNoChanges, pAsyncHandle );
  1216.             }
  1217.             __except( GPOExceptionFilter( GetExceptionInformation() ) ) {
  1218.                 SetThreadToken(NULL, hOldToken);
  1219.                 
  1220.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Extension %s ProcessGroupPolicy threw unhandled exception 0x%x."),
  1221.                             lpExt->lpDisplayName, GetExceptionCode() ));
  1222.                 LogEvent (TRUE, IDS_CAUGHT_EXCEPTION, lpExt->lpDisplayName, GetExceptionCode());
  1223.                 
  1224.             }
  1225.             FreeGPOList( pDeletedGPOList );
  1226.             pDeletedGPOList = NULL;
  1227.             bUsePerUserLocalSetting = lpExt->dwUserLocalSetting && !(lpGPOInfo->dwFlags & GP_MACHINE);
  1228.             if ( dwRet == ERROR_SUCCESS || dwRet == ERROR_OVERRIDE_NOCHANGES ) {
  1229.                 //
  1230.                 // ERROR_OVERRIDE_NOCHANGES means that extension processed the list and so the cached list
  1231.                 // must be updated, but the extension will be called the next time even if there are
  1232.                 // no changes.
  1233.                 //
  1234.                 SaveGPOList( lpExt->lpKeyName, lpGPOInfo,
  1235.                              HKEY_LOCAL_MACHINE,
  1236.                              bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : NULL,
  1237.                              FALSE, lpGPOInfo->lpGPOList );
  1238.                 uExtensionCount++;
  1239.             } else if ( dwRet == E_PENDING ) {
  1240.                 DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Extension %s ProcessGroupPolicy returned e_pending."),
  1241.                           lpExt->lpDisplayName));
  1242.             } else {
  1243.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Extension %s ProcessGroupPolicy failed, status 0x%x."),
  1244.                           lpExt->lpDisplayName, dwRet));
  1245.                 if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  1246.                     LogEvent (FALSE, IDS_CHANGES_FAILED, lpExt->lpDisplayName, dwRet);
  1247.                 }
  1248.             }
  1249.             WriteStatus( lpExt->lpKeyName, lpGPOInfo,
  1250.                          bUsePerUserLocalSetting ? lpGPOInfo->lpwszSidUser : NULL,
  1251.                          dwRet, dwCurrentTime,
  1252.                          (lpGPOInfo->dwFlags & GP_SLOW_LINK) != 0 );
  1253.         }
  1254.         //
  1255.         // Process next extension
  1256.         //
  1257.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: -----------------------")));
  1258.         lpExt = lpExt->pNext;
  1259.     }
  1260.     if (hOldToken)
  1261.         CloseHandle(hOldToken);
  1262.     //================================================================
  1263.     //
  1264.     // Success
  1265.     //
  1266.     //================================================================
  1267.     //
  1268.     // Set the return value
  1269.     //
  1270.     bRetVal = TRUE;
  1271. Exit:
  1272.     //
  1273.     // Unload the Group Policy Extensions
  1274.     //
  1275.     UnloadGPExtensions (lpGPOInfo);
  1276.     FreeLists( lpGPOInfo );
  1277.     lpGPOInfo->lpGPOList = NULL;
  1278.     lpGPOInfo->lpExtFilterList = NULL;
  1279.     //
  1280.     // Token groups can change only at logon time, so reset to false
  1281.     //
  1282.     lpGPOInfo->bMemChanged = FALSE;
  1283.     lpGPOInfo->bUserLocalMemChanged = FALSE;
  1284.     //
  1285.     // We migrate the policy data from old sid only at logon time.
  1286.     // reset it to false.
  1287.     //
  1288.     
  1289.     lpGPOInfo->bSidChanged = FALSE;
  1290.     if (pDCI) {
  1291.         pNetAPI32->pfnNetApiBufferFree(pDCI);
  1292.     }
  1293.     
  1294.     if (lpName) {
  1295.         LocalFree (lpName);
  1296.     }
  1297.     if (lpDomain) {
  1298.         LocalFree (lpDomain);
  1299.     }
  1300.     //
  1301.     // Release the critical section
  1302.     //
  1303.     if (lpGPOInfo->hCritSection) {
  1304.         LeaveCriticalPolicySection (lpGPOInfo->hCritSection);
  1305.         lpGPOInfo->hCritSection = NULL;
  1306.     }
  1307.     //
  1308.     // Announce that policies have changed
  1309.     //
  1310.     if (bRetVal) {
  1311.         if (uExtensionCount) {
  1312.             //
  1313.             // First, update User with new colors, bitmaps, etc.
  1314.             //
  1315.             if (lpGPOInfo->dwFlags & GP_REGPOLICY_CPANEL) {
  1316.                 //
  1317.                 // Something has changed in the control panel section
  1318.                 // Start control.exe with the /policy switch so the
  1319.                 // display is refreshed.
  1320.                 //
  1321.                 RefreshDisplay (lpGPOInfo);
  1322.             }
  1323.             //
  1324.             // Notify anyone waiting on an event handle
  1325.             //
  1326.             if (lpGPOInfo->hNotifyEvent) {
  1327.                 PulseEvent (lpGPOInfo->hNotifyEvent);
  1328.             }
  1329.             //
  1330.             // Create a thread to broadcase the WM_SETTINGCHANGE message
  1331.             //
  1332.             hThread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) PolicyChangedThread,
  1333.                                     (LPVOID) ((lpGPOInfo->dwFlags & GP_MACHINE) ? 1 : 0),
  1334.                                     CREATE_SUSPENDED, &dwThreadID);
  1335.             if (hThread) {
  1336.                 SetThreadPriority (hThread, THREAD_PRIORITY_IDLE);
  1337.                 ResumeThread (hThread);
  1338.                 CloseHandle (hThread);
  1339.             } else {
  1340.                 DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Failed to create background thread (%d)."),
  1341.                          GetLastError()));
  1342.                 PolicyChangedThread (((lpGPOInfo->dwFlags & GP_MACHINE) ? 1 : 0));
  1343.             }
  1344.         }
  1345.     }
  1346.     if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  1347.         if (lpGPOInfo->dwFlags & GP_MACHINE) {
  1348.             LogEvent (FALSE, IDS_MACHINE_POLICY_APPLIED);
  1349.         } else {
  1350.             LogEvent (FALSE, IDS_USER_POLICY_APPLIED);
  1351.         }
  1352.     }
  1353.     if (lpGPOInfo->dwFlags & GP_MACHINE) {
  1354.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Computer Group Policy has been applied.")));
  1355.     } else {
  1356.         DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: User Group Policy has been applied.")));
  1357.     }
  1358.     DebugMsg((DM_VERBOSE, TEXT("ProcessGPOs: Leaving with %d."), bRetVal));
  1359.     return bRetVal;
  1360. }
  1361. //*************************************************************
  1362. //
  1363. //  PolicyChangedThread()
  1364. //
  1365. //  Purpose:    Sends the WM_SETTINGCHANGE message announcing
  1366. //              that policy has changed.  This is done on a
  1367. //              separate thread because this could take many
  1368. //              seconds to succeed if an application is hung
  1369. //
  1370. //  Parameters: BOOL bMachine - machine or user policy has been applied
  1371. //
  1372. //
  1373. //  Return:     0
  1374. //
  1375. //*************************************************************
  1376. DWORD WINAPI PolicyChangedThread (BOOL bMachine)
  1377. {
  1378.     HINSTANCE hInst;
  1379.     NTSTATUS Status;
  1380.     BOOLEAN WasEnabled;
  1381.     DWORD dwBSM;
  1382.     hInst = LoadLibrary (TEXT("userenv.dll"));
  1383.     DebugMsg((DM_VERBOSE, TEXT("PolicyChangedThread: Entering with %d."), bMachine));
  1384.     //
  1385.     // Broadcase the WM_SETTINGCHANGE message
  1386.     //
  1387.     Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
  1388.     if (NT_SUCCESS(Status)) {
  1389.         dwBSM = BSM_ALLDESKTOPS | BSM_APPLICATIONS;
  1390.         BroadcastSystemMessage (BSF_IGNORECURRENTTASK | BSF_FORCEIFHUNG,
  1391.                                 &dwBSM,
  1392.                                 WM_SETTINGCHANGE,
  1393.                                 bMachine, (LPARAM) TEXT("Policy"));
  1394.         RtlAdjustPrivilege(SE_TCB_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
  1395.     }
  1396.     DebugMsg((DM_VERBOSE, TEXT("PolicyChangedThread: Leaving")));
  1397.     FreeLibraryAndExitThread (hInst, 0);
  1398.     return 0;
  1399. }
  1400. //*************************************************************
  1401. //
  1402. //  DeleteRegistryValue()
  1403. //
  1404. //  Purpose:    Callback from ParseRegistryFile that deletes
  1405. //              registry policies
  1406. //
  1407. //  Parameters: lpGPOInfo   -  GPO Information
  1408. //              lpKeyName   -  Key name
  1409. //              lpValueName -  Value name
  1410. //              dwType      -  Registry data type
  1411. //              lpData      -  Registry data
  1412. //
  1413. //  Return:     TRUE if successful
  1414. //              FALSE if an error occurs
  1415. //
  1416. //*************************************************************
  1417. BOOL DeleteRegistryValue (LPGPOINFO lpGPOInfo, LPTSTR lpKeyName,
  1418.                           LPTSTR lpValueName, DWORD dwType,
  1419.                           DWORD dwDataLength, LPBYTE lpData)
  1420. {
  1421.     DWORD dwDisp;
  1422.     HKEY hSubKey;
  1423.     LONG lResult;
  1424.     INT iStrLen;
  1425.     TCHAR szPolicies1[] = TEXT("Software\Policies");
  1426.     TCHAR szPolicies2[] = TEXT("Software\Microsoft\Windows\CurrentVersion\Policies");
  1427.     //
  1428.     // Check if there is a keyname
  1429.     //
  1430.     if (!lpKeyName || !(*lpKeyName)) {
  1431.         return TRUE;
  1432.     }
  1433.     //
  1434.     // Check if the key is in one of the policies keys
  1435.     //
  1436.     iStrLen = lstrlen(szPolicies1);
  1437.     if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szPolicies1,
  1438.                        iStrLen, lpKeyName, iStrLen) != CSTR_EQUAL) {
  1439.         iStrLen = lstrlen(szPolicies2);
  1440.         if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szPolicies2,
  1441.                            iStrLen, lpKeyName, iStrLen) != CSTR_EQUAL) {
  1442.             return TRUE;
  1443.         }
  1444.     }
  1445.     //
  1446.     // Check if the value name starts with **
  1447.     //
  1448.     if (lpValueName && (lstrlen(lpValueName) > 1)) {
  1449.         if ( (*lpValueName == TEXT('*')) && (*(lpValueName+1) == TEXT('*')) ) {
  1450.             return TRUE;
  1451.         }
  1452.     }
  1453.     //
  1454.     // We found a value that needs to be deleted
  1455.     //
  1456.     if (RegCleanUpValue (lpGPOInfo->hKeyRoot, lpKeyName, lpValueName)) {
  1457.         DebugMsg((DM_VERBOSE, TEXT("DeleteRegistryValue: Deleted %s\%s"),
  1458.                  lpKeyName, lpValueName));
  1459.     } else {
  1460.         DebugMsg((DM_WARNING, TEXT("DeleteRegistryValue: Failed to delete %s\%s"),
  1461.                  lpKeyName, lpValueName));
  1462.     }
  1463.     return TRUE;
  1464. }
  1465. //*************************************************************
  1466. //
  1467. //  ResetPolicies()
  1468. //
  1469. //  Purpose:    Resets the Policies and old Policies key to their
  1470. //              original state.
  1471. //
  1472. //  Parameters: lpGPOInfo   -   GPT information
  1473. //              lpArchive   -   Name of archive file
  1474. //
  1475. //
  1476. //  Return:     TRUE if successful
  1477. //              FALSE if an error occurs
  1478. //
  1479. //*************************************************************
  1480. BOOL ResetPolicies (LPGPOINFO lpGPOInfo, LPTSTR lpArchive)
  1481. {
  1482.     HKEY hKey;
  1483.     LONG lResult;
  1484.     DWORD dwDisp, dwValue = 0x95;
  1485.     DebugMsg((DM_VERBOSE, TEXT("ResetPolicies: Entering.")));
  1486.     //
  1487.     // Parse the archive file and delete any policies
  1488.     //
  1489.     if (!ParseRegistryFile (lpGPOInfo, lpArchive,
  1490.                             DeleteRegistryValue, NULL)) {
  1491.         DebugMsg((DM_WARNING, TEXT("ResetPolicies: Leaving")));
  1492.         return FALSE;
  1493.     }
  1494.     //
  1495.     // Recreate the new policies key
  1496.     //
  1497.     lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
  1498.                               TEXT("Software\Policies"),
  1499.                               0, NULL, REG_OPTION_NON_VOLATILE,
  1500.                               KEY_WRITE, NULL, &hKey, &dwDisp);
  1501.     if (lResult == ERROR_SUCCESS) {
  1502.         //
  1503.         // Re-apply security
  1504.         //
  1505.         RegCloseKey (hKey);
  1506.         if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
  1507.                               lpGPOInfo->hKeyRoot,
  1508.                               TEXT("Software\Policies"))) {
  1509.             DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to secure reg key.")));
  1510.         }
  1511.     } else {
  1512.         DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to create reg key with %d."), lResult));
  1513.     }
  1514.     //
  1515.     // Recreate the old policies key
  1516.     //
  1517.     lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
  1518.                               TEXT("Software\Microsoft\Windows\CurrentVersion\Policies"),
  1519.                               0, NULL, REG_OPTION_NON_VOLATILE,
  1520.                               KEY_WRITE, NULL, &hKey, &dwDisp);
  1521.     if (lResult == ERROR_SUCCESS) {
  1522.         //
  1523.         // Re-apply security
  1524.         //
  1525.         RegCloseKey (hKey);
  1526.         if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
  1527.                               lpGPOInfo->hKeyRoot,
  1528.                               TEXT("Software\Microsoft\Windows\CurrentVersion\Policies"))) {
  1529.             DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to secure reg key.")));
  1530.         }
  1531.     } else {
  1532.         DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to create reg key with %d."), lResult));
  1533.     }
  1534.     //
  1535.     // If this is user policy, reset the NoDriveTypeAutoRun default value
  1536.     //
  1537.     if (!(lpGPOInfo->dwFlags & GP_MACHINE)) {
  1538.         if (RegCreateKeyEx (lpGPOInfo->hKeyRoot,
  1539.                           TEXT("Software\Microsoft\Windows\CurrentVersion\Policies\Explorer"),
  1540.                           0, NULL, REG_OPTION_NON_VOLATILE,
  1541.                           KEY_WRITE, NULL, &hKey, &dwDisp) == ERROR_SUCCESS) {
  1542.             RegSetValueEx (hKey, TEXT("NoDriveTypeAutoRun"), 0,
  1543.                            REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
  1544.             RegCloseKey (hKey);
  1545.         }
  1546.     }
  1547.     DebugMsg((DM_VERBOSE, TEXT("ResetPolicies: Leaving.")));
  1548.     return TRUE;
  1549. }
  1550. //*************************************************************
  1551. //
  1552. //  SetupGPOFilter()
  1553. //
  1554. //  Purpose:    Setup up GPO Filter info
  1555. //
  1556. //  Parameters: lpGPOInfo   - GPO info
  1557. //
  1558. //  Return:     TRUE if successful
  1559. //              FALSE if an error occurs
  1560. //
  1561. //*************************************************************
  1562. BOOL SetupGPOFilter( LPGPOINFO lpGPOInfo )
  1563. {
  1564.     //
  1565.     // Format is [{ext guid1}{snapin guid1}..{snapin guidn}][{ext guid2}...]...
  1566.     // Both extension and snapin guids are in ascending order.
  1567.     //
  1568.     // Note: If the format is corrupt then take the conservative
  1569.     //       position and assume that it means that all
  1570.     //       extensions need to be applied to the GPO.
  1571.     //
  1572.     LPEXTFILTERLIST pExtFilterListTail = 0;
  1573.     PGROUP_POLICY_OBJECT lpGPO = 0;
  1574.     LPEXTFILTERLIST pExtFilterElem = NULL;
  1575.     lpGPOInfo->bXferToExtList = FALSE;
  1576.     lpGPO = lpGPOInfo->lpGPOList;
  1577.     while ( lpGPO ) {
  1578.         TCHAR *pchCur = lpGPO->lpExtensions;
  1579.         LPEXTLIST pExtListHead = 0;
  1580.         LPEXTLIST pExtListTail = 0;
  1581.         if ( pchCur ) {
  1582.             while ( *pchCur ) {
  1583.                 GUID guidExt;
  1584.                 LPEXTLIST pExtElem;
  1585.                 if ( *pchCur == TEXT('[') )
  1586.                     pchCur++;
  1587.                 else {
  1588.                     DebugMsg((DM_WARNING, TEXT("SetupGPOFilter: Corrupt extension name format.")));
  1589.                     FreeExtList( pExtListHead );
  1590.                     pExtListHead = 0;
  1591.                     break;
  1592.                 }
  1593.                 if ( ValidateGuid( pchCur ) )
  1594.                     StringToGuid( pchCur, &guidExt );
  1595.                 else {
  1596.                     DebugMsg((DM_WARNING, TEXT("SetupGPOFilter: Corrupt extension name format.")));
  1597.                     FreeExtList( pExtListHead );
  1598.                     pExtListHead = 0;
  1599.                     break;
  1600.                 }
  1601.                 pExtElem = LocalAlloc( LPTR, sizeof(EXTLIST) );
  1602.                 if ( pExtElem == 0 ) {
  1603.                     DebugMsg((DM_WARNING, TEXT("SetupGPOFilter: Unable to allocate memory.")));
  1604.                     FreeExtList( pExtListHead );
  1605.                     return FALSE;
  1606.                 }
  1607.                 pExtElem->guid = guidExt;
  1608.                 pExtElem->pNext = 0;
  1609.                 if ( pExtListTail )
  1610.                     pExtListTail->pNext = pExtElem;
  1611.                 else
  1612.                     pExtListHead = pExtElem;
  1613.                 pExtListTail = pExtElem;
  1614.                 while ( *pchCur && *pchCur != TEXT('[') )
  1615.                     pchCur++;
  1616.             } // while *pchcur
  1617.         } // if pchcur
  1618.         //
  1619.         // Append to lpExtFilterList
  1620.         //
  1621.         pExtFilterElem = LocalAlloc( LPTR, sizeof(EXTFILTERLIST) );
  1622.         if ( pExtFilterElem == NULL ) {
  1623.              DebugMsg((DM_WARNING, TEXT("SetupGPOFilter: Unable to allocate memory.")));
  1624.              FreeExtList( pExtListHead );
  1625.              return FALSE;
  1626.         }
  1627.         pExtFilterElem->lpExtList = pExtListHead;
  1628.         pExtFilterElem->lpGPO = lpGPO;
  1629.         pExtFilterElem->pNext = NULL;
  1630.         if ( pExtFilterListTail == 0 )
  1631.             lpGPOInfo->lpExtFilterList = pExtFilterElem;
  1632.         else
  1633.             pExtFilterListTail->pNext = pExtFilterElem;
  1634.         pExtFilterListTail = pExtFilterElem;
  1635.         //
  1636.         // Advance to next GPO
  1637.         //
  1638.         lpGPO = lpGPO->pNext;
  1639.     } // while lpgpo
  1640.     //
  1641.     // Transfer ownership from lpGPOList to lpExtFilterList
  1642.     //
  1643.     lpGPOInfo->bXferToExtList = TRUE;
  1644.     return TRUE;
  1645. }
  1646. //*************************************************************
  1647. //
  1648. //  FilterGPOs()
  1649. //
  1650. //  Purpose:    Filter GPOs not relevant to this extension
  1651. //
  1652. //  Parameters: lpExt        -  Extension
  1653. //              lpGPOInfo    -  GPO info
  1654. //
  1655. //*************************************************************
  1656. void FilterGPOs( LPGPEXT lpExt, LPGPOINFO lpGPOInfo )
  1657. {
  1658.     //
  1659.     // lpGPOInfo->lpGPOList will have the filtered list of GPOs
  1660.     //
  1661.     PGROUP_POLICY_OBJECT pGPOTail = 0;
  1662.     LPEXTFILTERLIST pExtFilterList = lpGPOInfo->lpExtFilterList;
  1663.     lpGPOInfo->lpGPOList = 0;
  1664.     while ( pExtFilterList ) {
  1665.         BOOL bFound = FALSE;
  1666.         LPEXTLIST pExtList = pExtFilterList->lpExtList;
  1667.         if ( pExtList == NULL ) {
  1668.             //
  1669.             // A null pExtlist means no extensions apply to this GPO
  1670.             //
  1671.             bFound = FALSE;
  1672.         } else {
  1673.             while (pExtList) {
  1674.                 INT iComp = CompareGuid( &lpExt->guid, &pExtList->guid );
  1675.                 if ( iComp == 0 ) {
  1676.                     bFound = TRUE;
  1677.                     break;
  1678.                 } else if ( iComp < 0 ) {
  1679.                     //
  1680.                     // Guids in pExtList are in ascending order, so we are done
  1681.                     //
  1682.                     break;
  1683.                 } else
  1684.                     pExtList = pExtList->pNext;
  1685.             } // while pextlist
  1686.         } // else
  1687.         if ( bFound ) {
  1688.             //
  1689.             // Append pExtFilterList->lpGPO to the filtered GPO list
  1690.             //
  1691.             pExtFilterList->lpGPO->pNext = 0;
  1692.             pExtFilterList->lpGPO->pPrev = pGPOTail;
  1693.             if ( pGPOTail == 0 )
  1694.                 lpGPOInfo->lpGPOList = pExtFilterList->lpGPO;
  1695.             else
  1696.                 pGPOTail->pNext = pExtFilterList->lpGPO;
  1697.             pGPOTail = pExtFilterList->lpGPO;
  1698.         }  // bFound
  1699.         pExtFilterList = pExtFilterList->pNext;
  1700.     }  // while pextfilterlist
  1701. }
  1702. //*************************************************************
  1703. //
  1704. //  GetDeletedGPOList()
  1705. //
  1706. //  Purpose:    Get the list of deleted GPOs
  1707. //
  1708. //  Parameters: lpGPOList        -  List of old GPOs
  1709. //              ppDeletedGPOList -  Deleted list returned here
  1710. //
  1711. //
  1712. //  Return:     TRUE if successful
  1713. //              FALSE if an error occurs
  1714. //
  1715. //*************************************************************
  1716. BOOL GetDeletedGPOList (PGROUP_POLICY_OBJECT lpGPOList,
  1717.                         PGROUP_POLICY_OBJECT *ppDeletedGPOList)
  1718. {
  1719.     *ppDeletedGPOList = NULL;
  1720.      //
  1721.      // It's possible that lpGPOList could be NULL.  This is ok.
  1722.      //
  1723.     if (!lpGPOList) {
  1724.         DebugMsg((DM_VERBOSE, TEXT("GetDeletedList: No old GPOs.  Leaving.")));
  1725.         return TRUE;
  1726.     }
  1727.     //
  1728.     // We need to do any delete operations in reverse order
  1729.     // of the way there were applied.
  1730.     //
  1731.     while ( lpGPOList ) {
  1732.         PGROUP_POLICY_OBJECT pCurGPO = lpGPOList;
  1733.         lpGPOList = lpGPOList->pNext;
  1734.         if ( pCurGPO->lParam & GPO_LPARAM_FLAG_DELETE ) {
  1735.             //
  1736.             // Prepend to deleted list
  1737.             //
  1738.             pCurGPO->pNext = *ppDeletedGPOList;
  1739.             pCurGPO->pPrev = NULL;
  1740.             if ( *ppDeletedGPOList )
  1741.                 (*ppDeletedGPOList)->pPrev = pCurGPO;
  1742.             *ppDeletedGPOList = pCurGPO;
  1743.         } else
  1744.             LocalFree( pCurGPO );
  1745.     }
  1746.     DebugMsg((DM_VERBOSE, TEXT("GetDeletedGPOList: Finished.")));
  1747.     return TRUE;
  1748. }
  1749. //*************************************************************
  1750. //
  1751. //  ReadGPOList()
  1752. //
  1753. //  Purpose:    Reads the list of Group Policy Objects from
  1754. //              the registry
  1755. //
  1756. //  Parameters: pszExtName -  GP extension
  1757. //              hKeyRoot   -  Registry handle
  1758. //              hKeyRootMach - Registry handle to hklm
  1759. //              lpwszSidUser - Sid of user, if non-null then it means
  1760. //                             per user local setting
  1761. //              bShadow    -  Read from shadow or from history list
  1762. //              lpGPOList  -  pointer to the array of GPOs
  1763. //
  1764. //
  1765. //  Return:     TRUE if successful
  1766. //              FALSE if an error occurs
  1767. //
  1768. //*************************************************************
  1769. BOOL ReadGPOList ( TCHAR * pszExtName, HKEY hKeyRoot,
  1770.                    HKEY hKeyRootMach, LPTSTR lpwszSidUser, BOOL bShadow,
  1771.                    PGROUP_POLICY_OBJECT * lpGPOList)
  1772. {
  1773.     INT iIndex = 0;
  1774.     LONG lResult;
  1775.     HKEY hKey, hSubKey = NULL;
  1776.     BOOL bResult = FALSE;
  1777.     TCHAR szSubKey[10];
  1778.     DWORD dwOptions, dwVersion;
  1779.     GPO_LINK GPOLink;
  1780.     LPARAM lParam;
  1781.     TCHAR szGPOName[50];
  1782.     LPTSTR lpDSPath = NULL, lpFileSysPath = NULL, lpDisplayName = NULL, lpExtensions = NULL, lpLink = NULL;
  1783.     DWORD dwDisp, dwSize, dwType, dwTemp, dwMaxSize;
  1784.     PGROUP_POLICY_OBJECT lpGPO, lpGPOTemp;
  1785.     TCHAR szKey[400];
  1786.     //
  1787.     // Set default
  1788.     //
  1789.     *lpGPOList = NULL;
  1790.     //
  1791.     // Open the key that holds the GPO list
  1792.     //
  1793.     if ( lpwszSidUser == 0 ) {
  1794.         wsprintf (szKey,
  1795.                   bShadow ? GP_SHADOW_KEY
  1796.                             : GP_HISTORY_KEY,
  1797.                   pszExtName );
  1798.     } else {
  1799.         wsprintf (szKey,
  1800.                   bShadow ? GP_SHADOW_SID_KEY
  1801.                           : GP_HISTORY_SID_KEY,
  1802.                           lpwszSidUser, pszExtName );
  1803.     }
  1804.     lResult = RegOpenKeyEx ( lpwszSidUser ? hKeyRootMach : hKeyRoot,
  1805.                             szKey,
  1806.                             0, KEY_READ, &hKey);
  1807.     if (lResult != ERROR_SUCCESS) {
  1808.         if (lResult == ERROR_FILE_NOT_FOUND) {
  1809.             return TRUE;
  1810.         } else {
  1811.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to open reg key with %d."), lResult));
  1812.             return FALSE;
  1813.         }
  1814.     }
  1815.     while (TRUE) {
  1816.         //
  1817.         // Enumerate through the subkeys.  The keys are named by index number
  1818.         // eg:  0, 1, 2, 3, etc...
  1819.         //
  1820.         IntToString (iIndex, szSubKey);
  1821.         lResult = RegOpenKeyEx (hKey, szSubKey, 0, KEY_READ, &hSubKey);
  1822.         if (lResult != ERROR_SUCCESS) {
  1823.             if (lResult == ERROR_FILE_NOT_FOUND) {
  1824.                 bResult = TRUE;
  1825.                 goto Exit;
  1826.             } else {
  1827.                 DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to open reg key <%s> with %d."), szSubKey, lResult));
  1828.                 goto Exit;
  1829.             }
  1830.         }
  1831.         //
  1832.         // Read the size of the largest value in this key
  1833.         //
  1834.         lResult = RegQueryInfoKey (hSubKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  1835.                                    &dwMaxSize, NULL, NULL);
  1836.         if (lResult != ERROR_SUCCESS) {
  1837.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query max size with %d."), lResult));
  1838.             goto Exit;
  1839.         }
  1840.         //
  1841.         // Allocate buffers based upon the value above
  1842.         //
  1843.         lpDSPath = LocalAlloc (LPTR, dwMaxSize);
  1844.         if (!lpDSPath) {
  1845.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to allocate memory with %d."), GetLastError()));
  1846.             goto Exit;
  1847.         }
  1848.         lpFileSysPath = LocalAlloc (LPTR, dwMaxSize);
  1849.         if (!lpFileSysPath) {
  1850.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to allocate memory with %d."), GetLastError()));
  1851.             goto Exit;
  1852.         }
  1853.         lpDisplayName = LocalAlloc (LPTR, dwMaxSize);
  1854.         if (!lpDisplayName) {
  1855.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to allocate memory with %d."), GetLastError()));
  1856.             goto Exit;
  1857.         }
  1858.         lpExtensions = LocalAlloc (LPTR, dwMaxSize);
  1859.         if (!lpExtensions) {
  1860.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to allocate memory with %d."), GetLastError()));
  1861.             goto Exit;
  1862.         }
  1863.         lpLink = LocalAlloc (LPTR, dwMaxSize);
  1864.         if (!lpLink) {
  1865.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to allocate memory with %d."), GetLastError()));
  1866.             goto Exit;
  1867.         }
  1868.         //
  1869.         // Read in the GPO
  1870.         //
  1871.         dwOptions = 0;
  1872.         dwSize = sizeof(dwOptions);
  1873.         lResult = RegQueryValueEx (hSubKey, TEXT("Options"), NULL, &dwType,
  1874.                                   (LPBYTE) &dwOptions, &dwSize);
  1875.         if (lResult != ERROR_SUCCESS) {
  1876.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query options reg value with %d."), lResult));
  1877.         }
  1878.         dwVersion = 0;
  1879.         dwSize = sizeof(dwVersion);
  1880.         lResult = RegQueryValueEx (hSubKey, TEXT("Version"), NULL, &dwType,
  1881.                                   (LPBYTE) &dwVersion, &dwSize);
  1882.         if (lResult != ERROR_SUCCESS) {
  1883.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query Version reg value with %d."), lResult));
  1884.         }
  1885.         dwSize = dwMaxSize;
  1886.         lResult = RegQueryValueEx (hSubKey, TEXT("DSPath"), NULL, &dwType,
  1887.                                   (LPBYTE) lpDSPath, &dwSize);
  1888.         if (lResult != ERROR_SUCCESS) {
  1889.             if (lResult != ERROR_FILE_NOT_FOUND) {
  1890.                 DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query DS reg value with %d."), lResult));
  1891.                 goto Exit;
  1892.             }
  1893.             LocalFree (lpDSPath);
  1894.             lpDSPath = NULL;
  1895.         }
  1896.         dwSize = dwMaxSize;
  1897.         lResult = RegQueryValueEx (hSubKey, TEXT("FileSysPath"), NULL, &dwType,
  1898.                                   (LPBYTE) lpFileSysPath, &dwSize);
  1899.         if (lResult != ERROR_SUCCESS) {
  1900.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query file sys path reg value with %d."), lResult));
  1901.             goto Exit;
  1902.         }
  1903.         dwSize = dwMaxSize;
  1904.         lResult = RegQueryValueEx (hSubKey, TEXT("DisplayName"), NULL, &dwType,
  1905.                                   (LPBYTE) lpDisplayName, &dwSize);
  1906.         if (lResult != ERROR_SUCCESS) {
  1907.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query display name reg value with %d."), lResult));
  1908.             goto Exit;
  1909.         }
  1910.         dwSize = dwMaxSize;
  1911.         lResult = RegQueryValueEx (hSubKey, TEXT("Extensions"), NULL, &dwType,
  1912.                                   (LPBYTE) lpExtensions, &dwSize);
  1913.         if (lResult != ERROR_SUCCESS) {
  1914.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query extension names reg value with %d."), lResult));
  1915.             LocalFree(lpExtensions);
  1916.             lpExtensions = NULL;
  1917.         }
  1918.         dwSize = dwMaxSize;
  1919.         lResult = RegQueryValueEx (hSubKey, TEXT("Link"), NULL, &dwType,
  1920.                                   (LPBYTE) lpLink, &dwSize);
  1921.         if (lResult != ERROR_SUCCESS) {
  1922.             if (lResult != ERROR_FILE_NOT_FOUND) {
  1923.                 DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query DS Object reg value with %d."), lResult));
  1924.             }
  1925.             LocalFree(lpLink);
  1926.             lpLink = NULL;
  1927.         }
  1928.         dwSize = sizeof(szGPOName);
  1929.         lResult = RegQueryValueEx (hSubKey, TEXT("GPOName"), NULL, &dwType,
  1930.                                   (LPBYTE) szGPOName, &dwSize);
  1931.         if (lResult != ERROR_SUCCESS) {
  1932.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query GPO name reg value with %d."), lResult));
  1933.             goto Exit;
  1934.         }
  1935.         GPOLink = GPLinkUnknown;
  1936.         dwSize = sizeof(GPOLink);
  1937.         lResult = RegQueryValueEx (hSubKey, TEXT("GPOLink"), NULL, &dwType,
  1938.                                   (LPBYTE) &GPOLink, &dwSize);
  1939.         if (lResult != ERROR_SUCCESS) {
  1940.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query reserved reg value with %d."), lResult));
  1941.         }
  1942.         lParam = 0;
  1943.         dwSize = sizeof(lParam);
  1944.         lResult = RegQueryValueEx (hSubKey, TEXT("lParam"), NULL, &dwType,
  1945.                                   (LPBYTE) &lParam, &dwSize);
  1946.         if (lResult != ERROR_SUCCESS) {
  1947.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to query lParam reg value with %d."), lResult));
  1948.         }
  1949.         //
  1950.         // Add the GPO to the list
  1951.         //
  1952.         if (!AddGPO (lpGPOList, dwOptions, dwVersion, lpDSPath, lpFileSysPath,
  1953.                      lpDisplayName, szGPOName, lpExtensions, GPOLink, lpLink, lParam,
  1954.                      FALSE, FALSE, FALSE)) {
  1955.             DebugMsg((DM_WARNING, TEXT("ReadGPOList: Failed to add GPO to list.")));
  1956.             goto Exit;
  1957.         }
  1958.         //
  1959.         // Free the buffers allocated above
  1960.         //
  1961.         if (lpDSPath) {
  1962.             LocalFree (lpDSPath);
  1963.             lpDSPath = NULL;
  1964.         }
  1965.         LocalFree (lpFileSysPath);
  1966.         lpFileSysPath = NULL;
  1967.         LocalFree (lpDisplayName);
  1968.         lpDisplayName = NULL;
  1969.         if (lpExtensions) {
  1970.             LocalFree(lpExtensions);
  1971.             lpExtensions = NULL;
  1972.         }
  1973.         if (lpLink) {
  1974.             LocalFree(lpLink);
  1975.             lpLink = NULL;
  1976.         }
  1977.         //
  1978.         // Close the subkey handle
  1979.         //
  1980.         RegCloseKey (hSubKey);
  1981.         hSubKey = NULL;
  1982.         iIndex++;
  1983.     }
  1984. Exit:
  1985.     if (lpDSPath) {
  1986.         LocalFree (lpDSPath);
  1987.     }
  1988.     if (lpFileSysPath) {
  1989.         LocalFree (lpFileSysPath);
  1990.     }
  1991.     if (lpDisplayName) {
  1992.         LocalFree (lpDisplayName);
  1993.     }
  1994.     if (lpExtensions) {
  1995.         LocalFree(lpExtensions);
  1996.     }
  1997.     if (lpLink) {
  1998.         LocalFree(lpLink);
  1999.     }
  2000.     if (hSubKey) {
  2001.         RegCloseKey (hSubKey);
  2002.     }
  2003.     RegCloseKey (hKey);
  2004.     if (!bResult) {
  2005.         //
  2006.         // Free any entries in the list
  2007.         //
  2008.         lpGPO = *lpGPOList;
  2009.         while (lpGPO) {
  2010.             lpGPOTemp = lpGPO->pNext;
  2011.             LocalFree (lpGPO);
  2012.             lpGPO = lpGPOTemp;
  2013.         }
  2014.         *lpGPOList = NULL;
  2015.     }
  2016.     return bResult;
  2017. }
  2018. //*************************************************************
  2019. //
  2020. //  SaveGPOList()
  2021. //
  2022. //  Purpose:    Saves the list of Group Policy Objects in
  2023. //              the registry
  2024. //
  2025. //  Parameters: pszExtName -  GP extension
  2026. //              lpGPOInfo  -  Group policy info
  2027. //              hKeyRootMach - Registry handle to hklm
  2028. //              lpwszSidUser - Sid of user, if non-null then it means
  2029. //                             per user local setting
  2030. //              bShadow    -  Save to shadow or to history list
  2031. //              lpGPOList  -  Array of GPOs
  2032. //
  2033. //
  2034. //  Return:     TRUE if successful
  2035. //              FALSE if an error occurs
  2036. //
  2037. //*************************************************************
  2038. BOOL SaveGPOList (TCHAR *pszExtName, LPGPOINFO lpGPOInfo,
  2039.                   HKEY hKeyRootMach, LPTSTR lpwszSidUser, BOOL bShadow,
  2040.                   PGROUP_POLICY_OBJECT lpGPOList)
  2041. {
  2042.     INT iIndex = 0;
  2043.     LONG lResult;
  2044.     HKEY hKey = NULL;
  2045.     BOOL bResult = FALSE;
  2046.     TCHAR szSubKey[400];
  2047.     DWORD dwDisp, dwSize;
  2048.     //
  2049.     // Start off with an empty key
  2050.     //
  2051.     if ( lpwszSidUser == 0 ) {
  2052.         wsprintf (szSubKey,
  2053.                   bShadow ? GP_SHADOW_KEY
  2054.                           : GP_HISTORY_KEY,
  2055.                   pszExtName);
  2056.     } else {
  2057.         wsprintf (szSubKey,
  2058.                   bShadow ? GP_SHADOW_SID_KEY
  2059.                           : GP_HISTORY_SID_KEY,
  2060.                   lpwszSidUser, pszExtName);
  2061.     }
  2062.     if (!RegDelnode (lpwszSidUser ? hKeyRootMach : lpGPOInfo->hKeyRoot,
  2063.                      szSubKey)) {
  2064.         DebugMsg((DM_VERBOSE, TEXT("SaveGPOList: RegDelnode failed.")));
  2065.     }
  2066.     //
  2067.     // Check if we have any GPOs to store.  It's ok for this to be NULL.
  2068.     //
  2069.     if (!lpGPOList) {
  2070.         return TRUE;
  2071.     }
  2072.     //
  2073.     // Set the proper security on the registry key
  2074.     //
  2075.     if ( !MakeRegKeySecure( (lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
  2076.                             lpwszSidUser ? hKeyRootMach : lpGPOInfo->hKeyRoot,
  2077.                             szSubKey ) ) {
  2078.         DebugMsg((DM_WARNING, TEXT("SaveGpoList: Failed to secure reg key.")));
  2079.     }
  2080.     //
  2081.     // Loop through the GPOs saving them in the registry
  2082.     //
  2083.     while (lpGPOList) {
  2084.         if ( lpwszSidUser == 0 ) {
  2085.             wsprintf (szSubKey,
  2086.                       bShadow ? TEXT("Software\Microsoft\Windows\CurrentVersion\Group Policy\Shadow\%ws\%d")
  2087.                               : TEXT("Software\Microsoft\Windows\CurrentVersion\Group Policy\History\%ws\%d"),
  2088.                       pszExtName,
  2089.                       iIndex);
  2090.         } else {
  2091.             wsprintf (szSubKey,
  2092.                       bShadow ? TEXT("Software\Microsoft\Windows\CurrentVersion\Group Policy\%ws\Shadow\%ws\%d")
  2093.                               : TEXT("Software\Microsoft\Windows\CurrentVersion\Group Policy\%ws\History\%ws\%d"),
  2094.                       lpwszSidUser, pszExtName, iIndex);
  2095.         }
  2096.         lResult = RegCreateKeyEx (lpwszSidUser ? hKeyRootMach : lpGPOInfo->hKeyRoot,
  2097.                                   szSubKey, 0, NULL,
  2098.                                   REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp);
  2099.         if (lResult != ERROR_SUCCESS) {
  2100.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to create reg key with %d."), lResult));
  2101.             goto Exit;
  2102.         }
  2103.         //
  2104.         // Save the GPO
  2105.         //
  2106.         dwSize = sizeof(lpGPOList->dwOptions);
  2107.         lResult = RegSetValueEx (hKey, TEXT("Options"), 0, REG_DWORD,
  2108.                                  (LPBYTE) &lpGPOList->dwOptions, dwSize);
  2109.         if (lResult != ERROR_SUCCESS) {
  2110.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set options reg value with %d."), lResult));
  2111.             goto Exit;
  2112.         }
  2113.         dwSize = sizeof(lpGPOList->dwVersion);
  2114.         lResult = RegSetValueEx (hKey, TEXT("Version"), 0, REG_DWORD,
  2115.                                  (LPBYTE) &lpGPOList->dwVersion, dwSize);
  2116.         if (lResult != ERROR_SUCCESS) {
  2117.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set Version reg value with %d."), lResult));
  2118.             goto Exit;
  2119.         }
  2120.         if (lpGPOList->lpDSPath) {
  2121.             dwSize = (lstrlen (lpGPOList->lpDSPath) + 1) * sizeof(TCHAR);
  2122.             lResult = RegSetValueEx (hKey, TEXT("DSPath"), 0, REG_SZ,
  2123.                                      (LPBYTE) lpGPOList->lpDSPath, dwSize);
  2124.             if (lResult != ERROR_SUCCESS) {
  2125.                 DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set DS reg value with %d."), lResult));
  2126.                 goto Exit;
  2127.             }
  2128.         }
  2129.         dwSize = (lstrlen (lpGPOList->lpFileSysPath) + 1) * sizeof(TCHAR);
  2130.         lResult = RegSetValueEx (hKey, TEXT("FileSysPath"), 0, REG_SZ,
  2131.                                   (LPBYTE) lpGPOList->lpFileSysPath, dwSize);
  2132.         if (lResult != ERROR_SUCCESS) {
  2133.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set file sys path reg value with %d."), lResult));
  2134.             goto Exit;
  2135.         }
  2136.         dwSize = (lstrlen (lpGPOList->lpDisplayName) + 1) * sizeof(TCHAR);
  2137.         lResult = RegSetValueEx (hKey, TEXT("DisplayName"), 0, REG_SZ,
  2138.                                 (LPBYTE) lpGPOList->lpDisplayName, dwSize);
  2139.         if (lResult != ERROR_SUCCESS) {
  2140.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set display name reg value with %d."), lResult));
  2141.             goto Exit;
  2142.         }
  2143.         if (lpGPOList->lpExtensions) {
  2144.             dwSize = (lstrlen (lpGPOList->lpExtensions) + 1) * sizeof(TCHAR);
  2145.             lResult = RegSetValueEx (hKey, TEXT("Extensions"), 0, REG_SZ,
  2146.                                     (LPBYTE) lpGPOList->lpExtensions, dwSize);
  2147.             if (lResult != ERROR_SUCCESS) {
  2148.                 DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set extension names reg value with %d."), lResult));
  2149.                 goto Exit;
  2150.             }
  2151.         }
  2152.         if (lpGPOList->lpLink) {
  2153.             dwSize = (lstrlen (lpGPOList->lpLink) + 1) * sizeof(TCHAR);
  2154.             lResult = RegSetValueEx (hKey, TEXT("Link"), 0, REG_SZ,
  2155.                                     (LPBYTE) lpGPOList->lpLink, dwSize);
  2156.             if (lResult != ERROR_SUCCESS) {
  2157.                 DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set DSObject reg value with %d."), lResult));
  2158.                 goto Exit;
  2159.             }
  2160.         }
  2161.         dwSize = (lstrlen (lpGPOList->szGPOName) + 1) * sizeof(TCHAR);
  2162.         lResult = RegSetValueEx (hKey, TEXT("GPOName"), 0, REG_SZ,
  2163.                                   (LPBYTE) lpGPOList->szGPOName, dwSize);
  2164.         if (lResult != ERROR_SUCCESS) {
  2165.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set GPO name reg value with %d."), lResult));
  2166.             goto Exit;
  2167.         }
  2168.         dwSize = sizeof(lpGPOList->GPOLink);
  2169.         lResult = RegSetValueEx (hKey, TEXT("GPOLink"), 0, REG_DWORD,
  2170.                                  (LPBYTE) &lpGPOList->GPOLink, dwSize);
  2171.         if (lResult != ERROR_SUCCESS) {
  2172.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set GPOLink reg value with %d."), lResult));
  2173.             goto Exit;
  2174.         }
  2175.         dwSize = sizeof(lpGPOList->lParam);
  2176.         lResult = RegSetValueEx (hKey, TEXT("lParam"), 0, REG_DWORD,
  2177.                                  (LPBYTE) &lpGPOList->lParam, dwSize);
  2178.         if (lResult != ERROR_SUCCESS) {
  2179.             DebugMsg((DM_WARNING, TEXT("SaveGPOList: Failed to set lParam reg value with %d."), lResult));
  2180.             goto Exit;
  2181.         }
  2182.         //
  2183.         // Close the handle
  2184.         //
  2185.         RegCloseKey (hKey);
  2186.         hKey = NULL;
  2187.         //
  2188.         // Prep for the next loop
  2189.         //
  2190.         iIndex++;
  2191.         lpGPOList = lpGPOList->pNext;
  2192.     }
  2193.     //
  2194.     // Success
  2195.     //
  2196.     bResult = TRUE;
  2197. Exit:
  2198.     if (hKey) {
  2199.         RegCloseKey (hKey);
  2200.     }
  2201.     return bResult;
  2202. }
  2203. //*************************************************************
  2204. //
  2205. //  WriteStatus()
  2206. //
  2207. //  Purpose:    Saves status in the registry
  2208. //
  2209. //  Parameters: lpGPOInfo  -  GPO info
  2210. //              lpExtName  -  GP extension name
  2211. //              dwStatus   -  Status to write
  2212. //              dwTime     -  Policy time to write
  2213. //              dwSlowLink -  Link speed to write
  2214. //
  2215. //
  2216. //  Return:     TRUE if successful
  2217. //              FALSE if an error occurs
  2218. //
  2219. //*************************************************************
  2220. BOOL WriteStatus( TCHAR *lpExtName, LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUser, DWORD dwStatus, DWORD dwTime,
  2221.                   DWORD dwSlowLink )
  2222. {
  2223.     HKEY hKey = NULL;
  2224.     DWORD dwDisp, dwSize;
  2225.     LONG lResult;
  2226.     BOOL bResult = FALSE;
  2227.     TCHAR szKey[400];
  2228.     if ( lpwszSidUser == 0 ) {
  2229.         wsprintf (szKey,
  2230.                   GP_EXTENSIONS_KEY,
  2231.                   lpExtName);
  2232.     } else {
  2233.         wsprintf (szKey,
  2234.                   GP_EXTENSIONS_SID_KEY,
  2235.                   lpwszSidUser, lpExtName);
  2236.     }
  2237.     lResult = RegCreateKeyEx (lpwszSidUser ? HKEY_LOCAL_MACHINE : lpGPOInfo->hKeyRoot,
  2238.                             szKey, 0, NULL,
  2239.                             REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDisp);
  2240.     if (lResult != ERROR_SUCCESS) {
  2241.         DebugMsg((DM_WARNING, TEXT("WriteStatus: Failed to create reg key with %d."), lResult));
  2242.         goto Exit;
  2243.     }
  2244.     dwSize = sizeof(dwStatus);
  2245.     lResult = RegSetValueEx (hKey, TEXT("Status"), 0, REG_DWORD,
  2246.                              (LPBYTE) &dwStatus, dwSize);
  2247.     if (lResult != ERROR_SUCCESS) {
  2248.         DebugMsg((DM_WARNING, TEXT("WriteStatus: Failed to set status reg value with %d."), lResult));
  2249.         goto Exit;
  2250.     }
  2251.     dwSize = sizeof(dwTime);
  2252.     lResult = RegSetValueEx (hKey, TEXT("LastPolicyTime"), 0, REG_DWORD,
  2253.                              (LPBYTE) &dwTime, dwSize);
  2254.     if (lResult != ERROR_SUCCESS) {
  2255.         DebugMsg((DM_WARNING, TEXT("WriteStatus: Failed to set time reg value with %d."), lResult));
  2256.         goto Exit;
  2257.     }
  2258.     dwSize = sizeof(dwSlowLink);
  2259.     lResult = RegSetValueEx (hKey, TEXT("PrevSlowLink"), 0, REG_DWORD,
  2260.                              (LPBYTE) &dwSlowLink, dwSize);
  2261.     if (lResult != ERROR_SUCCESS) {
  2262.         DebugMsg((DM_WARNING, TEXT("WriteStatus: Failed to set slowlink reg value with %d."), lResult));
  2263.         goto Exit;
  2264.     }
  2265.     bResult = TRUE;
  2266. Exit:
  2267.     if ( hKey != NULL )
  2268.         RegCloseKey( hKey );
  2269.     return bResult;
  2270. }
  2271. //*************************************************************
  2272. //
  2273. //  ReadStatus()
  2274. //
  2275. //  Purpose:    Reads status from the registry
  2276. //
  2277. //  Parameters: lpKeyName  -  Extension name
  2278. //              lpGPOInfo  -  GPO info
  2279. //              lpwszSidUser - Sid of user, if non-null then it means
  2280. //                             per user local setting
  2281. //              pdwStatus  -  Status returned here
  2282. //              pdwTime    -  Last policy time returned here
  2283. //              pdwSlowLink - Previous link speed returned here
  2284. //
  2285. //
  2286. //  Return:     TRUE if successful
  2287. //              FALSE if an error occurs
  2288. //
  2289. //*************************************************************
  2290. BOOL ReadStatus( TCHAR *lpKeyName, LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUser, DWORD *pdwStatus, DWORD *pdwTime,
  2291.                  DWORD *pdwSlowLink )
  2292. {
  2293.     HKEY hKey = NULL;
  2294.     DWORD dwType, dwSize;
  2295.     LONG lResult;
  2296.     BOOL bResult = FALSE;
  2297.     TCHAR szKey[400];
  2298.     if ( lpwszSidUser == 0 ) {
  2299.         wsprintf (szKey,
  2300.                   GP_EXTENSIONS_KEY,
  2301.                   lpKeyName);
  2302.     } else {
  2303.         wsprintf (szKey,
  2304.                   GP_EXTENSIONS_SID_KEY,
  2305.                   lpwszSidUser, lpKeyName);
  2306.     }
  2307.     lResult = RegOpenKeyEx (lpwszSidUser ? HKEY_LOCAL_MACHINE : lpGPOInfo->hKeyRoot,
  2308.                             szKey,
  2309.                             0, KEY_READ, &hKey);
  2310.     if (lResult != ERROR_SUCCESS) {
  2311.         if (lResult != ERROR_FILE_NOT_FOUND) {
  2312.             DebugMsg((DM_VERBOSE, TEXT("ReadStatus: Failed to open reg key with %d."), lResult));
  2313.         }
  2314.         goto Exit;
  2315.     }
  2316.     dwSize = sizeof(DWORD);
  2317.     lResult = RegQueryValueEx( hKey, TEXT("Status"), NULL,
  2318.                                &dwType, (LPBYTE) pdwStatus,
  2319.                                &dwSize );
  2320.     if (lResult != ERROR_SUCCESS) {
  2321.         if (lResult != ERROR_FILE_NOT_FOUND) {
  2322.             DebugMsg((DM_VERBOSE, TEXT("ReadStatus: Failed to read status reg value with %d."), lResult));
  2323.         }
  2324.         goto Exit;
  2325.     }
  2326.     dwSize = sizeof(DWORD);
  2327.     lResult = RegQueryValueEx( hKey, TEXT("LastPolicyTime"), NULL,
  2328.                                &dwType, (LPBYTE) pdwTime,
  2329.                                &dwSize );
  2330.     if (lResult != ERROR_SUCCESS) {
  2331.         DebugMsg((DM_VERBOSE, TEXT("ReadStatus: Failed to read time reg value with %d."), lResult));
  2332.         goto Exit;
  2333.     }
  2334.     dwSize = sizeof(DWORD);
  2335.     lResult = RegQueryValueEx( hKey, TEXT("PrevSlowLink"), NULL,
  2336.                                &dwType, (LPBYTE) pdwSlowLink,
  2337.                                &dwSize );
  2338.     if (lResult != ERROR_SUCCESS) {
  2339.         DebugMsg((DM_VERBOSE, TEXT("ReadStatus: Failed to read slowlink reg value with %d."), lResult));
  2340.         goto Exit;
  2341.     }
  2342.     bResult = TRUE;
  2343. Exit:
  2344.     if ( hKey != NULL )
  2345.         RegCloseKey( hKey );
  2346.     return bResult;
  2347. }
  2348. //*************************************************************
  2349. //
  2350. //  GetCurTime()
  2351. //
  2352. //  Purpose:    Returns current time in minutes, or 0 if there
  2353. //              is a failure
  2354. //
  2355. //*************************************************************
  2356. DWORD GetCurTime()
  2357. {
  2358.     DWORD dwCurTime = 0;
  2359.     LARGE_INTEGER liCurTime;
  2360.     if ( NT_SUCCESS( NtQuerySystemTime( &liCurTime) ) ) {
  2361.         if ( RtlTimeToSecondsSince1980 ( &liCurTime, &dwCurTime) ) {
  2362.             dwCurTime /= 60;   // seconds to minutes
  2363.         }
  2364.     }
  2365.     return dwCurTime;
  2366. }
  2367. //*************************************************************
  2368. //
  2369. //  CheckForGPOsToRemove()
  2370. //
  2371. //  Purpose:    Compares the GPOs in list1 with list 2 to determine
  2372. //              if any GPOs need to be removed.
  2373. //
  2374. //  Parameters: lpGPOList1  -   GPO link list 1
  2375. //              lpGPOList2  -   GPO link list 2
  2376. //
  2377. //  Return:     TRUE if one or more GPOs need to be removed
  2378. //              FALSE if not
  2379. //
  2380. //*************************************************************
  2381. BOOL CheckForGPOsToRemove (PGROUP_POLICY_OBJECT lpGPOList1, PGROUP_POLICY_OBJECT lpGPOList2)
  2382. {
  2383.     PGROUP_POLICY_OBJECT lpGPOSrc, lpGPODest;
  2384.     BOOL bFound;
  2385.     BOOL bResult = FALSE;
  2386.     //
  2387.     // First check to see if they are both NULL
  2388.     //
  2389.     if (!lpGPOList1 && !lpGPOList2) {
  2390.         return FALSE;
  2391.     }
  2392.     //
  2393.     // Go through every GPO in list 1, and see if it is still in list 2
  2394.     //
  2395.     lpGPOSrc = lpGPOList1;
  2396.     while (lpGPOSrc) {
  2397.         lpGPODest = lpGPOList2;
  2398.         bFound = FALSE;
  2399.         while (lpGPODest) {
  2400.             if (!lstrcmpi (lpGPOSrc->szGPOName, lpGPODest->szGPOName)) {
  2401.                 bFound = TRUE;
  2402.                 break;
  2403.             }
  2404.             lpGPODest = lpGPODest->pNext;
  2405.         }
  2406.         if (!bFound) {
  2407.             DebugMsg((DM_VERBOSE, TEXT("CheckForGPOsToRemove: GPO <%s> needs to be removed"), lpGPOSrc->lpDisplayName));
  2408.             lpGPOSrc->lParam |= GPO_LPARAM_FLAG_DELETE;
  2409.             bResult = TRUE;
  2410.         }
  2411.         lpGPOSrc = lpGPOSrc->pNext;
  2412.     }
  2413.     return bResult;
  2414. }
  2415. //*************************************************************
  2416. //
  2417. //  CompareGPOLists()
  2418. //
  2419. //  Purpose:    Compares one list of GPOs to another
  2420. //
  2421. //  Parameters: lpGPOList1  -   GPO link list 1
  2422. //              lpGPOList2  -   GPO link list 2
  2423. //
  2424. //  Return:     TRUE if the lists are the same
  2425. //              FALSE if not
  2426. //
  2427. //*************************************************************
  2428. BOOL CompareGPOLists (PGROUP_POLICY_OBJECT lpGPOList1, PGROUP_POLICY_OBJECT lpGPOList2)
  2429. {
  2430.     //
  2431.     // Check if one list is empty
  2432.     //
  2433.     if ((lpGPOList1 && !lpGPOList2) || (!lpGPOList1 && lpGPOList2)) {
  2434.         DebugMsg((DM_VERBOSE, TEXT("CompareGPOLists:  One list is empty")));
  2435.         return FALSE;
  2436.     }
  2437.     //
  2438.     // Loop through the GPOs
  2439.     //
  2440.     while (lpGPOList1 && lpGPOList2) {
  2441.         //
  2442.         // Compare GPO names
  2443.         //
  2444.         if (lstrcmpi (lpGPOList1->szGPOName, lpGPOList2->szGPOName) != 0) {
  2445.             DebugMsg((DM_VERBOSE, TEXT("CompareGPOLists:  Different entries found.")));
  2446.             return FALSE;
  2447.         }
  2448.         //
  2449.         // Compare the version numbers
  2450.         //
  2451.         if (lpGPOList1->dwVersion != lpGPOList2->dwVersion) {
  2452.             DebugMsg((DM_VERBOSE, TEXT("CompareGPOLists:  Different version numbers found")));
  2453.             return FALSE;
  2454.         }
  2455.         //
  2456.         // Move to the next node
  2457.         //
  2458.         lpGPOList1 = lpGPOList1->pNext;
  2459.         lpGPOList2 = lpGPOList2->pNext;
  2460.         //
  2461.         // Check if one list has more entries than the other
  2462.         //
  2463.         if ((lpGPOList1 && !lpGPOList2) || (!lpGPOList1 && lpGPOList2)) {
  2464.             DebugMsg((DM_VERBOSE, TEXT("CompareGPOLists:  One list has more entries than the other")));
  2465.             return FALSE;
  2466.         }
  2467.     }
  2468.     DebugMsg((DM_VERBOSE, TEXT("CompareGPOLists:  The lists are the same.")));
  2469.     return TRUE;
  2470. }
  2471. //*************************************************************
  2472. //
  2473. //  HistoryPresent()
  2474. //
  2475. //  Purpose:    Checks if the current extension has any cached
  2476. //              GPOs
  2477. //
  2478. //  Parameters: lpGPOInfo   -   GPOInfo
  2479. //              lpExt       -   Extension
  2480. //
  2481. //
  2482. //  Return:     TRUE if cached GPOs present
  2483. //              FALSE otherwise
  2484. //
  2485. //*************************************************************
  2486. BOOL HistoryPresent( LPGPOINFO lpGPOInfo, LPGPEXT lpExt )
  2487. {
  2488.     TCHAR szKey[400];
  2489.     LONG lResult;
  2490.     HKEY hKey;
  2491.     //
  2492.     // Check if history is cached on per user per machine basis
  2493.     //
  2494.     BOOL bUsePerUserLocalSetting = lpExt->dwUserLocalSetting && !(lpGPOInfo->dwFlags & GP_MACHINE);
  2495.     DmAssert( !bUsePerUserLocalSetting || lpGPOInfo->lpwszSidUser != 0 );
  2496.     if ( bUsePerUserLocalSetting ) {
  2497.         wsprintf( szKey, GP_HISTORY_SID_KEY,
  2498.                   lpGPOInfo->lpwszSidUser, lpExt->lpKeyName );
  2499.     } else {
  2500.         wsprintf( szKey, GP_HISTORY_KEY,
  2501.                   lpExt->lpKeyName );
  2502.     }
  2503.     lResult = RegOpenKeyEx ( bUsePerUserLocalSetting ? HKEY_LOCAL_MACHINE : lpGPOInfo->hKeyRoot,
  2504.                              szKey,
  2505.                              0, KEY_READ, &hKey);
  2506.     if (lResult == ERROR_SUCCESS) {
  2507.         RegCloseKey( hKey );
  2508.         return TRUE;
  2509.     } else
  2510.         return FALSE;
  2511. }
  2512. //*************************************************************
  2513. //
  2514. //  MigrateMembershipData()
  2515. //
  2516. //  Purpose:    Moves group membership data from old sid to new
  2517. //              sid.
  2518. //
  2519. //  Parameters: lpwszSidUserNew - New sid
  2520. //              lpwszSidUserOld - Old sid
  2521. //
  2522. //  Return:     TRUE if success
  2523. //              FALSE otherwise
  2524. //
  2525. //*************************************************************
  2526. BOOL MigrateMembershipData( LPTSTR lpwszSidUserNew, LPTSTR lpwszSidUserOld )
  2527. {
  2528.     DWORD dwCount = 0;
  2529.     DWORD dwSize, dwType, dwMaxSize, dwDisp;
  2530.     DWORD i= 0;
  2531.     LONG lResult;
  2532.     HKEY hKeyRead = NULL, hKeyWrite = NULL;
  2533.     BOOL bResult = TRUE;
  2534.     LPTSTR lpSid = NULL;
  2535.     TCHAR szKeyRead[250];
  2536.     TCHAR szKeyWrite[250];
  2537.     TCHAR szGroup[30];
  2538.     wsprintf( szKeyRead, GP_MEMBERSHIP_KEY, lpwszSidUserOld );
  2539.     lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, szKeyRead, 0, KEY_READ, &hKeyRead);
  2540.     if (lResult != ERROR_SUCCESS)
  2541.         return TRUE;
  2542.     wsprintf( szKeyWrite, GP_MEMBERSHIP_KEY, lpwszSidUserNew );
  2543.     if ( !RegDelnode( HKEY_LOCAL_MACHINE, szKeyWrite ) ) {
  2544.         DebugMsg((DM_VERBOSE, TEXT("MigrateMembershipData: RegDelnode failed.")));
  2545.         bResult = FALSE;
  2546.         goto Exit;
  2547.     }
  2548.     lResult = RegCreateKeyEx( HKEY_LOCAL_MACHINE, szKeyWrite, 0, NULL,
  2549.                               REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyWrite, &dwDisp);
  2550.     if (lResult != ERROR_SUCCESS) {
  2551.         DebugMsg((DM_WARNING, TEXT("MigrateMembershipData: Failed to create key with %d."), lResult));
  2552.         bResult = FALSE;
  2553.         goto Exit;
  2554.     }
  2555.     dwSize = sizeof(dwCount);
  2556.     lResult = RegQueryValueEx (hKeyRead, TEXT("Count"), NULL, &dwType,
  2557.                                (LPBYTE) &dwCount, &dwSize);
  2558.     if ( lResult != ERROR_SUCCESS ) {
  2559.         DebugMsg((DM_VERBOSE, TEXT("MigrateMembershipData: Failed to read membership count")));
  2560.         goto Exit;
  2561.     }
  2562.     lResult = RegQueryInfoKey (hKeyRead, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  2563.                                &dwMaxSize, NULL, NULL);
  2564.     if (lResult != ERROR_SUCCESS) {
  2565.         DebugMsg((DM_WARNING, TEXT("MigrateMembershipData: Failed to query max size with %d."), lResult));
  2566.         goto Exit;
  2567.     }
  2568.     //
  2569.     // Allocate buffer based upon the largest value
  2570.     //
  2571.     lpSid = LocalAlloc (LPTR, dwMaxSize);
  2572.     if (!lpSid) {
  2573.         DebugMsg((DM_WARNING, TEXT("MigrateMembershipData: Failed to allocate memory with %d."), lResult));
  2574.         bResult = FALSE;
  2575.         goto Exit;
  2576.     }
  2577.     for ( i=0; i<dwCount; i++ ) {
  2578.         wsprintf( szGroup, TEXT("Group%d"), i );
  2579.         dwSize = dwMaxSize;
  2580.         lResult = RegQueryValueEx (hKeyRead, szGroup, NULL, &dwType, (LPBYTE) lpSid, &dwSize);
  2581.         if (lResult != ERROR_SUCCESS) {
  2582.             DebugMsg((DM_WARNING, TEXT("MigrateMembershipData: Failed to read value %ws"), szGroup ));
  2583.             goto Exit;
  2584.         }
  2585.         dwSize = (lstrlen(lpSid) + 1) * sizeof(TCHAR);
  2586.         lResult = RegSetValueEx (hKeyWrite, szGroup, 0, REG_SZ, (LPBYTE) lpSid, dwSize);
  2587.         if (lResult != ERROR_SUCCESS) {
  2588.             bResult = FALSE;
  2589.             DebugMsg((DM_WARNING, TEXT("MigrateMembershipData: Failed to write value %ws"), szGroup ));
  2590.             goto Exit;
  2591.         }
  2592.     }
  2593.     dwSize = sizeof(dwCount);
  2594.     lResult = RegSetValueEx (hKeyWrite, TEXT("Count"), 0, REG_DWORD, (LPBYTE) &dwCount, dwSize);
  2595.     if (lResult != ERROR_SUCCESS) {
  2596.         bResult = FALSE;
  2597.         DebugMsg((DM_WARNING, TEXT("MigrateMembershipData: Failed to write count value") ));
  2598.         goto Exit;
  2599.     }
  2600. Exit:
  2601.     if ( lpSid )
  2602.         LocalFree( lpSid );
  2603.     if ( hKeyRead )
  2604.         RegCloseKey (hKeyRead);
  2605.     if ( hKeyWrite )
  2606.         RegCloseKey (hKeyWrite);
  2607.     return bResult;
  2608. }
  2609. //*************************************************************
  2610. //
  2611. //  MigrateGPOData()
  2612. //
  2613. //  Purpose:    Moves cached GPOs from old sid to new
  2614. //              sid.
  2615. //
  2616. //  Parameters: lpGPOInfo       -   GPOInfo
  2617. //              lpwszSidUserNew - New sid
  2618. //              lpwszSidUserOld - Old sid
  2619. //
  2620. //  Return:     TRUE if success
  2621. //              FALSE otherwise
  2622. //
  2623. //*************************************************************
  2624. BOOL MigrateGPOData( LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUserNew, LPTSTR lpwszSidUserOld )
  2625. {
  2626.     TCHAR szKey[250];
  2627.     LONG lResult;
  2628.     HKEY hKey = NULL;
  2629.     DWORD dwIndex = 0;
  2630.     TCHAR szExtension[50];
  2631.     DWORD dwSize = 50;
  2632.     FILETIME ftWrite;
  2633.     PGROUP_POLICY_OBJECT pGPOList, lpGPO, lpGPOTemp;
  2634.     BOOL bResult;
  2635.     wsprintf( szKey, GP_HISTORY_SID_ROOT_KEY, lpwszSidUserOld );
  2636.     lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hKey);
  2637.     if ( lResult != ERROR_SUCCESS )
  2638.         return TRUE;
  2639.     while (RegEnumKeyEx (hKey, dwIndex, szExtension, &dwSize,
  2640.                          NULL, NULL, NULL, &ftWrite) == ERROR_SUCCESS ) {
  2641.         if ( ReadGPOList( szExtension, NULL, HKEY_LOCAL_MACHINE,
  2642.                          lpwszSidUserOld, FALSE, &pGPOList) ) {
  2643.             bResult = SaveGPOList( szExtension, lpGPOInfo, HKEY_LOCAL_MACHINE,
  2644.                                    lpwszSidUserNew, FALSE, pGPOList );
  2645.             lpGPO = pGPOList;
  2646.             while (lpGPO) {
  2647.                 lpGPOTemp = lpGPO->pNext;
  2648.                 LocalFree (lpGPO);
  2649.                 lpGPO = lpGPOTemp;
  2650.             }
  2651.             if ( !bResult ) {
  2652.                 DebugMsg((DM_WARNING, TEXT("MigrateGPOData: Failed to save GPO list") ));
  2653.                 RegCloseKey( hKey );
  2654.                 return FALSE;
  2655.             }
  2656.         }
  2657.         dwSize = ARRAYSIZE(szExtension);
  2658.         dwIndex++;
  2659.     }
  2660.     RegCloseKey( hKey );
  2661.     return TRUE;
  2662. }
  2663. //*************************************************************
  2664. //
  2665. //  MigrateStatusData()
  2666. //
  2667. //  Purpose:    Moves extension status data from old sid to new
  2668. //              sid.
  2669. //
  2670. //  Parameters: lpGPOInfo       -   GPOInfo
  2671. //              lpwszSidUserNew - New sid
  2672. //              lpwszSidUserOld - Old sid
  2673. //
  2674. //  Return:     TRUE if success
  2675. //              FALSE otherwise
  2676. //
  2677. //*************************************************************
  2678. BOOL MigrateStatusData( LPGPOINFO lpGPOInfo, LPTSTR lpwszSidUserNew, LPTSTR lpwszSidUserOld )
  2679. {
  2680.     TCHAR szKey[250];
  2681.     LONG lResult;
  2682.     HKEY hKey = NULL;
  2683.     DWORD dwIndex = 0;
  2684.     TCHAR szExtension[50];
  2685.     DWORD dwSize = 50;
  2686.     FILETIME ftWrite;
  2687.     BOOL bTemp;
  2688.     DWORD dwStatus, dwTime, dwSlowLink;
  2689.     wsprintf( szKey, GP_EXTENSIONS_SID_ROOT_KEY, lpwszSidUserOld );
  2690.     lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hKey);
  2691.     if ( lResult != ERROR_SUCCESS )
  2692.         return TRUE;
  2693.     while (RegEnumKeyEx (hKey, dwIndex, szExtension, &dwSize,
  2694.                          NULL, NULL, NULL, &ftWrite) == ERROR_SUCCESS ) {
  2695.         if ( ReadStatus( szExtension, lpGPOInfo, lpwszSidUserOld, &dwStatus, &dwTime, &dwSlowLink ) ) {
  2696.             bTemp = WriteStatus( szExtension, lpGPOInfo, lpwszSidUserNew, dwStatus, dwTime, dwSlowLink );
  2697.             if ( !bTemp ) {
  2698.                 DebugMsg((DM_WARNING, TEXT("MigrateStatusData: Failed to save status") ));
  2699.                 RegCloseKey( hKey );
  2700.                 return FALSE;
  2701.             }
  2702.         }
  2703.         dwSize = ARRAYSIZE(szExtension);
  2704.         dwIndex++;
  2705.     }
  2706.     RegCloseKey( hKey );
  2707.     return TRUE;
  2708. }
  2709. //*************************************************************
  2710. //
  2711. //  CheckForChangedSid()
  2712. //
  2713. //  Purpose:    Checks if the user's sid has changed and if so,
  2714. //              moves history data from old sid to new sid.
  2715. //
  2716. //  Parameters: lpGPOInfo   -   GPOInfo
  2717. //
  2718. //  Return:     TRUE if success
  2719. //              FALSE otherwise
  2720. //