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.

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