Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1466 lines
40 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. //+---------------------------------------------------------------------------
  50. //
  51. // Function: HrOcCpsPreQueueFiles
  52. //
  53. // Purpose: Called by optional components installer code to handle
  54. // additional installation requirements for PhoneBook Server.
  55. //
  56. // Arguments:
  57. // pnocd [in] Pointer to NETOC data.
  58. //
  59. // Returns: S_OK if successfull, Win32 error otherwise.
  60. //
  61. // Author: quintinb 18 Sep 1998
  62. //
  63. // Notes:
  64. //
  65. HRESULT HrOcCpsPreQueueFiles(PNETOCDATA pnocd)
  66. {
  67. HRESULT hr = S_OK;
  68. switch ( pnocd->eit )
  69. {
  70. case IT_UPGRADE:
  71. case IT_INSTALL:
  72. case IT_REMOVE:
  73. // We need to setup the custom DIRID so that CPS will install
  74. // to the correct location. First get the path from the system.
  75. //
  76. ZeroMemory(g_szProgramFiles, sizeof(g_szProgramFiles));
  77. // This is a fresh install of CMAK, don't return an error
  78. //
  79. hr = SHGetSpecialFolderPath(NULL, g_szProgramFiles, CSIDL_PROGRAM_FILES, FALSE);
  80. if (SUCCEEDED(hr))
  81. {
  82. if (IT_UPGRADE == pnocd->eit)
  83. {
  84. hr = HrMoveOldCpsInstall(g_szProgramFiles);
  85. }
  86. // Next Create the CPS Dir ID
  87. //
  88. if (SUCCEEDED(hr))
  89. {
  90. hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd);
  91. if (SUCCEEDED(hr))
  92. {
  93. if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwCpsDirID, g_szProgramFiles))
  94. {
  95. hr = HRESULT_FROM_WIN32(GetLastError());
  96. }
  97. }
  98. }
  99. }
  100. break;
  101. }
  102. TraceError("HrOcCpsPreQueueFiles", hr);
  103. return hr;
  104. }
  105. //+---------------------------------------------------------------------------
  106. //
  107. // Function: HrMoveOldCpsInstall
  108. //
  109. // Purpose: This function moves the old cps directory to the new cps directory
  110. // location. Because of the problems with Front Page Extensions and
  111. // directory permissions we moved our install directory out from under
  112. // wwwroot to Program Files instead.
  113. //
  114. // Arguments:
  115. // pszprogramFiles [in]
  116. //
  117. // Returns: S_OK if successfull, Win32 error otherwise.
  118. //
  119. // Author: quintinb 26 Jan 1999
  120. //
  121. // Notes:
  122. //
  123. HRESULT HrMoveOldCpsInstall(PCWSTR pszProgramFiles)
  124. {
  125. WCHAR szOldCpsLocation[MAX_PATH+1];
  126. WCHAR szNewCpsLocation[MAX_PATH+1];
  127. WCHAR szTemp[MAX_PATH+1];
  128. SHFILEOPSTRUCT fOpStruct;
  129. HRESULT hr = S_OK;
  130. if ((NULL == pszProgramFiles) || (L'\0' == pszProgramFiles[0]))
  131. {
  132. return E_INVALIDARG;
  133. }
  134. //
  135. // First, lets build the old CPS location
  136. //
  137. hr = HrGetWwwRootDir(szTemp, celems(szTemp));
  138. if (SUCCEEDED(hr))
  139. {
  140. //
  141. // Zero the string buffers
  142. //
  143. ZeroMemory(szOldCpsLocation, celems(szOldCpsLocation));
  144. ZeroMemory(szNewCpsLocation, celems(szNewCpsLocation));
  145. wsprintfW(szOldCpsLocation, c_szSSFmt, szTemp, c_szPbsRootPath);
  146. //
  147. // Now check to see if the old cps location exists
  148. //
  149. DWORD dwDirectoryAttributes = GetFileAttributes(szOldCpsLocation);
  150. //
  151. // If we didn't get back -1 (error return code for GetFileAttributes), check to
  152. // see if we have a directory. If so, go ahead and copy the data over.
  153. //
  154. if ((-1 != dwDirectoryAttributes) && (dwDirectoryAttributes & FILE_ATTRIBUTE_DIRECTORY))
  155. {
  156. //
  157. // Now build the new cps location
  158. //
  159. wsprintfW(szNewCpsLocation, c_szSSFmt, pszProgramFiles, c_szPbsRootPath);
  160. //
  161. // Now copy the old files to the new location
  162. //
  163. ZeroMemory(&fOpStruct, sizeof(fOpStruct));
  164. fOpStruct.hwnd = NULL;
  165. fOpStruct.wFunc = FO_COPY;
  166. fOpStruct.pTo = szNewCpsLocation;
  167. fOpStruct.pFrom = szOldCpsLocation;
  168. fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
  169. if (0== SHFileOperation(&fOpStruct))
  170. {
  171. //
  172. // Now delete the original directory
  173. //
  174. fOpStruct.pTo = NULL;
  175. fOpStruct.wFunc = FO_DELETE;
  176. if (0 != SHFileOperation(&fOpStruct))
  177. {
  178. hr = S_FALSE;
  179. }
  180. }
  181. else
  182. {
  183. //
  184. // Note, SHFileOperation isn't guarenteed to return anything sensible here. We might
  185. // get back ERROR_NO_TOKEN or ERROR_INVALID_HANDLE, etc when the directory is just missing.
  186. // The following check probably isn't useful anymore because of this but I will leave it just
  187. // in case. Hopefully the file check above will make sure we don't hit this but ...
  188. //
  189. DWORD dwError = GetLastError();
  190. if ((ERROR_FILE_NOT_FOUND == dwError) || (ERROR_PATH_NOT_FOUND == dwError))
  191. {
  192. //
  193. // Then we couldn't find the old dir to move it. Not fatal.
  194. //
  195. hr = S_FALSE;
  196. }
  197. else
  198. {
  199. hr = HRESULT_FROM_WIN32(dwError);
  200. }
  201. }
  202. }
  203. else
  204. {
  205. //
  206. // Then we couldn't find the old dir to move it. Not fatal.
  207. //
  208. hr = S_FALSE;
  209. }
  210. }
  211. return hr;
  212. }
  213. //+---------------------------------------------------------------------------
  214. //
  215. // Function: HrGetWwwRootDir
  216. //
  217. // Purpose: This function retrieves the location of the InetPub\wwwroot dir from the
  218. // WwwRootDir registry key.
  219. //
  220. // Arguments:
  221. // szInetPub [out] String Buffer to hold the InetPub dir path
  222. // uInetPubCount [in] number of chars in the output buffer
  223. //
  224. // Returns: S_OK if successfull, Win32 error otherwise.
  225. //
  226. // Author: quintinb 26 Jan 1999
  227. //
  228. // Notes:
  229. //
  230. HRESULT HrGetWwwRootDir(PWSTR szWwwRoot, UINT uWwwRootCount)
  231. {
  232. HKEY hKey;
  233. HRESULT hr = S_OK;
  234. //
  235. // Check input params
  236. //
  237. if ((NULL == szWwwRoot) || (0 == uWwwRootCount))
  238. {
  239. return E_INVALIDARG;
  240. }
  241. //
  242. // Set the strings to empty
  243. //
  244. szWwwRoot[0] = L'\0';
  245. //
  246. // First try to open the InetStp key and get the wwwroot value.
  247. //
  248. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szInetRegPath, KEY_READ, &hKey);
  249. if (SUCCEEDED(hr))
  250. {
  251. DWORD dwSize = uWwwRootCount * sizeof(WCHAR);
  252. RegQueryValueExW(hKey, c_szWWWRootValue, NULL, NULL, (LPBYTE)szWwwRoot, &dwSize);
  253. RegCloseKey(hKey);
  254. hr = S_OK;
  255. }
  256. if (L'\0' == szWwwRoot[0])
  257. {
  258. // Well, we didn't get anything from the registry, lets try building the default.
  259. //
  260. WCHAR szTemp[MAX_PATH+1];
  261. if (GetWindowsDirectory(szTemp, MAX_PATH))
  262. {
  263. // Get the drive that the windows dir is on using _tsplitpath
  264. //
  265. WCHAR szDrive[_MAX_DRIVE+1];
  266. _wsplitpath(szTemp, szDrive, NULL, NULL, NULL);
  267. if (uWwwRootCount > (UINT)(lstrlenW(szDrive) + lstrlenW (c_szWwwRootPath) + 1))
  268. {
  269. wsprintfW(szWwwRoot, c_szSSFmt, szDrive, c_szWwwRootPath);
  270. hr = S_OK;
  271. }
  272. else
  273. {
  274. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  275. }
  276. }
  277. else
  278. {
  279. hr = HRESULT_FROM_WIN32(GetLastError());
  280. }
  281. }
  282. return hr;
  283. }
  284. //+---------------------------------------------------------------------------
  285. //
  286. // Function: HrOcCpsOnInstall
  287. //
  288. // Purpose: Called by optional components installer code to handle
  289. // additional installation requirements for PhoneBook Server.
  290. //
  291. // Arguments:
  292. // pnocd [in] Pointer to NETOC data.
  293. //
  294. // Returns: S_OK if successfull, Win32 error otherwise.
  295. //
  296. // Author: a-anasj 9 Mar 1998
  297. //
  298. // Notes:
  299. //
  300. HRESULT HrOcCpsOnInstall(PNETOCDATA pnocd)
  301. {
  302. HRESULT hr = S_OK;
  303. DWORD dwRet = 0;
  304. BOOL bRet = FALSE;
  305. switch (pnocd->eit)
  306. {
  307. case IT_INSTALL:
  308. case IT_UPGRADE:
  309. {
  310. // Register MS_Access data source
  311. //
  312. dwRet = RegisterPBServerDataSource();
  313. if ( NULL == dwRet)
  314. {
  315. hr = S_FALSE;
  316. }
  317. // Load Perfomance Monitor Counters
  318. //
  319. bRet = LoadPerfmonCounters();
  320. if (FALSE == bRet)
  321. {
  322. hr = S_FALSE;
  323. }
  324. // Create Virtual WWW and FTP roots
  325. //
  326. if (IT_UPGRADE == pnocd->eit)
  327. {
  328. //
  329. // If this is an upgrade, we must first delete the old Virtual Roots
  330. // before we can create new ones.
  331. //
  332. RemoveCPSVRoots();
  333. }
  334. dwRet = CreateCPSVRoots();
  335. if (NULL == dwRet)
  336. {
  337. hr = S_FALSE;
  338. }
  339. SetCpsDirPermissions();
  340. //
  341. // set additional security permssion to the reg key for ODBC
  342. //
  343. PSID pAuthenticatedUsersSid;
  344. SID_IDENTIFIER_AUTHORITY NTSidAuthority = SECURITY_NT_AUTHORITY;
  345. AllocateAndInitializeSid (&NTSidAuthority, 1, SECURITY_AUTHENTICATED_USER_RID,
  346. 0, 0, 0, 0, 0, 0, 0, &pAuthenticatedUsersSid);
  347. //
  348. // This function will handle pAuthenticatedUsersSid == NULL
  349. //
  350. AddToRegKeySD(c_szOdbcPbserver,
  351. pAuthenticatedUsersSid,
  352. KEY_QUERY_VALUE |
  353. KEY_SET_VALUE |
  354. KEY_CREATE_SUB_KEY |
  355. KEY_ENUMERATE_SUB_KEYS |
  356. KEY_NOTIFY |
  357. DELETE |
  358. READ_CONTROL);
  359. if (pAuthenticatedUsersSid)
  360. {
  361. FreeSid(pAuthenticatedUsersSid);
  362. }
  363. }
  364. break;
  365. case IT_REMOVE:
  366. // Remove the Virtual Directories, so access to the service is stopped.
  367. //
  368. RemoveCPSVRoots();
  369. break;
  370. }
  371. TraceError("HrOcCpsOnInstall", hr);
  372. return hr;
  373. }
  374. //+---------------------------------------------------------------------------
  375. //
  376. // Function: LoadPerfmonCounters
  377. //
  378. // Purpose: Do whatever is neccessary to make the performance monitor Display the PBServerMonitor counters
  379. //
  380. // Arguments:
  381. //
  382. // Returns: BOOL TRUE if successfull, Not TRUE otherwise.
  383. //
  384. // Author: a-anasj Mar 9/1998
  385. //
  386. // Notes: One of the installation requirements for PhoneBook Server.
  387. // is to load the perfomance monitor counters that allow PBServerMonitor
  388. // to report to the user on PhoneBook Server performance.
  389. // In this function we add the services registry entry first then we
  390. // call into LoadPerf.Dll to load the counters for us. The order is imperative.
  391. // I then add other registry entries related to PBServerMonitor.
  392. //
  393. BOOL LoadPerfmonCounters()
  394. {
  395. WinExec("lodctr.exe CPSSym.ini", SW_HIDE);
  396. return TRUE;
  397. }
  398. //+---------------------------------------------------------------------------
  399. //
  400. // Function: RegisterPBServerDataSource
  401. //
  402. // Purpose: Registers PBServer.
  403. //
  404. // Arguments: None
  405. //
  406. // Returns: Win32 error code
  407. //
  408. // Author: a-anasj 9 Mar 1998
  409. //
  410. // Notes:
  411. // History: 7-9-97 a-frankh Created
  412. // 10/4/97 mmaguire RAID #19906 - Totally restructured to include error handling
  413. // 5-14-98 quintinb removed unnecessary comments and cleaned up the function.
  414. //
  415. BOOL RegisterPBServerDataSource()
  416. {
  417. DWORD dwRet = 0;
  418. HKEY hkODBCInst = NULL;
  419. HKEY hkODBCDataSources = NULL;
  420. DWORD dwIndex;
  421. WCHAR szName[MAX_PATH+1];
  422. __try
  423. {
  424. // Open the hkODBCInst RegKey
  425. //
  426. dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, c_szOdbcInstKey, &hkODBCInst);
  427. if((ERROR_SUCCESS != dwRet) || (NULL == hkODBCInst))
  428. {
  429. __leave;
  430. }
  431. // Look to see the the "Microsoft Access" RegKey is defined
  432. // If it is, then set the value of the ODBC Data Sources RegKey below
  433. //
  434. dwIndex = 0;
  435. do
  436. {
  437. dwRet = RegEnumKey(hkODBCInst,dwIndex,szName,celems(szName));
  438. dwIndex++;
  439. } while ((ERROR_SUCCESS == dwRet) && (NULL == wcsstr(szName, c_szMsAccess)));
  440. if ( ERROR_SUCCESS != dwRet )
  441. {
  442. // We need the Microsoft Access *.mdb driver to work
  443. // and we could not find it
  444. //
  445. __leave;
  446. }
  447. // Open the hkODBCDataSources RegKey
  448. //
  449. dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, c_szOdbcDataSourcesPath,
  450. &hkODBCDataSources);
  451. if( ERROR_SUCCESS != dwRet )
  452. {
  453. __leave;
  454. }
  455. //
  456. // Use the name from the resource for registration purposes.
  457. //
  458. // NOTE: this string is from HKLM\Software\ODBC\ODBCINST.INI\*
  459. //
  460. lstrcpy(szName, SzLoadIds(IDS_OC_PB_DSN_NAME));
  461. // Set values in the hkODBCDataSources key
  462. //
  463. dwRet = RegSetValueEx(hkODBCDataSources, c_szPbServer, 0, REG_SZ,
  464. (LPBYTE)szName, (lstrlenW(szName)+1)*sizeof(WCHAR));
  465. if( ERROR_SUCCESS != dwRet )
  466. {
  467. __leave;
  468. }
  469. } // end __try
  470. __finally
  471. {
  472. if (hkODBCInst)
  473. {
  474. RegCloseKey (hkODBCInst);
  475. }
  476. if (hkODBCDataSources)
  477. {
  478. RegCloseKey (hkODBCDataSources);
  479. }
  480. }
  481. return (ERROR_SUCCESS == dwRet);
  482. }
  483. //+---------------------------------------------------------------------------
  484. //
  485. // Function: CreateCPSVRoots
  486. //
  487. // Purpose: Creates the Virtual Directories required for Phone Book Service.
  488. //
  489. // Arguments: None
  490. //
  491. // Returns: TRUE if successfull, FALSE otherwise.
  492. //
  493. // Author: a-anasj Mar 9/1998
  494. //
  495. // Notes:
  496. //
  497. BOOL CreateCPSVRoots()
  498. {
  499. // QBBUG - Should we make sure the physical paths exist before pointing a virtual root to them?
  500. WCHAR szPath[MAX_PATH+1];
  501. HRESULT hr;
  502. if (L'\0' == g_szProgramFiles[0])
  503. {
  504. return FALSE;
  505. }
  506. // Create the Bindir virtual root
  507. //
  508. wsprintfW(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsBinPath);
  509. hr = AddNewVirtualRoot(www, L"PBServer", szPath);
  510. if (S_OK != hr)
  511. {
  512. return FALSE;
  513. }
  514. // Now we set the Execute access permissions on the PBServer Virtual Root
  515. //
  516. PWSTR szVirtDir;
  517. szVirtDir = L"/LM/W3svc/1/ROOT/PBServer";
  518. SetVirtualRootAccessPermissions( szVirtDir, MD_ACCESS_EXECUTE | MD_ACCESS_READ );
  519. // Create the Data dir virtual roots
  520. //
  521. wsprintfW(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsDataPath);
  522. hr = AddNewVirtualRoot(www, L"PBSData", szPath);
  523. if (S_OK != hr)
  524. {
  525. return FALSE;
  526. }
  527. hr = AddNewVirtualRoot(ftp, L"PBSData", szPath);
  528. if (S_OK != hr)
  529. {
  530. return FALSE;
  531. }
  532. // Now we set the Execute access permissions on the PBServer Virtual Root
  533. //
  534. szVirtDir = L"/LM/MSFTPSVC/1/ROOT/PBSData";
  535. SetVirtualRootAccessPermissions(szVirtDir, MD_ACCESS_READ);
  536. return 1;
  537. }
  538. //+---------------------------------------------------------------------------
  539. //
  540. // The following are neccessary defines, define guids and typedefs enums
  541. // they are created for the benefit of AddNewVirtualRoot()
  542. //+---------------------------------------------------------------------------
  543. #define error_leave(x) goto leave_routine;
  544. #define MY_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
  545. EXTERN_C const GUID name \
  546. = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
  547. MY_DEFINE_GUID(CLSID_MSAdminBase, 0xa9e69610, 0xb80d, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50);
  548. MY_DEFINE_GUID(IID_IMSAdminBase, 0x70b51430, 0xb6ca, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50);
  549. //+---------------------------------------------------------------------------
  550. //
  551. // Function: AddNewVirtualRoot
  552. //
  553. // Purpose: Helps create Virtual Roots in the WWW and FTP services.
  554. //
  555. // Arguments:
  556. // PWSTR szDirW : Alias of new Virtual Root
  557. // PWSTR szPathW: Physical Path to wich the new Virtual Root will point
  558. //
  559. // Returns: S_OK if successfull, Win32 error otherwise.
  560. //
  561. // Author: a-anasj Mar 9/1998
  562. //
  563. // Notes:
  564. //
  565. HRESULT AddNewVirtualRoot(e_rootType rootType, PWSTR szDirW, PWSTR szPathW)
  566. {
  567. HRESULT hr = S_OK;
  568. IMSAdminBase *pIMeta = NULL;
  569. METADATA_HANDLE hMeta = NULL; // handle to metabase
  570. PWSTR szMBPathW;
  571. if (www == rootType)
  572. {
  573. szMBPathW = L"/LM/W3svc/1/ROOT";
  574. }
  575. else if (ftp == rootType)
  576. {
  577. szMBPathW = L"/LM/MSFTPSVC/1/ROOT";
  578. }
  579. else
  580. {
  581. // Unknown root type
  582. //
  583. ASSERT(FALSE);
  584. return S_FALSE;
  585. }
  586. if (FAILED(CoInitialize(NULL)))
  587. {
  588. return S_FALSE;
  589. }
  590. // Create an instance of the metabase object
  591. hr=::CoCreateInstance(CLSID_MSAdminBase,//CLSID_MSAdminBase,
  592. NULL,
  593. CLSCTX_ALL,
  594. IID_IMSAdminBase,
  595. (void **)&pIMeta);
  596. if (FAILED(hr))
  597. {
  598. error_leave("CoCreateInstance");
  599. }
  600. // open key to ROOT on website #1 (where all the VDirs live)
  601. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  602. szMBPathW,
  603. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  604. 1000,
  605. &hMeta);
  606. if (FAILED(hr))
  607. {
  608. error_leave("OpenKey");
  609. }
  610. // Add new VDir called szDirW
  611. hr=pIMeta->AddKey(hMeta, szDirW);
  612. if (FAILED(hr))
  613. {
  614. error_leave("Addkey");
  615. }
  616. // Set the physical path for this VDir
  617. METADATA_RECORD mr;
  618. mr.dwMDIdentifier = MD_VR_PATH;
  619. mr.dwMDAttributes = METADATA_INHERIT ;
  620. mr.dwMDUserType = IIS_MD_UT_FILE;
  621. mr.dwMDDataType = STRING_METADATA;
  622. mr.dwMDDataLen = (wcslen(szPathW) + 1) * sizeof(WCHAR);
  623. mr.pbMDData = (unsigned char*)(szPathW);
  624. hr=pIMeta->SetData(hMeta,szDirW,&mr);
  625. if (FAILED(hr))
  626. {
  627. error_leave("SetData");
  628. }
  629. //
  630. // we also need to set the keytype
  631. //
  632. ZeroMemory((PVOID)&mr, sizeof(METADATA_RECORD));
  633. mr.dwMDIdentifier = MD_KEY_TYPE;
  634. mr.dwMDAttributes = METADATA_INHERIT ;
  635. mr.dwMDUserType = IIS_MD_UT_FILE;
  636. mr.dwMDDataType = STRING_METADATA;
  637. mr.pbMDData = (unsigned char*)(www == rootType? L"IIsWebVirtualDir" : L"IIsFtpVirtualDir");
  638. mr.dwMDDataLen = (lstrlenW((PWSTR)mr.pbMDData) + 1) * sizeof(WCHAR);
  639. hr=pIMeta->SetData(hMeta,szDirW,&mr);
  640. if (FAILED(hr))
  641. {
  642. error_leave("SetData");
  643. }
  644. // Call CloseKey() prior to calling SaveData
  645. pIMeta->CloseKey(hMeta);
  646. hMeta = NULL;
  647. // Flush out the changes and close
  648. hr=pIMeta->SaveData();
  649. if (FAILED(hr))
  650. {
  651. error_leave("SaveData");
  652. }
  653. leave_routine:
  654. if (pIMeta)
  655. {
  656. if(hMeta)
  657. pIMeta->CloseKey(hMeta);
  658. pIMeta->Release();
  659. }
  660. CoUninitialize();
  661. return hr;
  662. }
  663. //+---------------------------------------------------------------------------
  664. //
  665. // Function: SetVirtualRootAccessPermissions
  666. //
  667. // Purpose : Sets Access Permissions to a Virtual Roots in the WWW service.
  668. //
  669. // Arguments:
  670. // PWSTR szVirtDir : Alias of new Virtual Root
  671. // DWORD dwAccessPermisions can be any combination of the following
  672. // or others defined in iiscnfg.h
  673. // MD_ACCESS_EXECUTE | MD_ACCESS_WRITE | MD_ACCESS_READ;
  674. //
  675. // Returns: S_OK if successfull, Win32 error otherwise.
  676. //
  677. // Author: a-anasj Mar 18/1998
  678. //
  679. // Notes:
  680. //
  681. HRESULT SetVirtualRootAccessPermissions(PWSTR szVirtDir, DWORD dwAccessPermisions)
  682. {
  683. HRESULT hr = S_OK; // com error status
  684. IMSAdminBase *pIMeta = NULL;
  685. METADATA_HANDLE hMeta = NULL; // handle to metabase
  686. if (FAILED(CoInitialize(NULL)))
  687. {
  688. return S_FALSE;
  689. }
  690. // Create an instance of the metabase object
  691. hr=::CoCreateInstance(CLSID_MSAdminBase,
  692. NULL,
  693. CLSCTX_ALL,
  694. IID_IMSAdminBase,
  695. (void **)&pIMeta);
  696. if (FAILED(hr))
  697. {
  698. error_leave("CoCreateInstance");
  699. }
  700. // open key to ROOT on website #1 (where all the VDirs live)
  701. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  702. szVirtDir,
  703. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  704. 1000,
  705. &hMeta);
  706. if (FAILED(hr))
  707. {
  708. error_leave("OpenKey");
  709. }
  710. // Set the physical path for this VDir
  711. METADATA_RECORD mr;
  712. mr.dwMDIdentifier = MD_ACCESS_PERM;
  713. mr.dwMDAttributes = METADATA_INHERIT ;
  714. mr.dwMDUserType = IIS_MD_UT_FILE;
  715. mr.dwMDDataType = DWORD_METADATA; // this used to be STRING_METADATA, but that was
  716. // the incorrect type and was causing vdir access
  717. // problems.
  718. // Now, create the access perm
  719. mr.pbMDData = (PBYTE) &dwAccessPermisions;
  720. mr.dwMDDataLen = sizeof (DWORD);
  721. mr.dwMDDataTag = 0; // datatag is a reserved field.
  722. hr=pIMeta->SetData(hMeta,
  723. TEXT ("/"), // The root of the Virtual Dir we opened above
  724. &mr);
  725. if (FAILED(hr))
  726. {
  727. error_leave("SetData");
  728. }
  729. // Call CloseKey() prior to calling SaveData
  730. pIMeta->CloseKey(hMeta);
  731. hMeta = NULL;
  732. // Flush out the changes and close
  733. hr=pIMeta->SaveData();
  734. if (FAILED(hr))
  735. {
  736. error_leave("SaveData");
  737. }
  738. leave_routine:
  739. if (pIMeta)
  740. {
  741. if(hMeta)
  742. pIMeta->CloseKey(hMeta);
  743. pIMeta->Release();
  744. }
  745. CoUninitialize();
  746. return hr;
  747. }
  748. //+---------------------------------------------------------------------------
  749. //
  750. // Function: RemoveCPSVRoots
  751. //
  752. // Purpose: Deletes the Virtual Directories required for Phone Book Service.
  753. //
  754. // Arguments: None
  755. //
  756. // Returns: TRUE if successfull, FALSE otherwise.
  757. //
  758. // Author: a-anasj Mar 9/1998
  759. // quintinb Jan 10/1999 added error checking and replaced asserts with traces
  760. //
  761. // Notes:
  762. //
  763. BOOL RemoveCPSVRoots()
  764. {
  765. HRESULT hr;
  766. HKEY hKey;
  767. hr = DeleteVirtualRoot(www, L"PBServer");
  768. if (SUCCEEDED(hr))
  769. {
  770. //
  771. // Now delete the associated reg key
  772. //
  773. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  774. L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots",
  775. KEY_ALL_ACCESS, &hKey);
  776. if (SUCCEEDED(hr))
  777. {
  778. if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBServer"))
  779. {
  780. hr = S_OK;
  781. }
  782. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  783. {
  784. hr = S_FALSE;
  785. }
  786. RegCloseKey(hKey);
  787. }
  788. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  789. {
  790. hr = S_FALSE;
  791. }
  792. }
  793. TraceError("RemoveCPSVRoots -- Deleting PBServer Www Vroot", hr);
  794. hr = DeleteVirtualRoot(www, L"PBSData");
  795. if (SUCCEEDED(hr))
  796. {
  797. //
  798. // Now delete the associated reg key
  799. //
  800. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  801. L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots",
  802. KEY_ALL_ACCESS, &hKey);
  803. if (SUCCEEDED(hr))
  804. {
  805. if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBSData"))
  806. {
  807. hr = S_OK;
  808. }
  809. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  810. {
  811. hr = S_FALSE;
  812. }
  813. RegCloseKey(hKey);
  814. }
  815. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  816. {
  817. hr = S_FALSE;
  818. }
  819. }
  820. TraceError("RemoveCPSVRoots -- Deleting PBSData WWW Vroot", hr);
  821. hr = DeleteVirtualRoot(ftp, L"PBSData");
  822. if (SUCCEEDED(hr))
  823. {
  824. //
  825. // Now delete the associated reg key
  826. //
  827. hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
  828. L"SYSTEM\\CurrentControlSet\\Services\\MSFTPSVC\\Parameters\\Virtual Roots",
  829. KEY_ALL_ACCESS, &hKey);
  830. if (SUCCEEDED(hr))
  831. {
  832. if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBSData"))
  833. {
  834. hr = S_OK;
  835. }
  836. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  837. {
  838. hr = S_FALSE;
  839. }
  840. RegCloseKey(hKey);
  841. }
  842. else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
  843. {
  844. hr = S_FALSE;
  845. }
  846. }
  847. TraceError("RemoveCPSVRoots -- Deleting PBSData FTP Vroot", hr);
  848. return TRUE;
  849. }
  850. //+---------------------------------------------------------------------------
  851. //
  852. // Function: DeleteVirtualRoot
  853. //
  854. // Purpose: Deletes a Virtual Root in the WWW or FTP services.
  855. //
  856. // Arguments:
  857. //
  858. // Returns: S_OK if successfull, Win32 error otherwise.
  859. //
  860. // Author: a-anasj Mar 9/1998
  861. //
  862. // Notes:
  863. //
  864. HRESULT DeleteVirtualRoot(e_rootType rootType, PWSTR szPathW)
  865. {
  866. HRESULT hr = S_OK; // com error status
  867. IMSAdminBase *pIMeta = NULL;
  868. METADATA_HANDLE hMeta = NULL; // handle to metabase
  869. PWSTR szMBPathW;
  870. if (www == rootType)
  871. {
  872. szMBPathW = L"/LM/W3svc/1/ROOT";
  873. }
  874. else if (ftp == rootType)
  875. {
  876. szMBPathW = L"/LM/MSFTPSVC/1/ROOT";
  877. }
  878. else
  879. {
  880. // Unknown root type
  881. //
  882. ASSERT(FALSE);
  883. return S_FALSE;
  884. }
  885. if (FAILED(CoInitialize(NULL)))
  886. {
  887. return S_FALSE;
  888. //error_leave("CoInitialize");
  889. }
  890. // Create an instance of the metabase object
  891. hr=::CoCreateInstance(CLSID_MSAdminBase,//CLSID_MSAdminBase,
  892. NULL,
  893. CLSCTX_ALL,
  894. IID_IMSAdminBase,
  895. (void **)&pIMeta);
  896. if (FAILED(hr))
  897. {
  898. error_leave("CoCreateInstance");
  899. }
  900. // open key to ROOT on website #1 (where all the VDirs live)
  901. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  902. szMBPathW,
  903. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  904. 1000,
  905. &hMeta);
  906. if (FAILED(hr))
  907. {
  908. error_leave("OpenKey");
  909. }
  910. // Add new VDir called szDirW
  911. hr=pIMeta->DeleteKey(hMeta, szPathW);
  912. if (FAILED(hr))
  913. {
  914. error_leave("DeleteKey");
  915. }
  916. // Call CloseKey() prior to calling SaveData
  917. pIMeta->CloseKey(hMeta);
  918. hMeta = NULL;
  919. // Flush out the changes and close
  920. hr=pIMeta->SaveData();
  921. if (FAILED(hr))
  922. {
  923. error_leave("SaveData");
  924. }
  925. leave_routine:
  926. if (pIMeta)
  927. {
  928. if(hMeta)
  929. pIMeta->CloseKey(hMeta);
  930. pIMeta->Release();
  931. }
  932. CoUninitialize();
  933. return hr;
  934. }
  935. HRESULT SetDirectoryAccessPermissions(PWSTR pszFile, ACCESS_MASK AccessRightsToModify,
  936. ACCESS_MODE fAccessFlags, PSID pSid)
  937. {
  938. if (!pszFile && !pSid)
  939. {
  940. return E_INVALIDARG;
  941. }
  942. EXPLICIT_ACCESS AccessEntry = {0};
  943. PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
  944. PACL pOldAccessList = NULL;
  945. PACL pNewAccessList = NULL;
  946. DWORD dwRes;
  947. // Get the current DACL information from the object.
  948. dwRes = GetNamedSecurityInfo(pszFile, // name of the object
  949. SE_FILE_OBJECT, // type of object
  950. DACL_SECURITY_INFORMATION, // type of information to set
  951. NULL, // provider is Windows NT
  952. NULL, // name or GUID of property or property set
  953. &pOldAccessList, // receives existing DACL information
  954. NULL, // receives existing SACL information
  955. &pSecurityDescriptor); // receives a pointer to the security descriptor
  956. if (ERROR_SUCCESS == dwRes)
  957. {
  958. //
  959. // Initialize the access list entry.
  960. //
  961. BuildTrusteeWithSid(&(AccessEntry.Trustee), pSid);
  962. AccessEntry.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
  963. AccessEntry.grfAccessMode = fAccessFlags;
  964. //
  965. // Set provider-independent standard rights.
  966. //
  967. AccessEntry.grfAccessPermissions = AccessRightsToModify;
  968. //
  969. // Build an access list from the access list entry.
  970. //
  971. dwRes = SetEntriesInAcl(1, &AccessEntry, pOldAccessList, &pNewAccessList);
  972. if (ERROR_SUCCESS == dwRes)
  973. {
  974. //
  975. // Set the access-control information in the object's DACL.
  976. //
  977. dwRes = SetNamedSecurityInfo(pszFile, // name of the object
  978. SE_FILE_OBJECT, // type of object
  979. DACL_SECURITY_INFORMATION, // type of information to set
  980. NULL, // pointer to the new owner SID
  981. NULL, // pointer to the new primary group SID
  982. pNewAccessList, // pointer to new DACL
  983. NULL); // pointer to new SACL
  984. }
  985. }
  986. //
  987. // Free the returned buffers.
  988. //
  989. if (pNewAccessList)
  990. {
  991. LocalFree(pNewAccessList);
  992. }
  993. if (pSecurityDescriptor)
  994. {
  995. LocalFree(pSecurityDescriptor);
  996. }
  997. //
  998. // If the system is using FAT instead of NTFS, then we will get the Invalid Acl error.
  999. //
  1000. if (ERROR_INVALID_ACL == dwRes)
  1001. {
  1002. return S_FALSE;
  1003. }
  1004. else
  1005. {
  1006. return HRESULT_FROM_WIN32(dwRes);
  1007. }
  1008. }
  1009. void SetCpsDirPermissions()
  1010. {
  1011. WCHAR szPath[MAX_PATH+1];
  1012. HRESULT hr;
  1013. //
  1014. // Create the SID for the Everyone Account (World account)
  1015. //
  1016. PSID pWorldSid;
  1017. SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
  1018. BOOL bRet = AllocateAndInitializeSid (&WorldSidAuthority, 1, SECURITY_WORLD_RID,
  1019. 0, 0, 0, 0, 0, 0, 0, &pWorldSid);
  1020. if (bRet && pWorldSid )
  1021. {
  1022. const ACCESS_MASK c_Write = FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA |
  1023. FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE |
  1024. FILE_DELETE_CHILD | FILE_APPEND_DATA;
  1025. const ACCESS_MASK c_Read = FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA |
  1026. FILE_LIST_DIRECTORY | SYNCHRONIZE | READ_CONTROL;
  1027. const ACCESS_MASK c_Execute = FILE_EXECUTE | FILE_TRAVERSE;
  1028. ACCESS_MASK arCpsRoot= c_Read;
  1029. ACCESS_MASK arCpsBin= c_Read | c_Execute;
  1030. ACCESS_MASK arCpsData= c_Read | c_Write;
  1031. ACCESS_MODE fAccessFlags = GRANT_ACCESS;
  1032. //
  1033. // Set the Data Dir access permissions
  1034. //
  1035. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsDataPath);
  1036. hr = SetDirectoryAccessPermissions(szPath, arCpsData, fAccessFlags, pWorldSid);
  1037. TraceError("SetCpsDirPermissions -- Data dir", hr);
  1038. //
  1039. // Set the Bin Dir access permissions
  1040. //
  1041. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsBinPath);
  1042. hr = SetDirectoryAccessPermissions(szPath, arCpsBin, fAccessFlags, pWorldSid);
  1043. TraceError("SetCpsDirPermissions -- Bin dir", hr);
  1044. //
  1045. // Set the Root Dir access permissions
  1046. //
  1047. wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsRootPath);
  1048. hr = SetDirectoryAccessPermissions(szPath, arCpsRoot, fAccessFlags, pWorldSid);
  1049. TraceError("SetCpsDirPermissions -- Root dir", hr);
  1050. FreeSid(pWorldSid);
  1051. }
  1052. }
  1053. DWORD AddToRegKeySD(PCWSTR pszRegKeyName, PSID pGroupSID, DWORD dwAccessMask)
  1054. {
  1055. #define MAX_DOMAIN_LEN 80
  1056. PSECURITY_DESCRIPTOR pRelSD = NULL;
  1057. PSECURITY_DESCRIPTOR pAbsSD = NULL;
  1058. DWORD cbSID;
  1059. SID_NAME_USE snuGroup;
  1060. DWORD dwDomainSize;
  1061. WCHAR szDomainName[MAX_DOMAIN_LEN];
  1062. PACL pDACL;
  1063. DWORD dwSDLength = 0;
  1064. DWORD dwSDRevision;
  1065. DWORD dwDACLLength = 0;
  1066. SECURITY_DESCRIPTOR_CONTROL sdcSDControl;
  1067. PACL pNewDACL = NULL;
  1068. DWORD dwAddDACLLength = 0;
  1069. BOOL fHasDACL = FALSE;
  1070. BOOL fDACLDefaulted = FALSE;
  1071. ACCESS_ALLOWED_ACE *pDACLAce;
  1072. DWORD dwError = 0;
  1073. DWORD i;
  1074. DWORD dwcSDLength; // Security descriptor length
  1075. if (!pszRegKeyName || !pGroupSID)
  1076. {
  1077. return ERROR_INVALID_PARAMETER;
  1078. }
  1079. // handle for security registry key
  1080. HKEY hSecurityRegKey = NULL;
  1081. // now open reg key to set security
  1082. dwError = RegOpenKeyEx (HKEY_LOCAL_MACHINE, pszRegKeyName, 0, KEY_ALL_ACCESS, &hSecurityRegKey);
  1083. if (dwError)
  1084. {
  1085. goto ErrorExit;
  1086. }
  1087. // get length of security descriptor
  1088. dwError = RegQueryInfoKey (hSecurityRegKey, NULL, NULL, NULL, NULL,
  1089. NULL, NULL, NULL, NULL, NULL, &dwcSDLength, NULL);
  1090. if (dwError)
  1091. {
  1092. goto ErrorExit;
  1093. }
  1094. // get SD memory
  1095. pRelSD = (PSECURITY_DESCRIPTOR) LocalAlloc (LPTR, (UINT)dwcSDLength);
  1096. // first get the self-relative SD
  1097. dwError = RegGetKeySecurity (hSecurityRegKey,
  1098. (SECURITY_INFORMATION)(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION),
  1099. pRelSD, &dwcSDLength);
  1100. if (dwError)
  1101. {
  1102. goto ErrorExit;
  1103. }
  1104. // check if SD is good
  1105. if (!pRelSD || !IsValidSecurityDescriptor (pRelSD))
  1106. {
  1107. dwError = GetLastError();
  1108. goto ErrorExit;
  1109. }
  1110. // get SD control bits
  1111. if (!GetSecurityDescriptorControl (pRelSD, (PSECURITY_DESCRIPTOR_CONTROL)&sdcSDControl,
  1112. (LPDWORD) &dwSDRevision))
  1113. {
  1114. dwError = GetLastError();
  1115. goto ErrorExit;
  1116. }
  1117. // check if DACL is present
  1118. if (SE_DACL_PRESENT & sdcSDControl)
  1119. {
  1120. // get dacl
  1121. if (!GetSecurityDescriptorDacl (pRelSD, (LPBOOL)&fHasDACL, (PACL *) &pDACL,
  1122. (LPBOOL) &fDACLDefaulted))
  1123. {
  1124. dwError = GetLastError();
  1125. goto ErrorExit;
  1126. }
  1127. // get dacl length
  1128. dwDACLLength = pDACL->AclSize;
  1129. // get length of new DACL
  1130. dwAddDACLLength = sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + GetLengthSid (pGroupSID);
  1131. }
  1132. else
  1133. {
  1134. // get length of new DACL
  1135. dwAddDACLLength = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) -
  1136. sizeof (DWORD) + GetLengthSid (pGroupSID);
  1137. }
  1138. // get memory needed for new DACL
  1139. pNewDACL = ( PACL) LocalAlloc (LPTR, dwDACLLength + dwAddDACLLength);
  1140. if (!pNewDACL)
  1141. {
  1142. dwError = GetLastError();
  1143. goto ErrorExit;
  1144. }
  1145. // get the sd length
  1146. dwSDLength = GetSecurityDescriptorLength (pRelSD);
  1147. // get memory for new SD
  1148. pAbsSD = ( PSECURITY_DESCRIPTOR)LocalAlloc ( LPTR, dwSDLength + dwAddDACLLength);
  1149. if (!pAbsSD)
  1150. {
  1151. dwError = GetLastError();
  1152. goto ErrorExit;
  1153. }
  1154. // change self-relative SD to absolute by making new SD
  1155. if (!InitializeSecurityDescriptor (pAbsSD, SECURITY_DESCRIPTOR_REVISION))
  1156. {
  1157. dwError = GetLastError();
  1158. goto ErrorExit;
  1159. }
  1160. // init new DACL
  1161. if (!InitializeAcl (pNewDACL, dwDACLLength + dwAddDACLLength, ACL_REVISION))
  1162. {
  1163. dwError = GetLastError();
  1164. goto ErrorExit;
  1165. }
  1166. // now add in all of the ACEs into the new DACL (if org DACL is there)
  1167. if (SE_DACL_PRESENT & sdcSDControl)
  1168. {
  1169. for (i = 0; i < pDACL->AceCount; i++)
  1170. {
  1171. // get ace from original dacl
  1172. if (!GetAce (pDACL, i, (LPVOID *) &pDACLAce))
  1173. {
  1174. dwError = GetLastError();
  1175. goto ErrorExit;
  1176. }
  1177. // check if group sid is already there. If so, skip it(don't copy)
  1178. if (EqualSid ((PSID)&(pDACLAce->SidStart), pGroupSID))
  1179. {
  1180. continue;
  1181. }
  1182. // now add ace to new dacl
  1183. if (!AddAccessAllowedAce (pNewDACL, ACL_REVISION, pDACLAce->Mask,
  1184. (PSID)&(pDACLAce->SidStart)))
  1185. {
  1186. dwError = GetLastError();
  1187. goto ErrorExit;
  1188. }
  1189. }
  1190. }
  1191. // now add new ACE to new DACL
  1192. if (!AddAccessAllowedAce (pNewDACL, ACL_REVISION, dwAccessMask, pGroupSID))
  1193. {
  1194. dwError = GetLastError();
  1195. goto ErrorExit;
  1196. }
  1197. // check if everything went ok
  1198. if (!IsValidAcl (pNewDACL))
  1199. {
  1200. dwError = GetLastError();
  1201. goto ErrorExit;
  1202. }
  1203. // now set security descriptor DACL
  1204. if (!SetSecurityDescriptorDacl (pAbsSD, TRUE, pNewDACL, fDACLDefaulted))
  1205. {
  1206. dwError = GetLastError();
  1207. goto ErrorExit;
  1208. }
  1209. // check if everything went ok
  1210. if (!IsValidSecurityDescriptor (pAbsSD))
  1211. {
  1212. dwError = GetLastError();
  1213. goto ErrorExit;
  1214. }
  1215. // now set the reg key security (this will overwrite any existing security)
  1216. dwError = RegSetKeySecurity (hSecurityRegKey,
  1217. (SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION), pAbsSD);
  1218. ErrorExit:
  1219. if (hSecurityRegKey)
  1220. {
  1221. RegCloseKey (hSecurityRegKey);
  1222. }
  1223. if (pRelSD)
  1224. {
  1225. LocalFree(pRelSD);
  1226. }
  1227. if (pAbsSD)
  1228. {
  1229. LocalFree (pAbsSD);
  1230. }
  1231. if (pNewDACL)
  1232. {
  1233. LocalFree (pNewDACL);
  1234. }
  1235. return (dwError);
  1236. }