windows-nt/Source/XPSP1/NT/inetsrv/iis/admin/snapin/pwiz.cpp
2020-09-26 16:20:57 +08:00

2888 lines
55 KiB
C++

fs/*++
Copyright (c) 1994-1998 Microsoft Corporation
Module Name :
pwiz.cpp
Abstract:
IIS Security Wizard
Author:
Ronald Meijer (ronaldm)
Project:
Internet Services Manager
Revision History:
--*/
//
// Include Files
//
#include "stdafx.h"
#include "common.h"
#include "inetprop.h"
#include "resource.h"
#include "pwiz.h"
#include <aclapi.h>
//#include <ntseapi.h>
#include <shlwapi.h>
BOOL CheckIfParentHasAccess(CComAuthInfo *pAuthInfo, CString csMetabaseNode);
BOOL ConvertToServiceLevelPath(CString & strMetaPath);
//
// IIS Security Template Class
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
//
// Package of access rights granted for "READ" access
//
#define ACCMASK_READ_FLAGS (0L\
| FILE_READ_DATA\
| READ_CONTROL\
| SYNCHRONIZE\
| FILE_READ_ATTRIBUTES\
| FILE_READ_EA\
)
//
// Package of access rights granted for "WRITE" access
//
// Note: This includes "delete" because the web service assumes
// "delete" when granting write access. This differs from
// the norm.
//
#define ACCMASK_WRITE_FLAGS (0L\
| FILE_WRITE_DATA\
| FILE_APPEND_DATA\
| DELETE\
| FILE_WRITE_ATTRIBUTES\
| FILE_WRITE_EA\
)
//
// Package of access rights granted for "EXECUTE" access
//
#define ACCMASK_EXEC_FLAGS (0L\
| FILE_EXECUTE\
)
//
// Package of access rights granted for "DIR BROWSE" access
//
//#define ACCMASK_DIRBROWSE_FLAGS (0L\
// | DS_LIST_OBJECT\
// )
//
// Package of access rights granted for "FULL CONTROL" access
//
#define ACCMASK_ADMIN_FLAGS (0L\
| STANDARD_RIGHTS_ALL\
| FILE_READ_DATA\
| FILE_WRITE_DATA\
| FILE_APPEND_DATA\
| FILE_READ_EA\
| FILE_WRITE_EA\
| FILE_EXECUTE\
| FILE_ADD_FILE\
| FILE_ADD_SUBDIRECTORY\
| FILE_READ_ATTRIBUTES\
| FILE_WRITE_ATTRIBUTES\
| FILE_LIST_DIRECTORY\
| FILE_DELETE_CHILD\
| FILE_TRAVERSE\
| ACTRL_DS_LIST_OBJECT\
)
//
// Package of access rights granted for "Everyone"
#define ACC_MASK_EVERYONE_FLAGS (0L\
| ACCMASK_READ_FLAGS\
| ACCMASK_EXEC_FLAGS\
)
//
//
// Access permission bit strings
//
FLAGTOSTRING fsAccessPerms[] =
{
{ MD_ACCESS_READ, IDS_PERMS_READ, TRUE },
{ MD_ACCESS_WRITE, IDS_PERMS_WRITE, TRUE },
{ MD_ACCESS_SCRIPT, IDS_PERMS_SCRIPT, TRUE },
{ MD_ACCESS_EXECUTE, IDS_PERMS_EXECUTE, TRUE },
};
//
// Access mask bit strings
//
FLAGTOSTRING fsAclFlags[] =
{
{ FILE_READ_DATA, IDS_ACL_READ, TRUE },
{ READ_CONTROL, IDS_ACL_READ_CONTROL, TRUE },
{ FILE_READ_ATTRIBUTES, IDS_ACL_READ_ATTRIB, TRUE },
{ FILE_READ_EA, IDS_ACL_READ_PROP, TRUE },
{ FILE_WRITE_DATA, IDS_ACL_WRITE, TRUE },
{ FILE_APPEND_DATA, IDS_ACL_APPEND, TRUE },
{ DELETE, IDS_ACL_DELETE, TRUE },
{ FILE_WRITE_ATTRIBUTES, IDS_ACL_WRITE_ATTRIB, TRUE },
{ FILE_WRITE_EA, IDS_ACL_WRITE_PROP, TRUE },
{ FILE_EXECUTE, IDS_ACL_EXECUTE, TRUE },
// { DS_LIST_CONTENTS, IDS_ACL_LIST_OBJECT, TRUE },
};
CIISSecurityTemplate::CIISSecurityTemplate(
IN CMetaKey * pKey,
IN LPCTSTR lpszMDPath,
IN BOOL fInherit
)
/*++
Routine Description:
Construct from open key
Arguments:
const CMetaKey * pKey : Open key
LPCTSTR lpszMDPath : Path
BOOL fInherit : TRUE to inherit properties
Return Value:
N/A
--*/
: CMetaProperties(pKey, lpszMDPath),
m_dwAccessPerms(0L),
m_dlProperties(),
m_strlSummary(),
m_ipl()
{
//
// Set base class member
//
m_fInherit = fInherit;
//
// Managed Properties
//
m_dlProperties.AddTail(MD_ACCESS_PERM);
m_dlProperties.AddTail(MD_IP_SEC);
}
/* virtual */
void
CIISSecurityTemplate::ParseFields()
/*++
Routine Description:
Break into fields.
Arguments:
None.
Return Value:
None.
--*/
{
BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
HANDLE_META_RECORD(MD_ACCESS_PERM, m_dwAccessPerms)
HANDLE_META_RECORD(MD_IP_SEC, m_ipl)
END_PARSE_META_RECORDS
//
// If "execute" or "script" is on, read should be as well (makes
// little sense otherwise)
//
if (IS_FLAG_SET(MP_V(m_dwAccessPerms), (MD_ACCESS_EXECUTE | MD_ACCESS_SCRIPT)))
{
SET_FLAG(MP_V(m_dwAccessPerms), MD_ACCESS_READ);
}
}
/* virtual */
HRESULT
CIISSecurityTemplate::ApplySettings(
IN BOOL fUseTemplate,
IN CComAuthInfo * pAuthInfo,
IN LPCTSTR lpszMDPath
)
{
BOOL fWriteProperties = TRUE;
CMetaKey mk(pAuthInfo, lpszMDPath, METADATA_PERMISSION_WRITE);
CError err(mk.QueryResult());
if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
{
if (fUseTemplate)
{
//
// Create the path
//
err = mk.CreatePathFromFailedOpen();
if (err.Succeeded())
{
err = mk.ReOpen(METADATA_PERMISSION_WRITE);
}
}
else
{
//
// No need to delete properties; everything's already
// inherited.
//
fWriteProperties = FALSE;
err.Reset();
}
}
if (fWriteProperties)
{
do
{
BREAK_ON_ERR_FAILURE(err);
if (fUseTemplate)
{
//
// Write values from template
//
err = mk.SetValue(
MD_ACCESS_PERM,
m_dwAccessPerms
);
BREAK_ON_ERR_FAILURE(err);
err = mk.SetValue(MD_IP_SEC, m_ipl);
BREAK_ON_ERR_FAILURE(err);
}
else
{
//
// We're going to use inheritance, so delete
// the values that might exist here
//
ASSERT(m_dlProperties.GetCount() > 0);
POSITION pos = m_dlProperties.GetHeadPosition();
while(pos)
{
DWORD dwID = m_dlProperties.GetNext(pos);
err = mk.DeleteValue(dwID);
if (err.HResult() == MD_ERROR_DATA_NOT_FOUND)
{
//
// That's ok
//
err.Reset();
}
if (err.Failed())
{
break;
}
}
}
}
while(FALSE);
}
return err;
}
void
CIISSecurityTemplate::AddSummaryString(
LPCTSTR szTextItem,
int cIndentLevel
)
/*++
Routine Description:
Helper function to add strings to the summary
Arguments:
LPCTSTR szTextItem : String to be added
int cIndentLevel : Indentation level
Return Value:
None
--*/
{
CString str(szTextItem);
//
// Add a tab at the beginning of each string for each
// level of indentation requested
//
for (int i = 0; i < cIndentLevel; ++i)
{
str = _T("\t") + str;
}
m_strlSummary.AddTail(str);
}
void
CIISSecurityTemplate::AddSummaryString(
UINT nID, int cIndentLevel)
/*++
Routine Description:
Helper function to add strings to the summary which are referred to
by string table resource ID
Arguments:
UINT nID : Resource ID
int cIndentLevel : Indentation level
Return Value:
None
--*/
{
CString str;
VERIFY(str.LoadString(nID));
AddSummaryString(str, cIndentLevel);
}
/* virtual */
void
CIISSecurityTemplate::GenerateSummary(
BOOL fUseTemplate,
CComAuthInfo * pAuthInfo,
LPCTSTR lpszMDPath
)
/*++
Routine Description:
Generate text summary of what's in the security template
Notes:
This doesn't clear the summary. It's the responsibility of
the calling process to clear beforehand, otherwise the summary
items get added at the end.
The derived class is expected to add its own information
--*/
{
//
// Summarize Access Permissions:
//
int nIndentLevel = 0;
AddSummaryString(IDS_PERMISSIONS, nIndentLevel++);
if (m_dwAccessPerms == 0L)
{
AddSummaryString(IDS_SUMMARY_NONE, nIndentLevel);
}
else
{
for (int i = 0; i < ARRAY_SIZE(fsAccessPerms); ++i)
{
if (IS_FLAG_SET(
m_dwAccessPerms,
fsAccessPerms[i].dwFlag
) == fsAccessPerms[i].fSet)
{
AddSummaryString(fsAccessPerms[i].nID, nIndentLevel);
}
}
}
//
// Summarize IP Access Restrictions:
//
--nIndentLevel;
AddSummaryString(IDS_ADDRESS_RESTRICTIONS, nIndentLevel++);
if (MP_V(m_ipl).IsEmpty())
{
AddSummaryString(IDS_SUMMARY_NONE, nIndentLevel);
}
else
{
CObListPlus oblAccessList;
BOOL fGrantByDefault;
//
// Get text version of ip access list for the summary
//
CError err(BuildIplOblistFromBlob(
m_ipl,
oblAccessList,
fGrantByDefault
));
if (err.Succeeded())
{
//
// List default denied/granted state
//
AddSummaryString(
fGrantByDefault ? IDS_SUMMARY_GRANTED : IDS_SUMMARY_DENIED,
nIndentLevel
);
//
// Enumerate restrictions (exceptions to the default)
//
CObListIter obli(oblAccessList);
CIPAccessDescriptor * pAccess;
CString str,
strAddress,
strGrpFormat,
strGrantedFmt,
strDeniedFmt;
VERIFY(strGrantedFmt.LoadString(IDS_SPECIFIC_GRANTED));
VERIFY(strDeniedFmt.LoadString(IDS_SPECIFIC_DENIED));
VERIFY(strGrpFormat.LoadString(IDS_FMT_SECURITY));
while (pAccess = (CIPAccessDescriptor *)obli.Next())
{
if (pAccess->IsDomainName())
{
strAddress = pAccess->QueryDomainName();
}
else if (pAccess->IsSingle())
{
strAddress = (LPCTSTR)pAccess->QueryIPAddress();
}
else
{
CString strIP, strMask;
strAddress.Format(
strGrpFormat,
(LPCTSTR)pAccess->QueryIPAddress().QueryIPAddress(strIP),
(LPCTSTR)pAccess->QuerySubnetMask().QueryIPAddress(strMask)
);
}
str.Format(
pAccess->HasAccess() ? strGrantedFmt : strDeniedFmt,
strAddress
);
AddSummaryString(str, nIndentLevel);
}
}
else
{
//
// better than nothing
//
AddSummaryString(IDS_ADDRESS_IP, nIndentLevel);
}
}
}
//////////////////////////////////////////////////////////////////////
CFTPSecurityTemplate::CFTPSecurityTemplate(
IN CMetaKey * pKey,
IN LPCTSTR lpszMDPath,
IN BOOL fInherit
)
/*++
Routine Description:
Construct from open key
Arguments:
const CMetaKey * pKey : Open key
LPCTSTR lpszMDPath : Path
BOOL fInherit : TRUE to inherit values, FALSE if not
Return Value:
N/A
--*/
: CIISSecurityTemplate(pKey, lpszMDPath, fInherit),
m_fAllowAnonymous(FALSE),
m_fAnonymousOnly(FALSE)
{
//
// Managed Properties
//
m_dlProperties.AddTail(MD_ALLOW_ANONYMOUS);
m_dlProperties.AddTail(MD_ANONYMOUS_ONLY);
}
/* virtual */
HRESULT
CFTPSecurityTemplate::LoadData()
/*++
Routine Description:
LoadData() base class override
Arguments:
None
Return Value:
HRESULT
Notes:
The FTP wizard has an annoying idiosynchrasy: access authentication
settings are per site, not per vdir. Therefore, they need to be set
and fetched in a separate path, and not be set at all if not
setting props on a site. What a pain...
--*/
{
TRACEEOLID(m_strMetaPath);
m_strMetaRoot = _T("Root");
CError err(CIISSecurityTemplate::LoadData());
if (lstrcmpi(m_strMetaRoot, g_cszRoot) == 0)
{
//
// Fetch the anonymous access settings from
// the instance node. Note: This explicit step
// should only be necessary for templates, because
// this would otherwise be picked up on inheritance.
//
ASSERT(!m_fInherit);
m_strMetaRoot.Empty();
err = CIISSecurityTemplate::LoadData();
}
return err;
}
/* virtual */
HRESULT
CWebSecurityTemplate::LoadData()
/*++
Routine Description:
LoadData() base class override
Arguments:
None
Return Value:
HRESULT
Notes:
--*/
{
TRACEEOLID(m_strMetaPath);
m_strMetaRoot = _T("Root");
CError err(CIISSecurityTemplate::LoadData());
return err;
}
/* virtual */
void
CFTPSecurityTemplate::ParseFields()
/*++
Routine Description:
Break into fields.
Arguments:
None.
Return Value:
None.
--*/
{
//
// Fetch base class values
//
CIISSecurityTemplate::ParseFields();
BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
HANDLE_META_RECORD(MD_ALLOW_ANONYMOUS, m_fAllowAnonymous)
HANDLE_META_RECORD(MD_ANONYMOUS_ONLY, m_fAnonymousOnly)
END_PARSE_META_RECORDS
}
/* virtual */
HRESULT
CFTPSecurityTemplate::ApplySettings(
BOOL fUseTemplates,
CComAuthInfo * pAuthInfo,
LPCTSTR lpszMDPath
)
{
//
// Write base class properties
//
CError err(CIISSecurityTemplate::ApplySettings(
fUseTemplates,
pAuthInfo,
lpszMDPath
));
if (err.Failed())
{
return err;
}
BOOL fWriteProperties = TRUE;
CMetaKey mk(pAuthInfo, lpszMDPath, METADATA_PERMISSION_WRITE);
err = mk.QueryResult();
if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
{
if (!fUseTemplates)
{
//
// No need to delete properties; everything's already
// inherited. Note that this is the only legit failure
// case. If using a template, the base class must have
// created the path by now.
//
fWriteProperties = FALSE;
err.Reset();
}
}
if (fWriteProperties)
{
do
{
if (mk.IsHomeDirectoryPath())
{
BREAK_ON_ERR_FAILURE(err);
//
// Path describes an instance path, which is the only
// time we need to do anything here
//
err = mk.ConvertToParentPath(TRUE);
BREAK_ON_ERR_FAILURE(err);
if (fUseTemplates)
{
//
// Write values from template
//
err = mk.SetValue(MD_ALLOW_ANONYMOUS, m_fAllowAnonymous);
BREAK_ON_ERR_FAILURE(err);
err = mk.SetValue(MD_ANONYMOUS_ONLY, m_fAnonymousOnly);
}
else
{
//
// Inheritance case: delete authentication
// values
//
mk.DeleteValue(MD_ALLOW_ANONYMOUS);
mk.DeleteValue(MD_ANONYMOUS_ONLY);
}
}
}
while(FALSE);
}
return err;
}
/* virtual */
void
CFTPSecurityTemplate::GenerateSummary(
BOOL fUseTemplates,
CComAuthInfo * pAuthInfo,
LPCTSTR lpszMDPath
)
{
//
// Authentication methods apply to instances only
//
if (CMetabasePath::IsHomeDirectoryPath(lpszMDPath))
{
//
// Add private summary items
//
AddSummaryString(IDS_AUTHENTICATION_METHODS);
//
// Summarize Authentication Methods:
//
AddSummaryString(m_fAllowAnonymous ?
IDS_AUTHENTICATION_ANONYMOUS : IDS_AUTHENTICATION_NO_ANONYMOUS, 1);
if (m_fAllowAnonymous && m_fAnonymousOnly)
{
AddSummaryString(IDS_AUTHENTICATION_ANONYMOUS_ONLY, 1);
}
}
//
// Add base class summary
//
CIISSecurityTemplate::GenerateSummary(
fUseTemplates, pAuthInfo, lpszMDPath);
}
///////////////////////////////////////////////////////////////////////
CWebSecurityTemplate::CWebSecurityTemplate(
CMetaKey * pKey,
LPCTSTR lpszMDPath,
BOOL fInherit
)
/*++
Routine Description:
Construct from open key
Arguments:
const CMetaKey * pKey : Open key
LPCTSTR lpszMDPath : Path
BOOL fInherit : TRUE to inherit values, FALSE if not
Return Value:
N/A
--*/
: CIISSecurityTemplate(pKey, lpszMDPath, fInherit),
m_dwAuthentication(MD_AUTH_ANONYMOUS),
m_dwDirBrowsing(
MD_DIRBROW_SHOW_DATE |
MD_DIRBROW_SHOW_TIME |
MD_DIRBROW_SHOW_SIZE |
MD_DIRBROW_SHOW_EXTENSION
)
{
//
// Managed Properties
//
m_dlProperties.AddTail(MD_AUTHORIZATION);
m_dlProperties.AddTail(MD_DIRECTORY_BROWSING);
}
/* virtual */
void
CWebSecurityTemplate::ParseFields()
/*++
Routine Description:
Break into fields.
Arguments:
None.
Return Value:
None.
--*/
{
//
// Fetch base class values
//
CIISSecurityTemplate::ParseFields();
BEGIN_PARSE_META_RECORDS(m_dwNumEntries, m_pbMDData)
HANDLE_META_RECORD(MD_AUTHORIZATION, m_dwAuthentication)
HANDLE_META_RECORD(MD_DIRECTORY_BROWSING, m_dwDirBrowsing)
END_PARSE_META_RECORDS
}
/* virtual */
HRESULT
CWebSecurityTemplate::ApplySettings(
BOOL fUseTemplates,
CComAuthInfo * pAuthInfo,
LPCTSTR lpszMDPath
)
/*++
Routine Description:
Apply the settings to the specified destination path
Arguments:
BOOL fUseTemplates : TRUE if the source is from a template,
FALSE if using inheritance.
LPCTSTR lpszServerName : Server name
LPCTSTR lpszService : Service name
DWORD dwInstance : Instance
LPCTSTR lpszParent : Parent path (or NULL)
LPCTSTR lpszAlias : Alias name (or NULL)
Return Value:
HRESULT
--*/
{
//
// Write base class properties
//
CError err(CIISSecurityTemplate::ApplySettings(
fUseTemplates, pAuthInfo, lpszMDPath
));
if (err.Failed())
{
return err;
}
BOOL fWriteProperties = TRUE;
CMetaKey mk(
pAuthInfo,
lpszMDPath,
METADATA_PERMISSION_WRITE
);
err = mk.QueryResult();
if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
{
if (!fUseTemplates)
{
//
// No need to delete properties; everything's already
// inherited. Note that this is the only legit failure
// case. If using a template, the base class must have
// created the path by now.
//
fWriteProperties = FALSE;
err.Reset();
}
}
if (fWriteProperties)
{
do
{
BREAK_ON_ERR_FAILURE(err);
if (fUseTemplates)
{
//
// Write values from template
//
err = mk.SetValue(
MD_AUTHORIZATION,
m_dwAuthentication
);
BREAK_ON_ERR_FAILURE(err);
err = mk.SetValue(
MD_DIRECTORY_BROWSING,
m_dwDirBrowsing
);
BREAK_ON_ERR_FAILURE(err);
}
//
// Nothing to do in the inheritance case, because the
// base class knows which properties should be deleted
//
}
while(FALSE);
}
return err;
}
//
// Authentication bit strings
//
FLAGTOSTRING fsAuthentications[] =
{
{ MD_AUTH_ANONYMOUS, IDS_AUTHENTICATION_ANONYMOUS, TRUE },
{ MD_AUTH_ANONYMOUS, IDS_AUTHENTICATION_NO_ANONYMOUS, FALSE },
{ MD_AUTH_BASIC, IDS_AUTHENTICATION_BASIC, TRUE },
{ MD_AUTH_MD5, IDS_AUTHENTICATION_DIGEST, TRUE },
{ MD_AUTH_NT, IDS_AUTHENTICATION_NT, TRUE },
};
/* virtual */
void
CWebSecurityTemplate::GenerateSummary(
BOOL fUseTemplates,
CComAuthInfo * pAuthInfo,
LPCTSTR lpszMDPath
)
/*++
Routine Description:
Generate text summary of what's in the security template. Arguments are
the same as ApplySettings(), so that the summary can reflect what will
actually be set.
Arguments:
BOOL fUseTemplates : TRUE if the source is from a template,
FALSE if using inheritance.
LPCTSTR lpszServerName : Server name
LPCTSTR lpszService : Service name
DWORD dwInstance : Instance
LPCTSTR lpszParent : Parent path (or NULL)
LPCTSTR lpszAlias : Alias name (or NULL)
Return Value:
None
--*/
{
AddSummaryString(IDS_AUTHENTICATION_METHODS);
int i;
//
// Summarize Authentication Methods:
//
if (m_dwAuthentication == 0L)
{
AddSummaryString(IDS_SUMMARY_NONE, 1);
}
else
{
for (i = 0; i < ARRAY_SIZE(fsAuthentications); ++i)
{
if (IS_FLAG_SET(m_dwAuthentication, fsAuthentications[i].dwFlag) == fsAuthentications[i].fSet)
{
AddSummaryString(fsAuthentications[i].nID, 1);
}
}
}
AddSummaryString(IDS_DIRECTORY_BROWSE);
if (IS_FLAG_SET(m_dwDirBrowsing, MD_DIRBROW_ENABLED))
{
AddSummaryString(IDS_DIR_BROWSE_ON, 1);
}
else
{
AddSummaryString(IDS_DIR_BROWSE_OFF, 1);
}
if (IS_FLAG_SET(m_dwDirBrowsing, MD_DIRBROW_LOADDEFAULT))
{
AddSummaryString(IDS_LOAD_DEFAULT_ON, 1);
}
else
{
AddSummaryString(IDS_LOAD_DEFAULT_OFF, 1);
}
//
// Add base class summary
//
CIISSecurityTemplate::GenerateSummary(
fUseTemplates, pAuthInfo, lpszMDPath);
}
///////////////////////////////////////////////////////////////////////
CIISSecWizSettings::CIISSecWizSettings(
CComAuthInfo * pAuthInfo,
LPCTSTR lpszMDPath
)
: CObjectPlus(),
m_auth(pAuthInfo),
m_strMDPath(lpszMDPath),
m_fUseTemplate(TRUE),
m_fSetAcls(FALSE),
m_fReplaceAcls(FALSE),
m_pist(NULL),
m_hResult(S_OK)
{
}
CIISSecWizSettings::~CIISSecWizSettings()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
if (m_pist != NULL)
{
delete m_pist;
}
}
HRESULT
CIISSecWizSettings::FetchProperties(
CMetaKey & mk,
LPCTSTR lpszPath,
BOOL fInherit
)
/*++
Routine Description:
Fetch metabase properties that are applicable for the security wizard
Arguments:
CMetaKey & mk : open key
LPCTSTR lpszPath : Optional path
BOOL fInherit : TRUE to inherit properties
Return Value:
HRESULT
--*/
{
CError err(mk.QueryResult());
if (err.Succeeded())
{
if (m_pist != NULL)
{
//
// Clean up existing template data (must
// have pressed "back")
//
delete m_pist;
}
//
// Create security template by calling the provided
// allocator (which allocates an object of the
// derived class which is service-specific)
//
LPCTSTR p = lpszPath;
if (p == NULL)
{
p = mk.QueryMetaPath();
}
CString spath, sname;
CMetabasePath::GetServicePath(p, spath);
CMetabasePath::GetLastNodeName(spath, sname);
if (sname.CompareNoCase(SZ_MBN_WEB) == 0)
{
m_pist = new CWebSecurityTemplate(&mk, lpszPath, fInherit);
}
else if (sname.CompareNoCase(SZ_MBN_FTP) == 0)
{
m_pist = new CFTPSecurityTemplate(&mk, lpszPath, fInherit);
}
else
{
return ERROR_INVALID_PARAMETER;
}
if (m_pist == NULL)
{
err = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
err = m_pist->LoadData();
}
}
return err;
}
//
// Permissions Wizard Source Page
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
IMPLEMENT_DYNCREATE(CPWSource, CIISWizardPage)
CPWSource::CPWSource(
IN CIISSecWizSettings * pSettings
)
/*++
Routine Description:
Constructor
Arguments:
CIISSecWizSettings * pSettings : Settings
Return Value:
None
--*/
: CIISWizardPage(
CPWSource::IDD, // Template
IDS_PERMWIZ, // Caption
HEADER_PAGE // Header
),
m_pSettings(pSettings)
{
//{{AFX_DATA_INIT(CPWSource)
m_nSource = RADIO_INHERITANCE;
//}}AFX_DATA_INIT
// ASSERT(m_pSettings);
// ASSERT(!m_pSettings->m_strServer.IsEmpty());
}
CPWSource::~CPWSource()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
}
void
CPWSource::DoDataExchange(
IN CDataExchange * pDX
)
/*++
Routine Description:
Initialise/Store control data
Arguments:
CDataExchange * pDX - DDX/DDV control structure
Return Value:
None
--*/
{
CIISWizardPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPWSource)
DDX_Radio(pDX, IDC_RADIO_INHERIT, m_nSource);
//}}AFX_DATA_MAP
}
void
CPWSource::SetControlStates()
/*++
Routine Description:
Set the state of the control data
Arguments:
None
Return Value:
None
--*/
{
SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
}
//
// Message Map
//
BEGIN_MESSAGE_MAP(CPWSource, CIISWizardPage)
//{{AFX_MSG_MAP(CPWSource)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//
// Message Handlers
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
BOOL
CPWSource::OnSetActive()
/*++
Routine Description:
Activation handler
Arguments:
None
Return Value:
TRUE for success, FALSE for failure
--*/
{
SetControlStates();
return CIISWizardPage::OnSetActive();
}
LRESULT
CPWSource::OnWizardNext()
/*++
Routine Description:
'next' handler. Store the source specified, so the next
pages can skip or continue.
Arguments:
None
Return Value:
0 to proceed, -1 to fail
--*/
{
UpdateData(TRUE);
m_pSettings->m_fUseTemplate = (m_nSource == RADIO_TEMPLATE);
if (!m_pSettings->m_fUseTemplate)
{
CError err;
CMetaKey mk(
m_pSettings->m_auth,
m_pSettings->m_strMDPath
);
if (mk.IsHomeDirectoryPath())
{
//
// Current path is a virtual server, and we're
// at the home directory. We need to back up
// twice.
//
err = mk.ConvertToParentPath(TRUE);
ASSERT(err.Succeeded());
}
//
// Convert to first parent path
//
err = mk.ConvertToParentPath(FALSE);
if (err.Succeeded())
{
err = m_pSettings->FetchProperties(mk, NULL, TRUE);
}
if (err.MessageBoxOnFailure())
{
return -1;
}
// Doing Inhert, so let's make sure
// that at least the node that we are inheriting from
// will have some sort of access...
if (FALSE == CheckIfParentHasAccess(m_pSettings->m_auth,m_pSettings->m_strMDPath))
{
// popup messagebox saying that parent that we are inheriting from
// does not give anyone access.
if (::AfxMessageBox(IDS_PARENT_PATH_MISSING_PERMISSIONS, MB_YESNO | MB_DEFBUTTON2 ) != IDYES)
{
return -1;
}
}
}
return CIISWizardPage::OnWizardNext();
}
//
// Permissions Wizard Template Page
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
IMPLEMENT_DYNCREATE(CPWTemplate, CIISWizardPage)
CPWTemplate::CPWTemplate(
IN CIISSecWizSettings * pSettings
)
/*++
Routine Description:
Constructor
Arguments:
CIISSecWizSettings * pSettings : Settings
Return Value:
None
--*/
: CIISWizardPage(
CPWTemplate::IDD, // Template
IDS_PERMWIZ, // Caption
HEADER_PAGE // Header
),
m_pSettings(pSettings)
{
//{{AFX_DATA_INIT(CPWTemplate)
//}}AFX_DATA_INIT
ASSERT(m_pSettings);
// ASSERT(!m_pSettings->m_strServer.IsEmpty());
}
CPWTemplate::~CPWTemplate()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
}
void
CPWTemplate::DoDataExchange(
IN CDataExchange * pDX
)
/*++
Routine Description:
Initialise/Store control data
Arguments:
CDataExchange * pDX - DDX/DDV control structure
Return Value:
None
--*/
{
CIISWizardPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPWTemplate)
DDX_Control(pDX, IDC_LIST_TEMPLATES, m_list_Templates);
DDX_Control(pDX, IDC_EDIT_DESCRIPTION, m_edit_Description);
//}}AFX_DATA_MAP
}
void
CPWTemplate::SetControlStates()
/*++
Routine Description:
Set the state of the control data
Arguments:
None
Return Value:
None
--*/
{
DWORD dwFlags = PSWIZB_BACK;
int nSel = m_list_Templates.GetCurSel();
if (nSel >= 0)
{
dwFlags |= PSWIZB_NEXT;
}
SetWizardButtons(dwFlags);
}
//
// Message Map
//
BEGIN_MESSAGE_MAP(CPWTemplate, CIISWizardPage)
//{{AFX_MSG_MAP(CPWTemplate)
ON_LBN_SELCHANGE(IDC_LIST_TEMPLATES, OnSelchangeListTemplates)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//
// Message Handlers
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
BOOL
CPWTemplate::OnSetActive()
/*++
Routine Description:
Activation handler
Arguments:
None
Return Value:
TRUE to show the page, FALSE to skip it.
--*/
{
if (!m_pSettings->m_fUseTemplate)
{
return FALSE;
}
SetControlStates();
return CIISWizardPage::OnSetActive();
}
LRESULT
CPWTemplate::OnWizardNext()
/*++
Routine Description:
'next' handler. Store the source specified, so the next
pages can skip or continue.
Arguments:
None
Return Value:
0 to proceed, -1 to fail
--*/
{
UpdateData(TRUE);
int nSel = m_list_Templates.GetCurSel();
if (nSel < 0)
{
return -1;
}
CString strItem;
m_list_Templates.GetText(nSel, strItem);
//
// Fetch the template, which is the text up until the tab
// character
//
int nTab = strItem.Find(_T('\t'));
ASSERT(nTab >= 0);
if (nTab >= 0)
{
strItem.ReleaseBuffer(nTab);
}
TRACEEOLID(strItem);
//
// Read the properties from the selected template
//
CString strMDTemplates;
CString strMDTemplates2;
if (!CMetabasePath::GetServiceInfoPath(
m_pSettings->m_strMDPath,
strMDTemplates,
NULL
))
{
ASSERT_MSG("Unable to generate info path");
return -1;
}
strMDTemplates = CMetabasePath(FALSE, strMDTemplates, SZ_MBN_TEMPLATES);
// at this point
// strMDTemplates=/LM/W3SVC/Info/Templates
//
// since this is a vdir, make it look like:
// strMDTemplates=/LM/W3SVC/Info/Templates/Secure Web Site
//
strMDTemplates = strMDTemplates + _T("/") + strItem;
CMetaKey mk(
m_pSettings->m_auth,
strMDTemplates
);
CError err(m_pSettings->FetchProperties(mk, NULL, FALSE));
if (err.MessageBoxOnFailure())
{
return -1;
}
return CIISWizardPage::OnWizardNext();
}
BOOL
CPWTemplate::OnInitDialog()
/*++
Routine Description:
WM_INITDIALOG handler. Initialize the dialog.
Arguments:
None.
Return Value:
TRUE if no focus is to be set automatically, FALSE if the focus
is already set.
--*/
{
CIISWizardPage::OnInitDialog();
//
// Assure the comments remain offscreen
//
m_list_Templates.SetTabStops(5000);
//
// Enumerate the existing templates
//
CError err;
CString strMDTemplates;
do
{
if (!CMetabasePath::GetServiceInfoPath(m_pSettings->m_strMDPath, strMDTemplates, NULL))
{
ASSERT_MSG("Unable to generate info path");
err = ERROR_PATH_NOT_FOUND;
break;
}
strMDTemplates = CMetabasePath(FALSE, strMDTemplates, SZ_MBN_TEMPLATES);
CMetaEnumerator mk(
m_pSettings->m_auth,
strMDTemplates
);
err = mk.QueryResult();
if (err.Failed())
{
break;
}
//
// Enumerate and add to the listbox.
//
CString strTemplate, strComment, strListItem;
while (err.Succeeded())
{
err = mk.Next(strTemplate);
if (err.Succeeded())
{
//
// Read off the open key
//
err = mk.QueryValue(
MD_SERVER_COMMENT,
strComment,
NULL,
strTemplate
);
if (err.Succeeded())
{
TRACEEOLID(strComment);
//
// Append the comment in the off-screen
// area of the listbox
//
strListItem.Format(_T("%s\t%s"),
(LPCTSTR)strTemplate,
(LPCTSTR)strComment
);
m_list_Templates.AddString(strListItem);
}
}
}
}
while(FALSE);
if (err.Failed())
{
if (err.Win32Error() == ERROR_PATH_NOT_FOUND)
{
AfxMessageBox(IDS_NO_TEMPLATES);
}
else if (err.Win32Error() != ERROR_NO_MORE_ITEMS)
{
err.MessageBox();
}
}
return TRUE;
}
void
CPWTemplate::OnSelchangeListTemplates()
/*++
Routine Description:
Handle selection change in the templates listbox
Arguments:
None
Return Value:
None
--*/
{
int nSel = m_list_Templates.GetCurSel();
ASSERT(nSel >= 0);
if (nSel >= 0)
{
CString strItem;
m_list_Templates.GetText(nSel, strItem);
//
// Fetch the comment, which is just beyond the tab
// character
//
int nTab = strItem.Find(_T('\t'));
ASSERT(nTab >= 0);
if (nTab >= 0)
{
strItem = strItem.Mid(nTab + 1);
}
m_edit_Description.SetWindowText(_T(""));
m_edit_Description.SetWindowText(strItem);
Invalidate();
UpdateWindow();
}
SetControlStates();
}
//
// Permissions Wizard ACL Page
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
IMPLEMENT_DYNCREATE(CPWACL, CIISWizardPage)
CPWACL::CPWACL(
IN CIISSecWizSettings * pSettings
)
/*++
Routine Description:
Constructor
Arguments:
CIISSecWizSettings * pSettings : Settings
Return Value:
None
--*/
: CIISWizardPage(
CPWACL::IDD, // Template
IDS_PERMWIZ, // Caption,
HEADER_PAGE // Header
),
m_pSettings(pSettings)
{
//{{AFX_DATA_INIT(CPWACL)
m_nRadioAclType = RADIO_MAXIMUM;
//}}AFX_DATA_INIT
ASSERT(m_pSettings);
// ASSERT(!m_pSettings->m_strServer.IsEmpty());
}
CPWACL::~CPWACL()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
}
void
CPWACL::DoDataExchange(
IN CDataExchange * pDX
)
/*++
Routine Description:
Initialise/Store control data
Arguments:
CDataExchange * pDX - DDX/DDV control structure
Return Value:
None
--*/
{
CIISWizardPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPWACL)
DDX_Control(pDX, IDC_ED_BOLD4, m_static_Line4);
DDX_Control(pDX, IDC_ED_BOLD3, m_static_Line3);
DDX_Control(pDX, IDC_ED_BOLD2, m_static_Line2);
DDX_Control(pDX, IDC_ED_BOLD1, m_static_Line1);
DDX_Radio(pDX, IDC_RADIO_ACL_MAXIMUM, m_nRadioAclType);
//}}AFX_DATA_MAP
}
void
CPWACL::SetControlStates()
/*++
Routine Description:
Set the state of the control data
Arguments:
None
Return Value:
None
--*/
{
SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
}
//
// Message Map
//
BEGIN_MESSAGE_MAP(CPWACL, CIISWizardPage)
//{{AFX_MSG_MAP(CPWACL)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL
GetPhysicalPath(
IN CMetaKey & mk,
IN CString & strMetaPath,
OUT CString & strPhysicalPath
)
/*++
Routine Description:
Get the physical path of the parent as described by the metabase path
Arguments:
CMetaKey & mk : Open metabase key
CString & strMetaPath : Metabase path
CString & strPhysicalPath : Returns physical path
Return Value:
TRUE for success, FALSE for failure
--*/
{
//
// Get physical path of parent
//
CString strAlias;
int nSlash = strMetaPath.ReverseFind(SZ_MBN_SEP_CHAR);
if (nSlash < 0)
{
//
// Didn't encounter a physical path at all!
//
TRACEEOLID("No physical path established -- ACLS skipped");
ASSERT(FALSE);
return FALSE;
}
strAlias = strMetaPath.Mid(nSlash + 1);
strMetaPath.ReleaseBuffer(nSlash);
TRACEEOLID(strAlias);
TRACEEOLID(strMetaPath);
BOOL fInherit = FALSE;
CError err(mk.QueryValue(
MD_VR_PATH,
strPhysicalPath,
&fInherit,
strMetaPath
));
if (err.Failed())
{
GetPhysicalPath(mk, strMetaPath, strPhysicalPath);
}
strPhysicalPath += _T("\\");
strPhysicalPath += strAlias;
return TRUE;
}
//
// Message Handlers
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
LRESULT
CPWACL::OnWizardNext()
/*++
Routine Description:
'next' handler. Store the acl replacement type specified, so the next
pages can skip or continue.
Arguments:
None
Return Value:
0 to proceed, -1 to fail
--*/
{
UpdateData(TRUE);
switch(m_nRadioAclType)
{
case RADIO_MINIMUM:
m_pSettings->m_fReplaceAcls = FALSE;
break;
case RADIO_MAXIMUM:
m_pSettings->m_fReplaceAcls = TRUE;
break;
case RADIO_NONE:
default:
m_pSettings->m_fSetAcls = FALSE;
}
return CIISWizardPage::OnWizardNext();
}
static PSID psidAdministrators = NULL;
static PSID psidEveryone = NULL;
BOOL
CPWACL::OnSetActive()
/*++
Routine Description:
Activation handler
Arguments:
None
Return Value:
TRUE to show the page, FALSE to skip it.
--*/
{
//
// Assume no acls until all tests pass
//
m_pSettings->m_fSetAcls = FALSE;
if (!m_pSettings->m_auth->IsLocal())
{
TRACEEOLID("We're not local -- skipping ACL phase");
return FALSE;
}
//
// Get properties on the current directory object
//
CChildNodeProps props(
m_pSettings->m_auth,
m_pSettings->m_strMDPath,
WITH_INHERITANCE
);
CError err(props.LoadData());
if (err.MessageBoxOnFailure())
{
TRACEEOLID("Unable to determine directory properties -- skipping ACLS");
ASSERT(FALSE);
return FALSE;
}
m_pSettings->m_fRedirected = props.IsRedirected();
if (m_pSettings->m_fRedirected)
{
TRACEEOLID("Redirection in place, will not set ACLS");
return FALSE;
}
//
// If the path is on a remote store, Then no ACL page. - boydm
//
if (::IsUNCName(MP_V(props.m_strPath)))
{
TRACEEOLID("share is remote, will not set ACLS");
return FALSE;
}
//
// Don't get confused here, build the real physical path
//
if (props.IsPathInherited())
{
TRACEEOLID("Path inherited");
//
// Look for parent path.
//
CString strMetaPath(props.QueryMetaRoot());
TRACEEOLID(strMetaPath);
CMetaKey mk(m_pSettings->m_auth);
err = mk.QueryResult();
if (err.Failed())
{
ASSERT(FALSE);
return FALSE;
}
if (!GetPhysicalPath(mk, strMetaPath, m_pSettings->m_strPath))
{
ASSERT(FALSE);
return FALSE;
}
}
else
{
m_pSettings->m_strPath = props.m_strPath;
}
DWORD dwFileSystemFlags;
if (::GetVolumeInformationSystemFlags(
m_pSettings->m_strPath,
&dwFileSystemFlags
))
{
if (!(dwFileSystemFlags & FS_PERSISTENT_ACLS))
{
//
// No ACLS
//
TRACEEOLID("Volume type doesn't accept ACLS -- skipping");
return FALSE;
}
}
//
// Build ACL information to be set
//
m_pSettings->m_AccessMaskAdmin = ACCMASK_ADMIN_FLAGS;
m_pSettings->m_AccessMaskDefault
= m_pSettings->m_AccessMaskEveryone = ACC_MASK_EVERYONE_FLAGS;
//
// Display proposed ACEs in bold-faced entries on the dialog
//
UINT nID = IDC_ED_BOLD1;
CString str;
VERIFY(str.LoadString(IDS_ACL_ADMINS));
GetDlgItem(nID++)->SetWindowText(str);
if (IS_FLAG_SET(m_pSettings->m_pist->m_dwAccessPerms, MD_ACCESS_READ))
{
VERIFY(str.LoadString(IDS_ACL_EV_READ));
GetDlgItem(nID++)->SetWindowText(str);
m_pSettings->m_AccessMaskEveryone |= ACCMASK_READ_FLAGS;
}
if (IS_FLAG_SET(m_pSettings->m_pist->m_dwAccessPerms, MD_ACCESS_WRITE))
{
VERIFY(str.LoadString(IDS_ACL_EV_WRITE));
GetDlgItem(nID++)->SetWindowText(str);
m_pSettings->m_AccessMaskEveryone |= ACCMASK_WRITE_FLAGS;
}
if (IS_FLAG_SET(m_pSettings->m_pist->m_dwAccessPerms, MD_ACCESS_EXECUTE))
{
VERIFY(str.LoadString(IDS_ACL_EV_EXEC));
GetDlgItem(nID++)->SetWindowText(str);
m_pSettings->m_AccessMaskEveryone |= ACCMASK_EXEC_FLAGS;
}
ZeroMemory(&m_pSettings->m_rgaae, sizeof(m_pSettings->m_rgaae));
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
SID_IDENTIFIER_AUTHORITY siaWorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
AllocateAndInitializeSid(
&siaNtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&psidAdministrators);
AllocateAndInitializeSid(
&siaWorldSidAuthority,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&psidEveryone);
//
// Set up permissions for the "Everyone" group
//
m_pSettings->m_rgaae[0].Trustee.pMultipleTrustee = NULL;
m_pSettings->m_rgaae[0].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
m_pSettings->m_rgaae[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
m_pSettings->m_rgaae[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
m_pSettings->m_rgaae[0].Trustee.ptstrName = (LPTSTR)psidEveryone;
m_pSettings->m_rgaae[0].grfAccessMode = SET_ACCESS;
m_pSettings->m_rgaae[0].grfAccessPermissions = m_pSettings->m_AccessMaskEveryone;
m_pSettings->m_rgaae[0].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
//
// Set up permissions for the "Administrators" group
//
m_pSettings->m_rgaae[1].Trustee.pMultipleTrustee = NULL;
m_pSettings->m_rgaae[1].Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
m_pSettings->m_rgaae[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
m_pSettings->m_rgaae[1].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
m_pSettings->m_rgaae[1].Trustee.ptstrName = (LPTSTR)psidAdministrators;
m_pSettings->m_rgaae[1].grfAccessMode = SET_ACCESS;
m_pSettings->m_rgaae[1].grfAccessPermissions = m_pSettings->m_AccessMaskAdmin;
m_pSettings->m_rgaae[1].grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
SetControlStates();
//
// Passed all tests, we'll give the option to set ACLS
//
m_pSettings->m_fSetAcls = TRUE;
return CIISWizardPage::OnSetActive();
}
//
// Permissions Wizard Template Page
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
IMPLEMENT_DYNCREATE(CPWSummary, CIISWizardPage)
CPWSummary::CPWSummary(
IN CIISSecWizSettings * pSettings
)
/*++
Routine Description:
Constructor
Arguments:
CIISSecWizSettings * pSettings : Settings
Return Value:
None
--*/
: CIISWizardPage(
CPWSummary::IDD, // Template
IDS_PERMWIZ, // Caption
HEADER_PAGE // Header
),
m_pSettings(pSettings)
{
//{{AFX_DATA_INIT(CPWSummary)
//}}AFX_DATA_INIT
ASSERT(m_pSettings);
// ASSERT(!m_pSettings->m_strServer.IsEmpty());
}
CPWSummary::~CPWSummary()
/*++
Routine Description:
Destructor
Arguments:
N/A
Return Value:
N/A
--*/
{
}
void
CPWSummary::DoDataExchange(
IN CDataExchange * pDX
)
/*++
Routine Description:
Initialise/Store control data
Arguments:
CDataExchange * pDX - DDX/DDV control structure
Return Value:
None
--*/
{
CIISWizardPage::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CPWSummary)
DDX_Control(pDX, IDC_LIST_SUMMARY, m_list_Summary);
//}}AFX_DATA_MAP
}
void
CPWSummary::SetControlStates()
/*++
Routine Description:
Set the state of the control data
Arguments:
None
Return Value:
None
--*/
{
SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
}
//
// Message Map
//
BEGIN_MESSAGE_MAP(CPWSummary, CIISWizardPage)
//{{AFX_MSG_MAP(CPWSummary)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void
CPWSummary::GenerateAclSummary()
/*++
Routine Description:
Break down ACL list into the summary
Arguments:
None
Return Value:
None
--*/
{
//
// Summarize ACL Settings:
//
int nIndentLevel = 0;
if (m_pSettings->m_fSetAcls)
{
m_pSettings->m_pist->AddSummaryString(
m_pSettings->m_fReplaceAcls
? IDS_ACL_REPLACEMENT
: IDS_ACL_ADDED,
nIndentLevel++
);
m_pSettings->m_pist->AddSummaryString(IDS_ACL_ADMIN, nIndentLevel);
m_pSettings->m_pist->AddSummaryString(IDS_ACL_EVR, nIndentLevel++);
// if (m_pSettings->m_AccessMaskEveryone
// == m_pSettings->m_AccessMaskDefault)
// {
// //
// // "Everyone" has zero access
// //
// m_pSettings->m_pist->AddSummaryString(
// IDS_SUMMARY_NONE,
// nIndentLevel
// );
// }
// else
// {
//
// Enumerate the specific rights granted
// to "everyone"
//
for (int i = 0; i < ARRAY_SIZE(fsAclFlags); ++i)
{
if (IS_FLAG_SET(
m_pSettings->m_AccessMaskEveryone,
fsAclFlags[i].dwFlag
) == fsAclFlags[i].fSet)
{
m_pSettings->m_pist->AddSummaryString(
fsAclFlags[i].nID,
nIndentLevel
);
}
}
// }
}
else
{
m_pSettings->m_pist->AddSummaryString(IDS_ACL_NONE, nIndentLevel);
}
}
void
CPWSummary::DisplaySummary()
/*++
Routine Description:
Break down the security settings and display them in text
form in the summary listbox.
Arguments:
None
Return Value:
None.
--*/
{
//
// Generate Summary
//
m_pSettings->m_pist->ClearSummary();
m_pSettings->m_pist->GenerateSummary(
m_pSettings->m_fUseTemplate,
m_pSettings->m_auth,
m_pSettings->m_strMDPath
);
GenerateAclSummary();
//
// Display it in the listbox
//
m_list_Summary.ResetContent();
POSITION pos = m_pSettings->m_pist->GetHeadPosition();
while(pos)
{
CString & str = m_pSettings->m_pist->GetNext(pos);
m_list_Summary.AddString(str);
}
}
//
// Message Handlers
//
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
BOOL
CPWSummary::OnSetActive()
{
SetControlStates();
DisplaySummary();
return CIISWizardPage::OnSetActive();
}
/* virtual */
LRESULT
CPWSummary::OnWizardNext()
{
//
// Store everything here
//
CError err(m_pSettings->m_pist->ApplySettings(
m_pSettings->m_fUseTemplate,
m_pSettings->m_auth,
m_pSettings->m_strMDPath
));
//
// Set the ACLS
//
if (err.Succeeded() && m_pSettings->m_fSetAcls)
{
err = ApplyACLSToFiles();
}
//
// Store the error for the completion page
//
m_pSettings->m_hResult = err;
return CIISWizardPage::OnWizardNext();
}
HRESULT
CPWSummary::ApplyACLSToFiles()
/*++
Routine Description:
Apply ACLS to files
Arguments:
None
Return Value:
HRESULT
--*/
{
CError err;
SECURITY_INFORMATION si = 0;
SECURITY_DESCRIPTOR * psd = NULL;
PACL pOldDacl = NULL, pNewDacl = NULL;;
//
// Can take a while.
//
CWaitCursor waitcursor;
do
{
err = GetNamedSecurityInfo(
(LPTSTR)(LPCTSTR)m_pSettings->m_strPath,
SE_FILE_OBJECT,
DACL_SECURITY_INFORMATION,
NULL, // owner SID
NULL, // group SID
&pOldDacl, // pointer to the DACL
NULL, // pointer to the SACL
(PVOID *)&psd
);
BREAK_ON_ERR_FAILURE(err);
if (!m_pSettings->m_fReplaceAcls)
{
m_pSettings->m_rgaae[0].grfAccessMode = GRANT_ACCESS;
m_pSettings->m_rgaae[1].grfAccessMode = GRANT_ACCESS;
}
// Prepare DACL according to template
err = SetEntriesInAcl(
ARRAY_SIZE(m_pSettings->m_rgaae),
m_pSettings->m_rgaae,
m_pSettings->m_fReplaceAcls ? NULL : pOldDacl,
&pNewDacl
);
BREAK_ON_ERR_FAILURE(err);
// Set permissions on the selected object
si |= DACL_SECURITY_INFORMATION;
si |= PROTECTED_DACL_SECURITY_INFORMATION;
err = HRESULT_FROM_WIN32(SetNamedSecurityInfo(
(LPTSTR)(LPCTSTR)m_pSettings->m_strPath,
SE_FILE_OBJECT,
si,
NULL,
NULL,
pNewDacl,
NULL));
BREAK_ON_ERR_FAILURE(err);
// For children of this object we should set empty DACL
// if we need only permissions inherited from parent
if (PathIsDirectory(m_pSettings->m_strPath))
{
if (m_pSettings->m_fReplaceAcls)
{
// Build security descriptor with empty DACL
ACL daclEmpty = {0};
InitializeAcl(&daclEmpty, sizeof(ACL), ACL_REVISION);
si = 0;
si |= DACL_SECURITY_INFORMATION;
si |= UNPROTECTED_DACL_SECURITY_INFORMATION;
err = SetPermToChildren(
m_pSettings->m_strPath,
si,
&daclEmpty,
NULL);
BREAK_ON_ERR_FAILURE(err);
}
}
// In other cases children should inherit permissions from the parent
}
while(FALSE);
if (pOldDacl != NULL)
{
LocalFree(pOldDacl);
}
if (pNewDacl != NULL)
{
LocalFree(pNewDacl);
}
if (psd != NULL)
{
LocalFree(psd);
}
return err;
}
BOOL
CPWSummary::OnInitDialog()
/*++
Routine Description:
WM_INITDIALOG handler. Initialize the dialog.
Arguments:
None.
Return Value:
TRUE if no focus is to be set automatically, FALSE if the focus
is already set.
--*/
{
CIISWizardPage::OnInitDialog();
//
// Set the tabs based on the hidden column headers
//
CRect rc1, rc2;
ASSERT(NULL != GetDlgItem(IDC_STATIC_TAB2) && NULL != GetDlgItem(IDC_STATIC_TAB1));
if (NULL != GetDlgItem(IDC_STATIC_TAB2) && NULL != GetDlgItem(IDC_STATIC_TAB1))
{
GetDlgItem(IDC_STATIC_TAB2)->GetWindowRect(&rc2);
GetDlgItem(IDC_STATIC_TAB1)->GetWindowRect(&rc1);
m_list_Summary.SetTabStops(((LPRECT)rc2)->left - ((LPRECT)rc1)->left);
}
return TRUE;
}
HRESULT
RunSecurityWizard(
CComAuthInfo * pauth,
CMetaInterface * pInterface,
CString& meta_path,
UINT nLeftBmpId,
UINT nHeadBmpId
)
{
CError err;
ASSERT(pInterface != NULL);
BOOL fAdmin;
err = DetermineIfAdministrator(
pInterface, meta_path, &fAdmin);
if (err.Failed() || !fAdmin)
{
AfxMessageBox(IDS_ACL_ADMINS);
return err;
}
CIISWizardSheet sheet(nLeftBmpId, nHeadBmpId);
CIISSecWizSettings sws(pauth, meta_path);
CIISWizardBookEnd pgWelcome(IDS_PWIZ_WELCOME, IDS_PERMWIZ, IDS_PWIZ_BODY);
CPWSource pgSource(&sws);
CPWTemplate pgTemplate(&sws);
CPWACL pgACL(&sws);
CPWSummary pgSummary(&sws);
CIISWizardBookEnd pgCompletion(&sws.m_hResult,
IDS_PWIZ_SUCCESS, IDS_PWIZ_FAILURE, IDS_PERMWIZ);
sheet.AddPage(&pgWelcome);
sheet.AddPage(&pgSource);
sheet.AddPage(&pgTemplate);
sheet.AddPage(&pgACL);
sheet.AddPage(&pgSummary);
sheet.AddPage(&pgCompletion);
sheet.DoModal();
return err;
}
BOOL CheckIfParentHasAccess(CComAuthInfo *pAuthInfo, CString csMetabaseNode)
{
int iReturn = TRUE;
CError err;
// check if the node is "/LM/W3SVC/1/Root"
if (TRUE == ConvertToServiceLevelPath(csMetabaseNode))
{
// look at this /lm/w3svc node to see if there is access
// at this node.
CMetaKey mk1(pAuthInfo,csMetabaseNode);
err = mk1.QueryResult();
if (err.Failed())
{
// let it inherit by default
iReturn = TRUE;
goto CheckIfParentHasAccess_Exit;
}
DWORD dwAccessPerms;
err = mk1.QueryValue(MD_ACCESS_PERM, dwAccessPerms);
if (err.Succeeded())
{
iReturn = TRUE;
}
else
{
iReturn = FALSE;
}
mk1.Close();
}
CheckIfParentHasAccess_Exit:
return iReturn;
}
BOOL ConvertToServiceLevelPath(CString &strMetaPath)
/*++
Routine Description:
Given the path, convert it to the service level path
e.g. "/LM/W3SVC/1/ROOT" returns "/LM/W3SVC/"
Arguments:
CString & strMetaPath : Path to be converted
Return value:
Pointer to the converted path, or NULL in case of error
--*/
{
// TRIM Off the last "/" or "\"
INT iLen = 0;
BOOL iReturn= 0;
LPTSTR lpBuffer = NULL;
LPTSTR pch1 = NULL;
LPTSTR pch2 = NULL;
iLen = strMetaPath.GetLength();
lpBuffer = (LPTSTR) LocalAlloc(LMEM_FIXED, (iLen + 1) * sizeof(TCHAR));
if (!lpBuffer)
{
return FALSE;
}
_tcscpy(lpBuffer,strMetaPath);
pch1 = _tcsrchr(lpBuffer, _T('/'));
if(pch1)
{
*pch1 = _T('\0');
}
else
{
pch1 = _tcsrchr(pch1, _T('\\'));
if(pch1){*pch1 = _T('\0');}
}
pch2 = _tcsrchr(lpBuffer, _T('/'));
if(pch2){*pch2 = _T('\0');}
else
{
pch2 = _tcsrchr(lpBuffer, _T('\\'));
if(pch2){*pch2 = _T('\0');}
}
strMetaPath = lpBuffer;
if (lpBuffer){LocalFree(lpBuffer);}
return TRUE;
}