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.

5596 lines
135 KiB

  1. /*++
  2. Copyright (c) 1994-2001 Microsoft Corporation
  3. Module Name :
  4. mdkeys.cpp
  5. Abstract:
  6. Metabase key wrapper class
  7. Author:
  8. Ronald Meijer (ronaldm)
  9. Sergei Antonov (sergeia)
  10. Project:
  11. Internet Services Manager
  12. Revision History:
  13. --*/
  14. #include "stdafx.h"
  15. #include "common.h"
  16. #include "idlg.h"
  17. #include "mdkeys.h"
  18. #include "iisdebug.h"
  19. #include "SiteCreator.h"
  20. #ifdef _DEBUG
  21. #undef THIS_FILE
  22. static char BASED_CODE THIS_FILE[] = __FILE__;
  23. #endif
  24. #define new DEBUG_NEW
  25. extern HINSTANCE hDLLInstance;
  26. //
  27. // Constants
  28. //
  29. #define MB_TIMEOUT (15000) // Timeout in milliseconds
  30. #define MB_INIT_BUFF_SIZE ( 256) // Initial buffer size
  31. //
  32. // CComAuthInfo implementation
  33. //
  34. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  35. /* static */
  36. BOOL
  37. CComAuthInfo::SplitUserNameAndDomain(
  38. IN OUT CString & strUserName,
  39. IN CString & strDomainName
  40. )
  41. /*++
  42. Routine Description:
  43. Split the user name and domain from the given
  44. username, which is in the format "domain\user".
  45. Return TRUE if the user name contained a domain
  46. FALSE if it did not
  47. Arguments:
  48. CString & strUserName : User name which may contain a domain name
  49. CString & strDomainName : Output domain name ("." if local)
  50. Return Value:
  51. TRUE if a domain is split off
  52. --*/
  53. {
  54. //
  55. // Assume local
  56. //
  57. strDomainName = _T(".");
  58. int nSlash = strUserName.Find(_T("\\"));
  59. if (nSlash >= 0)
  60. {
  61. strDomainName = strUserName.Left(nSlash);
  62. strUserName = strUserName.Mid(nSlash + 1);
  63. return TRUE;
  64. }
  65. return FALSE;
  66. }
  67. /* static */
  68. DWORD
  69. CComAuthInfo::VerifyUserPassword(
  70. IN LPCTSTR lpstrUserName,
  71. IN LPCTSTR lpstrPassword
  72. )
  73. /*++
  74. Routine Description:
  75. Verify the usernamer password combo checks out
  76. Arguments:
  77. LPCTSTR lpstrUserName : Domain/username combo
  78. LPCTSTR lpstrPassword : Password
  79. Return Value:
  80. ERROR_SUCCESS if the password checks out, an error code
  81. otherwise.
  82. --*/
  83. {
  84. CString strDomain;
  85. CString strUser(lpstrUserName);
  86. CString strPassword(lpstrPassword);
  87. SplitUserNameAndDomain(strUser, strDomain);
  88. //
  89. // In order to look up an account name, this process
  90. // must first be granted the privilege of doing so.
  91. //
  92. CError err;
  93. #if 0
  94. {
  95. HANDLE hToken;
  96. LUID AccountLookupValue;
  97. TOKEN_PRIVILEGES tkp;
  98. do
  99. {
  100. // sounds like it doesn't required for Whistler
  101. if (!::OpenProcessToken(GetCurrentProcess(),
  102. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  103. &hToken)
  104. )
  105. {
  106. err.GetLastWinError();
  107. break;
  108. }
  109. if (!::LookupPrivilegeValue(NULL, SE_TCB_NAME, &AccountLookupValue))
  110. {
  111. err.GetLastWinError();
  112. break;
  113. }
  114. tkp.PrivilegeCount = 1;
  115. tkp.Privileges[0].Luid = AccountLookupValue;
  116. tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  117. ::AdjustTokenPrivileges(
  118. hToken,
  119. FALSE,
  120. &tkp,
  121. sizeof(TOKEN_PRIVILEGES),
  122. (PTOKEN_PRIVILEGES)NULL,
  123. (PDWORD)NULL
  124. );
  125. err.GetLastWinError();
  126. if (err.Failed())
  127. {
  128. break;
  129. }
  130. HANDLE hUser = NULL;
  131. if (::LogonUser(
  132. strUser.GetBuffer(0),
  133. strDomain.GetBuffer(0),
  134. strPassword.GetBuffer(0),
  135. LOGON32_LOGON_NETWORK,
  136. LOGON32_PROVIDER_DEFAULT,
  137. &hUser
  138. ))
  139. {
  140. //
  141. // Success!
  142. //
  143. CloseHandle(hUser);
  144. }
  145. else
  146. {
  147. err.GetLastWinError();
  148. }
  149. //
  150. // Remove the privilege
  151. //
  152. }
  153. while(FALSE);
  154. }
  155. #endif
  156. HANDLE hUser = NULL;
  157. if (::LogonUser(
  158. strUser.GetBuffer(0),
  159. strDomain.GetBuffer(0),
  160. strPassword.GetBuffer(0),
  161. LOGON32_LOGON_NETWORK,
  162. LOGON32_PROVIDER_DEFAULT,
  163. &hUser))
  164. {
  165. //
  166. // Success!
  167. //
  168. CloseHandle(hUser);
  169. }
  170. else
  171. {
  172. err.GetLastWinError();
  173. }
  174. return err;
  175. }
  176. CComAuthInfo::CComAuthInfo(
  177. IN LPCOLESTR lpszServerName OPTIONAL,
  178. IN LPCOLESTR lpszUserName OPTIONAL,
  179. IN LPCOLESTR lpszPassword OPTIONAL
  180. )
  181. /*++
  182. Routine Description:
  183. Construct CIIServer object
  184. Argument:
  185. LPCOLESTR lpszServerName : Server name or NULL for local computer
  186. LPCOLESTR lpszUserName : User name of blank for no impersonation
  187. LPCOLESTR lpszPassword : Password (might be blank or NULL)
  188. Return Value:
  189. N/A
  190. --*/
  191. : m_bstrServerName(),
  192. m_bstrUserName(lpszUserName),
  193. m_bstrPassword(lpszPassword),
  194. m_fLocal(FALSE)
  195. {
  196. SetComputerName(lpszServerName);
  197. }
  198. CComAuthInfo::CComAuthInfo(
  199. IN CComAuthInfo & auth
  200. )
  201. /*++
  202. Routine Description:
  203. Copy constructor
  204. Arguments:
  205. CComAuthInfo & auth : Source object to copy from
  206. Return Value:
  207. N/A
  208. --*/
  209. : m_bstrServerName(auth.m_bstrServerName),
  210. m_bstrUserName(auth.m_bstrUserName),
  211. m_bstrPassword(auth.m_bstrPassword),
  212. m_fLocal(auth.m_fLocal)
  213. {
  214. }
  215. CComAuthInfo::CComAuthInfo(
  216. IN CComAuthInfo * pAuthInfo OPTIONAL
  217. )
  218. /*++
  219. Routine Description:
  220. Copy constructor
  221. Arguments:
  222. CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
  223. Return Value:
  224. N/A
  225. --*/
  226. : m_bstrServerName(),
  227. m_bstrUserName(),
  228. m_bstrPassword(),
  229. m_fLocal(FALSE)
  230. {
  231. if (pAuthInfo)
  232. {
  233. //
  234. // Full authentication information available
  235. //
  236. m_bstrUserName = pAuthInfo->m_bstrUserName;
  237. m_bstrPassword = pAuthInfo->m_bstrPassword;
  238. m_bstrServerName = pAuthInfo->m_bstrServerName;
  239. m_fLocal = pAuthInfo->m_fLocal;
  240. }
  241. else
  242. {
  243. //
  244. // Local computer w/o impersonation
  245. //
  246. SetComputerName(NULL);
  247. }
  248. }
  249. CComAuthInfo &
  250. CComAuthInfo::operator =(
  251. IN CComAuthInfo & auth
  252. )
  253. /*++
  254. Routine Description:
  255. Assignment operator
  256. Arguments:
  257. CComAuthInfo & auth : Source object to copy from
  258. Return Value:
  259. Reference to current object
  260. --*/
  261. {
  262. m_bstrServerName = auth.m_bstrServerName;
  263. m_bstrUserName = auth.m_bstrUserName;
  264. m_bstrPassword = auth.m_bstrPassword;
  265. m_fLocal = auth.m_fLocal;
  266. return *this;
  267. }
  268. CComAuthInfo &
  269. CComAuthInfo::operator =(
  270. IN CComAuthInfo * pAuthInfo OPTIONAL
  271. )
  272. /*++
  273. Routine Description:
  274. Assignment operator
  275. Arguments:
  276. CComAuthInfo * pAuthInfo : Source object to copy from (or NULL)
  277. Return Value:
  278. Reference to current object
  279. --*/
  280. {
  281. if (pAuthInfo)
  282. {
  283. m_bstrUserName = pAuthInfo->m_bstrUserName;
  284. m_bstrPassword = pAuthInfo->m_bstrPassword;
  285. SetComputerName(pAuthInfo->m_bstrServerName);
  286. }
  287. else
  288. {
  289. //
  290. // Local computer w/o impersonation
  291. //
  292. m_bstrUserName.Empty();
  293. m_bstrPassword.Empty();
  294. SetComputerName(NULL);
  295. }
  296. return *this;
  297. }
  298. CComAuthInfo &
  299. CComAuthInfo::operator =(
  300. IN LPCTSTR lpszServerName
  301. )
  302. /*++
  303. Routine Description:
  304. Assignment operator. Assign computer name w/o impersonation
  305. Arguments:
  306. LPCTSTR lpszServerName : Source server name
  307. Return Value:
  308. Reference to current object
  309. --*/
  310. {
  311. RemoveImpersonation();
  312. SetComputerName(lpszServerName);
  313. return *this;
  314. }
  315. void
  316. CComAuthInfo::SetComputerName(
  317. IN LPCOLESTR lpszServerName OPTIONAL
  318. )
  319. /*++
  320. Routine Description:
  321. Store the computer name. Determine if its local.
  322. Arguments:
  323. LPCOLESTR lpszServername : Server name. NULL indicates the local computer
  324. Return Value:
  325. None
  326. --*/
  327. {
  328. if (lpszServerName && *lpszServerName)
  329. {
  330. //
  331. // Specific computer name specified
  332. //
  333. m_bstrServerName = lpszServerName;
  334. m_fLocal = ::IsServerLocal(lpszServerName);
  335. }
  336. else
  337. {
  338. //
  339. // Use local computer name
  340. //
  341. // CODEWORK: Cache static version of computername maybe?
  342. //
  343. TCHAR szLocalServer[MAX_PATH + 1];
  344. DWORD dwSize = MAX_PATH;
  345. VERIFY(::GetComputerName(szLocalServer, &dwSize));
  346. m_bstrServerName = szLocalServer;
  347. m_fLocal = TRUE;
  348. }
  349. }
  350. void
  351. CComAuthInfo::SetImpersonation(
  352. IN LPCOLESTR lpszUser,
  353. IN LPCOLESTR lpszPassword
  354. )
  355. /*++
  356. Routine Description:
  357. Set impersonation parameters
  358. Arguments:
  359. LPCOLESTR lpszUser : User name
  360. LPCOLESTR lpszPassword : Password
  361. Return Value:
  362. None
  363. --*/
  364. {
  365. m_bstrUserName = lpszUser;
  366. StorePassword(lpszPassword);
  367. }
  368. void
  369. CComAuthInfo::RemoveImpersonation()
  370. /*++
  371. Routine Description:
  372. Remove impersonation parameters
  373. Arguments:
  374. None
  375. Return Value:
  376. None
  377. --*/
  378. {
  379. m_bstrUserName.Empty();
  380. m_bstrPassword.Empty();
  381. }
  382. COSERVERINFO *
  383. CComAuthInfo::CreateServerInfoStruct() const
  384. {
  385. return (CComAuthInfo::CreateServerInfoStruct(RPC_C_AUTHN_LEVEL_DEFAULT));
  386. }
  387. COSERVERINFO *
  388. CComAuthInfo::CreateServerInfoStruct(DWORD dwAuthnLevel) const
  389. /*++
  390. Routine Description:
  391. Create the server info structure. Might return NULL for the no frills case.
  392. Arguments:
  393. NULL
  394. Return Value:
  395. A COSERVERINFO structure, or NULL if the computer is local, and no
  396. impersonation is required.
  397. Notes:
  398. Caller must call FreeServerInfoStruct() to prevent memory leaks
  399. --*/
  400. {
  401. //
  402. // Be smart about the server name; optimize for local
  403. // computer name.
  404. //
  405. if (m_fLocal && !UsesImpersonation())
  406. {
  407. //
  408. // Special, no-frills case.
  409. //
  410. return NULL;
  411. }
  412. //
  413. // Create the COM server info for CoCreateInstanceEx
  414. //
  415. COSERVERINFO * pcsiName = NULL;
  416. do
  417. {
  418. pcsiName = (COSERVERINFO *)AllocMem(sizeof(COSERVERINFO));
  419. if (!pcsiName)
  420. {
  421. break;
  422. }
  423. pcsiName->pwszName = m_bstrServerName;
  424. //
  425. // Set impersonation
  426. //
  427. if (UsesImpersonation())
  428. {
  429. COAUTHINFO * pAuthInfo = (COAUTHINFO *)AllocMem(sizeof(COAUTHINFO));
  430. if (!pAuthInfo)
  431. {
  432. break;
  433. }
  434. COAUTHIDENTITY * pAuthIdentityData =
  435. (COAUTHIDENTITY *)AllocMem(sizeof(COAUTHIDENTITY));
  436. if (!pAuthIdentityData)
  437. {
  438. break;
  439. }
  440. CString strUserName(m_bstrUserName);
  441. CString strPassword(m_bstrPassword);
  442. CString strDomain;
  443. //
  444. // Break up domain\username combo
  445. //
  446. SplitUserNameAndDomain(strUserName, strDomain);
  447. pAuthIdentityData->UserLength = strUserName.GetLength();
  448. if (pAuthIdentityData->UserLength)
  449. {
  450. pAuthIdentityData->User = AllocString(
  451. strUserName,
  452. strUserName.GetLength()
  453. );
  454. }
  455. pAuthIdentityData->DomainLength = strDomain.GetLength();
  456. if (pAuthIdentityData->DomainLength)
  457. {
  458. pAuthIdentityData->Domain = AllocString(
  459. strDomain,
  460. strDomain.GetLength()
  461. );
  462. }
  463. pAuthIdentityData->PasswordLength = strPassword.GetLength();
  464. if (pAuthIdentityData->PasswordLength)
  465. {
  466. pAuthIdentityData->Password = AllocString(
  467. strPassword,
  468. strPassword.GetLength()
  469. );
  470. }
  471. // RPC_C_AUTHN_LEVEL_DEFAULT 0
  472. // RPC_C_AUTHN_LEVEL_NONE 1
  473. // RPC_C_AUTHN_LEVEL_CONNECT 2
  474. // RPC_C_AUTHN_LEVEL_CALL 3
  475. // RPC_C_AUTHN_LEVEL_PKT 4
  476. // RPC_C_AUTHN_LEVEL_PKT_INTEGRITY 5
  477. // RPC_C_AUTHN_LEVEL_PKT_PRIVACY 6
  478. if (RPC_C_AUTHN_LEVEL_DEFAULT != dwAuthnLevel)
  479. {
  480. // you can only specify stuff stronger than RPC_C_AUTHN_LEVEL_CONNECT
  481. if (dwAuthnLevel >= RPC_C_AUTHN_LEVEL_CONNECT && dwAuthnLevel <= RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
  482. {
  483. pAuthInfo->dwAuthnLevel = dwAuthnLevel;
  484. }
  485. else
  486. {
  487. pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
  488. }
  489. }
  490. else
  491. {
  492. pAuthInfo->dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
  493. }
  494. pAuthIdentityData->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  495. pAuthInfo->dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
  496. pAuthInfo->dwAuthnSvc = RPC_C_AUTHN_WINNT;
  497. pAuthInfo->dwAuthzSvc = RPC_C_AUTHZ_NONE;
  498. pAuthInfo->pwszServerPrincName = NULL;
  499. pAuthInfo->dwCapabilities = EOAC_NONE;
  500. pAuthInfo->pAuthIdentityData = pAuthIdentityData;
  501. pcsiName->pAuthInfo = pAuthInfo;
  502. }
  503. }
  504. while(FALSE);
  505. return pcsiName;
  506. }
  507. void
  508. CComAuthInfo::FreeServerInfoStruct(
  509. IN COSERVERINFO * pServerInfo
  510. ) const
  511. /*++
  512. Routine Description:
  513. As mentioned above -- free the server info structure
  514. Arguments:
  515. COSERVERINFO * pServerInfo : Server info structure
  516. Return Value:
  517. None
  518. --*/
  519. {
  520. if (pServerInfo)
  521. {
  522. if (pServerInfo->pAuthInfo)
  523. {
  524. if (pServerInfo->pAuthInfo->pAuthIdentityData)
  525. {
  526. if (pServerInfo->pAuthInfo->pAuthIdentityData)
  527. {
  528. SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->User);
  529. SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->Domain);
  530. SAFE_FREEMEM(pServerInfo->pAuthInfo->pAuthIdentityData->Password);
  531. FreeMem(pServerInfo->pAuthInfo->pAuthIdentityData);
  532. }
  533. }
  534. FreeMem(pServerInfo->pAuthInfo);
  535. }
  536. FreeMem(pServerInfo);
  537. }
  538. }
  539. HRESULT
  540. CComAuthInfo::ApplyProxyBlanket(
  541. IN OUT IUnknown * pInterface
  542. )
  543. /*++
  544. Routine Description:
  545. Set security information on the interface. The user name is of the form
  546. domain\username.
  547. Arguments:
  548. IUnknown * pInterface : Interface
  549. Return Value:
  550. HRESULT
  551. --*/
  552. {
  553. HRESULT hr = S_OK;
  554. COSERVERINFO * pcsiName = CreateServerInfoStruct();
  555. //
  556. // This method should only be called if we're using impersonation.
  557. // so the pcsiName returned should never be NULL.
  558. //
  559. // ASSERT(pcsiName && pcsiName->pAuthInfo);
  560. if (pcsiName && pcsiName->pAuthInfo)
  561. {
  562. hr = ::CoSetProxyBlanket(
  563. pInterface,
  564. pcsiName->pAuthInfo->dwAuthnSvc,
  565. pcsiName->pAuthInfo->dwAuthzSvc,
  566. pcsiName->pAuthInfo->pwszServerPrincName,
  567. pcsiName->pAuthInfo->dwAuthnLevel,
  568. pcsiName->pAuthInfo->dwImpersonationLevel,
  569. pcsiName->pAuthInfo->pAuthIdentityData,
  570. pcsiName->pAuthInfo->dwCapabilities
  571. );
  572. FreeServerInfoStruct(pcsiName);
  573. }
  574. return hr;
  575. }
  576. HRESULT
  577. CComAuthInfo::ApplyProxyBlanket(
  578. IN OUT IUnknown * pInterface,
  579. IN DWORD dwAuthnLevel
  580. )
  581. /*++
  582. Routine Description:
  583. Set security information on the interface. The user name is of the form
  584. domain\username.
  585. Arguments:
  586. IUnknown * pInterface : Interface
  587. Return Value:
  588. HRESULT
  589. --*/
  590. {
  591. HRESULT hr = S_OK;
  592. COSERVERINFO * pcsiName = CreateServerInfoStruct(dwAuthnLevel);
  593. //
  594. // This method should only be called if we're using impersonation.
  595. // so the pcsiName returned should never be NULL.
  596. //
  597. // ASSERT(pcsiName && pcsiName->pAuthInfo);
  598. if (pcsiName && pcsiName->pAuthInfo)
  599. {
  600. hr = ::CoSetProxyBlanket(
  601. pInterface,
  602. pcsiName->pAuthInfo->dwAuthnSvc,
  603. pcsiName->pAuthInfo->dwAuthzSvc,
  604. pcsiName->pAuthInfo->pwszServerPrincName,
  605. pcsiName->pAuthInfo->dwAuthnLevel,
  606. pcsiName->pAuthInfo->dwImpersonationLevel,
  607. pcsiName->pAuthInfo->pAuthIdentityData,
  608. pcsiName->pAuthInfo->dwCapabilities
  609. );
  610. FreeServerInfoStruct(pcsiName);
  611. }
  612. return hr;
  613. }
  614. //
  615. // CMetabasePath implemention
  616. //
  617. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  618. const LPCTSTR CMetabasePath::_cszMachine = SZ_MBN_MACHINE;
  619. const LPCTSTR CMetabasePath::_cszRoot = SZ_MBN_ROOT;
  620. const LPCTSTR CMetabasePath::_cszSep = SZ_MBN_SEP_STR;
  621. const TCHAR CMetabasePath::_chSep = SZ_MBN_SEP_CHAR;
  622. /* static */
  623. LPCTSTR
  624. CMetabasePath::ConvertToParentPath(
  625. OUT IN CString & strMetaPath
  626. )
  627. /*++
  628. Routine Description:
  629. Given the path, convert it to the parent path
  630. e.g. "foo/bar/etc" returns "foo/bar"
  631. Arguments:
  632. CString & strMetaPath : Path to be converted
  633. Return value:
  634. Pointer to the converted path, or NULL in case of error
  635. --*/
  636. {
  637. LPTSTR lpszPath = strMetaPath.GetBuffer(1);
  638. LPTSTR lpszTail = lpszPath + lstrlen(lpszPath) - 1;
  639. LPTSTR lpszReturn = NULL;
  640. do
  641. {
  642. if (lpszTail <= lpszPath)
  643. {
  644. break;
  645. }
  646. //
  647. // Strip trailing backslash
  648. //
  649. if (*lpszTail == _chSep)
  650. {
  651. *lpszTail-- = _T('\0');
  652. }
  653. //
  654. // Search for parent
  655. //
  656. while (lpszTail > lpszPath && *lpszTail != _chSep)
  657. {
  658. --lpszTail;
  659. }
  660. if (lpszTail <= lpszPath)
  661. {
  662. break;
  663. }
  664. *lpszTail = _T('\0');
  665. lpszReturn = lpszPath;
  666. }
  667. while(FALSE);
  668. strMetaPath.ReleaseBuffer();
  669. return lpszReturn;
  670. }
  671. /* static */
  672. LPCTSTR
  673. CMetabasePath::TruncatePath(
  674. IN int nLevel,
  675. IN LPCTSTR lpszMDPath,
  676. OUT CString & strNewPath,
  677. OUT CString * pstrRemainder OPTIONAL
  678. )
  679. /*++
  680. Routine Description:
  681. Truncate the given metabase path at the given level, that is,
  682. the nLevel'th separator in the path, starting at 0, where 0 will
  683. always give lpszPath back whether it started with a separator or not.
  684. Examples:
  685. "/lm/w3svc/1/foo" at level 2 returns "/lm/w3svc" as does
  686. "lm/w3svc/1/foo".
  687. Arguments:
  688. int nLevel 0-based separator count to truncate at.
  689. LPTSTR lpszMDPath Fully-qualified metabase path
  690. CString & strNewPath Returns truncated path
  691. CString * pstrRemainder Optionally returns the remainder past
  692. the nLevel'th separator.
  693. Return Value:
  694. The truncated path at the level requested. See examples above. *pstrRemainder
  695. returns the remainder of the path. If the path does not contain nLevel
  696. worth of separators, the entire path is returned, and the remainder will be
  697. blank.
  698. --*/
  699. {
  700. ASSERT_PTR(lpszMDPath);
  701. ASSERT(nLevel >= 0);
  702. if (!lpszMDPath || nLevel < 0)
  703. {
  704. return NULL;
  705. }
  706. //
  707. // Skip the first sep whether it exists or not
  708. //
  709. LPCTSTR lp = *lpszMDPath == _chSep ? lpszMDPath + 1 : lpszMDPath;
  710. LPCTSTR lpRem = NULL;
  711. int cSeparators = 0;
  712. if (nLevel)
  713. {
  714. //
  715. // Advance to the requested separator level
  716. //
  717. while (*lp)
  718. {
  719. if (*lp == _chSep)
  720. {
  721. if (++cSeparators == nLevel)
  722. {
  723. break;
  724. }
  725. }
  726. ++lp;
  727. }
  728. if (!*lp)
  729. {
  730. //
  731. // End of path is considered a separator
  732. //
  733. ++cSeparators;
  734. }
  735. ASSERT(cSeparators <= nLevel);
  736. if (cSeparators == nLevel)
  737. {
  738. //
  739. // Break up the strings
  740. //
  741. strNewPath = lpszMDPath;
  742. strNewPath.ReleaseBuffer((int)(lp - lpszMDPath));
  743. if (*lp)
  744. {
  745. lpRem = ++lp;
  746. }
  747. }
  748. }
  749. //
  750. // Return remainder
  751. //
  752. if (pstrRemainder && lpRem)
  753. {
  754. ASSERT_WRITE_PTR(pstrRemainder);
  755. *pstrRemainder = lpRem;
  756. }
  757. return strNewPath;
  758. }
  759. /* static */
  760. DWORD
  761. CMetabasePath::GetInstanceNumber(
  762. IN LPCTSTR lpszMDPath
  763. )
  764. /*++
  765. Routine Description:
  766. Get the number of the instance referred to in the given metabase
  767. path.
  768. Examples: "lm/w3svc/1/foo/bar" will return 1
  769. "lm/w3svc/" will return 0 (master instance)
  770. "lm/bogus/path/" will return 0xffffffff (error)
  771. Arguments:
  772. LPCTSTR lpszMDPath : A metabase path.
  773. Return Value:
  774. Instance number (0 indicates master instance)
  775. or 0xffffffff if the path is in error.
  776. --*/
  777. {
  778. DWORD dwInstance = 0xffffffff;
  779. CString strService, strInst;
  780. if (GetServicePath(lpszMDPath, strService, &strInst))
  781. {
  782. if (strInst.IsEmpty())
  783. {
  784. dwInstance = MASTER_INSTANCE;
  785. }
  786. else
  787. {
  788. if (_istdigit(strInst.GetAt(0)))
  789. {
  790. dwInstance = _ttol(strInst);
  791. }
  792. }
  793. }
  794. return dwInstance;
  795. }
  796. /* static */
  797. LPCTSTR
  798. CMetabasePath::GetLastNodeName(
  799. IN LPCTSTR lpszMDPath,
  800. OUT CString & strNodeName
  801. )
  802. /*++
  803. Routine Description:
  804. Get the last nodename off the metabase path
  805. Example:
  806. "/lm/foo/bar/" returns "bar"
  807. Arguments:
  808. LPCTSTR lpszMDPath : Metabase path
  809. Return Value:
  810. Pointer to the node name or NULL in case of a malformed path.
  811. --*/
  812. {
  813. ASSERT_PTR(lpszMDPath);
  814. if (!lpszMDPath || !*lpszMDPath)
  815. {
  816. return NULL;
  817. }
  818. LPCTSTR lp;
  819. LPCTSTR lpTail;
  820. lp = lpTail = lpszMDPath + lstrlen(lpszMDPath) - 1;
  821. //
  822. // Skip trailing separator
  823. //
  824. if (*lp == _chSep)
  825. {
  826. --lpTail;
  827. --lp;
  828. }
  829. strNodeName.Empty();
  830. while (*lp && *lp != _chSep)
  831. {
  832. strNodeName += *(lp--);
  833. }
  834. strNodeName.MakeReverse();
  835. return strNodeName;
  836. }
  837. /* static */
  838. void
  839. CMetabasePath::SplitMetaPathAtInstance(
  840. IN LPCTSTR lpszMDPath,
  841. OUT CString & strParent,
  842. OUT CString & strAlias
  843. )
  844. /*++
  845. Routine Description:
  846. Split the given path into parent metabase root and alias, with the root
  847. being the instance path, and the alias everything following the
  848. instance.
  849. Arguments:
  850. LPCTSTR lpszMDPath : Input path
  851. CString & strParent : Outputs the parent path
  852. CString & strAlias : Outputs the alias name
  853. Return Value:
  854. None.
  855. --*/
  856. {
  857. ASSERT_PTR(lpszMDPath);
  858. strParent = lpszMDPath;
  859. strAlias.Empty();
  860. LPTSTR lp = strParent.GetBuffer(0);
  861. ASSERT_PTR(lp);
  862. if (!lp)
  863. {
  864. //
  865. // This is just about impossible
  866. //
  867. return;
  868. }
  869. int cSeparators = 0;
  870. int iChar = 0;
  871. //
  872. // Looking for "LM/sss/ddd/" <-- 3d slash:
  873. //
  874. while (*lp && cSeparators < 2)
  875. {
  876. if (*lp++ == _chSep)
  877. {
  878. ++cSeparators;
  879. }
  880. ++iChar;
  881. }
  882. if (!*lp)
  883. {
  884. //
  885. // Bogus format
  886. //
  887. ASSERT_MSG("Bogus Format");
  888. return;
  889. }
  890. if (_istdigit(*lp))
  891. {
  892. //
  893. // Not at the master instance, skip one more.
  894. //
  895. while (*lp)
  896. {
  897. ++iChar;
  898. if (*lp++ == _chSep)
  899. {
  900. break;
  901. }
  902. }
  903. if (!*lp)
  904. {
  905. //
  906. // Bogus format
  907. //
  908. ASSERT_MSG("Bogus Format");
  909. return;
  910. }
  911. }
  912. strAlias = strParent.Mid(iChar);
  913. strParent.ReleaseBuffer(--iChar);
  914. }
  915. /* static */
  916. BOOL
  917. CMetabasePath::IsHomeDirectoryPath(
  918. IN LPCTSTR lpszMetaPath
  919. )
  920. /*++
  921. Routine Description:
  922. Determine if the path given describes a root directory
  923. Arguments:
  924. LPCTSTR lpszMetaPath : Metabase path
  925. Return Value:
  926. TRUE if the path describes a root directory,
  927. FALSE if it does not
  928. --*/
  929. {
  930. ASSERT_READ_PTR(lpszMetaPath);
  931. LPTSTR lpNode = lpszMetaPath ? _tcsrchr(lpszMetaPath, _chSep) : NULL;
  932. if (lpNode)
  933. {
  934. return _tcsicmp(++lpNode, _cszRoot) == 0;
  935. }
  936. return FALSE;
  937. }
  938. /* static */
  939. BOOL
  940. CMetabasePath::IsMasterInstance(
  941. IN LPCTSTR lpszMDPath
  942. )
  943. /*++
  944. Routine Description:
  945. Determine if the given metabase path points to the master instance
  946. (site). This is essentially the service path.
  947. Arguments:
  948. LPCTSTR lpszMDPath : Metabase path.
  949. Return Value:
  950. TRUE if the path is the master instance,
  951. FALSE otherwise.
  952. --*/
  953. {
  954. ASSERT_READ_PTR(lpszMDPath);
  955. if (!lpszMDPath || !*lpszMDPath)
  956. {
  957. return FALSE;
  958. }
  959. CString strService;
  960. CString strRemainder;
  961. LPCTSTR lpPath = TruncatePath(2, lpszMDPath, strService, &strRemainder);
  962. return lpPath && !strService.IsEmpty() && strRemainder.IsEmpty();
  963. }
  964. /* static */
  965. LPCTSTR
  966. CMetabasePath::GetServiceInfoPath(
  967. IN LPCTSTR lpszMDPath,
  968. OUT CString & strInfoPath,
  969. IN LPCTSTR lpszDefService OPTIONAL
  970. )
  971. /*++
  972. Routine Description:
  973. Generate the appropriate metabase service info path for the given
  974. metabase path.
  975. For example:
  976. "lm/w3svc/1/foo/bar" Generates "lm/w3svc/info"
  977. Arguments:
  978. LPCTSTR lpszMDPath : Input metabase path
  979. CString & strInfoPath : Returns the info path
  980. LPCTSTR lpszDefService : Optionally specifies the default service to
  981. use (e.g "w3svc") if no service could be found
  982. in the path.
  983. Return Value:
  984. The info metabase path or NULL if one could not be generated.
  985. --*/
  986. {
  987. //
  988. // Capability info stored off the service path ("lm/w3svc").
  989. //
  990. CString strService;
  991. CString strRem;
  992. //
  993. // Strip off everything past the service
  994. //
  995. if (!TruncatePath(2, lpszMDPath, strService, &strRem)
  996. || strService.IsEmpty())
  997. {
  998. if (!lpszDefService)
  999. {
  1000. TRACEEOLID("Unable to generate info path");
  1001. return NULL;
  1002. }
  1003. //
  1004. // Machine path (no service). Use web as default service to
  1005. // look for capability and version info.
  1006. //
  1007. strService = CMetabasePath(TRUE, lpszDefService);
  1008. }
  1009. strInfoPath = CMetabasePath(FALSE, strService, SZ_MBN_INFO);
  1010. return strInfoPath;
  1011. }
  1012. /* static */
  1013. LPCTSTR
  1014. CMetabasePath::CleanMetaPath(
  1015. IN OUT CString & strMetaRoot
  1016. )
  1017. /*++
  1018. Routine Description:
  1019. Clean up the metabase path to one valid for internal consumption.
  1020. This removes the beginning and trailing slashes off the path.
  1021. Arguments:
  1022. CString & strMetaRoot : Metabase path to be cleaned up.
  1023. Return Value:
  1024. Pointer to the metabase path
  1025. --*/
  1026. {
  1027. if (!strMetaRoot.IsEmpty())
  1028. {
  1029. if (strMetaRoot[strMetaRoot.GetLength() - 1] == _chSep)
  1030. {
  1031. strMetaRoot.ReleaseBuffer(strMetaRoot.GetLength() - 1);
  1032. }
  1033. if (!strMetaRoot.IsEmpty() && strMetaRoot[0] == _chSep)
  1034. {
  1035. strMetaRoot = strMetaRoot.Right(strMetaRoot.GetLength() - 1);
  1036. }
  1037. }
  1038. return strMetaRoot;
  1039. }
  1040. CMetabasePath::CMetabasePath(
  1041. IN BOOL fAddBasePath,
  1042. IN LPCTSTR lpszMDPath,
  1043. IN LPCTSTR lpszMDPath2 OPTIONAL,
  1044. IN LPCTSTR lpszMDPath3 OPTIONAL,
  1045. IN LPCTSTR lpszMDPath4 OPTIONAL
  1046. )
  1047. /*++
  1048. Routine Description:
  1049. Constructor.
  1050. Arguments:
  1051. BOOL fAddBasePath : TRUE to prepend base path ("LM")
  1052. FALSE if the path is complete
  1053. LPCTSTR lpszMDPath : Metabase path
  1054. LPCTSTR lpszMDPath2 : Optional child path
  1055. LPCTSTR lpszMDPath3 : Optional child path
  1056. LPCTSTR lpszMDPath4 : Optional child path
  1057. Return Value:
  1058. N/A
  1059. --*/
  1060. : m_strMetaPath()
  1061. {
  1062. ASSERT_READ_PTR(lpszMDPath);
  1063. if (fAddBasePath)
  1064. {
  1065. m_strMetaPath = _cszMachine;
  1066. AppendPath(lpszMDPath);
  1067. }
  1068. else
  1069. {
  1070. m_strMetaPath = lpszMDPath;
  1071. }
  1072. //
  1073. // Add optional path components
  1074. //
  1075. AppendPath(lpszMDPath2);
  1076. AppendPath(lpszMDPath3);
  1077. AppendPath(lpszMDPath4);
  1078. }
  1079. CMetabasePath::CMetabasePath(
  1080. IN LPCTSTR lpszSvc, OPTIONAL
  1081. IN DWORD dwInstance, OPTIONAL
  1082. IN LPCTSTR lpszParentPath, OPTIONAL
  1083. IN LPCTSTR lpszAlias OPTIONAL
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. Constructor. Construct with path components.
  1088. Arguments:
  1089. LPCTSTR lpszSvc : Service (may be NULL or "")
  1090. DWORD dwInstance : Instance number (may be 0 for master)
  1091. LPCTSTR lpszParentPath : Parent path (may be NULL or "")
  1092. LPCTSTR lpszAlias : Alias (may be NULL or "")
  1093. Return Value:
  1094. N/A
  1095. --*/
  1096. : m_strMetaPath()
  1097. {
  1098. BuildMetaPath(lpszSvc, dwInstance, lpszParentPath, lpszAlias);
  1099. }
  1100. void
  1101. CMetabasePath::AppendPath(
  1102. IN LPCTSTR lpszPath
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. Append path to current metabase path
  1107. Arguments:
  1108. LPCTSTR lpszPath : Metabase path
  1109. Return Value:
  1110. None
  1111. --*/
  1112. {
  1113. if (lpszPath && *lpszPath)
  1114. {
  1115. m_strMetaPath += _cszSep;
  1116. m_strMetaPath += lpszPath;
  1117. }
  1118. }
  1119. void
  1120. CMetabasePath::AppendPath(
  1121. IN DWORD dwInstance
  1122. )
  1123. /*++
  1124. Routine Description:
  1125. Append path to current metabase path
  1126. Arguments:
  1127. DWORD dwInstance : Instance path
  1128. Return Value:
  1129. None
  1130. --*/
  1131. {
  1132. if (!IS_MASTER_INSTANCE(dwInstance))
  1133. {
  1134. TCHAR szInstance[] = _T("4000000000");
  1135. _ltot(dwInstance, szInstance, 10);
  1136. m_strMetaPath += _cszSep;
  1137. m_strMetaPath += szInstance;
  1138. }
  1139. }
  1140. void
  1141. CMetabasePath::BuildMetaPath(
  1142. IN LPCTSTR lpszSvc OPTIONAL,
  1143. IN LPCTSTR lpszInstance OPTIONAL,
  1144. IN LPCTSTR lpszParentPath OPTIONAL,
  1145. IN LPCTSTR lpszAlias OPTIONAL
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. Build a complete metapath with the given service name, instance
  1150. number and optional path components.
  1151. Arguments:
  1152. LPCTSTR lpszSvc : Service (may be NULL or "")
  1153. LPCTSTR lpszInstance : Instance (may be NULL or "")
  1154. LPCTSTR lpszParentPath : Parent path (may be NULL or "")
  1155. LPCTSTR lpszAlias : Alias (may be NULL or "")
  1156. Return Value:
  1157. Pointer to internal buffer containing the path.
  1158. --*/
  1159. {
  1160. m_strMetaPath = _cszMachine;
  1161. AppendPath(lpszSvc);
  1162. AppendPath(lpszInstance);
  1163. AppendPath(lpszParentPath);
  1164. if (lpszAlias && *lpszAlias)
  1165. {
  1166. //
  1167. // Special case: If the alias is root, but we're
  1168. // at the master instance, ignore this.
  1169. //
  1170. if (lpszInstance || ::lstrcmpi(_cszRoot, lpszAlias))
  1171. {
  1172. m_strMetaPath += _cszSep;
  1173. m_strMetaPath += lpszAlias;
  1174. }
  1175. }
  1176. }
  1177. void
  1178. CMetabasePath::BuildMetaPath(
  1179. IN LPCTSTR lpszSvc OPTIONAL,
  1180. IN DWORD dwInstance OPTIONAL,
  1181. IN LPCTSTR lpszParentPath OPTIONAL,
  1182. IN LPCTSTR lpszAlias OPTIONAL
  1183. )
  1184. /*++
  1185. Routine Description:
  1186. Build a complete metapath with the given service name, instance
  1187. number and optional path components.
  1188. Arguments:
  1189. LPCTSTR lpszSvc : Service (may be NULL or "")
  1190. DWORD dwInstance : Instance number (may be 0 for master)
  1191. LPCTSTR lpszParentPath : Parent path (may be NULL or "")
  1192. LPCTSTR lpszAlias : Alias (may be NULL or "")
  1193. Return Value:
  1194. Pointer to internal buffer containing the path.
  1195. --*/
  1196. {
  1197. m_strMetaPath = _cszMachine;
  1198. AppendPath(lpszSvc);
  1199. AppendPath(dwInstance);
  1200. AppendPath(lpszParentPath);
  1201. if (lpszAlias && *lpszAlias)
  1202. {
  1203. //
  1204. // Special case: If the alias is root, but we're
  1205. // at the master instance, ignore this.
  1206. //
  1207. if (!IS_MASTER_INSTANCE(dwInstance) || ::lstrcmpi(_cszRoot, lpszAlias))
  1208. {
  1209. m_strMetaPath += _cszSep;
  1210. m_strMetaPath += lpszAlias;
  1211. }
  1212. }
  1213. }
  1214. //
  1215. // CIISInterface class
  1216. //
  1217. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1218. CIISInterface::CIISInterface(
  1219. IN CComAuthInfo * pAuthInfo, OPTIONAL
  1220. IN HRESULT hrInterface OPTIONAL
  1221. )
  1222. /*++
  1223. Routine Description:
  1224. Base class constructor.
  1225. Arguments:
  1226. CComAuthInfo * pAuthInfo : Auth info or NULL for local computer
  1227. HRESULT hrInterface : Initial error code. S_OK by default.
  1228. Return Value:
  1229. N/A
  1230. --*/
  1231. : m_auth(pAuthInfo),
  1232. m_hrInterface(hrInterface)
  1233. {
  1234. }
  1235. HRESULT
  1236. CIISInterface::Create(
  1237. IN int cInterfaces,
  1238. IN const IID rgIID[],
  1239. IN const GUID rgCLSID[],
  1240. OUT int * pnInterface, OPTIONAL
  1241. OUT IUnknown ** ppInterface
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. Create interface. This will try a range of interfaces in order of priority.
  1246. Arguments:
  1247. int cInterfaces : Number of interfaces in array.
  1248. const IID * rgIID : Array if IIDs
  1249. const GUID * rgCLSID : Array of CLSIDs
  1250. int * pnInterface : Returns the interface index that was successful.
  1251. or NULL if not interested.
  1252. IUnknown ** ppInterface : Returns pointer to the interface.
  1253. Return Value:
  1254. HRESULT
  1255. Notes:
  1256. This will attempt to create an interface, in order of declaration in
  1257. the IID and CLSIS arrays. The first successful interface to be created
  1258. will have its index returned in *pnInterfaces.
  1259. --*/
  1260. {
  1261. ASSERT(cInterfaces > 0);
  1262. ASSERT(rgIID && rgCLSID && ppInterface);
  1263. COSERVERINFO * pcsiName = m_auth.CreateServerInfoStruct();
  1264. MULTI_QI rgmqResults;
  1265. CError err;
  1266. int nInterface;
  1267. ZeroMemory(&rgmqResults, sizeof(rgmqResults));
  1268. //
  1269. // Try to create the interface in order
  1270. //
  1271. for (nInterface = 0; nInterface < cInterfaces; ++nInterface)
  1272. {
  1273. rgmqResults.pIID = &rgIID[nInterface];
  1274. err = ::CoCreateInstanceEx(
  1275. rgCLSID[nInterface],
  1276. NULL,
  1277. CLSCTX_SERVER,
  1278. pcsiName,
  1279. 1,
  1280. &rgmqResults
  1281. );
  1282. if (err.Succeeded() || err.Win32Error() == ERROR_ACCESS_DENIED)
  1283. {
  1284. break;
  1285. }
  1286. ZeroMemory(&rgmqResults, sizeof(rgmqResults));
  1287. }
  1288. if(err.Succeeded())
  1289. {
  1290. //
  1291. // Save the interface pointer
  1292. //
  1293. ASSERT_PTR(rgmqResults.pItf);
  1294. *ppInterface = rgmqResults.pItf;
  1295. if (pnInterface)
  1296. {
  1297. //
  1298. // Store successful interface index
  1299. //
  1300. *pnInterface = nInterface;
  1301. }
  1302. //
  1303. // Strangely enough, I now have still have to apply
  1304. // the proxy blanket. Apparently this is by design.
  1305. //
  1306. if (m_auth.UsesImpersonation())
  1307. {
  1308. ApplyProxyBlanket();
  1309. }
  1310. }
  1311. //
  1312. // Clean up
  1313. //
  1314. m_auth.FreeServerInfoStruct(pcsiName);
  1315. return err;
  1316. }
  1317. //
  1318. // CMetaInterface class
  1319. //
  1320. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1321. CMetaInterface::CMetaInterface(
  1322. IN CComAuthInfo * pAuthInfo OPTIONAL
  1323. )
  1324. /*++
  1325. Routine Description:
  1326. Construct and initialize the interface
  1327. Arguments:
  1328. CComAuthInfo * pAuthInfo : Authentication info. NULL indicates
  1329. the local computer.
  1330. Return Value:
  1331. N/A
  1332. --*/
  1333. : CIISInterface(pAuthInfo),
  1334. m_pInterface(NULL),
  1335. m_iTimeOutValue(MB_TIMEOUT)
  1336. {
  1337. //
  1338. // Initialize the interface
  1339. //
  1340. m_hrInterface = Create();
  1341. }
  1342. CMetaInterface::CMetaInterface(
  1343. IN CMetaInterface * pInterface
  1344. )
  1345. /*++
  1346. Routine Description:
  1347. Construct from existing interface (Copy Constructor)
  1348. Arguments:
  1349. CMetaInterface * pInterface : Existing interface
  1350. Return Value:
  1351. N/A
  1352. Notes:
  1353. Object will not take ownership of the interface,
  1354. it will merely add to the reference count, and
  1355. release it upon destruction
  1356. BUGBUG:
  1357. if pInterface is NULL, this will AV.
  1358. --*/
  1359. : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
  1360. m_pInterface(pInterface->m_pInterface),
  1361. m_iTimeOutValue(pInterface->m_iTimeOutValue)
  1362. {
  1363. ASSERT_READ_PTR(m_pInterface);
  1364. m_pInterface->AddRef();
  1365. }
  1366. CMetaInterface::~CMetaInterface()
  1367. /*++
  1368. Routine Description:
  1369. Destructor -- releases the interface
  1370. --*/
  1371. {
  1372. SAFE_RELEASE(m_pInterface);
  1373. }
  1374. HRESULT
  1375. CMetaInterface::CreateSite(
  1376. LPCTSTR service,
  1377. LPCTSTR comment,
  1378. LPCTSTR binding,
  1379. LPCTSTR home_path,
  1380. DWORD * pinst,
  1381. DWORD * pRequestedSiteInst
  1382. )
  1383. {
  1384. CError err;
  1385. BOOL bHonorRequestedSiteId = FALSE;
  1386. CSiteCreator sc(m_pInterface);
  1387. if (pRequestedSiteInst)
  1388. {
  1389. if (*pRequestedSiteInst != 0)
  1390. {
  1391. bHonorRequestedSiteId = TRUE;
  1392. }
  1393. }
  1394. if (bHonorRequestedSiteId)
  1395. {
  1396. err = sc.CreateNewSite2(
  1397. _tcsicmp(service, SZ_MBN_WEB) == 0 ? SC_W3SVC : SC_MSFTPSVC,
  1398. comment, binding, home_path, NULL, pinst, pRequestedSiteInst);
  1399. }
  1400. else
  1401. {
  1402. err = sc.CreateNewSite2(
  1403. _tcsicmp(service, SZ_MBN_WEB) == 0 ? SC_W3SVC : SC_MSFTPSVC,
  1404. comment, binding, home_path, NULL, pinst);
  1405. }
  1406. return err;
  1407. }
  1408. //
  1409. // CMetaKey class
  1410. //
  1411. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1412. //
  1413. // Helper macros
  1414. //
  1415. #define ASSURE_OPEN_KEY()\
  1416. if (!m_hKey && !m_fAllowRootOperations) { ASSERT_MSG("No open key"); return HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE); }
  1417. #define FETCH_PROPERTY_DATA_OR_FAIL(dwID, md)\
  1418. ZeroMemory(&md, sizeof(md)); \
  1419. if (!GetMDFieldDef(dwID, md.dwMDIdentifier, md.dwMDAttributes, md.dwMDUserType, md.dwMDDataType))\
  1420. { ASSERT_MSG("Bad property ID"); return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); }
  1421. //
  1422. // Static Initialization
  1423. //
  1424. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  1425. #define MD_SERVER_PLATFORM (IIS_MD_SERVER_BASE+100 )
  1426. #define MD_SERVER_VERSION_MAJOR (IIS_MD_SERVER_BASE+101 )
  1427. #define MD_SERVER_VERSION_MINOR (IIS_MD_SERVER_BASE+102 )
  1428. #define MD_SERVER_CAPABILITIES (IIS_MD_SERVER_BASE+103 )
  1429. #if 0
  1430. //
  1431. // Metabase table
  1432. //
  1433. const CMetaKey::MDFIELDDEF CMetaKey::s_rgMetaTable[] =
  1434. {
  1435. ///////////////////////////////////////////////////////////////////////////
  1436. //
  1437. // !!!IMPORTANT!!! This table must be sorted on dwMDIdentifier. (Will
  1438. // ASSERT if not not sorted)
  1439. //
  1440. { MD_MAX_BANDWIDTH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1441. { MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1442. { MD_SERVER_COMMAND, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1443. { MD_CONNECTION_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CONNECTION_TIMEOUT },
  1444. { MD_MAX_CONNECTIONS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_CONNECTIONS },
  1445. { MD_SERVER_COMMENT, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_SERVER_COMMENT },
  1446. { MD_SERVER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1447. { MD_SERVER_AUTOSTART, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1448. { MD_SERVER_SIZE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_SIZE },
  1449. { MD_SERVER_LISTEN_BACKLOG, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_BACKLOG },
  1450. { MD_SERVER_LISTEN_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_SERVER_LISTEN_TIMEOUT },
  1451. { MD_DOWNLEVEL_ADMIN_INSTANCE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_DOWNLEVEL_ADMIN_INSTANCE },
  1452. { MD_SERVER_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
  1453. { MD_WIN32_ERROR, METADATA_VOLATILE, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  1454. { MD_SERVER_PLATFORM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1455. { MD_SERVER_VERSION_MAJOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1456. { MD_SERVER_VERSION_MINOR, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1457. { MD_SERVER_CAPABILITIES, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1458. { MD_SECURE_BINDINGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, MULTISZ_METADATA, 0 },
  1459. { MD_FILTER_LOAD_ORDER, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1460. { MD_FILTER_IMAGE_PATH, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1461. { MD_FILTER_STATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1462. { MD_FILTER_ENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1463. { MD_FILTER_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1464. { MD_AUTH_CHANGE_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1465. { MD_AUTH_EXPIRED_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1466. { MD_AUTH_NOTIFY_PWD_EXP_URL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1467. { MD_ADV_NOTIFY_PWD_EXP_IN_DAYS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1468. { MD_ADV_CACHE_TTL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1469. { MD_AUTH_EXPIRED_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1470. { MD_AUTH_CHANGE_FLAGS, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1471. { MD_AUTH_NOTIFY_PWD_EXP_UNSECUREURL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1472. { MD_FRONTPAGE_WEB, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1473. { MD_IN_PROCESS_ISAPI_APPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_IN_PROCESS_ISAPI_APPS },
  1474. { MD_MAPCERT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1475. { MD_MAPNTACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1476. { MD_MAPNAME, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1477. { MD_MAPENABLED, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1478. { MD_MAPREALM, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1479. { MD_MAPPWD, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1480. { MD_ITACCT, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1481. { MD_CPP_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1482. { MD_SERIAL_CERT11, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1483. { MD_CPP_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1484. { MD_SERIAL_CERTW, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1485. { MD_CPP_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1486. { MD_SERIAL_DIGEST, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1487. { MD_CPP_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1488. { MD_SERIAL_ITA, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1489. { MD_FRONTPAGE_WEB, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1490. { MD_APP_FRIENDLY_NAME, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_FRIENDLY_NAME },
  1491. { MD_APP_ROOT, METADATA_INHERIT, IIS_MD_UT_WAM, STRING_METADATA, IDS_MD_APP_ROOT },
  1492. { MD_APP_ISOLATED, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_MD_APP_ISOLATED },
  1493. { MD_CPU_RESET_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_RESET_INTERVAL },
  1494. { MD_HC_COMPRESSION_DIRECTORY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1495. { MD_HC_DO_DYNAMIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1496. { MD_HC_DO_STATIC_COMPRESSION, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1497. { MD_HC_DO_DISK_SPACE_LIMITING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1498. { MD_HC_MAX_DISK_SPACE_USAGE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1499. { MD_VR_PATH, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PATH },
  1500. { MD_VR_USERNAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_USERNAME },
  1501. { MD_VR_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_VR_PASSWORD },
  1502. { MD_VR_ACL, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, BINARY_METADATA, 0 },
  1503. { MD_VR_UPDATE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  1504. { MD_LOG_TYPE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOG_TYPE },
  1505. { MD_LOGFILE_DIRECTORY, METADATA_INHERIT, IIS_MD_UT_FILE, EXPANDSZ_METADATA,IDS_MD_LOGFILE_DIRECTORY },
  1506. { MD_LOGFILE_PERIOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_PERIOD },
  1507. { MD_LOGFILE_TRUNCATE_SIZE, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGFILE_TRUNCATE_SIZE },
  1508. { MD_LOG_PLUGIN_MOD_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_MOD_ID },
  1509. { MD_LOG_PLUGIN_UI_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_UI_ID },
  1510. { MD_LOGSQL_DATA_SOURCES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_DATA_SOURCES },
  1511. { MD_LOGSQL_TABLE_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_TABLE_NAME },
  1512. { MD_LOGSQL_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_USER_NAME },
  1513. { MD_LOGSQL_PASSWORD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_LOGSQL_PASSWORD },
  1514. { MD_LOG_PLUGIN_ORDER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGIN_ORDER },
  1515. { MD_LOG_PLUGINS_AVAILABLE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_LOG_PLUGINS_AVAILABLE },
  1516. { MD_LOGEXT_FIELD_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGEXT_FIELD_MASK },
  1517. { MD_LOGFILE_LOCALTIME_ROLLOVER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGFILE_LOCALTIME_ROLLOVER },
  1518. { MD_LOGCUSTOM_PROPERTY_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGCUSTOM_PROPERTY_ID },
  1519. { MD_LOGCUSTOM_PROPERTY_MASK, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGCUSTOM_PROPERTY_MASK },
  1520. { MD_LOGCUSTOM_SERVICES_STRING, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_LOGCUSTOM_SERVICES_STRING },
  1521. { MD_LOGCUSTOM_PROPERTY_NODE_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOGCUSTOM_PROPERTY_NODE_ID },
  1522. { MD_EXIT_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_EXIT_MESSAGE },
  1523. { MD_GREETING_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_GREETING_MESSAGE },
  1524. { MD_MAX_CLIENTS_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_MAX_CLIENTS_MESSAGE },
  1525. { MD_MSDOS_DIR_OUTPUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MSDOS_DIR_OUTPUT },
  1526. { MD_ALLOW_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ALLOW_ANONYMOUS },
  1527. { MD_ANONYMOUS_ONLY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_ANONYMOUS_ONLY },
  1528. { MD_LOG_ANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_ANONYMOUS },
  1529. { MD_LOG_NONANONYMOUS, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_LOG_NONANONYMOUS },
  1530. { MD_BANNER_MESSAGE, METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_BANNER_MESSAGE },
  1531. { MD_SSL_PUBLIC_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1532. { MD_SSL_PRIVATE_KEY, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1533. { MD_SSL_KEY_PASSWORD, METADATA_SECURE, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1534. { MD_SSL_CERT_HASH, METADATA_INHERIT, IIS_MD_UT_SERVER, BINARY_METADATA, 0 },
  1535. { MD_SSL_CERT_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1536. { MD_SSL_CTL_IDENTIFIER, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1537. { MD_SSL_CTL_STORE_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, 0 },
  1538. { MD_SSL_USE_DS_MAPPER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1539. { MD_AUTHORIZATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_AUTHORIZATION },
  1540. { MD_REALM, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_REALM },
  1541. { MD_HTTP_EXPIRES, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_EXPIRES },
  1542. { MD_HTTP_PICS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_PICS },
  1543. { MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_HTTP_CUSTOM },
  1544. { MD_DIRECTORY_BROWSING, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DIRECTORY_BROWSING },
  1545. { MD_DEFAULT_LOAD_FILE, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOAD_FILE },
  1546. { MD_CONTENT_NEGOTIATION, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CONTENT_NEGOTIATION },
  1547. { MD_CUSTOM_ERROR, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_CUSTOM_ERROR },
  1548. { MD_FOOTER_DOCUMENT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_FOOTER_DOCUMENT },
  1549. { MD_FOOTER_ENABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_FOOTER_ENABLED },
  1550. { MD_HTTP_REDIRECT, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_HTTP_REDIRECT },
  1551. { MD_DEFAULT_LOGON_DOMAIN, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_DEFAULT_LOGON_DOMAIN },
  1552. { MD_LOGON_METHOD, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_LOGON_METHOD },
  1553. { MD_SCRIPT_MAPS, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_SCRIPT_MAPS },
  1554. { MD_MIME_MAP, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, IDS_MD_MIME_MAP },
  1555. { MD_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ACCESS_PERM },
  1556. { MD_IP_SEC, METADATA_INHERIT | METADATA_REFERENCE, IIS_MD_UT_FILE, BINARY_METADATA, IDS_MD_IP_SEC },
  1557. { MD_ANONYMOUS_USER_NAME, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_USER_NAME },
  1558. { MD_ANONYMOUS_PWD, METADATA_INHERIT | METADATA_SECURE, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_ANONYMOUS_PWD },
  1559. { MD_ANONYMOUS_USE_SUBAUTH, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ANONYMOUS_USE_SUBAUTH },
  1560. { MD_DONT_LOG, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_DONT_LOG },
  1561. { MD_ADMIN_ACL, METADATA_INHERIT | METADATA_SECURE | METADATA_REFERENCE,IIS_MD_UT_SERVER, BINARY_METADATA, IDS_MD_ADMIN_ACL },
  1562. { MD_SSI_EXEC_DISABLED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSI_EXEC_DISABLED },
  1563. { MD_SSL_ACCESS_PERM, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SSL_ACCESS_PERM },
  1564. { MD_NTAUTHENTICATION_PROVIDERS, METADATA_INHERIT, IIS_MD_UT_FILE, STRING_METADATA, IDS_MD_NTAUTHENTICATION_PROVIDERS },
  1565. { MD_SCRIPT_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_SCRIPT_TIMEOUT },
  1566. { MD_CACHE_EXTENSIONS, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_CACHE_EXTENSIONS },
  1567. { MD_CREATE_PROCESS_AS_USER, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROCESS_AS_USER },
  1568. { MD_CREATE_PROC_NEW_CONSOLE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CREATE_PROC_NEW_CONSOLE },
  1569. { MD_POOL_IDC_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_POOL_IDC_TIMEOUT },
  1570. { MD_ALLOW_KEEPALIVES, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_ALLOW_KEEPALIVES },
  1571. { MD_IS_CONTENT_INDEXED, METADATA_INHERIT, IIS_MD_UT_FILE, DWORD_METADATA, IDS_MD_IS_CONTENT_INDEXED },
  1572. { MD_ISM_ACCESS_CHECK, METADATA_NO_ATTRIBUTES, IIS_MD_UT_FILE, DWORD_METADATA, 0 },
  1573. { MD_ASP_BUFFERINGON, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_BUFFERINGON },
  1574. { MD_ASP_LOGERRORREQUESTS, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_LOGERRORREQUESTS },
  1575. { MD_ASP_SCRIPTERRORSSENTTOBROWSER, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTERRORSSENTTOBROWSER },
  1576. { MD_ASP_SCRIPTERRORMESSAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTERRORMESSAGE },
  1577. { MD_ASP_SCRIPTFILECACHESIZE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTFILECACHESIZE },
  1578. { MD_ASP_SCRIPTENGINECACHEMAX, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_SCRIPTENGINECACHEMAX },
  1579. { MD_ASP_SCRIPTTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SCRIPTTIMEOUT },
  1580. { MD_ASP_SESSIONTIMEOUT, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_SESSIONTIMEOUT },
  1581. { MD_ASP_ENABLEPARENTPATHS, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLEPARENTPATHS },
  1582. { MD_ASP_ALLOWSESSIONSTATE, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ALLOWSESSIONSTATE },
  1583. { MD_ASP_SCRIPTLANGUAGE, METADATA_INHERIT, ASP_MD_UT_APP, STRING_METADATA, IDS_ASP_SCRIPTLANGUAGE },
  1584. { MD_ASP_EXCEPTIONCATCHENABLE, METADATA_INHERIT, IIS_MD_UT_WAM, DWORD_METADATA, IDS_ASP_EXCEPTIONCATCHENABLE },
  1585. { MD_ASP_ENABLESERVERDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLESERVERDEBUG },
  1586. { MD_ASP_ENABLECLIENTDEBUG, METADATA_INHERIT, ASP_MD_UT_APP, DWORD_METADATA, IDS_ASP_ENABLECLIENTDEBUG },
  1587. { MD_WAM_USER_NAME, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_WAM_USER_NAME },
  1588. { MD_WAM_PWD, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_WAM_PWD },
  1589. //
  1590. // IIS6 Application Pools
  1591. //
  1592. { MD_APPPOOL_PERIODIC_RESTART_TIME, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_TIME },
  1593. { MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT,
  1594. METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_REQUEST_COUNT },
  1595. { MD_APPPOOL_MAX_PROCESS_COUNT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_MAX_PROCESS_COUNT },
  1596. { MD_APPPOOL_PINGING_ENABLED, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PINGING_ENABLED },
  1597. { MD_APPPOOL_IDLE_TIMEOUT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_IDLE_TIMEOUT },
  1598. { MD_APPPOOL_RAPID_FAIL_PROTECTION_ENABLED,
  1599. METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_RAPID_FAIL_PROTECTION_ENABLED },
  1600. { MD_APPPOOL_ORPHAN_PROCESSES_FOR_DEBUGGING,
  1601. METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_ORPHAN_PROCESSES_FOR_DEBUGGING },
  1602. { MD_APPPOOL_STARTUP_TIMELIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_STARTUP_TIMELIMIT },
  1603. { MD_APPPOOL_SHUTDOWN_TIMELIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_SHUTDOWN_TIMELIMIT },
  1604. { MD_APPPOOL_PING_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PING_INTERVAL },
  1605. { MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH,
  1606. METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_UL_APPPOOL_QUEUE_LENGTH },
  1607. { MD_APPPOOL_PERIODIC_RESTART_SCHEDULE,
  1608. METADATA_INHERIT, IIS_MD_UT_SERVER, MULTISZ_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_SCHEDULE },
  1609. { MD_APPPOOL_IDENTITY_TYPE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_IDENTITY_TYPE },
  1610. { MD_CPU_ACTION, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_ACTION },
  1611. { MD_CPU_LIMIT, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_CPU_LIMIT },
  1612. { MD_APPPOOL_PERIODIC_RESTART_MEMORY, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_PERIODIC_RESTART_MEMORY },
  1613. { MD_APPPOOL_COMMAND, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_COMMAND },
  1614. { MD_APPPOOL_STATE, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_APPPOOL_STATE },
  1615. { MD_RAPID_FAIL_PROTECTION_INTERVAL, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_RAPID_FAIL_PROTECTION_INTERVAL},
  1616. { MD_RAPID_FAIL_PROTECTION_MAX_CRASHES,
  1617. METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_RAPID_FAIL_PROTECTION_MAX_CRASHES},
  1618. { MD_APPPOOL_ORPHAN_ACTION_EXE, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_APPPOOL_ORPHAN_ACTION_EXE },
  1619. { MD_APPPOOL_ORPHAN_ACTION_PARAMS, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_APPPOOL_ORPHAN_ACTION_PARAMS},
  1620. { MD_APP_APPPOOL_ID, METADATA_INHERIT, IIS_MD_UT_SERVER, STRING_METADATA, IDS_MD_APP_APPPOOL_ID },
  1621. // Global parameters
  1622. { MD_MAX_GLOBAL_BANDWIDTH, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_MAX_GLOBAL_BANDWIDTH },
  1623. { MD_GLOBAL_STANDARD_APP_MODE_ENABLED,METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_GLOBAL_STANDARD_APP_MODE_ENABLED },
  1624. { MD_GLOBAL_LOG_IN_UTF_8, METADATA_INHERIT, IIS_MD_UT_SERVER, DWORD_METADATA, IDS_MD_GLOBAL_LOG_IN_UTF_8 },
  1625. { MD_ROOT_ENABLE_EDIT_WHILE_RUNNING, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, DWORD_METADATA, 0 },
  1626. };
  1627. #endif
  1628. /* static */
  1629. int
  1630. CMetaKey::MapMDIDToTableIndex(
  1631. IN DWORD dwID
  1632. )
  1633. /*++
  1634. Routine Description:
  1635. Map MD id value to table index. Return -1 if not found
  1636. Arguments:
  1637. DWORD dwID : MD id value
  1638. Return Value:
  1639. Index into the table that coresponds to the MD id value
  1640. --*/
  1641. {
  1642. #if defined(_DEBUG) //|| DBG
  1643. {
  1644. //
  1645. // Do a quick verification that our metadata
  1646. // table is sorted correctly.
  1647. //
  1648. static BOOL fTableChecked = FALSE;
  1649. if (!fTableChecked)
  1650. {
  1651. for (int n = 1; n < s_MetaTableSize; ++n)
  1652. {
  1653. if (s_rgMetaTable[n].dwMDIdentifier
  1654. <= s_rgMetaTable[n - 1].dwMDIdentifier)
  1655. {
  1656. TRACEEOLID("MD ID Table is out of order: Item is "
  1657. << n
  1658. << " "
  1659. << s_rgMetaTable[n].dwMDIdentifier
  1660. );
  1661. ASSERT_MSG("MD ID Table out of order");
  1662. }
  1663. }
  1664. //
  1665. // But only once.
  1666. //
  1667. ++fTableChecked;
  1668. }
  1669. }
  1670. #endif // _DEBUG
  1671. //
  1672. // Look up the ID in the table using a binary search
  1673. //
  1674. int nRange = s_MetaTableSize;
  1675. int nLow = 0;
  1676. int nHigh = nRange - 1;
  1677. int nMid;
  1678. int nHalf;
  1679. while (nLow <= nHigh)
  1680. {
  1681. if (0 != (nHalf = nRange / 2))
  1682. {
  1683. nMid = nLow + (nRange & 1 ? nHalf : (nHalf - 1));
  1684. if (s_rgMetaTable[nMid].dwMDIdentifier == dwID)
  1685. {
  1686. return nMid;
  1687. }
  1688. else if (s_rgMetaTable[nMid].dwMDIdentifier > dwID)
  1689. {
  1690. nHigh = --nMid;
  1691. nRange = nRange & 1 ? nHalf : nHalf - 1;
  1692. }
  1693. else
  1694. {
  1695. nLow = ++nMid;
  1696. nRange = nHalf;
  1697. }
  1698. }
  1699. else if (nRange)
  1700. {
  1701. return s_rgMetaTable[nLow].dwMDIdentifier == dwID ? nLow : -1;
  1702. }
  1703. else
  1704. {
  1705. break;
  1706. }
  1707. }
  1708. return -1;
  1709. }
  1710. static CMap<DWORD, DWORD, CMetaKey::MDFIELDDEF *, CMetaKey::MDFIELDDEF *&> g_metaid_map;
  1711. const CMetaKey::MDFIELDDEF *
  1712. CMetaKey::GetMetaProp(DWORD id)
  1713. {
  1714. MDFIELDDEF * p = NULL;
  1715. if (g_metaid_map.GetCount() == 0)
  1716. {
  1717. for (int i = 0; i < s_MetaTableSize; i++)
  1718. {
  1719. DWORD id2 = CMetaKey::s_rgMetaTable[i].dwMDIdentifier;
  1720. MDFIELDDEF * pt = (MDFIELDDEF *)&CMetaKey::s_rgMetaTable[i];
  1721. g_metaid_map.SetAt(id2, pt);
  1722. }
  1723. ASSERT(g_metaid_map.GetCount() > 0);
  1724. }
  1725. VERIFY(g_metaid_map.Lookup(id, p));
  1726. return (const CMetaKey::MDFIELDDEF *)p;
  1727. }
  1728. /* static */
  1729. BOOL
  1730. CMetaKey::GetMDFieldDef(
  1731. IN DWORD dwID,
  1732. OUT DWORD & dwMDIdentifier,
  1733. OUT DWORD & dwMDAttributes,
  1734. OUT DWORD & dwMDUserType,
  1735. OUT DWORD & dwMDDataType
  1736. )
  1737. /*++
  1738. Routine Description:
  1739. Get information about metabase property
  1740. Arguments:
  1741. DWORD dwID : Meta ID
  1742. DWORD & dwMDIdentifier : Meta parms
  1743. DWORD & dwMDAttributes : Meta parms
  1744. DWORD & dwMDUserType : Meta parms
  1745. DWORD & dwMDDataType : Meta parms
  1746. Return Value:
  1747. TRUE for success, FALSE for failure.
  1748. --*/
  1749. {
  1750. #if 0
  1751. int nID = MapMDIDToTableIndex(dwID);
  1752. if (nID == -1)
  1753. {
  1754. //
  1755. // Unrecognized meta data ID
  1756. //
  1757. ASSERT_MSG("Unrecognized meta data id");
  1758. return FALSE;
  1759. }
  1760. dwMDIdentifier = s_rgMetaTable[nID].dwMDIdentifier;
  1761. dwMDAttributes = s_rgMetaTable[nID].dwMDAttributes;
  1762. dwMDUserType = s_rgMetaTable[nID].dwMDUserType;
  1763. dwMDDataType = s_rgMetaTable[nID].dwMDDataType;
  1764. return TRUE;
  1765. #endif
  1766. const MDFIELDDEF * p = GetMetaProp(dwID);
  1767. if (p != NULL)
  1768. {
  1769. dwMDIdentifier = p->dwMDIdentifier;
  1770. dwMDAttributes = p->dwMDAttributes;
  1771. dwMDUserType = p->dwMDUserType;
  1772. dwMDDataType = p->dwMDDataType;
  1773. return TRUE;
  1774. }
  1775. return FALSE;
  1776. }
  1777. /* static */
  1778. BOOL
  1779. CMetaKey::IsPropertyInheritable(
  1780. IN DWORD dwID
  1781. )
  1782. /*++
  1783. Routine Description:
  1784. Check to see if the given property is inheritable
  1785. Arguments:
  1786. DWORD dwID : Metabase ID
  1787. Return Value:
  1788. TRUE if the metabase ID is inheritable, FALSE otherwise.
  1789. --*/
  1790. {
  1791. const MDFIELDDEF * p = GetMetaProp(dwID);
  1792. if (p == NULL)
  1793. {
  1794. ASSERT_MSG("Unrecognized meta data ID");
  1795. return FALSE;
  1796. }
  1797. return (p->dwMDAttributes & METADATA_INHERIT) != 0;
  1798. #if 0
  1799. int nID = MapMDIDToTableIndex(dwID);
  1800. if (nID == -1)
  1801. {
  1802. //
  1803. // Unrecognized meta data ID
  1804. //
  1805. ASSERT_MSG("Unrecognized meta data ID");
  1806. return FALSE;
  1807. }
  1808. return (s_rgMetaTable[nID].dwMDAttributes & METADATA_INHERIT) != 0;
  1809. #endif
  1810. }
  1811. /* static */
  1812. BOOL
  1813. CMetaKey::GetPropertyDescription(
  1814. IN DWORD dwID,
  1815. OUT CString & strName
  1816. )
  1817. /*++
  1818. Routine Description:
  1819. Get a description for the given property
  1820. Arguments:
  1821. DWORD dwID : Property ID
  1822. CString & strName : Returns friendly property name
  1823. Return Value:
  1824. TRUE for success, FALSE for failure
  1825. --*/
  1826. {
  1827. const MDFIELDDEF * p = GetMetaProp(dwID);
  1828. if (p == NULL)
  1829. {
  1830. ASSERT_MSG("Unrecognized meta data ID");
  1831. return FALSE;
  1832. }
  1833. UINT uID = p->uStringID;
  1834. #if 0
  1835. int nID = MapMDIDToTableIndex(dwID);
  1836. if (nID == -1)
  1837. {
  1838. //
  1839. // Unrecognized meta data ID
  1840. //
  1841. ASSERT_MSG("Unrecognized meta data ID");
  1842. return FALSE;
  1843. }
  1844. UINT uID = s_rgMetaTable[nID].uStringID;
  1845. #endif
  1846. BOOL fResult = TRUE;
  1847. if (uID > 0)
  1848. {
  1849. fResult = (strName.LoadString(uID) != 0);
  1850. ASSERT(fResult);
  1851. }
  1852. else
  1853. {
  1854. //
  1855. // Don't have a friendly name -- fake it
  1856. //
  1857. CComBSTR bstrFmt;
  1858. VERIFY(bstrFmt.LoadString(hDLLInstance, IDS_INHERITANCE_NO_NAME));
  1859. strName.Format(bstrFmt, dwID);
  1860. }
  1861. return fResult;
  1862. }
  1863. CMetaKey::CMetaKey(
  1864. IN CComAuthInfo * pAuthInfo OPTIONAL
  1865. )
  1866. /*++
  1867. Routine Description:
  1868. Constructor that creates the interface, but does not open the key.
  1869. This is the ONLY constructor that allows operations from
  1870. METDATA_MASTER_ROOT_HANDLE (read operations obviously)
  1871. Arguments:
  1872. CComAuthInfo * pAuthInfo : If NULL, opens interface on local machine
  1873. Return Value:
  1874. N/A
  1875. --*/
  1876. : CMetaInterface(pAuthInfo),
  1877. m_hKey(METADATA_MASTER_ROOT_HANDLE),
  1878. m_hBase(NULL),
  1879. m_hrKey(S_OK),
  1880. m_dwFlags(0L),
  1881. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1882. m_strMetaPath(),
  1883. m_fAllowRootOperations(TRUE),
  1884. m_fOwnKey(TRUE)
  1885. {
  1886. m_hrKey = CMetaInterface::QueryResult();
  1887. //
  1888. // Do not open key
  1889. //
  1890. }
  1891. CMetaKey::CMetaKey(
  1892. IN CMetaInterface * pInterface
  1893. )
  1894. /*++
  1895. Routine Description:
  1896. Construct with pre-existing interface. Does not
  1897. open any keys
  1898. Arguments:
  1899. CMetaInterface * pInterface : Preexisting interface
  1900. Return Value:
  1901. N/A
  1902. --*/
  1903. : CMetaInterface(pInterface),
  1904. m_hKey(NULL),
  1905. m_hBase(NULL),
  1906. m_strMetaPath(),
  1907. m_dwFlags(0L),
  1908. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1909. m_fAllowRootOperations(TRUE),
  1910. m_fOwnKey(TRUE)
  1911. {
  1912. m_hrKey = CMetaInterface::QueryResult();
  1913. }
  1914. CMetaKey::CMetaKey(
  1915. IN CComAuthInfo * pAuthInfo, OPTIONAL
  1916. IN LPCTSTR lpszMDPath, OPTIONAL
  1917. IN DWORD dwFlags,
  1918. IN METADATA_HANDLE hkBase
  1919. )
  1920. /*++
  1921. Routine Description:
  1922. Fully defined constructor that opens a key
  1923. Arguments:
  1924. CComAuthInfo * pAuthInfo : Auth info or NULL
  1925. LPCTSTR lpszMDPath : Path or NULL
  1926. DWORD dwFlags : Open permissions
  1927. METADATA_HANDLE hkBase : Base key
  1928. Return Value:
  1929. N/A
  1930. --*/
  1931. : CMetaInterface(pAuthInfo),
  1932. m_hKey(NULL),
  1933. m_hBase(NULL),
  1934. m_dwFlags(0L),
  1935. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1936. m_fAllowRootOperations(FALSE),
  1937. m_strMetaPath(),
  1938. m_fOwnKey(TRUE)
  1939. {
  1940. m_hrKey = CMetaInterface::QueryResult();
  1941. if (SUCCEEDED(m_hrKey))
  1942. {
  1943. m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
  1944. }
  1945. }
  1946. CMetaKey::CMetaKey(
  1947. IN CMetaInterface * pInterface,
  1948. IN LPCTSTR lpszMDPath, OPTIONAL
  1949. IN DWORD dwFlags,
  1950. IN METADATA_HANDLE hkBase
  1951. )
  1952. /*++
  1953. Routine Description:
  1954. Fully defined constructor that opens a key
  1955. Arguments:
  1956. CMetaInterface * pInterface : Existing interface
  1957. DWORD dwFlags : Open permissions
  1958. METADATA_HANDLE hkBase : Base key
  1959. LPCTSTR lpszMDPath : Path or NULL
  1960. Return Value:
  1961. N/A
  1962. --*/
  1963. : CMetaInterface(pInterface),
  1964. m_hKey(NULL),
  1965. m_hBase(NULL),
  1966. m_strMetaPath(),
  1967. m_dwFlags(0L),
  1968. m_cbInitialBufferSize(MB_INIT_BUFF_SIZE),
  1969. m_fAllowRootOperations(FALSE),
  1970. m_fOwnKey(TRUE)
  1971. {
  1972. m_hrKey = CMetaInterface::QueryResult();
  1973. if (SUCCEEDED(m_hrKey))
  1974. {
  1975. m_hrKey = Open(dwFlags, lpszMDPath, hkBase);
  1976. }
  1977. }
  1978. CMetaKey::CMetaKey(
  1979. IN BOOL fOwnKey,
  1980. IN CMetaKey * pKey
  1981. )
  1982. /*++
  1983. Routine Description:
  1984. Copy constructor.
  1985. Arguments:
  1986. BOOL fOwnKey : TRUE to take ownership of the key
  1987. const CMetaKey * pKey : Existing key
  1988. Return Value:
  1989. N/A
  1990. --*/
  1991. : CMetaInterface(pKey),
  1992. m_hKey(pKey->m_hKey),
  1993. m_hBase(pKey->m_hBase),
  1994. m_dwFlags(pKey->m_dwFlags),
  1995. m_cbInitialBufferSize(pKey->m_cbInitialBufferSize),
  1996. m_fAllowRootOperations(pKey->m_fAllowRootOperations),
  1997. m_hrKey(pKey->m_hrKey),
  1998. m_strMetaPath(pKey->m_strMetaPath),
  1999. m_fOwnKey(fOwnKey)
  2000. {
  2001. //
  2002. // No provisions for anything else at the moment
  2003. //
  2004. ASSERT(!m_fOwnKey);
  2005. }
  2006. CMetaKey::~CMetaKey()
  2007. /*++
  2008. Routine Description:
  2009. Destructor -- Close the key.
  2010. Arguments:
  2011. N/A
  2012. Return Value:
  2013. N/A
  2014. --*/
  2015. {
  2016. if (IsOpen() && m_fOwnKey)
  2017. {
  2018. Close();
  2019. }
  2020. }
  2021. /* virtual */
  2022. BOOL
  2023. CMetaKey::Succeeded() const
  2024. /*++
  2025. Routine Description:
  2026. Determine if object was constructed successfully
  2027. Arguments:
  2028. None
  2029. Return Value:
  2030. TRUE for success, FALSE for failure
  2031. --*/
  2032. {
  2033. return SUCCEEDED(m_hrKey);
  2034. }
  2035. /* virtual */
  2036. HRESULT
  2037. CMetaKey::QueryResult() const
  2038. /*++
  2039. Routine Description:
  2040. Return the construction error for this object
  2041. Arguments:
  2042. None
  2043. Return Value:
  2044. HRESULT from construction errors
  2045. --*/
  2046. {
  2047. return m_hrKey;
  2048. }
  2049. HRESULT
  2050. CMetaKey::Open(
  2051. IN DWORD dwFlags,
  2052. IN LPCTSTR lpszMDPath, OPTIONAL
  2053. IN METADATA_HANDLE hkBase
  2054. )
  2055. /*++
  2056. Routine Description:
  2057. Attempt to open a metabase key
  2058. Arguments:
  2059. DWORD dwFlags : Permission flags
  2060. LPCTSTR lpszMDPath : Optional path
  2061. METADATA_HANDLE hkBase : Base metabase key
  2062. Return Value:
  2063. HRESULT
  2064. --*/
  2065. {
  2066. ASSURE_PROPER_INTERFACE();
  2067. if (m_hKey != NULL)
  2068. {
  2069. // ASSERT_MSG("Attempting to open key that already has an open handle");
  2070. Close();
  2071. }
  2072. //
  2073. // Base key is stored for reopen purposes only
  2074. //
  2075. m_hBase = hkBase;
  2076. m_strMetaPath = lpszMDPath;
  2077. m_dwFlags = dwFlags;
  2078. return OpenKey(m_hBase, m_strMetaPath, m_dwFlags, &m_hKey);
  2079. }
  2080. HRESULT
  2081. CMetaKey::CreatePathFromFailedOpen()
  2082. /*++
  2083. Routine Description:
  2084. If the path doesn't exist, create it. This method should be
  2085. called after an Open call failed (because it will have initialized
  2086. m_strMetaPath.
  2087. Arguments:
  2088. None
  2089. Return Value:
  2090. HRESULT
  2091. --*/
  2092. {
  2093. CString strParentPath;
  2094. CString strObjectName;
  2095. CString strSavePath(m_strMetaPath);
  2096. CMetabasePath::SplitMetaPathAtInstance(
  2097. m_strMetaPath,
  2098. strParentPath,
  2099. strObjectName
  2100. );
  2101. CError err(Open(
  2102. METADATA_PERMISSION_WRITE,
  2103. strParentPath
  2104. ));
  2105. if (err.Succeeded())
  2106. {
  2107. //
  2108. // This really should never fail, because we're opening
  2109. // the path at the instance.
  2110. //
  2111. err = AddKey(strObjectName);
  2112. }
  2113. if (IsOpen())
  2114. {
  2115. Close();
  2116. }
  2117. //
  2118. // The previous open wiped out the path...
  2119. //
  2120. m_strMetaPath = strSavePath;
  2121. return err;
  2122. }
  2123. HRESULT
  2124. CMetaKey::Close()
  2125. /*++
  2126. Routine Description:
  2127. Close the currently open key.
  2128. Arguments:
  2129. N/A
  2130. Return Value:
  2131. N/A
  2132. --*/
  2133. {
  2134. ASSURE_PROPER_INTERFACE();
  2135. HRESULT hr = S_OK;
  2136. ASSERT(m_hKey != NULL);
  2137. ASSERT(m_fOwnKey);
  2138. if (m_hKey)
  2139. {
  2140. hr = CloseKey(m_hKey);
  2141. if (SUCCEEDED(hr))
  2142. {
  2143. m_hKey = NULL;
  2144. }
  2145. }
  2146. return hr;
  2147. }
  2148. HRESULT
  2149. CMetaKey::ConvertToParentPath(
  2150. IN BOOL fImmediate
  2151. )
  2152. /*++
  2153. Routine Description:
  2154. Change the path to the parent path.
  2155. Arguments:
  2156. BOOL fImmediate : If TRUE, the immediate parent's path will be used
  2157. if FALSE, the first parent that really exists
  2158. Return Value:
  2159. HRESULT
  2160. ERROR_INVALID_PARAMETER if there is no valid path
  2161. --*/
  2162. {
  2163. BOOL fIsOpen = IsOpen();
  2164. if (fIsOpen)
  2165. {
  2166. Close();
  2167. }
  2168. CError err;
  2169. FOREVER
  2170. {
  2171. if (!CMetabasePath::ConvertToParentPath(m_strMetaPath))
  2172. {
  2173. //
  2174. // There is no parent path
  2175. //
  2176. err = ERROR_INVALID_PARAMETER;
  2177. break;
  2178. }
  2179. err = ReOpen();
  2180. //
  2181. // Path not found is the only valid error
  2182. // other than success.
  2183. //
  2184. if (fImmediate
  2185. || err.Succeeded()
  2186. || err.Win32Error() != ERROR_PATH_NOT_FOUND)
  2187. {
  2188. break;
  2189. }
  2190. }
  2191. //
  2192. // Remember to reset the construction error
  2193. // which referred to the parent path.
  2194. //
  2195. m_hrKey = err;
  2196. return err;
  2197. }
  2198. /* protected */
  2199. HRESULT
  2200. CMetaKey::GetPropertyValue(
  2201. IN DWORD dwID,
  2202. OUT IN DWORD & dwSize, OPTIONAL
  2203. OUT IN void *& pvData, OPTIONAL
  2204. OUT IN DWORD * pdwDataType, OPTIONAL
  2205. IN BOOL * pfInheritanceOverride, OPTIONAL
  2206. IN LPCTSTR lpszMDPath, OPTIONAL
  2207. OUT DWORD * pdwAttributes OPTIONAL
  2208. )
  2209. /*++
  2210. Routine Description:
  2211. Get metadata on the currently open key.
  2212. Arguments:
  2213. DWORD dwID : Property ID number
  2214. DWORD & dwSize : Buffer size (could be 0)
  2215. void *& pvData : Buffer -- will allocate if NULL
  2216. DWORD * pdwDataType : NULL or on in contains valid data types,
  2217. : on out contains actual data type
  2218. BOOL * pfInheritanceOverride : NULL or on forces inheritance on/off
  2219. LPCTSTR lpszMDPath : Optional path off the open key
  2220. DWORD * pdwAttributes : Optionally returns attributes
  2221. Return Value:
  2222. HRESULT
  2223. ERROR_INVALID_HANDLE : If the handle is not open
  2224. ERROR_INVALID_PARAMETER : If the property id is not found,
  2225. or the data type doesn't match requested type
  2226. ERROR_OUTOFMEMORY : Out of memory
  2227. --*/
  2228. {
  2229. ASSURE_PROPER_INTERFACE();
  2230. ASSURE_OPEN_KEY();
  2231. METADATA_RECORD mdRecord;
  2232. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2233. //
  2234. // If unable to find this property ID in our table, or
  2235. // if we specified a desired type, and this type doesn't
  2236. // match it, give up.
  2237. //
  2238. if (pdwDataType && *pdwDataType != ALL_METADATA
  2239. && *pdwDataType != mdRecord.dwMDDataType)
  2240. {
  2241. ASSERT_MSG("Invalid parameter");
  2242. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2243. }
  2244. //
  2245. // Check to see if inheritance behaviour is overridden
  2246. //
  2247. if (pfInheritanceOverride)
  2248. {
  2249. if (*pfInheritanceOverride)
  2250. {
  2251. mdRecord.dwMDAttributes |= METADATA_INHERIT;
  2252. }
  2253. else
  2254. {
  2255. mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
  2256. }
  2257. }
  2258. //
  2259. // This causes a bad parameter error on input otherwise
  2260. //
  2261. mdRecord.dwMDAttributes &= ~METADATA_REFERENCE;
  2262. //
  2263. // If we're looking for inheritable properties, the path
  2264. // doesn't have to be completely specified.
  2265. //
  2266. if (mdRecord.dwMDAttributes & METADATA_INHERIT)
  2267. {
  2268. mdRecord.dwMDAttributes |= (METADATA_PARTIAL_PATH | METADATA_ISINHERITED);
  2269. }
  2270. ASSERT(dwSize > 0 || pvData == NULL);
  2271. mdRecord.dwMDDataLen = dwSize;
  2272. mdRecord.pbMDData = (LPBYTE)pvData;
  2273. //
  2274. // If no buffer provided, allocate one.
  2275. //
  2276. HRESULT hr = S_OK;
  2277. BOOL fBufferTooSmall = FALSE;
  2278. BOOL fAllocatedMemory = FALSE;
  2279. DWORD dwInitSize = m_cbInitialBufferSize;
  2280. do
  2281. {
  2282. if(mdRecord.pbMDData == NULL)
  2283. {
  2284. mdRecord.dwMDDataLen = dwInitSize;
  2285. mdRecord.pbMDData = (LPBYTE)AllocMem(dwInitSize);
  2286. if(mdRecord.pbMDData == NULL && dwInitSize > 0)
  2287. {
  2288. hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  2289. break;
  2290. }
  2291. ++fAllocatedMemory;
  2292. }
  2293. //
  2294. // Get the data
  2295. //
  2296. DWORD dwRequiredDataLen = 0;
  2297. hr = GetData(m_hKey, lpszMDPath, &mdRecord, &dwRequiredDataLen);
  2298. //
  2299. // Re-fetch the buffer if it's too small.
  2300. //
  2301. fBufferTooSmall =
  2302. (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) && fAllocatedMemory;
  2303. if(fBufferTooSmall)
  2304. {
  2305. //
  2306. // Delete the old buffer, and set up for a re-fetch.
  2307. //
  2308. FreeMem(mdRecord.pbMDData);
  2309. mdRecord.pbMDData = NULL;
  2310. dwInitSize = dwRequiredDataLen;
  2311. }
  2312. }
  2313. while(fBufferTooSmall);
  2314. //
  2315. // Failed
  2316. //
  2317. if(FAILED(hr) && fAllocatedMemory)
  2318. {
  2319. FreeMem(mdRecord.pbMDData);
  2320. mdRecord.pbMDData = NULL;
  2321. }
  2322. dwSize = mdRecord.dwMDDataLen;
  2323. pvData = mdRecord.pbMDData;
  2324. if (pdwDataType != NULL)
  2325. {
  2326. //
  2327. // Return actual data type
  2328. //
  2329. *pdwDataType = mdRecord.dwMDDataType;
  2330. }
  2331. if (pdwAttributes != NULL)
  2332. {
  2333. //
  2334. // Return data attributes
  2335. //
  2336. *pdwAttributes = mdRecord.dwMDAttributes;
  2337. }
  2338. return hr;
  2339. }
  2340. /* protected */
  2341. HRESULT
  2342. CMetaKey::GetDataPaths(
  2343. OUT CStringListEx & strlDataPaths,
  2344. IN DWORD dwMDIdentifier,
  2345. IN DWORD dwMDDataType,
  2346. IN LPCTSTR lpszMDPath OPTIONAL
  2347. )
  2348. /*++
  2349. Routine Description:
  2350. Get data paths
  2351. Arguments:
  2352. Return Value:
  2353. HRESULT
  2354. --*/
  2355. {
  2356. ASSURE_PROPER_INTERFACE();
  2357. ASSURE_OPEN_KEY();
  2358. //
  2359. // Start with a small buffer
  2360. //
  2361. DWORD dwMDBufferSize = 1024;
  2362. LPTSTR lpszBuffer = NULL;
  2363. CError err;
  2364. do
  2365. {
  2366. if (lpszBuffer != NULL)
  2367. {
  2368. FreeMem(lpszBuffer);
  2369. }
  2370. lpszBuffer = AllocTString(dwMDBufferSize);
  2371. if (lpszBuffer == NULL)
  2372. {
  2373. err = ERROR_NOT_ENOUGH_MEMORY;
  2374. break;
  2375. }
  2376. err = CMetaInterface::GetDataPaths(
  2377. m_hKey,
  2378. lpszMDPath,
  2379. dwMDIdentifier,
  2380. dwMDDataType,
  2381. dwMDBufferSize,
  2382. lpszBuffer,
  2383. &dwMDBufferSize
  2384. );
  2385. }
  2386. while(err.Win32Error() == ERROR_INSUFFICIENT_BUFFER);
  2387. if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
  2388. {
  2389. //
  2390. // That's ok... this is some sort of physical directory
  2391. // that doesn't currently exist in the metabase, and
  2392. // which therefore doesn't have any descendants anyway.
  2393. //
  2394. ZeroMemory(lpszBuffer, dwMDBufferSize);
  2395. err.Reset();
  2396. }
  2397. if (err.Succeeded())
  2398. {
  2399. ConvertDoubleNullListToStringList(lpszBuffer, strlDataPaths);
  2400. FreeMem(lpszBuffer);
  2401. }
  2402. return err;
  2403. }
  2404. HRESULT
  2405. CMetaKey::CheckDescendants(
  2406. IN DWORD dwID,
  2407. IN CComAuthInfo * pAuthInfo, OPTIONAL
  2408. IN LPCTSTR lpszMDPath OPTIONAL
  2409. )
  2410. /*++
  2411. Routine Description:
  2412. Check for descendant overrides; If there are any, bring up a dialog
  2413. that displays them, and give the user the opportunity the remove
  2414. the overrides.
  2415. Arguments:
  2416. DWORD dwID : Property ID
  2417. CComAuthInfo * pAuthInfo : Server or NULL
  2418. LPCTSTR lpszMDPath : Metabase path or NULL
  2419. Return Value:
  2420. HRESULT
  2421. --*/
  2422. {
  2423. ASSURE_PROPER_INTERFACE();
  2424. HRESULT hr = S_OK;
  2425. METADATA_RECORD mdRecord;
  2426. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2427. if (mdRecord.dwMDAttributes & METADATA_INHERIT)
  2428. {
  2429. CStringListEx strlDataPaths;
  2430. hr = GetDataPaths(
  2431. strlDataPaths,
  2432. mdRecord.dwMDIdentifier,
  2433. mdRecord.dwMDDataType,
  2434. lpszMDPath
  2435. );
  2436. if (SUCCEEDED(hr) && !strlDataPaths.IsEmpty())
  2437. {
  2438. //
  2439. // Bring up the inheritance override dialog
  2440. //
  2441. CInheritanceDlg dlg(
  2442. dwID,
  2443. FROM_WRITE_PROPERTY,
  2444. pAuthInfo,
  2445. lpszMDPath,
  2446. strlDataPaths
  2447. );
  2448. if (!dlg.IsEmpty())
  2449. {
  2450. dlg.DoModal();
  2451. }
  2452. }
  2453. }
  2454. return hr;
  2455. }
  2456. /* protected */
  2457. HRESULT
  2458. CMetaKey::SetPropertyValue(
  2459. IN DWORD dwID,
  2460. IN DWORD dwSize,
  2461. IN void * pvData,
  2462. IN BOOL * pfInheritanceOverride, OPTIONAL
  2463. IN LPCTSTR lpszMDPath OPTIONAL
  2464. )
  2465. /*++
  2466. Routine Description:
  2467. Set metadata on the open key. The key must have been opened with
  2468. write permission.
  2469. Arguments:
  2470. DWORD dwID : Property ID
  2471. DWORD dwSize : Size of data
  2472. void * pvData : Data buffer
  2473. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2474. LPCTSTR lpszMDPath : Optional path off the open key
  2475. Return Value:
  2476. HRESULT
  2477. ERROR_INVALID_HANDLE : If the handle is not open
  2478. ERROR_INVALID_PARAMETER : If the property id is not found,
  2479. or the buffer is NULL or of size 0
  2480. --*/
  2481. {
  2482. ASSURE_PROPER_INTERFACE();
  2483. ASSURE_OPEN_KEY();
  2484. if (pvData == NULL && dwSize != 0)
  2485. {
  2486. ASSERT_MSG("No Data");
  2487. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2488. }
  2489. METADATA_RECORD mdRecord;
  2490. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  2491. if (pfInheritanceOverride)
  2492. {
  2493. if (*pfInheritanceOverride)
  2494. {
  2495. mdRecord.dwMDAttributes |= METADATA_INHERIT;
  2496. }
  2497. else
  2498. {
  2499. mdRecord.dwMDAttributes &= ~METADATA_INHERIT;
  2500. }
  2501. }
  2502. mdRecord.dwMDDataLen = dwSize;
  2503. mdRecord.pbMDData = (LPBYTE)pvData;
  2504. return SetData(m_hKey, lpszMDPath, &mdRecord);
  2505. }
  2506. /* protected */
  2507. HRESULT
  2508. CMetaKey::GetAllData(
  2509. IN DWORD dwMDAttributes,
  2510. IN DWORD dwMDUserType,
  2511. IN DWORD dwMDDataType,
  2512. OUT DWORD * pdwMDNumEntries,
  2513. OUT DWORD * pdwMDDataLen,
  2514. OUT PBYTE * ppbMDData,
  2515. IN LPCTSTR lpszMDPath OPTIONAL
  2516. )
  2517. /*++
  2518. Routine Description:
  2519. Get all data off the open key. Buffer is created automatically.
  2520. Arguments:
  2521. DWORD dwMDAttributes : Attributes
  2522. DWORD dwMDUserType : User type to fetch
  2523. DWORD dwMDDataType : Data type to fetch
  2524. DWORD * pdwMDNumEntries : Returns number of entries read
  2525. DWORD * pdwMDDataLen : Returns size of data buffer
  2526. PBYTE * ppbMDData : Returns data buffer
  2527. LPCTSTR lpszMDPath : Optional data path
  2528. Return Value:
  2529. HRESULT
  2530. --*/
  2531. {
  2532. ASSURE_PROPER_INTERFACE();
  2533. ASSURE_OPEN_KEY();
  2534. //
  2535. // Check for valid parameters
  2536. //
  2537. if(!pdwMDDataLen || !ppbMDData || !pdwMDNumEntries)
  2538. {
  2539. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2540. }
  2541. HRESULT hr = S_OK;
  2542. BOOL fBufferTooSmall = FALSE;
  2543. DWORD dwMDDataSetNumber;
  2544. DWORD dwRequiredBufferSize;
  2545. DWORD dwInitSize = m_cbInitialBufferSize;
  2546. *ppbMDData = NULL;
  2547. do
  2548. {
  2549. *pdwMDDataLen = dwInitSize;
  2550. *ppbMDData = (LPBYTE)AllocMem(dwInitSize);
  2551. if (ppbMDData == NULL && dwInitSize > 0)
  2552. {
  2553. hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  2554. break;
  2555. }
  2556. hr = CMetaInterface::GetAllData(
  2557. m_hKey,
  2558. lpszMDPath,
  2559. dwMDAttributes,
  2560. dwMDUserType,
  2561. dwMDDataType,
  2562. pdwMDNumEntries,
  2563. &dwMDDataSetNumber,
  2564. *pdwMDDataLen,
  2565. *ppbMDData,
  2566. &dwRequiredBufferSize
  2567. );
  2568. //
  2569. // Re-fetch the buffer if it's too small.
  2570. //
  2571. fBufferTooSmall = (HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER);
  2572. if(fBufferTooSmall)
  2573. {
  2574. //
  2575. // Delete the old buffer, and set up for a re-fetch.
  2576. //
  2577. SAFE_FREEMEM(*ppbMDData);
  2578. dwInitSize = dwRequiredBufferSize;
  2579. }
  2580. }
  2581. while (fBufferTooSmall);
  2582. if (FAILED(hr))
  2583. {
  2584. //
  2585. // No good, be sure we don't leak anything
  2586. //
  2587. SAFE_FREEMEM(*ppbMDData);
  2588. dwInitSize = 0L;
  2589. }
  2590. return hr;
  2591. }
  2592. HRESULT
  2593. CMetaKey::QueryValue(
  2594. IN DWORD dwID,
  2595. IN OUT DWORD & dwValue,
  2596. IN BOOL * pfInheritanceOverride, OPTIONAL
  2597. IN LPCTSTR lpszMDPath, OPTIONAL
  2598. OUT DWORD * pdwAttributes OPTIONAL
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. Fetch data as a DWORD
  2603. Arguments:
  2604. DWORD dwID : Property ID
  2605. DWORD & dwValue : Returns the value read in
  2606. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2607. LPCTSTR lpszMDPath : Optional path off the open key
  2608. DWORD * pdwAttributes : Optionally returns attributes
  2609. Return Value:
  2610. HRESULT
  2611. --*/
  2612. {
  2613. DWORD dwSize = sizeof(dwValue);
  2614. DWORD dwDataType = DWORD_METADATA;
  2615. void * pvData = &dwValue;
  2616. return GetPropertyValue(
  2617. dwID,
  2618. dwSize,
  2619. pvData,
  2620. &dwDataType,
  2621. pfInheritanceOverride,
  2622. lpszMDPath,
  2623. pdwAttributes
  2624. );
  2625. }
  2626. HRESULT
  2627. CMetaKey::QueryValue(
  2628. IN DWORD dwID,
  2629. IN OUT CString & strValue,
  2630. IN BOOL * pfInheritanceOverride, OPTIONAL
  2631. IN LPCTSTR lpszMDPath, OPTIONAL
  2632. OUT DWORD * pdwAttributes OPTIONAL
  2633. )
  2634. /*++
  2635. Routine Description:
  2636. Fetch data as a string
  2637. Arguments:
  2638. DWORD dwID : Property ID
  2639. DWORD & strValue : Returns the value read in
  2640. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2641. LPCTSTR lpszMDPath : Optional path off the open key
  2642. DWORD * pdwAttributes : Optionally returns attributes
  2643. Return Value:
  2644. HRESULT
  2645. --*/
  2646. {
  2647. //
  2648. // Get GetData allocate the buffer for us
  2649. //
  2650. DWORD dwSize = 0;
  2651. DWORD dwDataType = ALL_METADATA;
  2652. LPTSTR lpData = NULL;
  2653. HRESULT hr = GetPropertyValue(
  2654. dwID,
  2655. dwSize,
  2656. (void *&)lpData,
  2657. &dwDataType,
  2658. pfInheritanceOverride,
  2659. lpszMDPath,
  2660. pdwAttributes
  2661. );
  2662. if (SUCCEEDED(hr))
  2663. {
  2664. //
  2665. // Notes: consider optional auto-expansion on EXPANDSZ_METADATA
  2666. // (see registry functions), and data type conversions for DWORD
  2667. // or MULTISZ_METADATA or BINARY_METADATA
  2668. //
  2669. if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
  2670. {
  2671. try
  2672. {
  2673. strValue = lpData;
  2674. }
  2675. catch(CMemoryException * e)
  2676. {
  2677. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  2678. strValue.Empty();
  2679. e->Delete();
  2680. }
  2681. }
  2682. else
  2683. {
  2684. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2685. }
  2686. }
  2687. if (lpData)
  2688. {
  2689. FreeMem(lpData);
  2690. }
  2691. return hr;
  2692. }
  2693. HRESULT
  2694. CMetaKey::QueryValue(
  2695. IN DWORD dwID,
  2696. IN OUT CStrPassword & strValue,
  2697. IN BOOL * pfInheritanceOverride, OPTIONAL
  2698. IN LPCTSTR lpszMDPath, OPTIONAL
  2699. OUT DWORD * pdwAttributes OPTIONAL
  2700. )
  2701. /*++
  2702. Routine Description:
  2703. Fetch data as a string
  2704. Arguments:
  2705. DWORD dwID : Property ID
  2706. CStrPassword & strValue : Returns the value read in
  2707. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2708. LPCTSTR lpszMDPath : Optional path off the open key
  2709. DWORD * pdwAttributes : Optionally returns attributes
  2710. Return Value:
  2711. HRESULT
  2712. --*/
  2713. {
  2714. //
  2715. // Get GetData allocate the buffer for us
  2716. //
  2717. DWORD dwSize = 0;
  2718. DWORD dwDataType = ALL_METADATA;
  2719. LPTSTR lpData = NULL;
  2720. HRESULT hr = GetPropertyValue(
  2721. dwID,
  2722. dwSize,
  2723. (void *&)lpData,
  2724. &dwDataType,
  2725. pfInheritanceOverride,
  2726. lpszMDPath,
  2727. pdwAttributes
  2728. );
  2729. if (SUCCEEDED(hr))
  2730. {
  2731. //
  2732. // Notes: consider optional auto-expansion on EXPANDSZ_METADATA
  2733. // (see registry functions), and data type conversions for DWORD
  2734. // or MULTISZ_METADATA or BINARY_METADATA
  2735. //
  2736. if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
  2737. {
  2738. try
  2739. {
  2740. strValue = (LPCTSTR) lpData;
  2741. }
  2742. catch(CMemoryException * e)
  2743. {
  2744. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  2745. strValue.Empty();
  2746. e->Delete();
  2747. }
  2748. }
  2749. else
  2750. {
  2751. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2752. }
  2753. }
  2754. if (lpData)
  2755. {
  2756. FreeMem(lpData);
  2757. }
  2758. return hr;
  2759. }
  2760. HRESULT
  2761. CMetaKey::QueryValue(
  2762. IN DWORD dwID,
  2763. IN OUT CComBSTR & strValue,
  2764. IN BOOL * pfInheritanceOverride, OPTIONAL
  2765. IN LPCTSTR lpszMDPath, OPTIONAL
  2766. OUT DWORD * pdwAttributes OPTIONAL
  2767. )
  2768. /*++
  2769. Routine Description:
  2770. Fetch data as a string
  2771. Arguments:
  2772. DWORD dwID : Property ID
  2773. DWORD & CComBSTR : Returns the value read in
  2774. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2775. LPCTSTR lpszMDPath : Optional path off the open key
  2776. DWORD * pdwAttributes : Optionally returns attributes
  2777. Return Value:
  2778. HRESULT
  2779. --*/
  2780. {
  2781. //
  2782. // Get GetData allocate the buffer for us
  2783. //
  2784. DWORD dwSize = 0;
  2785. DWORD dwDataType = ALL_METADATA;
  2786. LPTSTR lpData = NULL;
  2787. HRESULT hr = GetPropertyValue(
  2788. dwID,
  2789. dwSize,
  2790. (void *&)lpData,
  2791. &dwDataType,
  2792. pfInheritanceOverride,
  2793. lpszMDPath,
  2794. pdwAttributes
  2795. );
  2796. if (SUCCEEDED(hr))
  2797. {
  2798. //
  2799. // Notes: consider optional auto-expansion on EXPANDSZ_METADATA
  2800. // (see registry functions), and data type conversions for DWORD
  2801. // or MULTISZ_METADATA or BINARY_METADATA
  2802. //
  2803. if (dwDataType == EXPANDSZ_METADATA || dwDataType == STRING_METADATA)
  2804. {
  2805. strValue = lpData;
  2806. }
  2807. else
  2808. {
  2809. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  2810. }
  2811. }
  2812. if (lpData)
  2813. {
  2814. FreeMem(lpData);
  2815. }
  2816. return hr;
  2817. }
  2818. HRESULT
  2819. CMetaKey::QueryValue(
  2820. IN DWORD dwID,
  2821. IN OUT CStringListEx & strlValue,
  2822. IN BOOL * pfInheritanceOverride, OPTIONAL
  2823. IN LPCTSTR lpszMDPath, OPTIONAL
  2824. OUT DWORD * pdwAttributes OPTIONAL
  2825. )
  2826. /*++
  2827. Routine Description:
  2828. Fetch data as a stringlist
  2829. Arguments:
  2830. DWORD dwID : Property ID
  2831. DWORD & strlValue : Returns the value read in
  2832. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2833. LPCTSTR lpszMDPath : Optional path off the open key
  2834. DWORD * pdwAttributes : Optionally returns attributes
  2835. Return Value:
  2836. HRESULT
  2837. --*/
  2838. {
  2839. //
  2840. // Get GetData allocate the buffer for us
  2841. //
  2842. DWORD dwSize = 0;
  2843. DWORD dwDataType = MULTISZ_METADATA;
  2844. LPTSTR lpData = NULL;
  2845. HRESULT hr = GetPropertyValue(
  2846. dwID,
  2847. dwSize,
  2848. (void *&)lpData,
  2849. &dwDataType,
  2850. pfInheritanceOverride,
  2851. lpszMDPath,
  2852. pdwAttributes
  2853. );
  2854. if (SUCCEEDED(hr))
  2855. {
  2856. //
  2857. // Notes: Consider accepting a single STRING
  2858. //
  2859. ASSERT(dwDataType == MULTISZ_METADATA);
  2860. DWORD err = ConvertDoubleNullListToStringList(
  2861. lpData,
  2862. strlValue,
  2863. dwSize / sizeof(TCHAR)
  2864. );
  2865. hr = HRESULT_FROM_WIN32(err);
  2866. }
  2867. if (lpData)
  2868. {
  2869. FreeMem(lpData);
  2870. }
  2871. return hr;
  2872. }
  2873. HRESULT
  2874. CMetaKey::GetChildPaths(CStringListEx& child_paths, LPCTSTR path)
  2875. {
  2876. DWORD bsize = 0;
  2877. CError err;
  2878. LPTSTR pData = _T("");
  2879. do
  2880. {
  2881. err = CMetaInterface::GetChildPaths(
  2882. m_hKey, path, 0, pData, &bsize);
  2883. if (err.Failed() && err.Win32Error() != ERROR_INSUFFICIENT_BUFFER)
  2884. break;
  2885. pData = (LPTSTR)::LocalAlloc(LPTR, bsize * sizeof(WCHAR));
  2886. if (pData == NULL)
  2887. {
  2888. err = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  2889. break;
  2890. }
  2891. err = CMetaInterface::GetChildPaths(
  2892. m_hKey, path, bsize, pData, &bsize);
  2893. if (err.Failed()) break;
  2894. ConvertDoubleNullListToStringList(pData, child_paths);
  2895. } while (FALSE);
  2896. if (pData != NULL)
  2897. {
  2898. ::LocalFree(pData);
  2899. }
  2900. return err;
  2901. }
  2902. HRESULT
  2903. CMetaKey::QueryValue(
  2904. IN DWORD dwID,
  2905. IN OUT CBlob & blValue,
  2906. IN BOOL * pfInheritanceOverride, OPTIONAL
  2907. IN LPCTSTR lpszMDPath, OPTIONAL
  2908. OUT DWORD * pdwAttributes OPTIONAL
  2909. )
  2910. /*++
  2911. Routine Description:
  2912. Fetch data as a binary blob
  2913. Arguments:
  2914. DWORD dwID : Property ID
  2915. DWORD CBlob & blValue : Returns the binary blob
  2916. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2917. LPCTSTR lpszMDPath : Optional path off the open key
  2918. DWORD * pdwAttributes : Optionally returns attributes
  2919. Return Value:
  2920. HRESULT
  2921. --*/
  2922. {
  2923. //
  2924. // Get GetData allocate the buffer for us
  2925. //
  2926. DWORD dwSize = 0;
  2927. DWORD dwDataType = BINARY_METADATA;
  2928. LPBYTE pbData = NULL;
  2929. HRESULT hr = GetPropertyValue(
  2930. dwID,
  2931. dwSize,
  2932. (void *&)pbData,
  2933. &dwDataType,
  2934. pfInheritanceOverride,
  2935. lpszMDPath,
  2936. pdwAttributes
  2937. );
  2938. if (SUCCEEDED(hr))
  2939. {
  2940. //
  2941. // Blob takes ownership of the data, so don't free it...
  2942. //
  2943. ASSERT_READ_PTR2(pbData, dwSize);
  2944. blValue.SetValue(dwSize, pbData, FALSE);
  2945. }
  2946. return hr;
  2947. }
  2948. HRESULT
  2949. CMetaKey::SetValue(
  2950. IN DWORD dwID,
  2951. IN CStrPassword & strlValue,
  2952. IN BOOL * pfInheritanceOverride, OPTIONAL
  2953. IN LPCTSTR lpszMDPath OPTIONAL
  2954. )
  2955. {
  2956. LPTSTR lpstr = NULL;
  2957. HRESULT hr = S_OK;
  2958. lpstr = strlValue.GetClearTextPassword();
  2959. if (lpstr)
  2960. {
  2961. hr = SetPropertyValue(
  2962. dwID,
  2963. strlValue.GetByteLength(),
  2964. (void *)lpstr,
  2965. pfInheritanceOverride,
  2966. lpszMDPath
  2967. );
  2968. strlValue.DestroyClearTextPassword(lpstr);
  2969. }
  2970. return hr;
  2971. }
  2972. HRESULT
  2973. CMetaKey::SetValue(
  2974. IN DWORD dwID,
  2975. IN CStringListEx & strlValue,
  2976. IN BOOL * pfInheritanceOverride, OPTIONAL
  2977. IN LPCTSTR lpszMDPath OPTIONAL
  2978. )
  2979. /*++
  2980. Routine Description:
  2981. Store data as string
  2982. Arguments:
  2983. DWORD dwID : Property ID
  2984. CStringListEx & strlValue : Value to be written
  2985. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  2986. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  2987. Return Value:
  2988. HRESULT
  2989. --*/
  2990. {
  2991. DWORD cCharacters;
  2992. LPTSTR lpstr = NULL;
  2993. //
  2994. // Flatten value
  2995. //
  2996. ConvertStringListToDoubleNullList(
  2997. strlValue,
  2998. cCharacters,
  2999. lpstr
  3000. );
  3001. HRESULT hr = SetPropertyValue(
  3002. dwID,
  3003. cCharacters * sizeof(TCHAR),
  3004. (void *)lpstr,
  3005. pfInheritanceOverride,
  3006. lpszMDPath
  3007. );
  3008. SAFE_FREEMEM(lpstr);
  3009. return hr;
  3010. }
  3011. HRESULT
  3012. CMetaKey::SetValue(
  3013. IN DWORD dwID,
  3014. IN CBlob & blValue,
  3015. IN BOOL * pfInheritanceOverride, OPTIONAL
  3016. IN LPCTSTR lpszMDPath OPTIONAL
  3017. )
  3018. /*++
  3019. Routine Description:
  3020. Store data as binary
  3021. Arguments:
  3022. DWORD dwID : Property ID
  3023. CBlob & blValue : Value to be written
  3024. BOOL * pfInheritanceOverride : NULL or forces inheritance on/off
  3025. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  3026. Return Value:
  3027. HRESULT
  3028. --*/
  3029. {
  3030. return SetPropertyValue(
  3031. dwID,
  3032. blValue.GetSize(),
  3033. (void *)blValue.GetData(),
  3034. pfInheritanceOverride,
  3035. lpszMDPath
  3036. );
  3037. }
  3038. HRESULT
  3039. CMetaKey::DeleteValue(
  3040. DWORD dwID,
  3041. LPCTSTR lpszMDPath OPTIONAL
  3042. )
  3043. /*++
  3044. Routine Description:
  3045. Delete data
  3046. Arguments:
  3047. DWORD dwID : Property ID of property to be deleted
  3048. LPCTSTR lpszMDPath : Optional path (or NULL or "")
  3049. Return Value:
  3050. HRESULT
  3051. --*/
  3052. {
  3053. ASSURE_PROPER_INTERFACE();
  3054. ASSURE_OPEN_KEY();
  3055. METADATA_RECORD mdRecord;
  3056. FETCH_PROPERTY_DATA_OR_FAIL(dwID, mdRecord);
  3057. return DeleteData(
  3058. m_hKey,
  3059. lpszMDPath,
  3060. mdRecord.dwMDIdentifier,
  3061. mdRecord.dwMDDataType
  3062. );
  3063. }
  3064. HRESULT
  3065. CMetaKey::DoesPathExist(
  3066. IN LPCTSTR lpszMDPath
  3067. )
  3068. /*++
  3069. Routine Description:
  3070. Determine if the path exists
  3071. Arguments:
  3072. LPCTSTR lpszMDPath : Relative path off the open key
  3073. Return Value:
  3074. HRESULT, or S_OK if the path exists.
  3075. --*/
  3076. {
  3077. ASSURE_PROPER_INTERFACE();
  3078. ASSURE_OPEN_KEY();
  3079. FILETIME ft;
  3080. return GetLastChangeTime(m_hKey, lpszMDPath, &ft, FALSE);
  3081. }
  3082. HRESULT
  3083. CMetaInterface::Regenerate()
  3084. /*++
  3085. Routine Description:
  3086. Attempt to recreate the interface pointer. This assumes that the interface
  3087. had been successfully created before, but has become invalid at some
  3088. point afterwards.
  3089. Arguments:
  3090. None
  3091. Return Value:
  3092. HRESULT
  3093. --*/
  3094. {
  3095. ASSERT_PTR(m_pInterface); // Must have been initialised
  3096. SAFE_RELEASE(m_pInterface);
  3097. m_hrInterface = Create();
  3098. return m_hrInterface;
  3099. }
  3100. #define GET_TO_INTERFACE2()\
  3101. IMSAdminBase2 * pInterface2 = NULL;\
  3102. HRESULT hr = GetAdminInterface2(&pInterface2);\
  3103. if (SUCCEEDED(hr)) {
  3104. #define GET_TO_INTERFACE3()\
  3105. IMSAdminBase3 * pInterface3 = NULL;\
  3106. HRESULT hr = GetAdminInterface3(&pInterface3);\
  3107. if (SUCCEEDED(hr)) {
  3108. #define RELEASE_AND_RETURN2()\
  3109. if (pInterface2 != NULL)\
  3110. pInterface2->Release();\
  3111. }\
  3112. return hr
  3113. #define RELEASE_AND_RETURN3()\
  3114. if (pInterface3 != NULL)\
  3115. pInterface3->Release();\
  3116. }\
  3117. return hr
  3118. HRESULT
  3119. CMetaInterface::GetAdminInterface2(IMSAdminBase2 ** pp)
  3120. {
  3121. HRESULT hr = S_OK;
  3122. IMSAdminBase2 * p = NULL;
  3123. if (pp == NULL)
  3124. return E_POINTER;
  3125. if (m_auth.UsesImpersonation())
  3126. {
  3127. IUnknown * punk = NULL;
  3128. hr = m_pInterface->QueryInterface(__uuidof(IUnknown), (void **)&punk);
  3129. if (SUCCEEDED(hr))
  3130. {
  3131. if (SUCCEEDED(hr = m_auth.ApplyProxyBlanket(punk)))
  3132. {
  3133. if (SUCCEEDED(hr = punk->QueryInterface(IID_IMSAdminBase2, (void **)&p)))
  3134. {
  3135. if (p != NULL)
  3136. {
  3137. hr = m_auth.ApplyProxyBlanket(p);
  3138. if (SUCCEEDED(hr))
  3139. {
  3140. *pp = p;
  3141. }
  3142. }
  3143. }
  3144. }
  3145. }
  3146. if (punk != NULL)
  3147. punk->Release();
  3148. }
  3149. else
  3150. {
  3151. if (m_pInterface)
  3152. {
  3153. hr = m_pInterface->QueryInterface(IID_IMSAdminBase2, (void **)pp);
  3154. }
  3155. else
  3156. {
  3157. hr = E_NOINTERFACE;
  3158. }
  3159. }
  3160. return hr;
  3161. }
  3162. HRESULT
  3163. CMetaInterface::GetAdminInterface3(IMSAdminBase3 ** pp)
  3164. {
  3165. HRESULT hr = S_OK;
  3166. IMSAdminBase3 * p = NULL;
  3167. if (pp == NULL)
  3168. return E_POINTER;
  3169. if (m_auth.UsesImpersonation())
  3170. {
  3171. IUnknown * punk = NULL;
  3172. hr = m_pInterface->QueryInterface(__uuidof(IUnknown), (void **)&punk);
  3173. if (SUCCEEDED(hr))
  3174. {
  3175. if (SUCCEEDED(hr = m_auth.ApplyProxyBlanket(punk)))
  3176. {
  3177. if (SUCCEEDED(hr = punk->QueryInterface(IID_IMSAdminBase3, (void **)&p)))
  3178. {
  3179. if (p != NULL)
  3180. {
  3181. hr = m_auth.ApplyProxyBlanket(p);
  3182. if (SUCCEEDED(hr))
  3183. {
  3184. *pp = p;
  3185. }
  3186. }
  3187. }
  3188. }
  3189. }
  3190. if (punk != NULL)
  3191. punk->Release();
  3192. }
  3193. else
  3194. {
  3195. if (m_pInterface)
  3196. {
  3197. hr = m_pInterface->QueryInterface(IID_IMSAdminBase3, (void **)pp);
  3198. }
  3199. else
  3200. {
  3201. hr = E_NOINTERFACE;
  3202. }
  3203. }
  3204. return hr;
  3205. }
  3206. HRESULT CMetaInterface::BackupWithPassword(
  3207. IN LPCTSTR lpszBackupLocation,
  3208. IN DWORD dwMDVersion,
  3209. IN DWORD dwMDFlags,
  3210. IN LPCTSTR lpszPassword
  3211. )
  3212. {
  3213. GET_TO_INTERFACE2();
  3214. hr = pInterface2->BackupWithPasswd(lpszBackupLocation, dwMDVersion, dwMDFlags, lpszPassword);
  3215. RELEASE_AND_RETURN2();
  3216. }
  3217. HRESULT CMetaInterface::RestoreWithPassword(
  3218. IN LPCTSTR lpszBackupLocation,
  3219. IN DWORD dwMDVersion,
  3220. IN DWORD dwMDFlags,
  3221. IN LPCTSTR lpszPassword
  3222. )
  3223. {
  3224. GET_TO_INTERFACE2();
  3225. hr = pInterface2->RestoreWithPasswd(lpszBackupLocation, dwMDVersion, dwMDFlags, lpszPassword);
  3226. RELEASE_AND_RETURN2();
  3227. }
  3228. HRESULT CMetaInterface::EnumHistory(
  3229. OUT LPTSTR pszMDHistoryLocation,
  3230. OUT DWORD * pdwMDMajorVersion,
  3231. OUT DWORD * pdwMDMinorVersion,
  3232. OUT FILETIME * pftMDHistoryTime,
  3233. IN DWORD dwIndex
  3234. )
  3235. {
  3236. GET_TO_INTERFACE2();
  3237. hr = pInterface2->EnumHistory(pszMDHistoryLocation, pdwMDMajorVersion, pdwMDMinorVersion, pftMDHistoryTime, dwIndex);
  3238. RELEASE_AND_RETURN2();
  3239. }
  3240. HRESULT CMetaInterface::RestoreHistory(
  3241. IN LPCTSTR pszMDHistoryLocation,
  3242. IN DWORD dwMDMajorVersion,
  3243. IN DWORD dwMDMinorVersion,
  3244. IN DWORD dwMDFlags
  3245. )
  3246. {
  3247. // dwMDFlags. The flag is set to RESTORE_LATEST would signal the API that the Major and Minor version parameters
  3248. // are to be ignored and the history file at the HistoryLocation with the largest Major (and corresponding
  3249. // largest Minor version) should be restored. If this flag is specified, the dwMDMajorVersion, dwMDMinorVersion
  3250. // parameters must be set to 0 (zero).
  3251. GET_TO_INTERFACE2();
  3252. hr = pInterface2->RestoreHistory(pszMDHistoryLocation, dwMDMajorVersion, dwMDMinorVersion, dwMDFlags);
  3253. RELEASE_AND_RETURN2();
  3254. }
  3255. HRESULT
  3256. CMetaInterface::GetChildPaths(
  3257. METADATA_HANDLE hKey,
  3258. LPCTSTR path,
  3259. DWORD buf_size,
  3260. WCHAR * pbuf,
  3261. DWORD * preq_size
  3262. )
  3263. {
  3264. GET_TO_INTERFACE3();
  3265. hr = pInterface3->GetChildPaths(hKey, path, buf_size, pbuf, preq_size);
  3266. RELEASE_AND_RETURN3();
  3267. }
  3268. //
  3269. // CWamInterface class
  3270. //
  3271. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3272. CWamInterface::CWamInterface(
  3273. IN CComAuthInfo * pAuthInfo OPTIONAL
  3274. )
  3275. /*++
  3276. Routine Description:
  3277. Construct and initialize the interface.
  3278. Arguments:
  3279. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  3280. Return Value:
  3281. N/A
  3282. --*/
  3283. : CIISInterface(pAuthInfo),
  3284. m_pInterface(NULL),
  3285. m_fSupportsPooledProc(FALSE)
  3286. {
  3287. //
  3288. // Initialize the interface
  3289. //
  3290. m_hrInterface = Create();
  3291. }
  3292. CWamInterface::CWamInterface(
  3293. IN CWamInterface * pInterface
  3294. )
  3295. /*++
  3296. Routine Description:
  3297. Construct from existing interface (copy constructor)
  3298. Arguments:
  3299. CWamInterface * pInterface : Existing interface
  3300. Return Value:
  3301. N/A
  3302. --*/
  3303. : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
  3304. m_pInterface(pInterface->m_pInterface),
  3305. m_fSupportsPooledProc(FALSE)
  3306. {
  3307. ASSERT_PTR(m_pInterface);
  3308. m_pInterface->AddRef();
  3309. }
  3310. CWamInterface::~CWamInterface()
  3311. /*++
  3312. Routine Description:
  3313. Destructor -- releases the interface.
  3314. Arguments:
  3315. N/A
  3316. Return Value:
  3317. N/A
  3318. --*/
  3319. {
  3320. SAFE_RELEASE(m_pInterface);
  3321. }
  3322. /* protected */
  3323. HRESULT
  3324. CWamInterface::Create()
  3325. /*++
  3326. Routine Description:
  3327. Create the interface with DCOM
  3328. Arguments:
  3329. None
  3330. Return Value:
  3331. HRESULT
  3332. Notes:
  3333. First, it will attempt to create the new interface, if it
  3334. fails, it will attempt to create the downlevel interface
  3335. --*/
  3336. {
  3337. CLSID rgCLSID[2];
  3338. IID rgIID[2];
  3339. rgCLSID[1] = rgCLSID[0] = CLSID_WamAdmin;
  3340. rgIID[0] = IID_IWamAdmin2;
  3341. rgIID[1] = IID_IWamAdmin;
  3342. ASSERT(ARRAY_SIZE(rgCLSID) == ARRAY_SIZE(rgIID));
  3343. int cInterfaces = ARRAY_SIZE(rgCLSID);
  3344. int iInterface;
  3345. HRESULT hr = CIISInterface::Create(
  3346. cInterfaces,
  3347. rgIID,
  3348. rgCLSID,
  3349. &iInterface,
  3350. (IUnknown **)&m_pInterface
  3351. );
  3352. if (SUCCEEDED(hr))
  3353. {
  3354. //
  3355. // Only supported on IWamAdmin2
  3356. //
  3357. m_fSupportsPooledProc = (rgIID[iInterface] == IID_IWamAdmin2);
  3358. }
  3359. return hr;
  3360. }
  3361. HRESULT
  3362. CWamInterface::AppCreate(
  3363. IN LPCTSTR szMDPath,
  3364. IN DWORD dwAppProtection
  3365. )
  3366. /*++
  3367. Routine Description:
  3368. Create application
  3369. Arguments:
  3370. LPCTSTR szMDPath : Metabase path
  3371. DWORD dwAppProtection : APP_INPROC to create in-proc app
  3372. APP_OUTOFPROC to create out-of-proc app
  3373. APP_POOLEDPROC to create a pooled-proc app
  3374. Return Value:
  3375. HRESULT (ERROR_INVALID_PARAMETER if unsupported protection state is requested)
  3376. --*/
  3377. {
  3378. if (m_fSupportsPooledProc)
  3379. {
  3380. //
  3381. // Interface pointer is really IWamAdmin2, so call the new method
  3382. //
  3383. return ((IWamAdmin2 *)m_pInterface)->AppCreate2(szMDPath, dwAppProtection);
  3384. }
  3385. //
  3386. // Call the downlevel API
  3387. //
  3388. if (dwAppProtection == APP_INPROC || dwAppProtection == APP_OUTOFPROC)
  3389. {
  3390. BOOL fInProc = (dwAppProtection == APP_INPROC);
  3391. ASSERT_PTR(m_pInterface);
  3392. ASSURE_PROPER_INTERFACE();
  3393. return m_pInterface->AppCreate(szMDPath, fInProc);
  3394. }
  3395. return CError(ERROR_INVALID_PARAMETER);
  3396. }
  3397. #define GET_TO_INTERFACE()\
  3398. IIISApplicationAdmin * pAppAdmin = NULL;\
  3399. HRESULT hr = GetAppAdminInterface(&pAppAdmin);\
  3400. if (SUCCEEDED(hr)) {
  3401. #define RELEASE_AND_RETURN()\
  3402. if (pAppAdmin != NULL)\
  3403. pAppAdmin->Release();\
  3404. }\
  3405. return hr\
  3406. HRESULT
  3407. CWamInterface::GetAppAdminInterface(IIISApplicationAdmin ** pp)
  3408. {
  3409. HRESULT hr = S_OK;
  3410. IIISApplicationAdmin * p = NULL;
  3411. if (pp == NULL)
  3412. {
  3413. return E_POINTER;
  3414. }
  3415. if (m_auth.UsesImpersonation())
  3416. {
  3417. IUnknown * punk = NULL;
  3418. hr = m_pInterface->QueryInterface(__uuidof(IUnknown), (void **)&punk);
  3419. if (SUCCEEDED(hr))
  3420. {
  3421. if (SUCCEEDED(hr = m_auth.ApplyProxyBlanket(punk)))
  3422. {
  3423. if (SUCCEEDED(hr = punk->QueryInterface(IID_IIISApplicationAdmin, (void **)&p)))
  3424. {
  3425. if (p != NULL)
  3426. {
  3427. hr = m_auth.ApplyProxyBlanket(p);
  3428. if (SUCCEEDED(hr))
  3429. {
  3430. *pp = p;
  3431. }
  3432. }
  3433. }
  3434. }
  3435. }
  3436. if (punk != NULL)
  3437. {
  3438. punk->Release();
  3439. }
  3440. }
  3441. else
  3442. {
  3443. if (m_pInterface)
  3444. {
  3445. hr = m_pInterface->QueryInterface(IID_IIISApplicationAdmin, (void **)pp);
  3446. }
  3447. else
  3448. {
  3449. hr = E_NOINTERFACE;
  3450. }
  3451. }
  3452. return hr;
  3453. }
  3454. HRESULT
  3455. CWamInterface::CreateApplication(
  3456. LPCWSTR szMDPath,
  3457. DWORD dwAppMode,
  3458. LPCWSTR szAppPoolId,
  3459. BOOL fCreatePool
  3460. )
  3461. {
  3462. GET_TO_INTERFACE();
  3463. hr = pAppAdmin->CreateApplication(
  3464. szMDPath, dwAppMode, szAppPoolId, fCreatePool);
  3465. RELEASE_AND_RETURN();
  3466. }
  3467. HRESULT
  3468. CWamInterface::DeleteApplication(LPCWSTR szMDPath, BOOL fRecursive)
  3469. {
  3470. GET_TO_INTERFACE();
  3471. hr = pAppAdmin->DeleteApplication(szMDPath, fRecursive);
  3472. RELEASE_AND_RETURN();
  3473. }
  3474. HRESULT
  3475. CWamInterface::CreateApplicationPool(LPCWSTR szMDPath)
  3476. {
  3477. GET_TO_INTERFACE();
  3478. hr = pAppAdmin->CreateApplicationPool(szMDPath);
  3479. RELEASE_AND_RETURN();
  3480. }
  3481. HRESULT
  3482. CWamInterface::DeleteApplicationPool(LPCWSTR szMDPath)
  3483. {
  3484. GET_TO_INTERFACE();
  3485. hr = pAppAdmin->DeleteApplicationPool(szMDPath);
  3486. RELEASE_AND_RETURN();
  3487. }
  3488. HRESULT
  3489. CWamInterface::RecycleApplicationPool(LPCWSTR szMDPath)
  3490. {
  3491. GET_TO_INTERFACE();
  3492. hr = pAppAdmin->RecycleApplicationPool(szMDPath);
  3493. RELEASE_AND_RETURN();
  3494. }
  3495. HRESULT
  3496. CWamInterface::EnumerateApplicationsInPool(LPCTSTR szMDPath, BSTR * pbstr)
  3497. {
  3498. GET_TO_INTERFACE();
  3499. hr = pAppAdmin->EnumerateApplicationsInPool(szMDPath, pbstr);
  3500. RELEASE_AND_RETURN();
  3501. }
  3502. HRESULT CWamInterface::GetProcessMode(DWORD * pdwMode)
  3503. {
  3504. GET_TO_INTERFACE();
  3505. if (pAppAdmin)
  3506. {
  3507. hr = pAppAdmin->GetProcessMode(pdwMode);
  3508. }
  3509. RELEASE_AND_RETURN();
  3510. }
  3511. //
  3512. // CMetaback Class
  3513. //
  3514. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3515. const LPCTSTR CMetaBack::s_szMasterAppRoot =\
  3516. SZ_MBN_SEP_STR SZ_MBN_MACHINE SZ_MBN_SEP_STR SZ_MBN_WEB;
  3517. CMetaBack::CMetaBack(
  3518. IN CComAuthInfo * pAuthInfo OPTIONAL
  3519. )
  3520. /*++
  3521. Routine Description:
  3522. Constructor for metabase backup/restore operations class. This object
  3523. is both a WAM interface and a METABASE interface.
  3524. Arguments:
  3525. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  3526. Return Value:
  3527. N/A
  3528. --*/
  3529. : m_dwIndex(0),
  3530. CMetaInterface(pAuthInfo),
  3531. CWamInterface(pAuthInfo)
  3532. {
  3533. }
  3534. /* virtual */
  3535. BOOL
  3536. CMetaBack::Succeeded() const
  3537. /*++
  3538. Routine Description:
  3539. Determine if object was constructed successfully.
  3540. Arguments:
  3541. None
  3542. Return Value:
  3543. TRUE for success, FALSE for failure
  3544. --*/
  3545. {
  3546. BOOL bRet = FALSE;
  3547. bRet = CMetaInterface::Succeeded();
  3548. if (TRUE == bRet)
  3549. {
  3550. bRet = CWamInterface::Succeeded();
  3551. if (FALSE == bRet)
  3552. {
  3553. HRESULT hr = CWamInterface::QueryResult();
  3554. if (REGDB_E_CLASSNOTREG == hr)
  3555. {
  3556. // could mean that only FTP is installed and WAM is not available.
  3557. // just return success...
  3558. bRet = TRUE;
  3559. }
  3560. }
  3561. }
  3562. return bRet;
  3563. }
  3564. /* virtual */
  3565. HRESULT
  3566. CMetaBack::QueryResult() const
  3567. /*++
  3568. Routine Description:
  3569. Return the construction error for this object
  3570. Arguments:
  3571. None
  3572. Return Value:
  3573. HRESULT from construction errors
  3574. --*/
  3575. {
  3576. //
  3577. // Both interfaces must have constructed successfully
  3578. //
  3579. HRESULT hr = CMetaInterface::QueryResult();
  3580. if (SUCCEEDED(hr))
  3581. {
  3582. hr = CWamInterface::QueryResult();
  3583. if (REGDB_E_CLASSNOTREG == hr)
  3584. {
  3585. // could mean that only FTP is installed and WAM is not available.
  3586. // just return success...
  3587. hr = S_OK;
  3588. }
  3589. }
  3590. return hr;
  3591. }
  3592. HRESULT
  3593. CMetaBack::Restore(
  3594. IN LPCTSTR lpszLocation,
  3595. IN DWORD dwVersion
  3596. )
  3597. /*++
  3598. Routine Description:
  3599. Restore metabase
  3600. Arguments:
  3601. DWORD dwVersion : Backup version
  3602. LPCTSTR lpszLocation : Backup location
  3603. Return Value:
  3604. HRESULT
  3605. --*/
  3606. {
  3607. HRESULT hr = S_OK;
  3608. //
  3609. // Backup and restore the application information from a restore
  3610. //
  3611. CString strPath(s_szMasterAppRoot);
  3612. BOOL bDoesWamInterfaceExist = (REGDB_E_CLASSNOTREG != CWamInterface::QueryResult());
  3613. // Check if there is a WAM interface 1st...
  3614. // could mean that only FTP is installed and WAM is not available.
  3615. if (bDoesWamInterfaceExist)
  3616. {
  3617. // could mean that only FTP is installed and WAM is not available.
  3618. // just return success...
  3619. hr = AppDeleteRecoverable(strPath, TRUE);
  3620. }
  3621. if (SUCCEEDED(hr))
  3622. {
  3623. hr = CMetaInterface::Restore(lpszLocation, dwVersion, 0);
  3624. if (SUCCEEDED(hr))
  3625. {
  3626. if (bDoesWamInterfaceExist)
  3627. {
  3628. hr = AppRecover(strPath, TRUE);
  3629. }
  3630. }
  3631. }
  3632. return hr;
  3633. }
  3634. HRESULT
  3635. CMetaBack::BackupWithPassword(
  3636. IN LPCTSTR lpszLocation,
  3637. IN LPCTSTR lpszPassword
  3638. )
  3639. {
  3640. return CMetaInterface::BackupWithPassword(
  3641. lpszLocation,
  3642. MD_BACKUP_NEXT_VERSION,
  3643. MD_BACKUP_SAVE_FIRST,
  3644. lpszPassword
  3645. );
  3646. }
  3647. HRESULT
  3648. CMetaBack::RestoreWithPassword(
  3649. IN LPCTSTR lpszLocation,
  3650. IN DWORD dwVersion,
  3651. IN LPCTSTR lpszPassword
  3652. )
  3653. /*++
  3654. Routine Description:
  3655. Restore metabase
  3656. Arguments:
  3657. DWORD dwVersion : Backup version
  3658. LPCTSTR lpszLocation : Backup location
  3659. LPCTSTR lpszPassword : Backup password
  3660. Return Value:
  3661. HRESULT
  3662. --*/
  3663. {
  3664. //
  3665. // Backup and restore the application information from a restore
  3666. //
  3667. // BUGBUG: clear it out, why we had an error "parameter is incorrect" from AppDeleteRecoverable
  3668. CString strPath(s_szMasterAppRoot);
  3669. HRESULT hr;// = AppDeleteRecoverable(strPath, TRUE);
  3670. // if (SUCCEEDED(hr))
  3671. // {
  3672. hr = CMetaInterface::RestoreWithPassword(lpszLocation, dwVersion, 0, lpszPassword);
  3673. // if (SUCCEEDED(hr))
  3674. // {
  3675. // hr = AppRecover(strPath, TRUE);
  3676. // }
  3677. // }
  3678. return hr;
  3679. }
  3680. //
  3681. // CIISSvcControl class
  3682. //
  3683. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3684. CIISSvcControl::CIISSvcControl(
  3685. IN CComAuthInfo * pAuthInfo OPTIONAL
  3686. )
  3687. /*++
  3688. Routine Description:
  3689. Construct and initialize the interface.
  3690. Arguments:
  3691. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  3692. Return Value:
  3693. N/A
  3694. --*/
  3695. : CIISInterface(pAuthInfo),
  3696. m_pInterface(NULL)
  3697. {
  3698. //
  3699. // Initialize the interface
  3700. //
  3701. m_hrInterface = Create();
  3702. }
  3703. CIISSvcControl::CIISSvcControl(
  3704. IN CIISSvcControl * pInterface
  3705. )
  3706. /*++
  3707. Routine Description:
  3708. Construct from existing interface (copy constructor)
  3709. Arguments:
  3710. CIISSvcControl * pInterface : Existing interface
  3711. Return Value:
  3712. N/A
  3713. --*/
  3714. : CIISInterface(&pInterface->m_auth, pInterface->m_hrInterface),
  3715. m_pInterface(pInterface->m_pInterface)
  3716. {
  3717. ASSERT_PTR(m_pInterface);
  3718. m_pInterface->AddRef();
  3719. }
  3720. CIISSvcControl::~CIISSvcControl()
  3721. /*++
  3722. Routine Description:
  3723. Destructor -- releases the interface.
  3724. Arguments:
  3725. N/A
  3726. Return Value:
  3727. N/A
  3728. --*/
  3729. {
  3730. SAFE_RELEASE(m_pInterface);
  3731. }
  3732. //
  3733. // CMetaEnumerator Clas
  3734. //
  3735. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  3736. CMetaEnumerator::CMetaEnumerator(
  3737. IN CComAuthInfo * pAuthInfo OPTIONAL,
  3738. IN LPCTSTR lpszMDPath OPTIONAL,
  3739. IN METADATA_HANDLE hkBase OPTIONAL
  3740. )
  3741. /*++
  3742. Routine Description:
  3743. Metabase enumerator constructor. This constructor creates a new interface
  3744. and opens a key.
  3745. Arguments:
  3746. CComAuthInfo * pAuthInfo : Auth info. NULL indicates the local computer.
  3747. LPCTSTR lpszMDPath : Metabase path
  3748. METADATA_HANDLE hkBase : Metabase handle
  3749. Return Value:
  3750. N/A
  3751. --*/
  3752. : CMetaKey(pAuthInfo, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
  3753. m_dwIndex(0L)
  3754. {
  3755. }
  3756. CMetaEnumerator::CMetaEnumerator(
  3757. IN CMetaInterface * pInterface,
  3758. IN LPCTSTR lpszMDPath, OPTIONAL
  3759. IN METADATA_HANDLE hkBase OPTIONAL
  3760. )
  3761. /*++
  3762. Routine Description:
  3763. Metabase enumerator constructor. This constructor uses an existing
  3764. interface and opens a key.
  3765. Arguments:
  3766. CMetaInterface * pInterface : Existing interface
  3767. LPCTSTR lpszMDPath : Metabase path
  3768. METADATA_HANDLE hkBase : Metabase handle
  3769. Return Value:
  3770. N/A
  3771. --*/
  3772. : CMetaKey(pInterface, lpszMDPath, METADATA_PERMISSION_READ, hkBase),
  3773. m_dwIndex(0L)
  3774. {
  3775. }
  3776. CMetaEnumerator::CMetaEnumerator(
  3777. IN BOOL fOwnKey,
  3778. IN CMetaKey * pKey
  3779. )
  3780. /*++
  3781. Routine Description:
  3782. Metabase enumerator constructor. This constructor uses an existing
  3783. interface and open key.
  3784. Arguments:
  3785. BOOL fOwnKey : TRUE if we own the key (destructor will close)
  3786. CMetaKey * pKey : Open key
  3787. Return Value:
  3788. N/A
  3789. --*/
  3790. : CMetaKey(fOwnKey, pKey),
  3791. m_dwIndex(0L)
  3792. {
  3793. }
  3794. HRESULT
  3795. CMetaEnumerator::Next(
  3796. OUT CString & strKey,
  3797. IN LPCTSTR lpszMDPath OPTIONAL
  3798. )
  3799. /*++
  3800. Routine Description:
  3801. Get the next subkey
  3802. Arguments:
  3803. CString & str Returns keyname
  3804. LPCTSTR lpszMDPath Optional subpath
  3805. Return Value:
  3806. HRESULT
  3807. --*/
  3808. {
  3809. ASSURE_PROPER_INTERFACE();
  3810. ASSURE_OPEN_KEY();
  3811. LPTSTR lpKey = strKey.GetBuffer(MAX_PATH);
  3812. HRESULT hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++);
  3813. strKey.ReleaseBuffer();
  3814. return hr;
  3815. }
  3816. HRESULT
  3817. CMetaEnumerator::Next(
  3818. OUT DWORD & dwKey,
  3819. OUT CString & strKey,
  3820. IN LPCTSTR lpszMDPath OPTIONAL
  3821. )
  3822. /*++
  3823. Routine Description:
  3824. Get the next subkey as a DWORD. This skips non-numeric
  3825. keynames (including 0) until the first numeric key name
  3826. Arguments:
  3827. DWORD & dwKey Numeric key
  3828. CString & strKey Same key in string format
  3829. LPCTSTR lpszMDPath Optional subpath
  3830. Return Value:
  3831. HRESULT
  3832. --*/
  3833. {
  3834. ASSURE_PROPER_INTERFACE();
  3835. ASSURE_OPEN_KEY();
  3836. HRESULT hr = S_OK;
  3837. BOOL fContinue = TRUE;
  3838. while (fContinue)
  3839. {
  3840. fContinue = FALSE;
  3841. LPTSTR lpKey = strKey.GetBuffer(MAX_PATH);
  3842. hr = EnumKeys(m_hKey, lpszMDPath, lpKey, m_dwIndex++);
  3843. strKey.ReleaseBuffer();
  3844. if (SUCCEEDED(hr))
  3845. {
  3846. if (FALSE == (dwKey = _ttoi((LPCTSTR)strKey)))
  3847. {
  3848. //
  3849. // Ignore this one
  3850. //
  3851. fContinue = TRUE;
  3852. }
  3853. }
  3854. }
  3855. return hr;
  3856. }
  3857. //
  3858. // CIISApplication class
  3859. //
  3860. // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<</
  3861. CIISApplication::CIISApplication(
  3862. IN CComAuthInfo * pAuthInfo OPTIONAL,
  3863. IN LPCTSTR lpszMetapath
  3864. )
  3865. /*++
  3866. Routine Description:
  3867. Construct IIS application.
  3868. Arguments:
  3869. CComAuthInfo * pAuthInfo : Authentication info. NULL indicates the
  3870. local computer.
  3871. LPCTSTR lpszMetapath : Metabase path
  3872. Return Value:
  3873. N/A
  3874. --*/
  3875. : CWamInterface(pAuthInfo),
  3876. CMetaKey(pAuthInfo),
  3877. m_dwProcessProtection(APP_INPROC),
  3878. m_dwAppState(APPSTATUS_NOTDEFINED),
  3879. m_strFriendlyName(),
  3880. m_strAppRoot(),
  3881. m_strWamPath(lpszMetapath)
  3882. {
  3883. CommonConstruct();
  3884. }
  3885. void
  3886. CIISApplication::CommonConstruct()
  3887. /*++
  3888. Routine Description:
  3889. Perform common construction
  3890. Arguments:
  3891. None
  3892. Return Value:
  3893. None
  3894. --*/
  3895. {
  3896. //
  3897. // Munge the metapath so that WAM doesn't cough up a hairball.
  3898. //
  3899. //
  3900. // BUGBUG: CleanMetaPath() disabled currently
  3901. //
  3902. if (m_strWamPath[0] != SZ_MBN_SEP_CHAR)
  3903. {
  3904. m_strWamPath = SZ_MBN_SEP_CHAR + m_strWamPath;
  3905. }
  3906. do
  3907. {
  3908. m_hrApp = CWamInterface::QueryResult();
  3909. if (FAILED(m_hrApp))
  3910. {
  3911. break;
  3912. }
  3913. m_hrApp = RefreshAppState();
  3914. if (HRESULT_CODE(m_hrApp) == ERROR_PATH_NOT_FOUND)
  3915. {
  3916. //
  3917. // "Path Not Found" errors are acceptable, since
  3918. // the application may not yet exist.
  3919. //
  3920. m_hrApp = S_OK;
  3921. }
  3922. }
  3923. while(FALSE);
  3924. }
  3925. /* virtual */
  3926. BOOL
  3927. CIISApplication::Succeeded() const
  3928. /*++
  3929. Routine Description:
  3930. Determine if object was constructed successfully
  3931. Arguments:
  3932. None
  3933. Return Value:
  3934. TRUE for success, FALSE for failure
  3935. --*/
  3936. {
  3937. return CMetaInterface::Succeeded()
  3938. && CWamInterface::Succeeded()
  3939. && SUCCEEDED(m_hrApp);
  3940. }
  3941. /* virtual */
  3942. HRESULT
  3943. CIISApplication::QueryResult() const
  3944. /*++
  3945. Routine Description:
  3946. Return the construction error for this object
  3947. Arguments:
  3948. None
  3949. Return Value:
  3950. HRESULT from construction errors
  3951. --*/
  3952. {
  3953. //
  3954. // Both interfaces must have constructed successfully
  3955. //
  3956. HRESULT hr = CMetaInterface::QueryResult();
  3957. if (SUCCEEDED(hr))
  3958. {
  3959. hr = CWamInterface::QueryResult();
  3960. if (SUCCEEDED(hr))
  3961. {
  3962. hr = m_hrApp;
  3963. }
  3964. }
  3965. return hr;
  3966. }
  3967. HRESULT
  3968. CIISApplication::RefreshAppState()
  3969. /*++
  3970. Routine Description:
  3971. Refresh the application state
  3972. Arguments:
  3973. None
  3974. Return Value:
  3975. HRESULT
  3976. --*/
  3977. {
  3978. ASSERT(!m_strWamPath.IsEmpty());
  3979. HRESULT hr, hrKeys;
  3980. hr = AppGetStatus(m_strWamPath, &m_dwAppState);
  3981. if (FAILED(hr))
  3982. {
  3983. m_dwAppState = APPSTATUS_NOTDEFINED;
  3984. }
  3985. m_strAppRoot.Empty();
  3986. hrKeys = QueryValue(MD_APP_ROOT, m_strAppRoot, NULL, m_strWamPath);
  3987. m_dwProcessProtection = APP_INPROC;
  3988. hrKeys = QueryValue(
  3989. MD_APP_ISOLATED,
  3990. m_dwProcessProtection,
  3991. NULL,
  3992. m_strWamPath
  3993. );
  3994. hrKeys = QueryValue(
  3995. MD_APP_APPPOOL_ID,
  3996. m_strAppPoolId,
  3997. NULL,
  3998. m_strWamPath
  3999. );
  4000. m_strFriendlyName.Empty();
  4001. hrKeys = QueryValue(
  4002. MD_APP_FRIENDLY_NAME,
  4003. m_strFriendlyName,
  4004. NULL,
  4005. m_strWamPath
  4006. );
  4007. return hr;
  4008. }
  4009. HRESULT
  4010. CIISApplication::Create(
  4011. IN LPCTSTR lpszName, OPTIONAL
  4012. IN DWORD dwAppProtection
  4013. )
  4014. /*++
  4015. Routine Description:
  4016. Create the application
  4017. Arguments:
  4018. LPCTSTR lpszName : Application name
  4019. DWORD dwAppProtection : APP_INPROC to create in-proc app
  4020. APP_OUTOFPROC to create out-of-proc app
  4021. APP_POOLEDPROC to create a pooled-proc app
  4022. Return Value:
  4023. HRESULT
  4024. --*/
  4025. {
  4026. ASSERT(!m_strWamPath.IsEmpty());
  4027. HRESULT hr = AppCreate(m_strWamPath, dwAppProtection);
  4028. if (SUCCEEDED(hr))
  4029. {
  4030. //
  4031. // Write the friendly app name, which we maintain
  4032. // ourselves. Empty it first, because we might
  4033. // have picked up a name from inheritance.
  4034. //
  4035. m_strFriendlyName.Empty();
  4036. hr = WriteFriendlyName(lpszName);
  4037. RefreshAppState();
  4038. }
  4039. return hr;
  4040. }
  4041. HRESULT
  4042. CIISApplication::CreatePooled(
  4043. LPCTSTR name,
  4044. DWORD mode,
  4045. LPCTSTR pool_id,
  4046. BOOL fCreatePool)
  4047. {
  4048. ASSERT(!m_strWamPath.IsEmpty());
  4049. ASSERT(NULL != pool_id);
  4050. HRESULT hr = CreateApplication(m_strWamPath, mode, pool_id, fCreatePool);
  4051. if (SUCCEEDED(hr))
  4052. {
  4053. m_strFriendlyName.Empty();
  4054. hr = WriteFriendlyName(name);
  4055. RefreshAppState();
  4056. }
  4057. return hr;
  4058. }
  4059. HRESULT
  4060. CIISApplication::WriteFriendlyName(
  4061. IN LPCTSTR lpszName
  4062. )
  4063. /*++
  4064. Routine Description:
  4065. Write the friendly name. This will not write anything
  4066. if the name is the same as it was
  4067. Arguments:
  4068. LPCTSTR lpszName : New friendly name
  4069. Return Value:
  4070. HRESULT
  4071. --*/
  4072. {
  4073. HRESULT hr = S_OK;
  4074. if (m_strFriendlyName.CompareNoCase(lpszName) != 0)
  4075. {
  4076. hr = Open(METADATA_PERMISSION_WRITE, m_strWamPath);
  4077. if (SUCCEEDED(hr))
  4078. {
  4079. ASSERT_PTR(lpszName);
  4080. CString str(lpszName);
  4081. hr = SetValue(MD_APP_FRIENDLY_NAME, str);
  4082. Close();
  4083. if (SUCCEEDED(hr))
  4084. {
  4085. m_strFriendlyName = lpszName;
  4086. }
  4087. }
  4088. }
  4089. return hr;
  4090. }
  4091. HRESULT
  4092. CIISApplication::WritePoolId(LPCTSTR id)
  4093. {
  4094. HRESULT hr = S_OK;
  4095. if (m_strAppPoolId.CompareNoCase(id) != 0)
  4096. {
  4097. hr = Open(METADATA_PERMISSION_WRITE, m_strWamPath);
  4098. if (SUCCEEDED(hr))
  4099. {
  4100. ASSERT_PTR(id);
  4101. CString str(id);
  4102. hr = SetValue(MD_APP_APPPOOL_ID, str);
  4103. Close();
  4104. if (SUCCEEDED(hr))
  4105. {
  4106. m_strAppPoolId = id;
  4107. }
  4108. }
  4109. }
  4110. return hr;
  4111. }
  4112. /////////////////////////////////////////////////////////
  4113. // CIISAppPool class
  4114. CIISAppPool::CIISAppPool(
  4115. IN CComAuthInfo * pAuthInfo OPTIONAL,
  4116. IN LPCTSTR lpszMetapath
  4117. )
  4118. /*++
  4119. Routine Description:
  4120. Construct IIS application pool.
  4121. Arguments:
  4122. CComAuthInfo * pAuthInfo : Authentication info. NULL indicates the
  4123. local computer.
  4124. LPCTSTR lpszMetapath : Metabase path
  4125. Return Value:
  4126. N/A
  4127. --*/
  4128. : CWamInterface(pAuthInfo),
  4129. CMetaKey(pAuthInfo),
  4130. m_dwPoolState(0),
  4131. m_strWamPath(lpszMetapath)
  4132. {
  4133. if (m_strWamPath[0] != SZ_MBN_SEP_CHAR)
  4134. {
  4135. m_strWamPath = SZ_MBN_SEP_CHAR + m_strWamPath;
  4136. }
  4137. do
  4138. {
  4139. if (FAILED(m_hrPool = CWamInterface::QueryResult()))
  4140. {
  4141. break;
  4142. }
  4143. if (MD_ERROR_DATA_NOT_FOUND == (m_hrPool = RefreshState())
  4144. || HRESULT_CODE(m_hrPool) == ERROR_PATH_NOT_FOUND)
  4145. {
  4146. //
  4147. // "Path Not Found" errors are acceptable, since
  4148. // the pool may not yet exist.
  4149. //
  4150. m_hrPool = S_OK;
  4151. }
  4152. }
  4153. while(FALSE);
  4154. }
  4155. HRESULT
  4156. CIISAppPool::RefreshState()
  4157. {
  4158. ASSERT(!m_strWamPath.IsEmpty());
  4159. HRESULT hr;
  4160. hr = QueryValue(
  4161. MD_APP_APPPOOL_ID,
  4162. m_strAppPoolId,
  4163. NULL,
  4164. m_strWamPath
  4165. );
  4166. return hr;
  4167. }
  4168. /* virtual */
  4169. HRESULT
  4170. CIISAppPool::QueryResult() const
  4171. /*++
  4172. Routine Description:
  4173. Return the construction error for this object
  4174. Arguments:
  4175. None
  4176. Return Value:
  4177. HRESULT from construction errors
  4178. --*/
  4179. {
  4180. //
  4181. // Both interfaces must have constructed successfully
  4182. //
  4183. HRESULT hr = CMetaInterface::QueryResult();
  4184. if (SUCCEEDED(hr))
  4185. {
  4186. hr = CWamInterface::QueryResult();
  4187. if (SUCCEEDED(hr))
  4188. {
  4189. hr = m_hrPool;
  4190. }
  4191. }
  4192. return hr;
  4193. }
  4194. /* virtual */
  4195. BOOL
  4196. CIISAppPool::Succeeded() const
  4197. /*++
  4198. Routine Description:
  4199. Determine if object was constructed successfully
  4200. Arguments:
  4201. None
  4202. Return Value:
  4203. TRUE for success, FALSE for failure
  4204. --*/
  4205. {
  4206. return CMetaInterface::Succeeded()
  4207. && CWamInterface::Succeeded()
  4208. && SUCCEEDED(m_hrPool);
  4209. }
  4210. HRESULT
  4211. CIISAppPool::EnumerateApplications(CStringListEx& apps)
  4212. {
  4213. CString pool;
  4214. BSTR bstr = NULL;
  4215. CMetabasePath::GetLastNodeName(m_strWamPath, pool);
  4216. CError err = CWamInterface::EnumerateApplicationsInPool(
  4217. pool, &bstr);
  4218. if (err.Succeeded())
  4219. {
  4220. ConvertDoubleNullListToStringList(bstr, apps);
  4221. }
  4222. #ifdef _DEBUG
  4223. err.MessageBoxOnFailure();
  4224. #endif
  4225. SysFreeString(bstr);
  4226. return err;
  4227. }
  4228. HRESULT
  4229. CIISAppPool::Create(LPCTSTR name)
  4230. {
  4231. CString id;
  4232. if (name != NULL)
  4233. {
  4234. id = name;
  4235. }
  4236. else
  4237. {
  4238. CMetabasePath::GetLastNodeName(m_strWamPath, id);
  4239. }
  4240. CError err = CWamInterface::CreateApplicationPool(id);
  4241. return err;
  4242. }
  4243. HRESULT
  4244. CIISAppPool::Delete(LPCTSTR id)
  4245. {
  4246. CError err = CWamInterface::DeleteApplicationPool(id);
  4247. return err;
  4248. }
  4249. HRESULT
  4250. CIISAppPool::Recycle(LPCTSTR id)
  4251. {
  4252. CError err = CWamInterface::RecycleApplicationPool(id);
  4253. return err;
  4254. }
  4255. HRESULT
  4256. CIISAppPool::GetProcessMode(DWORD * pdwMode)
  4257. {
  4258. CError err = CWamInterface::GetProcessMode(pdwMode);
  4259. return err;
  4260. }