Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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