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 //#include #include 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; }