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.

485 lines
16 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: excladdr.cxx
  4. //
  5. // Contents: Implements classes for managing the current address
  6. // exclusion list
  7. //
  8. // Classes: CAddrExclusionMgr
  9. //
  10. // History: 07-Oct-00 jsimmons Created
  11. //--------------------------------------------------------------------
  12. #include "act.hxx"
  13. // The single instance of this object
  14. CAddrExclusionMgr gAddrExclusionMgr;
  15. CAddrExclusionMgr::CAddrExclusionMgr() :
  16. _dwNumStrings(0),
  17. _ppszStrings(NULL),
  18. _bInitRegistry(FALSE)
  19. {
  20. }
  21. //
  22. // GetExclusionList
  23. //
  24. // Returns the current exclusion list.
  25. //
  26. HRESULT CAddrExclusionMgr::GetExclusionList(
  27. DWORD* pdwNumStrings,
  28. LPWSTR** pppszStrings)
  29. {
  30. gpClientLock->LockExclusive();
  31. // Handle easy case
  32. if (_dwNumStrings == 0)
  33. {
  34. *pdwNumStrings = 0;
  35. *pppszStrings = NULL;
  36. gpClientLock->UnlockExclusive();
  37. return S_OK;
  38. }
  39. DWORD i;
  40. DWORD dwCopiedStrings;
  41. LPWSTR* ppszCopiedStrings;
  42. ppszCopiedStrings = (LPWSTR*)MIDL_user_allocate(sizeof(WCHAR*) * _dwNumStrings);
  43. if (!ppszCopiedStrings)
  44. {
  45. gpClientLock->UnlockExclusive();
  46. return E_OUTOFMEMORY;
  47. }
  48. dwCopiedStrings = 0;
  49. for (i = 0; i < _dwNumStrings; i++)
  50. {
  51. if (_ppszStrings[i])
  52. {
  53. ppszCopiedStrings[i] = (LPWSTR)MIDL_user_allocate(
  54. sizeof(WCHAR) * (lstrlen(_ppszStrings[i]) + 1));
  55. if (!ppszCopiedStrings[i])
  56. {
  57. // failure in the middle. cleanup previous allocations and return
  58. for (i = 0; i < _dwNumStrings; i++)
  59. {
  60. if (ppszCopiedStrings[i])
  61. MIDL_user_free(ppszCopiedStrings[i]);
  62. }
  63. MIDL_user_free(ppszCopiedStrings);
  64. gpClientLock->UnlockExclusive();
  65. return E_OUTOFMEMORY;
  66. }
  67. lstrcpy(ppszCopiedStrings[i], _ppszStrings[i]);
  68. dwCopiedStrings++;
  69. }
  70. }
  71. *pdwNumStrings = dwCopiedStrings;
  72. *pppszStrings = ppszCopiedStrings;
  73. gpClientLock->UnlockExclusive();
  74. return S_OK;
  75. }
  76. //
  77. // SetExclusionList
  78. //
  79. // Sets the current exclusion list, and pushes the
  80. // new bindings to all current running processes
  81. // registered with COM.
  82. //
  83. HRESULT CAddrExclusionMgr::SetExclusionList(
  84. DWORD dwNumStrings,
  85. LPWSTR* ppszStrings)
  86. {
  87. HRESULT hr = S_OK;
  88. RPC_STATUS status;
  89. DWORD i, j;
  90. LPWSTR* ppszStringsNew = NULL;
  91. gpClientLock->LockExclusive();
  92. if (dwNumStrings > 0)
  93. {
  94. ppszStringsNew = (LPWSTR*)PrivMemAlloc(sizeof(WCHAR*) * dwNumStrings);
  95. if (!ppszStringsNew)
  96. {
  97. gpClientLock->UnlockExclusive();
  98. return E_OUTOFMEMORY;
  99. }
  100. for (i = 0; i < dwNumStrings; i++)
  101. {
  102. // Skip any null entries. Assert in debug builds since
  103. // this is likely a sign of a broken app
  104. ASSERT(ppszStrings[i]);
  105. if (!ppszStrings[i])
  106. continue;
  107. ppszStringsNew[i] = (LPWSTR)PrivMemAlloc(
  108. sizeof(WCHAR) * (lstrlen(ppszStrings[i]) + 1));
  109. if (!ppszStringsNew[i])
  110. {
  111. // free up any earlier allocations that succeeded
  112. for (j = 0; j < i; j++)
  113. PrivMemFree(ppszStringsNew[j]);
  114. PrivMemFree(ppszStringsNew);
  115. gpClientLock->UnlockExclusive();
  116. // and return error
  117. return E_OUTOFMEMORY;
  118. }
  119. lstrcpy(ppszStringsNew[i], ppszStrings[i]);
  120. }
  121. }
  122. // Get rid of the old list
  123. FreeCurrentBuffers();
  124. // Save off the new one
  125. _dwNumStrings = dwNumStrings;
  126. _ppszStrings = ppszStringsNew;
  127. // Recompute the bindings
  128. status = ComputeNewResolverBindings();
  129. if (status == RPC_S_OK)
  130. {
  131. // Update currently running processes
  132. PushCurrentBindings();
  133. }
  134. else
  135. hr = E_OUTOFMEMORY;
  136. gpClientLock->UnlockExclusive();
  137. return hr;
  138. }
  139. //
  140. // EnableDisableDynamicTracking
  141. //
  142. // Turns on\off the dynamic address binding feature, and updates
  143. // the registry key accordingly.
  144. //
  145. HRESULT CAddrExclusionMgr::EnableDisableDynamicTracking(BOOL fEnable)
  146. {
  147. HRESULT hr = S_OK;
  148. LONG error;
  149. HKEY hOle;
  150. WCHAR* szY = L"Y";
  151. WCHAR* szN = L"N";
  152. gpClientLock->LockExclusive();
  153. // Open the registry key and change the value
  154. error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  155. L"SOFTWARE\\Microsoft\\OLE",
  156. NULL,
  157. KEY_WRITE,
  158. &hOle);
  159. if (error == ERROR_SUCCESS)
  160. {
  161. error = RegSetValueEx(hOle,
  162. L"EnableSystemDynamicIPTracking",
  163. 0,
  164. REG_SZ,
  165. (BYTE*)(fEnable ? szY : szN),
  166. 4); // 4 = one wchar + null
  167. if (error == ERROR_SUCCESS)
  168. {
  169. // Reset the global. Will be seen immediately
  170. gbDynamicIPChangesEnabled = fEnable ? TRUE : FALSE;
  171. }
  172. else
  173. hr = HRESULT_FROM_WIN32(GetLastError());
  174. CloseHandle(hOle);
  175. }
  176. else
  177. hr = HRESULT_FROM_WIN32(GetLastError());
  178. gpClientLock->UnlockExclusive();
  179. return hr;
  180. }
  181. //
  182. // IsExcludedAddress
  183. //
  184. // Checks to see if the specified address is in our
  185. // current exclusion list.
  186. //
  187. BOOL CAddrExclusionMgr::IsExcludedAddress(LPWSTR pszAddress)
  188. {
  189. DWORD i;
  190. ASSERT(gpClientLock->HeldExclusive());
  191. ASSERT(_ppszStrings);
  192. for (i = 0; i < _dwNumStrings; i++)
  193. {
  194. if (_ppszStrings[i])
  195. {
  196. if (lstrcmpi(_ppszStrings[i], pszAddress) == 0)
  197. {
  198. // found it in the list
  199. return TRUE;
  200. }
  201. }
  202. }
  203. return FALSE;
  204. }
  205. //
  206. // BuildExclusionDSA
  207. //
  208. // Constructs a new dsa and puts it in *ppdsaOut; the new
  209. // dsa is the same as pdsaSrc, minus any addresses that are
  210. // currently in the exclusion list.
  211. //
  212. HRESULT CAddrExclusionMgr::BuildExclusionDSA(
  213. DUALSTRINGARRAY* pdsaSrc,
  214. DUALSTRINGARRAY** ppdsaOut
  215. )
  216. {
  217. ASSERT(pdsaSrc && ppdsaOut);
  218. ASSERT(dsaValid(pdsaSrc));
  219. ASSERT(gpClientLock->HeldExclusive());
  220. SCMVDATEHEAP();
  221. DWORD i;
  222. BOOL bDone;
  223. USHORT* pStart;
  224. USHORT* pCurrent;
  225. USHORT* pCurrentNew;
  226. DWORD dwBindingsToExclude = 0;
  227. USHORT usNewDSALen = 0;
  228. DUALSTRINGARRAY* pdsaNew;
  229. BOOL* afIsExcludedAddress;
  230. *ppdsaOut = NULL;
  231. // If our list is empty, nothing to do
  232. if (_dwNumStrings == 0)
  233. return dsaAllocateAndCopy(ppdsaOut, pdsaSrc);
  234. // Allocate an array of bools on the stack. This
  235. // will be used to remember if an address is excluded
  236. // or not on the first pass, so we don't have to be
  237. // figure that out again on the second pass.
  238. //
  239. // Note that I will almost always allocate too much stack
  240. // memory -- better that than not enough. To be exact
  241. // I'd have to make an extra pass thru the dsa to see how
  242. // many string bindings there are - which sorta defeats
  243. // the purpose.
  244. afIsExcludedAddress = (BOOL*)_alloca(sizeof(BOOL) * pdsaSrc->wSecurityOffset);
  245. // First make one pass thru the incoming dsa to
  246. // see how many addresses we should retain, and
  247. // calculate how much space they will need.
  248. bDone = FALSE;
  249. pStart = pCurrent = &(pdsaSrc->aStringArray[0]);
  250. i = 0;
  251. do
  252. {
  253. // Find end of the current string binding. Be careful
  254. // to handle cases where there are no string bindings.
  255. while (*pCurrent != 0)
  256. pCurrent++;
  257. if ((i > 0) && (pCurrent == pStart) ||
  258. ((i == 0) && (*(pCurrent+1) == 0)))
  259. {
  260. // either found a zero after the previous
  261. // binding, or we found two zeroes in a row
  262. // at the beginning of pdsaSrc->aStringArray.
  263. bDone = TRUE;
  264. }
  265. else
  266. {
  267. i++; // count total # of strings found
  268. STRINGBINDING* psb = (STRINGBINDING*)pStart;
  269. // We only exclude addresses if they are using tcp
  270. if (psb->wTowerId == ID_TCP &&
  271. IsExcludedAddress(&(psb->aNetworkAddr)))
  272. {
  273. dwBindingsToExclude++;
  274. afIsExcludedAddress[i] = TRUE;
  275. }
  276. else
  277. {
  278. // Add string len plus 2 (space for towerid + null terminator)
  279. usNewDSALen += (lstrlen(&(psb->aNetworkAddr)) + 2);
  280. afIsExcludedAddress[i] = FALSE;
  281. }
  282. // advance to next string binding
  283. pCurrent++;
  284. pStart = pCurrent;
  285. }
  286. } while (!bDone);
  287. // If there are no addresses that need excluding, just copy
  288. // and return the incoming bindings.
  289. if (dwBindingsToExclude == 0)
  290. return dsaAllocateAndCopy(ppdsaOut, pdsaSrc);
  291. // If we didn't find any string bindings to use at all, then we
  292. // need to manually add a word for the initial NULL.
  293. if (usNewDSALen == 0)
  294. usNewDSALen = 1;
  295. // Add space for wNumEntries + wSecurityOffset
  296. usNewDSALen += (sizeof(USHORT) * 2);
  297. // Add size of all security bindings
  298. usNewDSALen += ((pdsaSrc->wNumEntries - pdsaSrc->wSecurityOffset));
  299. // Add one for the string bindings terminating NULL.
  300. usNewDSALen++;
  301. // Allocate the memory
  302. pdsaNew = (DUALSTRINGARRAY*)MIDL_user_allocate(usNewDSALen * sizeof(USHORT));
  303. if (!pdsaNew)
  304. return E_OUTOFMEMORY;
  305. ZeroMemory(pdsaNew, usNewDSALen * sizeof(USHORT));
  306. // Set length
  307. pdsaNew->wNumEntries = usNewDSALen - 2; // don't count wNumEntries\wSecOffset
  308. // Initialize ptr into the new dsa
  309. pCurrentNew = &(pdsaNew->aStringArray[0]);
  310. // If we are excluding all of the string bindings in pdsaSrc, then
  311. // there's no need to make a second pass
  312. if (dwBindingsToExclude == i)
  313. {
  314. // No string bindings left at all. Not a very useful
  315. // situation. Need to add the initial NULL:
  316. *pCurrentNew = NULL;
  317. pCurrentNew++;
  318. }
  319. else
  320. {
  321. // Make a second pass, copying the non-excluded addresses
  322. // over to the new dsa as we go.
  323. bDone = FALSE;
  324. pStart = pCurrent = &(pdsaSrc->aStringArray[0]);
  325. i = 0;
  326. do
  327. {
  328. // Find end of the current string binding
  329. while (*pCurrent != 0)
  330. pCurrent++;
  331. if ((i > 0) && (pCurrent == pStart) ||
  332. ((i == 0) && (*(pCurrent+1) == 0)))
  333. {
  334. // either found a zero after the previous
  335. // binding, or we found two zeroes in a row
  336. // at the beginning of pdsaSrc->aStringArray.
  337. bDone = TRUE;
  338. }
  339. else
  340. {
  341. i++; // count total # of strings found
  342. if (!afIsExcludedAddress[i]) // remembered from first pass above
  343. {
  344. STRINGBINDING* psb = (STRINGBINDING*)pStart;
  345. STRINGBINDING* psbNew = (STRINGBINDING*)pCurrentNew;
  346. // Copy tower id
  347. psbNew->wTowerId = psb->wTowerId;
  348. // Copy address
  349. lstrcpy(&(psbNew->aNetworkAddr), &(psb->aNetworkAddr));
  350. // Move cursor for new dsa (2=towerid + null terminator)
  351. pCurrentNew += (2 + lstrlen(&(psbNew->aNetworkAddr)));
  352. }
  353. pCurrent++;
  354. pStart = pCurrent;
  355. }
  356. } while (!bDone);
  357. }
  358. // Add final null terminator for string bindings
  359. *pCurrentNew = NULL; // points to after last string binding, NULL it out
  360. pCurrentNew++; // now points to first security binding
  361. // Set security offset
  362. pdsaNew->wSecurityOffset = (unsigned short)(pCurrentNew - &(pdsaNew->aStringArray[0]));
  363. // Copy security bindings en masse
  364. memcpy(pCurrentNew,
  365. &(pdsaSrc->aStringArray[pdsaSrc->wSecurityOffset]),
  366. (pdsaSrc->wNumEntries - pdsaSrc->wSecurityOffset) * sizeof(USHORT));
  367. ASSERT(dsaValid(pdsaNew));
  368. // Success
  369. *ppdsaOut = pdsaNew;
  370. SCMVDATEHEAP();
  371. return S_OK;
  372. }
  373. //
  374. // InitializeFromRegistry
  375. //
  376. // Reads initial address list from registry. Can only
  377. // be called once, after that subsequent calls will be
  378. // ignored.
  379. //
  380. void CAddrExclusionMgr::InitializeFromRegistry()
  381. {
  382. ASSERT(gpClientLock->HeldExclusive());
  383. if (_bInitRegistry)
  384. return;
  385. _bInitRegistry = TRUE; // this is it, success or fail
  386. // UNDONE -- if we wanted to, we could support persisting
  387. // the exclusion list in the registry, and read it out
  388. // here shortly after boot.
  389. return;
  390. }
  391. // Private function, no lock needed
  392. void CAddrExclusionMgr::FreeCurrentBuffers()
  393. {
  394. ASSERT((_dwNumStrings == 0 && _ppszStrings == 0) ||
  395. (_dwNumStrings != 0 && _ppszStrings != 0));
  396. DWORD i;
  397. for (i = 0; i < _dwNumStrings; i++)
  398. {
  399. PrivMemFree(_ppszStrings[i]);
  400. }
  401. if (_ppszStrings)
  402. PrivMemFree(_ppszStrings);
  403. _dwNumStrings = 0;
  404. _ppszStrings = NULL;
  405. return;
  406. }