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.

492 lines
14 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. hr = E_OUTOFMEMORY;
  132. }
  133. gpClientLock->UnlockExclusive();
  134. if (status == RPC_S_OK)
  135. {
  136. // Update currently running processes
  137. PushCurrentBindings();
  138. }
  139. return hr;
  140. }
  141. //
  142. // EnableDisableDynamicTracking
  143. //
  144. // Turns on\off the dynamic address binding feature, and updates
  145. // the registry key accordingly.
  146. //
  147. HRESULT CAddrExclusionMgr::EnableDisableDynamicTracking(BOOL fEnable)
  148. {
  149. HRESULT hr = S_OK;
  150. LONG error;
  151. HKEY hOle;
  152. WCHAR* szY = L"Y";
  153. WCHAR* szN = L"N";
  154. gpClientLock->LockExclusive();
  155. // Open the registry key and change the value
  156. error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  157. L"SOFTWARE\\Microsoft\\OLE",
  158. NULL,
  159. KEY_WRITE,
  160. &hOle);
  161. if (error == ERROR_SUCCESS)
  162. {
  163. error = RegSetValueEx(hOle,
  164. L"EnableSystemDynamicIPTracking",
  165. 0,
  166. REG_SZ,
  167. (BYTE*)(fEnable ? szY : szN),
  168. 4); // 4 = one wchar + null
  169. if (error == ERROR_SUCCESS)
  170. {
  171. // Reset the global. Will be seen immediately
  172. gbDynamicIPChangesEnabled = fEnable ? TRUE : FALSE;
  173. }
  174. else
  175. {
  176. hr = HRESULT_FROM_WIN32(GetLastError());
  177. }
  178. CloseHandle(hOle);
  179. }
  180. else
  181. {
  182. hr = HRESULT_FROM_WIN32(GetLastError());
  183. }
  184. gpClientLock->UnlockExclusive();
  185. return hr;
  186. }
  187. //
  188. // IsExcludedAddress
  189. //
  190. // Checks to see if the specified address is in our
  191. // current exclusion list.
  192. //
  193. BOOL CAddrExclusionMgr::IsExcludedAddress(LPWSTR pszAddress)
  194. {
  195. DWORD i;
  196. ASSERT(gpClientLock->HeldExclusive());
  197. ASSERT(_ppszStrings);
  198. for (i = 0; i < _dwNumStrings; i++)
  199. {
  200. if (_ppszStrings[i])
  201. {
  202. if (lstrcmpi(_ppszStrings[i], pszAddress) == 0)
  203. {
  204. // found it in the list
  205. return TRUE;
  206. }
  207. }
  208. }
  209. return FALSE;
  210. }
  211. //
  212. // BuildExclusionDSA
  213. //
  214. // Constructs a new dsa and puts it in *ppdsaOut; the new
  215. // dsa is the same as pdsaSrc, minus any addresses that are
  216. // currently in the exclusion list.
  217. //
  218. HRESULT CAddrExclusionMgr::BuildExclusionDSA(
  219. DUALSTRINGARRAY* pdsaSrc,
  220. DUALSTRINGARRAY** ppdsaOut
  221. )
  222. {
  223. ASSERT(pdsaSrc && ppdsaOut);
  224. ASSERT(dsaValid(pdsaSrc));
  225. ASSERT(gpClientLock->HeldExclusive());
  226. SCMVDATEHEAP();
  227. DWORD i;
  228. BOOL bDone;
  229. USHORT* pStart;
  230. USHORT* pCurrent;
  231. USHORT* pCurrentNew;
  232. DWORD dwBindingsToExclude = 0;
  233. USHORT usNewDSALen = 0;
  234. DUALSTRINGARRAY* pdsaNew;
  235. BOOL* afIsExcludedAddress;
  236. *ppdsaOut = NULL;
  237. // If our list is empty, nothing to do
  238. if (_dwNumStrings == 0)
  239. return dsaAllocateAndCopy(ppdsaOut, pdsaSrc);
  240. // Allocate an array of bools on the stack. This
  241. // will be used to remember if an address is excluded
  242. // or not on the first pass, so we don't have to be
  243. // figure that out again on the second pass.
  244. //
  245. // Note that I will almost always allocate too much stack
  246. // memory -- better that than not enough. To be exact
  247. // I'd have to make an extra pass thru the dsa to see how
  248. // many string bindings there are - which sorta defeats
  249. // the purpose.
  250. afIsExcludedAddress = (BOOL*)_alloca(sizeof(BOOL) * pdsaSrc->wSecurityOffset);
  251. // First make one pass thru the incoming dsa to
  252. // see how many addresses we should retain, and
  253. // calculate how much space they will need.
  254. bDone = FALSE;
  255. pStart = pCurrent = &(pdsaSrc->aStringArray[0]);
  256. i = 0;
  257. do
  258. {
  259. // Find end of the current string binding. Be careful
  260. // to handle cases where there are no string bindings.
  261. while (*pCurrent != 0)
  262. pCurrent++;
  263. if ((i > 0) && (pCurrent == pStart) ||
  264. ((i == 0) && (*(pCurrent+1) == 0)))
  265. {
  266. // either found a zero after the previous
  267. // binding, or we found two zeroes in a row
  268. // at the beginning of pdsaSrc->aStringArray.
  269. bDone = TRUE;
  270. }
  271. else
  272. {
  273. i++; // count total # of strings found
  274. STRINGBINDING* psb = (STRINGBINDING*)pStart;
  275. // We only exclude addresses if they are using tcp
  276. if (psb->wTowerId == ID_TCP &&
  277. IsExcludedAddress(&(psb->aNetworkAddr)))
  278. {
  279. dwBindingsToExclude++;
  280. afIsExcludedAddress[i] = TRUE;
  281. }
  282. else
  283. {
  284. // Add string len plus 2 (space for towerid + null terminator)
  285. usNewDSALen = usNewDSALen + (USHORT) (lstrlen(&(psb->aNetworkAddr)) + 2);
  286. afIsExcludedAddress[i] = FALSE;
  287. }
  288. // advance to next string binding
  289. pCurrent++;
  290. pStart = pCurrent;
  291. }
  292. } while (!bDone);
  293. // If there are no addresses that need excluding, just copy
  294. // and return the incoming bindings.
  295. if (dwBindingsToExclude == 0)
  296. return dsaAllocateAndCopy(ppdsaOut, pdsaSrc);
  297. // If we didn't find any string bindings to use at all, then we
  298. // need to manually add a word for the initial NULL.
  299. if (usNewDSALen == 0)
  300. usNewDSALen = 1;
  301. // Add space for wNumEntries + wSecurityOffset
  302. usNewDSALen += (sizeof(USHORT) * 2);
  303. // Add size of all security bindings
  304. usNewDSALen += ((pdsaSrc->wNumEntries - pdsaSrc->wSecurityOffset));
  305. // Add one for the string bindings terminating NULL.
  306. usNewDSALen++;
  307. // Allocate the memory
  308. pdsaNew = (DUALSTRINGARRAY*)MIDL_user_allocate(usNewDSALen * sizeof(USHORT));
  309. if (!pdsaNew)
  310. return E_OUTOFMEMORY;
  311. ZeroMemory(pdsaNew, usNewDSALen * sizeof(USHORT));
  312. // Set length
  313. pdsaNew->wNumEntries = usNewDSALen - 2; // don't count wNumEntries\wSecOffset
  314. // Initialize ptr into the new dsa
  315. pCurrentNew = &(pdsaNew->aStringArray[0]);
  316. // If we are excluding all of the string bindings in pdsaSrc, then
  317. // there's no need to make a second pass
  318. if (dwBindingsToExclude == i)
  319. {
  320. // No string bindings left at all. Not a very useful
  321. // situation. Need to add the initial NULL:
  322. *pCurrentNew = NULL;
  323. pCurrentNew++;
  324. }
  325. else
  326. {
  327. // Make a second pass, copying the non-excluded addresses
  328. // over to the new dsa as we go.
  329. bDone = FALSE;
  330. pStart = pCurrent = &(pdsaSrc->aStringArray[0]);
  331. i = 0;
  332. do
  333. {
  334. // Find end of the current string binding
  335. while (*pCurrent != 0)
  336. pCurrent++;
  337. if ((i > 0) && (pCurrent == pStart) ||
  338. ((i == 0) && (*(pCurrent+1) == 0)))
  339. {
  340. // either found a zero after the previous
  341. // binding, or we found two zeroes in a row
  342. // at the beginning of pdsaSrc->aStringArray.
  343. bDone = TRUE;
  344. }
  345. else
  346. {
  347. i++; // count total # of strings found
  348. if (!afIsExcludedAddress[i]) // remembered from first pass above
  349. {
  350. STRINGBINDING* psb = (STRINGBINDING*)pStart;
  351. STRINGBINDING* psbNew = (STRINGBINDING*)pCurrentNew;
  352. // Copy tower id
  353. psbNew->wTowerId = psb->wTowerId;
  354. // Copy address
  355. lstrcpy(&(psbNew->aNetworkAddr), &(psb->aNetworkAddr));
  356. // Move cursor for new dsa (2=towerid + null terminator)
  357. pCurrentNew += (2 + lstrlen(&(psbNew->aNetworkAddr)));
  358. }
  359. pCurrent++;
  360. pStart = pCurrent;
  361. }
  362. } while (!bDone);
  363. }
  364. // Add final null terminator for string bindings
  365. *pCurrentNew = NULL; // points to after last string binding, NULL it out
  366. pCurrentNew++; // now points to first security binding
  367. // Set security offset
  368. pdsaNew->wSecurityOffset = (unsigned short)(pCurrentNew - &(pdsaNew->aStringArray[0]));
  369. // Copy security bindings en masse
  370. memcpy(pCurrentNew,
  371. &(pdsaSrc->aStringArray[pdsaSrc->wSecurityOffset]),
  372. (pdsaSrc->wNumEntries - pdsaSrc->wSecurityOffset) * sizeof(USHORT));
  373. ASSERT(dsaValid(pdsaNew));
  374. // Success
  375. *ppdsaOut = pdsaNew;
  376. SCMVDATEHEAP();
  377. return S_OK;
  378. }
  379. //
  380. // InitializeFromRegistry
  381. //
  382. // Reads initial address list from registry. Can only
  383. // be called once, after that subsequent calls will be
  384. // ignored.
  385. //
  386. void CAddrExclusionMgr::InitializeFromRegistry()
  387. {
  388. ASSERT(gpClientLock->HeldExclusive());
  389. if (_bInitRegistry)
  390. return;
  391. _bInitRegistry = TRUE; // this is it, success or fail
  392. // UNDONE -- if we wanted to, we could support persisting
  393. // the exclusion list in the registry, and read it out
  394. // here shortly after boot.
  395. return;
  396. }
  397. // Private function, no lock needed
  398. void CAddrExclusionMgr::FreeCurrentBuffers()
  399. {
  400. ASSERT((_dwNumStrings == 0 && _ppszStrings == 0) ||
  401. (_dwNumStrings != 0 && _ppszStrings != 0));
  402. DWORD i;
  403. for (i = 0; i < _dwNumStrings; i++)
  404. {
  405. PrivMemFree(_ppszStrings[i]);
  406. }
  407. if (_ppszStrings)
  408. PrivMemFree(_ppszStrings);
  409. _dwNumStrings = 0;
  410. _ppszStrings = NULL;
  411. return;
  412. }