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.

999 lines
29 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. ObjEx.cxx
  5. Abstract:
  6. Main entry point for the object exporter service.
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 02-28-95 Bits 'n pieces
  11. ronans 04-14-97 HTTP support
  12. --*/
  13. #include <or.hxx>
  14. #include <mach.hxx>
  15. #include <misc.hxx>
  16. extern "C"
  17. {
  18. #define SECURITY_WIN32 // Used by sspi.h
  19. #include <sspi.h> // EnumerateSecurityPackages
  20. }
  21. //
  22. // Process globals - read-only except during init.
  23. //
  24. // MID of the string bindings for this machine.
  25. MID gLocalMid = 0;
  26. // Contains the buffer of protseq's to listen on from the registry
  27. PWSTR gpwstrProtseqs = 0;
  28. // Number of remote protseqs used by this process.
  29. USHORT cMyProtseqs = 0;
  30. // ProtseqIds of the remote protseqs used by this process.
  31. USHORT *aMyProtseqs = 0;
  32. BOOL g_fClientHttp = FALSE;
  33. //
  34. // Process globals - read-write
  35. //
  36. CSharedLock *gpServerLock = 0;
  37. CSharedLock *gpClientLock = 0;
  38. CSharedLock *gpProcessListLock = 0;
  39. CSharedLock *gpIPCheckLock = 0;
  40. CHashTable *gpServerOxidTable = 0;
  41. CHashTable *gpClientOxidTable = 0;
  42. CPList *gpClientOxidPList = 0;
  43. CHashTable *gpServerOidTable = 0;
  44. CServerOidPList *gpServerOidPList = 0;
  45. CList *gpServerPinnedOidList = 0;
  46. CHashTable *gpClientOidTable = 0;
  47. CServerSetTable *gpServerSetTable = 0;
  48. CHashTable *gpClientSetTable = 0;
  49. CPList *gpClientSetPList = 0;
  50. CHashTable *gpMidTable = 0;
  51. CList *gpTokenList = 0;
  52. DWORD gNextThreadID = 1;
  53. //+-------------------------------------------------------------------------
  54. //
  55. // Function: ComputeSecurity
  56. //
  57. // Synopsis: Looks up some registry keys and enumerates the security
  58. // packages on this machine.
  59. //
  60. //--------------------------------------------------------------------------
  61. // These variables hold values read out of the registry and cached.
  62. // s_fEnableDCOM is false if DCOM is disabled. The others contain
  63. // authentication information for legacy applications.
  64. BOOL s_fCatchServerExceptions;
  65. BOOL s_fBreakOnSilencedServerExceptions;
  66. BOOL s_fEnableDCOM;
  67. DWORD s_lAuthnLevel;
  68. DWORD s_lImpLevel;
  69. BOOL s_fMutualAuth;
  70. BOOL s_fSecureRefs;
  71. WCHAR *s_pLegacySecurity;
  72. DWORD s_dwLegacySecurityLen; // cached length of s_pLegacySecurity
  73. // ronans - s_fEnableDCOMHTTP is false if DCOMHTTP is disabled.
  74. BOOL s_fEnableDCOMHTTP;
  75. // s_sServerSvc is a list of security providers that OLE servers can use.
  76. // s_aClientSvc is a list of security providers that OLE clients can use.
  77. // The difference is that Chicago only supports the client side of some
  78. // security providers and OLE servers must know how to determine the
  79. // principal name for the provider. Clients get the principal name from
  80. // the server.
  81. DWORD s_cServerSvc = 0;
  82. USHORT *s_aServerSvc = NULL;
  83. DWORD s_cClientSvc = 0;
  84. SECPKG *s_aClientSvc = NULL;
  85. // The registry key for OLE's registry data.
  86. HKEY s_hOle = NULL;
  87. //+-------------------------------------------------------------------------
  88. //
  89. // Function: FindSvc
  90. //
  91. // Synopsis: Returns index of the specified authentication service or -1.
  92. //
  93. //--------------------------------------------------------------------------
  94. DWORD FindSvc( USHORT AuthnSvc, USHORT *aAuthnSvc, DWORD cAuthnSvc )
  95. {
  96. DWORD i;
  97. // Look for the id in the array.
  98. for (i = 0; i < cAuthnSvc; i++)
  99. if (aAuthnSvc[i] == AuthnSvc)
  100. return i;
  101. return -1;
  102. }
  103. //+-------------------------------------------------------------------------
  104. //
  105. // Function: FindSvc
  106. //
  107. // Synopsis: Returns index of the specified authentication service or -1.
  108. //
  109. //--------------------------------------------------------------------------
  110. DWORD FindSvc( USHORT AuthnSvc, SECPKG *aAuthnSvc, DWORD cAuthnSvc )
  111. {
  112. DWORD i;
  113. // Look for the id in the array.
  114. for (i = 0; i < cAuthnSvc; i++)
  115. if (aAuthnSvc[i].wId == AuthnSvc)
  116. return i;
  117. return -1;
  118. }
  119. //+-------------------------------------------------------------------------
  120. //
  121. // Function: ComputeSecurity
  122. //
  123. // Synopsis: Looks up some registry keys and enumerates the security
  124. // packages on this machine.
  125. //
  126. //--------------------------------------------------------------------------
  127. void ComputeSecurity()
  128. {
  129. SecPkgInfo *pAllPkg;
  130. SecPkgInfo *pNext;
  131. HRESULT hr;
  132. DWORD i;
  133. DWORD j;
  134. DWORD lMaxLen;
  135. HKEY hKey;
  136. DWORD lType;
  137. DWORD lData;
  138. DWORD lDataSize;
  139. WCHAR cBuffer[80];
  140. WCHAR *pSecProt = cBuffer;
  141. DWORD cServerSvc;
  142. USHORT *aServerSvc = NULL;
  143. DWORD cClientSvc;
  144. SECPKG *aClientSvc = NULL;
  145. BOOL fFiltered = FALSE;
  146. // Get the list of security packages.
  147. cClientSvc = 0;
  148. cServerSvc = 0;
  149. hr = EnumerateSecurityPackages( &lMaxLen, &pAllPkg );
  150. if (hr == SEC_E_OK)
  151. {
  152. // Allocate memory for both service lists.
  153. aServerSvc = (USHORT*)MIDL_user_allocate(sizeof(USHORT) * lMaxLen);
  154. aClientSvc = (SECPKG*)MIDL_user_allocate(sizeof(SECPKG) * lMaxLen);
  155. if (aServerSvc == NULL || aClientSvc == NULL)
  156. {
  157. hr = E_OUTOFMEMORY;
  158. MIDL_user_free(aServerSvc);
  159. MIDL_user_free(aClientSvc);
  160. aServerSvc = NULL;
  161. aClientSvc = NULL;
  162. // if out-of-mem, don't keep going.
  163. FreeContextBuffer(pAllPkg);
  164. return;
  165. }
  166. else
  167. {
  168. ZeroMemory(aServerSvc, sizeof(USHORT) * lMaxLen);
  169. ZeroMemory(aClientSvc, sizeof(SECPKG) * lMaxLen);
  170. // Check all packages.
  171. pNext = pAllPkg;
  172. for (i = 0; i < lMaxLen; i++)
  173. {
  174. // Authentication services with RPC id SECPKG_ID_NONE (0xffff)
  175. // won't work with RPC.
  176. if (pNext->wRPCID != SECPKG_ID_NONE)
  177. {
  178. // Determine if clients can use the package but don't
  179. // save duplicates.
  180. if ((pNext->fCapabilities & SECPKG_FLAG_CONNECTION) &&
  181. FindSvc(pNext->wRPCID, aClientSvc, cClientSvc) == -1)
  182. {
  183. // Copy rpcid
  184. aClientSvc[cClientSvc].wId = pNext->wRPCID;
  185. // Copy secpkg name if there is one
  186. if (pNext->Name)
  187. {
  188. DWORD dwBufSize = (lstrlen(pNext->Name) + 1) * sizeof(WCHAR);
  189. aClientSvc[cClientSvc].pName = (WCHAR*)MIDL_user_allocate(dwBufSize);
  190. if (!aClientSvc[cClientSvc].pName)
  191. {
  192. // No mem. Clean up what we have, and return
  193. FreeContextBuffer(pAllPkg);
  194. CleanupClientServerSvcs(cClientSvc,
  195. aClientSvc,
  196. cServerSvc,
  197. aServerSvc);
  198. return;
  199. }
  200. lstrcpy(aClientSvc[cClientSvc].pName, pNext->Name);
  201. }
  202. cClientSvc++;
  203. }
  204. // Determine if servers can use the package but don't save dups.
  205. if ( (pNext->fCapabilities & SECPKG_FLAG_CONNECTION) &&
  206. ~(pNext->fCapabilities & (SECPKG_FLAG_CLIENT_ONLY)) &&
  207. FindSvc(pNext->wRPCID, aServerSvc, cServerSvc) == -1)
  208. {
  209. aServerSvc[cServerSvc++] = pNext->wRPCID;
  210. }
  211. }
  212. pNext++;
  213. }
  214. }
  215. FreeContextBuffer(pAllPkg);
  216. pAllPkg = NULL;
  217. }
  218. // Sort and filter the security provider list by the security protocol value.
  219. hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\RPC",
  220. NULL, KEY_QUERY_VALUE, &hKey );
  221. if (hr == ERROR_SUCCESS)
  222. {
  223. // Query the value for DCOM Security
  224. // Note: this key is undocumented and is meant only for use by the test team.
  225. lDataSize = sizeof(cBuffer);
  226. hr = RegQueryValueEx( hKey, L"DCOM Security", NULL, &lType,
  227. (unsigned char *) pSecProt, &lDataSize );
  228. // Retry with more space if necessary
  229. if (hr == ERROR_MORE_DATA)
  230. {
  231. pSecProt = (WCHAR *) _alloca(lDataSize);
  232. hr = RegQueryValueEx( hKey, L"DCOM Security", NULL, &lType,
  233. (unsigned char *) pSecProt, &lDataSize );
  234. }
  235. if (hr == ERROR_SUCCESS && lType == REG_MULTI_SZ && lDataSize > 3)
  236. {
  237. fFiltered = TRUE;
  238. // Save original list
  239. DWORD cServerSvcPreFilter = cServerSvc;
  240. USHORT *aServerSvcPreFilter = aServerSvc;
  241. cServerSvc = 0;
  242. aServerSvc = NULL;
  243. // Allocate memory for server service list.
  244. aServerSvc = (USHORT*)MIDL_user_allocate(sizeof(USHORT) * cServerSvcPreFilter);
  245. if (!aServerSvc)
  246. {
  247. // No mem, cleanup and return
  248. CleanupClientServerSvcs(cClientSvc,
  249. aClientSvc,
  250. cServerSvcPreFilter,
  251. aServerSvcPreFilter);
  252. return;
  253. }
  254. ZeroMemory(aServerSvc, sizeof(USHORT) * cServerSvcPreFilter);
  255. // Fill in filtered list
  256. while (*pSecProt != 0 && (cServerSvc < cServerSvcPreFilter))
  257. {
  258. i = _wtoi( pSecProt );
  259. ASSERT(i <= USHRT_MAX); // this would be a test bug
  260. if (FindSvc( (USHORT)i, aServerSvcPreFilter, (USHORT)cServerSvcPreFilter ) != -1)
  261. aServerSvc[cServerSvc++] = (USHORT)i;
  262. pSecProt += wcslen(pSecProt)+1;
  263. }
  264. // Cleanup old server svc list. Will save filtered list below on normal path
  265. MIDL_user_free(aServerSvcPreFilter);
  266. aServerSvcPreFilter = NULL;
  267. cServerSvcPreFilter = 0;
  268. }
  269. // Close the key.
  270. RegCloseKey( hKey );
  271. }
  272. // Find snego in the client list.
  273. for (i = 0; i < cClientSvc; i++)
  274. if (aClientSvc[i].wId == RPC_C_AUTHN_GSS_NEGOTIATE)
  275. break;
  276. // If snego exists and is not first, move it first.
  277. if (i < cClientSvc && i != 0)
  278. {
  279. SECPKG sSwap = s_aClientSvc[i];
  280. memmove( &aClientSvc[1], &aClientSvc[0], sizeof(SECPKG)*i );
  281. aClientSvc[0] = sSwap;
  282. }
  283. // If there is no DCOM security value, move snego first in the server list.
  284. if (!fFiltered)
  285. {
  286. // Find snego in the server list.
  287. for (i = 0; i < cServerSvc; i++)
  288. if (aServerSvc[i] == RPC_C_AUTHN_GSS_NEGOTIATE)
  289. break;
  290. // If snego exists and is not first, move it first.
  291. if (i < cServerSvc && i != 0)
  292. {
  293. USHORT usSwap = aServerSvc[i];
  294. memmove( &aServerSvc[1], &aServerSvc[0], sizeof(USHORT)*i );
  295. aServerSvc[0] = usSwap;
  296. }
  297. }
  298. // Save new client\server svc lists.
  299. SetClientServerSvcs(cClientSvc, aClientSvc, cServerSvc, aServerSvc);
  300. // Set all the security flags to their default values.
  301. s_fEnableDCOM = FALSE;
  302. s_fEnableDCOMHTTP = FALSE;
  303. s_fCatchServerExceptions = TRUE;
  304. s_fBreakOnSilencedServerExceptions = FALSE;
  305. s_lAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
  306. s_lImpLevel = RPC_C_IMP_LEVEL_IDENTIFY;
  307. s_fMutualAuth = FALSE;
  308. s_fSecureRefs = FALSE;
  309. // Open the security key. s_hOle will only be non-NULL on the first pass
  310. // thru this code, after that we keep it open forever.
  311. if (s_hOle == NULL)
  312. {
  313. HKEY hOle = NULL;
  314. hr = RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\OLE",
  315. NULL, KEY_READ, &hOle );
  316. if (hr != ERROR_SUCCESS)
  317. return;
  318. LPVOID pv = InterlockedCompareExchangePointer ( (void **) &s_hOle, (void *) hOle, NULL);
  319. if ( pv != NULL )
  320. {
  321. RegCloseKey(hOle);
  322. }
  323. }
  324. ASSERT(s_hOle);
  325. // Query the value for EnableDCOM.
  326. lDataSize = sizeof(lData );
  327. hr = RegQueryValueEx( s_hOle, L"EnableDCOM", NULL, &lType,
  328. (unsigned char *) &lData, &lDataSize );
  329. if (hr == ERROR_SUCCESS && lType == REG_SZ && lDataSize != 0)
  330. {
  331. if (*((WCHAR *) &lData) == L'y' ||
  332. *((WCHAR *) &lData) == L'Y')
  333. s_fEnableDCOM = TRUE;
  334. }
  335. // ronans - Query the value for EnableDCOMHTTP.
  336. lDataSize = sizeof(lData );
  337. hr = RegQueryValueEx( s_hOle, L"EnableDCOMHTTP", NULL, &lType,
  338. (unsigned char *) &lData, &lDataSize );
  339. if (hr == ERROR_SUCCESS && lType == REG_SZ && lDataSize != 0)
  340. {
  341. if (*((WCHAR *) &lData) == L'y' ||
  342. *((WCHAR *) &lData) == L'Y')
  343. {
  344. s_fEnableDCOMHTTP = TRUE;
  345. KdPrintEx((DPFLTR_DCOMSS_ID,
  346. DPFLTR_WARNING_LEVEL,
  347. "OR: EnableDCOMHTTP set to TRUE\n"));
  348. }
  349. }
  350. if (!s_fEnableDCOMHTTP)
  351. {
  352. KdPrintEx((DPFLTR_DCOMSS_ID,
  353. DPFLTR_WARNING_LEVEL,
  354. "OR: EnableDCOMHTTP set to FALSE\n"));
  355. }
  356. // Query the value for IgnoreServerExceptions. This value is just
  357. // to let some ISVs debug their servers a little easier. In normal
  358. // operation these exceptions should be caught.
  359. lDataSize = sizeof(lData );
  360. hr = RegQueryValueEx( s_hOle, L"IgnoreServerExceptions", NULL, &lType,
  361. (unsigned char *) &lData, &lDataSize );
  362. if (hr == ERROR_SUCCESS && lType == REG_SZ && lDataSize != 0)
  363. {
  364. if (*((WCHAR *) &lData) == L'y' ||
  365. *((WCHAR *) &lData) == L'Y')
  366. s_fCatchServerExceptions = FALSE;
  367. }
  368. // Allow ISVs to enable debugbreaks on all silenced exceptions if there's a debugger present
  369. lDataSize = sizeof(lData );
  370. hr = RegQueryValueEx( s_hOle, L"BreakOnSilencedServerExceptions", NULL, &lType,
  371. (unsigned char *) &lData, &lDataSize );
  372. if (hr == ERROR_SUCCESS && lType == REG_SZ && lDataSize != 0)
  373. {
  374. if (*((WCHAR *) &lData) == L'y' ||
  375. *((WCHAR *) &lData) == L'Y')
  376. s_fBreakOnSilencedServerExceptions = TRUE;
  377. }
  378. // Query the value for the legacy services. Note: this key is undocumented
  379. // and is meant only for use by the test team.
  380. lDataSize = 0;
  381. hr = RegQueryValueEx( s_hOle, L"LegacyAuthenticationService", NULL,
  382. &lType, NULL, &lDataSize );
  383. if (hr == ERROR_SUCCESS && lType == REG_BINARY &&
  384. lDataSize >= sizeof(SECURITYBINDING))
  385. {
  386. WCHAR* pNewLegacySecurity = (WCHAR*)MIDL_user_allocate(sizeof(BYTE) * lDataSize);
  387. if (pNewLegacySecurity != NULL)
  388. {
  389. hr = RegQueryValueEx( s_hOle, L"LegacyAuthenticationService", NULL,
  390. &lType, (unsigned char *) pNewLegacySecurity,
  391. &lDataSize );
  392. // Verify that the data is a security binding.
  393. if (hr != ERROR_SUCCESS ||
  394. lType != REG_BINARY ||
  395. lDataSize < sizeof(SECURITYBINDING) ||
  396. pNewLegacySecurity[1] != 0 ||
  397. pNewLegacySecurity[(lDataSize >> 1) - 1] != 0)
  398. {
  399. MIDL_user_free(pNewLegacySecurity);
  400. pNewLegacySecurity = NULL;
  401. lDataSize = 0;
  402. }
  403. // Set it whether success or not. A misconfigured registry will cause
  404. // us to set it back to NULL.
  405. SetLegacySecurity(pNewLegacySecurity, lDataSize);
  406. }
  407. }
  408. // Query the value for the authentication level.
  409. lDataSize = sizeof(lData);
  410. hr = RegQueryValueEx( s_hOle, L"LegacyAuthenticationLevel", NULL,
  411. &lType, (unsigned char *) &lData, &lDataSize );
  412. if (hr == ERROR_SUCCESS && lType == REG_DWORD)
  413. {
  414. s_lAuthnLevel = lData;
  415. }
  416. // Query the value for the impersonation level.
  417. lDataSize = sizeof(lData);
  418. hr = RegQueryValueEx( s_hOle, L"LegacyImpersonationLevel", NULL,
  419. &lType, (unsigned char *) &lData, &lDataSize );
  420. if (hr == ERROR_SUCCESS && lType == REG_DWORD)
  421. {
  422. s_lImpLevel = lData;
  423. }
  424. // Query the value for mutual authentication.
  425. lDataSize = sizeof(lData);
  426. hr = RegQueryValueEx( s_hOle, L"LegacyMutualAuthentication", NULL,
  427. &lType, (unsigned char *) &lData, &lDataSize );
  428. if (hr == ERROR_SUCCESS && lType == REG_SZ && lDataSize != 0)
  429. {
  430. if (*((WCHAR *) &lData) == L'y' ||
  431. *((WCHAR *) &lData) == L'Y')
  432. s_fMutualAuth = TRUE;
  433. }
  434. // Query the value for secure interface references.
  435. lDataSize = sizeof(lData);
  436. hr = RegQueryValueEx( s_hOle, L"LegacySecureReferences", NULL,
  437. &lType, (unsigned char *) &lData, &lDataSize );
  438. if (hr == ERROR_SUCCESS && lType == REG_SZ && lDataSize != 0)
  439. {
  440. if (*((WCHAR *) &lData) == L'y' ||
  441. *((WCHAR *) &lData) == L'Y')
  442. s_fSecureRefs = TRUE;
  443. }
  444. ASSERT(gpPingSetQuotaManager);
  445. // Query the value for per-user pingset quota.
  446. lDataSize = sizeof(lData);
  447. hr = RegQueryValueEx( s_hOle, L"UserPingSetQuota", NULL,
  448. &lType, (unsigned char *) &lData, &lDataSize );
  449. if (hr == ERROR_SUCCESS && lType == REG_DWORD && lDataSize != 0)
  450. {
  451. gpPingSetQuotaManager->SetPerUserPingSetQuota(lData);
  452. }
  453. }
  454. void
  455. CleanupClientServerSvcs(
  456. DWORD cClientSvcs,
  457. SECPKG* aClientSvcs,
  458. DWORD cServerSvcs, // unused
  459. USHORT* aServerSvcs
  460. )
  461. {
  462. DWORD i;
  463. for (i = 0; i < cClientSvcs; i++)
  464. {
  465. if (aClientSvcs[i].pName)
  466. {
  467. MIDL_user_free(aClientSvcs[i].pName);
  468. }
  469. }
  470. MIDL_user_free(aClientSvcs);
  471. MIDL_user_free(aServerSvcs);
  472. return;
  473. }
  474. void
  475. SetClientServerSvcs(
  476. DWORD cClientSvcs,
  477. SECPKG* aClientSvcs,
  478. DWORD cServerSvcs,
  479. USHORT* aServerSvcs
  480. )
  481. /*++
  482. Routine Description:
  483. Saves the supplied client\server security svcs.
  484. Return Value:
  485. None
  486. --*/
  487. {
  488. gpClientLock->LockExclusive();
  489. // Cleanup the old ones
  490. CleanupClientServerSvcs(s_cClientSvc, s_aClientSvc, s_cServerSvc, s_aServerSvc);
  491. // Save the new ones
  492. s_cClientSvc = cClientSvcs;
  493. s_aClientSvc = aClientSvcs;
  494. s_cServerSvc = cServerSvcs;
  495. s_aServerSvc = aServerSvcs;
  496. gpClientLock->UnlockExclusive();
  497. return;
  498. }
  499. BOOL
  500. GetClientServerSvcs(
  501. DWORD* pcClientSvcs,
  502. SECPKG** paClientSvcs,
  503. DWORD* pcServerSvcs,
  504. USHORT** paServerSvcs
  505. )
  506. /*++
  507. Routine Description:
  508. Saves the supplied client\server security svcs.
  509. Return Value:
  510. TRUE -- success
  511. FALSE -- no mem
  512. --*/
  513. {
  514. BOOL fReturn = FALSE;
  515. SECPKG* aClientSvcs = NULL;
  516. USHORT* aServerSvcs = NULL;
  517. gpClientLock->LockShared();
  518. *pcClientSvcs = 0;
  519. *paClientSvcs = NULL;
  520. *pcServerSvcs = 0;
  521. *paServerSvcs = NULL;
  522. aServerSvcs = (USHORT*)MIDL_user_allocate(sizeof(USHORT) * s_cServerSvc);
  523. if (aServerSvcs)
  524. {
  525. // Copy server svcs
  526. CopyMemory(aServerSvcs, s_aServerSvc, sizeof(USHORT) * s_cServerSvc);
  527. aClientSvcs = (SECPKG*)MIDL_user_allocate(sizeof(SECPKG) * s_cClientSvc);
  528. if (aClientSvcs)
  529. {
  530. DWORD i;
  531. ZeroMemory(aClientSvcs, sizeof(SECPKG) * s_cClientSvc);
  532. // Copy client svcs
  533. for (i = 0; i < s_cClientSvc; i++)
  534. {
  535. // Copy the id
  536. aClientSvcs[i].wId = s_aClientSvc[i].wId;
  537. // Copy the name if it has one
  538. if (s_aClientSvc[i].pName)
  539. {
  540. DWORD dwLen = lstrlen(s_aClientSvc[i].pName) + 1;
  541. aClientSvcs[i].pName = (WCHAR*)MIDL_user_allocate(sizeof(WCHAR) * dwLen);
  542. if (!aClientSvcs[i].pName)
  543. {
  544. // Cleanup what we have, then return
  545. CleanupClientServerSvcs(s_cClientSvc,
  546. aClientSvcs,
  547. s_cServerSvc,
  548. aServerSvcs);
  549. break;
  550. }
  551. lstrcpy(aClientSvcs[i].pName, s_aClientSvc[i].pName);
  552. }
  553. }
  554. if (i == s_cClientSvc)
  555. {
  556. // Success - caller will now own the memory
  557. *pcClientSvcs = s_cClientSvc;
  558. *paClientSvcs = aClientSvcs;
  559. *pcServerSvcs = s_cServerSvc;
  560. *paServerSvcs = aServerSvcs;
  561. fReturn = TRUE;
  562. }
  563. }
  564. else
  565. {
  566. MIDL_user_free(aServerSvcs);
  567. }
  568. }
  569. gpClientLock->UnlockShared();
  570. return fReturn;
  571. }
  572. BOOL
  573. GetLegacySecurity(
  574. WCHAR** ppszLegacySecurity
  575. )
  576. {
  577. BOOL fRet = TRUE;
  578. DWORD dwLen;
  579. *ppszLegacySecurity = NULL;
  580. gpClientLock->LockShared();
  581. if (s_dwLegacySecurityLen)
  582. {
  583. *ppszLegacySecurity = (WCHAR*)MIDL_user_allocate(sizeof(BYTE) * s_dwLegacySecurityLen);
  584. if (*ppszLegacySecurity)
  585. {
  586. CopyMemory(*ppszLegacySecurity, s_pLegacySecurity, sizeof(BYTE) * s_dwLegacySecurityLen);
  587. fRet = TRUE;
  588. }
  589. else
  590. fRet = FALSE;
  591. }
  592. gpClientLock->UnlockShared();
  593. return fRet;
  594. };
  595. void
  596. SetLegacySecurity(
  597. WCHAR* pszLegacySecurity,
  598. DWORD dwDataSize
  599. )
  600. {
  601. gpClientLock->LockExclusive();
  602. // Free the old one, save the new one
  603. MIDL_user_free(s_pLegacySecurity);
  604. s_pLegacySecurity = pszLegacySecurity;
  605. // Cache the size of the new data
  606. s_dwLegacySecurityLen = dwDataSize;
  607. gpClientLock->UnlockExclusive();
  608. return;
  609. }
  610. //
  611. // Startup
  612. //
  613. static CONST PWSTR gpwstrProtocolsPath = L"Software\\Microsoft\\Rpc";
  614. static CONST PWSTR gpwstrProtocolsValue = L"DCOM Protocols";
  615. DWORD StartObjectExporter(
  616. void
  617. )
  618. /*++
  619. Routine Description:
  620. Starts the object resolver service.
  621. Arguments:
  622. None
  623. Return Value:
  624. None
  625. Notes: This function is a bit weak on cleanup code in case of errors. This
  626. is because if this function fails for any reason, RPCSS will not
  627. start. Usually this function will never fail since 1) we always
  628. start at machine boot, when lots of memory is available; and 2) we
  629. don't support stopping or restarting of RPCSS.
  630. --*/
  631. {
  632. ORSTATUS status;
  633. int i;
  634. DWORD tid;
  635. HANDLE hThread;
  636. RPC_BINDING_VECTOR *pbv;
  637. status = RtlInitializeCriticalSection(&gcsFastProcessLock);
  638. if (!NT_SUCCESS(status))
  639. return status;
  640. status = RtlInitializeCriticalSection(&gcsTokenLock);
  641. if (!NT_SUCCESS(status))
  642. return status;
  643. status = OR_OK;
  644. // Allocate PingSet quota manager
  645. gpPingSetQuotaManager = new CPingSetQuotaManager(status);
  646. if ((status != OR_OK) || !gpPingSetQuotaManager)
  647. {
  648. delete gpPingSetQuotaManager;
  649. gpPingSetQuotaManager = NULL;
  650. return OR_NOMEM;
  651. }
  652. // Lookup security data.
  653. ComputeSecurity();
  654. UpdateState(SERVICE_START_PENDING);
  655. // Allocate tables
  656. // Assume 16 exporting processes/threads.
  657. gpServerOxidTable = new CHashTable(status, DEBUG_MIN(16,4));
  658. if (status != OR_OK)
  659. {
  660. delete gpServerOxidTable;
  661. gpServerOxidTable = 0;
  662. }
  663. // Assume 11 exported OIDs per process/thread.
  664. gpServerOidTable = new CHashTable(status, 11*(DEBUG_MIN(16,4)));
  665. if (status != OR_OK)
  666. {
  667. delete gpServerOidTable;
  668. gpServerOidTable = 0;
  669. }
  670. gpServerSetTable = new CServerSetTable(status);
  671. if (status != OR_OK)
  672. {
  673. delete gpServerSetTable;
  674. gpServerSetTable = 0;
  675. }
  676. // Assume < 16 imported OXIDs
  677. gpClientOxidTable = new CHashTable(status, DEBUG_MIN(16,4));
  678. if (status != OR_OK)
  679. {
  680. delete gpClientOxidTable;
  681. gpClientOxidTable = 0;
  682. }
  683. // Assume an average of 4 imported object ids per imported oxid
  684. gpClientOidTable = new CHashTable(status, 4*DEBUG_MIN(16,4));
  685. if (status != OR_OK)
  686. {
  687. delete gpClientOidTable;
  688. gpClientOidTable = 0;
  689. }
  690. // Assume <16 servers (remote machines) in use per client.
  691. gpClientSetTable = new CHashTable(status, DEBUG_MIN(16,4));
  692. if (status != OR_OK)
  693. {
  694. delete gpClientSetTable;
  695. gpClientSetTable = 0;
  696. }
  697. gpMidTable = new CHashTable(status, DEBUG_MIN(16,2));
  698. if (status != OR_OK)
  699. {
  700. delete gpMidTable;
  701. gpMidTable = 0;
  702. }
  703. // Allocate lists
  704. gpClientOxidPList = new CPList(status, BasePingInterval);
  705. if (status != OR_OK)
  706. {
  707. delete gpClientOxidPList;
  708. gpClientOxidPList = 0;
  709. }
  710. gpServerOidPList = new CServerOidPList(status);
  711. if (status != OR_OK)
  712. {
  713. delete gpServerOidPList;
  714. gpServerOidPList = 0;
  715. }
  716. gpClientSetPList = new CPList(status, BasePingInterval);
  717. if (status != OR_OK)
  718. {
  719. delete gpClientSetPList;
  720. gpClientSetPList = 0;
  721. }
  722. gpTokenList = new CList();
  723. gpProcessList = new CBList(DEBUG_MIN(128,4));
  724. gpServerPinnedOidList = new CList();
  725. // Allocate RPC security callback manager
  726. gpCRpcSecurityCallbackMgr = new CRpcSecurityCallbackManager(status);
  727. if (status != OR_OK)
  728. {
  729. delete gpCRpcSecurityCallbackMgr;
  730. gpCRpcSecurityCallbackMgr = NULL;
  731. }
  732. if ( status != OR_OK
  733. || !gpServerLock
  734. || !gpClientLock
  735. || !gpServerOxidTable
  736. || !gpClientOxidTable
  737. || !gpClientOxidPList
  738. || !gpServerOidTable
  739. || !gpServerOidPList
  740. || !gpClientOidTable
  741. || !gpMidTable
  742. || !gpServerSetTable
  743. || !gpClientSetTable
  744. || !gpClientSetPList
  745. || !gpTokenList
  746. || !gpProcessList
  747. || !gpServerPinnedOidList
  748. || !gpCRpcSecurityCallbackMgr
  749. )
  750. {
  751. return(OR_NOMEM);
  752. }
  753. // Read protseqs from the registry
  754. DWORD dwType;
  755. DWORD dwLenBuffer = 118;
  756. HKEY hKey;
  757. status =
  758. RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  759. gpwstrProtocolsPath,
  760. 0,
  761. KEY_READ,
  762. &hKey);
  763. ASSERT(gpwstrProtseqs == 0);
  764. if (status == ERROR_SUCCESS)
  765. {
  766. do
  767. {
  768. delete gpwstrProtseqs;
  769. gpwstrProtseqs = new WCHAR[(dwLenBuffer + 1 )/2];
  770. if (gpwstrProtseqs)
  771. {
  772. status = RegQueryValueEx(hKey,
  773. gpwstrProtocolsValue,
  774. 0,
  775. &dwType,
  776. (PBYTE)gpwstrProtseqs,
  777. &dwLenBuffer
  778. );
  779. }
  780. else
  781. {
  782. return(OR_NOMEM);
  783. }
  784. }
  785. while (status == ERROR_MORE_DATA);
  786. RegCloseKey(hKey);
  787. }
  788. if ( status != ERROR_SUCCESS
  789. || dwType != REG_MULTI_SZ )
  790. {
  791. KdPrintEx((DPFLTR_DCOMSS_ID,
  792. DPFLTR_WARNING_LEVEL,
  793. "OR: No protseqs configured\n"));
  794. delete gpwstrProtseqs;
  795. gpwstrProtseqs = 0;
  796. }
  797. // Always listen to local protocols
  798. // If this fails, the service should fail.
  799. status = UseProtseqIfNecessary(ID_LPC);
  800. if (status != RPC_S_OK)
  801. {
  802. return(status);
  803. }
  804. UpdateState(SERVICE_START_PENDING);
  805. // set g_fClientHttp to false initially
  806. g_fClientHttp = FALSE;
  807. // This fails during setup. If it fails, only remote secure activations
  808. // will be affected so it is safe to ignore.
  809. RegisterAuthInfoIfNecessary();
  810. // Construct remote protseq id and compressed binding arrays.
  811. status = StartListeningIfNecessary();
  812. if (status != OR_OK)
  813. {
  814. return(status);
  815. }
  816. UpdateState(SERVICE_START_PENDING);
  817. // Register OR server interfaces.
  818. status =
  819. RpcServerRegisterIf(_ILocalObjectExporter_ServerIfHandle, 0, 0);
  820. ASSERT(status == RPC_S_OK);
  821. status =
  822. RpcServerRegisterIf(_IObjectExporter_ServerIfHandle, 0, 0);
  823. ASSERT(status == RPC_S_OK);
  824. return(status);
  825. }