Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1460 lines
41 KiB

  1. //*************************************************************
  2. //
  3. // Functions to apply policy
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1995
  7. // All rights reserved
  8. //
  9. //*************************************************************
  10. #include "uenv.h"
  11. #include <regstr.h>
  12. #include <winnetwk.h>
  13. #include <lm.h>
  14. //
  15. // Update mode constants
  16. //
  17. #define UM_OFF 0
  18. #define UM_AUTOMATIC 1
  19. #define UM_MANUAL 2
  20. //
  21. // Prefix constants for value names
  22. //
  23. #define NUM_PREFIX 3
  24. #define PREFIX_UNKNOWN 0
  25. #define PREFIX_DELETE 1
  26. #define PREFIX_SOFT 2
  27. #define PREFIX_DELVALS 3
  28. //
  29. // Max size of a value's data
  30. //
  31. #define MAX_VALUE_DATA 4096
  32. //
  33. // Default group size
  34. //
  35. #define DEFAULT_GROUP_SIZE 8192
  36. //
  37. // Registry value names
  38. //
  39. TCHAR g_szUpdateModeValue[] = TEXT("UpdateMode");
  40. TCHAR g_szNetPathValue[] = TEXT("NetworkPath");
  41. TCHAR g_szLogonKey[] = WINLOGON_KEY;
  42. CHAR g_szPolicyHandler[] = "PolicyHandler"; // This needs to be ANSI
  43. TCHAR g_szTmpKeyName[] = TEXT("AdminConfigData");
  44. TCHAR g_szPrefixDel[] = TEXT("**del.");
  45. TCHAR g_szPrefixSoft[] = TEXT("**soft.");
  46. TCHAR g_szPrefixDelvals[] = TEXT("**delvals.");
  47. //
  48. // Function proto-types
  49. //
  50. HKEY OpenUserKey(HKEY hkeyRoot, LPCTSTR pszName, BOOL * pfFoundSpecific);
  51. UINT MergeRegistryData(HKEY hkeySrc, HKEY hkeyDst, LPTSTR pszKeyNameBuffer,
  52. UINT cbKeyNameBuffer);
  53. UINT CopyKeyValues(HKEY hkeySrc,HKEY hkeyDst);
  54. BOOL HasSpecialPrefix(LPTSTR szValueName, DWORD * pdwPrefix,
  55. LPTSTR szStrippedValueName);
  56. BOOL GetGroupProcessingOrder(HKEY hkeyHiveRoot,LPTSTR * pGroupBuffer, DWORD * pdwGroupSize);
  57. BOOL FindGroupInList(LPTSTR pszGroupName, LPTSTR pszGroupList);
  58. LPTSTR GetUserGroups (LPCTSTR lpServerName, LPCTSTR lpUserName, HANDLE hToken, DWORD * puEntriesRead);
  59. //*************************************************************
  60. //
  61. // ApplySystemPolicy()
  62. //
  63. // Purpose: Entry point for Windows NT4 System Policy.
  64. //
  65. // Parameters: dwFlags - Flags
  66. // hToken - User's token
  67. // hKeyCurrentUser - Registry to the root of the user's hive
  68. // lpUserName - User's name
  69. // lpPolicyPath - Path to the policy file (ntconfig.pol). Can be NULL.
  70. // lpServerName - Domain controller name used for group
  71. // membership look up. Can be NULL.
  72. //
  73. // Return: TRUE if successful
  74. // FALSE if an error occurs
  75. // Comments:
  76. //
  77. // History: Date Author Comment
  78. // 05/30/95 ericflo Created
  79. // 10/12/98 ericflo Update for NT5
  80. //
  81. //*************************************************************
  82. BOOL WINAPI ApplySystemPolicy (DWORD dwFlags, HANDLE hToken, HKEY hKeyCurrentUser,
  83. LPCTSTR lpUserName, LPCTSTR lpPolicyPath,
  84. LPCTSTR lpServerName)
  85. {
  86. LONG lResult;
  87. BOOL bResult = FALSE;
  88. BOOL fFoundUser=FALSE;
  89. HKEY hkeyMain=NULL, hkeyRoot=NULL, hkeyUser, hkeyLogon;
  90. DWORD dwUpdateMode=UM_AUTOMATIC;
  91. DWORD dwData, dwSize;
  92. TCHAR szFilePath[MAX_PATH];
  93. TCHAR szLocalPath[MAX_PATH];
  94. TCHAR szTempDir[MAX_PATH];
  95. TCHAR szTempKey[100];
  96. CHAR szHandler[MAX_PATH+50]; // This needs to be ANSI
  97. TCHAR szComputerName[MAX_PATH];
  98. TCHAR szBuffer[MAX_PATH+1];
  99. WIN32_FILE_ATTRIBUTE_DATA fad;
  100. LPTSTR lpEnd;
  101. HANDLE hOldToken;
  102. //
  103. // Verbose output
  104. //
  105. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Entering")));
  106. //
  107. // Initialize szFilePath
  108. //
  109. szFilePath[0] = TEXT('\0');
  110. //
  111. // Check the registry to see if update is specified and get update path
  112. //
  113. lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
  114. REGSTR_PATH_UPDATE,
  115. 0,
  116. KEY_READ,
  117. &hkeyMain);
  118. if (lResult == ERROR_SUCCESS) {
  119. //
  120. // Look for the update mode.
  121. //
  122. dwSize=sizeof(dwUpdateMode);
  123. if (RegQueryValueEx(hkeyMain,g_szUpdateModeValue,NULL,NULL,
  124. (LPBYTE) &dwUpdateMode,&dwSize) != ERROR_SUCCESS) {
  125. dwUpdateMode = UM_OFF;
  126. }
  127. //
  128. // if manual update is specified, also get the path to update from
  129. // (UNC path or path with drive letter)
  130. //
  131. if (dwUpdateMode==UM_MANUAL) {
  132. dwSize=sizeof(szTempDir);
  133. lResult = RegQueryValueEx(hkeyMain, g_szNetPathValue, NULL, NULL,
  134. (LPBYTE) szTempDir, &dwSize);
  135. if (lResult != ERROR_SUCCESS) {
  136. TCHAR szErr[MAX_PATH];
  137. RegCloseKey(hkeyMain);
  138. ReportError(hToken, PI_NOUI, 1, EVENT_MISSINGPOLICYFILEENTRY, GetErrString(lResult, szErr));
  139. return FALSE;
  140. }
  141. ExpandEnvironmentStrings (szTempDir, szFilePath, MAX_PATH);
  142. }
  143. RegCloseKey(hkeyMain);
  144. }
  145. //
  146. // If this machine has policy turned off, then we can exit now.
  147. //
  148. if (dwUpdateMode == UM_OFF) {
  149. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Policy is turned off on this machine.")));
  150. return TRUE;
  151. }
  152. //
  153. // If we are running in automatic mode, use the supplied
  154. // policy file.
  155. //
  156. if (dwUpdateMode == UM_AUTOMATIC) {
  157. if (lpPolicyPath && *lpPolicyPath) {
  158. lstrcpy (szFilePath, lpPolicyPath);
  159. }
  160. }
  161. //
  162. // If we don't have a policy file, then we can exit now.
  163. //
  164. if (szFilePath[0] == TEXT('\0')) {
  165. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: No Policy file. Leaving.")));
  166. return TRUE;
  167. }
  168. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: PolicyPath is: <%s>."), szFilePath));
  169. //
  170. // Impersonate the user
  171. //
  172. if (!ImpersonateUser(hToken, &hOldToken)) {
  173. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to impersonate user")));
  174. return FALSE;
  175. }
  176. //
  177. // Test if the policy file exists
  178. //
  179. if (!GetFileAttributesEx (szFilePath, GetFileExInfoStandard, &fad)) {
  180. lResult = GetLastError();
  181. if (!RevertToUser(&hOldToken)) {
  182. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
  183. }
  184. if ( (lResult == ERROR_FILE_NOT_FOUND) ||
  185. (lResult == ERROR_PATH_NOT_FOUND) ) {
  186. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: No policy file.")));
  187. return TRUE;
  188. } else {
  189. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Failed to query for policy file with error %d."), lResult));
  190. return FALSE;
  191. }
  192. }
  193. //
  194. // Create a temporary file name
  195. //
  196. dwSize = ARRAYSIZE(szBuffer);
  197. if (!GetUserProfileDirectory(hToken, szBuffer, &dwSize)) {
  198. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to query user profile directory with error %d."), GetLastError()));
  199. if (!RevertToUser(&hOldToken)) {
  200. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
  201. }
  202. return FALSE;
  203. }
  204. if (!GetTempFileName (szBuffer, TEXT("prf"), 0, szLocalPath)) {
  205. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to create temporary filename with error %d."), GetLastError()));
  206. if (!RevertToUser(&hOldToken)) {
  207. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
  208. }
  209. return FALSE;
  210. }
  211. //
  212. // Copy the policy hive
  213. //
  214. if (!CopyFile(szFilePath, szLocalPath, FALSE)) {
  215. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to copy policy file with error %d."), GetLastError()));
  216. if (!RevertToUser(&hOldToken)) {
  217. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
  218. }
  219. goto Exit;
  220. }
  221. //
  222. // Revert to being 'ourself'
  223. //
  224. if (!RevertToUser(&hOldToken)) {
  225. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
  226. }
  227. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Local PolicyPath is: <%s>."), szLocalPath));
  228. //
  229. // Query for the computer name
  230. //
  231. dwSize = ARRAYSIZE(szComputerName);
  232. if (!GetComputerName(szComputerName, &dwSize)) {
  233. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: GetComputerName failed.")));
  234. goto Exit;
  235. }
  236. //
  237. // Check to see if an installable policy handler has been added. If
  238. // so, call it and let it do the work.
  239. //
  240. lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  241. g_szLogonKey,
  242. 0,
  243. KEY_READ,
  244. &hkeyLogon);
  245. if (lResult == ERROR_SUCCESS) {
  246. HANDLE hDLL = NULL;
  247. BOOL fRet;
  248. PFNPROCESSPOLICIES pfn;
  249. dwSize = ARRAYSIZE(szHandler);
  250. lResult = RegQueryValueExA(hkeyLogon,
  251. g_szPolicyHandler,
  252. NULL, NULL,
  253. (LPBYTE) szHandler,
  254. &dwSize);
  255. RegCloseKey(hkeyLogon);
  256. if (lResult == ERROR_SUCCESS) {
  257. LPSTR lpEntryPoint = szHandler;
  258. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Machine has a custom Policy Handler of: %S."), szHandler));
  259. //
  260. // Search for the ,
  261. //
  262. while (*lpEntryPoint && *lpEntryPoint != TEXT(',')) {
  263. lpEntryPoint++;
  264. }
  265. //
  266. // Check if we found the ,
  267. //
  268. if (*lpEntryPoint) {
  269. *lpEntryPoint = TEXT('\0');
  270. lpEntryPoint++;
  271. hDLL = LoadLibraryA(szHandler);
  272. if (hDLL) {
  273. pfn = (PFNPROCESSPOLICIES) GetProcAddress(hDLL, lpEntryPoint);
  274. if (pfn != NULL) {
  275. //
  276. // Call the function.
  277. // Note that the parameters are UNICODE.
  278. //
  279. fRet = (*pfn) (NULL,
  280. szLocalPath,
  281. lpUserName,
  282. szComputerName,
  283. 0);
  284. //
  285. // if callout policy downloader returns FALSE, then we don't
  286. // do any processing on our own. If it returns TRUE then we
  287. // go ahead and process policies normally, in addition to whatever
  288. // he may have done.
  289. //
  290. if (!fRet) {
  291. FreeLibrary(hDLL);
  292. bResult = TRUE;
  293. goto Exit;
  294. }
  295. } else {
  296. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to find entry point %S in policy dll. Error %d."),
  297. lpEntryPoint, GetLastError()));
  298. }
  299. FreeLibrary(hDLL);
  300. } else {
  301. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to load %S with error %d."),
  302. szHandler, GetLastError()));
  303. }
  304. }
  305. }
  306. }
  307. //
  308. // Load the policy hive into registry
  309. //
  310. wsprintf (szTempKey, TEXT("%s (%d)"), g_szTmpKeyName, GetTickCount());
  311. lResult = MyRegLoadKey(HKEY_USERS, szTempKey, szLocalPath);
  312. if (lResult != ERROR_SUCCESS) {
  313. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to load policy hive. Error = %d"), lResult));
  314. goto Exit;
  315. }
  316. //
  317. // Open the policy hive.
  318. //
  319. lResult = RegOpenKeyEx (HKEY_USERS,
  320. szTempKey,
  321. 0,
  322. KEY_READ,
  323. &hkeyMain);
  324. if (lResult != ERROR_SUCCESS) {
  325. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to open policy hive. Error = %d"), lResult));
  326. MyRegUnLoadKey(HKEY_USERS, szTempKey);
  327. goto Exit;
  328. }
  329. //
  330. // For user and machine policies, see if there is an appropriate entry
  331. // in policy file (either a key with user/computer name,
  332. // or a default user or workstation entry). If there is, then merge
  333. // information under that key into registry. (If there isn't, it's
  334. // not an error-- just nothing to do.)
  335. //
  336. if (dwFlags & SP_FLAG_APPLY_USER_POLICY) {
  337. //
  338. // Merge user-specific policies if user name was specified
  339. //
  340. if (RegOpenKeyEx(hkeyMain,
  341. REGSTR_KEY_POL_USERS,
  342. 0,
  343. KEY_READ,
  344. &hkeyRoot) == ERROR_SUCCESS) {
  345. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Looking for user specific policy.")));
  346. hkeyUser = OpenUserKey(hkeyRoot, lpUserName, &fFoundUser);
  347. if (hkeyUser) {
  348. MergeRegistryData(hkeyUser,hKeyCurrentUser,szBuffer, ARRAYSIZE(szBuffer));
  349. RegCloseKey(hkeyUser);
  350. }
  351. RegCloseKey(hkeyRoot);
  352. }
  353. //
  354. // Merge group specific policies if user name specified, and we
  355. // *didn't* find a specific user entry above
  356. //
  357. if (!fFoundUser && lpServerName && *lpServerName) {
  358. HKEY hkeyGroups, hkeyGroup;
  359. LPTSTR GroupBuffer, ApiBuf;
  360. DWORD dwGroupSize = DEFAULT_GROUP_SIZE;
  361. DWORD uEntriesRead;
  362. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Processing group(s) policy.")));
  363. GroupBuffer = GlobalAlloc(GPTR, DEFAULT_GROUP_SIZE * sizeof(TCHAR));
  364. if (GroupBuffer) {
  365. //
  366. // if there is a group processing order specified in policy hive,
  367. // then process groups
  368. //
  369. if (RegOpenKeyEx(hkeyMain,
  370. REGSTR_KEY_POL_USERGROUPS,
  371. 0,
  372. KEY_READ,
  373. &hkeyGroups) == ERROR_SUCCESS) {
  374. if (GetGroupProcessingOrder(hkeyMain, &GroupBuffer, &dwGroupSize)) {
  375. //
  376. // Enumerate the groups that this user belongs to
  377. //
  378. ApiBuf = GetUserGroups (lpServerName, lpUserName, hToken, &uEntriesRead);
  379. if (ApiBuf) {
  380. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: User belongs to %d groups."), uEntriesRead));
  381. if (uEntriesRead) {
  382. //
  383. // Walk through the list of groups (ordered lowest priority
  384. // to highest priority). for each group, if the user belongs
  385. // to it then download policies for that group.
  386. //
  387. LPTSTR pszGroup = GroupBuffer;
  388. TCHAR szKeyNameBuffer[MAX_PATH+1];
  389. while (*pszGroup) {
  390. //
  391. // Does user belong to this group?
  392. //
  393. if (FindGroupInList(pszGroup, ApiBuf)) {
  394. //
  395. // Open the key in the hive for this group
  396. //
  397. if (RegOpenKeyEx (hkeyGroups,
  398. pszGroup,
  399. 0,
  400. KEY_READ,
  401. &hkeyGroup) == ERROR_SUCCESS) {
  402. //
  403. // Merge group policies
  404. //
  405. MergeRegistryData(hkeyGroup,
  406. hKeyCurrentUser,
  407. szKeyNameBuffer,
  408. ARRAYSIZE(szKeyNameBuffer));
  409. RegCloseKey (hkeyGroup);
  410. }
  411. }
  412. pszGroup += lstrlen(pszGroup) + 1;
  413. }
  414. }
  415. GlobalFree (ApiBuf);
  416. } else {
  417. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to get user's groups.")));
  418. }
  419. } else {
  420. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to get group processing order.")));
  421. }
  422. RegCloseKey(hkeyGroups);
  423. } else {
  424. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to allocate memory for group policy. Error = %d"), GetLastError()));
  425. }
  426. GlobalFree (GroupBuffer);
  427. } else {
  428. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to allocate memory for group policy. Error = %d"), GetLastError()));
  429. }
  430. }
  431. }
  432. if (dwFlags & SP_FLAG_APPLY_MACHINE_POLICY) {
  433. //
  434. // Merge machine-specific policies if computer name was specified
  435. //
  436. if (RegOpenKeyEx(hkeyMain,
  437. REGSTR_KEY_POL_COMPUTERS,
  438. 0,
  439. KEY_READ,
  440. &hkeyRoot) == ERROR_SUCCESS) {
  441. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Looking for machine specific policy.")));
  442. hkeyUser = OpenUserKey(hkeyRoot, szComputerName, &fFoundUser);
  443. if (hkeyUser) {
  444. MergeRegistryData(hkeyUser, HKEY_LOCAL_MACHINE, szBuffer, ARRAYSIZE(szBuffer));
  445. RegCloseKey(hkeyUser);
  446. }
  447. RegCloseKey(hkeyRoot);
  448. }
  449. }
  450. //
  451. // Close the policy key
  452. //
  453. RegCloseKey(hkeyMain);
  454. //
  455. // Unload the policy hive.
  456. //
  457. if (!MyRegUnLoadKey(HKEY_USERS, szTempKey)) {
  458. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to unload policy hive. Error = %d"), lResult));
  459. goto Exit;
  460. }
  461. //
  462. // Success
  463. //
  464. bResult = TRUE;
  465. Exit:
  466. //
  467. // Delete the policy files
  468. //
  469. if (!DeleteFile (szLocalPath)) {
  470. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to delete policy file <%s>. Error %d"),
  471. szLocalPath, GetLastError()));
  472. }
  473. lstrcat (szLocalPath, c_szLog);
  474. if (!DeleteFile (szLocalPath)) {
  475. DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to delete policy log file <%s>. Error %d"),
  476. szLocalPath, GetLastError()));
  477. }
  478. DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Leaving with %d"), bResult));
  479. return bResult;
  480. }
  481. //*************************************************************
  482. //
  483. // OpenUserKey()
  484. //
  485. // Purpose: Attempts to open the user specific key, or the
  486. // .default key.
  487. //
  488. // Parameters: hkeyRoot - Root key
  489. // pszName - User name
  490. // fFoundSpecific - Found the requested key
  491. //
  492. // Return: hkey if successful
  493. // NULL if not
  494. //
  495. // Comments:
  496. //
  497. // History: Date Author Comment
  498. // 9/13/95 ericflo Ported
  499. //
  500. //*************************************************************
  501. HKEY OpenUserKey(HKEY hkeyRoot,LPCTSTR pszName, BOOL *pfFoundSpecific)
  502. {
  503. HKEY hkeyTest;
  504. *pfFoundSpecific = FALSE;
  505. //
  506. // See if there is a subkey under the specified key with the given
  507. // user name
  508. //
  509. if ((RegOpenKeyEx(hkeyRoot,
  510. pszName,
  511. 0,
  512. KEY_READ,
  513. &hkeyTest)) == ERROR_SUCCESS) {
  514. *pfFoundSpecific = TRUE;
  515. DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: Found specific entry for %s ignoring .Default."), pszName));
  516. return hkeyTest;
  517. }
  518. //
  519. // If not, see if there is a default key
  520. //
  521. if ((RegOpenKeyEx(hkeyRoot,
  522. REGSTR_KEY_POL_DEFAULT,
  523. 0,
  524. KEY_READ,
  525. &hkeyTest)) == ERROR_SUCCESS) {
  526. DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: No entry for %s, using .Default instead."), pszName));
  527. return hkeyTest;
  528. }
  529. //
  530. // No entry for this name in policy file
  531. //
  532. DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: No user/machine specific policy and no .Default policy.")));
  533. return NULL;
  534. }
  535. //*************************************************************
  536. //
  537. // MergeRegistryData()
  538. //
  539. // Purpose: Merges hkeySrc and subkeys into hkeyDst.
  540. //
  541. // Parameters: hkeySrc - Source
  542. // hkeyDst - Destination
  543. // pszKeyNameBuffer - Key name
  544. // cbKeyNameBuffer - Size of key name buffer
  545. //
  546. //
  547. // Return: ERROR_SUCCESS if successful
  548. // otherwise an error value
  549. //
  550. // Comments:
  551. //
  552. // History: Date Author Comment
  553. // 9/13/95 ericflo Ported
  554. //
  555. //*************************************************************
  556. UINT MergeRegistryData(HKEY hkeySrc, HKEY hkeyDst, LPTSTR pszKeyNameBuffer,
  557. UINT cbKeyNameBuffer)
  558. {
  559. UINT nIndex = 0,uRet=ERROR_SUCCESS;
  560. //
  561. // Look for any subkeys of the source key
  562. //
  563. while ((uRet=RegEnumKey(hkeySrc,nIndex,pszKeyNameBuffer,
  564. cbKeyNameBuffer)) == ERROR_SUCCESS) {
  565. HKEY hkeySubkeySrc,hkeySubkeyDst;
  566. //
  567. // Create the subkey under the destination key
  568. //
  569. if ((uRet=RegCreateKey(hkeyDst,pszKeyNameBuffer,
  570. &hkeySubkeyDst)) != ERROR_SUCCESS)
  571. return uRet;
  572. if ((uRet=RegOpenKey(hkeySrc, pszKeyNameBuffer,
  573. &hkeySubkeySrc)) != ERROR_SUCCESS) {
  574. RegCloseKey(hkeySubkeyDst);
  575. return uRet;
  576. }
  577. //
  578. // Copy the key values from source subkey to destination subkey
  579. //
  580. uRet=CopyKeyValues(hkeySubkeySrc,hkeySubkeyDst);
  581. if (uRet == ERROR_SUCCESS) {
  582. //
  583. // Merge recursively on subkeys of these keys, if any
  584. //
  585. uRet = MergeRegistryData(hkeySubkeySrc,hkeySubkeyDst,pszKeyNameBuffer,
  586. cbKeyNameBuffer);
  587. }
  588. RegCloseKey(hkeySubkeySrc);
  589. RegCloseKey(hkeySubkeyDst);
  590. if (uRet != ERROR_SUCCESS) {
  591. return uRet;
  592. }
  593. nIndex ++;
  594. }
  595. if (uRet == ERROR_NO_MORE_ITEMS) {
  596. uRet=ERROR_SUCCESS;
  597. }
  598. return uRet;
  599. }
  600. //*************************************************************
  601. //
  602. // CopyKeyValues()
  603. //
  604. // Purpose: Copies all key values from hkeySrc to hkeyDst
  605. //
  606. // Parameters: hkeySrc - Source
  607. // hkeyDst - destination
  608. //
  609. // Return: Error code
  610. //
  611. // Comments:
  612. //
  613. // History: Date Author Comment
  614. // 9/14/95 ericflo Ported
  615. //
  616. //*************************************************************
  617. UINT CopyKeyValues(HKEY hkeySrc, HKEY hkeyDst)
  618. {
  619. DWORD dwSubkeyCount,dwMaxSubkeyNameLen,dwMaxClassNameLen,dwValueCount,
  620. dwMaxValueNameLen,dwMaxValueDataLen,dwDescriptorLen,dwClassNameLen;
  621. FILETIME ftLastWriteTime;
  622. UINT uRet=ERROR_SUCCESS;
  623. TCHAR szClassName[255];
  624. //
  625. // Do RegQueryInfoKey to find out if there are values for the source key,
  626. // and the size of value name and value data buffes to alloc
  627. //
  628. dwClassNameLen = ARRAYSIZE(szClassName);
  629. uRet=RegQueryInfoKey(hkeySrc,szClassName,&dwClassNameLen,NULL,&dwSubkeyCount,
  630. &dwMaxSubkeyNameLen,&dwMaxClassNameLen,&dwValueCount,&dwMaxValueNameLen,
  631. &dwMaxValueDataLen,&dwDescriptorLen,&ftLastWriteTime);
  632. if (uRet != ERROR_SUCCESS) {
  633. return uRet;
  634. }
  635. //
  636. // If there are values...
  637. //
  638. if (dwValueCount) {
  639. TCHAR ValueName[MAX_PATH];
  640. LPBYTE ValueData;
  641. DWORD dwType,dwValueNameSize,dwValueDataSize;
  642. UINT nIndex = 0;
  643. ValueData = GlobalAlloc (GPTR, MAX_VALUE_DATA);
  644. if (!ValueData) {
  645. return GetLastError();
  646. }
  647. //
  648. // the "**delvals" control code is special, must be processed
  649. // first; look for it now and if it exists delete all existing
  650. // values under this key in destination registry
  651. //
  652. if (RegQueryValueEx(hkeySrc,g_szPrefixDelvals,NULL,NULL,NULL,NULL) == ERROR_SUCCESS) {
  653. DeleteAllValues(hkeyDst);
  654. }
  655. //
  656. // Enumerate the values of the source key, and create each value
  657. // under the destination key
  658. //
  659. do {
  660. dwValueNameSize = MAX_PATH;
  661. dwValueDataSize = MAX_VALUE_DATA;
  662. if ((uRet=RegEnumValue(hkeySrc,nIndex, ValueName,
  663. &dwValueNameSize,NULL,&dwType, ValueData,
  664. &dwValueDataSize)) == ERROR_SUCCESS) {
  665. DWORD dwPrefix;
  666. //
  667. // Look for special prefixes which indicate we should treat
  668. // these values specially
  669. //
  670. if (HasSpecialPrefix(ValueName, &dwPrefix, ValueName)) {
  671. //
  672. // ValueName now contains real value name stripped
  673. // of prefix, filled in above by HasSpecialPrefix().
  674. // Adjust value name size, the value name will shorten
  675. // because the prefix has been removed.
  676. //
  677. dwValueNameSize = lstrlen (ValueName) + 1;
  678. switch (dwPrefix) {
  679. case PREFIX_DELETE:
  680. //
  681. // Delete this value in destination
  682. //
  683. RegDeleteValue(hkeyDst, ValueName);
  684. uRet = ERROR_SUCCESS;
  685. DebugMsg((DM_VERBOSE, TEXT("Deleted value: %s"), ValueName));
  686. break;
  687. case PREFIX_SOFT:
  688. //
  689. // "soft" value, only set this if it doesn't already
  690. // exist in destination
  691. //
  692. {
  693. TCHAR TmpValueData[MAX_PATH+1];
  694. DWORD dwSize=sizeof(TmpValueData);
  695. if (RegQueryValueEx(hkeyDst, ValueName,
  696. NULL,NULL,(LPBYTE) TmpValueData,
  697. &dwSize) != ERROR_SUCCESS) {
  698. //
  699. // The value doesn't exist, set the value.
  700. //
  701. uRet=RegSetValueEx(hkeyDst, ValueName, 0,
  702. dwType, ValueData,
  703. dwValueDataSize);
  704. } else {
  705. //
  706. // Value already exists, nothing to do
  707. //
  708. uRet = ERROR_SUCCESS;
  709. }
  710. }
  711. break;
  712. case PREFIX_DELVALS:
  713. // processed early on above, fall through and ignore
  714. default:
  715. //
  716. // Got some prefix that we don't understand... presumably,
  717. // from a future version. Ignore this value, rather than
  718. // propagating it into the registry, prefix and all.
  719. // This will give us less backward compatibility headaches
  720. // down the road.
  721. //
  722. uRet = ERROR_SUCCESS; // nothing to do
  723. break;
  724. }
  725. } else {
  726. //
  727. // Copy the value normally to destination key
  728. //
  729. uRet=RegSetValueEx(hkeyDst,ValueName,0,
  730. dwType,ValueData,dwValueDataSize);
  731. #if DBG
  732. if (uRet == ERROR_SUCCESS) {
  733. switch (dwType) {
  734. case REG_SZ:
  735. case REG_EXPAND_SZ:
  736. DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s => %s [OK]"),
  737. ValueName, (LPTSTR)ValueData));
  738. break;
  739. case REG_DWORD:
  740. DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s => %d [OK]"),
  741. ValueName, (DWORD)*ValueData));
  742. break;
  743. default:
  744. DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s was set successfully"),
  745. ValueName));
  746. }
  747. } else {
  748. DebugMsg((DM_WARNING, TEXT("CopyKeyValues: Failed to set %s with error %d."),
  749. ValueName, uRet));
  750. }
  751. #endif
  752. }
  753. }
  754. nIndex++;
  755. } while (uRet == ERROR_SUCCESS);
  756. if (uRet == ERROR_NO_MORE_ITEMS) {
  757. uRet=ERROR_SUCCESS;
  758. }
  759. GlobalFree (ValueData);
  760. }
  761. return uRet;
  762. }
  763. //*************************************************************
  764. //
  765. // HasSpecialPrefix()
  766. //
  767. // Purpose: Checks to see if szValueName has a special prefix (a la
  768. // "**<something>." Returns TRUE if it does, FALSE otherwise.
  769. // if TRUE, returns the numerical index of the prefix in *pdwPrefix,
  770. // and copies the rest of value name (after the ".") into
  771. // szStrippedValueName. Buffer for szStrippedValueName must be at
  772. // least as large as szValueName. It is safe to pass the same
  773. // buffer to szValueName and szStrippedValueName and have the name
  774. // modified in place.
  775. //
  776. // Parameters: szValueName - Value Name
  777. // pdwPrefix - Index of the prefix
  778. // szStrippedValueName - Value name without the **
  779. //
  780. //
  781. // Return: TRUE if value name has a prefix
  782. // FALSE if it does not
  783. //
  784. // Comments:
  785. //
  786. // History: Date Author Comment
  787. // 9/14/95 ericflo Ported
  788. //
  789. //*************************************************************
  790. typedef struct tagPREFIXMAP {
  791. const LPTSTR pszPrefix;
  792. DWORD dwPrefixIndex;
  793. } PREFIXMAP;
  794. BOOL HasSpecialPrefix(LPTSTR szValueName, DWORD * pdwPrefix,
  795. LPTSTR szStrippedValueName)
  796. {
  797. PREFIXMAP PrefixMap[] = {
  798. {g_szPrefixDel, PREFIX_DELETE},
  799. {g_szPrefixSoft, PREFIX_SOFT},
  800. {g_szPrefixDelvals, PREFIX_DELVALS}
  801. };
  802. UINT nCount,nLen;
  803. //
  804. // Does the value name begin with "**"?
  805. //
  806. if (!szValueName || (lstrlen(szValueName) < 2) ||
  807. szValueName[0] != TEXT('*') || szValueName[1] != TEXT('*'))
  808. return FALSE; // not a special prefix
  809. //
  810. // Try all the prefixes we know to try to find a match
  811. //
  812. for (nCount = 0; nCount < ARRAYSIZE(PrefixMap); nCount++) {
  813. nLen = lstrlen (PrefixMap[nCount].pszPrefix);
  814. if (CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
  815. szValueName, nLen,
  816. PrefixMap[nCount].pszPrefix, nLen) == 2) {
  817. *pdwPrefix = PrefixMap[nCount].dwPrefixIndex;
  818. //
  819. // make a copy of the value name, sans prefix, into
  820. // the stripped value name buffer
  821. //
  822. lstrcpy (szStrippedValueName,szValueName + nLen);
  823. return TRUE;
  824. }
  825. }
  826. //
  827. // this is a prefix, but not one we know.
  828. //
  829. *pdwPrefix = PREFIX_UNKNOWN;
  830. lstrcpy (szStrippedValueName,szValueName);
  831. return TRUE;
  832. }
  833. //*************************************************************
  834. //
  835. // GetGroupProcessingOrder()
  836. //
  837. // Purpose: Gets the list of groups in order
  838. //
  839. // Parameters: hkeyHiveRoot - Registry key
  840. // GroupBuffer - Pointer to group buffer
  841. // pdwBufferSize - Buffer size
  842. //
  843. // Return: Number of entries if successful
  844. // 0 if an error occurs
  845. //
  846. // Comments:
  847. //
  848. // History: Date Author Comment
  849. // 9/14/95 ericflo Ported
  850. //
  851. //*************************************************************
  852. BOOL GetGroupProcessingOrder(HKEY hkeyHiveRoot, LPTSTR * pGroupBuffer,
  853. DWORD * pdwGroupSize)
  854. {
  855. DWORD cEntries,cMaxValueName,cMaxData;
  856. HKEY hkeyGroupData;
  857. UINT uRet;
  858. LPTSTR GroupBuffer = *pGroupBuffer;
  859. LPTSTR lpTemp;
  860. DWORD dwGroupSize = *pdwGroupSize;
  861. TCHAR szValueName[10], szGroupName[48+1]; // netware groups can be up to 48 chars
  862. DWORD dwUsed = 0, dwSize; // amount of buffer used
  863. UINT nLen,nRead=0;
  864. //
  865. // Open the group data key
  866. //
  867. uRet = RegOpenKeyEx(hkeyHiveRoot,
  868. REGSTR_KEY_POL_USERGROUPDATA,
  869. 0,
  870. KEY_READ,
  871. &hkeyGroupData);
  872. if (uRet != ERROR_SUCCESS) {
  873. //
  874. // Group data key doesn't exist (most likely), no downloading to do
  875. //
  876. return FALSE;
  877. }
  878. //
  879. // Find out the number of values in group data key
  880. //
  881. if ((RegQueryInfoKey (hkeyGroupData,NULL,NULL,NULL,NULL,NULL,
  882. NULL,&cEntries,&cMaxValueName,&cMaxData,NULL,NULL ) != ERROR_SUCCESS) ||
  883. !cEntries) {
  884. RegCloseKey(hkeyGroupData);
  885. return FALSE;
  886. }
  887. //
  888. // The values are stored as "1"="<group name>", "2"="<group name>", etc.
  889. // where 1 is most important. we will pack the names into a buffer lowest
  890. // priority to highest. So if we have n values, start with value name "<n>"
  891. // and work down to "1".
  892. //
  893. while (cEntries) {
  894. wsprintf(szValueName, TEXT("%lu"), cEntries);
  895. dwSize = ARRAYSIZE(szGroupName);
  896. if (RegQueryValueEx(hkeyGroupData,szValueName,NULL,NULL,
  897. (LPBYTE) szGroupName,&dwSize) == ERROR_SUCCESS) {
  898. nLen = lstrlen(szGroupName) + 1;
  899. //
  900. // Resize buffer if neccessary (add 1 for extra terminating null)
  901. //
  902. if (nLen + dwUsed + 1 > dwGroupSize) {
  903. //
  904. // add a little extra so we don't realloc on every item
  905. //
  906. dwGroupSize = dwGroupSize + nLen + 256;
  907. lpTemp = GlobalReAlloc(GroupBuffer,
  908. (dwGroupSize * sizeof(TCHAR)),
  909. GMEM_MOVEABLE);
  910. if (!lpTemp) {
  911. RegCloseKey(hkeyGroupData);
  912. return FALSE;
  913. }
  914. GroupBuffer = lpTemp;
  915. }
  916. lstrcpy(GroupBuffer + dwUsed, szGroupName);
  917. dwUsed += nLen;
  918. nRead++;
  919. }
  920. cEntries --;
  921. }
  922. //
  923. // Doubly null-terminate buffer
  924. //
  925. *(GroupBuffer + dwUsed) = TEXT('\0');
  926. RegCloseKey(hkeyGroupData);
  927. *pGroupBuffer = GroupBuffer;
  928. *pdwGroupSize = dwGroupSize;
  929. return (nRead > 0);
  930. }
  931. //*************************************************************
  932. //
  933. // FindGroupInList()
  934. //
  935. // Purpose: Determines if the requested group
  936. // is in the list of groups
  937. //
  938. // Parameters: pszGroupName - Group looking for
  939. // pszGroupList - List of groups null seperated
  940. //
  941. // Return: TRUE if found
  942. // FALSE if not
  943. //
  944. // Comments:
  945. //
  946. // History: Date Author Comment
  947. // 9/15/95 ericflo Ported
  948. //
  949. //*************************************************************
  950. BOOL FindGroupInList(LPTSTR pszGroupName, LPTSTR pszGroupList)
  951. {
  952. while (*pszGroupList) {
  953. if (!lstrcmpi(pszGroupList,pszGroupName)) {
  954. DebugMsg((DM_VERBOSE, TEXT("FindGroupInList: User is a member of the %s group."), pszGroupName));
  955. return TRUE;
  956. }
  957. pszGroupList += lstrlen(pszGroupList) + 1;
  958. }
  959. DebugMsg((DM_VERBOSE, TEXT("FindGroupInList: User is NOT a member of the %s group."), pszGroupName));
  960. return FALSE;
  961. }
  962. //*************************************************************
  963. //
  964. // GetUserGroups()
  965. //
  966. // Purpose: Retrieves a list of groups this user belongs to
  967. //
  968. // Parameters: lpServerName - Server name
  969. // lpUserName - User name
  970. // hToken - User's token
  971. // puEntriesRead - Number of groups
  972. //
  973. // Return: Pointer to list if successful
  974. // Null if not
  975. //
  976. // Comments:
  977. //
  978. // History: Date Author Comment
  979. // 9/15/95 ericflo Created
  980. //
  981. //*************************************************************
  982. LPTSTR GetUserGroups (LPCTSTR lpServerName, LPCTSTR lpUserName,
  983. HANDLE hToken, DWORD * puEntriesRead)
  984. {
  985. UINT nIndex;
  986. NET_API_STATUS status;
  987. LPBYTE lpGroups, lpTemp;
  988. PGROUP_INFO_0 pgi0;
  989. DWORD dwEntriesRead, dwTotalEntries;
  990. DWORD cchSizeNeeded;
  991. LPTSTR lpGroupNames, lpName;
  992. PNETAPI32_API pNetAPI32;
  993. HANDLE hOldToken;
  994. //
  995. // Load netapi32
  996. //
  997. pNetAPI32 = LoadNetAPI32();
  998. if (!pNetAPI32) {
  999. DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to load netapi32 with %d."),
  1000. GetLastError()));
  1001. return NULL;
  1002. }
  1003. //
  1004. // Impersonate the user
  1005. //
  1006. if (!ImpersonateUser(hToken, &hOldToken)) {
  1007. DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to impersonate user")));
  1008. return NULL;
  1009. }
  1010. //
  1011. // Query for the groups
  1012. //
  1013. status = pNetAPI32->pfnNetUserGetGroups (lpServerName, lpUserName,
  1014. 0, &lpGroups, 0xFFFFFFFF, &dwEntriesRead,
  1015. &dwTotalEntries);
  1016. if (status == NERR_Success) {
  1017. //
  1018. // NetUserGetGroups opens a named pipe to the server. To close
  1019. // it, we need to call NetUserGetInfo on the local machine
  1020. //
  1021. if (pNetAPI32->pfnNetUserGetInfo (NULL, lpUserName,
  1022. 0, &lpTemp) == NERR_Success) {
  1023. pNetAPI32->pfnNetApiBufferFree (lpTemp);
  1024. }
  1025. } else {
  1026. DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: NetUserGetGroups failed with %d"), status));
  1027. if (!RevertToUser(&hOldToken)) {
  1028. DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to revert to self")));
  1029. }
  1030. return NULL;
  1031. }
  1032. //
  1033. // Revert to self
  1034. //
  1035. if (!RevertToUser(&hOldToken)) {
  1036. DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to revert to self")));
  1037. }
  1038. //
  1039. // NetUserGetGroups returns names packed in structures with fixed-length
  1040. // fields. Need to copy that into caller's buffer packed with the names
  1041. // packed end-to-end.
  1042. //
  1043. // Count the total buffer size we need, which will be smaller than the
  1044. // API buffer to NetUserGetGroups because we're not using fixed-length
  1045. // fields
  1046. //
  1047. cchSizeNeeded = 1;
  1048. pgi0 = (PGROUP_INFO_0) lpGroups;
  1049. for (nIndex=0; nIndex < dwEntriesRead; nIndex++) {
  1050. cchSizeNeeded += lstrlen(pgi0->grpi0_name) + 1;
  1051. pgi0++;
  1052. }
  1053. *puEntriesRead = dwEntriesRead;
  1054. //
  1055. // Build the list of group names
  1056. //
  1057. lpGroupNames = GlobalAlloc (GPTR, cchSizeNeeded * sizeof (TCHAR));
  1058. if (!lpGroupNames) {
  1059. pNetAPI32->pfnNetApiBufferFree (lpGroups);
  1060. return NULL;
  1061. }
  1062. DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: User is a member of the following global groups:")));
  1063. lpName = lpGroupNames;
  1064. pgi0 = (PGROUP_INFO_0) lpGroups;
  1065. for (nIndex=0; nIndex < dwEntriesRead; nIndex++) {
  1066. DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: %s"), pgi0->grpi0_name));
  1067. lstrcpy (lpName, pgi0->grpi0_name);
  1068. lpName += lstrlen(pgi0->grpi0_name) + 1;
  1069. pgi0++;
  1070. }
  1071. //
  1072. // Free the memory allocated by NetUserGetGroups
  1073. //
  1074. pNetAPI32->pfnNetApiBufferFree (lpGroups);
  1075. return lpGroupNames;
  1076. }