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.

1573 lines
45 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. Misc.cxx
  5. Abstract:
  6. Initalization, Heap, debug, thread manager for OR
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 02-11-95 Bits 'n pieces
  11. --*/
  12. #include <or.hxx>
  13. #include <mach.hxx>
  14. #include <excladdr.hxx>
  15. #include <addrrefresh.hxx>
  16. extern "C"
  17. {
  18. #define SECURITY_WIN32 // Used by security.h
  19. #include <security.h>
  20. }
  21. BOOL fListened = FALSE;
  22. BOOL gfRegisteredAuthInfo = FALSE;
  23. extern BOOL gbDynamicIPChangesEnabled;
  24. extern DWORD gdwTimeoutPeriodForStaleMids;
  25. const UINT IP_MAXIMUM_RAW_NAME = 16; // xxx.xxx.xxx.xxx
  26. const UINT IP_MAXIMUM_PRETTY_NAME = 256; // DNS limit
  27. // Contains compressed remote protseqs and network addresses
  28. // for this process, minus any addresses in the current
  29. // exclusion list. This is a refcounted object
  30. CDualStringArray* gpdsaMyBindings = 0;
  31. // Contains all compressed remote protseqs and network addresses
  32. // for this process. Not refcounted. We maintain this one
  33. // to help when building a new gpdsaMyBindings above.
  34. DUALSTRINGARRAY* gpdsaFullBindings = 0;
  35. // Contains initial DNS name for TCP
  36. WCHAR gwszInitialDNSName[IP_MAXIMUM_PRETTY_NAME];
  37. // Authentication services successfully registered.
  38. DWORD s_cRpcssSvc = 0;
  39. SECPKG *s_aRpcssSvc = NULL;
  40. // Unique ID used to track which global resolver bindings
  41. // are currently in use. Note that this starts at one, and
  42. // everybody else starts theirs at zero. Therefore any
  43. // updates that originate from PushCurrentBindings should
  44. // take precedence. This should be looked at\modified only
  45. // when gpClientLock is taken, in sync with modifying
  46. // gpdsaMyBindings. In addition, this should be incremented
  47. // whenever gpdsaMyBindings is updated with new bindings.
  48. DWORD64 g_dwResolverBindingsID = 1;
  49. // Definitions used for asynchronous mid releases
  50. const DWORD ASYNCMIDRELEASEARGS_SIG = 0xFEDCBA02;
  51. typedef struct _ASYNCMIDRELEASEARGS
  52. {
  53. DWORD dwAMRASig; // see ASYNCMIDRELEASEARGS_SIG
  54. HANDLE hTimer;
  55. CMid* pMidToRelease;
  56. } ASYNCMIDRELEASEARGS;
  57. // Crypt context for generating random #'s
  58. HCRYPTPROV ghCryptCtx = NULL;
  59. ORSTATUS
  60. StartListeningIfNecessary()
  61. /*++
  62. Routine Description:
  63. If the process has not successfully listened to remote
  64. protocols this routine will try do to so.
  65. Note:
  66. Will not add ncacn_np to the list of supported Network OLE
  67. protocols because RpcBindingServerFromClient() doesn't
  68. work on named pipes and is required to unmarshal an in
  69. interface pointer.
  70. Arguments:
  71. n/a
  72. Return Value:
  73. OR_OK - Success.
  74. OR_NOMEM - Resource problems.
  75. --*/
  76. {
  77. RPC_STATUS status;
  78. PWSTR pwstr = gpwstrProtseqs;
  79. USHORT id;
  80. CIPAddrs* pIPAddrs = NULL;
  81. BOOL bPushNewBindings = FALSE;
  82. if (fListened == TRUE)
  83. {
  84. return(OR_OK);
  85. }
  86. gpClientLock->LockExclusive();
  87. if (fListened == TRUE)
  88. {
  89. gpClientLock->UnlockExclusive();
  90. return(OR_OK);
  91. }
  92. OrStringCopy(gwszInitialDNSName, L"");
  93. if (pwstr)
  94. {
  95. while (*pwstr)
  96. {
  97. // skip leading white space
  98. while ((*pwstr == L' ') || (*pwstr == L'\t'))
  99. {
  100. pwstr++;
  101. }
  102. if (*pwstr)
  103. {
  104. id = GetProtseqId(pwstr);
  105. // ronans - DCOMHTTP
  106. // we want to add http to the list of bindings even if listening does not
  107. // succeed as this machine could still be a client of http without being a server
  108. if (0 != id)
  109. {
  110. KdPrintEx((DPFLTR_DCOMSS_ID,
  111. DPFLTR_WARNING_LEVEL,
  112. "OR: Trying to listen to [%d]\n",
  113. id));
  114. if (id == ID_DCOMHTTP )
  115. g_fClientHttp = TRUE;
  116. status = UseProtseqIfNecessary(id);
  117. if (status == RPC_S_OK)
  118. {
  119. if (id == ID_TCP)
  120. {
  121. gAddrRefreshMgr.SetListenedOnTCP();
  122. gAddrRefreshMgr.RegisterForAddressChanges();
  123. // There may have been processes which connected before
  124. // we were able to listen on tcp. To make sure they
  125. // have the correct bindings, we must refresh them now.
  126. bPushNewBindings = TRUE;
  127. }
  128. // if listening succeeded - no need to special case http as its in the normal
  129. // list of protocols
  130. if (id == ID_DCOMHTTP )
  131. g_fClientHttp = FALSE;
  132. fListened = TRUE;
  133. KdPrintEx((DPFLTR_DCOMSS_ID,
  134. DPFLTR_WARNING_LEVEL,
  135. "OR: Listen succeeded on [%d]\n",
  136. id));
  137. }
  138. else
  139. KdPrintEx((DPFLTR_DCOMSS_ID,
  140. DPFLTR_WARNING_LEVEL,
  141. "OR: Listen failed on [%d]\n",
  142. id));
  143. }
  144. }
  145. pwstr = OrStringSearch(pwstr, 0) + 1;
  146. }
  147. }
  148. if ( FALSE == fListened
  149. && 0 != gLocalMid)
  150. {
  151. // Didn't manage to listen to anything new, no need to
  152. // recompute all the global arrays.
  153. gpClientLock->UnlockExclusive();
  154. return(OR_OK);
  155. }
  156. // ??? limit to only those protseqs listed in the registry,
  157. // if the another service used more protseqs they would show up here.
  158. RPC_BINDING_VECTOR *pbv;
  159. PWSTR pwstrT;
  160. DUALSTRINGARRAY *pdsaT;
  161. PWSTR *aAddresses;
  162. USHORT *aProtseqs;
  163. unsigned short psaLen;
  164. DWORD i;
  165. DWORD iProtseq;
  166. status = RpcServerInqBindings(&pbv);
  167. if (RPC_S_OK == status)
  168. {
  169. aAddresses = new PWSTR[pbv->Count];
  170. aProtseqs = new USHORT[pbv->Count];
  171. if ( !aAddresses
  172. || !aProtseqs)
  173. {
  174. RpcBindingVectorFree(&pbv);
  175. delete aAddresses; // 0 or allocated.
  176. delete aProtseqs; // 0 or allocated.
  177. status = OR_NOMEM;
  178. }
  179. }
  180. else
  181. status = OR_NOMEM;
  182. if (status != OR_OK)
  183. {
  184. gpClientLock->UnlockExclusive();
  185. return(status);
  186. }
  187. // Build array of protseqs id's and addresses we're listening to.
  188. pwstr = gpwstrProtseqs;
  189. if (pwstr)
  190. {
  191. psaLen = 0;
  192. iProtseq = 0;
  193. // start with the list of allowed protocols
  194. // listed in the registry. For each protocol, in order,
  195. // check to see if there is an endpoint registered for it.
  196. // NOTE: Do not change the order of these loops
  197. // It is pertinent to correctly order the final
  198. // string.
  199. while (*pwstr)
  200. {
  201. id = GetProtseqId(pwstr);
  202. if (0 != id)
  203. {
  204. for (i = 0; i < pbv->Count; i++)
  205. {
  206. PWSTR pwstrStringBinding;
  207. status = RpcBindingToStringBinding(pbv->BindingH[i], &pwstrStringBinding);
  208. if (status != RPC_S_OK)
  209. {
  210. break;
  211. }
  212. ASSERT(pwstrStringBinding);
  213. status = RpcStringBindingParse(pwstrStringBinding,
  214. 0,
  215. &pwstrT,
  216. &aAddresses[iProtseq],
  217. 0,
  218. 0);
  219. RPC_STATUS statusT = RpcStringFree(&pwstrStringBinding);
  220. ASSERT(statusT == RPC_S_OK && pwstrStringBinding == 0);
  221. if (status != RPC_S_OK)
  222. {
  223. break;
  224. }
  225. //
  226. // if the protocol name matches we can use this one
  227. //
  228. if (lstrcmpW(pwstrT, pwstr) == 0)
  229. {
  230. aProtseqs[iProtseq] = id;
  231. status = RpcStringFree(&pwstrT);
  232. ASSERT(status == RPC_S_OK && pwstrT == 0);
  233. // Disallow datagram protocols till they
  234. // support SSL and snego.
  235. if (!IsLocal(aProtseqs[iProtseq]) && aProtseqs[iProtseq] != ID_NP &&
  236. aProtseqs[iProtseq] != ID_UDP && aProtseqs[iProtseq] != ID_IPX)
  237. {
  238. // Only hand out remote non-named pipes protseqs.
  239. // Save the dns name RPC gave us; we will need this in future
  240. // if the IP's change and we need to rebuild the bindings
  241. //
  242. // In some cases RPC may give us 127.0.0.1. Don't use that address.
  243. //
  244. if (aProtseqs[iProtseq] == ID_TCP &&
  245. lstrcmpi(aAddresses[iProtseq], L"127.0.0.1"))
  246. {
  247. OrStringCopy(gwszInitialDNSName, aAddresses[iProtseq]);
  248. psaLen += (unsigned short) (1 + OrStringLen(aAddresses[iProtseq]) + 1);
  249. }
  250. else if (aProtseqs[iProtseq] != ID_TCP)
  251. {
  252. psaLen += (unsigned short) (1 + OrStringLen(aAddresses[iProtseq]) + 1);
  253. }
  254. // compute length w/IP address(es)
  255. if (aProtseqs[iProtseq] == ID_TCP || aProtseqs[iProtseq] == ID_UDP || ID_DCOMHTTP == aProtseqs[iProtseq])
  256. {
  257. if (!pIPAddrs)
  258. {
  259. pIPAddrs = gpMachineName->GetIPAddrs();
  260. }
  261. if (pIPAddrs)
  262. {
  263. NetworkAddressVector* pNetworkAddrVector = pIPAddrs->_pIPAddresses;
  264. ASSERT(pNetworkAddrVector);
  265. for (ULONG j=0; j<pNetworkAddrVector->Count; j++)
  266. {
  267. // do not include the loopback address in resolver bindings.
  268. if (lstrcmpW(L"127.0.0.1", pNetworkAddrVector->NetworkAddresses[j]) != 0)
  269. {
  270. psaLen += (unsigned short) (1 + OrStringLen(pNetworkAddrVector->NetworkAddresses[j]) + 1);
  271. }
  272. }
  273. }
  274. }
  275. }
  276. iProtseq++;
  277. break;
  278. }
  279. else
  280. {
  281. status = RpcStringFree(&pwstrT);
  282. ASSERT(status == RPC_S_OK && pwstrT == 0);
  283. status = RpcStringFree(&aAddresses[iProtseq]);
  284. ASSERT(status == RPC_S_OK && pwstrT == 0);
  285. }
  286. }
  287. if (status != RPC_S_OK)
  288. {
  289. break;
  290. }
  291. }
  292. pwstr = OrStringSearch(pwstr, 0) + 1;
  293. }
  294. }
  295. if (status != RPC_S_OK)
  296. {
  297. delete aAddresses;
  298. delete aProtseqs;
  299. RPC_STATUS status_tmp = RpcBindingVectorFree(&pbv);
  300. ASSERT(pbv == 0 && status_tmp == RPC_S_OK);
  301. gpClientLock->UnlockExclusive();
  302. if (pIPAddrs)
  303. pIPAddrs->DecRefCount();
  304. return(status);
  305. }
  306. // string bindings final null, authn and authz service list and
  307. // one final nulls
  308. if (psaLen == 0)
  309. {
  310. // No remote bindings, leave space for an extra NULL.
  311. psaLen = 1;
  312. }
  313. if (s_cRpcssSvc == 0)
  314. {
  315. // No authentication services, leave space for an extra NULL.
  316. psaLen += 1;
  317. }
  318. psaLen += (unsigned short)(1 + 3*s_cRpcssSvc + 1);
  319. pdsaT = new(psaLen * sizeof(WCHAR)) DUALSTRINGARRAY;
  320. if (!pdsaT)
  321. {
  322. delete aAddresses;
  323. delete aProtseqs;
  324. status = RpcBindingVectorFree(&pbv);
  325. ASSERT(pbv == 0 && status == RPC_S_OK);
  326. gpClientLock->UnlockExclusive();
  327. if (pIPAddrs)
  328. pIPAddrs->DecRefCount();
  329. return OR_NOMEM;
  330. }
  331. pdsaT->wNumEntries = psaLen;
  332. if (s_cRpcssSvc == 0)
  333. pdsaT->wSecurityOffset = psaLen - 2;
  334. else
  335. pdsaT->wSecurityOffset = (unsigned short)(psaLen - 3*s_cRpcssSvc - 1);
  336. pwstrT = pdsaT->aStringArray;
  337. for (i = 0; i < iProtseq; i++)
  338. {
  339. // Disallow datagram protocols till they
  340. // support SSL and snego.
  341. if (!IsLocal(aProtseqs[i]) && aProtseqs[i] != ID_NP &&
  342. aProtseqs[i] != ID_UDP && aProtseqs[i] != ID_IPX)
  343. {
  344. // Make sure we don't put the localhost ip in here either.
  345. if ((aProtseqs[i] != ID_TCP)
  346. ||
  347. ((aProtseqs[i] == ID_TCP) && (lstrcmpi(aAddresses[i], L"127.0.0.1"))))
  348. {
  349. *pwstrT = aProtseqs[i];
  350. pwstrT++;
  351. OrStringCopy(pwstrT, aAddresses[i]);
  352. pwstrT = OrStringSearch(pwstrT, 0) + 1; // next
  353. }
  354. // add the IP address(es)
  355. if (aProtseqs[i] == ID_TCP || aProtseqs[i] == ID_UDP || ID_DCOMHTTP == aProtseqs[i])
  356. {
  357. if (!pIPAddrs)
  358. {
  359. pIPAddrs = gpMachineName->GetIPAddrs();
  360. }
  361. if (pIPAddrs)
  362. {
  363. NetworkAddressVector* pNetworkAddrVector = pIPAddrs->_pIPAddresses;
  364. ASSERT(pNetworkAddrVector);
  365. for (ULONG j=0; j<pNetworkAddrVector->Count; j++)
  366. {
  367. // do not include the loopback address in resolver bindings.
  368. if (lstrcmpW(L"127.0.0.1", pNetworkAddrVector->NetworkAddresses[j]) != 0)
  369. {
  370. *pwstrT = aProtseqs[i];
  371. pwstrT++;
  372. OrStringCopy(pwstrT, pNetworkAddrVector->NetworkAddresses[j]);
  373. pwstrT = OrStringSearch(pwstrT, 0) + 1; // next
  374. }
  375. }
  376. }
  377. }
  378. }
  379. status = RpcStringFree(&aAddresses[i]);
  380. ASSERT(status == RPC_S_OK);
  381. }
  382. if (pdsaT->wSecurityOffset == 2)
  383. {
  384. // No remote bindings, put in first null.
  385. pdsaT->aStringArray[0] = 0;
  386. pwstrT++;
  387. }
  388. // Zero final terminator
  389. *pwstrT = 0;
  390. pwstrT++;
  391. // Security authn services
  392. for (i = 0; i < s_cRpcssSvc; i++)
  393. {
  394. // Authn service, Authz service (-1 means none), NULL principal name
  395. *pwstrT = s_aRpcssSvc[i].wId;
  396. pwstrT++;
  397. *pwstrT = -1;
  398. pwstrT++;
  399. *pwstrT = 0;
  400. pwstrT++;
  401. }
  402. // If there are no authentication services, put in an extra NULL.
  403. if (s_cRpcssSvc == 0)
  404. {
  405. *pwstrT = 0;
  406. pwstrT++;
  407. }
  408. // Final NULL
  409. *pwstrT = 0;
  410. ASSERT(dsaValid(pdsaT));
  411. USHORT cRemoteProtseqs = 0;
  412. // Convert aProtseqs into remote only array of protseqs and count them.
  413. for (i = 0; i < iProtseq; i++)
  414. {
  415. // Disallow datagram protocols till they
  416. // support SSL and snego.
  417. if (!IsLocal(aProtseqs[i]) && aProtseqs[i] != ID_NP &&
  418. aProtseqs[i] != ID_UDP && aProtseqs[i] != ID_IPX)
  419. {
  420. aProtseqs[cRemoteProtseqs] = aProtseqs[i];
  421. cRemoteProtseqs++;
  422. }
  423. }
  424. delete aAddresses;
  425. status = RpcBindingVectorFree(&pbv);
  426. ASSERT(pbv == 0 && status == RPC_S_OK);
  427. if (pIPAddrs) pIPAddrs->DecRefCount();
  428. pIPAddrs = NULL;
  429. gAddrExclusionMgr.InitializeFromRegistry();
  430. // Obtain bindings filtered by exclusion list
  431. HRESULT hr;
  432. DUALSTRINGARRAY* pdsaFiltered;
  433. hr = gAddrExclusionMgr.BuildExclusionDSA(pdsaT, &pdsaFiltered);
  434. if (FAILED(hr))
  435. {
  436. delete pdsaT;
  437. gpClientLock->UnlockExclusive();
  438. return (OR_NOMEM);
  439. }
  440. // The mid object makes a copy of pdsaFiltered, it doesn't own it
  441. BOOL fMidInitOkay = FALSE;
  442. CMid *pMid = new(pdsaFiltered->wNumEntries * sizeof(WCHAR)) CMid(pdsaFiltered, TRUE, gLocalMid, &fMidInitOkay);
  443. if (pMid && fMidInitOkay)
  444. {
  445. CDualStringArray* pdsaWrapper = new CDualStringArray(pdsaFiltered);
  446. if (pdsaWrapper)
  447. {
  448. if (gpdsaFullBindings) delete gpdsaFullBindings;
  449. gpdsaFullBindings = pdsaT; // the full bindings
  450. ASSERT(gpClientLock->HeldExclusive());
  451. gpMidTable->Add(pMid);
  452. aMyProtseqs = aProtseqs;
  453. cMyProtseqs = cRemoteProtseqs;
  454. if (gpdsaMyBindings) gpdsaMyBindings->Release();
  455. gpdsaMyBindings = pdsaWrapper; // the filtered bindings
  456. gLocalMid = pMid->Id();
  457. // Increment id counter
  458. g_dwResolverBindingsID++;
  459. // Release the lock now, so we don't hold it across PushCurrentBindings.
  460. gpClientLock->UnlockExclusive();
  461. // Push new bindings if so called for. Not fatal if this fails
  462. if (bPushNewBindings)
  463. {
  464. PushCurrentBindings();
  465. }
  466. return OR_OK;
  467. }
  468. }
  469. // Failed to get memory or mid object failed to init
  470. if (pMid) pMid->Release();
  471. delete pdsaT;
  472. MIDL_user_free(pdsaFiltered);
  473. delete aProtseqs;
  474. gpClientLock->UnlockExclusive();
  475. return(OR_NOMEM);
  476. }
  477. BOOL IsHttpClient()
  478. /*++
  479. Routine Description:
  480. Returns the global client http flag while holding a lock
  481. Return Value:
  482. None
  483. --*/
  484. {
  485. BOOL retval;
  486. gpClientLock->LockExclusive();
  487. retval = g_fClientHttp;
  488. gpClientLock->UnlockExclusive();
  489. return retval;
  490. }
  491. void CALLBACK
  492. AsyncMidReleaseTimerCallback(void* pvParam, BOOLEAN TimerOrWaitFired)
  493. /*++
  494. Routine Description:
  495. Releases the mid object that was queued to a timer in
  496. DoAsyncMidRelease below.
  497. Return Value:
  498. None
  499. --*/
  500. {
  501. BOOL fResult;
  502. ASYNCMIDRELEASEARGS* pArgs;
  503. ASSERT(TimerOrWaitFired);
  504. pArgs = (ASYNCMIDRELEASEARGS*)pvParam;
  505. ASSERT(pArgs);
  506. ASSERT(pArgs->dwAMRASig == ASYNCMIDRELEASEARGS_SIG);
  507. ASSERT(pArgs->hTimer);
  508. ASSERT(pArgs->pMidToRelease);
  509. gpClientLock->LockExclusive();
  510. pArgs->pMidToRelease->Release();
  511. gpClientLock->UnlockExclusive();
  512. // Make a non-blocking call to delete the timer.
  513. fResult = DeleteTimerQueueTimer(NULL,
  514. pArgs->hTimer,
  515. NULL);
  516. ASSERT(fResult || (GetLastError() == ERROR_IO_PENDING));
  517. // Finally, delete the argument structure
  518. delete pArgs;
  519. return;
  520. }
  521. void
  522. DoAsyncMidRelease(CMid* pMid, DWORD dwReleaseInMSec)
  523. /*++
  524. Routine Description:
  525. Creates a timer callback that will call ->Release on the
  526. supplied mid object in the specified amount of time. If
  527. the timer creation fails, does an immediate release.
  528. Return Value:
  529. None
  530. --*/
  531. {
  532. BOOL bResult;
  533. HANDLE hNewTimer;
  534. ASYNCMIDRELEASEARGS* pArgs;
  535. ASSERT(pMid);
  536. ASSERT(gpClientLock->HeldExclusive());
  537. pArgs = new ASYNCMIDRELEASEARGS;
  538. if (!pArgs)
  539. {
  540. // Nothing we can do -- mid will be released synchronously
  541. // when this occurs.
  542. return;
  543. }
  544. // Initialize the struct
  545. pArgs->dwAMRASig = ASYNCMIDRELEASEARGS_SIG;
  546. pArgs->hTimer = NULL;
  547. pArgs->pMidToRelease = pMid;
  548. pMid->Reference();
  549. bResult = CreateTimerQueueTimer(&(pArgs->hTimer),
  550. NULL,
  551. AsyncMidReleaseTimerCallback,
  552. pArgs,
  553. dwReleaseInMSec,
  554. 0,
  555. 0);
  556. if (!bResult)
  557. {
  558. // Timer failed; release struct and mid object immediately to
  559. // avoid leaking them. Like above, mid is released sync.
  560. pMid->Release();
  561. delete pArgs;
  562. }
  563. return;
  564. }
  565. RPC_STATUS
  566. ComputeNewResolverBindings(void)
  567. /*++
  568. Routine Description:
  569. Creates the local OR bindings using the current IP addresses, and
  570. places the results in gpdsaFullBindings. gpdsaFullBindings is then
  571. passed to the address exclusion mgr object, who creates a "filtered"
  572. set of bindings, which omits any currently excluded addresses; these
  573. bindings are saved in gpdsaMyBindings.
  574. Caller must be holding gpClientLock.
  575. Return Value:
  576. RPC_S_OK
  577. RPC_S_OUT_OF_MEMORY
  578. RPC_S_OUT_OF_RESOURCES
  579. --*/
  580. {
  581. BOOL fDoneTCP = FALSE;
  582. BOOL fDoneUDP = FALSE;
  583. DWORD i;
  584. CIPAddrs* pIPAddrs;
  585. DWORD dwNumAddrs;
  586. ASSERT(gpdsaMyBindings);
  587. ASSERT(gpClientLock->HeldExclusive());
  588. pIPAddrs = gpMachineName->GetIPAddrs();
  589. dwNumAddrs = pIPAddrs ? pIPAddrs->_pIPAddresses->Count : 0;
  590. // compute size of new dsa (for each IP address, leave space
  591. // for two copies (one for TCP/IP and one for UDP).
  592. DWORD psaLen = pIPAddrs ? (pIPAddrs->_pIPAddresses->StringBufferSpace * 2) : 0;
  593. psaLen += sizeof(DUALSTRINGARRAY) + (gpdsaMyBindings->DSA()->wNumEntries * sizeof(USHORT));
  594. DWORD dwDNSLen = (DWORD) OrStringLen(gwszInitialDNSName);
  595. if (dwDNSLen > 0)
  596. {
  597. psaLen += dwDNSLen + 2;
  598. }
  599. // Allocate space for the new bindings
  600. DUALSTRINGARRAY *pdsaT = new(psaLen) DUALSTRINGARRAY;
  601. if (pdsaT == NULL)
  602. {
  603. if (pIPAddrs) pIPAddrs->DecRefCount();
  604. return RPC_S_OUT_OF_RESOURCES;
  605. }
  606. PWSTR pwstrT = pdsaT->aStringArray;
  607. PWSTR pwstrSrc = gpdsaFullBindings->aStringArray;
  608. // copy in the information. For TCP/IP and UDP, we copy in the
  609. // new IP addresses. For all others, we leave as is.
  610. psaLen = 0;
  611. while (*pwstrSrc)
  612. {
  613. USHORT id = *pwstrSrc; // current tower id
  614. pwstrSrc++;
  615. if (id == NCACN_IP_TCP)
  616. {
  617. if (!fDoneTCP)
  618. {
  619. // copy in the DNS name, if any, obtained initially from RPC
  620. // in StartListeningIfNecessary
  621. if (dwDNSLen > 0)
  622. {
  623. *pwstrT = id;
  624. pwstrT++;
  625. OrStringCopy(pwstrT, gwszInitialDNSName);
  626. pwstrT += dwDNSLen + 1;
  627. psaLen += dwDNSLen + 2;
  628. }
  629. // copy in the new IP addresses
  630. fDoneTCP = TRUE;
  631. for (UINT i=0; i<dwNumAddrs; i++)
  632. {
  633. *pwstrT = id; // copy in the tower id
  634. pwstrT++;
  635. OrStringCopy(pwstrT, pIPAddrs->_pIPAddresses->NetworkAddresses[i]);
  636. size_t len = OrStringLen(pIPAddrs->_pIPAddresses->NetworkAddresses[i]) + 1;
  637. pwstrT += len;
  638. psaLen += (DWORD) len + 1;
  639. }
  640. }
  641. }
  642. else if (id == NCADG_IP_UDP)
  643. {
  644. if (!fDoneUDP)
  645. {
  646. // copy in the new IP addresses
  647. fDoneUDP = TRUE;
  648. for (UINT i=0; i<dwNumAddrs; i++)
  649. {
  650. *pwstrT = id; // copy in the tower id
  651. pwstrT++;
  652. OrStringCopy(pwstrT, pIPAddrs->_pIPAddresses->NetworkAddresses[i]);
  653. size_t len = OrStringLen(pIPAddrs->_pIPAddresses->NetworkAddresses[i]) + 1;
  654. pwstrT += len;
  655. psaLen += (DWORD) len + 1;
  656. }
  657. }
  658. }
  659. else
  660. {
  661. // just copy the existing entry unchanged.
  662. *pwstrT = id; // copy in the tower id
  663. pwstrT++;
  664. OrStringCopy(pwstrT, pwstrSrc);
  665. size_t len = OrStringLen(pwstrSrc) + 1;
  666. pwstrT += len;
  667. psaLen += (DWORD) len + 1;
  668. }
  669. // skip to the next towerid entry
  670. pwstrSrc += OrStringLen(pwstrSrc) + 1;
  671. }
  672. // Zero final terminator
  673. if (psaLen == 0)
  674. {
  675. *((DWORD*) pwstrT) = 0;
  676. pwstrT += 2;
  677. psaLen += 2;
  678. }
  679. else
  680. {
  681. *pwstrT = 0;
  682. pwstrT++;
  683. psaLen += 1;
  684. }
  685. // Security authn services
  686. pdsaT->wSecurityOffset = (unsigned short) psaLen;
  687. for (i = 0; i < s_cRpcssSvc; i++)
  688. {
  689. // Authn service, Authz service (-1 means none), NULL principal name
  690. *pwstrT = s_aRpcssSvc[i].wId;
  691. pwstrT++;
  692. *pwstrT = -1;
  693. pwstrT++;
  694. *pwstrT = 0;
  695. pwstrT++;
  696. }
  697. // If there are no authentication services, put in an extra NULL.
  698. if (s_cRpcssSvc == 0)
  699. {
  700. *pwstrT = 0;
  701. pwstrT++;
  702. psaLen += 1;
  703. }
  704. // Final NULL
  705. psaLen += 3*s_cRpcssSvc + 1;
  706. *pwstrT = 0;
  707. // update the size
  708. pdsaT->wNumEntries = (unsigned short) psaLen;
  709. ASSERT(dsaValid(pdsaT));
  710. // Done with ipaddrs
  711. if (pIPAddrs) pIPAddrs->DecRefCount();
  712. pIPAddrs = NULL;
  713. // Always replace the current "full" bindings, so they
  714. // are always up-to-date.
  715. delete gpdsaFullBindings;
  716. gpdsaFullBindings = pdsaT;
  717. pdsaT = NULL;
  718. HRESULT hr;
  719. DUALSTRINGARRAY* pdsaFiltered;
  720. hr = gAddrExclusionMgr.BuildExclusionDSA(gpdsaFullBindings, &pdsaFiltered);
  721. if (FAILED(hr))
  722. return RPC_S_OUT_OF_RESOURCES;
  723. if (dsaCompare(gpdsaMyBindings->DSA(), pdsaFiltered))
  724. {
  725. // the old and new local resolver strings are the same
  726. // so don't change anything, just throw away the new one.
  727. MIDL_user_free(pdsaFiltered);
  728. return RPC_S_OK;
  729. }
  730. // The two are different. First, let's see if an old mid entry
  731. // for the new bindings is still in the table.
  732. CMid* pNewLocalMid = NULL;
  733. CMid* pOldMatchingLocalMid = NULL;
  734. pOldMatchingLocalMid = (CMid*)gpMidTable->Lookup(CMidKey(pdsaFiltered));
  735. if (pOldMatchingLocalMid)
  736. {
  737. // Returned mid should be both local and stale
  738. ASSERT(pOldMatchingLocalMid->IsLocal());
  739. ASSERT(pOldMatchingLocalMid->IsStale());
  740. }
  741. else
  742. {
  743. // Not in the table already, create a new mid
  744. BOOL fMidInitOkay = FALSE;
  745. // The mid object makes a copy of pdsaFiltered, it doesn't own it
  746. pNewLocalMid = new(pdsaFiltered->wNumEntries * sizeof(WCHAR))
  747. CMid(pdsaFiltered, TRUE, gLocalMid, &fMidInitOkay);
  748. if (!pNewLocalMid || !fMidInitOkay)
  749. {
  750. if (pNewLocalMid)
  751. {
  752. delete pNewLocalMid;
  753. }
  754. MIDL_user_free(pdsaFiltered);
  755. return RPC_S_OUT_OF_RESOURCES;
  756. }
  757. }
  758. // Always need to construct a new gpdsaMyBindings
  759. CDualStringArray* pdsaWrapper = new CDualStringArray(pdsaFiltered);
  760. if (pdsaWrapper)
  761. {
  762. ASSERT(gpClientLock->HeldExclusive());
  763. if (pOldMatchingLocalMid)
  764. {
  765. // Mark the mid that's already in the table
  766. // as no longer stale, and reference it so it
  767. // stays in the table.
  768. pOldMatchingLocalMid->Reference();
  769. pOldMatchingLocalMid->MarkStale(FALSE);
  770. }
  771. else
  772. {
  773. // Add new local mid to the table; it's "not stale" by default
  774. ASSERT(pNewLocalMid);
  775. gpMidTable->Add(pNewLocalMid);
  776. }
  777. // Mark the current mid as stale
  778. CMid* pCurrentMid = (CMid*)gpMidTable->Lookup(CMidKey(gpdsaMyBindings->DSA()));
  779. ASSERT(pCurrentMid);
  780. pCurrentMid->MarkStale(TRUE);
  781. // The old local mid object would normally be guaranteed to remain in the table
  782. // for as long as gpClientLock is held. It is possible that an activation in-flight
  783. // concurrent with this thread may try to look up the old local mid shortly
  784. // after this code finishes, and if not found the oxid resolution will proceed
  785. // as if the mid was a remote machine, not local. This leads to major problems.
  786. // To get around this somewhat fuzzy window, we addref the old mid (thus keeping
  787. // it in the table), and ask for a timer callback at a later time when we will
  788. // be virtually guaranteed that all such in-flight local activations referencing
  789. // the old mid will have completed.
  790. DoAsyncMidRelease(pCurrentMid, gdwTimeoutPeriodForStaleMids);
  791. // DoAsyncMidRelease takes a reference to be released later; still need
  792. // to release it here.
  793. pCurrentMid->Release();
  794. // Release old bindings
  795. gpdsaMyBindings->Release();
  796. // Remember new ones
  797. gpdsaMyBindings = pdsaWrapper;
  798. // Increment id counter
  799. g_dwResolverBindingsID++;
  800. return RPC_S_OK;
  801. }
  802. // No mem
  803. if (pNewLocalMid) delete pNewLocalMid;
  804. MIDL_user_free(pdsaFiltered);
  805. return RPC_S_OUT_OF_RESOURCES;
  806. }
  807. RPC_STATUS
  808. CopyMyOrBindings(DUALSTRINGARRAY **ppdsaOrBindings, DWORD64* pdwBindingsID)
  809. /*++
  810. Routine Description:
  811. Copies the current OR bindings to return to the
  812. caller.
  813. Parameters:
  814. ppdsaOrBindings -- where to put the bindings when done
  815. pdwBindingsID -- if successful, contains the binding id of the
  816. returned bindings. Can be NULL if the client
  817. does not care.
  818. Return Value:
  819. RPC_S_OK
  820. RPC_S_OUT_OF_MEMORY
  821. RPC_S_OUT_OF_RESOURCES
  822. --*/
  823. {
  824. HRESULT hr;
  825. RPC_STATUS status = RPC_S_OK;
  826. CDualStringArray* pdsaBindings;
  827. DWORD64 dwBindingsID;
  828. SCMVDATEHEAP();
  829. // Take lock only long enough to take a reference on
  830. // the current bindings
  831. gpClientLock->LockExclusive();
  832. pdsaBindings = gpdsaMyBindings;
  833. if (pdsaBindings)
  834. pdsaBindings->AddRef();
  835. // Save id now while we're under the lock
  836. dwBindingsID = g_dwResolverBindingsID;
  837. // We call this here in case we failed to register for
  838. // address change notifications. If it previously succeeded,
  839. // then this call is a no-op, otherwise it might succeed
  840. // this time around.
  841. gAddrRefreshMgr.RegisterForAddressChanges();
  842. gpClientLock->UnlockExclusive();
  843. ASSERT(pdsaBindings);
  844. if (!pdsaBindings)
  845. return RPC_S_OUT_OF_RESOURCES;
  846. hr = dsaAllocateAndCopy(ppdsaOrBindings, pdsaBindings->DSA());
  847. if (SUCCEEDED(hr) && pdwBindingsID)
  848. {
  849. *pdwBindingsID = dwBindingsID;
  850. }
  851. pdsaBindings->Release();
  852. SCMVDATEHEAP();
  853. return ((hr == S_OK) ? RPC_S_OK : RPC_S_OUT_OF_RESOURCES);
  854. }
  855. /*
  856. // Debugging hack: for when you only want to debug the bindings
  857. // update stuff with one process instead of every process
  858. // on the box.
  859. DWORD GetUpdateablePID()
  860. {
  861. HKEY hOle;
  862. DWORD error;
  863. DWORD dwValue = -1;
  864. DWORD dwType;
  865. DWORD dwBufSize = sizeof(DWORD);
  866. error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  867. L"SOFTWARE\\Microsoft\\OLE",
  868. NULL,
  869. KEY_READ,
  870. &hOle);
  871. if (error == ERROR_SUCCESS)
  872. {
  873. error = RegQueryValueEx(
  874. hOle,
  875. L"UpdateablePID",
  876. 0,
  877. &dwType,
  878. (BYTE*)&dwValue,
  879. &dwBufSize);
  880. RegCloseKey(hOle);
  881. }
  882. return dwValue;
  883. }
  884. */
  885. void
  886. GetCurrentBindingsAndID(DWORD64* pdwBindingsID, CDualStringArray** ppDSABindings)
  887. /*++
  888. Routine Description:
  889. Returns to the caller the current bindings and their id. *ppDSABindings
  890. will have a refcount added.
  891. Return Value:
  892. void
  893. --*/
  894. {
  895. ASSERT(!gpClientLock->HeldExclusive());
  896. ASSERT(pdwBindingsID && ppDSABindings);
  897. // Take reference on gpClientLock long enough to grab a
  898. // reference on the current bindings
  899. gpClientLock->LockExclusive();
  900. ASSERT(gpdsaMyBindings);
  901. *ppDSABindings = gpdsaMyBindings;
  902. (*ppDSABindings)->AddRef();
  903. *pdwBindingsID = g_dwResolverBindingsID;
  904. gpClientLock->UnlockExclusive();
  905. return;
  906. }
  907. void
  908. PushCurrentBindings()
  909. /*++
  910. Routine Description:
  911. Propagates the current resolver bindings to all currently
  912. running processes.
  913. Return Value:
  914. void
  915. --*/
  916. {
  917. ORSTATUS status;
  918. DWORD64 dwBindingsID;
  919. CDualStringArray* pDSABindings = NULL;
  920. ASSERT(!gpClientLock->HeldExclusive());
  921. // If not enabled, don't do it
  922. if (!gbDynamicIPChangesEnabled)
  923. return;
  924. GetCurrentBindingsAndID(&dwBindingsID, &pDSABindings);
  925. ASSERT(pDSABindings);
  926. // Take a shared lock on the process list, and copy all of
  927. // the contained processes to a separate list, with an
  928. // extra refcount added. Then we release the lock, and
  929. // push the new bindings to each process. New processes
  930. // that connect after we leave the lock will automatically
  931. // get the newest bindings.
  932. gpProcessListLock->LockShared();
  933. // Allocate space on the stack to remember each process in
  934. // the list.
  935. DWORD i = 0;
  936. DWORD dwTotalProcesses = 0;
  937. DWORD dwListSize = gpProcessList->Size();
  938. // Check for nothing to do. This can occur early during boot.
  939. if (dwListSize == 0)
  940. {
  941. gpProcessListLock->UnlockShared();
  942. pDSABindings->Release();
  943. return;
  944. }
  945. CProcess* pprocess;
  946. CProcess** ppProcessList =
  947. (CProcess**)_alloca(sizeof(CProcess*) * dwListSize);
  948. // Copy contents of current list
  949. CBListIterator all_procs(gpProcessList);
  950. while (pprocess = (CProcess*)all_procs.Next())
  951. {
  952. // Only push bindings if process has not been rundown
  953. if (!pprocess->HasBeenRundown())
  954. {
  955. // This is the moral equivalent of ReferenceProcess(pprocess, TRUE),
  956. // it will prevent the process object from being rundown while
  957. // we're using it. It will be balanced out below by the
  958. // ReleaseProcess call.
  959. pprocess->ClientReference();
  960. ppProcessList[dwTotalProcesses++] = pprocess;
  961. }
  962. }
  963. ASSERT(dwTotalProcesses <= dwListSize);
  964. gpProcessListLock->UnlockShared();
  965. // Now that we're outside the lock, update each process with
  966. // the new bindings. Note that even if another refresh
  967. // beats us, the process object tracks the binding id's, so
  968. // the right thing will happen.
  969. for (i = 0; i < dwTotalProcesses; i++)
  970. {
  971. status = ppProcessList[i]->UpdateResolverBindings(dwBindingsID, pDSABindings->DSA());
  972. if (status != OR_OK)
  973. {
  974. // For use with the debugging hack above
  975. // if (pprocess->GetPID() != GetUpdateablePID())
  976. // continue;
  977. // Right now I'm considering this a best-case effort; it
  978. // can expectedly fail in some circumstances; eg, a process
  979. // initializes COM, does work, then uninit's COM and stops
  980. // listening on the ole32<->rpcss interfaces.
  981. KdPrintEx((DPFLTR_DCOMSS_ID,
  982. DPFLTR_WARNING_LEVEL,
  983. "OR: failed to update dynamic resolver "
  984. "bindings for process pid=%d\n",
  985. ppProcessList[i]->GetPID()));
  986. }
  987. }
  988. // Release references on process objects
  989. for (i = 0; i < dwTotalProcesses; i++)
  990. {
  991. ReleaseProcess(ppProcessList[i]);
  992. }
  993. pDSABindings->Release();
  994. return;
  995. }
  996. void
  997. RegisterAuthInfoIfNecessary()
  998. /*++
  999. Routine Description:
  1000. Initializes all COM authentication services. The list is computed in
  1001. ComputeSecurity. Ignore failures. On normal boots the authentication
  1002. services register without error on the first call. During setup the
  1003. authentication services never register but the machine receives no
  1004. remote secure activation requests.
  1005. Return Value:
  1006. none
  1007. --*/
  1008. {
  1009. DWORD Status;
  1010. SECPKG *pSvcList;
  1011. DWORD i;
  1012. DWORD j = 0;
  1013. DWORD k;
  1014. DWORD cClientSvcs;
  1015. SECPKG* aClientSvcs;
  1016. DWORD cServerSvcs;
  1017. USHORT* aServerSvcs;
  1018. // Doesn't matter if we call RegisterAuthInfo more than once by chance.
  1019. if (gfRegisteredAuthInfo)
  1020. return;
  1021. // Retrieve client\server services
  1022. if (!GetClientServerSvcs(&cClientSvcs, &aClientSvcs, &cServerSvcs, &aServerSvcs))
  1023. return;
  1024. if (cServerSvcs == 0)
  1025. {
  1026. CleanupClientServerSvcs(cClientSvcs, aClientSvcs, cServerSvcs, aServerSvcs);
  1027. return;
  1028. }
  1029. // Allocate an array to hold the list of authentication services that
  1030. // were successfully registered.
  1031. pSvcList = new SECPKG[cServerSvcs];
  1032. if (pSvcList == NULL)
  1033. {
  1034. CleanupClientServerSvcs(cClientSvcs, aClientSvcs, cServerSvcs, aServerSvcs);
  1035. return;
  1036. }
  1037. ZeroMemory(pSvcList, sizeof(SECPKG) * cServerSvcs);
  1038. // Loop over the list of authentication services to register.
  1039. for (i = 0; i < cServerSvcs; i++)
  1040. {
  1041. Status = RpcServerRegisterAuthInfo( NULL, aServerSvcs[i], NULL, NULL );
  1042. if (Status == RPC_S_OK)
  1043. {
  1044. pSvcList[j].wId = aServerSvcs[i];
  1045. pSvcList[j].pName = NULL;
  1046. for (k= 0; k < cClientSvcs; k++)
  1047. {
  1048. if (aClientSvcs[k].wId == aServerSvcs[i])
  1049. {
  1050. if (aClientSvcs[k].pName)
  1051. {
  1052. DWORD dwLen = lstrlen(aClientSvcs[k].pName) + 1;
  1053. pSvcList[j].pName = new WCHAR[dwLen];
  1054. if (!pSvcList[j].pName)
  1055. {
  1056. // No mem; cleanup previously-allocated stuff and return
  1057. for (i = 0; i < cServerSvcs; i++)
  1058. {
  1059. if (pSvcList[i].pName)
  1060. {
  1061. delete pSvcList[i].pName;
  1062. }
  1063. }
  1064. delete pSvcList;
  1065. CleanupClientServerSvcs(cClientSvcs, aClientSvcs, cServerSvcs, aServerSvcs);
  1066. return;
  1067. }
  1068. lstrcpy(pSvcList[j].pName, aClientSvcs[k].pName);
  1069. }
  1070. break;
  1071. }
  1072. }
  1073. ASSERT( pSvcList[j].pName != NULL );
  1074. j++;
  1075. }
  1076. }
  1077. CleanupClientServerSvcs(cClientSvcs, aClientSvcs, cServerSvcs, aServerSvcs);
  1078. cClientSvcs = 0;
  1079. aClientSvcs = NULL;
  1080. cServerSvcs = 0;
  1081. aServerSvcs = NULL;
  1082. // If no authentication services were registered.
  1083. if (j == 0)
  1084. return;
  1085. // Save the new service list if no other thread has.
  1086. gpClientLock->LockExclusive();
  1087. if (!gfRegisteredAuthInfo)
  1088. {
  1089. gfRegisteredAuthInfo = TRUE;
  1090. s_cRpcssSvc = j;
  1091. s_aRpcssSvc = pSvcList;
  1092. pSvcList = NULL;
  1093. }
  1094. gpClientLock->UnlockExclusive();
  1095. // Free the service list if not saved in a global.
  1096. if (pSvcList)
  1097. {
  1098. for (i = 0; i < cServerSvcs; i++)
  1099. {
  1100. if (pSvcList[i].pName)
  1101. {
  1102. delete pSvcList[i].pName;
  1103. }
  1104. }
  1105. delete pSvcList;
  1106. }
  1107. return;
  1108. }
  1109. /*++
  1110. Routine Description:
  1111. Return TRUE if the specified authentication service is in the
  1112. dual string array.
  1113. --*/
  1114. BOOL ValidAuthnSvc( const DUALSTRINGARRAY *pBinding, WORD wService )
  1115. {
  1116. const WCHAR *pwstrT = &pBinding->aStringArray[pBinding->wSecurityOffset];
  1117. while (*pwstrT)
  1118. {
  1119. if (*pwstrT == wService)
  1120. {
  1121. return TRUE;
  1122. }
  1123. pwstrT = OrStringSearch((PWSTR) pwstrT, 0) + 1;
  1124. }
  1125. return FALSE;
  1126. }
  1127. //
  1128. // Local ID allocation
  1129. //
  1130. BOOL
  1131. AllocateId(ID* pID)
  1132. /*++
  1133. Routine Description:
  1134. Allocates and returns a random 64-bit integer.
  1135. Arguments:
  1136. pID - pointer to the caller's 64-bit #
  1137. Return Value:
  1138. TRUE -- random # successfully generated
  1139. FALSE -- error occurred
  1140. --*/
  1141. {
  1142. ASSERT(pID);
  1143. if (FAILED(gRNG.GenerateRandomNumber(pID, sizeof(*pID))))
  1144. {
  1145. return FALSE;
  1146. }
  1147. return TRUE;
  1148. }
  1149. //
  1150. // Implementation of random # generation wrapper class
  1151. //
  1152. // single global definition of the above class
  1153. CRandomNumberGenerator gRNG;
  1154. // Constructor\destructor
  1155. CRandomNumberGenerator::CRandomNumberGenerator() : _rc4SafeCtx(NULL) {}
  1156. CRandomNumberGenerator::~CRandomNumberGenerator()
  1157. {
  1158. if (_rc4SafeCtx)
  1159. {
  1160. rc4_safe_shutdown(_rc4SafeCtx); // free safe rc4 resources.
  1161. _rc4SafeCtx = NULL;
  1162. }
  1163. }
  1164. // Initialize - not threadsafe
  1165. BOOL CRandomNumberGenerator::Initialize()
  1166. {
  1167. if (!_rc4SafeCtx)
  1168. rc4_safe_startup(&_rc4SafeCtx);
  1169. // if this fails to init, we should find out why
  1170. ASSERT(_rc4SafeCtx);
  1171. return (_rc4SafeCtx) ? TRUE : FALSE;
  1172. }
  1173. #define RC4_REKEY_PARAM (500000)
  1174. // GenerateRandomNumber - threadsafe
  1175. HRESULT CRandomNumberGenerator::GenerateRandomNumber(PVOID pBuffer, ULONG ulBufSize)
  1176. {
  1177. unsigned int KeyEntry;
  1178. unsigned int KeyBytesUsed = 0;
  1179. if (!_rc4SafeCtx)
  1180. {
  1181. ASSERT(!"Should not be called before Initialize\n");
  1182. return E_OUTOFMEMORY;
  1183. }
  1184. rc4_safe_select(_rc4SafeCtx, &KeyEntry, &KeyBytesUsed);
  1185. if (KeyBytesUsed >= RC4_REKEY_PARAM)
  1186. {
  1187. BYTE newSeed[256];
  1188. if (!RtlGenRandom(newSeed, sizeof(newSeed)))
  1189. {
  1190. ASSERT(!"RtlGenRandom failure\n");
  1191. return E_OUTOFMEMORY;
  1192. }
  1193. rc4_safe_key(_rc4SafeCtx, KeyEntry, sizeof(newSeed), newSeed);
  1194. }
  1195. // the rc4_safe fucntion is thread safe
  1196. rc4_safe(_rc4SafeCtx, KeyEntry, ulBufSize, pBuffer);
  1197. return S_OK;
  1198. }
  1199. //
  1200. // Debug helper(s)
  1201. //
  1202. #if DBG
  1203. int __cdecl __RPC_FAR ValidateError(
  1204. IN ORSTATUS Status,
  1205. IN ...)
  1206. /*++
  1207. Routine Description
  1208. Tests that 'Status' is one of an expected set of error codes.
  1209. Used on debug builds as part of the VALIDATE() macro.
  1210. Example:
  1211. VALIDATE( (Status,
  1212. OR_BADSET,
  1213. // more error codes here
  1214. OR_OK,
  1215. 0) // list must be terminated with 0
  1216. );
  1217. This function is called with the OrStatus and expected errors codes
  1218. as parameters. If OrStatus is not one of the expected error
  1219. codes and it not zero a message will be printed to the debugger
  1220. and the function will return false. The VALIDATE macro ASSERT's the
  1221. return value.
  1222. Arguments:
  1223. Status - Status code in question.
  1224. ... - One or more expected status codes. Terminated with 0 (OR_OK).
  1225. Return Value:
  1226. TRUE - Status code is in the list or the status is 0.
  1227. FALSE - Status code is not in the list.
  1228. --*/
  1229. {
  1230. RPC_STATUS CurrentStatus;
  1231. va_list Marker;
  1232. if (Status == 0) return(TRUE);
  1233. va_start(Marker, Status);
  1234. while (CurrentStatus = va_arg(Marker, RPC_STATUS))
  1235. {
  1236. if (CurrentStatus == Status)
  1237. {
  1238. return(TRUE);
  1239. }
  1240. }
  1241. va_end(Marker);
  1242. KdPrintEx((DPFLTR_DCOMSS_ID,
  1243. DPFLTR_WARNING_LEVEL,
  1244. "OR Assertion: unexpected failure %lu\n",
  1245. (unsigned long)Status));
  1246. return(FALSE);
  1247. }
  1248. //
  1249. // Dummy implementation to keep the linker happy
  1250. //
  1251. HRESULT CStackWalkerCF_CreateInstance (IUnknown *pUnkOuter, REFIID riid, void** ppv)
  1252. {
  1253. ASSERT (!"You shouldn't be calling this");
  1254. return E_NOTIMPL;
  1255. }
  1256. #endif