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.

2065 lines
62 KiB

  1. //*************************************************************
  2. //
  3. // Group Policy Support for registry policies
  4. //
  5. // Microsoft Confidential
  6. // Copyright (c) Microsoft Corporation 1997-1998
  7. // All rights reserved
  8. //
  9. //*************************************************************
  10. #include "gphdr.h"
  11. //*************************************************************
  12. //
  13. // DeleteRegistryValue()
  14. //
  15. // Purpose: Callback from ParseRegistryFile that deletes
  16. // registry policies
  17. //
  18. // Parameters: lpGPOInfo - GPO Information
  19. // lpKeyName - Key name
  20. // lpValueName - Value name
  21. // dwType - Registry data type
  22. // lpData - Registry data
  23. // pwszGPO - Gpo
  24. // pwszSOM - Sdou that the Gpo is linked to
  25. // pHashTable - Hash table for registry keys
  26. //
  27. // Return: TRUE if successful
  28. // FALSE if an error occurs
  29. //
  30. //*************************************************************
  31. BOOL DeleteRegistryValue (LPGPOINFO lpGPOInfo, LPTSTR lpKeyName,
  32. LPTSTR lpValueName, DWORD dwType,
  33. DWORD dwDataLength, LPBYTE lpData,
  34. WCHAR *pwszGPO,
  35. WCHAR *pwszSOM, REGHASHTABLE *pHashTable)
  36. {
  37. DWORD dwDisp;
  38. HKEY hSubKey;
  39. LONG lResult;
  40. INT iStrLen;
  41. TCHAR szPolicies1[] = TEXT("Software\\Policies");
  42. TCHAR szPolicies2[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies");
  43. XLastError xe;
  44. //
  45. // Check if there is a keyname
  46. //
  47. if (!lpKeyName || !(*lpKeyName)) {
  48. return TRUE;
  49. }
  50. //
  51. // Check if the key is in one of the policies keys
  52. //
  53. iStrLen = lstrlen(szPolicies1);
  54. if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szPolicies1,
  55. iStrLen, lpKeyName, iStrLen) != CSTR_EQUAL) {
  56. iStrLen = lstrlen(szPolicies2);
  57. if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE, szPolicies2,
  58. iStrLen, lpKeyName, iStrLen) != CSTR_EQUAL) {
  59. return TRUE;
  60. }
  61. }
  62. //
  63. // Check if the value name starts with **
  64. //
  65. if (lpValueName && (lstrlen(lpValueName) > 1)) {
  66. if ( (*lpValueName == TEXT('*')) && (*(lpValueName+1) == TEXT('*')) ) {
  67. return TRUE;
  68. }
  69. }
  70. //
  71. // We found a value that needs to be deleted
  72. //
  73. if (RegCleanUpValue (lpGPOInfo->hKeyRoot, lpKeyName, lpValueName)) {
  74. DebugMsg((DM_VERBOSE, TEXT("DeleteRegistryValue: Deleted %s\\%s"),
  75. lpKeyName, lpValueName));
  76. } else {
  77. xe = GetLastError();
  78. DebugMsg((DM_WARNING, TEXT("DeleteRegistryValue: Failed to delete %s\\%s"),
  79. lpKeyName, lpValueName));
  80. return FALSE;
  81. }
  82. return TRUE;
  83. }
  84. //*************************************************************
  85. //
  86. // ResetPolicies()
  87. //
  88. // Purpose: Resets the Policies and old Policies key to their
  89. // original state.
  90. //
  91. // Parameters: lpGPOInfo - GPT information
  92. // lpArchive - Name of archive file
  93. //
  94. //
  95. // Return: TRUE if successful
  96. // FALSE if an error occurs
  97. //
  98. //*************************************************************
  99. BOOL ResetPolicies (LPGPOINFO lpGPOInfo, LPTSTR lpArchive)
  100. {
  101. HKEY hKey;
  102. LONG lResult;
  103. DWORD dwDisp, dwValue = 0x91;
  104. XLastError xe;
  105. DebugMsg((DM_VERBOSE, TEXT("ResetPolicies: Entering.")));
  106. //
  107. // Parse the archive file and delete any policies
  108. //
  109. if (!ParseRegistryFile (lpGPOInfo, lpArchive,
  110. DeleteRegistryValue, NULL, NULL, NULL, NULL, FALSE )) {
  111. xe = GetLastError();
  112. DebugMsg((DM_WARNING, TEXT("ResetPolicies: Leaving")));
  113. return FALSE;
  114. }
  115. //
  116. // Recreate the new policies key
  117. //
  118. lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
  119. TEXT("Software\\Policies"),
  120. 0, NULL, REG_OPTION_NON_VOLATILE,
  121. KEY_WRITE, NULL, &hKey, &dwDisp);
  122. if (lResult == ERROR_SUCCESS) {
  123. //
  124. // Re-apply security
  125. //
  126. RegCloseKey (hKey);
  127. if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
  128. lpGPOInfo->hKeyRoot,
  129. TEXT("Software\\Policies"))) {
  130. DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to secure reg key.")));
  131. }
  132. } else {
  133. DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to create reg key with %d."), lResult));
  134. }
  135. //
  136. // Recreate the old policies key
  137. //
  138. lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
  139. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"),
  140. 0, NULL, REG_OPTION_NON_VOLATILE,
  141. KEY_WRITE, NULL, &hKey, &dwDisp);
  142. if (lResult == ERROR_SUCCESS) {
  143. //
  144. // Re-apply security
  145. //
  146. RegCloseKey (hKey);
  147. if (!MakeRegKeySecure((lpGPOInfo->dwFlags & GP_MACHINE) ? NULL : lpGPOInfo->hToken,
  148. lpGPOInfo->hKeyRoot,
  149. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies"))) {
  150. DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to secure reg key.")));
  151. }
  152. } else {
  153. DebugMsg((DM_WARNING, TEXT("ResetPolicies: Failed to create reg key with %d."), lResult));
  154. }
  155. //
  156. // If this is user policy, reset the NoDriveTypeAutoRun default value
  157. //
  158. if (!(lpGPOInfo->dwFlags & GP_MACHINE)) {
  159. if (RegCreateKeyEx (lpGPOInfo->hKeyRoot,
  160. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"),
  161. 0, NULL, REG_OPTION_NON_VOLATILE,
  162. KEY_WRITE, NULL, &hKey, &dwDisp) == ERROR_SUCCESS) {
  163. RegSetValueEx (hKey, TEXT("NoDriveTypeAutoRun"), 0,
  164. REG_DWORD, (LPBYTE) &dwValue, sizeof(dwValue));
  165. RegCloseKey (hKey);
  166. }
  167. }
  168. DebugMsg((DM_VERBOSE, TEXT("ResetPolicies: Leaving.")));
  169. return TRUE;
  170. }
  171. //*************************************************************
  172. //
  173. // ArchiveRegistryValue()
  174. //
  175. // Purpose: Archives a registry value in the specified file
  176. //
  177. // Parameters: hFile - File handle of archive file
  178. // lpKeyName - Key name
  179. // lpValueName - Value name
  180. // dwType - Registry value type
  181. // dwDataLength - Registry value size
  182. // lpData - Registry value
  183. //
  184. // Return: TRUE if successful
  185. // FALSE if an error occurs
  186. //
  187. //*************************************************************
  188. BOOL ArchiveRegistryValue(HANDLE hFile, LPWSTR lpKeyName,
  189. LPWSTR lpValueName, DWORD dwType,
  190. DWORD dwDataLength, LPBYTE lpData)
  191. {
  192. BOOL bResult = FALSE;
  193. DWORD dwBytesWritten;
  194. DWORD dwTemp;
  195. const WCHAR cOpenBracket = L'[';
  196. const WCHAR cCloseBracket = L']';
  197. const WCHAR cSemiColon = L';';
  198. XLastError xe;
  199. //
  200. // Write the entry to the text file.
  201. //
  202. // Format:
  203. //
  204. // [keyname;valuename;type;datalength;data]
  205. //
  206. // open bracket
  207. if (!WriteFile (hFile, &cOpenBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  208. dwBytesWritten != sizeof(WCHAR))
  209. {
  210. xe = GetLastError();
  211. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write open bracket with %d"),
  212. GetLastError()));
  213. goto Exit;
  214. }
  215. // key name
  216. dwTemp = (lstrlen (lpKeyName) + 1) * sizeof (WCHAR);
  217. if (!WriteFile (hFile, lpKeyName, dwTemp, &dwBytesWritten, NULL) ||
  218. dwBytesWritten != dwTemp)
  219. {
  220. xe = GetLastError();
  221. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write key name with %d"),
  222. GetLastError()));
  223. goto Exit;
  224. }
  225. // semicolon
  226. if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  227. dwBytesWritten != sizeof(WCHAR))
  228. {
  229. xe = GetLastError();
  230. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
  231. GetLastError()));
  232. goto Exit;
  233. }
  234. // value name
  235. dwTemp = (lstrlen (lpValueName) + 1) * sizeof (WCHAR);
  236. if (!WriteFile (hFile, lpValueName, dwTemp, &dwBytesWritten, NULL) ||
  237. dwBytesWritten != dwTemp)
  238. {
  239. xe = GetLastError();
  240. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write value name with %d"),
  241. GetLastError()));
  242. goto Exit;
  243. }
  244. // semicolon
  245. if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  246. dwBytesWritten != sizeof(WCHAR))
  247. {
  248. xe = GetLastError();
  249. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
  250. GetLastError()));
  251. goto Exit;
  252. }
  253. // type
  254. if (!WriteFile (hFile, &dwType, sizeof(DWORD), &dwBytesWritten, NULL) ||
  255. dwBytesWritten != sizeof(DWORD))
  256. {
  257. xe = GetLastError();
  258. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write data type with %d"),
  259. GetLastError()));
  260. goto Exit;
  261. }
  262. // semicolon
  263. if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  264. dwBytesWritten != sizeof(WCHAR))
  265. {
  266. xe = GetLastError();
  267. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
  268. GetLastError()));
  269. goto Exit;
  270. }
  271. // data length
  272. if (!WriteFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesWritten, NULL) ||
  273. dwBytesWritten != sizeof(DWORD))
  274. {
  275. xe = GetLastError();
  276. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write data type with %d"),
  277. GetLastError()));
  278. goto Exit;
  279. }
  280. // semicolon
  281. if (!WriteFile (hFile, &cSemiColon, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  282. dwBytesWritten != sizeof(WCHAR))
  283. {
  284. xe = GetLastError();
  285. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write semicolon with %d"),
  286. GetLastError()));
  287. goto Exit;
  288. }
  289. // data
  290. if (!WriteFile (hFile, lpData, dwDataLength, &dwBytesWritten, NULL) ||
  291. dwBytesWritten != dwDataLength)
  292. {
  293. xe = GetLastError();
  294. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write data with %d"),
  295. GetLastError()));
  296. goto Exit;
  297. }
  298. // close bracket
  299. if (!WriteFile (hFile, &cCloseBracket, sizeof(WCHAR), &dwBytesWritten, NULL) ||
  300. dwBytesWritten != sizeof(WCHAR))
  301. {
  302. xe = GetLastError();
  303. DebugMsg((DM_WARNING, TEXT("ArchiveRegistryValue: Failed to write close bracket with %d"),
  304. GetLastError()));
  305. goto Exit;
  306. }
  307. //
  308. // Sucess
  309. //
  310. bResult = TRUE;
  311. Exit:
  312. return bResult;
  313. }
  314. //*************************************************************
  315. //
  316. // ParseRegistryFile()
  317. //
  318. // Purpose: Parses a registry.pol file
  319. //
  320. // Parameters: lpGPOInfo - GPO information
  321. // lpRegistry - Path to registry.pol
  322. // pfnRegFileCallback - Callback function
  323. // hArchive - Handle to archive file
  324. // pwszGPO - Gpo
  325. // pwszSOM - Sdou that the Gpo is linked to
  326. // pHashTable - Hash table for registry keys
  327. //
  328. //
  329. // Return: TRUE if successful
  330. // FALSE if an error occurs
  331. //
  332. //*************************************************************
  333. BOOL ParseRegistryFile (LPGPOINFO lpGPOInfo, LPTSTR lpRegistry,
  334. PFNREGFILECALLBACK pfnRegFileCallback,
  335. HANDLE hArchive, WCHAR *pwszGPO,
  336. WCHAR *pwszSOM, REGHASHTABLE *pHashTable,
  337. BOOL bRsopPlanningMode)
  338. {
  339. HANDLE hFile = INVALID_HANDLE_VALUE;
  340. BOOL bResult = FALSE;
  341. DWORD dwTemp, dwBytesRead, dwType, dwDataLength;
  342. LPWSTR lpKeyName = 0, lpValueName = 0, lpTemp;
  343. LPBYTE lpData = NULL;
  344. WCHAR chTemp;
  345. HANDLE hOldToken;
  346. XLastError xe;
  347. //
  348. // Verbose output
  349. //
  350. DebugMsg((DM_VERBOSE, TEXT("ParseRegistryFile: Entering with <%s>."),
  351. lpRegistry));
  352. //
  353. // Open the registry file
  354. //
  355. if(!bRsopPlanningMode) {
  356. if (!ImpersonateUser(lpGPOInfo->hToken, &hOldToken)) {
  357. xe = GetLastError();
  358. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to impersonate user")));
  359. goto Exit;
  360. }
  361. }
  362. hFile = CreateFile (lpRegistry, GENERIC_READ, FILE_SHARE_READ, NULL,
  363. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  364. NULL);
  365. if(!bRsopPlanningMode) {
  366. RevertToUser(&hOldToken);
  367. }
  368. if (hFile == INVALID_HANDLE_VALUE) {
  369. if ((GetLastError() == ERROR_FILE_NOT_FOUND) ||
  370. (GetLastError() == ERROR_PATH_NOT_FOUND))
  371. {
  372. bResult = TRUE;
  373. goto Exit;
  374. }
  375. else
  376. {
  377. xe = GetLastError();
  378. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: CreateFile failed with %d"),
  379. GetLastError()));
  380. CEvents ev(TRUE, EVENT_NO_REGISTRY);
  381. ev.AddArg(lpRegistry); ev.AddArgWin32Error(GetLastError()); ev.Report();
  382. goto Exit;
  383. }
  384. }
  385. //
  386. // Allocate buffers to hold the keyname, valuename, and data
  387. //
  388. lpKeyName = (LPWSTR) LocalAlloc (LPTR, MAX_KEYNAME_SIZE * sizeof(WCHAR));
  389. if (!lpKeyName)
  390. {
  391. xe = GetLastError();
  392. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to allocate memory with %d"),
  393. GetLastError()));
  394. goto Exit;
  395. }
  396. lpValueName = (LPWSTR) LocalAlloc (LPTR, MAX_VALUENAME_SIZE * sizeof(WCHAR));
  397. if (!lpValueName)
  398. {
  399. xe = GetLastError();
  400. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to allocate memory with %d"),
  401. GetLastError()));
  402. goto Exit;
  403. }
  404. //
  405. // Read the header block
  406. //
  407. // 2 DWORDS, signature (PReg) and version number and 2 newlines
  408. //
  409. if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
  410. dwBytesRead != sizeof(dwTemp))
  411. {
  412. xe = ERROR_INVALID_DATA;
  413. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read signature with %d"),
  414. GetLastError()));
  415. goto Exit;
  416. }
  417. if (dwTemp != REGFILE_SIGNATURE)
  418. {
  419. xe = ERROR_INVALID_DATA;
  420. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Invalid file signature")));
  421. goto Exit;
  422. }
  423. if (!ReadFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesRead, NULL) ||
  424. dwBytesRead != sizeof(dwTemp))
  425. {
  426. xe = ERROR_INVALID_DATA;
  427. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read version number with %d"),
  428. GetLastError()));
  429. goto Exit;
  430. }
  431. if (dwTemp != REGISTRY_FILE_VERSION)
  432. {
  433. xe = ERROR_INVALID_DATA;
  434. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Invalid file version")));
  435. goto Exit;
  436. }
  437. //
  438. // Read the data
  439. //
  440. while (TRUE)
  441. {
  442. //
  443. // Read the first character. It will either be a [ or the end
  444. // of the file.
  445. //
  446. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  447. {
  448. if (GetLastError() != ERROR_HANDLE_EOF)
  449. {
  450. xe = ERROR_INVALID_DATA;
  451. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read first character with %d"),
  452. GetLastError()));
  453. goto Exit;
  454. }
  455. break;
  456. }
  457. if ((dwBytesRead == 0) || (chTemp != L'['))
  458. {
  459. break;
  460. }
  461. //
  462. // Read the keyname
  463. //
  464. lpTemp = lpKeyName;
  465. dwTemp = 0;
  466. while (dwTemp < MAX_KEYNAME_SIZE)
  467. {
  468. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  469. {
  470. xe = ERROR_INVALID_DATA;
  471. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read keyname character with %d"),
  472. GetLastError()));
  473. goto Exit;
  474. }
  475. *lpTemp++ = chTemp;
  476. if (chTemp == TEXT('\0'))
  477. break;
  478. dwTemp++;
  479. }
  480. if (dwTemp >= MAX_KEYNAME_SIZE)
  481. {
  482. xe = ERROR_INVALID_DATA;
  483. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Keyname exceeded max size")));
  484. goto Exit;
  485. }
  486. //
  487. // Read the semi-colon
  488. //
  489. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  490. {
  491. if (GetLastError() != ERROR_HANDLE_EOF)
  492. {
  493. xe = ERROR_INVALID_DATA;
  494. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read first character with %d"),
  495. GetLastError()));
  496. goto Exit;
  497. }
  498. break;
  499. }
  500. if ((dwBytesRead == 0) || (chTemp != L';'))
  501. {
  502. break;
  503. }
  504. //
  505. // Read the valuename
  506. //
  507. lpTemp = lpValueName;
  508. dwTemp = 0;
  509. while (dwTemp < MAX_VALUENAME_SIZE)
  510. {
  511. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  512. {
  513. xe = ERROR_INVALID_DATA;
  514. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read valuename character with %d"),
  515. GetLastError()));
  516. goto Exit;
  517. }
  518. *lpTemp++ = chTemp;
  519. if (chTemp == TEXT('\0'))
  520. break;
  521. dwTemp++;
  522. }
  523. if (dwTemp >= MAX_VALUENAME_SIZE)
  524. {
  525. xe = ERROR_INVALID_DATA;
  526. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Valuename exceeded max size")));
  527. goto Exit;
  528. }
  529. //
  530. // Read the semi-colon
  531. //
  532. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  533. {
  534. if (GetLastError() != ERROR_HANDLE_EOF)
  535. {
  536. xe = ERROR_INVALID_DATA;
  537. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read first character with %d"),
  538. GetLastError()));
  539. goto Exit;
  540. }
  541. break;
  542. }
  543. if ((dwBytesRead == 0) || (chTemp != L';'))
  544. {
  545. break;
  546. }
  547. //
  548. // Read the type
  549. //
  550. if (!ReadFile (hFile, &dwType, sizeof(DWORD), &dwBytesRead, NULL))
  551. {
  552. xe = ERROR_INVALID_DATA;
  553. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read type with %d"),
  554. GetLastError()));
  555. goto Exit;
  556. }
  557. //
  558. // Skip semicolon
  559. //
  560. if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  561. {
  562. xe = ERROR_INVALID_DATA;
  563. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to skip semicolon with %d"),
  564. GetLastError()));
  565. goto Exit;
  566. }
  567. //
  568. // Read the data length
  569. //
  570. if (!ReadFile (hFile, &dwDataLength, sizeof(DWORD), &dwBytesRead, NULL))
  571. {
  572. xe = ERROR_INVALID_DATA;
  573. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to data length with %d"),
  574. GetLastError()));
  575. goto Exit;
  576. }
  577. //
  578. // Skip semicolon
  579. //
  580. if (!ReadFile (hFile, &dwTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  581. {
  582. xe = ERROR_INVALID_DATA;
  583. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to skip semicolon with %d"),
  584. GetLastError()));
  585. goto Exit;
  586. }
  587. //
  588. // Allocate memory for data
  589. //
  590. lpData = (LPBYTE) LocalAlloc (LPTR, dwDataLength);
  591. if (!lpData)
  592. {
  593. xe = GetLastError();
  594. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to allocate memory for data with %d"),
  595. GetLastError()));
  596. goto Exit;
  597. }
  598. //
  599. // Read data
  600. //
  601. if (!ReadFile (hFile, lpData, dwDataLength, &dwBytesRead, NULL))
  602. {
  603. xe = ERROR_INVALID_DATA;
  604. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to read data with %d"),
  605. GetLastError()));
  606. goto Exit;
  607. }
  608. //
  609. // Skip closing bracket
  610. //
  611. if (!ReadFile (hFile, &chTemp, sizeof(WCHAR), &dwBytesRead, NULL))
  612. {
  613. xe = ERROR_INVALID_DATA;
  614. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Failed to skip closing bracket with %d"),
  615. GetLastError()));
  616. goto Exit;
  617. }
  618. if (chTemp != L']')
  619. {
  620. xe = ERROR_INVALID_DATA;
  621. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Expected to find ], but found %c"),
  622. chTemp));
  623. goto Exit;
  624. }
  625. //
  626. // Call the callback function
  627. //
  628. if (!pfnRegFileCallback (lpGPOInfo, lpKeyName, lpValueName,
  629. dwType, dwDataLength, lpData,
  630. pwszGPO, pwszSOM, pHashTable ))
  631. {
  632. xe = GetLastError();
  633. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: Callback function returned false.")));
  634. goto Exit;
  635. }
  636. //
  637. // Archive the data if appropriate
  638. //
  639. if (hArchive) {
  640. if (!ArchiveRegistryValue(hArchive, lpKeyName, lpValueName,
  641. dwType, dwDataLength, lpData)) {
  642. DebugMsg((DM_WARNING, TEXT("ParseRegistryFile: ArchiveRegistryValue returned false.")));
  643. }
  644. }
  645. LocalFree (lpData);
  646. lpData = NULL;
  647. }
  648. bResult = TRUE;
  649. Exit:
  650. //
  651. // Finished
  652. //
  653. if ( !bResult )
  654. {
  655. CEvents ev(TRUE, EVENT_REGISTRY_TEMPLATE_ERROR);
  656. ev.AddArg(lpRegistry ? lpRegistry : TEXT("")); ev.AddArgWin32Error( xe ); ev.Report();
  657. }
  658. DebugMsg((DM_VERBOSE, TEXT("ParseRegistryFile: Leaving.")));
  659. if (lpData) {
  660. LocalFree (lpData);
  661. }
  662. if ( hFile != INVALID_HANDLE_VALUE ) {
  663. CloseHandle (hFile);
  664. }
  665. if ( lpKeyName ) {
  666. LocalFree (lpKeyName);
  667. }
  668. if ( lpValueName ) {
  669. LocalFree (lpValueName);
  670. }
  671. return bResult;
  672. }
  673. //*************************************************************
  674. //
  675. // ProcessRegistryValue()
  676. //
  677. // Purpose: Callback passed to ParseRegistryFile from ProcessRegistryFiles. Invokes AddRegHashEntry
  678. // with appropriate parameters depending on the registry policy settings.
  679. //
  680. // Parameters:
  681. // pUnused - Not used. It si there only to conform to the signature
  682. // expected by ParseRegistryFile.
  683. // lpKeyName - registry key name
  684. // lpValueName - Registry value name
  685. // dwType - Registry value type
  686. // dwDataLength - Length of registry value data.
  687. // lpData - Regsitry value data
  688. // *pwszGPO - GPO associated with this registry setting
  689. // *pwszSOM - SOM associated with the GPO
  690. // *pHashTable - Hash table containing registry policy data for a policy target.
  691. //
  692. // Return: TRUE if successful
  693. // FALSE if an error occurs
  694. //
  695. //*************************************************************
  696. BOOL ProcessRegistryValue ( void* pUnused,
  697. LPTSTR lpKeyName,
  698. LPTSTR lpValueName,
  699. DWORD dwType,
  700. DWORD dwDataLength,
  701. LPBYTE lpData,
  702. WCHAR *pwszGPO,
  703. WCHAR *pwszSOM,
  704. REGHASHTABLE *pHashTable)
  705. {
  706. BOOL bLoggingOk = TRUE;
  707. //
  708. // Special case some values
  709. //
  710. if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  711. TEXT("**del."), 6, lpValueName, 6) == 2)
  712. {
  713. LPTSTR lpRealValueName = lpValueName + 6;
  714. //
  715. // Delete one specific value
  716. //
  717. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
  718. lpRealValueName, 0, 0, NULL,
  719. pwszGPO, pwszSOM, lpValueName, TRUE );
  720. }
  721. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  722. TEXT("**delvals."), 10, lpValueName, 10) == 2)
  723. {
  724. //
  725. // Delete all values in the destination key
  726. //
  727. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEALLVALUES, lpKeyName,
  728. NULL, 0, 0, NULL,
  729. pwszGPO, pwszSOM, lpValueName, TRUE );
  730. }
  731. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  732. TEXT("**DeleteValues"), 14, lpValueName, 14) == 2)
  733. {
  734. TCHAR szValueName[MAX_PATH];
  735. LPTSTR lpName, lpNameTemp;
  736. lpName = (LPTSTR)lpData;
  737. while (*lpName) {
  738. lpNameTemp = szValueName;
  739. while (*lpName && *lpName == TEXT(' ')) {
  740. lpName++;
  741. }
  742. while (*lpName && *lpName != TEXT(';')) {
  743. *lpNameTemp++ = *lpName++;
  744. }
  745. *lpNameTemp= TEXT('\0');
  746. while (*lpName == TEXT(';')) {
  747. lpName++;
  748. }
  749. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
  750. szValueName, 0, 0, NULL,
  751. pwszGPO, pwszSOM, lpValueName, TRUE );
  752. }
  753. }
  754. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  755. TEXT("**DeleteKeys"), 12, lpValueName, 12) == 2)
  756. {
  757. TCHAR szKeyName[MAX_KEYNAME_SIZE];
  758. LPTSTR lpName, lpNameTemp, lpEnd;
  759. lpName = (LPTSTR)lpData;
  760. while (*lpName) {
  761. szKeyName[0] = TEXT('\0');
  762. lpNameTemp = szKeyName;
  763. while (*lpName && *lpName == TEXT(' ')) {
  764. lpName++;
  765. }
  766. while (*lpName && *lpName != TEXT(';')) {
  767. *lpNameTemp++ = *lpName++;
  768. }
  769. *lpNameTemp= TEXT('\0');
  770. while (*lpName == TEXT(';')) {
  771. lpName++;
  772. }
  773. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEKEY, lpKeyName,
  774. NULL, 0, 0, NULL,
  775. pwszGPO, pwszSOM, lpValueName, TRUE );
  776. }
  777. }
  778. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  779. TEXT("**soft."), 7, lpValueName, 7) == 2)
  780. {
  781. //
  782. // In planning mode we will assume the value does not exist in the target computer.
  783. // Therefore, we set it if no value exists in the hash table.
  784. //
  785. // Soft add is dealt with differently in planning mode vs. diag mode.
  786. // In diag mode, check is done while processing policy and it is logged as a add value
  787. // if the key doesn't exist.
  788. // In planning mode, key is not supposed to exist beforehand and the hash table itself is
  789. // used to determine whether to add the key or not.
  790. LPTSTR lpRealValueName = lpValueName + 7;
  791. bLoggingOk = AddRegHashEntry( pHashTable, REG_SOFTADDVALUE, lpKeyName,
  792. lpRealValueName, dwType, dwDataLength, lpData,
  793. pwszGPO, pwszSOM, lpValueName, TRUE );
  794. }
  795. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  796. TEXT("**SecureKey"), 11, lpValueName, 11) == 2)
  797. {
  798. // There is nothing to do here.
  799. } else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  800. TEXT("**Comment:"), 10, lpValueName, 10) == 2)
  801. {
  802. //
  803. // Comment - can be ignored
  804. //
  805. }
  806. else
  807. {
  808. //
  809. // AddRegHashEntry needs to log a key being logged but no values.
  810. //
  811. bLoggingOk = AddRegHashEntry( pHashTable, REG_ADDVALUE, lpKeyName,
  812. lpValueName, dwType, dwDataLength, lpData,
  813. pwszGPO, pwszSOM, TEXT(""), TRUE );
  814. }
  815. return bLoggingOk;
  816. }
  817. //*************************************************************
  818. //
  819. // ResetRegKeySecurity
  820. //
  821. // Purpose: Resets the security on a user's key
  822. //
  823. // Parameters: hKeyRoot - Handle to the root of the hive
  824. // lpKeyName - Subkey name
  825. //
  826. //
  827. // Return: TRUE if successful
  828. // FALSE if an error occurs
  829. //
  830. //*************************************************************
  831. BOOL ResetRegKeySecurity (HKEY hKeyRoot, LPTSTR lpKeyName)
  832. {
  833. PSECURITY_DESCRIPTOR pSD = NULL;
  834. DWORD dwSize = 0;
  835. LONG lResult;
  836. HKEY hSubKey;
  837. XLastError xe;
  838. RegGetKeySecurity(hKeyRoot, DACL_SECURITY_INFORMATION, pSD, &dwSize);
  839. if (!dwSize) {
  840. DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: RegGetKeySecurity returned 0")));
  841. return FALSE;
  842. }
  843. pSD = LocalAlloc (LPTR, dwSize);
  844. if (!pSD) {
  845. xe = GetLastError();
  846. DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: Failed to allocate memory")));
  847. return FALSE;
  848. }
  849. lResult = RegGetKeySecurity(hKeyRoot, DACL_SECURITY_INFORMATION, pSD, &dwSize);
  850. if (lResult != ERROR_SUCCESS) {
  851. xe = GetLastError();
  852. DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: Failed to query key security with %d"),
  853. lResult));
  854. LocalFree (pSD);
  855. return FALSE;
  856. }
  857. lResult = RegOpenKeyEx(hKeyRoot,
  858. lpKeyName,
  859. 0,
  860. WRITE_DAC | KEY_ENUMERATE_SUB_KEYS | READ_CONTROL,
  861. &hSubKey);
  862. if (lResult != ERROR_SUCCESS) {
  863. xe = GetLastError();
  864. DebugMsg((DM_WARNING, TEXT("ResetRegKeySecurity: Failed to open sub key with %d"),
  865. lResult));
  866. LocalFree (pSD);
  867. return FALSE;
  868. }
  869. lResult = RegSetKeySecurity (hSubKey, DACL_SECURITY_INFORMATION, pSD);
  870. RegCloseKey (hSubKey);
  871. LocalFree (pSD);
  872. if (lResult != ERROR_SUCCESS) {
  873. xe = GetLastError();
  874. DebugMsg((DM_WARNING, TEXT("ResetRegKeySecure: Failed to set security, error = %d"), lResult));
  875. return FALSE;
  876. }
  877. return TRUE;
  878. }
  879. //*************************************************************
  880. //
  881. // SetRegistryValue()
  882. //
  883. // Purpose: Callback from ParseRegistryFile that sets
  884. // registry policies
  885. //
  886. // Parameters: lpGPOInfo - GPO Information
  887. // lpKeyName - Key name
  888. // lpValueName - Value name
  889. // dwType - Registry data type
  890. // lpData - Registry data
  891. // pwszGPO - Gpo
  892. // pwszSOM - Sdou that the Gpo is linked to
  893. // pHashTable - Hash table for registry keys
  894. //
  895. // Return: TRUE if successful
  896. // FALSE if an error occurs
  897. //
  898. //*************************************************************
  899. BOOL SetRegistryValue (LPGPOINFO lpGPOInfo, LPTSTR lpKeyName,
  900. LPTSTR lpValueName, DWORD dwType,
  901. DWORD dwDataLength, LPBYTE lpData,
  902. WCHAR *pwszGPO,
  903. WCHAR *pwszSOM, REGHASHTABLE *pHashTable)
  904. {
  905. DWORD dwDisp;
  906. HKEY hSubKey;
  907. LONG lResult;
  908. BOOL bLoggingOk = TRUE;
  909. BOOL bRsopLogging = (pHashTable != NULL); // Is diagnostic mode Rsop logging enabled ?
  910. BOOL bUseValueName = FALSE;
  911. BOOL bRegOpSuccess = TRUE;
  912. XLastError xe;
  913. //
  914. // Special case some values
  915. //
  916. if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  917. TEXT("**del."), 6, lpValueName, 6) == 2)
  918. {
  919. LPTSTR lpRealValueName = lpValueName + 6;
  920. //
  921. // Delete one specific value
  922. //
  923. lResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
  924. lpKeyName, 0, KEY_WRITE, &hSubKey);
  925. if (lResult == ERROR_SUCCESS)
  926. {
  927. lResult = RegDeleteValue(hSubKey, lpRealValueName);
  928. if ((lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND))
  929. {
  930. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted value <%s>."),
  931. lpRealValueName));
  932. if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  933. CEvents ev(FALSE, EVENT_DELETED_VALUE);
  934. ev.AddArg(lpRealValueName); ev.Report();
  935. }
  936. if ( bRsopLogging ) {
  937. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
  938. lpRealValueName, 0, 0, NULL,
  939. pwszGPO, pwszSOM, lpValueName, TRUE );
  940. if (!bLoggingOk) {
  941. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE <%s>."), lpRealValueName));
  942. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  943. }
  944. }
  945. }
  946. else
  947. {
  948. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to delete value <%s> with %d"),
  949. lpRealValueName, lResult));
  950. xe = lResult;
  951. CEvents ev(TRUE, EVENT_FAIL_DELETE_VALUE);
  952. ev.AddArg(lpRealValueName); ev.AddArgWin32Error(lResult); ev.Report();
  953. bRegOpSuccess = FALSE;
  954. }
  955. RegCloseKey (hSubKey);
  956. }
  957. else if (lResult == ERROR_FILE_NOT_FOUND) {
  958. //
  959. // Log into rsop even if the key is not found
  960. //
  961. if ( bRsopLogging ) {
  962. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
  963. lpRealValueName, 0, 0, NULL,
  964. pwszGPO, pwszSOM, lpValueName, TRUE );
  965. if (!bLoggingOk) {
  966. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  967. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE (notfound) <%s>."), lpRealValueName));
  968. }
  969. }
  970. }
  971. }
  972. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  973. TEXT("**delvals."), 10, lpValueName, 10) == 2)
  974. {
  975. //
  976. // Delete all values in the destination key
  977. //
  978. lResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
  979. lpKeyName, 0, KEY_WRITE | KEY_READ, &hSubKey);
  980. if (lResult == ERROR_SUCCESS)
  981. {
  982. if (!bRsopLogging)
  983. bRegOpSuccess = DeleteAllValues(hSubKey);
  984. else
  985. bRegOpSuccess = RsopDeleteAllValues(hSubKey, pHashTable, lpKeyName,
  986. pwszGPO, pwszSOM, lpValueName, &bLoggingOk );
  987. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted all values in <%s>."),
  988. lpKeyName));
  989. RegCloseKey (hSubKey);
  990. if (!bRegOpSuccess) {
  991. xe = GetLastError();
  992. }
  993. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: DeleteAllvalues finished for %s. bRegOpSuccess = %s, bLoggingOk = %s."),
  994. lpKeyName, (bRegOpSuccess ? TEXT("TRUE") : TEXT("FALSE")), (bLoggingOk ? TEXT("TRUE") : TEXT("FALSE"))));
  995. }
  996. else if (lResult == ERROR_FILE_NOT_FOUND) {
  997. //
  998. // Log into rsop even if the key is not found
  999. // as just deleteallvalues
  1000. //
  1001. if ( bRsopLogging ) {
  1002. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEALLVALUES, lpKeyName,
  1003. NULL, 0, 0, NULL,
  1004. pwszGPO, pwszSOM, lpValueName, TRUE );
  1005. if (!bLoggingOk) {
  1006. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEALLVALUES (notfound) key - <%s>, value <%s>."), lpKeyName, lpValueName));
  1007. }
  1008. }
  1009. }
  1010. }
  1011. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1012. TEXT("**DeleteValues"), 14, lpValueName, 14) == 2)
  1013. {
  1014. TCHAR szValueName[MAX_PATH];
  1015. LPTSTR lpName, lpNameTemp;
  1016. LONG lKeyResult;
  1017. //
  1018. // Delete the values (semi-colon separated)
  1019. //
  1020. lKeyResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
  1021. lpKeyName, 0, KEY_WRITE, &hSubKey);
  1022. lpName = (LPTSTR)lpData;
  1023. while (*lpName) {
  1024. lpNameTemp = szValueName;
  1025. while (*lpName && *lpName == TEXT(' ')) {
  1026. lpName++;
  1027. }
  1028. while (*lpName && *lpName != TEXT(';')) {
  1029. *lpNameTemp++ = *lpName++;
  1030. }
  1031. *lpNameTemp= TEXT('\0');
  1032. while (*lpName == TEXT(';')) {
  1033. lpName++;
  1034. }
  1035. if (lKeyResult == ERROR_SUCCESS)
  1036. {
  1037. lResult = RegDeleteValue (hSubKey, szValueName);
  1038. if ((lResult == ERROR_SUCCESS) || (lResult == ERROR_FILE_NOT_FOUND))
  1039. {
  1040. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted value <%s>."),
  1041. szValueName));
  1042. if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  1043. CEvents ev(FALSE, EVENT_DELETED_VALUE);
  1044. ev.AddArg(szValueName); ev.Report();
  1045. }
  1046. if ( bRsopLogging ) {
  1047. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
  1048. szValueName, 0, 0, NULL,
  1049. pwszGPO, pwszSOM, lpValueName, TRUE );
  1050. if (!bLoggingOk) {
  1051. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE value <%s>."), szValueName));
  1052. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  1053. }
  1054. }
  1055. }
  1056. else
  1057. {
  1058. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to delete value <%s> with %d"),
  1059. szValueName, lResult));
  1060. CEvents ev(TRUE, EVENT_FAIL_DELETE_VALUE);
  1061. ev.AddArg(szValueName); ev.AddArgWin32Error(lResult); ev.Report();
  1062. xe = lResult;
  1063. bRegOpSuccess = FALSE;
  1064. }
  1065. }
  1066. else if (lKeyResult == ERROR_FILE_NOT_FOUND) {
  1067. if ( bRsopLogging ) {
  1068. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEVALUE, lpKeyName,
  1069. szValueName, 0, 0, NULL,
  1070. pwszGPO, pwszSOM, lpValueName, TRUE );
  1071. if (!bLoggingOk) {
  1072. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEVALUE value (not found case) <%s>."), szValueName));
  1073. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  1074. }
  1075. }
  1076. }
  1077. }
  1078. if (lKeyResult == ERROR_SUCCESS)
  1079. {
  1080. RegCloseKey (hSubKey);
  1081. }
  1082. }
  1083. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1084. TEXT("**DeleteKeys"), 12, lpValueName, 12) == 2)
  1085. {
  1086. TCHAR szKeyName[MAX_KEYNAME_SIZE];
  1087. LPTSTR lpName, lpNameTemp, lpEnd;
  1088. //
  1089. // Delete keys
  1090. //
  1091. lpName = (LPTSTR)lpData;
  1092. while (*lpName) {
  1093. szKeyName[0] = TEXT('\0');
  1094. lpNameTemp = szKeyName;
  1095. while (*lpName && *lpName == TEXT(' ')) {
  1096. lpName++;
  1097. }
  1098. while (*lpName && *lpName != TEXT(';')) {
  1099. *lpNameTemp++ = *lpName++;
  1100. }
  1101. *lpNameTemp= TEXT('\0');
  1102. while (*lpName == TEXT(';')) {
  1103. lpName++;
  1104. }
  1105. if (RegDelnode (lpGPOInfo->hKeyRoot,
  1106. szKeyName))
  1107. {
  1108. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Deleted key <%s>."),
  1109. szKeyName));
  1110. if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  1111. CEvents ev(FALSE, EVENT_DELETED_KEY);
  1112. ev.AddArg(szKeyName); ev.Report();
  1113. }
  1114. }
  1115. else
  1116. {
  1117. xe = GetLastError();
  1118. bRegOpSuccess = FALSE;
  1119. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: RegDelnode for key <%s>."), szKeyName));
  1120. }
  1121. if ( bRsopLogging ) {
  1122. bLoggingOk = AddRegHashEntry( pHashTable, REG_DELETEKEY, szKeyName,
  1123. NULL, 0, 0, NULL,
  1124. pwszGPO, pwszSOM, lpValueName, TRUE );
  1125. if (!bLoggingOk) {
  1126. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_DELETEKEY <%s>."), szKeyName));
  1127. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  1128. }
  1129. }
  1130. }
  1131. }
  1132. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1133. TEXT("**soft."), 7, lpValueName, 7) == 2)
  1134. {
  1135. //
  1136. // "soft" value, only set this if it doesn't already
  1137. // exist in destination
  1138. //
  1139. lResult = RegOpenKeyEx (lpGPOInfo->hKeyRoot,
  1140. lpKeyName, 0, KEY_QUERY_VALUE, &hSubKey);
  1141. if (lResult == ERROR_SUCCESS)
  1142. {
  1143. TCHAR TmpValueData[MAX_PATH+1];
  1144. DWORD dwSize=sizeof(TmpValueData);
  1145. lResult = RegQueryValueEx(hSubKey, lpValueName + 7,
  1146. NULL,NULL,(LPBYTE) TmpValueData,
  1147. &dwSize);
  1148. RegCloseKey (hSubKey);
  1149. if (lResult != ERROR_SUCCESS)
  1150. {
  1151. lpValueName += 7;
  1152. bUseValueName = TRUE;
  1153. goto SetValue;
  1154. }
  1155. }
  1156. }
  1157. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1158. TEXT("**SecureKey"), 11, lpValueName, 11) == 2)
  1159. {
  1160. //
  1161. // Secure / unsecure a key (user only)
  1162. //
  1163. if (!(lpGPOInfo->dwFlags & GP_MACHINE))
  1164. {
  1165. if (*((LPDWORD)lpData) == 1)
  1166. {
  1167. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Securing key <%s>."),
  1168. lpKeyName));
  1169. bRegOpSuccess = MakeRegKeySecure(lpGPOInfo->hToken, lpGPOInfo->hKeyRoot, lpKeyName);
  1170. }
  1171. else
  1172. {
  1173. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Unsecuring key <%s>."),
  1174. lpKeyName));
  1175. bRegOpSuccess = ResetRegKeySecurity (lpGPOInfo->hKeyRoot, lpKeyName);
  1176. }
  1177. if (!bRegOpSuccess) {
  1178. xe = GetLastError();
  1179. }
  1180. }
  1181. }
  1182. else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1183. TEXT("**Comment:"), 10, lpValueName, 10) == 2)
  1184. {
  1185. //
  1186. // Comment - can be ignored
  1187. //
  1188. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: Found comment %s."),
  1189. (lpValueName+10)));
  1190. }
  1191. else
  1192. {
  1193. SetValue:
  1194. //
  1195. // Save registry value
  1196. //
  1197. lResult = RegCreateKeyEx (lpGPOInfo->hKeyRoot,
  1198. lpKeyName, 0, NULL, REG_OPTION_NON_VOLATILE,
  1199. KEY_WRITE, NULL, &hSubKey, &dwDisp);
  1200. if (lResult == ERROR_SUCCESS)
  1201. {
  1202. if ((dwType == REG_NONE) && (dwDataLength == 0) &&
  1203. (*lpValueName == L'\0'))
  1204. {
  1205. lResult = ERROR_SUCCESS;
  1206. }
  1207. else
  1208. {
  1209. lResult = RegSetValueEx (hSubKey, lpValueName, 0, dwType,
  1210. lpData, dwDataLength);
  1211. }
  1212. if ( bRsopLogging ) {
  1213. bLoggingOk = AddRegHashEntry( pHashTable, REG_ADDVALUE, lpKeyName,
  1214. lpValueName, dwType, dwDataLength, lpData,
  1215. pwszGPO, pwszSOM, bUseValueName ? lpValueName : TEXT(""), TRUE );
  1216. if (!bLoggingOk) {
  1217. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: AddRegHashEntry failed for REG_ADDVALUE key <%s>, value <%s>."), lpKeyName, lpValueName));
  1218. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  1219. }
  1220. }
  1221. RegCloseKey (hSubKey);
  1222. if (lResult == ERROR_SUCCESS)
  1223. {
  1224. switch (dwType) {
  1225. case REG_SZ:
  1226. case REG_EXPAND_SZ:
  1227. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: %s => %s [OK]"),
  1228. lpValueName, (LPTSTR)lpData));
  1229. if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  1230. CEvents ev(FALSE, EVENT_SET_STRING_VALUE);
  1231. ev.AddArg(lpValueName); ev.AddArg((LPTSTR)lpData); ev.Report();
  1232. }
  1233. break;
  1234. case REG_DWORD:
  1235. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: %s => %d [OK]"),
  1236. lpValueName, *((LPDWORD)lpData)));
  1237. if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  1238. CEvents ev(FALSE, EVENT_SET_DWORD_VALUE);
  1239. ev.AddArg(lpValueName); ev.AddArg((DWORD)*lpData); ev.Report();
  1240. }
  1241. break;
  1242. case REG_NONE:
  1243. break;
  1244. default:
  1245. DebugMsg((DM_VERBOSE, TEXT("SetRegistryValue: %s was set successfully"),
  1246. lpValueName));
  1247. if (lpGPOInfo->dwFlags & GP_VERBOSE) {
  1248. CEvents ev(FALSE, EVENT_SET_UNKNOWN_VALUE);
  1249. ev.AddArg(lpValueName); ev.Report();
  1250. }
  1251. break;
  1252. }
  1253. if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1254. TEXT("Control Panel\\Colors"), 20, lpKeyName, 20) == 2) {
  1255. lpGPOInfo->dwFlags |= GP_REGPOLICY_CPANEL;
  1256. } else if (CompareString (LOCALE_USER_DEFAULT, NORM_IGNORECASE,
  1257. TEXT("Control Panel\\Desktop"), 21, lpKeyName, 21) == 2) {
  1258. lpGPOInfo->dwFlags |= GP_REGPOLICY_CPANEL;
  1259. }
  1260. }
  1261. else
  1262. {
  1263. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to set value <%s> with %d"),
  1264. lpValueName, lResult));
  1265. xe = lResult;
  1266. CEvents ev(TRUE, EVENT_FAILED_SET);
  1267. ev.AddArg(lpValueName); ev.AddArgWin32Error(lResult); ev.Report();
  1268. bRegOpSuccess = FALSE;
  1269. }
  1270. }
  1271. else
  1272. {
  1273. DebugMsg((DM_WARNING, TEXT("SetRegistryValue: Failed to open key <%s> with %d"),
  1274. lpKeyName, lResult));
  1275. xe = lResult;
  1276. CEvents ev(TRUE, EVENT_FAILED_CREATE);
  1277. ev.AddArg(lpKeyName); ev.AddArgWin32Error(lResult); ev.Report();
  1278. bRegOpSuccess = FALSE;
  1279. }
  1280. }
  1281. return bLoggingOk && bRegOpSuccess;
  1282. }
  1283. //*************************************************************
  1284. //
  1285. // ProcessGPORegistryPolicy()
  1286. //
  1287. // Purpose: Proceses GPO registry policy
  1288. //
  1289. // Parameters: lpGPOInfo - GPO information
  1290. // pChangedGPOList - Link list of changed GPOs
  1291. //
  1292. // Notes: This function is called in the context of
  1293. // local system, which allows us to create the
  1294. // directory, write to the file etc.
  1295. //
  1296. // Return: TRUE if successful
  1297. // FALSE if an error occurs
  1298. //
  1299. //*************************************************************
  1300. BOOL ProcessGPORegistryPolicy (LPGPOINFO lpGPOInfo,
  1301. PGROUP_POLICY_OBJECT pChangedGPOList, HRESULT *phrRsopLogging)
  1302. {
  1303. PGROUP_POLICY_OBJECT lpGPO;
  1304. TCHAR szPath[MAX_PATH];
  1305. TCHAR szBuffer[MAX_PATH];
  1306. TCHAR szKeyName[100];
  1307. LPTSTR lpEnd, lpGPOComment;
  1308. HANDLE hFile;
  1309. DWORD dwTemp, dwBytesWritten;
  1310. REGHASHTABLE *pHashTable = NULL;
  1311. WIN32_FIND_DATA findData;
  1312. ADMFILEINFO *pAdmFileCache = NULL;
  1313. XLastError xe;
  1314. //
  1315. // Get the path name to the appropriate profile
  1316. //
  1317. *phrRsopLogging = S_OK;
  1318. szPath[0] = TEXT('\0');
  1319. dwTemp = ARRAYSIZE(szPath);
  1320. if (lpGPOInfo->dwFlags & GP_MACHINE) {
  1321. GetAllUsersProfileDirectoryEx(szPath, &dwTemp, TRUE);
  1322. } else {
  1323. GetUserProfileDirectory(lpGPOInfo->hToken, szPath, &dwTemp);
  1324. }
  1325. if (szPath[0] == TEXT('\0')) {
  1326. xe = GetLastError();
  1327. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to get path to profile root")));
  1328. return FALSE;
  1329. }
  1330. //
  1331. // Tack on the archive file name
  1332. //
  1333. DmAssert( lstrlen(szPath) + lstrlen(TEXT("\\ntuser.pol")) < MAX_PATH );
  1334. lstrcat (szPath, TEXT("\\ntuser.pol"));
  1335. //
  1336. // Delete any existing policies
  1337. //
  1338. if (!ResetPolicies (lpGPOInfo, szPath)) {
  1339. xe = GetLastError();
  1340. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ResetPolicies failed.")));
  1341. return FALSE;
  1342. }
  1343. //
  1344. // Delete the old archive file
  1345. //
  1346. SetFileAttributes (szPath, FILE_ATTRIBUTE_NORMAL);
  1347. DeleteFile (szPath);
  1348. //
  1349. // Recreate the archive file
  1350. //
  1351. hFile = CreateFile (szPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  1352. FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN,
  1353. NULL);
  1354. if (hFile == INVALID_HANDLE_VALUE)
  1355. {
  1356. xe = GetLastError();
  1357. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to create archive file with %d"),
  1358. GetLastError()));
  1359. return FALSE;
  1360. }
  1361. //
  1362. // Set the header information in the archive file
  1363. //
  1364. dwTemp = REGFILE_SIGNATURE;
  1365. if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
  1366. dwBytesWritten != sizeof(dwTemp))
  1367. {
  1368. xe = GetLastError();
  1369. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to write signature with %d"),
  1370. GetLastError()));
  1371. CloseHandle (hFile);
  1372. return FALSE;
  1373. }
  1374. dwTemp = REGISTRY_FILE_VERSION;
  1375. if (!WriteFile (hFile, &dwTemp, sizeof(dwTemp), &dwBytesWritten, NULL) ||
  1376. dwBytesWritten != sizeof(dwTemp))
  1377. {
  1378. xe = GetLastError();
  1379. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to write version number with %d"),
  1380. GetLastError()));
  1381. CloseHandle (hFile);
  1382. return FALSE;
  1383. }
  1384. if ( lpGPOInfo->pWbemServices ) {
  1385. //
  1386. // If Rsop logging is enabled, setup hash table
  1387. //
  1388. pHashTable = AllocHashTable();
  1389. if ( pHashTable == NULL ) {
  1390. CloseHandle (hFile);
  1391. *phrRsopLogging = HRESULT_FROM_WIN32(GetLastError());
  1392. xe = GetLastError();
  1393. return FALSE;
  1394. }
  1395. }
  1396. //
  1397. // Now loop through the GPOs applying the registry.pol files
  1398. //
  1399. lpGPO = pChangedGPOList;
  1400. while ( lpGPO ) {
  1401. //
  1402. // Add the source GPO comment
  1403. //
  1404. lpGPOComment = (LPTSTR) LocalAlloc (LPTR, (lstrlen(lpGPO->lpDisplayName) + 25) * sizeof(TCHAR));
  1405. if (lpGPOComment) {
  1406. lstrcpy (szKeyName, TEXT("Software\\Policies\\Microsoft\\Windows\\Group Policy Objects\\"));
  1407. lstrcat (szKeyName, lpGPO->szGPOName);
  1408. lstrcpy (lpGPOComment, TEXT("**Comment:GPO Name: "));
  1409. lstrcat (lpGPOComment, lpGPO->lpDisplayName);
  1410. if (!ArchiveRegistryValue(hFile, szKeyName, lpGPOComment, REG_SZ, 0, NULL)) {
  1411. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ArchiveRegistryValue returned false.")));
  1412. }
  1413. LocalFree (lpGPOComment);
  1414. }
  1415. //
  1416. // Build the path to registry.pol
  1417. //
  1418. DmAssert( lstrlen(lpGPO->lpFileSysPath) + lstrlen(c_szRegistryPol) + 1 < MAX_PATH );
  1419. lstrcpy (szBuffer, lpGPO->lpFileSysPath);
  1420. lpEnd = CheckSlash (szBuffer);
  1421. lstrcpy (lpEnd, c_szRegistryPol);
  1422. if (!ParseRegistryFile (lpGPOInfo, szBuffer, SetRegistryValue, hFile,
  1423. lpGPO->lpDSPath, lpGPO->lpLink, pHashTable, FALSE )) {
  1424. xe = GetLastError();
  1425. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ParseRegistryFile failed.")));
  1426. CloseHandle (hFile);
  1427. FreeHashTable( pHashTable );
  1428. // no logging is done in any case
  1429. return FALSE;
  1430. }
  1431. if ( lpGPOInfo->pWbemServices ) {
  1432. //
  1433. // Log Adm data
  1434. //
  1435. HANDLE hFindFile;
  1436. WIN32_FILE_ATTRIBUTE_DATA attrData;
  1437. DWORD dwFilePathSize = lstrlen( lpGPO->lpFileSysPath );
  1438. TCHAR szComputerName[3*MAX_COMPUTERNAME_LENGTH + 1];
  1439. DWORD dwSize;
  1440. dwSize = 3*MAX_COMPUTERNAME_LENGTH + 1;
  1441. if (!GetComputerName(szComputerName, &dwSize)) {
  1442. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Couldn't get the computer Name with error %d."), GetLastError()));
  1443. szComputerName[0] = TEXT('\0');
  1444. }
  1445. dwSize = dwFilePathSize + MAX_PATH;
  1446. WCHAR *pwszEnd;
  1447. WCHAR *pwszFile = (WCHAR *) LocalAlloc( LPTR, dwSize * sizeof(WCHAR) );
  1448. if ( pwszFile == 0 ) {
  1449. xe = GetLastError();
  1450. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: ParseRegistryFile failed to allocate memory.")));
  1451. CloseHandle (hFile);
  1452. FreeHashTable( pHashTable );
  1453. // no logging is done in any case
  1454. return FALSE;
  1455. }
  1456. lstrcpy( pwszFile, lpGPO->lpFileSysPath );
  1457. //
  1458. // Strip off trailing 'machine' or 'user'
  1459. //
  1460. pwszEnd = pwszFile + lstrlen( pwszFile );
  1461. if ( lpGPOInfo->dwFlags & GP_MACHINE )
  1462. pwszEnd -= 7; // length of "machine"
  1463. else
  1464. pwszEnd -= 4; // length of "user"
  1465. lstrcpy( pwszEnd, L"Adm\\*.adm");
  1466. //
  1467. // Remember end point so that the actual Adm filename can be
  1468. // easily concatenated.
  1469. //
  1470. pwszEnd = pwszEnd + lstrlen( L"Adm\\" );
  1471. //
  1472. // Enumerate all Adm files
  1473. //
  1474. hFindFile = FindFirstFile( pwszFile, &findData);
  1475. if ( hFindFile != INVALID_HANDLE_VALUE )
  1476. {
  1477. do
  1478. {
  1479. if ( !(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
  1480. {
  1481. DmAssert( dwFilePathSize + lstrlen(findData.cFileName) + lstrlen( L"\\Adm\\" ) < dwSize );
  1482. lstrcpy( pwszEnd, findData.cFileName);
  1483. ZeroMemory (&attrData, sizeof(attrData));
  1484. if ( GetFileAttributesEx (pwszFile, GetFileExInfoStandard, &attrData ) != 0 ) {
  1485. if ( !AddAdmFile( pwszFile, lpGPO->lpDSPath, &attrData.ftLastWriteTime,
  1486. szComputerName, &pAdmFileCache ) ) {
  1487. DebugMsg((DM_WARNING,
  1488. TEXT("ProcessGPORegistryPolicy: AddAdmFile failed.")));
  1489. if (pHashTable->hrError == S_OK)
  1490. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  1491. }
  1492. }
  1493. } // if findData & file_attr_dir
  1494. } while ( FindNextFile(hFindFile, &findData) );// do
  1495. FindClose(hFindFile);
  1496. } // if hfindfile
  1497. LocalFree( pwszFile );
  1498. } // if rsoploggingenabled
  1499. lpGPO = lpGPO->pNext;
  1500. }
  1501. //
  1502. // Log registry data to Cimom database
  1503. //
  1504. if ( lpGPOInfo->pWbemServices ) {
  1505. if ( ! LogRegistryRsopData( lpGPOInfo->dwFlags, pHashTable, lpGPOInfo->pWbemServices ) ) {
  1506. DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Error when logging Registry Rsop data. Continuing.")));
  1507. if (pHashTable->hrError == S_OK)
  1508. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  1509. }
  1510. if ( ! LogAdmRsopData( pAdmFileCache, lpGPOInfo->pWbemServices ) ) {
  1511. DebugMsg((DM_WARNING, TEXT("ProcessGPOs: Error when logging Adm Rsop data. Continuing.")));
  1512. if (pHashTable->hrError == S_OK)
  1513. pHashTable->hrError = HRESULT_FROM_WIN32(GetLastError());
  1514. }
  1515. *phrRsopLogging = pHashTable->hrError;
  1516. }
  1517. FreeHashTable( pHashTable );
  1518. FreeAdmFileCache( pAdmFileCache );
  1519. CloseHandle (hFile);
  1520. #if 0
  1521. //
  1522. // Set the security on the file
  1523. //
  1524. if (!MakeFileSecure (szPath, 0)) {
  1525. DebugMsg((DM_WARNING, TEXT("ProcessGPORegistryPolicy: Failed to set security on the group policy registry file with %d"),
  1526. GetLastError()));
  1527. }
  1528. #endif
  1529. return TRUE;
  1530. }
  1531. //*************************************************************
  1532. //
  1533. // AddAdmFile()
  1534. //
  1535. // Purpose: Prepends to list of Adm files
  1536. //
  1537. // Parameters: pwszFile - File path
  1538. // pwszGPO - Gpo
  1539. // pftWrite - Last write time
  1540. // ppAdmFileCache - List of Adm files processed
  1541. //
  1542. //*************************************************************
  1543. BOOL AddAdmFile( WCHAR *pwszFile, WCHAR *pwszGPO, FILETIME *pftWrite, WCHAR *szComputerName,
  1544. ADMFILEINFO **ppAdmFileCache )
  1545. {
  1546. XPtrLF<WCHAR> xszLongPath;
  1547. LPTSTR pwszUNCPath;
  1548. DebugMsg((DM_VERBOSE, TEXT("AllocAdmFileInfo: Adding File name <%s> to the Adm list."), pwszFile));
  1549. if ((szComputerName) && (*szComputerName) && (!IsUNCPath(pwszFile))) {
  1550. xszLongPath = MakePathUNC(pwszFile, szComputerName);
  1551. if (!xszLongPath) {
  1552. DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to Make the path UNC with error %d."), GetLastError()));
  1553. return FALSE;
  1554. }
  1555. pwszUNCPath = xszLongPath;
  1556. }
  1557. else
  1558. pwszUNCPath = pwszFile;
  1559. ADMFILEINFO *pAdmInfo = AllocAdmFileInfo( pwszUNCPath, pwszGPO, pftWrite );
  1560. if ( pAdmInfo == NULL )
  1561. return FALSE;
  1562. pAdmInfo->pNext = *ppAdmFileCache;
  1563. *ppAdmFileCache = pAdmInfo;
  1564. return TRUE;
  1565. }
  1566. //*************************************************************
  1567. //
  1568. // FreeAdmFileCache()
  1569. //
  1570. // Purpose: Frees Adm File list
  1571. //
  1572. // Parameters: pAdmFileCache - List of Adm files to free
  1573. //
  1574. //
  1575. //*************************************************************
  1576. void FreeAdmFileCache( ADMFILEINFO *pAdmFileCache )
  1577. {
  1578. ADMFILEINFO *pNext;
  1579. while ( pAdmFileCache ) {
  1580. pNext = pAdmFileCache->pNext;
  1581. FreeAdmFileInfo( pAdmFileCache );
  1582. pAdmFileCache = pNext;
  1583. }
  1584. }
  1585. //*************************************************************
  1586. //
  1587. // AllocAdmFileInfo()
  1588. //
  1589. // Purpose: Allocates a new struct for ADMFILEINFO
  1590. //
  1591. // Parameters: pwszFile - File name
  1592. // pwszGPO - Gpo
  1593. // pftWrite - Last write time
  1594. //
  1595. //
  1596. //*************************************************************
  1597. ADMFILEINFO * AllocAdmFileInfo( WCHAR *pwszFile, WCHAR *pwszGPO, FILETIME *pftWrite )
  1598. {
  1599. XLastError xe;
  1600. ADMFILEINFO *pAdmFileInfo = (ADMFILEINFO *) LocalAlloc( LPTR, sizeof(ADMFILEINFO) );
  1601. if ( pAdmFileInfo == NULL ) {
  1602. DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to allocate memory.")));
  1603. return NULL;
  1604. }
  1605. pAdmFileInfo->pwszFile = (WCHAR *) LocalAlloc( LPTR, (lstrlen(pwszFile) + 1) * sizeof(WCHAR) );
  1606. if ( pAdmFileInfo->pwszFile == NULL ) {
  1607. xe = GetLastError();
  1608. DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to allocate memory.")));
  1609. LocalFree( pAdmFileInfo );
  1610. return NULL;
  1611. }
  1612. pAdmFileInfo->pwszGPO = (WCHAR *) LocalAlloc( LPTR, (lstrlen(pwszGPO) + 1) * sizeof(WCHAR) );
  1613. if ( pAdmFileInfo->pwszGPO == NULL ) {
  1614. xe = GetLastError();
  1615. DebugMsg((DM_WARNING, TEXT("AllocAdmFileInfo: Failed to allocate memory.")));
  1616. LocalFree( pAdmFileInfo->pwszFile );
  1617. LocalFree( pAdmFileInfo );
  1618. return NULL;
  1619. }
  1620. lstrcpy( pAdmFileInfo->pwszFile, pwszFile );
  1621. lstrcpy( pAdmFileInfo->pwszGPO, pwszGPO );
  1622. pAdmFileInfo->ftWrite = *pftWrite;
  1623. return pAdmFileInfo;
  1624. }
  1625. //*************************************************************
  1626. //
  1627. // FreeAdmFileInfo()
  1628. //
  1629. // Purpose: Deletes a ADMFILEINFO struct
  1630. //
  1631. // Parameters: pAdmFileInfo - Struct to delete
  1632. // pftWrite - Last write time
  1633. //
  1634. //
  1635. //*************************************************************
  1636. void FreeAdmFileInfo( ADMFILEINFO *pAdmFileInfo )
  1637. {
  1638. if ( pAdmFileInfo ) {
  1639. LocalFree( pAdmFileInfo->pwszFile );
  1640. LocalFree( pAdmFileInfo->pwszGPO );
  1641. LocalFree( pAdmFileInfo );
  1642. }
  1643. }