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.

2430 lines
56 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1997
  5. //
  6. // File: cgenobj.cxx
  7. //
  8. // Contents: Microsoft ADs IIS Provider Generic Object
  9. //
  10. //
  11. // History: 28-Feb-97 SophiaC Created.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "iis.hxx"
  15. #pragma hdrstop
  16. // Class CIISGenObject
  17. DEFINE_IDispatch_ExtMgr_Implementation(CIISGenObject)
  18. DEFINE_IADs_Implementation(CIISGenObject)
  19. CIISGenObject::CIISGenObject():
  20. _pExtMgr(NULL),
  21. _pPropertyCache(NULL),
  22. _pszServerName(NULL),
  23. _pszMetaBasePath(NULL),
  24. _pAdminBase(NULL),
  25. _pSchema(NULL),
  26. _pDispMgr(NULL)
  27. {
  28. VariantInit(&_vFilter);
  29. ENLIST_TRACKING(CIISGenObject);
  30. }
  31. HRESULT
  32. CIISGenObject::CreateGenericObject(
  33. BSTR Parent,
  34. BSTR CommonName,
  35. BSTR ClassName,
  36. CCredentials& Credentials,
  37. DWORD dwObjectState,
  38. REFIID riid,
  39. void **ppvObj
  40. )
  41. {
  42. CIISGenObject FAR * pGenObject = NULL;
  43. CADsExtMgr FAR * pExtensionMgr = NULL;
  44. HRESULT hr = S_OK;
  45. LPWSTR pszClassName = ClassName;
  46. hr = AllocateGenObject(ClassName, Credentials, &pGenObject);
  47. BAIL_ON_FAILURE(hr);
  48. hr = pGenObject->InitializeCoreObject(
  49. Parent,
  50. CommonName,
  51. ClassName,
  52. L"",
  53. CLSID_IISGenObject,
  54. dwObjectState
  55. );
  56. BAIL_ON_FAILURE(hr);
  57. hr = pGenObject->CacheMetaDataPath();
  58. BAIL_ON_FAILURE(hr);
  59. hr = pGenObject->_pPropertyCache->InitializePropertyCache(
  60. pGenObject->_pszServerName
  61. );
  62. BAIL_ON_FAILURE(hr);
  63. //
  64. // To maintain compatibility with IIS4 we want to fail when
  65. // creating a new object if the metabase path already exists.
  66. //
  67. if( ADS_OBJECT_UNBOUND == pGenObject->_dwObjectState )
  68. {
  69. hr = ::MetaBaseDetectKey( pGenObject->_pAdminBase,
  70. pGenObject->_pszMetaBasePath
  71. );
  72. if( SUCCEEDED(hr) )
  73. {
  74. hr = HRESULT_FROM_WIN32( ERROR_ALREADY_EXISTS );
  75. }
  76. else if( ERROR_PATH_NOT_FOUND == HRESULT_CODE(hr) )
  77. {
  78. hr = S_OK;
  79. }
  80. BAIL_ON_FAILURE(hr);
  81. }
  82. if ( !_wcsicmp(ClassName, L"IIsFtpServer") ||
  83. !_wcsicmp(ClassName, L"IIsWebServer") ||
  84. !_wcsicmp(ClassName, L"IIsNntpServer") ||
  85. !_wcsicmp(ClassName, L"IIsSmtpServer") ||
  86. !_wcsicmp(ClassName, L"IIsPop3Server") ||
  87. !_wcsicmp(ClassName, L"IIsImapServer")
  88. )
  89. {
  90. pszClassName = L"IIsServer";
  91. }
  92. else if ( !_wcsicmp(ClassName, L"IIsWebDirectory") ||
  93. !_wcsicmp(ClassName, L"IIsWebVirtualDir"))
  94. {
  95. pszClassName = L"IIsApp";
  96. }
  97. hr = ADSILoadExtensionManager(
  98. pszClassName,
  99. (IADs *)pGenObject,
  100. Credentials,
  101. pGenObject->_pDispMgr,
  102. &pExtensionMgr
  103. );
  104. BAIL_ON_FAILURE(hr);
  105. pGenObject->_pExtMgr = pExtensionMgr;
  106. hr = pGenObject->QueryInterface(riid, ppvObj);
  107. BAIL_ON_FAILURE(hr);
  108. pGenObject->Release();
  109. RRETURN(hr);
  110. error:
  111. delete pGenObject;
  112. RRETURN(hr);
  113. }
  114. CIISGenObject::~CIISGenObject( )
  115. {
  116. if (_pExtMgr)
  117. {
  118. delete _pExtMgr;
  119. }
  120. VariantClear(&_vFilter);
  121. if (_pDispMgr)
  122. {
  123. delete _pDispMgr;
  124. }
  125. if (_pPropertyCache)
  126. {
  127. delete _pPropertyCache;
  128. }
  129. if (_pszServerName) {
  130. FreeADsStr(_pszServerName);
  131. }
  132. if (_pszMetaBasePath){
  133. FreeADsStr(_pszMetaBasePath);
  134. }
  135. }
  136. STDMETHODIMP
  137. CIISGenObject::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  138. {
  139. if (ppv == NULL) {
  140. RRETURN(E_POINTER);
  141. }
  142. if (IsEqualIID(iid, IID_IUnknown))
  143. {
  144. *ppv = (IADs FAR *) this;
  145. }
  146. else if (IsEqualIID(iid, IID_IADsContainer))
  147. {
  148. *ppv = (IADsContainer FAR *) this;
  149. }
  150. else if (IsEqualIID(iid, IID_IADs))
  151. {
  152. *ppv = (IADs FAR *) this;
  153. }
  154. else if (IsEqualIID(iid, IID_IISBaseObject))
  155. {
  156. *ppv = (IISBaseObject FAR *) this;
  157. }
  158. else if (IsEqualIID(iid, IID_IDispatch))
  159. {
  160. *ppv = (IADs FAR *) this;
  161. }
  162. else if (_pExtMgr)
  163. {
  164. RRETURN(_pExtMgr->QueryInterface(iid,ppv));
  165. }
  166. else
  167. {
  168. *ppv = NULL;
  169. return E_NOINTERFACE;
  170. }
  171. AddRef();
  172. return NOERROR;
  173. }
  174. HRESULT
  175. CIISGenObject::SetInfo()
  176. {
  177. HRESULT hr = S_OK;
  178. COSERVERINFO csiName;
  179. COSERVERINFO *pcsiParam = &csiName;
  180. IClassFactory * pcsfFactory = NULL;
  181. IIISApplicationAdmin * pAppAdmin = NULL;
  182. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  183. // Check to see if we're creating an IIsApplicationPool
  184. // If so, use the IISApplicationAdmin interface
  185. if ( !_wcsicmp(_ADsClass, L"IIsApplicationPool"))
  186. {
  187. memset(pcsiParam, 0, sizeof(COSERVERINFO));
  188. //
  189. // special case to handle "localhost" to work-around ole32 bug
  190. //
  191. if (_pszServerName == NULL || _wcsicmp(_pszServerName,L"localhost") == 0) {
  192. pcsiParam->pwszName = NULL;
  193. }
  194. else {
  195. pcsiParam->pwszName = _pszServerName;
  196. }
  197. hr = CoGetClassObject(
  198. CLSID_WamAdmin,
  199. CLSCTX_SERVER,
  200. pcsiParam,
  201. IID_IClassFactory,
  202. (void**) &pcsfFactory
  203. );
  204. BAIL_ON_FAILURE(hr);
  205. hr = pcsfFactory->CreateInstance(
  206. NULL,
  207. IID_IIISApplicationAdmin,
  208. (void **) &pAppAdmin
  209. );
  210. BAIL_ON_FAILURE(hr);
  211. hr = pAppAdmin->CreateApplicationPool( _Name );
  212. // Don't BAIL_ON_FAILURE here! Check the HR below first...
  213. }
  214. // Otherwise do the creation the old fashioned way
  215. else {
  216. hr = IISCreateObject();
  217. }
  218. //
  219. // Since methods that we aggregate like IIsApp::AppCreate may
  220. // persist our path in the metabase we don't want to fail just
  221. // because the path exists. This is done to maintain backward
  222. // compatibility with IIS4.
  223. //
  224. if( ERROR_ALREADY_EXISTS != HRESULT_CODE(hr) )
  225. {
  226. BAIL_ON_FAILURE(hr);
  227. }
  228. //
  229. // If the create succeded, set the object type to bound
  230. //
  231. SetObjectState(ADS_OBJECT_BOUND);
  232. }
  233. hr = IISSetObject();
  234. BAIL_ON_FAILURE(hr);
  235. error:
  236. if (pcsfFactory) {
  237. pcsfFactory->Release();
  238. }
  239. if (pAppAdmin) {
  240. pAppAdmin->Release();
  241. }
  242. RRETURN(hr);
  243. }
  244. HRESULT
  245. CIISGenObject::IISSetObject()
  246. {
  247. HRESULT hr = S_OK;
  248. METADATA_HANDLE hObjHandle = NULL;
  249. PMETADATA_RECORD pMetaDataArray = NULL;
  250. DWORD dwMDNumDataEntries = 0;
  251. //
  252. // Add SetObject functionality : sophiac
  253. //
  254. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  255. hr = E_ADS_OBJECT_UNBOUND;
  256. BAIL_ON_FAILURE(hr);
  257. }
  258. hr = OpenAdminBaseKey(
  259. _Credentials,
  260. _pszServerName,
  261. (LPWSTR) _pszMetaBasePath,
  262. METADATA_PERMISSION_WRITE,
  263. &_pAdminBase,
  264. &hObjHandle
  265. );
  266. BAIL_ON_FAILURE(hr);
  267. hr = _pPropertyCache->IISMarshallProperties(
  268. &pMetaDataArray,
  269. &dwMDNumDataEntries
  270. );
  271. BAIL_ON_FAILURE(hr);
  272. hr = MetaBaseSetAllData(
  273. _pAdminBase,
  274. hObjHandle,
  275. L"",
  276. (PMETADATA_RECORD)pMetaDataArray,
  277. dwMDNumDataEntries
  278. );
  279. BAIL_ON_FAILURE(hr);
  280. error:
  281. if (pMetaDataArray) {
  282. FreeMetaDataRecordArray(pMetaDataArray, dwMDNumDataEntries);
  283. }
  284. if (_pAdminBase && hObjHandle) {
  285. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  286. }
  287. RRETURN(hr);
  288. }
  289. HRESULT
  290. CIISGenObject::IISCreateObject()
  291. {
  292. HRESULT hr = S_OK;
  293. METADATA_HANDLE hObjHandle = NULL;
  294. METADATA_RECORD mdrData;
  295. WCHAR DataBuf[MAX_PATH];
  296. WCHAR * PathBuf = (WCHAR *)AllocADsMem((DWORD) wcslen(_pszMetaBasePath)*sizeof(WCHAR) + 2);
  297. WCHAR * pChild = NULL;
  298. if (PathBuf == NULL)
  299. {
  300. hr = E_OUTOFMEMORY;
  301. BAIL_ON_FAILURE(hr);
  302. }
  303. wcscpy(PathBuf, _pszMetaBasePath);
  304. WCHAR * q = NULL, * p = NULL;
  305. do
  306. {
  307. hr = MetaBaseDetectKey(_pAdminBase, PathBuf);
  308. // if failed, try parent path
  309. if (FAILED(hr))
  310. {
  311. p = _tcsrchr(PathBuf, _T('/'));
  312. if (p != NULL)
  313. {
  314. if (q != NULL)
  315. *q = _T('/');
  316. *p = 0;
  317. pChild = p + 1;
  318. }
  319. else
  320. {
  321. BAIL_ON_FAILURE(hr);
  322. }
  323. }
  324. else
  325. {
  326. break;
  327. }
  328. q = p;
  329. } while (true);
  330. hr = OpenAdminBaseKey(
  331. _Credentials,
  332. _pszServerName,
  333. PathBuf,
  334. METADATA_PERMISSION_WRITE,
  335. &_pAdminBase,
  336. &hObjHandle
  337. );
  338. BAIL_ON_FAILURE(hr);
  339. if (pChild != NULL)
  340. {
  341. hr = MetaBaseCreateObject(
  342. _pAdminBase,
  343. hObjHandle,
  344. pChild
  345. );
  346. }
  347. if( ERROR_ALREADY_EXISTS != HRESULT_CODE(hr) )
  348. {
  349. BAIL_ON_FAILURE(hr);
  350. }
  351. //
  352. // Set KeyType
  353. //
  354. if (wcslen(_ADsClass) >= MAX_PATH)
  355. {
  356. BAIL_ON_FAILURE(E_ADS_BAD_PARAMETER);
  357. }
  358. wcscpy((LPWSTR)DataBuf, _ADsClass);
  359. mdrData.dwMDIdentifier = MD_KEY_TYPE;
  360. mdrData.dwMDDataType = STRING_METADATA;
  361. mdrData.dwMDUserType = IIS_MD_UT_SERVER;
  362. mdrData.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  363. mdrData.dwMDDataLen = (DWORD)(wcslen(DataBuf)+1)*2;
  364. mdrData.pbMDData = (PBYTE)DataBuf;
  365. hr = _pAdminBase->SetData(
  366. hObjHandle,
  367. pChild,
  368. &mdrData);
  369. BAIL_ON_FAILURE(hr);
  370. error:
  371. if (_pAdminBase && hObjHandle)
  372. {
  373. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  374. }
  375. if (PathBuf != NULL)
  376. {
  377. FreeADsMem(PathBuf);
  378. }
  379. RRETURN(hr);
  380. }
  381. HRESULT
  382. CIISGenObject::GetInfo()
  383. {
  384. _pPropertyCache->flushpropcache();
  385. RRETURN(GetInfo(TRUE));
  386. }
  387. HRESULT
  388. CIISGenObject::GetInfo(
  389. BOOL fExplicit
  390. )
  391. {
  392. HRESULT hr = S_OK;
  393. METADATA_HANDLE hObjHandle = NULL;
  394. DWORD dwMDAttributes = METADATA_INHERIT;
  395. DWORD dwMDUserType = ALL_METADATA;
  396. DWORD dwMDDataType = ALL_METADATA;
  397. DWORD dwMDNumDataEntries;
  398. DWORD dwMDDataSetNumber;
  399. LPBYTE pBuffer = NULL;
  400. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  401. hr = E_ADS_OBJECT_UNBOUND;
  402. BAIL_ON_FAILURE(hr);
  403. }
  404. hr = OpenAdminBaseKey(
  405. _Credentials,
  406. _pszServerName,
  407. _pszMetaBasePath,
  408. METADATA_PERMISSION_READ,
  409. &_pAdminBase,
  410. &hObjHandle
  411. );
  412. BAIL_ON_FAILURE(hr);
  413. hr = MetaBaseGetAllData(
  414. _pAdminBase,
  415. hObjHandle,
  416. L"",
  417. dwMDAttributes,
  418. dwMDUserType,
  419. dwMDDataType,
  420. &dwMDNumDataEntries,
  421. &dwMDDataSetNumber,
  422. (LPBYTE *)&pBuffer
  423. );
  424. BAIL_ON_FAILURE(hr);
  425. hr = _pPropertyCache->IISUnMarshallProperties(
  426. pBuffer,
  427. pBuffer,
  428. dwMDNumDataEntries,
  429. fExplicit
  430. );
  431. BAIL_ON_FAILURE(hr);
  432. error:
  433. if (pBuffer) {
  434. FreeADsMem(pBuffer);
  435. }
  436. if (_pAdminBase && hObjHandle) {
  437. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  438. }
  439. RRETURN(hr);
  440. }
  441. /* IADsContainer methods */
  442. STDMETHODIMP
  443. CIISGenObject::get_Count(long FAR* retval)
  444. {
  445. RRETURN(E_NOTIMPL);
  446. }
  447. STDMETHODIMP
  448. CIISGenObject::get_Filter(THIS_ VARIANT FAR* pVar)
  449. {
  450. RRETURN(E_NOTIMPL);
  451. }
  452. STDMETHODIMP
  453. CIISGenObject::put_Filter(THIS_ VARIANT Var)
  454. {
  455. RRETURN(E_NOTIMPL);
  456. }
  457. STDMETHODIMP
  458. CIISGenObject::put_Hints(THIS_ VARIANT Var)
  459. {
  460. RRETURN( E_NOTIMPL);
  461. }
  462. STDMETHODIMP
  463. CIISGenObject::get_Hints(THIS_ VARIANT FAR* pVar)
  464. {
  465. RRETURN(E_NOTIMPL);
  466. }
  467. STDMETHODIMP
  468. CIISGenObject::GetObject(
  469. BSTR ClassName,
  470. BSTR RelativeName,
  471. IDispatch * FAR* ppObject
  472. )
  473. {
  474. HRESULT hr = S_OK;
  475. hr = ::RelativeGetObject(
  476. _ADsPath,
  477. ClassName,
  478. RelativeName,
  479. _Credentials,
  480. ppObject,
  481. FALSE
  482. );
  483. RRETURN(hr);
  484. }
  485. STDMETHODIMP
  486. CIISGenObject::get__NewEnum(
  487. THIS_ IUnknown * FAR* retval
  488. )
  489. {
  490. HRESULT hr;
  491. IUnknown FAR* punkEnum=NULL;
  492. IEnumVARIANT * penum = NULL;
  493. *retval = NULL;
  494. hr = CIISGenObjectEnum::Create(
  495. (CIISGenObjectEnum **)&penum,
  496. _ADsPath,
  497. _vFilter,
  498. _Credentials
  499. );
  500. BAIL_ON_FAILURE(hr);
  501. hr = penum->QueryInterface(
  502. IID_IUnknown,
  503. (VOID FAR* FAR*)retval
  504. );
  505. BAIL_ON_FAILURE(hr);
  506. if (penum) {
  507. penum->Release();
  508. }
  509. RRETURN(NOERROR);
  510. error:
  511. if (penum) {
  512. delete penum;
  513. }
  514. RRETURN(hr);
  515. }
  516. inline
  517. HRESULT
  518. ValidateRelativePath(
  519. IN LPCWSTR wszRelativePath
  520. )
  521. /*++
  522. Routine Description:
  523. Determine if a relative path is valid. This is really just to check
  524. assumptions that are made about the relative path.
  525. It doesn't do much now, but might be expanded and moved to a common
  526. location if necessary.
  527. Arguments:
  528. IN wszRelativePath : a relative ads path
  529. Return Value:
  530. E_ADS_BAD_PATHNAME if the path is not valid
  531. --*/
  532. {
  533. HRESULT hr = E_ADS_BAD_PATHNAME;
  534. if( wszRelativePath && *wszRelativePath != L'/' )
  535. {
  536. hr = S_OK;
  537. }
  538. RRETURN(hr);
  539. }
  540. STDMETHODIMP
  541. CIISGenObject::Create(
  542. THIS_ BSTR ClassName,
  543. BSTR RelativeName,
  544. IDispatch * FAR* ppObject
  545. )
  546. {
  547. HRESULT hr = S_OK;
  548. IADs * pADs = NULL;
  549. BOOL bRelativeNameExtended = FALSE;
  550. LPWSTR pwszParentClass = NULL;
  551. LPWSTR pwszParentADsPath = NULL;
  552. LPWSTR pwszRelativeName = NULL;
  553. DWORD i = 0;
  554. //
  555. // Validate if this class really exists in the schema
  556. // and validate that this object can be created in this
  557. // container
  558. //
  559. hr = _pSchema->ValidateClassName(ClassName);
  560. BAIL_ON_FAILURE(hr);
  561. //
  562. // Handle case where RelativeName may be an extended path,
  563. // such as foo/bar/baz.
  564. //
  565. hr = ValidateRelativePath( RelativeName );
  566. BAIL_ON_FAILURE(hr);
  567. bRelativeNameExtended = ( wcschr( RelativeName, L'/' ) != NULL );
  568. if( bRelativeNameExtended )
  569. {
  570. pwszRelativeName = wcsrchr( RelativeName, L'/' ) + 1;
  571. hr = ResolveExtendedChildPath( RelativeName,
  572. &pwszParentADsPath,
  573. &pwszParentClass );
  574. BAIL_ON_FAILURE(hr);
  575. }
  576. else
  577. {
  578. pwszParentClass = _ADsClass;
  579. pwszParentADsPath = _ADsPath;
  580. pwszRelativeName = RelativeName;
  581. }
  582. //
  583. // validate name --> can't have ',' in the name
  584. //
  585. while (RelativeName[i] != L'\0' && RelativeName[i] != L',')
  586. i++;
  587. if (RelativeName[i] != L'\0' || i >= METADATA_MAX_NAME_LEN) {
  588. hr = E_ADS_BAD_PARAMETER;
  589. BAIL_ON_FAILURE(hr);
  590. }
  591. hr = _pSchema->ValidateContainedClassName(pwszParentClass, ClassName);
  592. BAIL_ON_FAILURE(hr);
  593. hr = CIISGenObject::CreateGenericObject(
  594. pwszParentADsPath,
  595. pwszRelativeName,
  596. ClassName,
  597. _Credentials,
  598. ADS_OBJECT_UNBOUND,
  599. IID_IADs,
  600. (void **)&pADs
  601. );
  602. BAIL_ON_FAILURE(hr);
  603. hr = pADs->QueryInterface(
  604. IID_IDispatch,
  605. (void **)ppObject
  606. );
  607. BAIL_ON_FAILURE(hr);
  608. error:
  609. if (pADs) {
  610. pADs->Release();
  611. }
  612. if( bRelativeNameExtended )
  613. {
  614. ADsFreeString( pwszParentClass );
  615. ADsFreeString( pwszParentADsPath );
  616. }
  617. RRETURN(hr);
  618. }
  619. STDMETHODIMP
  620. CIISGenObject::Delete(
  621. THIS_ BSTR bstrClassName,
  622. BSTR bstrRelativeName
  623. )
  624. {
  625. HRESULT hr = S_OK;
  626. METADATA_HANDLE hObjHandle = NULL;
  627. COSERVERINFO csiName;
  628. COSERVERINFO *pcsiParam = &csiName;
  629. IClassFactory * pcsfFactory = NULL;
  630. IIISApplicationAdmin * pAppAdmin = NULL;
  631. //
  632. // Get Server and Path name
  633. //
  634. hr = CacheMetaDataPath();
  635. BAIL_ON_FAILURE(hr);
  636. // Check to see if we're deleting an IIsApplicationPool
  637. // If so, use the IISApplicationAdmin interface
  638. if ( !_wcsicmp(bstrClassName, L"IIsApplicationPool"))
  639. {
  640. memset(pcsiParam, 0, sizeof(COSERVERINFO));
  641. //
  642. // special case to handle "localhost" to work-around ole32 bug
  643. //
  644. if (_pszServerName == NULL || _wcsicmp(_pszServerName,L"localhost") == 0) {
  645. pcsiParam->pwszName = NULL;
  646. }
  647. else {
  648. pcsiParam->pwszName = _pszServerName;
  649. }
  650. hr = CoGetClassObject(
  651. CLSID_WamAdmin,
  652. CLSCTX_SERVER,
  653. pcsiParam,
  654. IID_IClassFactory,
  655. (void**) &pcsfFactory
  656. );
  657. BAIL_ON_FAILURE(hr);
  658. hr = pcsfFactory->CreateInstance(
  659. NULL,
  660. IID_IIISApplicationAdmin,
  661. (void **) &pAppAdmin
  662. );
  663. BAIL_ON_FAILURE(hr);
  664. hr = pAppAdmin->DeleteApplicationPool( bstrRelativeName );
  665. BAIL_ON_FAILURE(hr);
  666. }
  667. // Otherwise do the delete the old fashioned way
  668. else {
  669. hr = OpenAdminBaseKey(
  670. _Credentials,
  671. _pszServerName,
  672. _pszMetaBasePath,
  673. METADATA_PERMISSION_WRITE,
  674. &_pAdminBase,
  675. &hObjHandle
  676. );
  677. BAIL_ON_FAILURE(hr);
  678. //
  679. // Pass in full path
  680. //
  681. hr = MetaBaseDeleteObject(
  682. _pAdminBase,
  683. hObjHandle,
  684. (LPWSTR)bstrRelativeName
  685. );
  686. BAIL_ON_FAILURE(hr);
  687. }
  688. error:
  689. if (pcsfFactory) {
  690. pcsfFactory->Release();
  691. }
  692. if (pAppAdmin) {
  693. pAppAdmin->Release();
  694. }
  695. if (_pAdminBase && hObjHandle) {
  696. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  697. }
  698. RRETURN(hr);
  699. }
  700. STDMETHODIMP
  701. CIISGenObject::CopyHere(
  702. THIS_ BSTR SourceName,
  703. BSTR NewName,
  704. IDispatch * FAR* ppObject
  705. )
  706. {
  707. HRESULT hr = S_OK;
  708. IUnknown *pUnk = NULL;
  709. METADATA_HANDLE hObjHandle = NULL;
  710. LPWSTR pszIISPathName = NULL;
  711. IADs *pADs = NULL;
  712. BSTR bstrClassName = NULL;
  713. LPWSTR pszPath = NULL;
  714. IWamAdmin2 *pWamAdmin = NULL;
  715. LPWSTR pszIISNewName = NULL;
  716. bool bIsW3 = false;
  717. bIsW3 = CheckIsW3(_ADsPath);
  718. if (bIsW3)
  719. {
  720. hr = InitWamAdmin(_pszServerName, &pWamAdmin);
  721. BAIL_ON_FAILURE(hr);
  722. }
  723. //
  724. // open common path node
  725. //
  726. hr = BuildIISPathFromADsPath(
  727. _ADsPath,
  728. &pszIISPathName
  729. );
  730. BAIL_ON_FAILURE(hr);
  731. hr = OpenAdminBaseKey(
  732. _Credentials,
  733. _pszServerName,
  734. pszIISPathName,
  735. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  736. &_pAdminBase,
  737. &hObjHandle
  738. );
  739. BAIL_ON_FAILURE(hr);
  740. //
  741. // Do Copy operation
  742. //
  743. hr = MetaBaseCopyObject(
  744. _pAdminBase,
  745. hObjHandle,
  746. (LPWSTR)SourceName,
  747. hObjHandle,
  748. (LPWSTR)NewName
  749. );
  750. BAIL_ON_FAILURE(hr);
  751. if (hObjHandle) {
  752. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  753. hObjHandle = NULL;
  754. }
  755. if (pszIISPathName) {
  756. DWORD dwLen;
  757. dwLen = (DWORD)(wcslen(pszIISPathName) + wcslen(NewName)) + 2;
  758. pszIISNewName = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR));
  759. if (!pszIISNewName) {
  760. hr = E_OUTOFMEMORY;
  761. BAIL_ON_FAILURE(hr);
  762. }
  763. wcscpy(pszIISNewName, pszIISPathName);
  764. if (NewName) {
  765. wcscat(pszIISNewName, L"/");
  766. wcscat(pszIISNewName, (LPWSTR)NewName);
  767. }
  768. }
  769. if (bIsW3 && pWamAdmin)
  770. {
  771. hr = pWamAdmin->AppRecover((LPWSTR) pszIISNewName, TRUE);
  772. BAIL_ON_FAILURE(hr);
  773. }
  774. hr = get_CoreADsClass(&bstrClassName);
  775. BAIL_ON_FAILURE(hr);
  776. hr = CIISGenObject::CreateGenericObject(
  777. _ADsPath,
  778. NewName,
  779. bstrClassName,
  780. _Credentials,
  781. ADS_OBJECT_BOUND,
  782. IID_IADs,
  783. (void **)&pADs
  784. );
  785. BAIL_ON_FAILURE(hr);
  786. pszPath = ((CIISGenObject*)pADs)->ReturnMetaDataPath();
  787. hr = pADs->QueryInterface(
  788. IID_IDispatch,
  789. (void **)ppObject
  790. );
  791. BAIL_ON_FAILURE(hr);
  792. error:
  793. if (_pAdminBase) {
  794. if (hObjHandle) {
  795. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  796. }
  797. }
  798. if (pWamAdmin) {
  799. UninitWamAdmin(pWamAdmin);
  800. }
  801. if (bstrClassName) {
  802. ADsFreeString(bstrClassName);
  803. }
  804. if (pszIISPathName) {
  805. FreeADsStr(pszIISPathName);
  806. }
  807. if (pszIISNewName) {
  808. FreeADsMem(pszIISNewName);
  809. }
  810. if (pADs){
  811. pADs->Release();
  812. }
  813. RRETURN(hr);
  814. }
  815. bool
  816. CIISGenObject::CheckIsW3(LPCWSTR pszPath)
  817. {
  818. // we should only return true if the second part of the path = 'W3SVC'
  819. // IIS://localhost/W3SVC/1/blah
  820. WCHAR* token = NULL;
  821. WCHAR* pszWorker = NULL;
  822. pszWorker = new WCHAR[(DWORD)wcslen(pszPath) + 1];
  823. if (!pszWorker)
  824. {
  825. return false;
  826. }
  827. wcscpy(pszWorker, pszPath);
  828. // get the first token
  829. token = wcstok((WCHAR*)pszWorker, L"/");
  830. // get the second token
  831. token = wcstok(NULL, L"/");
  832. token = wcstok(NULL, L"/");
  833. if (token && !_wcsicmp(token, L"w3svc"))
  834. {
  835. if (pszWorker)
  836. {
  837. delete [] pszWorker;
  838. }
  839. return true;
  840. }
  841. if (pszWorker)
  842. {
  843. delete [] pszWorker;
  844. }
  845. return false;
  846. }
  847. STDMETHODIMP
  848. CIISGenObject::MoveHere(
  849. THIS_ BSTR SourceName,
  850. BSTR NewName,
  851. IDispatch * FAR* ppObject
  852. )
  853. {
  854. HRESULT hr = S_OK;
  855. IUnknown *pUnk = NULL;
  856. METADATA_HANDLE hObjHandle = NULL;
  857. LPWSTR pszIISPathName = NULL;
  858. IADs *pADs = NULL;
  859. BSTR bstrClassName = NULL;
  860. LPWSTR pszPath = NULL;
  861. IWamAdmin2 *pWamAdmin = NULL;
  862. LPWSTR pszIISOldName = NULL;
  863. LPWSTR pszIISNewName = NULL;
  864. bool bIsW3 = false;
  865. bIsW3 = CheckIsW3(_ADsPath);
  866. if (bIsW3)
  867. {
  868. hr = InitWamAdmin(_pszServerName, &pWamAdmin);
  869. BAIL_ON_FAILURE(hr);
  870. }
  871. //
  872. // open common path node
  873. //
  874. hr = BuildIISPathFromADsPath(
  875. _ADsPath,
  876. &pszIISPathName
  877. );
  878. BAIL_ON_FAILURE(hr);
  879. if (pszIISPathName) {
  880. DWORD dwLen;
  881. dwLen = (DWORD)(wcslen(pszIISPathName) + wcslen(SourceName)) + 2;
  882. pszIISOldName = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR));
  883. if (!pszIISOldName) {
  884. hr = E_OUTOFMEMORY;
  885. BAIL_ON_FAILURE(hr);
  886. }
  887. wcscpy(pszIISOldName, pszIISPathName);
  888. if (NewName) {
  889. wcscat(pszIISOldName, L"/");
  890. wcscat(pszIISOldName, (LPWSTR)SourceName);
  891. }
  892. }
  893. if (bIsW3 && pWamAdmin)
  894. {
  895. hr = pWamAdmin->AppDeleteRecoverable((LPWSTR) pszIISOldName, TRUE);
  896. BAIL_ON_FAILURE(hr);
  897. }
  898. hr = OpenAdminBaseKey(
  899. _Credentials,
  900. _pszServerName,
  901. pszIISPathName,
  902. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  903. &_pAdminBase,
  904. &hObjHandle
  905. );
  906. BAIL_ON_FAILURE(hr);
  907. //
  908. // Do Move operation
  909. //
  910. hr = MetaBaseMoveObject(
  911. _pAdminBase,
  912. hObjHandle,
  913. (LPWSTR)SourceName,
  914. hObjHandle,
  915. (LPWSTR)NewName
  916. );
  917. BAIL_ON_FAILURE(hr);
  918. if (hObjHandle) {
  919. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  920. hObjHandle = NULL;
  921. }
  922. if (pszIISPathName) {
  923. DWORD dwLen;
  924. dwLen = (DWORD)(wcslen(pszIISPathName) + wcslen(NewName)) + 2;
  925. pszIISNewName = (LPWSTR)AllocADsMem(dwLen*sizeof(WCHAR));
  926. if (!pszIISNewName) {
  927. hr = E_OUTOFMEMORY;
  928. BAIL_ON_FAILURE(hr);
  929. }
  930. wcscpy(pszIISNewName, pszIISPathName);
  931. if (NewName) {
  932. wcscat(pszIISNewName, L"/");
  933. wcscat(pszIISNewName, (LPWSTR)NewName);
  934. }
  935. }
  936. if (bIsW3 && pWamAdmin)
  937. {
  938. hr = pWamAdmin->AppRecover((LPWSTR) pszIISNewName, TRUE);
  939. BAIL_ON_FAILURE(hr);
  940. }
  941. hr = get_CoreADsClass(&bstrClassName);
  942. BAIL_ON_FAILURE(hr);
  943. hr = CIISGenObject::CreateGenericObject(
  944. _ADsPath,
  945. NewName,
  946. bstrClassName,
  947. _Credentials,
  948. ADS_OBJECT_BOUND,
  949. IID_IADs,
  950. (void **)&pADs
  951. );
  952. BAIL_ON_FAILURE(hr);
  953. pszPath = ((CIISGenObject*)pADs)->ReturnMetaDataPath();
  954. hr = pADs->QueryInterface(
  955. IID_IDispatch,
  956. (void **)ppObject
  957. );
  958. BAIL_ON_FAILURE(hr);
  959. error:
  960. if (_pAdminBase) {
  961. if (hObjHandle) {
  962. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  963. }
  964. }
  965. if (pWamAdmin) {
  966. UninitWamAdmin(pWamAdmin);
  967. }
  968. if (bstrClassName) {
  969. ADsFreeString(bstrClassName);
  970. }
  971. if (pszIISPathName) {
  972. FreeADsStr(pszIISPathName);
  973. }
  974. if (pszIISOldName) {
  975. FreeADsMem(pszIISOldName);
  976. }
  977. if (pszIISNewName) {
  978. FreeADsMem(pszIISNewName);
  979. }
  980. if (pADs){
  981. pADs->Release();
  982. }
  983. RRETURN(hr);
  984. }
  985. HRESULT
  986. CIISGenObject::AllocateGenObject(
  987. LPWSTR pszClassName,
  988. CCredentials& Credentials,
  989. CIISGenObject ** ppGenObject
  990. )
  991. {
  992. CIISGenObject FAR * pGenObject = NULL;
  993. CAggregatorDispMgr FAR * pDispMgr = NULL;
  994. CPropertyCache FAR * pPropertyCache = NULL;
  995. HRESULT hr = S_OK;
  996. pGenObject = new CIISGenObject();
  997. if (pGenObject == NULL) {
  998. hr = E_OUTOFMEMORY;
  999. }
  1000. BAIL_ON_FAILURE(hr);
  1001. pDispMgr = new CAggregatorDispMgr;
  1002. if (pDispMgr == NULL) {
  1003. hr = E_OUTOFMEMORY;
  1004. }
  1005. BAIL_ON_FAILURE(hr);
  1006. hr = pDispMgr->LoadTypeInfoEntry(
  1007. LIBID_ADs,
  1008. IID_IADs,
  1009. (IADs *)pGenObject,
  1010. DISPID_REGULAR
  1011. );
  1012. BAIL_ON_FAILURE(hr);
  1013. hr = pDispMgr->LoadTypeInfoEntry(LIBID_ADs,
  1014. IID_IADsContainer,
  1015. (IADsContainer *)pGenObject,
  1016. DISPID_NEWENUM
  1017. );
  1018. BAIL_ON_FAILURE(hr);
  1019. hr = pDispMgr->LoadTypeInfoEntry(
  1020. LIBID_IISOle,
  1021. IID_IISBaseObject,
  1022. (IISBaseObject *)pGenObject,
  1023. DISPID_REGULAR
  1024. );
  1025. BAIL_ON_FAILURE(hr);
  1026. hr = CPropertyCache::createpropertycache(
  1027. (CCoreADsObject FAR *)pGenObject,
  1028. &pPropertyCache
  1029. );
  1030. BAIL_ON_FAILURE(hr);
  1031. pDispMgr->RegisterPropertyCache((IPropertyCache*)pPropertyCache);
  1032. pGenObject->_Credentials = Credentials;
  1033. pGenObject->_pPropertyCache = pPropertyCache;
  1034. pGenObject->_pDispMgr = pDispMgr;
  1035. *ppGenObject = pGenObject;
  1036. RRETURN(hr);
  1037. error:
  1038. if (pDispMgr)
  1039. {
  1040. delete pDispMgr;
  1041. }
  1042. if (pGenObject)
  1043. {
  1044. delete pGenObject;
  1045. }
  1046. RRETURN(hr);
  1047. }
  1048. /* INTRINSA suppress=null_pointers, uninitialized */
  1049. STDMETHODIMP
  1050. CIISGenObject::Get(
  1051. THIS_ BSTR bstrName,
  1052. VARIANT FAR* pvProp
  1053. )
  1054. {
  1055. HRESULT hr = S_OK;
  1056. DWORD dwSyntaxId;
  1057. DWORD dwSyntax;
  1058. DWORD dwNumValues = 0;
  1059. LPIISOBJECT pIISSrcObjects = NULL;
  1060. WCHAR wchName[MAX_PATH];
  1061. BSTR bstrClassName = NULL;
  1062. //
  1063. // check if property is a supported property
  1064. //
  1065. hr = get_CoreADsClass(&bstrClassName);
  1066. BAIL_ON_FAILURE(hr);
  1067. if (NULL == bstrClassName)
  1068. {
  1069. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1070. }
  1071. hr = _pSchema->ValidateProperty(bstrClassName, bstrName);
  1072. BAIL_ON_FAILURE(hr);
  1073. //
  1074. // lookup ADSI IIS syntax Id
  1075. //
  1076. hr = _pSchema->LookupSyntaxID(bstrName, &dwSyntax);
  1077. BAIL_ON_FAILURE(hr);
  1078. //
  1079. // check if property is BITMASK type;
  1080. // if BITMASK type, get corresponding DWORD flag property
  1081. //
  1082. // check if property is RAW BINARY type;
  1083. // if RAW BINARY type, get corresponding NTACL flag property
  1084. //
  1085. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) {
  1086. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  1087. BAIL_ON_FAILURE(hr);
  1088. }
  1089. //
  1090. // retrieve data object from cache; if one exists
  1091. //
  1092. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY)
  1093. {
  1094. hr = _pPropertyCache->getproperty(
  1095. wchName,
  1096. &dwSyntaxId,
  1097. &dwNumValues,
  1098. &pIISSrcObjects
  1099. );
  1100. }
  1101. else
  1102. {
  1103. hr = _pPropertyCache->getproperty(
  1104. bstrName,
  1105. &dwSyntaxId,
  1106. &dwNumValues,
  1107. &pIISSrcObjects
  1108. );
  1109. }
  1110. BAIL_ON_FAILURE(hr);
  1111. //
  1112. // reset it to its syntax id if BITMASK type
  1113. //
  1114. pIISSrcObjects->IISType = dwSyntax;
  1115. //
  1116. // translate the IIS objects to variants
  1117. //
  1118. //
  1119. // always return an array for multisz type
  1120. //
  1121. if (dwSyntax == IIS_SYNTAX_ID_BINARY)
  1122. {
  1123. hr = IISTypeToVarTypeCopy(
  1124. _pSchema,
  1125. bstrName,
  1126. pIISSrcObjects,
  1127. pvProp,
  1128. TRUE
  1129. );
  1130. }
  1131. else if (dwNumValues == 1 && dwSyntax != IIS_SYNTAX_ID_MULTISZ &&
  1132. dwSyntax != IIS_SYNTAX_ID_MIMEMAP ) {
  1133. hr = IISTypeToVarTypeCopy(
  1134. _pSchema,
  1135. bstrName,
  1136. pIISSrcObjects,
  1137. pvProp,
  1138. FALSE
  1139. );
  1140. }else {
  1141. hr = IISTypeToVarTypeCopyConstruct(
  1142. _pSchema,
  1143. bstrName,
  1144. pIISSrcObjects,
  1145. dwNumValues,
  1146. pvProp,
  1147. FALSE
  1148. );
  1149. }
  1150. BAIL_ON_FAILURE(hr);
  1151. error:
  1152. if (bstrClassName) {
  1153. ADsFreeString(bstrClassName);
  1154. }
  1155. if (pIISSrcObjects) {
  1156. IISTypeFreeIISObjects(
  1157. pIISSrcObjects,
  1158. dwNumValues
  1159. );
  1160. }
  1161. RRETURN(hr);
  1162. }
  1163. STDMETHODIMP
  1164. CIISGenObject::Put(
  1165. THIS_ BSTR bstrName,
  1166. VARIANT vProp
  1167. )
  1168. {
  1169. HRESULT hr = S_OK;
  1170. DWORD dwSyntaxId = 0;
  1171. DWORD dwIndex = 0;
  1172. LPIISOBJECT pIISDestObjects = NULL;
  1173. DWORD dwNumValues = 0;
  1174. VARIANT * pVarArray = NULL;
  1175. VARIANT * pvProp = NULL;
  1176. VARIANT vVar;
  1177. WCHAR wchName[MAX_PATH];
  1178. BSTR bstrClassName = NULL;
  1179. //
  1180. // check if property is a supported property
  1181. //
  1182. hr = get_CoreADsClass(&bstrClassName);
  1183. BAIL_ON_FAILURE(hr);
  1184. hr = _pSchema->ValidateProperty(bstrClassName, bstrName);
  1185. BAIL_ON_FAILURE(hr);
  1186. //
  1187. // lookup its syntax ID
  1188. //
  1189. hr = _pSchema->LookupSyntaxID( bstrName, &dwSyntaxId);
  1190. BAIL_ON_FAILURE(hr);
  1191. //
  1192. // Issue: How do we handle multi-valued support
  1193. //
  1194. VariantInit(&vVar);
  1195. hr = VariantCopyInd(&vVar, &vProp);
  1196. BAIL_ON_FAILURE(hr);
  1197. if ((V_VT(&vVar) & VT_VARIANT) && V_ISARRAY(&vVar)) {
  1198. hr = ConvertArrayToVariantArray(
  1199. vVar,
  1200. &pVarArray,
  1201. &dwNumValues
  1202. );
  1203. BAIL_ON_FAILURE(hr);
  1204. pvProp = pVarArray;
  1205. }
  1206. else {
  1207. dwNumValues = 1;
  1208. pvProp = &vVar;
  1209. }
  1210. //
  1211. // check if the variant maps to the syntax of this property
  1212. //
  1213. hr = VarTypeToIISTypeCopyConstruct(
  1214. dwSyntaxId,
  1215. pvProp,
  1216. dwNumValues,
  1217. &pIISDestObjects,
  1218. FALSE
  1219. );
  1220. BAIL_ON_FAILURE(hr);
  1221. //
  1222. // check if property is BITMASK type;
  1223. // if BITMASK type, get corresponding DWORD flag property
  1224. //
  1225. if (dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) {
  1226. VARIANT vGetProp;
  1227. DWORD dwMask;
  1228. DWORD dwFlagValue;
  1229. hr = _pSchema->LookupBitMask(bstrName, &dwMask);
  1230. BAIL_ON_FAILURE(hr);
  1231. //
  1232. // get its corresponding DWORD flag value
  1233. //
  1234. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  1235. BAIL_ON_FAILURE(hr);
  1236. VariantInit(&vGetProp);
  1237. hr = Get(wchName, &vGetProp);
  1238. BAIL_ON_FAILURE(hr);
  1239. dwFlagValue = V_I4(&vGetProp);
  1240. if (pIISDestObjects->IISValue.value_1.dwDWORD) {
  1241. dwFlagValue |= dwMask;
  1242. }
  1243. else {
  1244. dwFlagValue &= ~dwMask;
  1245. }
  1246. pIISDestObjects->IISValue.value_1.dwDWORD = dwFlagValue;
  1247. pIISDestObjects->IISType = IIS_SYNTAX_ID_DWORD;
  1248. bstrName = wchName;
  1249. }
  1250. if (dwSyntaxId == IIS_SYNTAX_ID_BINARY) {
  1251. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  1252. BAIL_ON_FAILURE(hr);
  1253. bstrName = wchName;
  1254. }
  1255. //
  1256. // Find this property in the cache
  1257. //
  1258. hr = _pPropertyCache->findproperty(
  1259. bstrName,
  1260. &dwIndex
  1261. );
  1262. //
  1263. // If this property does not exist in the
  1264. // cache, add this property into the cache.
  1265. //
  1266. if (FAILED(hr)) {
  1267. hr = _pPropertyCache->addproperty(
  1268. bstrName,
  1269. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  1270. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  1271. dwNumValues,
  1272. pIISDestObjects
  1273. );
  1274. //
  1275. // If the operation fails for some reason
  1276. // move on to the next property
  1277. //
  1278. BAIL_ON_FAILURE(hr);
  1279. }
  1280. //
  1281. // Now update the property in the cache
  1282. //
  1283. hr = _pPropertyCache->putproperty(
  1284. bstrName,
  1285. CACHE_PROPERTY_MODIFIED,
  1286. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  1287. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  1288. dwNumValues,
  1289. pIISDestObjects
  1290. );
  1291. BAIL_ON_FAILURE(hr);
  1292. error:
  1293. if (pIISDestObjects) {
  1294. IISTypeFreeIISObjects(
  1295. pIISDestObjects,
  1296. dwNumValues
  1297. );
  1298. }
  1299. if (bstrClassName) {
  1300. ADsFreeString(bstrClassName);
  1301. }
  1302. if (pVarArray) {
  1303. DWORD i = 0;
  1304. for (i = 0; i < dwNumValues; i++) {
  1305. VariantClear(pVarArray + i);
  1306. }
  1307. FreeADsMem(pVarArray);
  1308. }
  1309. VariantClear(&vVar);
  1310. RRETURN(hr);
  1311. }
  1312. STDMETHODIMP
  1313. CIISGenObject::PutEx(
  1314. THIS_ long lnControlCode,
  1315. BSTR bstrName,
  1316. VARIANT vProp
  1317. )
  1318. {
  1319. HRESULT hr = S_OK;
  1320. DWORD dwSyntaxId = 0;
  1321. DWORD dwIndex = 0;
  1322. LPIISOBJECT pIISDestObjects = NULL;
  1323. DWORD dwNumValues = 0;
  1324. DWORD dwFlags = 0;
  1325. VARIANT * pVarArray = NULL;
  1326. VARIANT * pvProp = NULL;
  1327. VARIANT vVar;
  1328. WCHAR wchName[MAX_PATH];
  1329. BSTR bstrClassName = NULL;
  1330. METADATA_HANDLE hObjHandle = NULL;
  1331. //
  1332. // check if property is a supported property
  1333. //
  1334. hr = get_CoreADsClass(&bstrClassName);
  1335. BAIL_ON_FAILURE(hr);
  1336. hr = _pSchema->ValidateProperty(bstrClassName, bstrName);
  1337. BAIL_ON_FAILURE(hr);
  1338. //
  1339. // lookup its syntax Id
  1340. //
  1341. hr = _pSchema->LookupSyntaxID( bstrName, &dwSyntaxId);
  1342. BAIL_ON_FAILURE(hr);
  1343. switch (lnControlCode) {
  1344. case ADS_PROPERTY_CLEAR:
  1345. dwFlags = CACHE_PROPERTY_CLEARED;
  1346. pIISDestObjects = NULL;
  1347. dwNumValues = 0;
  1348. break;
  1349. case ADS_PROPERTY_UPDATE:
  1350. dwFlags = CACHE_PROPERTY_MODIFIED;
  1351. //
  1352. // Now begin the rest of the processing
  1353. //
  1354. VariantInit(&vVar);
  1355. hr = VariantCopyInd(&vVar, &vProp);
  1356. BAIL_ON_FAILURE(hr);
  1357. if ((V_VT(&vVar) & VT_VARIANT) && V_ISARRAY(&vVar)) {
  1358. hr = ConvertArrayToVariantArray(
  1359. vVar,
  1360. &pVarArray,
  1361. &dwNumValues
  1362. );
  1363. BAIL_ON_FAILURE(hr);
  1364. pvProp = pVarArray;
  1365. }
  1366. else {
  1367. hr = E_FAIL;
  1368. BAIL_ON_FAILURE(hr);
  1369. }
  1370. VariantClear(&vVar);
  1371. //
  1372. // check if the variant maps to the syntax of this property
  1373. //
  1374. hr = VarTypeToIISTypeCopyConstruct(
  1375. dwSyntaxId,
  1376. pvProp,
  1377. dwNumValues,
  1378. &pIISDestObjects,
  1379. TRUE
  1380. );
  1381. BAIL_ON_FAILURE(hr);
  1382. break;
  1383. default:
  1384. RRETURN(hr = E_ADS_BAD_PARAMETER);
  1385. }
  1386. //
  1387. // check if property is BITMASK type;
  1388. // if BITMASK type, get corresponding DWORD flag property
  1389. //
  1390. if (dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) {
  1391. VARIANT vGetProp;
  1392. DWORD dwMask;
  1393. DWORD dwFlagValue;
  1394. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  1395. BAIL_ON_FAILURE(hr);
  1396. if (dwFlags != CACHE_PROPERTY_CLEARED) {
  1397. hr = _pSchema->LookupBitMask(bstrName, &dwMask);
  1398. BAIL_ON_FAILURE(hr);
  1399. //
  1400. // get its corresponding DWORD flag value
  1401. //
  1402. VariantInit(&vGetProp);
  1403. hr = Get(wchName, &vGetProp);
  1404. BAIL_ON_FAILURE(hr);
  1405. dwFlagValue = V_I4(&vGetProp);
  1406. if (pIISDestObjects->IISValue.value_1.dwDWORD) {
  1407. dwFlagValue |= dwMask;
  1408. }
  1409. else {
  1410. dwFlagValue &= ~dwMask;
  1411. }
  1412. pIISDestObjects->IISValue.value_1.dwDWORD = dwFlagValue;
  1413. pIISDestObjects->IISType = IIS_SYNTAX_ID_DWORD;
  1414. }
  1415. bstrName = wchName;
  1416. }
  1417. if (dwSyntaxId == IIS_SYNTAX_ID_BINARY) {
  1418. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  1419. BAIL_ON_FAILURE(hr);
  1420. bstrName = wchName;
  1421. }
  1422. //
  1423. // Find this property in the cache
  1424. //
  1425. hr = _pPropertyCache->findproperty(
  1426. bstrName,
  1427. &dwIndex
  1428. );
  1429. //
  1430. // If this property does not exist in the
  1431. // cache, add this property into the cache.
  1432. //
  1433. if (FAILED(hr)) {
  1434. hr = _pPropertyCache->addproperty(
  1435. bstrName,
  1436. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  1437. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  1438. dwNumValues,
  1439. pIISDestObjects
  1440. );
  1441. //
  1442. // If the operation fails for some reason
  1443. // move on to the next property
  1444. //
  1445. BAIL_ON_FAILURE(hr);
  1446. }
  1447. //
  1448. // Now update the property in the cache
  1449. //
  1450. hr = _pPropertyCache->putproperty(
  1451. bstrName,
  1452. dwFlags,
  1453. dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK ?
  1454. IIS_SYNTAX_ID_DWORD : dwSyntaxId,
  1455. dwNumValues,
  1456. pIISDestObjects
  1457. );
  1458. BAIL_ON_FAILURE(hr);
  1459. if (dwFlags == CACHE_PROPERTY_CLEARED) {
  1460. DWORD dwMetaId;
  1461. hr = _pSchema->LookupMetaID(bstrName, &dwMetaId);
  1462. BAIL_ON_FAILURE(hr);
  1463. hr = InitServerInfo(_Credentials, _pszServerName, &_pAdminBase, &_pSchema);
  1464. BAIL_ON_FAILURE(hr);
  1465. hr = OpenAdminBaseKey(
  1466. _Credentials,
  1467. _pszServerName,
  1468. _pszMetaBasePath,
  1469. METADATA_PERMISSION_WRITE,
  1470. &_pAdminBase,
  1471. &hObjHandle
  1472. );
  1473. BAIL_ON_FAILURE(hr);
  1474. hr = _pAdminBase->DeleteData(
  1475. hObjHandle,
  1476. (LPWSTR)L"",
  1477. dwMetaId,
  1478. ALL_METADATA
  1479. );
  1480. if (hr == MD_ERROR_DATA_NOT_FOUND) {
  1481. hr = S_OK;
  1482. }
  1483. }
  1484. error:
  1485. if (_pAdminBase && hObjHandle) {
  1486. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  1487. }
  1488. if (bstrClassName) {
  1489. ADsFreeString(bstrClassName);
  1490. }
  1491. if (pIISDestObjects) {
  1492. IISTypeFreeIISObjects(
  1493. pIISDestObjects,
  1494. dwNumValues
  1495. );
  1496. }
  1497. if (pVarArray) {
  1498. DWORD i = 0;
  1499. for (i = 0; i < dwNumValues; i++) {
  1500. VariantClear(pVarArray + i);
  1501. }
  1502. FreeADsMem(pVarArray);
  1503. }
  1504. RRETURN(hr);
  1505. }
  1506. /* INTRINSA suppress=null_pointers, uninitialized */
  1507. STDMETHODIMP
  1508. CIISGenObject::GetEx(
  1509. THIS_ BSTR bstrName,
  1510. VARIANT FAR* pvProp
  1511. )
  1512. {
  1513. HRESULT hr = S_OK;
  1514. DWORD dwSyntaxId;
  1515. DWORD dwSyntax;
  1516. DWORD dwNumValues = 0;
  1517. LPIISOBJECT pIISSrcObjects = NULL;
  1518. WCHAR wchName[MAX_PATH];
  1519. BSTR bstrClassName = NULL;
  1520. //
  1521. // check if property is a supported property
  1522. //
  1523. hr = get_CoreADsClass(&bstrClassName);
  1524. BAIL_ON_FAILURE(hr);
  1525. if (NULL == bstrClassName)
  1526. {
  1527. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1528. }
  1529. hr = _pSchema->ValidateProperty(bstrClassName, bstrName);
  1530. BAIL_ON_FAILURE(hr);
  1531. //
  1532. // lookup its syntax Id
  1533. //
  1534. hr = _pSchema->LookupSyntaxID(bstrName, &dwSyntax);
  1535. BAIL_ON_FAILURE(hr);
  1536. //
  1537. // check if property is BITMASK type;
  1538. // if BITMASK type, get corresponding DWORD flag property
  1539. //
  1540. // check if property is RAW BINARY type;
  1541. // if RAW BINARY type, get corresponding NTACL flag property
  1542. //
  1543. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY) {
  1544. hr = _pSchema->LookupFlagPropName(bstrName, (LPWSTR)wchName);
  1545. BAIL_ON_FAILURE(hr);
  1546. }
  1547. //
  1548. // retrieve data object from cache; if one exists
  1549. //
  1550. if (dwSyntax == IIS_SYNTAX_ID_BOOL_BITMASK || dwSyntax == IIS_SYNTAX_ID_BINARY)
  1551. {
  1552. hr = _pPropertyCache->getproperty(
  1553. wchName,
  1554. &dwSyntaxId,
  1555. &dwNumValues,
  1556. &pIISSrcObjects
  1557. );
  1558. }
  1559. else
  1560. {
  1561. hr = _pPropertyCache->getproperty(
  1562. bstrName,
  1563. &dwSyntaxId,
  1564. &dwNumValues,
  1565. &pIISSrcObjects
  1566. );
  1567. }
  1568. BAIL_ON_FAILURE(hr);
  1569. //
  1570. // reset it to its syntax id if BITMASK type
  1571. //
  1572. pIISSrcObjects->IISType = dwSyntax;
  1573. //
  1574. // translate the IIS objects to variants
  1575. //
  1576. hr = IISTypeToVarTypeCopyConstruct(
  1577. _pSchema,
  1578. bstrName,
  1579. pIISSrcObjects,
  1580. dwNumValues,
  1581. pvProp,
  1582. TRUE
  1583. );
  1584. BAIL_ON_FAILURE(hr);
  1585. error:
  1586. if (bstrClassName) {
  1587. ADsFreeString(bstrClassName);
  1588. }
  1589. if (pIISSrcObjects) {
  1590. IISTypeFreeIISObjects(
  1591. pIISSrcObjects,
  1592. dwNumValues
  1593. );
  1594. }
  1595. RRETURN(hr);
  1596. }
  1597. HRESULT
  1598. CIISGenObject::CacheMetaDataPath()
  1599. {
  1600. HRESULT hr = E_FAIL;
  1601. OBJECTINFO ObjectInfo;
  1602. POBJECTINFO pObjectInfo = &ObjectInfo;
  1603. CLexer Lexer(_ADsPath);
  1604. LPWSTR pszIISPathName = NULL;
  1605. memset(pObjectInfo, 0, sizeof(OBJECTINFO));
  1606. hr = ADsObject(&Lexer, pObjectInfo);
  1607. BAIL_ON_FAILURE(hr);
  1608. _pszServerName = AllocADsStr(pObjectInfo->TreeName);
  1609. if (!_pszServerName) {
  1610. hr = E_OUTOFMEMORY;
  1611. BAIL_ON_FAILURE(hr);
  1612. }
  1613. hr = InitServerInfo(_Credentials, _pszServerName, &_pAdminBase, &_pSchema);
  1614. BAIL_ON_FAILURE(hr);
  1615. pszIISPathName = AllocADsStr(_ADsPath);
  1616. if (!pszIISPathName) {
  1617. hr = E_OUTOFMEMORY;
  1618. BAIL_ON_FAILURE(hr);
  1619. }
  1620. *pszIISPathName = L'\0';
  1621. hr = BuildIISPathFromADsPath(
  1622. pObjectInfo,
  1623. pszIISPathName
  1624. );
  1625. BAIL_ON_FAILURE(hr);
  1626. _pszMetaBasePath = AllocADsStr(pszIISPathName);
  1627. if (!_pszMetaBasePath) {
  1628. hr = E_OUTOFMEMORY;
  1629. BAIL_ON_FAILURE(hr);
  1630. }
  1631. error:
  1632. if (pszIISPathName) {
  1633. FreeADsStr(pszIISPathName);
  1634. }
  1635. FreeObjectInfo(pObjectInfo);
  1636. RRETURN(hr);
  1637. }
  1638. STDMETHODIMP
  1639. CIISGenObject::GetDataPaths(
  1640. THIS_ BSTR bstrName,
  1641. THIS_ LONG lnAttribute,
  1642. VARIANT FAR* pvProp
  1643. )
  1644. {
  1645. HRESULT hr = S_OK;
  1646. DWORD dwMetaId;
  1647. DWORD dwAttribute;
  1648. DWORD dwTemp;
  1649. METADATA_HANDLE hObjHandle = NULL;
  1650. LPBYTE pBuffer = NULL;
  1651. //
  1652. // check if property is a supported property
  1653. //
  1654. hr = _pSchema->LookupMetaID(bstrName, &dwMetaId);
  1655. BAIL_ON_FAILURE(hr);
  1656. hr = _pSchema->LookupMDFlags(dwMetaId, &dwAttribute, &dwTemp);
  1657. BAIL_ON_FAILURE(hr);
  1658. switch (lnAttribute) {
  1659. case IIS_ANY_PROPERTY:
  1660. break;
  1661. case IIS_INHERITABLE_ONLY:
  1662. if ((METADATA_INHERIT & dwAttribute) != METADATA_INHERIT) {
  1663. RRETURN(hr = MD_ERROR_DATA_NOT_FOUND);
  1664. }
  1665. break;
  1666. default :
  1667. RRETURN(hr = E_ADS_BAD_PARAMETER);
  1668. }
  1669. //
  1670. // Get Server and Path name
  1671. //
  1672. hr = CacheMetaDataPath();
  1673. BAIL_ON_FAILURE(hr);
  1674. hr = OpenAdminBaseKey(
  1675. _Credentials,
  1676. _pszServerName,
  1677. _pszMetaBasePath,
  1678. METADATA_PERMISSION_READ,
  1679. &_pAdminBase,
  1680. &hObjHandle
  1681. );
  1682. BAIL_ON_FAILURE(hr);
  1683. hr = MetaBaseGetDataPaths(_pAdminBase,
  1684. hObjHandle,
  1685. dwMetaId,
  1686. (LPBYTE *)&pBuffer
  1687. );
  1688. BAIL_ON_FAILURE(hr);
  1689. hr = MakeVariantFromPathArray( (LPWSTR)_ADsPath, (LPWSTR)pBuffer, pvProp);
  1690. BAIL_ON_FAILURE(hr);
  1691. error:
  1692. if (pBuffer) {
  1693. FreeADsMem(pBuffer);
  1694. }
  1695. if (_pAdminBase && hObjHandle) {
  1696. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  1697. }
  1698. RRETURN(hr);
  1699. }
  1700. STDMETHODIMP
  1701. CIISGenObject::GetPropertyAttribObj(
  1702. THIS_ BSTR bstrName,
  1703. IDispatch * FAR* ppObject
  1704. )
  1705. {
  1706. HRESULT hr = S_OK;
  1707. DWORD dwMetaId;
  1708. DWORD i = 0;
  1709. PROPERTYINFO *pPropertyInfo = NULL;
  1710. IISPropertyAttribute * pPropAttrib = NULL;
  1711. WCHAR wchName[MAX_PATH];
  1712. METADATA_HANDLE hObjHandle = NULL;
  1713. DWORD dwBufferSize = 0;
  1714. METADATA_RECORD mdrMDData;
  1715. LPBYTE pBuffer = NULL;
  1716. VARIANT vVar;
  1717. VariantInit(&vVar);
  1718. *ppObject = NULL;
  1719. //
  1720. // if passed in bstrName is a meta id, then convert it to property name
  1721. //
  1722. if (wcslen(bstrName) >= MAX_PATH) bstrName[MAX_PATH - 1] = L'\0';
  1723. wcscpy((LPWSTR)wchName, bstrName);
  1724. while (wchName[i] != L'\0' && wchName[i] >= L'0' &&
  1725. wchName[i] <= L'9') {
  1726. i++;
  1727. }
  1728. if (i == wcslen((LPWSTR)wchName)) {
  1729. dwMetaId = _wtoi((LPWSTR)wchName);
  1730. hr = _pSchema->ConvertID_To_PropName(dwMetaId, (LPWSTR)wchName);
  1731. BAIL_ON_FAILURE(hr);
  1732. }
  1733. else {
  1734. //
  1735. // check if property is a supported property
  1736. //
  1737. hr = _pSchema->LookupMetaID(bstrName, &dwMetaId);
  1738. BAIL_ON_FAILURE(hr);
  1739. }
  1740. hr = OpenAdminBaseKey(
  1741. _Credentials,
  1742. _pszServerName,
  1743. _pszMetaBasePath,
  1744. METADATA_PERMISSION_READ,
  1745. &_pAdminBase,
  1746. &hObjHandle
  1747. );
  1748. BAIL_ON_FAILURE(hr);
  1749. MD_SET_DATA_RECORD(&mdrMDData,
  1750. dwMetaId,
  1751. METADATA_INHERIT | METADATA_ISINHERITED,
  1752. ALL_METADATA,
  1753. ALL_METADATA,
  1754. dwBufferSize,
  1755. pBuffer);
  1756. hr = _pAdminBase->GetData(
  1757. hObjHandle,
  1758. L"",
  1759. &mdrMDData,
  1760. &dwBufferSize
  1761. );
  1762. pBuffer = (LPBYTE) AllocADsMem(dwBufferSize);
  1763. mdrMDData.pbMDData = pBuffer;
  1764. mdrMDData.dwMDDataLen = dwBufferSize;
  1765. hr = _pAdminBase->GetData(
  1766. hObjHandle,
  1767. L"",
  1768. &mdrMDData,
  1769. &dwBufferSize
  1770. );
  1771. BAIL_ON_FAILURE(hr);
  1772. //
  1773. // get default value
  1774. //
  1775. pPropertyInfo = _pSchema->GetPropertyInfo(wchName);
  1776. ASSERT(pPropertyInfo != NULL);
  1777. if (pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_DWORD ||
  1778. pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_MIMEMAP ||
  1779. pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_IPSECLIST ||
  1780. pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_BINARY ||
  1781. pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_NTACL) {
  1782. vVar.vt = VT_I4;
  1783. vVar.lVal = pPropertyInfo->dwDefault;
  1784. }
  1785. else if (pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_BOOL ||
  1786. pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_BOOL_BITMASK) {
  1787. vVar.vt = VT_BOOL;
  1788. vVar.boolVal = pPropertyInfo->dwDefault ? VARIANT_TRUE : VARIANT_FALSE;
  1789. }
  1790. else if (pPropertyInfo->dwSyntaxId == IIS_SYNTAX_ID_MULTISZ) {
  1791. LPWSTR pszStr = pPropertyInfo->szDefault;
  1792. hr = MakeVariantFromStringArray(NULL,
  1793. pszStr,
  1794. &vVar);
  1795. BAIL_ON_FAILURE(hr);
  1796. }
  1797. else {
  1798. vVar.vt = VT_BSTR;
  1799. hr = ADsAllocString( pPropertyInfo->szDefault, &(vVar.bstrVal));
  1800. BAIL_ON_FAILURE(hr);
  1801. }
  1802. hr = CPropertyAttribute::CreatePropertyAttribute(
  1803. IID_IISPropertyAttribute,
  1804. (VOID**)&pPropAttrib
  1805. );
  1806. BAIL_ON_FAILURE(hr);
  1807. hr = ((CPropertyAttribute*)pPropAttrib)->InitFromRawData(
  1808. (LPWSTR) wchName,
  1809. dwMetaId,
  1810. mdrMDData.dwMDUserType, // usertype
  1811. mdrMDData.dwMDAttributes, // attributes
  1812. &vVar
  1813. );
  1814. BAIL_ON_FAILURE(hr);
  1815. *ppObject = (IDispatch*)pPropAttrib;
  1816. error:
  1817. if (pBuffer) {
  1818. FreeADsMem(pBuffer);
  1819. }
  1820. if (hObjHandle) {
  1821. CloseAdminBaseKey(_pAdminBase, hObjHandle);
  1822. }
  1823. RRETURN(hr);
  1824. }
  1825. HRESULT
  1826. CIISGenObject::ResolveExtendedChildPath(
  1827. IN BSTR RelativeChildPath,
  1828. OUT BSTR *pParentPath,
  1829. OUT BSTR *pParentClass
  1830. )
  1831. /*++
  1832. Routine Description:
  1833. Helper method called from CIISGenObject::Create() finds the
  1834. metabase key that is most proximate to RelativeChildPath and
  1835. returns the ADS class for this key along with adjusted path
  1836. for the parent.
  1837. Arguments:
  1838. IN RelativeChildPath : An extended subpath, such as foo/bar
  1839. OUT pParentPath : Allocated with ADsAllocString
  1840. OUT pParentClass : Allocated with ADsAllocString
  1841. Return Value:
  1842. S_OK
  1843. S_FALSE : No path found in the metabase
  1844. --*/
  1845. {
  1846. ADsAssert( RelativeChildPath );
  1847. ADsAssert( pParentPath );
  1848. ADsAssert( pParentClass );
  1849. *pParentPath = NULL;
  1850. *pParentClass = NULL;
  1851. HRESULT hr = S_OK;
  1852. DWORD cbBuffSize;
  1853. LPWSTR pwszPathBuffer = NULL;
  1854. DWORD dwLen;
  1855. BOOL bFound;
  1856. WCHAR *pch = NULL;
  1857. WCHAR wszParentClassBuffer[MAX_PATH];
  1858. //
  1859. // Build buffer to hold the metabase and ads paths
  1860. //
  1861. cbBuffSize = (DWORD)((wcslen(_ADsPath) + wcslen(RelativeChildPath) + 2)
  1862. * sizeof(WCHAR));
  1863. pwszPathBuffer = (LPWSTR)AllocADsMem( cbBuffSize );
  1864. if( !pwszPathBuffer )
  1865. {
  1866. hr = E_OUTOFMEMORY;
  1867. BAIL_ON_FAILURE(hr);
  1868. }
  1869. ZeroMemory( pwszPathBuffer, cbBuffSize );
  1870. //
  1871. // Build the metabase path for the child
  1872. //
  1873. if (wcslen(_pszMetaBasePath) > wcslen(_ADsPath))
  1874. {
  1875. BAIL_ON_FAILURE(E_ADS_BAD_PARAMETER);
  1876. }
  1877. wcscpy( pwszPathBuffer, _pszMetaBasePath );
  1878. dwLen = (DWORD)wcslen( pwszPathBuffer );
  1879. ADsAssert( dwLen );
  1880. if( pwszPathBuffer[dwLen - 1] != L'/' )
  1881. {
  1882. pwszPathBuffer[dwLen] = L'/';
  1883. }
  1884. wcscat( pwszPathBuffer, RelativeChildPath );
  1885. //
  1886. // Look for the closest path in the metabase to our child
  1887. //
  1888. bFound = FALSE;
  1889. pch = wcsrchr( pwszPathBuffer, L'/' );
  1890. if (pch != NULL)
  1891. *pch = 0;
  1892. while( !bFound && 0 != wcscmp( pwszPathBuffer, _pszMetaBasePath ) )
  1893. {
  1894. hr = MetaBaseDetectKey( _pAdminBase, pwszPathBuffer );
  1895. if( SUCCEEDED(hr) )
  1896. {
  1897. bFound = TRUE;
  1898. }
  1899. else if( ERROR_PATH_NOT_FOUND == HRESULT_CODE(hr) )
  1900. {
  1901. // Continue up the path buffer
  1902. pch = wcsrchr( pwszPathBuffer, L'/' );
  1903. if (pch != NULL)
  1904. *pch = 0;
  1905. hr = S_FALSE;
  1906. }
  1907. else
  1908. {
  1909. BAIL_ON_FAILURE( hr );
  1910. }
  1911. }
  1912. //
  1913. // Get pParentClass
  1914. //
  1915. if( bFound )
  1916. {
  1917. // Get the key type from the node
  1918. hr = MetaBaseGetADsClass( _pAdminBase,
  1919. pwszPathBuffer,
  1920. _pSchema,
  1921. wszParentClassBuffer,
  1922. MAX_PATH
  1923. );
  1924. BAIL_ON_FAILURE( hr );
  1925. }
  1926. else
  1927. {
  1928. // Use our own key type
  1929. if (wcslen(_ADsClass) >= MAX_PATH)
  1930. {
  1931. BAIL_ON_FAILURE(E_ADS_BAD_PARAMETER);
  1932. }
  1933. wcscpy( wszParentClassBuffer, _ADsClass );
  1934. }
  1935. hr = ADsAllocString( wszParentClassBuffer, pParentClass );
  1936. BAIL_ON_FAILURE( hr );
  1937. //
  1938. // Get pParentPath
  1939. //
  1940. wcscpy( pwszPathBuffer, _ADsPath );
  1941. wcscat( pwszPathBuffer, L"/" );
  1942. wcscat( pwszPathBuffer, RelativeChildPath );
  1943. pch = wcsrchr( pwszPathBuffer, L'/' );
  1944. if (pch != NULL)
  1945. *pch = 0;
  1946. hr = ADsAllocString( pwszPathBuffer, pParentPath );
  1947. BAIL_ON_FAILURE( hr );
  1948. error:
  1949. if( pwszPathBuffer )
  1950. {
  1951. FreeADsMem( pwszPathBuffer );
  1952. }
  1953. RRETURN( hr );
  1954. }