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.

903 lines
26 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: cumiconn.cxx
  7. //
  8. // Contents: Contains the UMI connection object implementation
  9. //
  10. // History: 03-02-00 SivaramR Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "winnt.hxx"
  14. //----------------------------------------------------------------------------
  15. // Function: CreateConnection
  16. //
  17. // Synopsis: Creates a connection object. Called by class factory.
  18. //
  19. // Arguments:
  20. //
  21. // iid Interface requested. Only interface supported is IUmiConnection.
  22. // ppInterface Returns pointer to interface requested
  23. //
  24. // Returns: S_OK on success. Error code otherwise.
  25. //
  26. // Modifies: *ppInterface to return a pointer to the interface requested
  27. //
  28. //----------------------------------------------------------------------------
  29. HRESULT CUmiConnection::CreateConnection(
  30. REFIID iid,
  31. LPVOID *ppInterface
  32. )
  33. {
  34. CUmiConnection *pConn = NULL;
  35. HRESULT hr = S_OK;
  36. ADsAssert(ppInterface);
  37. pConn = new CUmiConnection();
  38. if(NULL == pConn)
  39. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  40. // initialize connection object
  41. hr = pConn->FInit();
  42. BAIL_ON_FAILURE(hr);
  43. hr = pConn->QueryInterface(iid, ppInterface);
  44. BAIL_ON_FAILURE(hr);
  45. pConn->Release();
  46. RRETURN(S_OK);
  47. error:
  48. if(pConn != NULL)
  49. delete pConn;
  50. RRETURN(hr);
  51. }
  52. //----------------------------------------------------------------------------
  53. // Function: CUmiConnection
  54. //
  55. // Synopsis: Constructor. Initializes all member variables
  56. //
  57. // Arguments:
  58. //
  59. // None
  60. //
  61. // Returns: Nothing.
  62. //
  63. // Modifies: Nothing.
  64. //
  65. //----------------------------------------------------------------------------
  66. CUmiConnection::CUmiConnection(void)
  67. {
  68. m_pIUmiPropList = NULL;
  69. m_pCUmiPropList = NULL;
  70. m_ulErrorStatus = 0;
  71. m_pIADsOpenDSObj = NULL;
  72. m_fAlreadyOpened = FALSE;
  73. m_pszComputerName = NULL;
  74. m_pszDomainName = NULL;
  75. }
  76. //----------------------------------------------------------------------------
  77. // Function: ~CUmiConnection
  78. //
  79. // Synopsis: Destructor. Frees member variables
  80. //
  81. // Arguments:
  82. //
  83. // None
  84. //
  85. // Returns: Nothing.
  86. //
  87. // Modifies: Nothing.
  88. //
  89. //----------------------------------------------------------------------------
  90. CUmiConnection::~CUmiConnection(void)
  91. {
  92. if(m_pIUmiPropList != NULL)
  93. m_pIUmiPropList->Release();
  94. if(m_pszComputerName != NULL)
  95. FreeADsStr(m_pszComputerName);
  96. if(m_pszDomainName != NULL)
  97. FreeADsStr(m_pszDomainName);
  98. if(m_pIADsOpenDSObj != NULL)
  99. m_pIADsOpenDSObj->Release();
  100. // m_pCUmiPropList does not have to be deleted since the Release() above
  101. // has already done it.
  102. }
  103. //----------------------------------------------------------------------------
  104. // Function: FInit
  105. //
  106. // Synopsis: Initializes connection object.
  107. //
  108. // Arguments:
  109. //
  110. // None
  111. //
  112. // Returns: S_OK on success. Error code otherwise.
  113. //
  114. // Modifies: Nothing.
  115. //
  116. //----------------------------------------------------------------------------
  117. HRESULT CUmiConnection::FInit(void)
  118. {
  119. HRESULT hr = S_OK;
  120. CUmiPropList *pPropList = NULL;
  121. pPropList = new CUmiPropList(ConnectionClass, g_dwConnectionTableSize);
  122. if(NULL == pPropList)
  123. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  124. hr = pPropList->FInit(NULL, g_UmiConUnImplProps);
  125. BAIL_ON_FAILURE(hr);
  126. hr = pPropList->QueryInterface(
  127. IID_IUmiPropList,
  128. (void **) &m_pIUmiPropList
  129. );
  130. BAIL_ON_FAILURE(hr);
  131. // DECLARE_STD_REFCOUNTING initializes the refcount to 1. Call Release()
  132. // on the created object, so that releasing the interface pointer will
  133. // free the object.
  134. pPropList->Release();
  135. m_pCUmiPropList = pPropList;
  136. hr = m_pCUmiPropList->SetDefaultConnProps();
  137. BAIL_ON_FAILURE(hr);
  138. RRETURN(S_OK);
  139. error:
  140. if(m_pIUmiPropList != NULL) {
  141. m_pIUmiPropList->Release();
  142. m_pIUmiPropList = NULL;
  143. m_pCUmiPropList = NULL;
  144. }
  145. else if(pPropList != NULL)
  146. delete pPropList;
  147. RRETURN(hr);
  148. }
  149. //----------------------------------------------------------------------------
  150. // Function: QueryInterface
  151. //
  152. // Synopsis: Queries connection object for supported interfaces. Only
  153. // IUmiConnection is supported.
  154. //
  155. // Arguments:
  156. //
  157. // iid interface requested
  158. // ppInterface Returns pointer to interface requested. NULL if interface
  159. // is not supported.
  160. //
  161. // Returns: S_OK on success. Error code otherwise.
  162. //
  163. // Modifies: *ppInterface to return interface pointer
  164. //
  165. //----------------------------------------------------------------------------
  166. STDMETHODIMP CUmiConnection::QueryInterface(
  167. REFIID iid,
  168. LPVOID *ppInterface
  169. )
  170. {
  171. if(NULL == ppInterface)
  172. RRETURN(E_INVALIDARG);
  173. *ppInterface = NULL;
  174. if(IsEqualIID(iid, IID_IUnknown))
  175. *ppInterface = (IUmiConnection *) this;
  176. else if(IsEqualIID(iid, IID_IUmiConnection))
  177. *ppInterface = (IUmiConnection *) this;
  178. else if(IsEqualIID(iid, IID_IUmiBaseObject))
  179. *ppInterface = (IUmiBaseObject *) this;
  180. else if(IsEqualIID(iid, IID_IUmiPropList))
  181. *ppInterface = (IUmiPropList *) this;
  182. else
  183. RRETURN(E_NOINTERFACE);
  184. AddRef();
  185. RRETURN(S_OK);
  186. }
  187. //----------------------------------------------------------------------------
  188. // Function: GetLastStatus
  189. //
  190. // Synopsis: Returns status or error code from the last operation. Currently
  191. // only numeric status is returned i.e, no error objects are
  192. // returned. Implements IUmiBaseObject::GetLastStatus().
  193. //
  194. // Arguments:
  195. //
  196. // uFlags Reserved. Must be 0 for now.
  197. // puSpecificStatus Returns status code
  198. // riid IID requested. Ignored currently.
  199. // pStatusObj Returns interface requested. Always returns NULL currently.
  200. //
  201. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  202. //
  203. // Modifies: *puSpecificStatus to return status code.
  204. //
  205. //----------------------------------------------------------------------------
  206. STDMETHODIMP CUmiConnection::GetLastStatus(
  207. ULONG uFlags,
  208. ULONG *puSpecificStatus,
  209. REFIID riid,
  210. LPVOID *pStatusObj
  211. )
  212. {
  213. if(pStatusObj != NULL)
  214. *pStatusObj = NULL;
  215. if(puSpecificStatus != NULL)
  216. *puSpecificStatus = 0;
  217. if(uFlags != 0)
  218. RRETURN(UMI_E_INVALID_FLAGS);
  219. if(NULL == puSpecificStatus)
  220. RRETURN(UMI_E_INVALIDARG);
  221. *puSpecificStatus = m_ulErrorStatus;
  222. RRETURN(UMI_S_NO_ERROR);
  223. }
  224. //----------------------------------------------------------------------------
  225. // Function: GetInterfacePropList
  226. //
  227. // Synopsis: Returns a pointer to the interface property list implementation
  228. // for the connection object. Implements
  229. // IUmiBaseObject::GetInterfacePropList().
  230. //
  231. // Arguments:
  232. //
  233. // uFlags Reserved. Must be 0 for now.
  234. // pPropList Returns pointer to IUmiPropertyList interface
  235. //
  236. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  237. //
  238. // Modifies: *pPropList to return interface pointer
  239. //
  240. //----------------------------------------------------------------------------
  241. STDMETHODIMP CUmiConnection::GetInterfacePropList(
  242. ULONG uFlags,
  243. IUmiPropList **pPropList
  244. )
  245. {
  246. HRESULT hr = UMI_S_NO_ERROR;
  247. SetLastStatus(0);
  248. if(uFlags != 0)
  249. BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
  250. if(NULL == pPropList)
  251. BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
  252. ADsAssert(m_pIUmiPropList != NULL);
  253. hr = m_pIUmiPropList->QueryInterface(IID_IUmiPropList, (void **)pPropList);
  254. error:
  255. if(FAILED(hr))
  256. SetLastStatus(hr);
  257. RRETURN(MapHrToUmiError(hr));
  258. }
  259. //----------------------------------------------------------------------------
  260. // Function: SetLastStatus
  261. //
  262. // Synopsis: Sets the status of the last operation.
  263. //
  264. // Arguments:
  265. //
  266. // ulStatus Status to be set
  267. //
  268. // Returns: Nothing
  269. //
  270. // Modifies: Nothing
  271. //
  272. //----------------------------------------------------------------------------
  273. void CUmiConnection::SetLastStatus(ULONG ulStatus)
  274. {
  275. m_ulErrorStatus = ulStatus;
  276. return;
  277. }
  278. //----------------------------------------------------------------------------
  279. // Function: Open
  280. //
  281. // Synopsis: Opens the object specified by a URL and gets the interface
  282. // requested on this object. Implements IUmiConnection::Open().
  283. //
  284. // Arguments:
  285. //
  286. // pURL Pointer to an IUmiURL interface
  287. // uFlags Reserved. Must be 0 for now.
  288. // TargetIID Interface requested
  289. // ppInterface Returns pointer to interface requested
  290. //
  291. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  292. //
  293. // Modifies: *ppInterface to return interface pointer
  294. //
  295. //----------------------------------------------------------------------------
  296. STDMETHODIMP CUmiConnection::Open(
  297. IUmiURL *pURL,
  298. ULONG uFlags,
  299. REFIID TargetIID,
  300. LPVOID *ppInterface
  301. )
  302. {
  303. HRESULT hr = UMI_S_NO_ERROR;
  304. LPWSTR pszUserName = NULL, pszPassword = NULL;
  305. DWORD dwBindFlags = 0, dwNumComponents = 0, dwIndex = 0;
  306. LPWSTR *ppszClasses = NULL;
  307. WCHAR pszUrl[MAX_URL+1];
  308. WCHAR *pszLongUrl = pszUrl;
  309. ULONG ulUrlLen = MAX_URL;
  310. IUnknown *pIUnknown = NULL;
  311. CWinNTNamespaceCF tmpNamCF;
  312. ULONGLONG PathType = 0;
  313. BOOL fPrevAlreadyOpened = FALSE;
  314. LPWSTR pszPrevComputer = NULL, pszPrevDomain = NULL;
  315. SetLastStatus(0);
  316. if(uFlags != 0)
  317. BAIL_ON_FAILURE(hr = UMI_E_INVALID_FLAGS);
  318. if( (NULL == pURL) || (NULL == ppInterface) )
  319. BAIL_ON_FAILURE(hr = UMI_E_INVALIDARG);
  320. *ppInterface = NULL;
  321. // Check if the user specified any interface properties for authentication
  322. hr = GetUserName(&pszUserName);
  323. BAIL_ON_FAILURE(hr);
  324. hr = GetPassword(&pszPassword);
  325. BAIL_ON_FAILURE(hr);
  326. hr = GetBindFlags(&dwBindFlags);
  327. BAIL_ON_FAILURE(hr);
  328. // check if this is a native path or UMI path
  329. hr = pURL->GetPathInfo(0, &PathType);
  330. BAIL_ON_FAILURE(hr);
  331. if(PathType & UMIPATH_INFO_NATIVE_STRING) {
  332. // Get the native path from the URL
  333. hr = pURL->Get(0, &ulUrlLen, pszUrl);
  334. if(WBEM_E_BUFFER_TOO_SMALL == hr) {
  335. // need to allocate more memory for URL
  336. pszLongUrl = (WCHAR *) AllocADsMem(ulUrlLen * sizeof(WCHAR));
  337. if(NULL == pszLongUrl)
  338. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  339. hr = pURL->Get(0, &ulUrlLen, pszLongUrl);
  340. }
  341. BAIL_ON_FAILURE(hr);
  342. }
  343. else {
  344. // assume UMI path if not native
  345. hr = UmiToWinNTPath(
  346. pURL,
  347. &pszLongUrl,
  348. &dwNumComponents,
  349. &ppszClasses
  350. );
  351. BAIL_ON_FAILURE(hr);
  352. }
  353. hr = tmpNamCF.CreateInstance(
  354. NULL,
  355. IID_IADsOpenDSObject,
  356. (void **) &m_pIADsOpenDSObj
  357. );
  358. BAIL_ON_FAILURE(hr);
  359. //
  360. // we need a way to distinguish between calls to OpenDSObject from UMI
  361. // vs ADSI. We use the bind flags for this purpose. If ADS_AUTH_RESERVED
  362. // is set, then the call is from UMI. ADSI clients are not allowed to use
  363. // this flag - OLEDB relies on this.
  364. //
  365. hr = m_pIADsOpenDSObj->OpenDSObject(
  366. pszLongUrl,
  367. pszUserName,
  368. pszPassword,
  369. dwBindFlags | ADS_AUTH_RESERVED,
  370. (IDispatch **) &pIUnknown
  371. );
  372. BAIL_ON_FAILURE(hr);
  373. // save off state in case we need to restore it later
  374. fPrevAlreadyOpened = m_fAlreadyOpened;
  375. pszPrevComputer = m_pszComputerName;
  376. pszPrevDomain = m_pszDomainName;
  377. // ensure that the returned object is what the user requested and that the
  378. // object is on the same domain/server that this connection is for
  379. hr = CheckObject(
  380. pIUnknown,
  381. dwNumComponents,
  382. ppszClasses
  383. );
  384. BAIL_ON_FAILURE(hr);
  385. hr = pIUnknown->QueryInterface(
  386. TargetIID,
  387. ppInterface
  388. );
  389. if(FAILED(hr)) {
  390. // restore state of connection
  391. m_fAlreadyOpened = fPrevAlreadyOpened;
  392. if(m_pszComputerName != pszPrevComputer) {
  393. if(m_pszComputerName != NULL)
  394. FreeADsStr(m_pszComputerName);
  395. m_pszComputerName = pszPrevComputer;
  396. }
  397. if(m_pszDomainName != pszPrevDomain) {
  398. if(m_pszDomainName != NULL)
  399. FreeADsStr(m_pszDomainName);
  400. m_pszDomainName = pszPrevDomain;
  401. }
  402. goto error;
  403. }
  404. // make interface properties read-only
  405. m_pCUmiPropList->DisableWrites();
  406. error:
  407. if(pszUserName != NULL)
  408. FreeADsMem(pszUserName);
  409. if(pszPassword != NULL)
  410. FreeADsMem(pszPassword);
  411. if(pIUnknown != NULL)
  412. pIUnknown->Release();
  413. if( (pszLongUrl != NULL) && (pszLongUrl != pszUrl) )
  414. FreeADsMem(pszLongUrl);
  415. if(ppszClasses != NULL) {
  416. for(dwIndex = 0; dwIndex < dwNumComponents; dwIndex++) {
  417. if(ppszClasses[dwIndex] != NULL)
  418. FreeADsStr(ppszClasses[dwIndex]);
  419. }
  420. FreeADsMem(ppszClasses);
  421. }
  422. if(FAILED(hr)) {
  423. SetLastStatus(hr);
  424. if(m_pIADsOpenDSObj != NULL) {
  425. m_pIADsOpenDSObj->Release();
  426. m_pIADsOpenDSObj = NULL;
  427. }
  428. }
  429. RRETURN(MapHrToUmiError(hr));
  430. }
  431. //----------------------------------------------------------------------------
  432. // Function: GetUserName
  433. //
  434. // Synopsis: Gets the username from the interface property cache. If the
  435. // interface property was not set, the default username is
  436. // returned.
  437. //
  438. // Arguments:
  439. //
  440. // ppszUserName Returns pointer to the username
  441. //
  442. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  443. //
  444. // Modifies: *ppszUserName to return the username.
  445. //
  446. //----------------------------------------------------------------------------
  447. HRESULT CUmiConnection::GetUserName(LPWSTR *ppszUserName)
  448. {
  449. HRESULT hr = UMI_S_NO_ERROR;
  450. UMI_PROPERTY_VALUES *pUmiProp = NULL;
  451. LPWSTR pszUserName = NULL;
  452. ADsAssert(ppszUserName != NULL);
  453. *ppszUserName = NULL;
  454. hr = m_pIUmiPropList->Get(
  455. TEXT(CONN_INTF_PROP_USERNAME),
  456. 0,
  457. &pUmiProp
  458. );
  459. if(FAILED(hr)) {
  460. // shouldn't happen
  461. BAIL_ON_FAILURE(hr = UMI_E_FAIL);
  462. }
  463. ADsAssert(UMI_TYPE_LPWSTR == pUmiProp->pPropArray->uType);
  464. ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
  465. pszUserName = pUmiProp->pPropArray->pUmiValue->pszStrValue[0];
  466. if(pszUserName != NULL) {
  467. *ppszUserName = AllocADsStr(pszUserName);
  468. if(NULL == *ppszUserName)
  469. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  470. }
  471. else
  472. *ppszUserName = NULL;
  473. error:
  474. if(pUmiProp != NULL)
  475. m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
  476. RRETURN(hr);
  477. }
  478. //----------------------------------------------------------------------------
  479. // Function: GetPassword
  480. //
  481. // Synopsis: Gets the password from the interface property cache. If the
  482. // interface property was not set, the default password is
  483. // returned.
  484. //
  485. // Arguments:
  486. //
  487. // ppszPassword Returns pointer to the password
  488. //
  489. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  490. //
  491. // Modifies: *ppszPassword to return the password.
  492. //
  493. //----------------------------------------------------------------------------
  494. HRESULT CUmiConnection::GetPassword(LPWSTR *ppszPassword)
  495. {
  496. HRESULT hr = UMI_S_NO_ERROR;
  497. UMI_PROPERTY_VALUES *pUmiProp = NULL;
  498. LPWSTR pszPassword = NULL;
  499. ADsAssert(ppszPassword != NULL);
  500. *ppszPassword = NULL;
  501. hr = m_pCUmiPropList->GetHelper(
  502. TEXT(CONN_INTF_PROP_PASSWORD),
  503. 0,
  504. &pUmiProp,
  505. UMI_TYPE_NULL, // no-op
  506. TRUE // this is an internal call to GetHelper
  507. );
  508. if(FAILED(hr)) {
  509. // shouldn't happen
  510. BAIL_ON_FAILURE(hr = UMI_E_FAIL);
  511. }
  512. ADsAssert(UMI_TYPE_LPWSTR == pUmiProp->pPropArray->uType);
  513. ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
  514. pszPassword = pUmiProp->pPropArray->pUmiValue->pszStrValue[0];
  515. if(pszPassword != NULL) {
  516. *ppszPassword = AllocADsStr(pszPassword);
  517. if(NULL == *ppszPassword)
  518. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  519. }
  520. else
  521. *ppszPassword = NULL;
  522. error:
  523. if(pUmiProp != NULL)
  524. m_pCUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
  525. RRETURN(hr);
  526. }
  527. //----------------------------------------------------------------------------
  528. // Function: GetBindFlags
  529. //
  530. // Synopsis: Gets the bind flags from the interface property cache. If the
  531. // interface properties were not set, the default bind flags are
  532. // returned.
  533. //
  534. // Arguments:
  535. //
  536. // pdwBindFlags Returns the bind flags.
  537. //
  538. // Returns: UMI_S_NO_ERROR on success. Error code otherwise.
  539. //
  540. // Modifies: *pdwBindFlags to return the bind flags.
  541. //
  542. //----------------------------------------------------------------------------
  543. HRESULT CUmiConnection::GetBindFlags(DWORD *pdwBindFlags)
  544. {
  545. HRESULT hr = UMI_S_NO_ERROR;
  546. UMI_PROPERTY_VALUES *pUmiProp = NULL;
  547. DWORD dwUmiBindFlags = 0;
  548. ADsAssert(pdwBindFlags != NULL);
  549. hr = m_pIUmiPropList->Get(
  550. TEXT(CONN_INTF_PROP_SECURE_AUTH),
  551. 0,
  552. &pUmiProp
  553. );
  554. if(SUCCEEDED(hr)) {
  555. ADsAssert(UMI_TYPE_BOOL == pUmiProp->pPropArray->uType);
  556. ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
  557. if(TRUE == pUmiProp->pPropArray->pUmiValue->bValue[0])
  558. dwUmiBindFlags |= ADS_SECURE_AUTHENTICATION;
  559. m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
  560. pUmiProp = NULL;
  561. }
  562. else
  563. // shouldn't happen
  564. BAIL_ON_FAILURE(hr = UMI_E_FAIL);
  565. hr = m_pIUmiPropList->Get(
  566. TEXT(CONN_INTF_PROP_READONLY_SERVER),
  567. 0,
  568. &pUmiProp
  569. );
  570. if(SUCCEEDED(hr)) {
  571. ADsAssert(UMI_TYPE_BOOL == pUmiProp->pPropArray->uType);
  572. ADsAssert(pUmiProp->pPropArray->pUmiValue != NULL);
  573. if(TRUE == pUmiProp->pPropArray->pUmiValue->bValue[0])
  574. dwUmiBindFlags |= ADS_READONLY_SERVER;
  575. m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
  576. pUmiProp = NULL;
  577. }
  578. else
  579. // shouldn't happen
  580. BAIL_ON_FAILURE(hr = UMI_E_FAIL);
  581. *pdwBindFlags = dwUmiBindFlags;
  582. error:
  583. if(pUmiProp != NULL)
  584. m_pIUmiPropList->FreeMemory(0, pUmiProp); // ignore error return
  585. RRETURN(hr);
  586. }
  587. //----------------------------------------------------------------------------
  588. // Function: CheckObject
  589. //
  590. // Synopsis: Checks that the returned object is the same as what the user
  591. // requested, if the user passed in a UMI path i.e the classes
  592. // of the components in the UMI path to the object retrieved
  593. // should be the same as what the user requested.
  594. // This function also checks to make sure that subsequent calls to
  595. // Open(), after the first call, specify the same server/domain
  596. // as the first call. If the path used in the first call to Open()
  597. // specifies only a domain name, then all subsequent Open() calls
  598. // should also specify only a domain name and no computer name.
  599. // If the first call to Open() specified only a computer name, then
  600. // all subsequent calls should specify the same computer name. If
  601. // the first call to Open specified the WinNT namespace path
  602. // (umi:///winnt or WinNT:), then subsequent Open() calls can
  603. // connect to any domain/computer. Also, the namespace object can
  604. // be opened successfully even if we already connected to a
  605. // computer/domain.
  606. //
  607. // Arguments:
  608. //
  609. // pUnknown Pointer to the IUnknown of object retrieved
  610. // dwNumComps Number of components if the path is a UMI path. 0 otherwise.
  611. // ppszClasses Array containing the class of each component, if the path is
  612. // a UMI path to an object other than the namespace obejct.
  613. // NULL otherwise.
  614. //
  615. // Returns: S_OK on success. Error code otherwise.
  616. //
  617. // Modifies: Nothing
  618. //
  619. //----------------------------------------------------------------------------
  620. HRESULT CUmiConnection::CheckObject(
  621. IUnknown *pUnknown,
  622. DWORD dwNumComps,
  623. LPWSTR *ppszClasses
  624. )
  625. {
  626. HRESULT hr = S_OK;
  627. IUmiADSIPrivate *pUmiPrivate = NULL;
  628. CCoreADsObject *pCoreObj = NULL;
  629. LPWSTR pszComputerName = NULL, pszDomainName = NULL;
  630. DWORD dwIndex = 0, dwCoreIndex = 0;
  631. ADsAssert(pUnknown != NULL);
  632. hr = pUnknown->QueryInterface(
  633. IID_IUmiADSIPrivate,
  634. (LPVOID *) &pUmiPrivate
  635. );
  636. BAIL_ON_FAILURE(hr);
  637. hr = pUmiPrivate->GetCoreObject((void **) &pCoreObj);
  638. BAIL_ON_FAILURE(hr);
  639. if(ppszClasses != NULL) {
  640. // user specified a UMI path and it was not umi:///winnt. Make sure the
  641. // classes are the same, as mentioned above.
  642. // walk the list of classes in reverse order. Reason for reverse order
  643. // is that the WinNT provider may tack on an additional component to
  644. // the ADsPath stored in the core object. For example,
  645. // Open("WinNT://ntdsdc1") would return an ADsPath of
  646. // "WinNT://ntdev/ntdsdc1".
  647. dwCoreIndex = pCoreObj->_dwNumComponents - 1;
  648. for(dwIndex = dwNumComps - 1; ((long) dwIndex) >= 0; dwIndex--) {
  649. if( _wcsicmp(
  650. ppszClasses[dwIndex],
  651. pCoreObj->_CompClasses[dwCoreIndex]) ) {
  652. if( (0 == dwIndex) && (dwNumComps > 1) ) {
  653. if(0 == _wcsicmp(pCoreObj->_CompClasses[1],
  654. SCHEMA_CLASS_NAME)) {
  655. // if the first component of a schema path doesn't match,
  656. // make sure it is "Domain". Need this special case because
  657. // of a bug in the WinNT provider. First component of a
  658. // schema path is ignored and hence the UMI path always
  659. // returns "Computer" as the class for this component. This
  660. // special case allows binding using a path like
  661. // umi://winnt/domain=ntdev/schema=schema.
  662. if(0 == _wcsicmp(ppszClasses[dwIndex],
  663. DOMAIN_CLASS_NAME)) {
  664. dwCoreIndex--;
  665. continue;
  666. }
  667. }
  668. }
  669. BAIL_ON_FAILURE(hr = UMI_E_INVALID_PATH);
  670. }
  671. dwCoreIndex--;
  672. }
  673. } // if(ppszClasses...)
  674. // get the domain/computer name specified in the path
  675. if(pCoreObj->_dwNumComponents > 0) {
  676. for(dwIndex = pCoreObj->_dwNumComponents - 1; ((long) dwIndex) >= 0;
  677. dwIndex--) {
  678. if(0 == (_wcsicmp(
  679. pCoreObj->_CompClasses[dwIndex],
  680. SCHEMA_CLASS_NAME)) ) {
  681. // schema container is a special case. We can connect to the
  682. // schema on any computer/domain irrespective of where we are
  683. // connected currently. This is to allow for CIMOM to connect to
  684. // the schema container for a computer. Currently, the WinNT
  685. // provider returns WinNT://ntdev/schema as the schema path on the
  686. // object WinNT://ntdsdc1. Hence we need to allow CIMOM to connect
  687. // to ntdev even after connecting to ntdsdc1.
  688. break; // pszComputerName and pszDomainName are both NULL
  689. }
  690. if(0 == (_wcsicmp(
  691. pCoreObj->_CompClasses[dwIndex],
  692. COMPUTER_CLASS_NAME)) ) {
  693. pszComputerName =
  694. pCoreObj->_ObjectInfo.DisplayComponentArray[dwIndex];
  695. break;
  696. }
  697. else if(0 == (_wcsicmp(
  698. pCoreObj->_CompClasses[dwIndex],
  699. DOMAIN_CLASS_NAME)) ) {
  700. pszDomainName =
  701. pCoreObj->_ObjectInfo.DisplayComponentArray[dwIndex];
  702. break;
  703. }
  704. } // for(..)
  705. } // if(pCoreObj...)
  706. if(FALSE == m_fAlreadyOpened) {
  707. // first call to Open()
  708. if(pszComputerName != NULL) {
  709. m_pszComputerName = AllocADsStr(pszComputerName);
  710. if(NULL == m_pszComputerName) {
  711. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  712. }
  713. }
  714. else if(pszDomainName != NULL) {
  715. m_pszDomainName = AllocADsStr(pszDomainName);
  716. if(NULL == m_pszDomainName) {
  717. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  718. }
  719. }
  720. m_fAlreadyOpened = TRUE;
  721. }
  722. else if( (pszComputerName != NULL) || (pszDomainName != NULL) ) {
  723. // Already opened connection and this is not the namespace object.
  724. // Make sure that the domain/computer is same as before.
  725. if(m_pszComputerName != NULL) {
  726. if( (NULL == pszComputerName) ||
  727. (_wcsicmp(m_pszComputerName, pszComputerName)) ) {
  728. BAIL_ON_FAILURE(hr = UMI_E_MISMATCHED_SERVER);
  729. }
  730. }
  731. else if(m_pszDomainName != NULL) {
  732. if( (NULL == pszDomainName) ||
  733. (_wcsicmp(m_pszDomainName, pszDomainName)) ) {
  734. BAIL_ON_FAILURE(hr = UMI_E_MISMATCHED_DOMAIN);
  735. }
  736. }
  737. else {
  738. // both m_pszComputerName and m_pszDomainName are NULL. Previous
  739. // open() must have been for a namespace object.
  740. if(pszComputerName != NULL) {
  741. m_pszComputerName = AllocADsStr(pszComputerName);
  742. if(NULL == m_pszComputerName) {
  743. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  744. }
  745. }
  746. else if(pszDomainName != NULL) {
  747. m_pszDomainName = AllocADsStr(pszDomainName);
  748. if(NULL == m_pszDomainName) {
  749. BAIL_ON_FAILURE(hr = UMI_E_OUT_OF_MEMORY);
  750. }
  751. }
  752. } // else {
  753. } // else if(pszComputer...)
  754. error:
  755. if(pUmiPrivate != NULL)
  756. pUmiPrivate->Release();
  757. RRETURN(hr);
  758. }