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.

547 lines
20 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: config.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include <shlwapi.h>
  13. #include "config.h"
  14. #include "util.h"
  15. #include "strings.h"
  16. LPCTSTR CConfig::s_rgpszSubkeys[] = { REGSTR_KEY_OFFLINEFILES,
  17. REGSTR_KEY_OFFLINEFILESPOLICY };
  18. LPCTSTR CConfig::s_rgpszValues[] = { REGSTR_VAL_DEFCACHESIZE,
  19. REGSTR_VAL_CSCENABLED,
  20. REGSTR_VAL_GOOFFLINEACTION,
  21. REGSTR_VAL_NOCONFIGCACHE,
  22. REGSTR_VAL_NOCACHEVIEWER,
  23. REGSTR_VAL_NOMAKEAVAILABLEOFFLINE,
  24. REGSTR_VAL_SYNCATLOGOFF,
  25. REGSTR_VAL_SYNCATLOGON,
  26. REGSTR_VAL_SYNCATSUSPEND,
  27. REGSTR_VAL_NOREMINDERS,
  28. REGSTR_VAL_REMINDERFREQMINUTES,
  29. REGSTR_VAL_INITIALBALLOONTIMEOUTSECONDS,
  30. REGSTR_VAL_REMINDERBALLOONTIMEOUTSECONDS,
  31. REGSTR_VAL_EVENTLOGGINGLEVEL,
  32. REGSTR_VAL_PURGEATLOGOFF,
  33. REGSTR_VAL_PURGEONLYAUTOCACHEATLOGOFF,
  34. REGSTR_VAL_FIRSTPINWIZARDSHOWN,
  35. REGSTR_VAL_SLOWLINKSPEED,
  36. REGSTR_VAL_ALWAYSPINSUBFOLDERS,
  37. REGSTR_VAL_ENCRYPTCACHE,
  38. REGSTR_VAL_NOFRADMINPIN
  39. };
  40. //
  41. // Returns the single instance of the CConfig class.
  42. // Note that by making the singleton instance a function static
  43. // object it is not created until the first call to GetSingleton.
  44. //
  45. CConfig& CConfig::GetSingleton(
  46. void
  47. )
  48. {
  49. static CConfig TheConfig;
  50. return TheConfig;
  51. }
  52. //
  53. // This is the workhorse of the CSCUI policy code for scalar values.
  54. // The caller passes in a value (iVAL_XXXXXX) identifier from the eValues
  55. // enumeration to identify the policy/preference value of interest.
  56. // Known keys in the registry are scanned until a value is found.
  57. // The scanning order enforces the precedence of policy vs. default vs.
  58. // preference and machine vs. user.
  59. //
  60. DWORD CConfig::GetValue(
  61. eValues iValue,
  62. bool *pbSetByPolicy
  63. ) const
  64. {
  65. //
  66. // This table identifies each DWORD policy/preference item used by CSCUI.
  67. // The entries MUST be ordered the same as the eValues enumeration.
  68. // Each entry describes the possible sources for data and a default value
  69. // to be used if no registry entries are present or if there's a problem reading
  70. // the registry.
  71. //
  72. static const struct Item
  73. {
  74. DWORD fSrc; // Mask indicating the reg locations to read.
  75. DWORD dwDefault; // Hard-coded default.
  76. } rgItems[] = {
  77. // Value ID eSRC_PREF_CU | eSRC_PREF_LM | eSRC_POL_CU | eSRC_POL_LM Default value
  78. // -------------------------------------- ------------ ------------ ----------- ----------- -------------------
  79. /* iVAL_DEFCACHESIZE */ { eSRC_POL_LM, 1000 },
  80. /* iVAL_CSCENABLED */ { eSRC_POL_LM, 1 },
  81. /* iVAL_GOOFFLINEACTION */ { eSRC_PREF_CU | eSRC_POL_CU | eSRC_POL_LM, eGoOfflineSilent },
  82. /* iVAL_NOCONFIGCACHE */ { eSRC_POL_CU | eSRC_POL_LM, 0 },
  83. /* iVAL_NOCACHEVIEWER */ { eSRC_POL_CU | eSRC_POL_LM, 0 },
  84. /* iVAL_NOMAKEAVAILABLEOFFLINE */ { eSRC_POL_CU | eSRC_POL_LM, 0 },
  85. /* iVAL_SYNCATLOGOFF */ { eSRC_PREF_CU | eSRC_POL_CU | eSRC_POL_LM, eSyncFull },
  86. /* iVAL_SYNCATLOGON */ { eSRC_PREF_CU | eSRC_POL_CU | eSRC_POL_LM, eSyncNone },
  87. /* iVAL_SYNCATSUSPEND */ { eSRC_POL_CU | eSRC_POL_LM, eSyncNone },
  88. /* iVAL_NOREMINDERS */ { eSRC_PREF_CU | eSRC_POL_CU | eSRC_POL_LM, 0 },
  89. /* iVAL_REMINDERFREQMINUTES */ { eSRC_PREF_CU | eSRC_POL_CU | eSRC_POL_LM, 60 },
  90. /* iVAL_INITIALBALLOONTIMEOUTSECONDS */ { eSRC_POL_CU | eSRC_POL_LM, 30 },
  91. /* iVAL_REMINDERBALLOONTIMEOUTSECONDS */ { eSRC_POL_CU | eSRC_POL_LM, 15 },
  92. /* iVAL_EVENTLOGGINGLEVEL */ { eSRC_PREF_CU | eSRC_PREF_LM | eSRC_POL_CU | eSRC_POL_LM, 0 },
  93. /* iVAL_PURGEATLOGOFF */ { eSRC_POL_LM, 0 },
  94. /* iVAL_PURGEONLYAUTOCACHEATLOGOFF */ { eSRC_POL_LM, 0 },
  95. /* iVAL_FIRSTPINWIZARDSHOWN */ { eSRC_PREF_CU , 0 },
  96. /* iVAL_SLOWLINKSPEED */ { eSRC_PREF_CU | eSRC_PREF_LM | eSRC_POL_CU | eSRC_POL_LM, 640 },
  97. /* iVAL_ALWAYSPINSUBFOLDERS */ { eSRC_POL_LM, 0 },
  98. /* iVAL_ENCRYPTCACHE */ { eSRC_PREF_LM | eSRC_POL_LM, 0 },
  99. /* iVAL_NOFRADMINPIN */ { eSRC_POL_CU | eSRC_POL_LM, 0 }
  100. };
  101. //
  102. // This table maps registry keys and subkey names to our
  103. // source mask values. The array is ordered with the highest
  104. // precedence sources first. A policy level mask is also
  105. // associated with each entry so that we honor the "big switch"
  106. // for enabling/disabling CSCUI policies.
  107. //
  108. static const struct Source
  109. {
  110. eSources fSrc; // Source for reg data.
  111. HKEY hkeyRoot; // Root key in registry (hkcu, hklm).
  112. eSubkeys iSubkey; // Index into s_rgpszSubkeys[]
  113. } rgSrcs[] = { { eSRC_POL_LM, HKEY_LOCAL_MACHINE, iSUBKEY_POL },
  114. { eSRC_POL_CU, HKEY_CURRENT_USER, iSUBKEY_POL },
  115. { eSRC_PREF_CU, HKEY_CURRENT_USER, iSUBKEY_PREF },
  116. { eSRC_PREF_LM, HKEY_LOCAL_MACHINE, iSUBKEY_PREF }
  117. };
  118. const Item& item = rgItems[iValue];
  119. DWORD dwResult = item.dwDefault; // Set default return value.
  120. bool bSetByPolicy = false;
  121. //
  122. // Iterate over all of the sources until we find one that is specified
  123. // for this item. For each iteration, if we're able to read the value,
  124. // that's the one we return. If not we drop down to the next source
  125. // in the precedence order (rgSrcs[]) and try to read it's value. If
  126. // we've tried all of the sources without a successful read we return the
  127. // hard-coded default.
  128. //
  129. for (int i = 0; i < ARRAYSIZE(rgSrcs); i++)
  130. {
  131. const Source& src = rgSrcs[i];
  132. //
  133. // Is this source valid for this item?
  134. //
  135. if (0 != (src.fSrc & item.fSrc))
  136. {
  137. //
  138. // This source is valid for this item. Read it.
  139. //
  140. DWORD cbResult = sizeof(dwResult);
  141. DWORD dwType;
  142. if (ERROR_SUCCESS == SHGetValue(src.hkeyRoot,
  143. s_rgpszSubkeys[src.iSubkey],
  144. s_rgpszValues[iValue],
  145. &dwType,
  146. &dwResult,
  147. &cbResult))
  148. {
  149. //
  150. // We read a value from the registry so we're done.
  151. //
  152. bSetByPolicy = (0 != (eSRC_POL & src.fSrc));
  153. break;
  154. }
  155. }
  156. }
  157. if (NULL != pbSetByPolicy)
  158. *pbSetByPolicy = bSetByPolicy;
  159. return dwResult;
  160. }
  161. //
  162. // Save a custom GoOfflineAction list to the registry.
  163. // See comments for LoadCustomGoOfflineActions for formatting details.
  164. //
  165. HRESULT
  166. CConfig::SaveCustomGoOfflineActions(
  167. HKEY hkey,
  168. HDPA hdpaGOA
  169. )
  170. {
  171. if (NULL == hdpaGOA)
  172. {
  173. return E_INVALIDARG;
  174. }
  175. HRESULT hr = NOERROR;
  176. TCHAR szServer[MAX_PATH];
  177. TCHAR szAction[20];
  178. const int cGOA = DPA_GetPtrCount(hdpaGOA);
  179. for (int i = 0; i < cGOA; i++)
  180. {
  181. //
  182. // Write each sharename-action pair to the registry.
  183. // The action value must be converted to ASCII to be
  184. // compatible with the values generated by poledit.
  185. //
  186. CustomGOA *pGOA = (CustomGOA *)DPA_GetPtr(hdpaGOA, i);
  187. if (NULL != pGOA)
  188. {
  189. wnsprintf(szAction, ARRAYSIZE(szAction), TEXT("%d"), DWORD(pGOA->GetAction()));
  190. pGOA->GetServerName(szServer, ARRAYSIZE(szServer));
  191. DWORD dwResult = RegSetValueEx(hkey,
  192. szServer,
  193. 0,
  194. REG_SZ,
  195. (CONST BYTE *)szAction,
  196. (lstrlen(szAction)+1) * sizeof(szAction[0]));
  197. hr = HRESULT_FROM_WIN32(dwResult);
  198. if (FAILED(hr))
  199. {
  200. Trace((TEXT("Error 0x%08X saving GoOfflineAction for \"%s\" to registry."),
  201. hr, szServer));
  202. break;
  203. }
  204. }
  205. }
  206. return hr;
  207. }
  208. bool
  209. CConfig::CustomGOAExists(
  210. HDPA hdpaGOA,
  211. const CustomGOA& goa
  212. )
  213. {
  214. if (NULL != hdpaGOA)
  215. {
  216. const int cEntries = DPA_GetPtrCount(hdpaGOA);
  217. for (int i = 0; i < cEntries; i++)
  218. {
  219. CustomGOA *pGOA = (CustomGOA *)DPA_GetPtr(hdpaGOA, i);
  220. if (NULL != pGOA)
  221. {
  222. if (0 == goa.CompareByServer(*pGOA))
  223. return true;
  224. }
  225. }
  226. }
  227. return false;
  228. }
  229. //
  230. // Builds an array of Go-offline actions.
  231. // Each entry is a server-action pair.
  232. //
  233. void
  234. CConfig::GetCustomGoOfflineActions(
  235. HDPA hdpa,
  236. bool *pbSetByPolicy // optional. Can be NULL.
  237. )
  238. {
  239. TraceAssert(NULL != hdpa);
  240. static const struct Source
  241. {
  242. eSources fSrc; // Source for reg data.
  243. HKEY hkeyRoot; // Root key in registry (hkcu, hklm).
  244. eSubkeys iSubkey; // Index into s_rgpszSubkeys[]
  245. } rgSrcs[] = { { eSRC_POL_LM, HKEY_LOCAL_MACHINE, iSUBKEY_POL },
  246. { eSRC_POL_CU, HKEY_CURRENT_USER, iSUBKEY_POL },
  247. { eSRC_PREF_CU, HKEY_CURRENT_USER, iSUBKEY_PREF }
  248. };
  249. ClearCustomGoOfflineActions(hdpa);
  250. bool bSetByPolicyAny = false;
  251. bool bSetByPolicy = false;
  252. //
  253. // Iterate over all of the possible sources.
  254. //
  255. for (int i = 0; i < ARRAYSIZE(rgSrcs); i++)
  256. {
  257. const Source& src = rgSrcs[i];
  258. HKEY hkey;
  259. DWORD dwResult = RegOpenKeyEx(src.hkeyRoot,
  260. s_rgpszSubkeys[src.iSubkey],
  261. 0,
  262. KEY_READ,
  263. &hkey);
  264. if (ERROR_SUCCESS == dwResult)
  265. {
  266. HKEY hkeyGOA;
  267. dwResult = RegOpenKeyEx(hkey,
  268. REGSTR_SUBKEY_CUSTOMGOOFFLINEACTIONS,
  269. 0,
  270. KEY_READ,
  271. &hkeyGOA);
  272. if (ERROR_SUCCESS == dwResult)
  273. {
  274. TCHAR szName[MAX_PATH];
  275. TCHAR szValue[20];
  276. DWORD dwIndex = 0;
  277. do
  278. {
  279. DWORD dwType;
  280. DWORD cbValue = sizeof(szValue);
  281. DWORD cchName = ARRAYSIZE(szName);
  282. dwResult = RegEnumValue(hkeyGOA,
  283. dwIndex,
  284. szName,
  285. &cchName,
  286. NULL,
  287. &dwType,
  288. (LPBYTE)szValue,
  289. &cbValue);
  290. if (ERROR_SUCCESS == dwResult)
  291. {
  292. dwIndex++;
  293. if (REG_SZ == dwType)
  294. {
  295. //
  296. // Convert from "0","1","2" to 0,1,2
  297. //
  298. DWORD dwValue = szValue[0] - TEXT('0');
  299. if (IsValidGoOfflineAction(dwValue))
  300. {
  301. //
  302. // Only add if value is of proper type and value.
  303. // Protects against someone manually adding garbage
  304. // to the registry.
  305. //
  306. // Server names can also be entered into the registry
  307. // using poledit (and winnt.adm). This entry mechanism
  308. // can't validate format so we need to ensure the entry
  309. // doesn't have leading '\' or space characters.
  310. //
  311. LPCTSTR pszServer = szName;
  312. while(*pszServer && (TEXT('\\') == *pszServer || TEXT(' ') == *pszServer))
  313. pszServer++;
  314. bSetByPolicy = (0 != (src.fSrc & eSRC_POL));
  315. bSetByPolicyAny = bSetByPolicyAny || bSetByPolicy;
  316. CustomGOA *pGOA = new CustomGOA(pszServer,
  317. (CConfig::OfflineAction)dwValue,
  318. bSetByPolicy);
  319. if (NULL != pGOA)
  320. {
  321. if (CustomGOAExists(hdpa, *pGOA) || -1 == DPA_AppendPtr(hdpa, pGOA))
  322. {
  323. delete pGOA;
  324. }
  325. }
  326. }
  327. else
  328. {
  329. Trace((TEXT("GoOfflineAction value %d invalid for \"%s\""),
  330. dwValue, szName));
  331. }
  332. }
  333. else
  334. {
  335. Trace((TEXT("GoOfflineAction for \"%s\" has invalid reg type %d"),
  336. szName, dwType));
  337. }
  338. }
  339. }
  340. while(ERROR_SUCCESS == dwResult);
  341. RegCloseKey(hkeyGOA);
  342. }
  343. RegCloseKey(hkey);
  344. }
  345. }
  346. if (NULL != pbSetByPolicy)
  347. *pbSetByPolicy = bSetByPolicyAny;
  348. }
  349. //
  350. // Delete all CustomGOA blocks attached to a DPA.
  351. // When complete, the DPA is empty.
  352. //
  353. void
  354. CConfig::ClearCustomGoOfflineActions( // [static]
  355. HDPA hdpaGOA
  356. )
  357. {
  358. if (NULL != hdpaGOA)
  359. {
  360. const int cEntries = DPA_GetPtrCount(hdpaGOA);
  361. for (int i = cEntries - 1; 0 <= i; i--)
  362. {
  363. CustomGOA *pGOA = (CustomGOA *)DPA_GetPtr(hdpaGOA, i);
  364. delete pGOA;
  365. DPA_DeletePtr(hdpaGOA, i);
  366. }
  367. }
  368. }
  369. //
  370. // Retrieve the go-offline action for a specific server. If the server
  371. // has a "customized" action defined by either system policy or user
  372. // setting, that action is used. Otherwise, the "default" action is
  373. // used.
  374. //
  375. int
  376. CConfig::GoOfflineAction(
  377. LPCTSTR pszServer
  378. ) const
  379. {
  380. int iAction = GoOfflineAction(); // Get default action.
  381. if (NULL == pszServer)
  382. return iAction;
  383. TraceAssert(NULL != pszServer);
  384. //
  385. // Skip passed any leading backslashes for comparison.
  386. // The values we store in the registry don't have a leading "\\".
  387. //
  388. while(*pszServer && TEXT('\\') == *pszServer)
  389. pszServer++;
  390. HRESULT hr;
  391. CConfig::OfflineActionInfo info;
  392. CConfig::OfflineActionIter iter = CreateOfflineActionIter();
  393. while(S_OK == (hr = iter.Next(&info)))
  394. {
  395. if (0 == lstrcmpi(pszServer, info.szServer))
  396. {
  397. iAction = info.iAction; // Return custom action.
  398. break;
  399. }
  400. }
  401. //
  402. // Guard against bogus reg data.
  403. //
  404. if (eNumOfflineActions <= iAction || 0 > iAction)
  405. iAction = eGoOfflineSilent;
  406. return iAction;
  407. }
  408. //-----------------------------------------------------------------------------
  409. // CConfig::CustomGOA
  410. // "GOA" is "Go Offline Action"
  411. //-----------------------------------------------------------------------------
  412. bool
  413. CConfig::CustomGOA::operator < (
  414. const CustomGOA& rhs
  415. ) const
  416. {
  417. int diff = CompareByServer(rhs);
  418. if (0 == diff)
  419. diff = m_action - rhs.m_action;
  420. return diff < 0;
  421. }
  422. //
  423. // Compare two CustomGoOfflineAction objects by their
  424. // server names. Comparison is case-insensitive.
  425. // Returns: <0 = *this < rhs
  426. // 0 = *this == rhs
  427. // >0 = *this > rhs
  428. //
  429. int
  430. CConfig::CustomGOA::CompareByServer(
  431. const CustomGOA& rhs
  432. ) const
  433. {
  434. return lstrcmpi(GetServerName(), rhs.GetServerName());
  435. }
  436. //-----------------------------------------------------------------------------
  437. // CConfig::OfflineActionIter
  438. //-----------------------------------------------------------------------------
  439. CConfig::OfflineActionIter::OfflineActionIter(
  440. const CConfig *pConfig
  441. ) : m_pConfig(const_cast<CConfig *>(pConfig)),
  442. m_iAction(-1),
  443. m_hdpaGOA(DPA_Create(4))
  444. {
  445. }
  446. CConfig::OfflineActionIter::~OfflineActionIter(
  447. void
  448. )
  449. {
  450. if (NULL != m_hdpaGOA)
  451. {
  452. CConfig::ClearCustomGoOfflineActions(m_hdpaGOA);
  453. DPA_Destroy(m_hdpaGOA);
  454. }
  455. }
  456. HRESULT
  457. CConfig::OfflineActionIter::Next(
  458. OfflineActionInfo *pInfo
  459. )
  460. {
  461. if (NULL == m_hdpaGOA)
  462. {
  463. return E_OUTOFMEMORY;
  464. }
  465. HRESULT hr = S_FALSE;
  466. if (-1 == m_iAction)
  467. {
  468. m_pConfig->GetCustomGoOfflineActions(m_hdpaGOA);
  469. m_iAction = 0;
  470. }
  471. if (m_iAction < DPA_GetPtrCount(m_hdpaGOA))
  472. {
  473. CustomGOA *pGOA = (CustomGOA *)DPA_GetPtr(m_hdpaGOA, m_iAction);
  474. if (NULL != pGOA)
  475. {
  476. hr = StringCchCopy(pInfo->szServer, ARRAYSIZE(pInfo->szServer), pGOA->GetServerName());
  477. pInfo->iAction = (DWORD)pGOA->GetAction();
  478. m_iAction++;
  479. }
  480. }
  481. return hr;
  482. }