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.

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