/*++ 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 "comprop.h" #include #include #include // // 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 const 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 LPCTSTR lpszServerName, IN LPCTSTR lpszService, IN DWORD dwInstance, IN LPCTSTR lpszParent, IN LPCTSTR lpszAlias ) /*++ 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 --*/ { BOOL fWriteProperties = TRUE; CMetaKey mk( lpszServerName, METADATA_PERMISSION_WRITE, lpszService, dwInstance, lpszParent, lpszAlias ); 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( IN LPCTSTR szTextItem, IN int cIndentLevel OPTIONAL ) /*++ 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( IN UINT nID, IN int cIndentLevel OPTIONAL ) /*++ 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( IN BOOL fUseTemplate, IN LPCTSTR lpszServerName, IN LPCTSTR lpszService, IN DWORD dwInstance, IN LPCTSTR lpszParent, IN LPCTSTR lpszAlias ) /*++ Routine Description: Generate text summary of what's in the security template 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 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); } } } CIISSecWizSettings::CIISSecWizSettings( IN pfnNewSecurityTemplate pfnTemplateAllocator, IN LPCTSTR lpszServer, IN LPCTSTR lpszService, IN DWORD dwInstance, IN LPCTSTR lpszParent, IN LPCTSTR lpszAlias ) /*++ Routine Description: Constructor Arguments: pfnNewSecurityTemplate pfnTemplateAllocator : Function to allocate templ. LPCTSTR lpszServer : Server name LPCTSTR lpszService : Service name DWORD dwInstance : Instance number LPCTSTR lpszParent : Parent path LPCTSTR lpszAlias : Alias node name Return Value: N/A --*/ : CObjectPlus(), m_pfnTemplateAllocator(pfnTemplateAllocator), m_strServer(lpszServer), m_strService(lpszService), m_strParent(), m_strAlias(), m_dwInstance(dwInstance), m_fUseTemplate(TRUE), m_fSetAcls(FALSE), m_fReplaceAcls(FALSE), m_pist(NULL), m_hResult(S_OK) { if (lpszParent) { m_strParent = lpszParent; } if (lpszAlias) { m_strAlias = lpszAlias; } } CIISSecWizSettings::~CIISSecWizSettings() /*++ Routine Description: Destructor Arguments: N/A Return Value: N/A --*/ { if (m_pist != NULL) { delete m_pist; } } HRESULT CIISSecWizSettings::FetchProperties( IN CMetaKey & mk, IN LPCTSTR lpszPath, OPTIONAL IN BOOL fInherit OPTIONAL ) /*++ 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) // m_pist = (*m_pfnTemplateAllocator)(&mk, lpszPath, fInherit); 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_strServer, METADATA_PERMISSION_READ, m_pSettings->m_strService, m_pSettings->m_dwInstance, m_pSettings->m_strParent, m_pSettings->m_strAlias ); 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; } } 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 // CMetaKey mk( m_pSettings->m_strServer, METADATA_PERMISSION_READ, m_pSettings->m_strService, MASTER_INSTANCE, g_cszTemplates, strItem ); CError err(m_pSettings->FetchProperties(mk, g_cszRoot, 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 // CMetaEnumerator mk( m_pSettings->m_strServer, m_pSettings->m_strService, MASTER_INSTANCE, g_cszTemplates ); CError err(mk.QueryResult()); if (err.Failed()) { if (err.Win32Error() == ERROR_PATH_NOT_FOUND) { AfxMessageBox(IDS_NO_TEMPLATES); } else { err.MessageBox(); } } else { // // 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); } } } } 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 (!IsServerLocal(m_pSettings->m_strServer)) { TRACEEOLID("We're not local -- skipping ACL phase"); return FALSE; } // // Get properties on the current directory object // CChildNodeProps props( m_pSettings->m_strServer, m_pSettings->m_strService, m_pSettings->m_dwInstance, m_pSettings->m_strParent, m_pSettings->m_strAlias, 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_strServer); 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_strServer, m_pSettings->m_strService, m_pSettings->m_dwInstance, m_pSettings->m_strParent, m_pSettings->m_strAlias ); 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() /*++ Routine Description: Activation handler Arguments: None Return Value: TRUE for success, FALSE for failure --*/ { SetControlStates(); DisplaySummary(); return CIISWizardPage::OnSetActive(); } /* virtual */ LRESULT CPWSummary::OnWizardNext() /*++ Routine Description: 'Next' button handler. Force the control data to be stored Arguments: None Return Value: 0 to proceed, -1 to fail --*/ { // // Store everything here // CError err(m_pSettings->m_pist->ApplySettings( m_pSettings->m_fUseTemplate, m_pSettings->m_strServer, m_pSettings->m_strService, m_pSettings->m_dwInstance, m_pSettings->m_strParent, m_pSettings->m_strAlias )); // // 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; 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 COMDLL_ISMSecurityWizard( IN pfnNewSecurityTemplate pfnTemplateAllocator, IN CMetaInterface * pInterface, IN UINT nLeftBmpId, IN UINT nHeadBmpId, IN LPCTSTR lpszService, IN DWORD dwInstance, IN LPCTSTR lpszParent, IN LPCTSTR lpszAlias ) /*++ Routine Description: Launch the security wizard Arguments: pfnNewSecurityTemplate pfnTemplateAllocator : Function to allocate template. CMetaInterface * pInterface : Existing interface LPCTSTR lpszService : Service name DWORD dwInstance : Parent instance LPCTSTR lpszParent : Parent path LPCTSTR lpszAlias : Child to configure or NULL Return Value: HRESULT --*/ { CError err; ASSERT(pInterface != NULL); LPCTSTR lpszServer = pInterface->QueryServerName(); ASSERT(lpszServer != NULL); // // Only run wizard if they are an administrator - boydm // BOOL fAdmin; err = DetermineIfAdministrator( pInterface, lpszService, dwInstance, &fAdmin ); if (err.Failed() || !fAdmin) { AfxMessageBox(IDS_ACL_ADMINS); return err; } CIISWizardSheet sheet(nLeftBmpId, nHeadBmpId); // // Create security wizard settings object // CIISSecWizSettings sws( pfnTemplateAllocator, lpszServer, lpszService, dwInstance, lpszParent, lpszAlias ); 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; }