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.

826 lines
26 KiB

  1. /*++
  2. Copyright (C) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. COMTRANS.CPP
  5. Abstract:
  6. Connects via COM
  7. History:
  8. a-davj 13-Jan-98 Created.
  9. --*/
  10. #include "precomp.h"
  11. #include <wbemidl.h>
  12. #include <wbemint.h>
  13. #include <reg.h>
  14. #include <wbemutil.h>
  15. #include <objidl.h>
  16. #include <cominit.h>
  17. #include "wbemprox.h"
  18. #include "comtrans.h"
  19. #include <winntsec.h>
  20. #include <genutils.h>
  21. #include <arrtempl.h>
  22. #include <wmiutils.h>
  23. #include <strsafe.h>
  24. #include <winsock2.h>
  25. #include <autoptr.h>
  26. // The following should not be changed since 9x boxes to not support privacy.
  27. #define AUTH_LEVEL RPC_C_AUTHN_LEVEL_DEFAULT
  28. class CSocketInit
  29. {
  30. private:
  31. bool m_bInitDone;
  32. public:
  33. CSocketInit() : m_bInitDone(false){};
  34. int Init();
  35. ~CSocketInit(){if(m_bInitDone) WSACleanup ();};
  36. };
  37. int CSocketInit::Init()
  38. {
  39. WORD wVersionRequested;
  40. WSADATA wsaData;
  41. int err;
  42. wVersionRequested = MAKEWORD( 2, 2 );
  43. int iRet = WSAStartup (wVersionRequested, & wsaData);
  44. if(iRet == 0)
  45. m_bInitDone = true;
  46. return iRet;
  47. }
  48. BOOL bGotDot(char * pTest)
  49. {
  50. if(pTest == NULL)
  51. return FALSE;
  52. for(;*pTest && *pTest != '.'; pTest++); // intentional semi
  53. if(*pTest == '.')
  54. return TRUE;
  55. else
  56. return FALSE;
  57. }
  58. struct hostent * GetFQDN(WCHAR * pServer)
  59. {
  60. SIZE_T Len = wcslen(pServer);
  61. SIZE_T LenAnsi = 4*Len;
  62. wmilib::auto_buffer<CHAR> pAnsiServerName(new CHAR[LenAnsi+1]);
  63. ULONG BytesCopyed = 0;
  64. //
  65. // Use the same routine that RPCRT4 uses
  66. //
  67. NTSTATUS Status = RtlUnicodeToMultiByteN(pAnsiServerName.get(),LenAnsi,&BytesCopyed,pServer,Len*sizeof(WCHAR));
  68. if (0 != Status) return NULL;
  69. pAnsiServerName[BytesCopyed] = 0;
  70. // if it is an ip string
  71. long lIP = inet_addr(pAnsiServerName.get());
  72. if(lIP != INADDR_NONE)
  73. {
  74. struct hostent * pRet = gethostbyaddr((char *)&lIP, 4, AF_INET );
  75. if(pRet && pRet->h_name)
  76. {
  77. // search the returned name for at least one dot. Sometimes, gethostbyaddr will just return
  78. // the lanman name and not the fqdn.
  79. if(bGotDot(pRet->h_name))
  80. return pRet; // normal case, all is well!
  81. // try passing the short name to get the fqdn version
  82. DWORD dwLen = lstrlenA(pRet->h_name) + 1;
  83. char * pNew = new char[dwLen];
  84. if(pNew == NULL)
  85. return NULL;
  86. CVectorDeleteMe<char> dm2(pNew);
  87. StringCchCopyA(pNew, dwLen, pRet->h_name);
  88. pRet = gethostbyname(pNew);
  89. if(pRet && bGotDot(pRet->h_name))
  90. return pRet; // normal case, all is well!
  91. }
  92. }
  93. return gethostbyname(pAnsiServerName.get());
  94. }
  95. #define PREFIXSTR L"RPCSS/"
  96. HRESULT BuildReturnString(WCHAR * pFQDN, WCHAR ** ppResult)
  97. {
  98. if(pFQDN == NULL)
  99. return WBEM_E_INVALID_PARAMETER;
  100. DWORD dwBuffLen = wcslen(pFQDN) + wcslen(PREFIXSTR) + 1;
  101. *ppResult = new WCHAR[dwBuffLen];
  102. if(*ppResult == NULL)
  103. return WBEM_E_OUT_OF_MEMORY;
  104. StringCchCopy(*ppResult, dwBuffLen, PREFIXSTR);
  105. StringCchCat(*ppResult, dwBuffLen, pFQDN);
  106. return S_OK;
  107. }
  108. HRESULT GetPrincipal(WCHAR * pServerMachine, WCHAR ** ppResult, BOOL &bLocal, CSocketInit & sock)
  109. {
  110. DWORD dwLocalFQDNLen = 0;
  111. DWORD dwBuffLen;
  112. WCHAR * pwsCurrentCompFQDN = NULL;
  113. bLocal = FALSE;
  114. *ppResult = NULL;
  115. // Get the current computer name in FQDN format
  116. BOOL bRet = GetComputerNameEx(ComputerNameDnsFullyQualified, NULL, &dwLocalFQDNLen);
  117. if(bRet || GetLastError() != ERROR_MORE_DATA)
  118. return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,GetLastError());
  119. dwLocalFQDNLen++; // add one for the null
  120. pwsCurrentCompFQDN = new WCHAR[dwLocalFQDNLen];
  121. if(pwsCurrentCompFQDN == NULL)
  122. return WBEM_E_OUT_OF_MEMORY;
  123. CVectorDeleteMe<WCHAR> dm(pwsCurrentCompFQDN);
  124. bRet = GetComputerNameEx(ComputerNameDnsFullyQualified, pwsCurrentCompFQDN, &dwLocalFQDNLen);
  125. if(!bRet)
  126. return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,GetLastError());
  127. // if the name is "." or equal to the current machine, no need to do much fancy work here
  128. if(bAreWeLocal ( pServerMachine ))
  129. {
  130. bLocal = TRUE;
  131. return BuildReturnString(pwsCurrentCompFQDN, ppResult);
  132. }
  133. // probably not local. Use sockets to establish the FQDN of the server
  134. if(0 != sock.Init())
  135. return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,GetLastError());
  136. struct hostent * pEnt = GetFQDN(pServerMachine);
  137. if(pEnt == NULL || pEnt->h_name == NULL)
  138. {
  139. // we failed. just return the best we can
  140. return BuildReturnString(pServerMachine, ppResult);
  141. }
  142. // all is well. Convert the host name to WCHAR.
  143. DWORD dwHostLen = lstrlenA(pEnt->h_name) + 1;
  144. WCHAR * pwsHostFQDN = new WCHAR[dwHostLen];
  145. if(pwsHostFQDN == NULL)
  146. return WBEM_E_OUT_OF_MEMORY;
  147. CVectorDeleteMe<WCHAR> dm2(pwsHostFQDN);
  148. mbstowcs(pwsHostFQDN, pEnt->h_name, dwHostLen);
  149. // now there is the possibility that they specified the ip of the local machine.
  150. // In that case, set the bLocal in case caller needs to know this
  151. if(wbem_wcsicmp(pwsHostFQDN, pwsCurrentCompFQDN) == 0)
  152. bLocal = TRUE;
  153. // now, make the actual string.
  154. return BuildReturnString(pwsHostFQDN, ppResult);
  155. }
  156. //***************************************************************************
  157. //
  158. // CDCOMTrans::CDCOMTrans
  159. //
  160. // DESCRIPTION:
  161. //
  162. // Constructor.
  163. //
  164. //***************************************************************************
  165. CDCOMTrans::CDCOMTrans()
  166. {
  167. m_cRef=0;
  168. m_pLevel1 = NULL;
  169. InterlockedIncrement(&g_cObj);
  170. m_bInitialized = TRUE;
  171. }
  172. //***************************************************************************
  173. //
  174. // CDCOMTrans::~CDCOMTrans
  175. //
  176. // DESCRIPTION:
  177. //
  178. // Destructor.
  179. //
  180. //***************************************************************************
  181. CDCOMTrans::~CDCOMTrans(void)
  182. {
  183. if(m_pLevel1)
  184. m_pLevel1->Release();
  185. InterlockedDecrement(&g_cObj);
  186. }
  187. //***************************************************************************
  188. // HRESULT CDCOMTrans::QueryInterface
  189. // long CDCOMTrans::AddRef
  190. // long CDCOMTrans::Release
  191. //
  192. // DESCRIPTION:
  193. //
  194. // Standard Com IUNKNOWN functions.
  195. //
  196. //***************************************************************************
  197. STDMETHODIMP CDCOMTrans::QueryInterface (
  198. IN REFIID riid,
  199. OUT PPVOID ppv
  200. )
  201. {
  202. *ppv=NULL;
  203. if (m_bInitialized && (IID_IUnknown==riid || riid == IID_IWbemClientTransport))
  204. *ppv=(IWbemClientTransport *)this;
  205. if (NULL!=*ppv)
  206. {
  207. ((LPUNKNOWN)*ppv)->AddRef();
  208. return NOERROR;
  209. }
  210. return ResultFromScode(E_NOINTERFACE);
  211. }
  212. bool IsImpersonating(SECURITY_IMPERSONATION_LEVEL &impLevel)
  213. {
  214. HANDLE hThreadToken;
  215. bool bImpersonating = false;
  216. if(OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE,
  217. &hThreadToken))
  218. {
  219. DWORD dwBytesReturned = 0;
  220. if(GetTokenInformation(
  221. hThreadToken,
  222. TokenImpersonationLevel,
  223. &impLevel,
  224. sizeof(DWORD),
  225. &dwBytesReturned
  226. ) && ((SecurityImpersonation == impLevel) ||
  227. (SecurityDelegation == impLevel)))
  228. bImpersonating = true;
  229. CloseHandle(hThreadToken);
  230. }
  231. return bImpersonating;
  232. }
  233. //***************************************************************************
  234. //
  235. // IsLocalConnection(IWbemLevel1Login * pLogin)
  236. //
  237. // DESCRIPTION:
  238. //
  239. // Querries the server to see if this is a local connection. This is done
  240. // by creating a event and asking the server to set it. This will only work
  241. // if the server is the same box.
  242. //
  243. // RETURN VALUE:
  244. //
  245. // true if the server is the same box.
  246. //
  247. //***************************************************************************
  248. BOOL IsLocalConnection(IUnknown * pInterface)
  249. {
  250. IRpcOptions *pRpcOpt = NULL;
  251. ULONG_PTR dwProperty = 0;
  252. HRESULT hr = pInterface->QueryInterface(IID_IRpcOptions, (void**)&pRpcOpt);
  253. //DbgPrintfA(0,"QueryInterface(IID_IRpcOptions) hr = %08x\n",hr);
  254. if (SUCCEEDED(hr))
  255. {
  256. hr = pRpcOpt->Query(pInterface, COMBND_SERVER_LOCALITY, &dwProperty);
  257. pRpcOpt->Release();
  258. if (SUCCEEDED(hr))
  259. return (SERVER_LOCALITY_REMOTE == dwProperty)?FALSE:TRUE;
  260. }
  261. else if (E_NOINTERFACE == hr) // real pointer, not a proxy
  262. {
  263. return TRUE;
  264. }
  265. return FALSE;
  266. }
  267. //***************************************************************************
  268. //
  269. // SetClientIdentity
  270. //
  271. // DESCRIPTION:
  272. //
  273. // Passes the machine name and process id to the server. Failure is not
  274. // serious since this is debugging type info in any case.
  275. //
  276. //***************************************************************************
  277. void SetClientIdentity(IUnknown * pLogin, bool bSet, BSTR PrincipalArg, DWORD dwAuthenticationLevel,
  278. COAUTHIDENTITY *pauthident, DWORD dwCapabilities, DWORD dwAuthnSvc)
  279. {
  280. bool bRet = false;
  281. IWbemLoginClientID * pLoginHelper = NULL;
  282. SCODE sc = pLogin->QueryInterface(IID_IWbemLoginClientID, (void **)&pLoginHelper);
  283. if(sc != S_OK)
  284. return;
  285. if(bSet)
  286. sc = WbemSetProxyBlanket(
  287. pLoginHelper,
  288. dwAuthnSvc,
  289. RPC_C_AUTHZ_NONE,
  290. PrincipalArg,
  291. dwAuthenticationLevel,
  292. RPC_C_IMP_LEVEL_IMPERSONATE,
  293. pauthident,
  294. dwCapabilities);
  295. CReleaseMe rm(pLoginHelper);
  296. TCHAR tcMyName[MAX_COMPUTERNAME_LENGTH + 1];
  297. DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
  298. if(!GetComputerName(tcMyName,&dwSize))
  299. return;
  300. long lProcID = GetCurrentProcessId();
  301. pLoginHelper->SetClientInfo(tcMyName, lProcID, 0);
  302. }
  303. SCODE CDCOMTrans::DoConnection(
  304. BSTR NetworkResource,
  305. BSTR User,
  306. BSTR Password,
  307. BSTR Locale,
  308. long lFlags,
  309. BSTR Authority,
  310. IWbemContext *pCtx,
  311. IWbemServices **pInterface)
  312. {
  313. HRESULT hr = DoActualConnection(NetworkResource, User, Password, Locale,
  314. lFlags, Authority, pCtx, pInterface);
  315. if(hr == 0x800706be)
  316. {
  317. ERRORTRACE((LOG_WBEMPROX,"Initial connection failed with 0x800706be, retrying\n"));
  318. Sleep(5000);
  319. hr = DoActualConnection(NetworkResource, User, Password, Locale,
  320. lFlags, Authority, pCtx, pInterface);
  321. }
  322. return hr;
  323. }
  324. SCODE CDCOMTrans::DoActualConnection(
  325. BSTR NetworkResource,
  326. BSTR User,
  327. BSTR Password,
  328. BSTR Locale,
  329. long lFlags,
  330. BSTR Authority,
  331. IWbemContext *pCtx,
  332. IWbemServices **pInterface)
  333. {
  334. BSTR AuthArg = NULL, UserArg = NULL;
  335. // this is the pricipal as extracted from the optional Authority argument
  336. BSTR PrincipalArg = NULL;
  337. // this is the pricipal which is calculated from the server name in the path
  338. WCHAR * pwCalculatedPrincipal = NULL;
  339. bool bAuthenticate = true;
  340. bool bSet = false;
  341. CSocketInit sock;
  342. SCODE sc = WBEM_E_FAILED;
  343. sc = DetermineLoginTypeEx(AuthArg, UserArg, PrincipalArg, Authority, User);
  344. if(sc != S_OK)
  345. {
  346. ERRORTRACE((LOG_WBEMPROX, "Cannot determine Login type, Authority = %S, User = %S\n",Authority, User));
  347. return sc;
  348. }
  349. CSysFreeMe fm1(AuthArg);
  350. CSysFreeMe fm2(UserArg);
  351. CSysFreeMe fm3(PrincipalArg);
  352. // Determine if it is local
  353. WCHAR *t_ServerMachine = ExtractMachineName ( NetworkResource ) ;
  354. if ( t_ServerMachine == NULL )
  355. {
  356. ERRORTRACE((LOG_WBEMPROX, "Cannot extract machine name -%S-\n", NetworkResource));
  357. return WBEM_E_INVALID_PARAMETER ;
  358. }
  359. CVectorDeleteMe<WCHAR> dm(t_ServerMachine);
  360. BOOL t_Local;
  361. if(PrincipalArg == NULL)
  362. {
  363. sc = GetPrincipal(t_ServerMachine, &pwCalculatedPrincipal, t_Local, sock);
  364. if(FAILED(sc))
  365. {
  366. t_Local = bAreWeLocal(t_ServerMachine);
  367. ERRORTRACE((LOG_WBEMPROX, "GetPrincipal(%S) hr = %08x\n",t_ServerMachine,sc));
  368. }
  369. else
  370. {
  371. DEBUGTRACE((LOG_WBEMPROX, "Using the principal -%S-\n", pwCalculatedPrincipal));
  372. }
  373. }
  374. else
  375. t_Local = bAreWeLocal(t_ServerMachine);
  376. CVectorDeleteMe<WCHAR> dm2(pwCalculatedPrincipal);
  377. SECURITY_IMPERSONATION_LEVEL impLevel = SecurityImpersonation;
  378. bool bImpersonatingThread = IsImpersonating (impLevel);
  379. bool bCredentialsSpecified = (UserArg || AuthArg || Password);
  380. // Setup the authentication structures
  381. COSERVERINFO si;
  382. si.pwszName = t_ServerMachine;
  383. si.dwReserved1 = 0;
  384. si.dwReserved2 = 0;
  385. si.pAuthInfo = NULL;
  386. COAUTHINFO ai;
  387. si.pAuthInfo = &ai;
  388. ai.dwAuthzSvc = RPC_C_AUTHZ_NONE;
  389. if(PrincipalArg)
  390. {
  391. ai.dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS;
  392. ai.pwszServerPrincName = PrincipalArg;
  393. }
  394. else if (pwCalculatedPrincipal)
  395. {
  396. ai.dwAuthnSvc = RPC_C_AUTHN_GSS_NEGOTIATE;
  397. ai.pwszServerPrincName = pwCalculatedPrincipal;
  398. }
  399. else
  400. {
  401. ai.dwAuthnSvc = RPC_C_AUTHN_WINNT;
  402. ai.pwszServerPrincName = NULL;
  403. }
  404. ai.dwAuthnLevel = AUTH_LEVEL;
  405. ai.dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
  406. ai.dwCapabilities = 0;
  407. COAUTHIDENTITY authident;
  408. if(bCredentialsSpecified)
  409. {
  410. // Load up the structure.
  411. memset((void *)&authident,0,sizeof(COAUTHIDENTITY));
  412. if(UserArg)
  413. {
  414. authident.UserLength = wcslen(UserArg);
  415. authident.User = (LPWSTR)UserArg;
  416. }
  417. if(AuthArg)
  418. {
  419. authident.DomainLength = wcslen(AuthArg);
  420. authident.Domain = (LPWSTR)AuthArg;
  421. }
  422. if(Password)
  423. {
  424. authident.PasswordLength = wcslen(Password);
  425. authident.Password = (LPWSTR)Password;
  426. }
  427. authident.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  428. ai.pAuthIdentityData = &authident;
  429. }
  430. else
  431. ai.pAuthIdentityData = NULL;
  432. // Get the IWbemLevel1Login pointer
  433. sc = DoCCI(&si ,t_Local, lFlags);
  434. if((sc == 0x800706d3 || sc == 0x800706ba) && !t_Local)
  435. {
  436. // If we are going to a stand alone dcom box, try again with the authentication level lowered
  437. ai.dwAuthnLevel = RPC_C_AUTHN_LEVEL_NONE;
  438. SCODE hr = DoCCI(&si ,t_Local, lFlags);
  439. if(hr == S_OK)
  440. {
  441. sc = S_OK;
  442. bAuthenticate = false;
  443. }
  444. }
  445. if(sc != S_OK)
  446. return sc;
  447. // Set the values used for CoSetProxyBlanket calls. If the principal was passed in via the Authority
  448. // argument, then it is used and kerberos is forced. Otherwise, the values will be set based on
  449. // querying the Proxy it will be either NULL (if NTLM is used) or COLE_DEFAULT_PRINCIPAL.
  450. DWORD dwAuthnSvc = RPC_C_AUTHN_WINNT;
  451. WCHAR * pwCSPBPrincipal = NULL;
  452. if(PrincipalArg)
  453. {
  454. dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS;
  455. pwCSPBPrincipal = PrincipalArg;
  456. }
  457. else
  458. {
  459. DWORD dwQueryAuthnLevel, dwQueryImpLevel, dwQueryCapabilities;
  460. HRESULT hr = CoQueryProxyBlanket(
  461. m_pLevel1, //Location for the proxy to query
  462. &dwAuthnSvc, //Location for the current authentication service
  463. NULL, //Location for the current authorization service
  464. NULL, //Location for the current principal name
  465. &dwQueryAuthnLevel, //Location for the current authentication level
  466. &dwQueryImpLevel, //Location for the current impersonation level
  467. NULL,
  468. &dwQueryCapabilities //Location for flags indicating further capabilities of the proxy
  469. );
  470. if(SUCCEEDED(hr) && dwAuthnSvc != RPC_C_AUTHN_WINNT)
  471. {
  472. pwCSPBPrincipal = COLE_DEFAULT_PRINCIPAL;
  473. }
  474. else
  475. {
  476. dwAuthnSvc = RPC_C_AUTHN_WINNT;
  477. pwCSPBPrincipal = NULL;
  478. }
  479. }
  480. // The authentication level is set based on having to go to a share level box or not. The
  481. // capabilities are set based on if we are an impersonating thread or not
  482. DWORD dwAuthenticationLevel, dwCapabilities;
  483. if(bAuthenticate)
  484. dwAuthenticationLevel = AUTH_LEVEL;
  485. else
  486. dwAuthenticationLevel = RPC_C_AUTHN_LEVEL_NONE;
  487. if(bImpersonatingThread && !UserArg)
  488. dwCapabilities = EOAC_STATIC_CLOAKING;
  489. else
  490. dwCapabilities = EOAC_NONE;
  491. // Do the security negotiation
  492. if(!t_Local)
  493. {
  494. // Suppress the SetBlanket call if we are on a Win2K delegation-level thread with implicit credentials
  495. if (!(bImpersonatingThread && !bCredentialsSpecified && (SecurityDelegation == impLevel)))
  496. {
  497. // Note that if we are on a Win2K impersonating thread with no user specified
  498. // we should allow DCOM to use whatever EOAC capabilities are set up for this
  499. // application. This allows remote connections with NULL User/Password but
  500. // non-NULL authority to succeed.
  501. sc = WbemSetProxyBlanket(
  502. m_pLevel1,
  503. dwAuthnSvc,
  504. RPC_C_AUTHZ_NONE,
  505. pwCSPBPrincipal,
  506. dwAuthenticationLevel,
  507. RPC_C_IMP_LEVEL_IMPERSONATE,
  508. (bCredentialsSpecified) ? &authident : NULL,
  509. dwCapabilities);
  510. bSet = true;
  511. if(sc != S_OK)
  512. {
  513. ERRORTRACE((LOG_WBEMPROX,"Error setting Level1 login interface security pointer, return code is 0x%x\n", sc));
  514. return sc;
  515. }
  516. }
  517. }
  518. else // LOCAL case
  519. {
  520. // if impersonating set cloaking
  521. if(bImpersonatingThread)
  522. {
  523. sc = WbemSetProxyBlanket(
  524. m_pLevel1,
  525. RPC_C_AUTHN_WINNT,
  526. RPC_C_AUTHZ_NONE,
  527. NULL,
  528. dwAuthenticationLevel,
  529. RPC_C_IMP_LEVEL_IMPERSONATE,
  530. NULL,
  531. EOAC_STATIC_CLOAKING);
  532. if(sc != S_OK && sc != 0x80004002) // no such interface is ok since you get that when
  533. // called inproc!
  534. {
  535. ERRORTRACE((LOG_WBEMPROX,"Error setting Level1 login interface security pointer, return code is 0x%x\n", sc));
  536. return sc;
  537. }
  538. }
  539. }
  540. SetClientIdentity(m_pLevel1, bSet, PrincipalArg,
  541. dwAuthenticationLevel,
  542. &authident,
  543. dwCapabilities,
  544. dwAuthnSvc);
  545. if(bCredentialsSpecified && IsLocalConnection(m_pLevel1))
  546. {
  547. ERRORTRACE((LOG_WBEMPROX,"Credentials were specified for a local connections\n"));
  548. return WBEM_E_LOCAL_CREDENTIALS;
  549. }
  550. // The MAX_WAIT flag only applies to CoCreateInstanceEx, get rid of it
  551. lFlags = lFlags & ~WBEM_FLAG_CONNECT_USE_MAX_WAIT;
  552. sc = m_pLevel1->NTLMLogin(NetworkResource, Locale, lFlags, pCtx,(IWbemServices**) pInterface);
  553. if(sc == 0x800706d3 && !t_Local) // RPC_S_UNKNOWN_AUTHN_SERVICE
  554. {
  555. // If we are going to a stand alone dcom box, try again with the authentication level lowered
  556. ERRORTRACE((LOG_WBEMPROX,"Attempt to connect to %S returned RPC_S_UNKNOWN_AUTHN_SERVICE\n",NetworkResource));
  557. HRESULT hr;
  558. hr = SetInterfaceSecurityAuth(m_pLevel1, &authident, false);
  559. if (SUCCEEDED(hr))
  560. hr = m_pLevel1->NTLMLogin(NetworkResource, Locale, lFlags, pCtx, (IWbemServices**)pInterface);
  561. if(hr == S_OK)
  562. {
  563. SetInterfaceSecurityAuth((IUnknown *)*pInterface, &authident, false);
  564. }
  565. }
  566. else
  567. if(SUCCEEDED(sc) && bAuthenticate == false && !t_Local)
  568. {
  569. // this is used to support share level boxs. The scripting code is written to expect that
  570. // the IWbemServices pointer is ready to use and so it must be lowered before returning.
  571. WbemSetProxyBlanket(*pInterface, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,
  572. RPC_C_AUTHN_LEVEL_NONE, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE);
  573. }
  574. if(FAILED(sc))
  575. ERRORTRACE((LOG_WBEMPROX,"NTLMLogin resulted in hr = 0x%x\n", sc));
  576. return sc;
  577. }
  578. struct WaitThreadArg
  579. {
  580. DWORD m_dwThreadId;
  581. HANDLE m_hTerminate;
  582. };
  583. DWORD WINAPI TimeoutThreadRoutine(LPVOID lpParameter)
  584. {
  585. WaitThreadArg * pReq = (WaitThreadArg *)lpParameter;
  586. DWORD dwRet = WaitForSingleObject(pReq->m_hTerminate, 60000);
  587. if(dwRet == WAIT_TIMEOUT)
  588. {
  589. HRESULT hr = CoInitializeEx(NULL,COINIT_MULTITHREADED );
  590. if(FAILED(hr))
  591. return 1;
  592. ICancelMethodCalls * px = NULL;
  593. hr = CoGetCancelObject(pReq->m_dwThreadId, IID_ICancelMethodCalls,
  594. (void **)&px);
  595. if(SUCCEEDED(hr))
  596. {
  597. hr = px->Cancel(0);
  598. px->Release();
  599. }
  600. CoUninitialize();
  601. }
  602. return 0;
  603. }
  604. //***************************************************************************
  605. //
  606. // DoCCI
  607. //
  608. // DESCRIPTION:
  609. //
  610. // Connects up to WBEM via DCOM. But before making the call, a thread cancel
  611. // thread may be created to handle the case where we try to connect up
  612. // to a box which is hanging
  613. //
  614. // PARAMETERS:
  615. //
  616. // NetworkResource Namespze path
  617. // ppLogin set to Login proxy
  618. // bLocal Indicates if connection is local
  619. // lFlags Mainly used for WBEM_FLAG_CONNECT_USE_MAX_WAIT flag
  620. //
  621. // RETURN VALUE:
  622. //
  623. // S_OK all is well
  624. // else error listed in WBEMSVC.H
  625. //
  626. //***************************************************************************
  627. SCODE CDCOMTrans::DoCCI (IN COSERVERINFO * psi, IN BOOL bLocal, long lFlags )
  628. {
  629. if(lFlags & WBEM_FLAG_CONNECT_USE_MAX_WAIT)
  630. {
  631. // special case. we want to spawn off a thread that will kill of our
  632. // request if it takes too long
  633. WaitThreadArg arg;
  634. arg.m_hTerminate = CreateEvent(NULL, FALSE, FALSE, NULL);
  635. if(arg.m_hTerminate == NULL)
  636. return WBEM_E_OUT_OF_MEMORY;
  637. CCloseMe cm(arg.m_hTerminate);
  638. arg.m_dwThreadId = GetCurrentThreadId();
  639. DWORD dwIDLikeIcare;
  640. HRESULT hr = CoEnableCallCancellation(NULL);
  641. if(FAILED(hr))
  642. return hr;
  643. HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TimeoutThreadRoutine,
  644. (LPVOID)&arg, 0, &dwIDLikeIcare);
  645. if(hThread == NULL)
  646. {
  647. CoDisableCallCancellation(NULL);
  648. return WBEM_E_OUT_OF_MEMORY;
  649. }
  650. CCloseMe cm2(hThread);
  651. hr = DoActualCCI (psi, bLocal,
  652. lFlags & ~WBEM_FLAG_CONNECT_USE_MAX_WAIT );
  653. CoDisableCallCancellation(NULL);
  654. SetEvent(arg.m_hTerminate);
  655. WaitForSingleObject(hThread, INFINITE);
  656. return hr;
  657. }
  658. else
  659. return DoActualCCI (psi, bLocal, lFlags );
  660. }
  661. //***************************************************************************
  662. //
  663. // DoActualCCI
  664. //
  665. // DESCRIPTION:
  666. //
  667. // Connects up to WBEM via DCOM.
  668. //
  669. // PARAMETERS:
  670. //
  671. // NetworkResource Namespze path
  672. // ppLogin set to Login proxy
  673. // bLocal Indicates if connection is local
  674. // lFlags Not used
  675. //
  676. // RETURN VALUE:
  677. //
  678. // S_OK all is well
  679. // else error listed in WBEMSVC.H
  680. //
  681. //***************************************************************************
  682. SCODE CDCOMTrans::DoActualCCI (IN COSERVERINFO * psi, IN BOOL bLocal, long lFlags )
  683. {
  684. HRESULT t_Result ;
  685. MULTI_QI mqi;
  686. mqi.pIID = &IID_IWbemLevel1Login;
  687. mqi.pItf = 0;
  688. mqi.hr = 0;
  689. t_Result = CoCreateInstanceEx (
  690. CLSID_WbemLevel1Login,
  691. NULL,
  692. CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
  693. ( bLocal ) ? NULL : psi ,
  694. 1,
  695. &mqi
  696. );
  697. if ( t_Result == S_OK )
  698. {
  699. m_pLevel1 = (IWbemLevel1Login*) mqi.pItf ;
  700. DEBUGTRACE((LOG_WBEMPROX,"ConnectViaDCOM, CoCreateInstanceEx resulted in hr = 0x%x\n", t_Result ));
  701. }
  702. else
  703. {
  704. ERRORTRACE((LOG_WBEMPROX,"ConnectViaDCOM, CoCreateInstanceEx resulted in hr = 0x%x\n", t_Result ));
  705. }
  706. return t_Result ;
  707. }