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

//+---------------------------------------------------------------------------
//
// File: NcCPS.CPP
//
// Module: NetOC.DLL
//
// Synopsis: Implements the dll entry points required to integrate into
// NetOC.DLL the installation of the following components.
//
// NETCPS
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// Author: a-anasj 9 Mar 1998
//
//+---------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <iadmw.h> // Interface header
#include <iiscnfg.h> // MD_ & IIS_MD_ defines
#include <LOADPERF.H>
#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>
#include "ncatl.h"
#include "resource.h"
#include "nccm.h"
//
// Define Globals
//
WCHAR g_szProgramFiles[MAX_PATH+1];
//
// Define Constants
//
static const WCHAR c_szInetRegPath[] = L"Software\\Microsoft\\InetStp";
static const WCHAR c_szWWWRootValue[] = L"PathWWWRoot";
static const WCHAR c_szSSFmt[] = L"%s%s";
static const WCHAR c_szMsAccess[] = L"Microsoft Access";
static const WCHAR c_szOdbcDataSourcesPath[] = L"SOFTWARE\\ODBC\\ODBC.INI\\ODBC Data Sources";
static const WCHAR c_szPbServer[] = L"PBServer";
static const WCHAR c_szOdbcInstKey[] = L"SOFTWARE\\ODBC\\ODBCINST.INI";
static const WCHAR c_szWwwRootPath[] = L"\\Inetpub\\wwwroot";
static const WCHAR c_szWwwRoot[] = L"\\wwwroot";
static const WCHAR c_szPbsRootPath[] = L"\\Phone Book Service";
static const WCHAR c_szPbsBinPath[] = L"\\Phone Book Service\\Bin";
static const WCHAR c_szPbsDataPath[] = L"\\Phone Book Service\\Data";
static const WCHAR c_szOdbcPbserver[] = L"Software\\ODBC\\odbc.ini\\pbserver";
const DWORD c_dwCpsDirID = 123175; // just must be larger than DIRID_USER = 0x8000;
//+---------------------------------------------------------------------------
//
// Function: HrOcCpsPreQueueFiles
//
// Purpose: Called by optional components installer code to handle
// additional installation requirements for PhoneBook Server.
//
// Arguments:
// pnocd [in] Pointer to NETOC data.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: quintinb 18 Sep 1998
//
// Notes:
//
HRESULT HrOcCpsPreQueueFiles(PNETOCDATA pnocd)
{
HRESULT hr = S_OK;
switch ( pnocd->eit )
{
case IT_UPGRADE:
case IT_INSTALL:
case IT_REMOVE:
// We need to setup the custom DIRID so that CPS will install
// to the correct location. First get the path from the system.
//
ZeroMemory(g_szProgramFiles, sizeof(g_szProgramFiles));
// This is a fresh install of CMAK, don't return an error
//
hr = SHGetSpecialFolderPath(NULL, g_szProgramFiles, CSIDL_PROGRAM_FILES, FALSE);
if (SUCCEEDED(hr))
{
if (IT_UPGRADE == pnocd->eit)
{
hr = HrMoveOldCpsInstall(g_szProgramFiles);
}
// Next Create the CPS Dir ID
//
if (SUCCEEDED(hr))
{
hr = HrEnsureInfFileIsOpen(pnocd->pszComponentId, *pnocd);
if (SUCCEEDED(hr))
{
if(!SetupSetDirectoryId(pnocd->hinfFile, c_dwCpsDirID, g_szProgramFiles))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}
}
break;
}
TraceError("HrOcCpsPreQueueFiles", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrMoveOldCpsInstall
//
// Purpose: This function moves the old cps directory to the new cps directory
// location. Because of the problems with Front Page Extensions and
// directory permissions we moved our install directory out from under
// wwwroot to Program Files instead.
//
// Arguments:
// pszprogramFiles [in]
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: quintinb 26 Jan 1999
//
// Notes:
//
HRESULT HrMoveOldCpsInstall(PCWSTR pszProgramFiles)
{
WCHAR szOldCpsLocation[MAX_PATH+1];
WCHAR szNewCpsLocation[MAX_PATH+1];
WCHAR szTemp[MAX_PATH+1];
SHFILEOPSTRUCT fOpStruct;
HRESULT hr = S_OK;
if ((NULL == pszProgramFiles) || (L'\0' == pszProgramFiles[0]))
{
return E_INVALIDARG;
}
//
// First, lets build the old CPS location
//
hr = HrGetWwwRootDir(szTemp, celems(szTemp));
if (SUCCEEDED(hr))
{
//
// Zero the string buffers
//
ZeroMemory(szOldCpsLocation, celems(szOldCpsLocation));
ZeroMemory(szNewCpsLocation, celems(szNewCpsLocation));
wsprintfW(szOldCpsLocation, c_szSSFmt, szTemp, c_szPbsRootPath);
//
// Now check to see if the old cps location exists
//
DWORD dwDirectoryAttributes = GetFileAttributes(szOldCpsLocation);
//
// If we didn't get back -1 (error return code for GetFileAttributes), check to
// see if we have a directory. If so, go ahead and copy the data over.
//
if ((-1 != dwDirectoryAttributes) && (dwDirectoryAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
//
// Now build the new cps location
//
wsprintfW(szNewCpsLocation, c_szSSFmt, pszProgramFiles, c_szPbsRootPath);
//
// Now copy the old files to the new location
//
ZeroMemory(&fOpStruct, sizeof(fOpStruct));
fOpStruct.hwnd = NULL;
fOpStruct.wFunc = FO_COPY;
fOpStruct.pTo = szNewCpsLocation;
fOpStruct.pFrom = szOldCpsLocation;
fOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR;
if (0== SHFileOperation(&fOpStruct))
{
//
// Now delete the original directory
//
fOpStruct.pTo = NULL;
fOpStruct.wFunc = FO_DELETE;
if (0 != SHFileOperation(&fOpStruct))
{
hr = S_FALSE;
}
}
else
{
//
// Note, SHFileOperation isn't guarenteed to return anything sensible here. We might
// get back ERROR_NO_TOKEN or ERROR_INVALID_HANDLE, etc when the directory is just missing.
// The following check probably isn't useful anymore because of this but I will leave it just
// in case. Hopefully the file check above will make sure we don't hit this but ...
//
DWORD dwError = GetLastError();
if ((ERROR_FILE_NOT_FOUND == dwError) || (ERROR_PATH_NOT_FOUND == dwError))
{
//
// Then we couldn't find the old dir to move it. Not fatal.
//
hr = S_FALSE;
}
else
{
hr = HRESULT_FROM_WIN32(dwError);
}
}
}
else
{
//
// Then we couldn't find the old dir to move it. Not fatal.
//
hr = S_FALSE;
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrGetWwwRootDir
//
// Purpose: This function retrieves the location of the InetPub\wwwroot dir from the
// WwwRootDir registry key.
//
// Arguments:
// szInetPub [out] String Buffer to hold the InetPub dir path
// uInetPubCount [in] number of chars in the output buffer
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: quintinb 26 Jan 1999
//
// Notes:
//
HRESULT HrGetWwwRootDir(PWSTR szWwwRoot, UINT uWwwRootCount)
{
HKEY hKey;
HRESULT hr = S_OK;
//
// Check input params
//
if ((NULL == szWwwRoot) || (0 == uWwwRootCount))
{
return E_INVALIDARG;
}
//
// Set the strings to empty
//
szWwwRoot[0] = L'\0';
//
// First try to open the InetStp key and get the wwwroot value.
//
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szInetRegPath, KEY_READ, &hKey);
if (SUCCEEDED(hr))
{
DWORD dwSize = uWwwRootCount * sizeof(WCHAR);
RegQueryValueExW(hKey, c_szWWWRootValue, NULL, NULL, (LPBYTE)szWwwRoot, &dwSize);
RegCloseKey(hKey);
hr = S_OK;
}
if (L'\0' == szWwwRoot[0])
{
// Well, we didn't get anything from the registry, lets try building the default.
//
WCHAR szTemp[MAX_PATH+1];
if (GetWindowsDirectory(szTemp, MAX_PATH))
{
// Get the drive that the windows dir is on using _tsplitpath
//
WCHAR szDrive[_MAX_DRIVE+1];
_wsplitpath(szTemp, szDrive, NULL, NULL, NULL);
if (uWwwRootCount > (UINT)(lstrlenW(szDrive) + lstrlenW (c_szWwwRootPath) + 1))
{
wsprintfW(szWwwRoot, c_szSSFmt, szDrive, c_szWwwRootPath);
hr = S_OK;
}
else
{
hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
}
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: HrOcCpsOnInstall
//
// Purpose: Called by optional components installer code to handle
// additional installation requirements for PhoneBook Server.
//
// Arguments:
// pnocd [in] Pointer to NETOC data.
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: a-anasj 9 Mar 1998
//
// Notes:
//
HRESULT HrOcCpsOnInstall(PNETOCDATA pnocd)
{
HRESULT hr = S_OK;
DWORD dwRet = 0;
BOOL bRet = FALSE;
switch (pnocd->eit)
{
case IT_INSTALL:
case IT_UPGRADE:
{
// Register MS_Access data source
//
dwRet = RegisterPBServerDataSource();
if ( NULL == dwRet)
{
hr = S_FALSE;
}
// Load Perfomance Monitor Counters
//
bRet = LoadPerfmonCounters();
if (FALSE == bRet)
{
hr = S_FALSE;
}
// Create Virtual WWW and FTP roots
//
if (IT_UPGRADE == pnocd->eit)
{
//
// If this is an upgrade, we must first delete the old Virtual Roots
// before we can create new ones.
//
RemoveCPSVRoots();
}
dwRet = CreateCPSVRoots();
if (NULL == dwRet)
{
hr = S_FALSE;
}
SetCpsDirPermissions();
//
// set additional security permssion to the reg key for ODBC
//
PSID pAuthenticatedUsersSid;
SID_IDENTIFIER_AUTHORITY NTSidAuthority = SECURITY_NT_AUTHORITY;
AllocateAndInitializeSid (&NTSidAuthority, 1, SECURITY_AUTHENTICATED_USER_RID,
0, 0, 0, 0, 0, 0, 0, &pAuthenticatedUsersSid);
//
// This function will handle pAuthenticatedUsersSid == NULL
//
AddToRegKeySD(c_szOdbcPbserver,
pAuthenticatedUsersSid,
KEY_QUERY_VALUE |
KEY_SET_VALUE |
KEY_CREATE_SUB_KEY |
KEY_ENUMERATE_SUB_KEYS |
KEY_NOTIFY |
DELETE |
READ_CONTROL);
if (pAuthenticatedUsersSid)
{
FreeSid(pAuthenticatedUsersSid);
}
}
break;
case IT_REMOVE:
// Remove the Virtual Directories, so access to the service is stopped.
//
RemoveCPSVRoots();
break;
}
TraceError("HrOcCpsOnInstall", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: LoadPerfmonCounters
//
// Purpose: Do whatever is neccessary to make the performance monitor Display the PBServerMonitor counters
//
// Arguments:
//
// Returns: BOOL TRUE if successfull, Not TRUE otherwise.
//
// Author: a-anasj Mar 9/1998
//
// Notes: One of the installation requirements for PhoneBook Server.
// is to load the perfomance monitor counters that allow PBServerMonitor
// to report to the user on PhoneBook Server performance.
// In this function we add the services registry entry first then we
// call into LoadPerf.Dll to load the counters for us. The order is imperative.
// I then add other registry entries related to PBServerMonitor.
//
BOOL LoadPerfmonCounters()
{
WinExec("lodctr.exe CPSSym.ini", SW_HIDE);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: RegisterPBServerDataSource
//
// Purpose: Registers PBServer.
//
// Arguments: None
//
// Returns: Win32 error code
//
// Author: a-anasj 9 Mar 1998
//
// Notes:
// History: 7-9-97 a-frankh Created
// 10/4/97 mmaguire RAID #19906 - Totally restructured to include error handling
// 5-14-98 quintinb removed unnecessary comments and cleaned up the function.
//
BOOL RegisterPBServerDataSource()
{
DWORD dwRet = 0;
HKEY hkODBCInst = NULL;
HKEY hkODBCDataSources = NULL;
DWORD dwIndex;
WCHAR szName[MAX_PATH+1];
__try
{
// Open the hkODBCInst RegKey
//
dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, c_szOdbcInstKey, &hkODBCInst);
if((ERROR_SUCCESS != dwRet) || (NULL == hkODBCInst))
{
__leave;
}
// Look to see the the "Microsoft Access" RegKey is defined
// If it is, then set the value of the ODBC Data Sources RegKey below
//
dwIndex = 0;
do
{
dwRet = RegEnumKey(hkODBCInst,dwIndex,szName,celems(szName));
dwIndex++;
} while ((ERROR_SUCCESS == dwRet) && (NULL == wcsstr(szName, c_szMsAccess)));
if ( ERROR_SUCCESS != dwRet )
{
// We need the Microsoft Access *.mdb driver to work
// and we could not find it
//
__leave;
}
// Open the hkODBCDataSources RegKey
//
dwRet = RegOpenKey(HKEY_LOCAL_MACHINE, c_szOdbcDataSourcesPath,
&hkODBCDataSources);
if( ERROR_SUCCESS != dwRet )
{
__leave;
}
//
// Use the name from the resource for registration purposes.
//
// NOTE: this string is from HKLM\Software\ODBC\ODBCINST.INI\*
//
lstrcpy(szName, SzLoadIds(IDS_OC_PB_DSN_NAME));
// Set values in the hkODBCDataSources key
//
dwRet = RegSetValueEx(hkODBCDataSources, c_szPbServer, 0, REG_SZ,
(LPBYTE)szName, (lstrlenW(szName)+1)*sizeof(WCHAR));
if( ERROR_SUCCESS != dwRet )
{
__leave;
}
} // end __try
__finally
{
if (hkODBCInst)
{
RegCloseKey (hkODBCInst);
}
if (hkODBCDataSources)
{
RegCloseKey (hkODBCDataSources);
}
}
return (ERROR_SUCCESS == dwRet);
}
//+---------------------------------------------------------------------------
//
// Function: CreateCPSVRoots
//
// Purpose: Creates the Virtual Directories required for Phone Book Service.
//
// Arguments: None
//
// Returns: TRUE if successfull, FALSE otherwise.
//
// Author: a-anasj Mar 9/1998
//
// Notes:
//
BOOL CreateCPSVRoots()
{
// QBBUG - Should we make sure the physical paths exist before pointing a virtual root to them?
WCHAR szPath[MAX_PATH+1];
HRESULT hr;
if (L'\0' == g_szProgramFiles[0])
{
return FALSE;
}
// Create the Bindir virtual root
//
wsprintfW(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsBinPath);
hr = AddNewVirtualRoot(www, L"PBServer", szPath);
if (S_OK != hr)
{
return FALSE;
}
// Now we set the Execute access permissions on the PBServer Virtual Root
//
PWSTR szVirtDir;
szVirtDir = L"/LM/W3svc/1/ROOT/PBServer";
SetVirtualRootAccessPermissions( szVirtDir, MD_ACCESS_EXECUTE | MD_ACCESS_READ );
// Create the Data dir virtual roots
//
wsprintfW(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsDataPath);
hr = AddNewVirtualRoot(www, L"PBSData", szPath);
if (S_OK != hr)
{
return FALSE;
}
hr = AddNewVirtualRoot(ftp, L"PBSData", szPath);
if (S_OK != hr)
{
return FALSE;
}
// Now we set the Execute access permissions on the PBServer Virtual Root
//
szVirtDir = L"/LM/MSFTPSVC/1/ROOT/PBSData";
SetVirtualRootAccessPermissions(szVirtDir, MD_ACCESS_READ);
return 1;
}
//+---------------------------------------------------------------------------
//
// The following are neccessary defines, define guids and typedefs enums
// they are created for the benefit of AddNewVirtualRoot()
//+---------------------------------------------------------------------------
#define error_leave(x) goto leave_routine;
#define MY_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
EXTERN_C const GUID name \
= { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
MY_DEFINE_GUID(CLSID_MSAdminBase, 0xa9e69610, 0xb80d, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50);
MY_DEFINE_GUID(IID_IMSAdminBase, 0x70b51430, 0xb6ca, 0x11d0, 0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50);
//+---------------------------------------------------------------------------
//
// Function: AddNewVirtualRoot
//
// Purpose: Helps create Virtual Roots in the WWW and FTP services.
//
// Arguments:
// PWSTR szDirW : Alias of new Virtual Root
// PWSTR szPathW: Physical Path to wich the new Virtual Root will point
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: a-anasj Mar 9/1998
//
// Notes:
//
HRESULT AddNewVirtualRoot(e_rootType rootType, PWSTR szDirW, PWSTR szPathW)
{
HRESULT hr = S_OK;
IMSAdminBase *pIMeta = NULL;
METADATA_HANDLE hMeta = NULL; // handle to metabase
PWSTR szMBPathW;
if (www == rootType)
{
szMBPathW = L"/LM/W3svc/1/ROOT";
}
else if (ftp == rootType)
{
szMBPathW = L"/LM/MSFTPSVC/1/ROOT";
}
else
{
// Unknown root type
//
ASSERT(FALSE);
return S_FALSE;
}
if (FAILED(CoInitialize(NULL)))
{
return S_FALSE;
}
// Create an instance of the metabase object
hr=::CoCreateInstance(CLSID_MSAdminBase,//CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&pIMeta);
if (FAILED(hr))
{
error_leave("CoCreateInstance");
}
// open key to ROOT on website #1 (where all the VDirs live)
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
szMBPathW,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
1000,
&hMeta);
if (FAILED(hr))
{
error_leave("OpenKey");
}
// Add new VDir called szDirW
hr=pIMeta->AddKey(hMeta, szDirW);
if (FAILED(hr))
{
error_leave("Addkey");
}
// Set the physical path for this VDir
METADATA_RECORD mr;
mr.dwMDIdentifier = MD_VR_PATH;
mr.dwMDAttributes = METADATA_INHERIT ;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.dwMDDataLen = (wcslen(szPathW) + 1) * sizeof(WCHAR);
mr.pbMDData = (unsigned char*)(szPathW);
hr=pIMeta->SetData(hMeta,szDirW,&mr);
if (FAILED(hr))
{
error_leave("SetData");
}
//
// we also need to set the keytype
//
ZeroMemory((PVOID)&mr, sizeof(METADATA_RECORD));
mr.dwMDIdentifier = MD_KEY_TYPE;
mr.dwMDAttributes = METADATA_INHERIT ;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = STRING_METADATA;
mr.pbMDData = (unsigned char*)(www == rootType? L"IIsWebVirtualDir" : L"IIsFtpVirtualDir");
mr.dwMDDataLen = (lstrlenW((PWSTR)mr.pbMDData) + 1) * sizeof(WCHAR);
hr=pIMeta->SetData(hMeta,szDirW,&mr);
if (FAILED(hr))
{
error_leave("SetData");
}
// Call CloseKey() prior to calling SaveData
pIMeta->CloseKey(hMeta);
hMeta = NULL;
// Flush out the changes and close
hr=pIMeta->SaveData();
if (FAILED(hr))
{
error_leave("SaveData");
}
leave_routine:
if (pIMeta)
{
if(hMeta)
pIMeta->CloseKey(hMeta);
pIMeta->Release();
}
CoUninitialize();
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: SetVirtualRootAccessPermissions
//
// Purpose : Sets Access Permissions to a Virtual Roots in the WWW service.
//
// Arguments:
// PWSTR szVirtDir : Alias of new Virtual Root
// DWORD dwAccessPermisions can be any combination of the following
// or others defined in iiscnfg.h
// MD_ACCESS_EXECUTE | MD_ACCESS_WRITE | MD_ACCESS_READ;
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: a-anasj Mar 18/1998
//
// Notes:
//
HRESULT SetVirtualRootAccessPermissions(PWSTR szVirtDir, DWORD dwAccessPermisions)
{
HRESULT hr = S_OK; // com error status
IMSAdminBase *pIMeta = NULL;
METADATA_HANDLE hMeta = NULL; // handle to metabase
if (FAILED(CoInitialize(NULL)))
{
return S_FALSE;
}
// Create an instance of the metabase object
hr=::CoCreateInstance(CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&pIMeta);
if (FAILED(hr))
{
error_leave("CoCreateInstance");
}
// open key to ROOT on website #1 (where all the VDirs live)
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
szVirtDir,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
1000,
&hMeta);
if (FAILED(hr))
{
error_leave("OpenKey");
}
// Set the physical path for this VDir
METADATA_RECORD mr;
mr.dwMDIdentifier = MD_ACCESS_PERM;
mr.dwMDAttributes = METADATA_INHERIT ;
mr.dwMDUserType = IIS_MD_UT_FILE;
mr.dwMDDataType = DWORD_METADATA; // this used to be STRING_METADATA, but that was
// the incorrect type and was causing vdir access
// problems.
// Now, create the access perm
mr.pbMDData = (PBYTE) &dwAccessPermisions;
mr.dwMDDataLen = sizeof (DWORD);
mr.dwMDDataTag = 0; // datatag is a reserved field.
hr=pIMeta->SetData(hMeta,
TEXT ("/"), // The root of the Virtual Dir we opened above
&mr);
if (FAILED(hr))
{
error_leave("SetData");
}
// Call CloseKey() prior to calling SaveData
pIMeta->CloseKey(hMeta);
hMeta = NULL;
// Flush out the changes and close
hr=pIMeta->SaveData();
if (FAILED(hr))
{
error_leave("SaveData");
}
leave_routine:
if (pIMeta)
{
if(hMeta)
pIMeta->CloseKey(hMeta);
pIMeta->Release();
}
CoUninitialize();
return hr;
}
//+---------------------------------------------------------------------------
//
// Function: RemoveCPSVRoots
//
// Purpose: Deletes the Virtual Directories required for Phone Book Service.
//
// Arguments: None
//
// Returns: TRUE if successfull, FALSE otherwise.
//
// Author: a-anasj Mar 9/1998
// quintinb Jan 10/1999 added error checking and replaced asserts with traces
//
// Notes:
//
BOOL RemoveCPSVRoots()
{
HRESULT hr;
HKEY hKey;
hr = DeleteVirtualRoot(www, L"PBServer");
if (SUCCEEDED(hr))
{
//
// Now delete the associated reg key
//
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots",
KEY_ALL_ACCESS, &hKey);
if (SUCCEEDED(hr))
{
if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBServer"))
{
hr = S_OK;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_FALSE;
}
RegCloseKey(hKey);
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_FALSE;
}
}
TraceError("RemoveCPSVRoots -- Deleting PBServer Www Vroot", hr);
hr = DeleteVirtualRoot(www, L"PBSData");
if (SUCCEEDED(hr))
{
//
// Now delete the associated reg key
//
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots",
KEY_ALL_ACCESS, &hKey);
if (SUCCEEDED(hr))
{
if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBSData"))
{
hr = S_OK;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_FALSE;
}
RegCloseKey(hKey);
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_FALSE;
}
}
TraceError("RemoveCPSVRoots -- Deleting PBSData WWW Vroot", hr);
hr = DeleteVirtualRoot(ftp, L"PBSData");
if (SUCCEEDED(hr))
{
//
// Now delete the associated reg key
//
hr = HrRegOpenKeyEx(HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Services\\MSFTPSVC\\Parameters\\Virtual Roots",
KEY_ALL_ACCESS, &hKey);
if (SUCCEEDED(hr))
{
if (ERROR_SUCCESS == RegDeleteValue(hKey, L"/PBSData"))
{
hr = S_OK;
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_FALSE;
}
RegCloseKey(hKey);
}
else if (HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) == hr)
{
hr = S_FALSE;
}
}
TraceError("RemoveCPSVRoots -- Deleting PBSData FTP Vroot", hr);
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: DeleteVirtualRoot
//
// Purpose: Deletes a Virtual Root in the WWW or FTP services.
//
// Arguments:
//
// Returns: S_OK if successfull, Win32 error otherwise.
//
// Author: a-anasj Mar 9/1998
//
// Notes:
//
HRESULT DeleteVirtualRoot(e_rootType rootType, PWSTR szPathW)
{
HRESULT hr = S_OK; // com error status
IMSAdminBase *pIMeta = NULL;
METADATA_HANDLE hMeta = NULL; // handle to metabase
PWSTR szMBPathW;
if (www == rootType)
{
szMBPathW = L"/LM/W3svc/1/ROOT";
}
else if (ftp == rootType)
{
szMBPathW = L"/LM/MSFTPSVC/1/ROOT";
}
else
{
// Unknown root type
//
ASSERT(FALSE);
return S_FALSE;
}
if (FAILED(CoInitialize(NULL)))
{
return S_FALSE;
//error_leave("CoInitialize");
}
// Create an instance of the metabase object
hr=::CoCreateInstance(CLSID_MSAdminBase,//CLSID_MSAdminBase,
NULL,
CLSCTX_ALL,
IID_IMSAdminBase,
(void **)&pIMeta);
if (FAILED(hr))
{
error_leave("CoCreateInstance");
}
// open key to ROOT on website #1 (where all the VDirs live)
hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
szMBPathW,
METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
1000,
&hMeta);
if (FAILED(hr))
{
error_leave("OpenKey");
}
// Add new VDir called szDirW
hr=pIMeta->DeleteKey(hMeta, szPathW);
if (FAILED(hr))
{
error_leave("DeleteKey");
}
// Call CloseKey() prior to calling SaveData
pIMeta->CloseKey(hMeta);
hMeta = NULL;
// Flush out the changes and close
hr=pIMeta->SaveData();
if (FAILED(hr))
{
error_leave("SaveData");
}
leave_routine:
if (pIMeta)
{
if(hMeta)
pIMeta->CloseKey(hMeta);
pIMeta->Release();
}
CoUninitialize();
return hr;
}
HRESULT SetDirectoryAccessPermissions(PWSTR pszFile, ACCESS_MASK AccessRightsToModify,
ACCESS_MODE fAccessFlags, PSID pSid)
{
if (!pszFile && !pSid)
{
return E_INVALIDARG;
}
EXPLICIT_ACCESS AccessEntry = {0};
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
PACL pOldAccessList = NULL;
PACL pNewAccessList = NULL;
DWORD dwRes;
// Get the current DACL information from the object.
dwRes = GetNamedSecurityInfo(pszFile, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // type of information to set
NULL, // provider is Windows NT
NULL, // name or GUID of property or property set
&pOldAccessList, // receives existing DACL information
NULL, // receives existing SACL information
&pSecurityDescriptor); // receives a pointer to the security descriptor
if (ERROR_SUCCESS == dwRes)
{
//
// Initialize the access list entry.
//
BuildTrusteeWithSid(&(AccessEntry.Trustee), pSid);
AccessEntry.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
AccessEntry.grfAccessMode = fAccessFlags;
//
// Set provider-independent standard rights.
//
AccessEntry.grfAccessPermissions = AccessRightsToModify;
//
// Build an access list from the access list entry.
//
dwRes = SetEntriesInAcl(1, &AccessEntry, pOldAccessList, &pNewAccessList);
if (ERROR_SUCCESS == dwRes)
{
//
// Set the access-control information in the object's DACL.
//
dwRes = SetNamedSecurityInfo(pszFile, // name of the object
SE_FILE_OBJECT, // type of object
DACL_SECURITY_INFORMATION, // type of information to set
NULL, // pointer to the new owner SID
NULL, // pointer to the new primary group SID
pNewAccessList, // pointer to new DACL
NULL); // pointer to new SACL
}
}
//
// Free the returned buffers.
//
if (pNewAccessList)
{
LocalFree(pNewAccessList);
}
if (pSecurityDescriptor)
{
LocalFree(pSecurityDescriptor);
}
//
// If the system is using FAT instead of NTFS, then we will get the Invalid Acl error.
//
if (ERROR_INVALID_ACL == dwRes)
{
return S_FALSE;
}
else
{
return HRESULT_FROM_WIN32(dwRes);
}
}
void SetCpsDirPermissions()
{
WCHAR szPath[MAX_PATH+1];
HRESULT hr;
//
// Create the SID for the Everyone Account (World account)
//
PSID pWorldSid;
SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
BOOL bRet = AllocateAndInitializeSid (&WorldSidAuthority, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &pWorldSid);
if (bRet && pWorldSid )
{
const ACCESS_MASK c_Write = FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | FILE_WRITE_EA |
FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE |
FILE_DELETE_CHILD | FILE_APPEND_DATA;
const ACCESS_MASK c_Read = FILE_READ_ATTRIBUTES | FILE_READ_DATA | FILE_READ_EA |
FILE_LIST_DIRECTORY | SYNCHRONIZE | READ_CONTROL;
const ACCESS_MASK c_Execute = FILE_EXECUTE | FILE_TRAVERSE;
ACCESS_MASK arCpsRoot= c_Read;
ACCESS_MASK arCpsBin= c_Read | c_Execute;
ACCESS_MASK arCpsData= c_Read | c_Write;
ACCESS_MODE fAccessFlags = GRANT_ACCESS;
//
// Set the Data Dir access permissions
//
wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsDataPath);
hr = SetDirectoryAccessPermissions(szPath, arCpsData, fAccessFlags, pWorldSid);
TraceError("SetCpsDirPermissions -- Data dir", hr);
//
// Set the Bin Dir access permissions
//
wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsBinPath);
hr = SetDirectoryAccessPermissions(szPath, arCpsBin, fAccessFlags, pWorldSid);
TraceError("SetCpsDirPermissions -- Bin dir", hr);
//
// Set the Root Dir access permissions
//
wsprintf(szPath, c_szSSFmt, g_szProgramFiles, c_szPbsRootPath);
hr = SetDirectoryAccessPermissions(szPath, arCpsRoot, fAccessFlags, pWorldSid);
TraceError("SetCpsDirPermissions -- Root dir", hr);
FreeSid(pWorldSid);
}
}
DWORD AddToRegKeySD(PCWSTR pszRegKeyName, PSID pGroupSID, DWORD dwAccessMask)
{
#define MAX_DOMAIN_LEN 80
PSECURITY_DESCRIPTOR pRelSD = NULL;
PSECURITY_DESCRIPTOR pAbsSD = NULL;
DWORD cbSID;
SID_NAME_USE snuGroup;
DWORD dwDomainSize;
WCHAR szDomainName[MAX_DOMAIN_LEN];
PACL pDACL;
DWORD dwSDLength = 0;
DWORD dwSDRevision;
DWORD dwDACLLength = 0;
SECURITY_DESCRIPTOR_CONTROL sdcSDControl;
PACL pNewDACL = NULL;
DWORD dwAddDACLLength = 0;
BOOL fHasDACL = FALSE;
BOOL fDACLDefaulted = FALSE;
ACCESS_ALLOWED_ACE *pDACLAce;
DWORD dwError = 0;
DWORD i;
DWORD dwcSDLength; // Security descriptor length
if (!pszRegKeyName || !pGroupSID)
{
return ERROR_INVALID_PARAMETER;
}
// handle for security registry key
HKEY hSecurityRegKey = NULL;
// now open reg key to set security
dwError = RegOpenKeyEx (HKEY_LOCAL_MACHINE, pszRegKeyName, 0, KEY_ALL_ACCESS, &hSecurityRegKey);
if (dwError)
{
goto ErrorExit;
}
// get length of security descriptor
dwError = RegQueryInfoKey (hSecurityRegKey, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &dwcSDLength, NULL);
if (dwError)
{
goto ErrorExit;
}
// get SD memory
pRelSD = (PSECURITY_DESCRIPTOR) LocalAlloc (LPTR, (UINT)dwcSDLength);
// first get the self-relative SD
dwError = RegGetKeySecurity (hSecurityRegKey,
(SECURITY_INFORMATION)(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION),
pRelSD, &dwcSDLength);
if (dwError)
{
goto ErrorExit;
}
// check if SD is good
if (!pRelSD || !IsValidSecurityDescriptor (pRelSD))
{
dwError = GetLastError();
goto ErrorExit;
}
// get SD control bits
if (!GetSecurityDescriptorControl (pRelSD, (PSECURITY_DESCRIPTOR_CONTROL)&sdcSDControl,
(LPDWORD) &dwSDRevision))
{
dwError = GetLastError();
goto ErrorExit;
}
// check if DACL is present
if (SE_DACL_PRESENT & sdcSDControl)
{
// get dacl
if (!GetSecurityDescriptorDacl (pRelSD, (LPBOOL)&fHasDACL, (PACL *) &pDACL,
(LPBOOL) &fDACLDefaulted))
{
dwError = GetLastError();
goto ErrorExit;
}
// get dacl length
dwDACLLength = pDACL->AclSize;
// get length of new DACL
dwAddDACLLength = sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + GetLengthSid (pGroupSID);
}
else
{
// get length of new DACL
dwAddDACLLength = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) -
sizeof (DWORD) + GetLengthSid (pGroupSID);
}
// get memory needed for new DACL
pNewDACL = ( PACL) LocalAlloc (LPTR, dwDACLLength + dwAddDACLLength);
if (!pNewDACL)
{
dwError = GetLastError();
goto ErrorExit;
}
// get the sd length
dwSDLength = GetSecurityDescriptorLength (pRelSD);
// get memory for new SD
pAbsSD = ( PSECURITY_DESCRIPTOR)LocalAlloc ( LPTR, dwSDLength + dwAddDACLLength);
if (!pAbsSD)
{
dwError = GetLastError();
goto ErrorExit;
}
// change self-relative SD to absolute by making new SD
if (!InitializeSecurityDescriptor (pAbsSD, SECURITY_DESCRIPTOR_REVISION))
{
dwError = GetLastError();
goto ErrorExit;
}
// init new DACL
if (!InitializeAcl (pNewDACL, dwDACLLength + dwAddDACLLength, ACL_REVISION))
{
dwError = GetLastError();
goto ErrorExit;
}
// now add in all of the ACEs into the new DACL (if org DACL is there)
if (SE_DACL_PRESENT & sdcSDControl)
{
for (i = 0; i < pDACL->AceCount; i++)
{
// get ace from original dacl
if (!GetAce (pDACL, i, (LPVOID *) &pDACLAce))
{
dwError = GetLastError();
goto ErrorExit;
}
// check if group sid is already there. If so, skip it(don't copy)
if (EqualSid ((PSID)&(pDACLAce->SidStart), pGroupSID))
{
continue;
}
// now add ace to new dacl
if (!AddAccessAllowedAce (pNewDACL, ACL_REVISION, pDACLAce->Mask,
(PSID)&(pDACLAce->SidStart)))
{
dwError = GetLastError();
goto ErrorExit;
}
}
}
// now add new ACE to new DACL
if (!AddAccessAllowedAce (pNewDACL, ACL_REVISION, dwAccessMask, pGroupSID))
{
dwError = GetLastError();
goto ErrorExit;
}
// check if everything went ok
if (!IsValidAcl (pNewDACL))
{
dwError = GetLastError();
goto ErrorExit;
}
// now set security descriptor DACL
if (!SetSecurityDescriptorDacl (pAbsSD, TRUE, pNewDACL, fDACLDefaulted))
{
dwError = GetLastError();
goto ErrorExit;
}
// check if everything went ok
if (!IsValidSecurityDescriptor (pAbsSD))
{
dwError = GetLastError();
goto ErrorExit;
}
// now set the reg key security (this will overwrite any existing security)
dwError = RegSetKeySecurity (hSecurityRegKey,
(SECURITY_INFORMATION)(DACL_SECURITY_INFORMATION), pAbsSD);
ErrorExit:
if (hSecurityRegKey)
{
RegCloseKey (hSecurityRegKey);
}
if (pRelSD)
{
LocalFree(pRelSD);
}
if (pAbsSD)
{
LocalFree (pAbsSD);
}
if (pNewDACL)
{
LocalFree (pNewDACL);
}
return (dwError);
}