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.

2039 lines
61 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // File: NcCPS.CPP
  4. //
  5. // Module: NetOC.DLL
  6. //
  7. // Synopsis: Implements the dll entry points required to integrate into
  8. // NetOC.DLL the installation of the following components.
  9. //
  10. // NETCPS
  11. //
  12. // Copyright (C) Microsoft Corporation. All rights reserved.
  13. //
  14. // Author: a-anasj 9 Mar 1998
  15. //
  16. //+---------------------------------------------------------------------------
  17. #include "pch.h"
  18. #pragma hdrstop
  19. #include <iadmw.h> // Interface header
  20. #include <iiscnfg.h> // MD_ & IIS_MD_ defines
  21. #include <LOADPERF.H>
  22. #include <atlbase.h>
  23. extern CComModule _Module;
  24. #include <atlcom.h>
  25. #include "ncatl.h"
  26. #include "resource.h"
  27. #include "nccm.h"
  28. //
  29. // Define Globals
  30. //
  31. WCHAR g_szProgramFiles[MAX_PATH+1];
  32. //
  33. // Define Constants
  34. //
  35. static const WCHAR c_szInetRegPath[] = L"Software\\Microsoft\\InetStp";
  36. static const WCHAR c_szWWWRootValue[] = L"PathWWWRoot";
  37. static const WCHAR c_szSSFmt[] = L"%s%s";
  38. static const WCHAR c_szMsAccess[] = L"Microsoft Access";
  39. static const WCHAR c_szOdbcDataSourcesPath[] = L"SOFTWARE\\ODBC\\ODBC.INI\\ODBC Data Sources";
  40. static const WCHAR c_szPbServer[] = L"PBServer";
  41. static const WCHAR c_szOdbcInstKey[] = L"SOFTWARE\\ODBC\\ODBCINST.INI";
  42. static const WCHAR c_szWwwRootPath[] = L"\\Inetpub\\wwwroot";
  43. static const WCHAR c_szWwwRoot[] = L"\\wwwroot";
  44. static const WCHAR c_szPbsRootPath[] = L"\\Phone Book Service";
  45. static const WCHAR c_szPbsBinPath[] = L"\\Phone Book Service\\Bin";
  46. static const WCHAR c_szPbsDataPath[] = L"\\Phone Book Service\\Data";
  47. static const WCHAR c_szOdbcPbserver[] = L"Software\\ODBC\\odbc.ini\\pbserver";
  48. const DWORD c_dwCpsDirID = 123175; // just must be larger than DIRID_USER = 0x8000;
  49. static const WCHAR c_szPBSAppPoolID[] = L"PBSAppPool";
  50. static const WCHAR c_szPBSGroupID[] = L"PBS";
  51. static const WCHAR c_szPBSGroupDescription[] = L"Phone Book Service";
  52. static const WCHAR c_szAppPoolKey[] = L"IIsApplicationPool";
  53. static const WCHAR c_szPerfMonAppName[] = L"%SystemRoot%\\System32\\lodctr.exe";
  54. static const WCHAR c_szPerfMonIniFile[] = L"CPSSym.ini";
  55. //+---------------------------------------------------------------------------
  56. //
  57. // Function: SetPrivilege
  58. //
  59. // Notes: lifted unchanged from MSDN (used by TakeOwnershipOfRegKey)
  60. //
  61. BOOL SetPrivilege(
  62. HANDLE hToken, // access token handle
  63. LPCTSTR lpszPrivilege, // name of privilege to enable/disable
  64. BOOL bEnablePrivilege // to enable or disable privilege
  65. )
  66. {
  67. TOKEN_PRIVILEGES tp;
  68. LUID luid;
  69. if ( !LookupPrivilegeValue(
  70. NULL, // lookup privilege on local system
  71. lpszPrivilege, // privilege to lookup
  72. &luid ) ) // receives LUID of privilege
  73. {
  74. printf("LookupPrivilegeValue error: %u\n", GetLastError() );
  75. return FALSE;
  76. }
  77. tp.PrivilegeCount = 1;
  78. tp.Privileges[0].Luid = luid;
  79. if (bEnablePrivilege)
  80. tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  81. else
  82. tp.Privileges[0].Attributes = 0;
  83. // Enable the privilege or disable all privileges.
  84. if ( !AdjustTokenPrivileges(
  85. hToken,
  86. FALSE,
  87. &tp,
  88. sizeof(TOKEN_PRIVILEGES),
  89. (PTOKEN_PRIVILEGES) NULL,
  90. (PDWORD) NULL) )
  91. {
  92. printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
  93. return FALSE;
  94. }
  95. return TRUE;
  96. }
  97. //+---------------------------------------------------------------------------
  98. //
  99. // Function: TakeOwnershipOfRegKey
  100. //
  101. // Purpose: There is an old registry key that we can't delete because it doesn't
  102. // inherit permissions. Take ownership of it so it can be deleted.
  103. //
  104. // Arguments:
  105. // pszKey [in] string representing reg key
  106. //
  107. // Returns: S_OK if successful, Win32 error otherwise.
  108. //
  109. // Author: SumitC 4-Dec-2002
  110. //
  111. // Notes:
  112. //
  113. HRESULT TakeOwnershipOfRegKey(LPWSTR pszRegKey)
  114. {
  115. HRESULT hr = S_OK;
  116. DWORD dwRes = ERROR_SUCCESS;
  117. PSID psidAdmin = NULL;
  118. PACL pACL = NULL;
  119. HANDLE hToken = NULL;
  120. EXPLICIT_ACCESS ea = {0} ;
  121. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  122. //
  123. // from MSDN, the following is "the way" to take ownership of an object
  124. //
  125. BOOL bRet = AllocateAndInitializeSid (&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
  126. DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdmin);
  127. if (!bRet || !psidAdmin)
  128. {
  129. dwRes = GetLastError();
  130. TraceError("TakeOwnershipOfRegKey - AllocateAndInitializeSid failed, GLE=%u", dwRes);
  131. goto Cleanup;
  132. }
  133. // Open a handle to the access token for the calling process.
  134. if (!OpenProcessToken(GetCurrentProcess(),
  135. TOKEN_ADJUST_PRIVILEGES,
  136. &hToken))
  137. {
  138. dwRes = GetLastError();
  139. TraceError("TakeOwnershipOfRegKey - OpenProcessToken failed with, GLE=%u", dwRes);
  140. goto Cleanup;
  141. }
  142. // Enable the SE_TAKE_OWNERSHIP_NAME privilege.
  143. if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))
  144. {
  145. dwRes = GetLastError();
  146. TraceError("TakeOwnershipOfRegKey - SetPrivilege to takeownership failed, GLE=%u", dwRes);
  147. goto Cleanup;
  148. }
  149. // Set the owner in the object's security descriptor.
  150. dwRes = SetNamedSecurityInfo(pszRegKey, // name of the object
  151. SE_REGISTRY_KEY, // type of object
  152. OWNER_SECURITY_INFORMATION, // change only the object's owner
  153. psidAdmin, // SID of Administrators
  154. NULL,
  155. NULL,
  156. NULL);
  157. // Disable the SE_TAKE_OWNERSHIP_NAME privilege.
  158. if (!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))
  159. {
  160. dwRes = GetLastError();
  161. TraceError("TakeOwnershipOfRegKey - SetPrivilege to revoke takeownership failed, GLE=%u", dwRes);
  162. goto Cleanup;
  163. }
  164. // NOTE: I'm doing it in this order to make sure the SetPrivilege gets reverted
  165. // even if SetNamedSecurityInfo fails.
  166. if (ERROR_SUCCESS != dwRes)
  167. {
  168. TraceError("TakeOwnershipOfRegKey - SetNamedSecurityInfo failed, GLE=%u", dwRes);
  169. if (ERROR_FILE_NOT_FOUND == dwRes)
  170. {
  171. // probably upgrading from a post-Win2k build. Anyway, if the reg
  172. // key doesn't exist, there's nothing to do, so exit without an error
  173. dwRes = 0;
  174. }
  175. goto Cleanup;
  176. }
  177. // create an ACL to give ownership to admins
  178. // Set full control for Administrators.
  179. ea.grfAccessPermissions = GENERIC_ALL;
  180. ea.grfAccessMode = SET_ACCESS;
  181. ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  182. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  183. ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  184. ea.Trustee.ptstrName = (LPTSTR) psidAdmin;
  185. dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
  186. if (ERROR_SUCCESS != dwRes)
  187. {
  188. TraceError("TakeOwnershipOfRegKey - couldn't create needed ACL, GLE=%u", dwRes);
  189. goto Cleanup;
  190. }
  191. //
  192. // Now change the DACL to allow deletion
  193. //
  194. dwRes = SetNamedSecurityInfo(pszRegKey, // name of the object
  195. SE_REGISTRY_KEY, // type of object
  196. DACL_SECURITY_INFORMATION, // type of information to set
  197. NULL, // pointer to the new owner SID
  198. NULL, // pointer to the new primary group SID
  199. pACL, // pointer to new DACL
  200. NULL); // pointer to new SACL
  201. if (ERROR_SUCCESS != dwRes)
  202. {
  203. TraceError("TakeOwnershipOfRegKey - tried to change DACL for PBS reg key under ODBC, GLE=%u", dwRes);
  204. goto Cleanup;
  205. }
  206. // successfully changed DACL
  207. Cleanup:
  208. if (psidAdmin)
  209. {
  210. FreeSid(psidAdmin);
  211. }
  212. if (pACL)
  213. {
  214. LocalFree(pACL);
  215. }
  216. if (hToken)
  217. {
  218. CloseHandle(hToken);
  219. }
  220. if (dwRes != ERROR_SUCCESS)
  221. {
  222. hr = HRESULT_FROM_WIN32(dwRes);
  223. }
  224. TraceError("TakeOwnershipOfRegKey", hr);
  225. return hr;
  226. }
  227. //+---------------------------------------------------------------------------
  228. //
  229. // Function: HrOcCpsPreQueueFiles
  230. //
  231. // Purpose: Called by optional components installer code to handle
  232. // additional installation requirements for PhoneBook Server.
  233. //
  234. // Arguments:
  235. // pnocd [in] Pointer to NETOC data.
  236. //
  237. // Returns: S_OK if successful, Win32 error otherwise.
  238. //
  239. // Author: quintinb 18 Sep 1998
  240. //
  241. // Notes:
  242. //
  243. HRESULT HrOcCpsPreQueueFiles(PNETOCDATA pnocd)
  244. {
  245. HRESULT hr = S_OK;
  246. switch ( pnocd->eit )
  247. {
  248. case IT_UPGRADE:
  249. case IT_INSTALL:
  250. case IT_REMOVE:
  251. // We need to setup the custom DIRID so that CPS will install
  252. // to the correct location. First get the path from the system.
  253. //
  254. ZeroMemory(g_szProgramFiles, sizeof(g_szProgramFiles));
  255. hr = SHGetSpecialFolderPath(NULL, g_szProgramFiles, CSIDL_PROGRAM_FILES, FALSE);
  256. if (SUCCEEDED(hr))
  257. {
  258. // Next Create the CPS Dir ID
  259. //
  260. if (SUCCEEDED(hr))
  261. {
  262. hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd);
  263. if (SUCCEEDED(hr))
  264. {
  265. if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwCpsDirID, g_szProgramFiles))
  266. {
  267. hr = HRESULT_FROM_WIN32(GetLastError());
  268. }
  269. }
  270. }
  271. // Before proceeding, make sure that setting the DIRID worked. CPS's
  272. // INF file is hosed if the DIRID isn't set.
  273. //
  274. if (SUCCEEDED(hr))
  275. {
  276. if (IT_UPGRADE == pnocd->eit)
  277. {
  278. hr = HrMoveOldCpsInstall(g_szProgramFiles);
  279. TraceError("HrOcCpsPreQueueFiles - HrMoveOldCpsInstall failed, hr=%u", hr);
  280. // we'll say that failing to move the old install is not fatal
  281. // On Win2k, some registry keys end up with permissions so that
  282. // they can't be removed, and this causes upgrade failures,
  283. // so we have to take ownership of said registry key(s)
  284. //
  285. WCHAR szPBSKey[MAX_PATH+1];
  286. lstrcpy(szPBSKey, L"MACHINE\\");
  287. lstrcat(szPBSKey, c_szOdbcPbserver);
  288. hr = TakeOwnershipOfRegKey(szPBSKey);
  289. }
  290. }
  291. }
  292. break;
  293. }
  294. TraceError("HrOcCpsPreQueueFiles", hr);
  295. return hr;
  296. }
  297. //+---------------------------------------------------------------------------
  298. //
  299. // Function: HrMoveOldCpsInstall
  300. //
  301. // Purpose: This function moves the old cps directory to the new cps directory
  302. // location. Because of the problems with Front Page Extensions and
  303. // directory permissions we moved our install directory out from under
  304. // wwwroot to Program Files instead.
  305. //
  306. // Arguments:
  307. // pszprogramFiles [in]
  308. //
  309. // Returns: S_OK if successful, Win32 error otherwise.
  310. //
  311. // Author: quintinb 26 Jan 1999
  312. //
  313. // Notes:
  314. //
  315. HRESULT HrMoveOldCpsInstall(PCWSTR pszProgramFiles)
  316. {
  317. WCHAR szOldCpsLocation[MAX_PATH+1];
  318. WCHAR szNewCpsLocation[MAX_PATH+1];
  319. WCHAR szTemp[MAX_PATH+1];
  320. SHFILEOPSTRUCT fOpStruct;
  321. HRESULT hr = S_OK;
  322. if ((NULL == pszProgramFiles) || (L'\0' == pszProgramFiles[0]))
  323. {
  324. return E_INVALIDARG;
  325. }
  326. //
  327. // First, lets build the old CPS location
  328. //
  329. hr = HrGetWwwRootDir(szTemp, celems(szTemp));
  330. if (SUCCEEDED(hr))
  331. {
  332. //
  333. // Zero the string buffers
  334. //
  335. ZeroMemory(szOldCpsLocation, celems(szOldCpsLocation));
  336. ZeroMemory(szNewCpsLocation, celems(szNewCpsLocation));
  337. wsprintfW(szOldCpsLocation, c_szSSFmt, szTemp, c_szPbsRootPath);
  338. //
  339. // Now check to see if the old cps location exists
  340. //
  341. DWORD dwDirectoryAttributes = GetFileAttributes(szOldCpsLocation);
  342. //
  343. // If we didn't get back -1 (error return code for GetFileAttributes), check to
  344. // see if we have a directory. If so, go ahead and copy the data over.
  345. //
  346. if ((-1 != dwDirectoryAttributes) && (dwDirectoryAttributes & FILE_ATTRIBUTE_DIRECTORY))
  347. {
  348. //
  349. // Now build the new cps location
  350. //
  351. wsprintfW(szNewCpsLocation, c_szSSFmt, pszProgramFiles, c_szPbsRootPath);
  352. //
  353. // Now copy the old files to the new location
  354. //
  355. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  356. fOpStruct.hwnd = NULL;
  357. fOpStruct.wFunc = FO_COPY;
  358. fOpStruct.pTo = szNewCpsLocation;
  359. fOpStruct.pFrom = szOldCpsLocation;
  360. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
  361. if (0== SHFileOperation(&fOpStruct))
  362. {
  363. //
  364. // Now delete the original directory
  365. //
  366. fOpStruct.pTo = NULL;
  367. fOpStruct.wFunc = FO_DELETE;
  368. if (0 != SHFileOperation(&fOpStruct))
  369. {
  370. hr = S_FALSE;
  371. }
  372. }
  373. else
  374. {
  375. //
  376. // Note, SHFileOperation isn't guaranteed to return anything sensible here. We might
  377. // get back ERROR_NO_TOKEN or ERROR_INVALID_HANDLE, etc when the directory is just missing.
  378. // The following check probably isn't useful anymore because of this but I will leave it just
  379. // in case. Hopefully the file check above will make sure we don't hit this but ...
  380. //
  381. DWORD dwError = GetLastError();
  382. if ((ERROR_FILE_NOT_FOUND == dwError) || (ERROR_PATH_NOT_FOUND == dwError))
  383. {
  384. //
  385. // Then we couldn't find the old dir to move it. Not fatal.
  386. //
  387. hr = S_FALSE;
  388. }
  389. else
  390. {
  391. hr = HRESULT_FROM_WIN32(dwError);
  392. }
  393. }
  394. }
  395. else
  396. {
  397. //
  398. // Then we couldn't find the old dir to move it. Not fatal.
  399. //
  400. hr = S_FALSE;
  401. }
  402. }
  403. return hr;
  404. }
  405. //+---------------------------------------------------------------------------
  406. //
  407. // Function: HrGetWwwRootDir
  408. //
  409. // Purpose: This function retrieves the location of the InetPub\wwwroot dir from the
  410. // WwwRootDir registry key.
  411. //
  412. // Arguments:
  413. // szInetPub [out] String Buffer to hold the InetPub dir path
  414. // uInetPubCount [in] number of chars in the output buffer
  415. //
  416. // Returns: S_OK if successful, Win32 error otherwise.
  417. //
  418. // Author: quintinb 26 Jan 1999
  419. //
  420. // Notes:
  421. //
  422. HRESULT HrGetWwwRootDir(PWSTR szWwwRoot, UINT uWwwRootCount)
  423. {
  424. HKEY hKey;
  425. HRESULT hr = S_OK;
  426. //
  427. // Check input params
  428. //
  429. if ((NULL == szWwwRoot) || (0 == uWwwRootCount))
  430. {
  431. return E_INVALIDARG;
  432. }
  433. //
  434. // Set the strings to empty
  435. //
  436. szWwwRoot[0] = L'\0';
  437. //
  438. // First try to open the InetStp key and get the wwwroot value.
  439. //
  440. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szInetRegPath, KEY_READ, &hKey);
  441. if (SUCCEEDED(hr))
  442. {
  443. DWORD dwSize = uWwwRootCount * sizeof(WCHAR);
  444. RegQueryValueExW(hKey, c_szWWWRootValue, NULL, NULL, (LPBYTE)szWwwRoot, &dwSize);
  445. RegCloseKey(hKey);
  446. hr = S_OK;
  447. }
  448. if (L'\0' == szWwwRoot[0])
  449. {
  450. // Well, we didn't get anything from the registry, lets try building the default.
  451. //
  452. WCHAR szTemp[MAX_PATH+1];
  453. if (GetWindowsDirectory(szTemp, MAX_PATH))
  454. {
  455. // Get the drive that the windows dir is on using _tsplitpath
  456. //
  457. WCHAR szDrive[_MAX_DRIVE+1];
  458. _wsplitpath(szTemp, szDrive, NULL, NULL, NULL);
  459. if (uWwwRootCount > (UINT)(lstrlenW(szDrive) + lstrlenW (c_szWwwRootPath) + 1))
  460. {
  461. wsprintfW(szWwwRoot, c_szSSFmt, szDrive, c_szWwwRootPath);
  462. hr = S_OK;
  463. }
  464. else
  465. {
  466. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  467. }
  468. }
  469. else
  470. {
  471. hr = HRESULT_FROM_WIN32(GetLastError());
  472. }
  473. }
  474. return hr;
  475. }
  476. //+---------------------------------------------------------------------------
  477. //
  478. // Function: HrOcCpsOnInstall
  479. //
  480. // Purpose: Called by optional components installer code to handle
  481. // additional installation requirements for PhoneBook Server.
  482. //
  483. // Arguments:
  484. // pnocd [in] Pointer to NETOC data.
  485. //
  486. // Returns: S_OK if successful, Win32 error otherwise.
  487. //
  488. // Author: a-anasj 9 Mar 1998
  489. //
  490. // Notes:
  491. //
  492. HRESULT HrOcCpsOnInstall(PNETOCDATA pnocd)
  493. {
  494. HRESULT hr = S_OK;
  495. DWORD dwRet = 0;
  496. BOOL bRet = FALSE;
  497. switch (pnocd->eit)
  498. {
  499. case IT_INSTALL:
  500. case IT_UPGRADE:
  501. {
  502. // Register MS_Access data source
  503. //
  504. dwRet = RegisterPBServerDataSource();
  505. if ( NULL == dwRet)
  506. {
  507. hr = S_FALSE;
  508. }
  509. // Load Perfomance Monitor Counters
  510. //
  511. bRet = LoadPerfmonCounters();
  512. if (FALSE == bRet)
  513. {
  514. hr = S_FALSE;
  515. }
  516. // Create Virtual WWW and FTP roots
  517. //
  518. if (IT_UPGRADE == pnocd->eit)
  519. {
  520. //
  521. // If this is an upgrade, we must first delete the old Virtual Roots
  522. // before we can create new ones.
  523. //
  524. RemoveCPSVRoots();
  525. }
  526. dwRet = CreateCPSVRoots();
  527. if (FALSE == dwRet)
  528. {
  529. hr = S_FALSE;
  530. }
  531. SetCpsDirPermissions();
  532. //
  533. // Place PBS in its own Application Pool
  534. //
  535. if (S_OK != CreateNewAppPoolAndAddPBS())
  536. {
  537. hr = S_FALSE;
  538. }
  539. //
  540. // Work with IIS's Security Lockdown wizard to enable ISAPI requests to ourselves
  541. //
  542. if (S_OK != EnableISAPIRequests(pnocd->strDesc.c_str()))
  543. {
  544. hr = S_FALSE;
  545. }
  546. }
  547. break;
  548. case IT_REMOVE:
  549. // Remove the Virtual Directories, so access to the service is stopped.
  550. //
  551. RemoveCPSVRoots();
  552. //
  553. // Delete PBS's Application pool
  554. //
  555. (void) DeleteAppPool();
  556. //
  557. // Fire up our worker process to tell IIS not to accept PBS requests anymore
  558. //
  559. hr = UseProcessToEnableDisablePBS(FALSE); // FALSE => disable
  560. if (S_OK != hr)
  561. {
  562. // Bah Humbug
  563. TraceError("HrOcCpsOnInstall - disabling PBS failed, probably already removed", hr);
  564. hr = S_FALSE;
  565. }
  566. break;
  567. }
  568. TraceError("HrOcCpsOnInstall", hr);
  569. return hr;
  570. }
  571. //+---------------------------------------------------------------------------
  572. //
  573. // Function: LoadPerfmonCounters
  574. //
  575. // Purpose: Do whatever is neccessary to make the performance monitor Display the PBServerMonitor counters
  576. //
  577. // Arguments:
  578. //
  579. // Returns: BOOL TRUE if successful, Not TRUE otherwise.
  580. //
  581. // Author: a-anasj Mar 9/1998
  582. //
  583. // Notes: One of the installation requirements for PhoneBook Server.
  584. // is to load the perfomance monitor counters that allow PBServerMonitor
  585. // to report to the user on PhoneBook Server performance.
  586. // In this function we add the services registry entry first then we
  587. // call into LoadPerf.Dll to load the counters for us. The order is imperative.
  588. // I then add other registry entries related to PBServerMonitor.
  589. //
  590. BOOL LoadPerfmonCounters()
  591. {
  592. SHELLEXECUTEINFO sei = { 0 };
  593. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  594. sei.fMask = SEE_MASK_DOENVSUBST;
  595. sei.lpFile = c_szPerfMonAppName;
  596. sei.lpParameters = c_szPerfMonIniFile;
  597. sei.nShow = SW_HIDE;
  598. return ShellExecuteEx(&sei);
  599. }
  600. //+---------------------------------------------------------------------------
  601. //
  602. // Function: RegisterPBServerDataSource
  603. //
  604. // Purpose: Registers PBServer.
  605. //
  606. // Arguments: None
  607. //
  608. // Returns: Win32 error code
  609. //
  610. // Author: a-anasj 9 Mar 1998
  611. //
  612. // Notes:
  613. // History: 7-9-97 a-frankh Created
  614. // 10/4/97 mmaguire RAID #19906 - Totally restructured to include error handling
  615. // 5-14-98 quintinb removed unnecessary comments and cleaned up the function.
  616. //
  617. BOOL RegisterPBServerDataSource()
  618. {
  619. DWORD dwRet = 0;
  620. HKEY hkODBCInst = NULL;
  621. HKEY hkODBCDataSources = NULL;
  622. DWORD dwIndex;
  623. WCHAR szName[MAX_PATH+1];
  624. __try
  625. {
  626. // Open the hkODBCInst RegKey
  627. //
  628. dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, c_szOdbcInstKey, &hkODBCInst);
  629. if((ERROR_SUCCESS != dwRet) || (NULL == hkODBCInst))
  630. {
  631. __leave;
  632. }
  633. // Look to see the the "Microsoft Access" RegKey is defined
  634. // If it is, then set the value of the ODBC Data Sources RegKey below
  635. //
  636. dwIndex = 0;
  637. do
  638. {
  639. dwRet = RegEnumKey(hkODBCInst,dwIndex,szName,celems(szName));
  640. dwIndex++;
  641. } while ((ERROR_SUCCESS == dwRet) && (NULL == wcsstr(szName, c_szMsAccess)));
  642. if ( ERROR_SUCCESS != dwRet )
  643. {
  644. // We need the Microsoft Access *.mdb driver to work
  645. // and we could not find it
  646. //
  647. __leave;
  648. }
  649. // Open the hkODBCDataSources RegKey
  650. //
  651. dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, c_szOdbcDataSourcesPath,
  652. &hkODBCDataSources);
  653. if( ERROR_SUCCESS != dwRet )
  654. {
  655. __leave;
  656. }
  657. //
  658. // Use the name from the resource for registration purposes.
  659. //
  660. // NOTE: this string is from HKLM\Software\ODBC\ODBCINST.INI\*
  661. //
  662. lstrcpy(szName, SzLoadIds(IDS_OC_PB_DSN_NAME));
  663. // Set values in the hkODBCDataSources key
  664. //
  665. dwRet = RegSetValueEx(hkODBCDataSources, c_szPbServer, 0, REG_SZ,
  666. (LPBYTE)szName, (lstrlenW(szName)+1)*sizeof(WCHAR));
  667. if( ERROR_SUCCESS != dwRet )
  668. {
  669. __leave;
  670. }
  671. } // end __try
  672. __finally
  673. {
  674. if (hkODBCInst)
  675. {
  676. RegCloseKey (hkODBCInst);
  677. }
  678. if (hkODBCDataSources)
  679. {
  680. RegCloseKey (hkODBCDataSources);
  681. }
  682. }
  683. return (ERROR_SUCCESS == dwRet);
  684. }
  685. //+---------------------------------------------------------------------------
  686. //
  687. // Function: CreateCPSVRoots
  688. //
  689. // Purpose: Creates the Virtual Directories required for Phone Book Service.
  690. //
  691. // Arguments: None
  692. //
  693. // Returns: TRUE if successful, FALSE otherwise.
  694. //
  695. // Author: a-anasj Mar 9/1998
  696. //
  697. // Notes:
  698. //
  699. BOOL CreateCPSVRoots()
  700. {
  701. // QBBUG - Should we make sure the physical paths exist before pointing a virtual root to them?
  702. WCHAR szPath[MAX_PATH+1];
  703. HRESULT hr;
  704. if (L'\0' == g_szProgramFiles[0])
  705. {
  706. return FALSE;
  707. }
  708. // Create the Bindir virtual root
  709. //
  710. wsprintfW(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsBinPath);
  711. hr = AddNewVirtualRoot(www, L"PBServer", szPath);
  712. if (S_OK != hr)
  713. {
  714. return FALSE;
  715. }
  716. // Now we set the Execute access permissions on the PBServer Virtual Root
  717. //
  718. PWSTR szVirtDir;
  719. szVirtDir = L"/LM/W3svc/1/ROOT/PBServer";
  720. SetVirtualRootAccessPermissions( szVirtDir, MD_ACCESS_EXECUTE | MD_ACCESS_READ);
  721. // Create the Data dir virtual roots
  722. //
  723. wsprintfW(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsDataPath);
  724. hr = AddNewVirtualRoot(www, L"PBSData", szPath);
  725. if (S_OK != hr)
  726. {
  727. return FALSE;
  728. }
  729. hr = AddNewVirtualRoot(ftp, L"PBSData", szPath);
  730. if (S_OK != hr)
  731. {
  732. return FALSE;
  733. }
  734. // Now we set the Execute access permissions on the PBServer Virtual Root
  735. //
  736. szVirtDir = L"/LM/MSFTPSVC/1/ROOT/PBSData";
  737. hr = SetVirtualRootAccessPermissions(szVirtDir, MD_ACCESS_READ);
  738. if (S_OK != hr)
  739. {
  740. TraceTag(ttidNetOc, "CreateCPSVRoots - SetVirtualRootAccessPermissions failed with 0x%x", hr);
  741. }
  742. // And disable anonymous FTP
  743. //
  744. szVirtDir = L"/LM/MSFTPSVC/1";
  745. hr = SetVirtualRootNoAnonymous(szVirtDir);
  746. if (S_OK != hr)
  747. {
  748. TraceTag(ttidNetOc, "CreateCPSVRoots - SetVirtualRootNoAnonymous failed with 0x%x", hr);
  749. }
  750. return 1;
  751. }
  752. //+---------------------------------------------------------------------------
  753. //
  754. // The following are neccessary defines, define guids and typedefs enums
  755. // they are created for the benefit of AddNewVirtualRoot()
  756. //+---------------------------------------------------------------------------
  757. #define error_leave(x) goto leave_routine;
  758. #define MY_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  759. EXTERN_C const GUID name \
  760. = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
  761. MY_DEFINE_GUID(CLSID_MSAdminBase, 0xa9e69610, 0xb80d, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50);
  762. MY_DEFINE_GUID(IID_IMSAdminBase, 0x70b51430, 0xb6ca, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50);
  763. //+---------------------------------------------------------------------------
  764. //
  765. // Function: AddNewVirtualRoot
  766. //
  767. // Purpose: Helps create Virtual Roots in the WWW and FTP services.
  768. //
  769. // Arguments:
  770. // PWSTR szDirW : Alias of new Virtual Root
  771. // PWSTR szPathW: Physical Path to wich the new Virtual Root will point
  772. //
  773. // Returns: S_OK if successful, Win32 error otherwise.
  774. //
  775. // Author: a-anasj Mar 9/1998
  776. //
  777. // Notes:
  778. //
  779. HRESULT AddNewVirtualRoot(e_rootType rootType, PWSTR szDirW, PWSTR szPathW)
  780. {
  781. HRESULT hr = S_OK;
  782. IMSAdminBase *pIMeta = NULL;
  783. METADATA_HANDLE hMeta = NULL; // handle to metabase
  784. PWSTR szMBPathW;
  785. if (www == rootType)
  786. {
  787. szMBPathW = L"/LM/W3svc/1/ROOT";
  788. }
  789. else if (ftp == rootType)
  790. {
  791. szMBPathW = L"/LM/MSFTPSVC/1/ROOT";
  792. }
  793. else
  794. {
  795. // Unknown root type
  796. //
  797. ASSERT(FALSE);
  798. return S_FALSE;
  799. }
  800. if (FAILED(CoInitialize(NULL)))
  801. {
  802. return S_FALSE;
  803. }
  804. // Create an instance of the metabase object
  805. hr=::CoCreateInstance(CLSID_MSAdminBase,//CLSID_MSAdminBase,
  806. NULL,
  807. CLSCTX_ALL,
  808. IID_IMSAdminBase,
  809. (void **)&pIMeta);
  810. if (FAILED(hr))
  811. {
  812. error_leave("CoCreateInstance");
  813. }
  814. // open key to ROOT on website #1 (where all the VDirs live)
  815. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  816. szMBPathW,
  817. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  818. 1000,
  819. &hMeta);
  820. if (FAILED(hr))
  821. {
  822. error_leave("OpenKey");
  823. }
  824. // Add new VDir called szDirW
  825. hr=pIMeta->AddKey(hMeta, szDirW);
  826. if (FAILED(hr))
  827. {
  828. error_leave("Addkey");
  829. }
  830. // Set the physical path for this VDir
  831. METADATA_RECORD mr;
  832. mr.dwMDIdentifier = MD_VR_PATH;
  833. mr.dwMDAttributes = METADATA_INHERIT ;
  834. mr.dwMDUserType = IIS_MD_UT_FILE;
  835. mr.dwMDDataType = STRING_METADATA;
  836. mr.dwMDDataLen = (wcslen(szPathW) + 1) * sizeof(WCHAR);
  837. mr.pbMDData = (unsigned char*)(szPathW);
  838. hr=pIMeta->SetData(hMeta,szDirW,&mr);
  839. if (FAILED(hr))
  840. {
  841. error_leave("SetData");
  842. }
  843. //
  844. // we also need to set the keytype
  845. //
  846. ZeroMemory((PVOID)&mr, sizeof(METADATA_RECORD));
  847. mr.dwMDIdentifier = MD_KEY_TYPE;
  848. mr.dwMDAttributes = METADATA_INHERIT ;
  849. mr.dwMDUserType = IIS_MD_UT_FILE;
  850. mr.dwMDDataType = STRING_METADATA;
  851. mr.pbMDData = (unsigned char*)(www == rootType? L"IIsWebVirtualDir" : L"IIsFtpVirtualDir");
  852. mr.dwMDDataLen = (lstrlenW((PWSTR)mr.pbMDData) + 1) * sizeof(WCHAR);
  853. hr=pIMeta->SetData(hMeta,szDirW,&mr);
  854. if (FAILED(hr))
  855. {
  856. error_leave("SetData");
  857. }
  858. // Call CloseKey() prior to calling SaveData
  859. pIMeta->CloseKey(hMeta);
  860. hMeta = NULL;
  861. // Flush out the changes and close
  862. hr=pIMeta->SaveData();
  863. if (FAILED(hr))
  864. {
  865. error_leave("SaveData");
  866. }
  867. leave_routine:
  868. if (pIMeta)
  869. {
  870. if(hMeta)
  871. pIMeta->CloseKey(hMeta);
  872. pIMeta->Release();
  873. }
  874. CoUninitialize();
  875. return hr;
  876. }
  877. //+---------------------------------------------------------------------------
  878. //
  879. // Function: SetVirtualRootAccessPermissions
  880. //
  881. // Purpose : Sets Access Permissions to a Virtual Roots in the WWW service.
  882. //
  883. // Arguments:
  884. // PWSTR szVirtDir : Alias of new Virtual Root
  885. // DWORD dwAccessPermisions can be any combination of the following
  886. // or others defined in iiscnfg.h
  887. // MD_ACCESS_EXECUTE | MD_ACCESS_WRITE | MD_ACCESS_READ;
  888. //
  889. // Returns: S_OK if successful, Win32 error otherwise.
  890. //
  891. // Author: a-anasj Mar 18/1998
  892. //
  893. // Notes:
  894. //
  895. HRESULT SetVirtualRootAccessPermissions(PWSTR szVirtDir, DWORD dwAccessPermissions)
  896. {
  897. HRESULT hr = S_OK; // com error status
  898. IMSAdminBase *pIMeta = NULL;
  899. METADATA_HANDLE hMeta = NULL; // handle to metabase
  900. if (FAILED(CoInitialize(NULL)))
  901. {
  902. TraceTag(ttidNetOc, "SetVirtualRootAccessPermissions - CoInitialize failed with 0x%x", hr);
  903. return S_FALSE;
  904. }
  905. // Create an instance of the metabase object
  906. hr=::CoCreateInstance(CLSID_MSAdminBase,
  907. NULL,
  908. CLSCTX_ALL,
  909. IID_IMSAdminBase,
  910. (void **)&pIMeta);
  911. if (FAILED(hr))
  912. {
  913. TraceTag(ttidNetOc, "SetVirtualRootAccessPermissions - CoCreateInstance failed with 0x%x", hr);
  914. error_leave("CoCreateInstance");
  915. }
  916. // open key to ROOT on website #1 (where all the VDirs live)
  917. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  918. szVirtDir,
  919. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  920. 1000,
  921. &hMeta);
  922. if (FAILED(hr))
  923. {
  924. TraceTag(ttidNetOc, "SetVirtualRootAccessPermissions - OpenKey failed with 0x%x", hr);
  925. error_leave("OpenKey");
  926. }
  927. // Set the physical path for this VDir
  928. METADATA_RECORD mr;
  929. mr.dwMDIdentifier = MD_ACCESS_PERM;
  930. mr.dwMDAttributes = METADATA_INHERIT;
  931. mr.dwMDUserType = IIS_MD_UT_FILE;
  932. mr.dwMDDataType = DWORD_METADATA; // this used to be STRING_METADATA, but that was
  933. // the incorrect type and was causing vdir access
  934. // problems.
  935. // Now, create the access perm
  936. mr.pbMDData = (PBYTE) &dwAccessPermissions;
  937. mr.dwMDDataLen = sizeof (DWORD);
  938. mr.dwMDDataTag = 0; // datatag is a reserved field.
  939. hr=pIMeta->SetData(hMeta,
  940. TEXT ("/"), // The root of the Virtual Dir we opened above
  941. &mr);
  942. if (FAILED(hr))
  943. {
  944. TraceTag(ttidNetOc, "SetVirtualRootAccessPermissions - SetData failed with 0x%x", hr);
  945. error_leave("SetData");
  946. }
  947. // Call CloseKey() prior to calling SaveData
  948. pIMeta->CloseKey(hMeta);
  949. hMeta = NULL;
  950. // Flush out the changes and close
  951. hr=pIMeta->SaveData();
  952. if (FAILED(hr))
  953. {
  954. TraceTag(ttidNetOc, "SetVirtualRootAccessPermissions - SaveData failed with 0x%x", hr);
  955. error_leave("SaveData");
  956. }
  957. leave_routine:
  958. if (pIMeta)
  959. {
  960. if(hMeta)
  961. pIMeta->CloseKey(hMeta);
  962. pIMeta->Release();
  963. }
  964. CoUninitialize();
  965. return hr;
  966. }
  967. //+---------------------------------------------------------------------------
  968. //
  969. // Function: SetVirtualRootNoAnonymous
  970. //
  971. // Purpose : Unchecks the "Allow Anonymous Access" checkbox in FTP UI
  972. //
  973. // Arguments:
  974. // PWSTR szVirtDir : Alias of Virtual Root
  975. //
  976. // Returns: S_OK if successful, Win32 error otherwise.
  977. //
  978. // Author: sumitc 23-Nov-2002 Created
  979. //
  980. // Notes:
  981. //
  982. HRESULT SetVirtualRootNoAnonymous(PWSTR szVirtDir)
  983. {
  984. HRESULT hr = S_OK; // com error status
  985. IMSAdminBase *pIMeta = NULL;
  986. METADATA_HANDLE hMeta = NULL; // handle to metabase
  987. if (FAILED(CoInitialize(NULL)))
  988. {
  989. TraceTag(ttidNetOc, "SetVirtualRootNoAnonymous - CoInitialize failed with 0x%x", hr);
  990. return S_FALSE;
  991. }
  992. // Create an instance of the metabase object
  993. hr=::CoCreateInstance(CLSID_MSAdminBase,
  994. NULL,
  995. CLSCTX_ALL,
  996. IID_IMSAdminBase,
  997. (void **)&pIMeta);
  998. if (FAILED(hr))
  999. {
  1000. TraceTag(ttidNetOc, "SetVirtualRootNoAnonymous - CoCreateInstance failed with 0x%x", hr);
  1001. error_leave("CoCreateInstance");
  1002. }
  1003. // open key to ROOT on website #1 (where all the VDirs live)
  1004. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1005. szVirtDir,
  1006. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1007. 1000,
  1008. &hMeta);
  1009. if (FAILED(hr))
  1010. {
  1011. TraceTag(ttidNetOc, "SetVirtualRootNoAnonymous - OpenKey failed with 0x%x", hr);
  1012. error_leave("OpenKey");
  1013. }
  1014. METADATA_RECORD mr;
  1015. DWORD dwAllowAnonymous = 0;
  1016. mr.dwMDIdentifier = MD_ALLOW_ANONYMOUS;
  1017. mr.dwMDAttributes = METADATA_INHERIT;
  1018. mr.dwMDUserType = IIS_MD_UT_SERVER;
  1019. mr.dwMDDataType = DWORD_METADATA;
  1020. mr.pbMDData = (PBYTE) &dwAllowAnonymous;
  1021. mr.dwMDDataLen = sizeof (DWORD);
  1022. mr.dwMDDataTag = 0; // datatag is a reserved field.
  1023. hr=pIMeta->SetData(hMeta,
  1024. TEXT ("/"), // The root of the Virtual Dir we opened above
  1025. &mr);
  1026. if (FAILED(hr))
  1027. {
  1028. TraceTag(ttidNetOc, "SetVirtualRootNoAnonymous - SetData failed with 0x%x", hr);
  1029. error_leave("SetData");
  1030. }
  1031. // Call CloseKey() prior to calling SaveData
  1032. pIMeta->CloseKey(hMeta);
  1033. hMeta = NULL;
  1034. // Flush out the changes and close
  1035. hr=pIMeta->SaveData();
  1036. if (FAILED(hr))
  1037. {
  1038. TraceTag(ttidNetOc, "SetVirtualRootNoAnonymous - SaveData failed with 0x%x", hr);
  1039. error_leave("SaveData");
  1040. }
  1041. leave_routine:
  1042. if (pIMeta)
  1043. {
  1044. if(hMeta)
  1045. pIMeta->CloseKey(hMeta);
  1046. pIMeta->Release();
  1047. }
  1048. CoUninitialize();
  1049. return hr;
  1050. }
  1051. //+---------------------------------------------------------------------------
  1052. //
  1053. // Function: RemoveCPSVRoots
  1054. //
  1055. // Purpose: Deletes the Virtual Directories required for Phone Book Service.
  1056. //
  1057. // Arguments: None
  1058. //
  1059. // Returns: TRUE if successful, FALSE otherwise.
  1060. //
  1061. // Author: a-anasj Mar 9/1998
  1062. // quintinb Jan 10/1999 added error checking and replaced asserts with traces
  1063. //
  1064. // Notes:
  1065. //
  1066. BOOL RemoveCPSVRoots()
  1067. {
  1068. HRESULT hr;
  1069. HKEY hKey;
  1070. hr = DeleteVirtualRoot(www, L"PBServer");
  1071. if (SUCCEEDED(hr))
  1072. {
  1073. //
  1074. // Now delete the associated reg key
  1075. //
  1076. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1077. L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots",
  1078. KEY_ALL_ACCESS, &hKey);
  1079. if (SUCCEEDED(hr))
  1080. {
  1081. if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBServer"))
  1082. {
  1083. hr = S_OK;
  1084. }
  1085. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1086. {
  1087. hr = S_FALSE;
  1088. }
  1089. RegCloseKey(hKey);
  1090. }
  1091. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1092. {
  1093. hr = S_FALSE;
  1094. }
  1095. }
  1096. TraceError("RemoveCPSVRoots -- Deleting PBServer Www Vroot", hr);
  1097. hr = DeleteVirtualRoot(www, L"PBSData");
  1098. if (SUCCEEDED(hr))
  1099. {
  1100. //
  1101. // Now delete the associated reg key
  1102. //
  1103. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1104. L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots",
  1105. KEY_ALL_ACCESS, &hKey);
  1106. if (SUCCEEDED(hr))
  1107. {
  1108. if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBSData"))
  1109. {
  1110. hr = S_OK;
  1111. }
  1112. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1113. {
  1114. hr = S_FALSE;
  1115. }
  1116. RegCloseKey(hKey);
  1117. }
  1118. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1119. {
  1120. hr = S_FALSE;
  1121. }
  1122. }
  1123. TraceError("RemoveCPSVRoots -- Deleting PBSData WWW Vroot", hr);
  1124. hr = DeleteVirtualRoot(ftp, L"PBSData");
  1125. if (SUCCEEDED(hr))
  1126. {
  1127. //
  1128. // Now delete the associated reg key
  1129. //
  1130. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1131. L"SYSTEM\\CurrentControlSet\\Services\\MSFTPSVC\\Parameters\\Virtual Roots",
  1132. KEY_ALL_ACCESS, &hKey);
  1133. if (SUCCEEDED(hr))
  1134. {
  1135. if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBSData"))
  1136. {
  1137. hr = S_OK;
  1138. }
  1139. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1140. {
  1141. hr = S_FALSE;
  1142. }
  1143. RegCloseKey(hKey);
  1144. }
  1145. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  1146. {
  1147. hr = S_FALSE;
  1148. }
  1149. }
  1150. TraceError("RemoveCPSVRoots -- Deleting PBSData FTP Vroot", hr);
  1151. return TRUE;
  1152. }
  1153. //+---------------------------------------------------------------------------
  1154. //
  1155. // Function: DeleteVirtualRoot
  1156. //
  1157. // Purpose: Deletes a Virtual Root in the WWW or FTP services.
  1158. //
  1159. // Arguments:
  1160. //
  1161. // Returns: S_OK if successful, Win32 error otherwise.
  1162. //
  1163. // Author: a-anasj Mar 9/1998
  1164. //
  1165. // Notes:
  1166. //
  1167. HRESULT DeleteVirtualRoot(e_rootType rootType, PWSTR szPathW)
  1168. {
  1169. HRESULT hr = S_OK; // com error status
  1170. IMSAdminBase *pIMeta = NULL;
  1171. METADATA_HANDLE hMeta = NULL; // handle to metabase
  1172. PWSTR szMBPathW;
  1173. if (www == rootType)
  1174. {
  1175. szMBPathW = L"/LM/W3svc/1/ROOT";
  1176. }
  1177. else if (ftp == rootType)
  1178. {
  1179. szMBPathW = L"/LM/MSFTPSVC/1/ROOT";
  1180. }
  1181. else
  1182. {
  1183. // Unknown root type
  1184. //
  1185. ASSERT(FALSE);
  1186. return S_FALSE;
  1187. }
  1188. if (FAILED(CoInitialize(NULL)))
  1189. {
  1190. return S_FALSE;
  1191. //error_leave("CoInitialize");
  1192. }
  1193. // Create an instance of the metabase object
  1194. hr=::CoCreateInstance(CLSID_MSAdminBase,//CLSID_MSAdminBase,
  1195. NULL,
  1196. CLSCTX_ALL,
  1197. IID_IMSAdminBase,
  1198. (void **)&pIMeta);
  1199. if (FAILED(hr))
  1200. {
  1201. error_leave("CoCreateInstance");
  1202. }
  1203. // open key to ROOT on website #1 (where all the VDirs live)
  1204. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1205. szMBPathW,
  1206. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1207. 1000,
  1208. &hMeta);
  1209. if (FAILED(hr))
  1210. {
  1211. error_leave("OpenKey");
  1212. }
  1213. // Add new VDir called szDirW
  1214. hr=pIMeta->DeleteKey(hMeta, szPathW);
  1215. if (FAILED(hr))
  1216. {
  1217. error_leave("DeleteKey");
  1218. }
  1219. // Call CloseKey() prior to calling SaveData
  1220. pIMeta->CloseKey(hMeta);
  1221. hMeta = NULL;
  1222. // Flush out the changes and close
  1223. hr=pIMeta->SaveData();
  1224. if (FAILED(hr))
  1225. {
  1226. error_leave("SaveData");
  1227. }
  1228. leave_routine:
  1229. if (pIMeta)
  1230. {
  1231. if(hMeta)
  1232. pIMeta->CloseKey(hMeta);
  1233. pIMeta->Release();
  1234. }
  1235. CoUninitialize();
  1236. return hr;
  1237. }
  1238. HRESULT SetDirectoryAccessPermissions(PWSTR pszFile, ACCESS_MASK AccessRightsToModify,
  1239. ACCESS_MODE fAccessFlags, PSID pSid)
  1240. {
  1241. if (!pszFile && !pSid)
  1242. {
  1243. return E_INVALIDARG;
  1244. }
  1245. EXPLICIT_ACCESS AccessEntry = {0};
  1246. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  1247. PACL pOldAccessList = NULL;
  1248. PACL pNewAccessList = NULL;
  1249. DWORD dwRes;
  1250. // Get the current DACL information from the object.
  1251. dwRes = GetNamedSecurityInfo(pszFile, // name of the object
  1252. SE_FILE_OBJECT, // type of object
  1253. DACL_SECURITY_INFORMATION, // type of information to set
  1254. NULL, // provider is Windows NT
  1255. NULL, // name or GUID of property or property set
  1256. &pOldAccessList, // receives existing DACL information
  1257. NULL, // receives existing SACL information
  1258. &pSecurityDescriptor); // receives a pointer to the security descriptor
  1259. if (ERROR_SUCCESS == dwRes)
  1260. {
  1261. //
  1262. // Initialize the access list entry.
  1263. //
  1264. BuildTrusteeWithSid(&(AccessEntry.Trustee), pSid);
  1265. AccessEntry.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  1266. AccessEntry.grfAccessMode = fAccessFlags;
  1267. //
  1268. // Set provider-independent standard rights.
  1269. //
  1270. AccessEntry.grfAccessPermissions = AccessRightsToModify;
  1271. //
  1272. // Build an access list from the access list entry.
  1273. //
  1274. dwRes = SetEntriesInAcl(1, &AccessEntry, pOldAccessList, &pNewAccessList);
  1275. if (ERROR_SUCCESS == dwRes)
  1276. {
  1277. //
  1278. // Set the access-control information in the object's DACL.
  1279. //
  1280. dwRes = SetNamedSecurityInfo(pszFile, // name of the object
  1281. SE_FILE_OBJECT, // type of object
  1282. DACL_SECURITY_INFORMATION, // type of information to set
  1283. NULL, // pointer to the new owner SID
  1284. NULL, // pointer to the new primary group SID
  1285. pNewAccessList, // pointer to new DACL
  1286. NULL); // pointer to new SACL
  1287. }
  1288. }
  1289. //
  1290. // Free the returned buffers.
  1291. //
  1292. if (pNewAccessList)
  1293. {
  1294. LocalFree(pNewAccessList);
  1295. }
  1296. if (pSecurityDescriptor)
  1297. {
  1298. LocalFree(pSecurityDescriptor);
  1299. }
  1300. //
  1301. // If the system is using FAT instead of NTFS, then we will get the Invalid Acl error.
  1302. //
  1303. if (ERROR_INVALID_ACL == dwRes)
  1304. {
  1305. return S_FALSE;
  1306. }
  1307. else
  1308. {
  1309. return HRESULT_FROM_WIN32(dwRes);
  1310. }
  1311. }
  1312. void SetCpsDirPermissions()
  1313. {
  1314. WCHAR szPath[MAX_PATH+1];
  1315. HRESULT hr;
  1316. //
  1317. // Previous versions of CPS gave "Everyone" permissions for the CPS directories.
  1318. // For .Netserver2003 onwards, we ACL differently, but need to undo the previous ACL'ing.
  1319. // Thus the first block below removes all access for "Everyone". The 2nd block
  1320. // grants the appropriate access to "Authenticated Users". See bug 729903 for details.
  1321. //
  1322. //
  1323. // Create the SID for the Everyone Account (World account)
  1324. //
  1325. PSID pWorldSid;
  1326. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1327. BOOL bRet = AllocateAndInitializeSid (&WorldSidAuthority, 1, SECURITY_WORLD_RID,
  1328. 0, 0, 0, 0, 0, 0, 0, &pWorldSid);
  1329. if (bRet && pWorldSid)
  1330. {
  1331. ACCESS_MODE fAccessFlags = REVOKE_ACCESS;
  1332. //
  1333. // Set the Data Dir access permissions
  1334. //
  1335. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsDataPath);
  1336. hr = SetDirectoryAccessPermissions(szPath, 0, fAccessFlags, pWorldSid);
  1337. TraceError("SetCpsDirPermissions -- removed Everyone perms from Data dir", hr);
  1338. //
  1339. // Set the Bin Dir access permissions
  1340. //
  1341. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsBinPath);
  1342. hr = SetDirectoryAccessPermissions(szPath, 0, fAccessFlags, pWorldSid);
  1343. TraceError("SetCpsDirPermissions -- removed Everyone perms from Bin dir", hr);
  1344. //
  1345. // Set the Root Dir access permissions
  1346. //
  1347. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsRootPath);
  1348. hr = SetDirectoryAccessPermissions(szPath, 0, fAccessFlags, pWorldSid);
  1349. TraceError("SetCpsDirPermissions -- removed Everyone perms from Root dir", hr);
  1350. FreeSid(pWorldSid);
  1351. }
  1352. //
  1353. // Create the SID for "Authenticated Users"
  1354. //
  1355. PSID pAuthUsersSid;
  1356. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1357. bRet = AllocateAndInitializeSid (&NtAuthority, 1, SECURITY_AUTHENTICATED_USER_RID,
  1358. 0, 0, 0, 0, 0, 0, 0, &pAuthUsersSid);
  1359. if (bRet && pAuthUsersSid)
  1360. {
  1361. const ACCESS_MASK c_Write = FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA |
  1362. FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE |
  1363. FILE_DELETE_CHILD | FILE_APPEND_DATA;
  1364. const ACCESS_MASK c_Read = FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA |
  1365. FILE_LIST_DIRECTORY | SYNCHRONIZE | READ_CONTROL;
  1366. const ACCESS_MASK c_Execute = FILE_EXECUTE | FILE_TRAVERSE;
  1367. ACCESS_MASK arCpsRoot= c_Read;
  1368. ACCESS_MASK arCpsBin= c_Read | c_Execute;
  1369. ACCESS_MASK arCpsData= c_Read | c_Write;
  1370. ACCESS_MODE fAccessFlags = GRANT_ACCESS;
  1371. //
  1372. // Set the Data Dir access permissions
  1373. //
  1374. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsDataPath);
  1375. hr = SetDirectoryAccessPermissions(szPath, arCpsData, fAccessFlags, pAuthUsersSid);
  1376. TraceError("SetCpsDirPermissions -- Data dir", hr);
  1377. //
  1378. // Set the Bin Dir access permissions
  1379. //
  1380. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsBinPath);
  1381. hr = SetDirectoryAccessPermissions(szPath, arCpsBin, fAccessFlags, pAuthUsersSid);
  1382. TraceError("SetCpsDirPermissions -- Bin dir", hr);
  1383. //
  1384. // Set the Root Dir access permissions
  1385. //
  1386. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsRootPath);
  1387. hr = SetDirectoryAccessPermissions(szPath, arCpsRoot, fAccessFlags, pAuthUsersSid);
  1388. TraceError("SetCpsDirPermissions -- Root dir", hr);
  1389. FreeSid(pAuthUsersSid);
  1390. }
  1391. }
  1392. //+---------------------------------------------------------------------------
  1393. //
  1394. // Function: CreateNewAppPoolAndAddPBS
  1395. //
  1396. // Purpose: Creates new app pool for PBS, and sets non-default params we need
  1397. //
  1398. // Arguments: none
  1399. //
  1400. // Returns: S_OK if successful, Win32 error otherwise.
  1401. //
  1402. // Author: SumitC 24-Sep-2001
  1403. //
  1404. // Notes:
  1405. //
  1406. HRESULT CreateNewAppPoolAndAddPBS()
  1407. {
  1408. HRESULT hr = S_OK;
  1409. IMSAdminBase *pIMeta = NULL;
  1410. METADATA_HANDLE hMeta = NULL;
  1411. METADATA_RECORD mr;
  1412. if (FAILED(CoInitialize(NULL)))
  1413. {
  1414. return S_FALSE;
  1415. }
  1416. // Create an instance of the metabase object
  1417. hr=::CoCreateInstance(CLSID_MSAdminBase,
  1418. NULL,
  1419. CLSCTX_ALL,
  1420. IID_IMSAdminBase,
  1421. (void **)&pIMeta);
  1422. if (FAILED(hr))
  1423. {
  1424. error_leave("CoCreateInstance");
  1425. }
  1426. // open key to App Pools root
  1427. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1428. L"/LM/W3svc/AppPools",
  1429. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1430. 1000,
  1431. &hMeta);
  1432. if (FAILED(hr))
  1433. {
  1434. error_leave("OpenKey");
  1435. }
  1436. // Add new app pool
  1437. hr=pIMeta->AddKey(hMeta, c_szPBSAppPoolID);
  1438. if (FAILED(hr))
  1439. {
  1440. error_leave("Addkey");
  1441. }
  1442. // Set the key type
  1443. ZeroMemory((PVOID)&mr, sizeof(METADATA_RECORD));
  1444. mr.dwMDIdentifier = MD_KEY_TYPE;
  1445. mr.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  1446. mr.dwMDUserType = IIS_MD_UT_SERVER;
  1447. mr.dwMDDataType = STRING_METADATA;
  1448. mr.dwMDDataLen = (wcslen(c_szAppPoolKey) + 1) * sizeof(WCHAR);
  1449. mr.pbMDData = (unsigned char*)(c_szAppPoolKey);
  1450. mr.dwMDDataTag = 0; // reserved
  1451. hr=pIMeta->SetData(hMeta, c_szPBSAppPoolID, &mr);
  1452. if (FAILED(hr))
  1453. {
  1454. error_leave("SetData");
  1455. }
  1456. // Disable overlapped rotation
  1457. ZeroMemory((PVOID)&mr, sizeof(METADATA_RECORD));
  1458. DWORD dwDisableOverlappingRotation = TRUE;
  1459. mr.dwMDIdentifier = MD_APPPOOL_DISALLOW_OVERLAPPING_ROTATION;
  1460. mr.dwMDAttributes = METADATA_INHERIT;
  1461. mr.dwMDUserType = IIS_MD_UT_SERVER;
  1462. mr.dwMDDataType = DWORD_METADATA;
  1463. mr.pbMDData = (PBYTE) &dwDisableOverlappingRotation;
  1464. mr.dwMDDataLen = sizeof (DWORD);
  1465. mr.dwMDDataTag = 0; // reserved
  1466. hr=pIMeta->SetData(hMeta, c_szPBSAppPoolID, &mr);
  1467. if (FAILED(hr))
  1468. {
  1469. error_leave("SetData");
  1470. }
  1471. // Call CloseKey() prior to calling SaveData
  1472. pIMeta->CloseKey(hMeta);
  1473. hMeta = NULL;
  1474. // Flush out the changes and close
  1475. hr=pIMeta->SaveData();
  1476. if (FAILED(hr))
  1477. {
  1478. error_leave("SaveData");
  1479. }
  1480. //
  1481. // Now add PBS to this app pool
  1482. //
  1483. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1484. L"/LM/w3svc/1/Root/PBServer",
  1485. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1486. 1000,
  1487. &hMeta);
  1488. if (FAILED(hr))
  1489. {
  1490. error_leave("OpenKey");
  1491. }
  1492. ZeroMemory((PVOID)&mr, sizeof(METADATA_RECORD));
  1493. mr.dwMDIdentifier = MD_APP_APPPOOL_ID;
  1494. mr.dwMDAttributes = METADATA_INHERIT;
  1495. mr.dwMDUserType = IIS_MD_UT_SERVER;
  1496. mr.dwMDDataType = STRING_METADATA;
  1497. mr.dwMDDataLen = (wcslen(c_szPBSAppPoolID) + 1) * sizeof(WCHAR);
  1498. mr.pbMDData = (unsigned char*)(c_szPBSAppPoolID);
  1499. hr=pIMeta->SetData(hMeta, TEXT(""), &mr);
  1500. if (FAILED(hr))
  1501. {
  1502. error_leave("SetData");
  1503. }
  1504. // Call CloseKey() prior to calling SaveData
  1505. pIMeta->CloseKey(hMeta);
  1506. hMeta = NULL;
  1507. // Flush out the changes and close
  1508. hr=pIMeta->SaveData();
  1509. if (FAILED(hr))
  1510. {
  1511. error_leave("SaveData");
  1512. }
  1513. leave_routine:
  1514. if (pIMeta)
  1515. {
  1516. if(hMeta)
  1517. pIMeta->CloseKey(hMeta);
  1518. pIMeta->Release();
  1519. }
  1520. CoUninitialize();
  1521. return hr;
  1522. }
  1523. //+---------------------------------------------------------------------------
  1524. //
  1525. // Function: DeleteAppPool
  1526. //
  1527. // Purpose: Deletes new app pool created for PBS
  1528. //
  1529. // Arguments: none
  1530. //
  1531. // Returns: S_OK if successful, Win32 error otherwise.
  1532. //
  1533. // Author: SumitC 24-Sep-2001
  1534. //
  1535. // Notes:
  1536. //
  1537. HRESULT DeleteAppPool()
  1538. {
  1539. HRESULT hr = S_OK;
  1540. IMSAdminBase *pIMeta = NULL;
  1541. METADATA_HANDLE hMeta = NULL;
  1542. if (FAILED(CoInitialize(NULL)))
  1543. {
  1544. return S_FALSE;
  1545. }
  1546. // Create an instance of the metabase object
  1547. hr=::CoCreateInstance(CLSID_MSAdminBase,
  1548. NULL,
  1549. CLSCTX_ALL,
  1550. IID_IMSAdminBase,
  1551. (void **)&pIMeta);
  1552. if (FAILED(hr))
  1553. {
  1554. error_leave("CoCreateInstance");
  1555. }
  1556. // open key to App Pools root
  1557. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  1558. L"/LM/W3svc/AppPools",
  1559. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1560. 1000,
  1561. &hMeta);
  1562. if (FAILED(hr))
  1563. {
  1564. error_leave("OpenKey");
  1565. }
  1566. // Delete previously-created app pool
  1567. hr=pIMeta->DeleteKey(hMeta, c_szPBSAppPoolID);
  1568. if (FAILED(hr))
  1569. {
  1570. error_leave("DeleteKey");
  1571. }
  1572. // Call CloseKey() prior to calling SaveData
  1573. pIMeta->CloseKey(hMeta);
  1574. hMeta = NULL;
  1575. // Flush out the changes and close
  1576. hr=pIMeta->SaveData();
  1577. if (FAILED(hr))
  1578. {
  1579. error_leave("SaveData");
  1580. }
  1581. leave_routine:
  1582. if (pIMeta)
  1583. {
  1584. if(hMeta)
  1585. pIMeta->CloseKey(hMeta);
  1586. pIMeta->Release();
  1587. }
  1588. CoUninitialize();
  1589. return hr;
  1590. }
  1591. //+---------------------------------------------------------------------------
  1592. //
  1593. // Function: EnableISAPIRequests
  1594. //
  1595. // Purpose: Enables ISAPI requests if appropriate
  1596. //
  1597. // Arguments: szComponentName - mostly for reporting errors
  1598. //
  1599. // Returns: S_OK if successful, Win32 error otherwise.
  1600. //
  1601. // Author: SumitC 18-Sep-2001
  1602. //
  1603. // Notes:
  1604. //
  1605. HRESULT EnableISAPIRequests(PCTSTR szComponentName)
  1606. {
  1607. HRESULT hr = S_OK;
  1608. BOOL fEnablePBSRequests = FALSE;
  1609. BOOL fDontShowUI = FALSE;
  1610. // NOTE: if the following becomes available as a global var or a member of pnocd, use that.
  1611. fDontShowUI = (g_ocmData.sic.SetupData.OperationFlags & SETUPOP_BATCH) &&
  1612. (!g_ocmData.fShowUnattendedMessages);
  1613. if (fDontShowUI)
  1614. {
  1615. // "Unattended" mode
  1616. //
  1617. // Per the IIS spec, the NetCMAK or NetCPS unattended file entry is a good enough
  1618. // indication that the admin intends to install *and enable* PBS, so
  1619. // we can enable PBS requests, as long as we log that we did this.
  1620. //
  1621. fEnablePBSRequests = TRUE;
  1622. }
  1623. else
  1624. {
  1625. // "Attended mode", so interact with user
  1626. int nRet;
  1627. //
  1628. // warn admin about security concerns and ask about enabling PBS requests
  1629. //
  1630. nRet = NcMsgBoxMc(g_ocmData.hwnd, IDS_OC_CAPTION, IDS_OC_PBS_ENABLE_ISAPI_REQUESTS,
  1631. MB_YESNO | MB_ICONWARNING);
  1632. fEnablePBSRequests = (IDYES == nRet) ? TRUE : FALSE;
  1633. }
  1634. //
  1635. // Enable if appropriate, or say they have to do this themselves
  1636. //
  1637. if (FALSE == fEnablePBSRequests)
  1638. {
  1639. //
  1640. // Don't show UI because the previous dialog has already explained the situation.
  1641. //
  1642. (void) ReportEventHrString(TEXT("You must enable Phone Book Service ISAPI requests using the IIS Security Wizard"),
  1643. IDS_OC_PBS_ENABLE_ISAPI_YOURSELF, szComponentName);
  1644. }
  1645. else
  1646. {
  1647. //
  1648. // Fire up a process to enable PBS in the IIS metabase
  1649. //
  1650. hr = UseProcessToEnableDisablePBS(TRUE); // TRUE => enable
  1651. if (S_OK != hr)
  1652. {
  1653. //
  1654. // we use a function that puts up UI if appropriate, otherwise logs.
  1655. //
  1656. (void) ReportErrorHr(hr,
  1657. IDS_OC_PBS_ENABLE_ISAPI_YOURSELF,
  1658. g_ocmData.hwnd, szComponentName);
  1659. }
  1660. else
  1661. {
  1662. //
  1663. // Write Success event to the event log
  1664. //
  1665. HANDLE hEventLog = RegisterEventSource(NULL, NETOC_SERVICE_NAME);
  1666. if (NULL == hEventLog)
  1667. {
  1668. TraceTag(ttidNetOc, "EnableISAPIRequests - RegisterEventSource failed (GLE=%d), couldn't log success event", GetLastError());
  1669. }
  1670. else
  1671. {
  1672. PCWSTR plpszArgs[2];
  1673. plpszArgs[0] = NETOC_SERVICE_NAME;
  1674. plpszArgs[1] = L"Phone Book Service";
  1675. if (!ReportEvent(hEventLog, // event log handle
  1676. EVENTLOG_INFORMATION_TYPE, // event type
  1677. 0, // category zero
  1678. IDS_OC_ISAPI_REENABLED, // event identifier
  1679. NULL, // no user security identifier
  1680. 2, // two substitution strings
  1681. 0, // no data
  1682. plpszArgs, // pointer to string array
  1683. NULL)) // pointer to data
  1684. {
  1685. TraceTag(ttidNetOc, "EnableISAPIRequests - ReportEvent failed with %x, couldn't log success event", GetLastError());
  1686. }
  1687. DeregisterEventSource(hEventLog);
  1688. }
  1689. // I suppose I could now ReportErrorHr saying that logging the success event failed.
  1690. // But I won't.
  1691. }
  1692. }
  1693. return hr;
  1694. }
  1695. //+---------------------------------------------------------------------------
  1696. //
  1697. // Function: UseProcessToEnableDisablePBS
  1698. //
  1699. // Purpose: Starts a process (pbsnetoc.exe) to enable or disable PBS within
  1700. // the IIS metabase
  1701. //
  1702. // Arguments: fEnable - true => enable PBS, false => disable PBS
  1703. //
  1704. // Returns: S_OK if successful, HRESULT otherwise.
  1705. //
  1706. // Author: SumitC 05-Jun-2002
  1707. //
  1708. // Notes: We need to use this method (instead of a call from within netoc.dll)
  1709. // because IIS wants us to use ADSI to get to their metabase. However,
  1710. // ADSI has problems when used by several clients within a large process.
  1711. // Specifically, whoever uses ADSI first causes the list of ADSI providers
  1712. // to be initialized - and frozen. If any providers register themselves
  1713. // after this, they will be ignored by this ADSI instance. Thus, if our
  1714. // code is running within a process like setup.exe (gui-mode setup) or
  1715. // sysocmgr.exe, and some other ADSI client initializes ADSI early on,
  1716. // and then IIS registers itself, and then we try to do our setup via
  1717. // ADSI calls - those would fail. Using a separate EXE bypasses this problem.
  1718. //
  1719. HRESULT UseProcessToEnableDisablePBS(BOOL fEnable)
  1720. {
  1721. HRESULT hr = S_OK;
  1722. STARTUPINFO StartupInfo = {0};
  1723. PROCESS_INFORMATION ProcessInfo = {0};
  1724. WCHAR szFullPath[MAX_PATH + 1];
  1725. WCHAR szCmdLine[MAX_PATH + 1];
  1726. DWORD dwReturnValue = S_OK;
  1727. GetSystemDirectory(szFullPath, MAX_PATH + 1);
  1728. if ((lstrlen(szFullPath) + lstrlen(L"\\setup\\pbsnetoc.exe")) <= MAX_PATH)
  1729. {
  1730. lstrcat(szFullPath, L"\\setup\\pbsnetoc.exe");
  1731. }
  1732. wsprintf(szCmdLine, L"%s %s", szFullPath, (fEnable ? L"/i" : L"/u"));
  1733. if (NULL == CreateProcess(szFullPath, szCmdLine,
  1734. NULL, NULL, FALSE, 0,
  1735. NULL, NULL,
  1736. &StartupInfo, &ProcessInfo))
  1737. {
  1738. hr = HRESULT_FROM_WIN32(GetLastError());
  1739. TraceError("RunAsExeFromSystem() CreateProcess() for pbsnetoc.exe failed, GLE=%u.", GetLastError());
  1740. ProcessInfo.hProcess = NULL;
  1741. }
  1742. else
  1743. {
  1744. WaitForSingleObject(ProcessInfo.hProcess, 10 * 1000); // wait 10 seconds
  1745. (void) GetExitCodeProcess(ProcessInfo.hProcess, &dwReturnValue);
  1746. if (dwReturnValue != S_OK)
  1747. {
  1748. hr = (HRESULT) dwReturnValue;
  1749. }
  1750. CloseHandle(ProcessInfo.hProcess);
  1751. CloseHandle(ProcessInfo.hThread);
  1752. }
  1753. return hr;
  1754. }