/*++ Microsoft Windows Copyright (C) Microsoft Corporation, 1981 - 1998 Module Name: secpath.cxx Abstract: this file contains the code for the dialog that is used for associating security groups with paths. Author: Rahul Thombre (RahulTh) 4/14/1998 Revision History: 4/14/1998 RahulTh Created this module. --*/ #include "precomp.hxx" // //mapping between help ids and controls ids for this dialog // const DWORD g_aHelpIDMap_IDD_SECPATH[] = { IDC_SECPATH_ICON, IDH_DISABLEHELP, IDC_SECPATH_DESC, IDH_DISABLEHELP, IDC_SECPATH_SECGROUP, IDH_DISABLEHELP, IDC_EDIT_SECGROUP, IDH_EDIT_SECGROUP, IDC_BROWSE_SECGROUP, IDH_BROWSE_SECGROUP, IDC_SECPATH_TARGET, IDH_DISABLEHELP, 0, 0 }; /////////////////////////// /// Construction CSecGroupPath::CSecGroupPath (CWnd * pParent, UINT cookie, LPCTSTR szFolderName, LPCTSTR szGroupName /*=NULL*/, LPCTSTR szGroupSidStr /*=NULL*/, LPCTSTR szTarget /*= NULL*/) : CDialog(CSecGroupPath::IDD, pParent), m_redirPath (cookie), m_cookie (cookie) { m_szFolderName = szFolderName; m_szGroup = szGroupName; m_szSidStr = szGroupSidStr; m_szTarget = szTarget; if (! m_szTarget.IsEmpty()) { m_szTarget.TrimLeft(); m_szTarget.TrimRight(); m_szTarget.TrimRight(L'\\'); } m_bPathValid = FALSE; m_iCurrType = -1; } ///////////////////////// ///Overrides void CSecGroupPath::DoDataExchange (CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSecGroupPath) DDX_Control(pDX, IDC_EDIT_SECGROUP, m_EditSecGroup); DDX_Control(pDX, IDC_BROWSE_SECGROUP, m_btnBrowseSecGroup); DDX_Control(pDX, IDC_SECPATH_PLACEHOLDER, m_placeHolder); //}}AFX_DATA_MAP } ///////////////////// /// Message maps BEGIN_MESSAGE_MAP(CSecGroupPath, CDialog) //{{AFX_MSG_MAP(CSecGroupPath) ON_BN_CLICKED (IDC_BROWSE_SECGROUP, OnBrowseGroups) ON_EN_UPDATE (IDC_EDIT_SECGROUP, OnSecGroupUpdate) ON_EN_KILLFOCUS (IDC_EDIT_SECGROUP, OnSecGroupKillFocus) ON_MESSAGE (WM_PATH_TWEAKED, OnPathTweak) ON_MESSAGE (WM_HELP, OnHelp) ON_MESSAGE (WM_CONTEXTMENU, OnContextMenu) //}AFX_MSG_MAP END_MESSAGE_MAP() BOOL CSecGroupPath::OnInitDialog () { CError error (this); CDialog::OnInitDialog(); // // Make sure that the supplied path is parseable into one of the known // types // if (! m_szTarget.IsEmpty()) m_redirPath.Load ((LPCTSTR) m_szTarget); // This will always succeed if m_szTarget is not empty m_pathChooser.Instantiate (m_cookie, this, &m_placeHolder, (const CRedirPath *) &m_redirPath, SWP_SHOWWINDOW ); m_EditSecGroup.SetWindowText (m_szGroup); m_EditSecGroup.SetSel (0, -1, FALSE); m_EditSecGroup.SetFocus(); SetOKState(); return FALSE; //returning FALSE since we are setting the focus to the edit box } void CSecGroupPath::OnOK () { CError error(this); CString szRoot; CString szSuffix; CRedirPath newPath (m_cookie); BOOL bStatus = TRUE; UINT pathType; //first check if we have a valid group. OnSecGroupKillFocus(); //if the target is not a UNC path, try to convert it to one. m_pathChooser.OnRootKillFocus(); if (!m_fValidSid) { error.ShowMessage (IDS_NOSECURITY_INFO); return; } m_EditSecGroup.GetWindowText (m_szGroup); m_szGroup.TrimLeft(); m_szGroup.TrimRight(); m_szSidStr.TrimLeft(); m_szSidStr.TrimRight(); m_szSidStr.MakeLower(); m_pathChooser.GetRoot (szRoot); pathType = m_pathChooser.GetType(); bStatus = TRUE; if (m_redirPath.IsPathDifferent (pathType, (LPCTSTR)szRoot)) { // The path has changed, so use the new suffix newPath.GenerateSuffix (szSuffix, m_cookie, pathType); bStatus = newPath.Load (pathType, (LPCTSTR) szRoot, (LPCTSTR) szSuffix); if (bStatus) newPath.GeneratePath (m_szTarget); } else { m_redirPath.GeneratePath (m_szTarget); } //check if all the data has been provided. if (! bStatus || m_szTarget == TEXT("*") || //this particular check is very important -- see code for CFileInfo::LoadSection to see why m_szGroup.IsEmpty()) { error.ShowMessage (IDS_INVALID_GROUPPATH); } else if (pathType != IDS_USERPROFILE_PATH && ! PathIsUNC ((LPCTSTR) m_szTarget) ) { error.SetStyle (MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2); error.SetTitle (IDS_DEFAULT_WARNING_TITLE); if (IDYES == error.ShowMessage (IDS_PATHNOTUNC_WARNING)) { CDialog::OnOK(); } } else { CDialog::OnOK(); } } void CSecGroupPath::OnCancel (void) { m_pathChooser.OnCancel(); CDialog::OnCancel(); } //browse the security groups void CSecGroupPath::OnBrowseGroups () { AFX_MANAGE_STATE(AfxGetStaticModuleState()); CError error(this); PCWSTR apwszAttribs[] = { L"ObjectSid" }; DWORD dwError = ERROR_SUCCESS; HRESULT hr; IDsObjectPicker * pDsObjectPicker = NULL; DSOP_INIT_INFO InitInfo; const ULONG cbNumScopes = 3; DSOP_SCOPE_INIT_INFO ascopes[cbNumScopes]; IDataObject * pdo = NULL; STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL }; UINT cf = 0; PDS_SELECTION_LIST pDsSelList = NULL; FORMATETC formatetc = { (CLIPFORMAT)cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; PDS_SELECTION pDsSelection = NULL; BOOL bAllocatedStgMedium = FALSE; SAFEARRAY * pVariantArr = NULL; PSID pSid = NULL; CString szDomain; CString szAcct; SID_NAME_USE eUse; hr = CoInitialize (NULL); if (SUCCEEDED (hr)) { hr = CoCreateInstance (CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER, IID_IDsObjectPicker, (void **) & pDsObjectPicker ); } if (FAILED(hr)) { dwError = IDS_OBJPICK_ERROR; goto BrwsGrp_Err; } //Initialize the scopes ZeroMemory (ascopes, cbNumScopes * sizeof (DSOP_SCOPE_INIT_INFO)); ascopes[0].cbSize = sizeof (DSOP_SCOPE_INIT_INFO); ascopes[0].flType = DSOP_SCOPE_TYPE_ENTERPRISE_DOMAIN; ascopes[0].flScope = DSOP_SCOPE_FLAG_STARTING_SCOPE; ascopes[0].FilterFlags.Uplevel.flBothModes = DSOP_FILTER_BUILTIN_GROUPS | DSOP_FILTER_UNIVERSAL_GROUPS_DL | DSOP_FILTER_UNIVERSAL_GROUPS_SE | DSOP_FILTER_GLOBAL_GROUPS_DL | DSOP_FILTER_GLOBAL_GROUPS_SE; ascopes[0].FilterFlags.Uplevel.flNativeModeOnly = DSOP_FILTER_DOMAIN_LOCAL_GROUPS_DL | DSOP_FILTER_DOMAIN_LOCAL_GROUPS_SE; ascopes[1].cbSize = sizeof (DSOP_SCOPE_INIT_INFO); ascopes[1].flType = DSOP_SCOPE_TYPE_GLOBAL_CATALOG; ascopes[1].FilterFlags.Uplevel.flBothModes = ascopes[0].FilterFlags.Uplevel.flBothModes; ascopes[1].FilterFlags.Uplevel.flNativeModeOnly = ascopes[0].FilterFlags.Uplevel.flNativeModeOnly; ascopes[2].cbSize = sizeof (DSOP_SCOPE_INIT_INFO); ascopes[2].flType = DSOP_SCOPE_TYPE_TARGET_COMPUTER; ascopes[2].FilterFlags.flDownlevel = DSOP_DOWNLEVEL_FILTER_LOCAL_GROUPS | DSOP_DOWNLEVEL_FILTER_GLOBAL_GROUPS; //Populate the InitInfo structure that is used to initialize the object //picker. ZeroMemory (&InitInfo, sizeof (InitInfo)); InitInfo.cbSize = sizeof (InitInfo); InitInfo.cDsScopeInfos = cbNumScopes; InitInfo.aDsScopeInfos = ascopes; InitInfo.cAttributesToFetch = 1; InitInfo.apwzAttributeNames = apwszAttribs; hr = pDsObjectPicker->Initialize (&InitInfo); if (FAILED (hr)) { dwError = IDS_OBJPICK_ERROR; goto BrwsGrp_Err; } hr = pDsObjectPicker->InvokeDialog (this->m_hWnd, &pdo); if (FAILED(hr)) { dwError = IDS_OBJPICK_ERROR; goto BrwsGrp_Err; } if (S_FALSE == hr) //the user hit cancel goto BrwsGrp_CleanupAndQuit; //if we are here, the user chose, OK, so find out what group was chosen cf = RegisterClipboardFormat (CFSTR_DSOP_DS_SELECTION_LIST); if (0 == cf) { dwError = IDS_NOSECURITY_INFO; goto BrwsGrp_Err; } //set the clipformat for the formatetc structure formatetc.cfFormat = (CLIPFORMAT)cf; hr = pdo->GetData (&formatetc, &stgmedium); if (FAILED (hr) ) { dwError = IDS_NOSECURITY_INFO; goto BrwsGrp_Err; } bAllocatedStgMedium = TRUE; pDsSelList = (PDS_SELECTION_LIST) GlobalLock (stgmedium.hGlobal); if (NULL == pDsSelList) { dwError = IDS_NOSECURITY_INFO; goto BrwsGrp_Err; } if (!pDsSelList->cItems) //some item must have been selected { dwError = IDS_NOSECURITY_INFO; goto BrwsGrp_Err; } pDsSelection = &(pDsSelList->aDsSelection[0]); //we must get the ObjectSid attribute, otherwise we fail //so make sure that the attribute has been fetched. if (!pDsSelList->cFetchedAttributes || (! (VT_ARRAY & pDsSelection->pvarFetchedAttributes->vt))) { dwError = IDS_NOSECURITY_INFO; goto BrwsGrp_Err; } pVariantArr = pDsSelection->pvarFetchedAttributes->parray; pSid = (PSID) pVariantArr->pvData; if (STATUS_SUCCESS != GetFriendlyNameFromSid (pSid, szDomain, szAcct, &eUse)) { dwError = IDS_NOSECURITY_INFO; goto BrwsGrp_Err; } //store away the string representation of this sid if (STATUS_SUCCESS != GetStringFromSid(pSid, m_szSidStr)) goto BrwsGrp_Err; m_szSidStr.MakeLower(); if (!szDomain.IsEmpty()) szAcct = szDomain + '\\' + szAcct; m_EditSecGroup.SetWindowText (szAcct); m_fValidSid = TRUE; goto BrwsGrp_CleanupAndQuit; BrwsGrp_Err: error.ShowMessage (dwError); BrwsGrp_CleanupAndQuit: if (pDsSelList) GlobalUnlock (stgmedium.hGlobal); if (bAllocatedStgMedium) ReleaseStgMedium (&stgmedium); if (pdo) pdo->Release(); if (pDsObjectPicker) pDsObjectPicker->Release (); } void CSecGroupPath::SetOKState (void) { CString szGroup; CString szPath; BOOL bCheckPath = FALSE; m_EditSecGroup.GetWindowText(szGroup); szGroup.TrimLeft(); szGroup.TrimRight(); if (IDS_SPECIFIC_PATH == m_iCurrType || IDS_PERUSER_PATH == m_iCurrType) { bCheckPath = TRUE; m_pathChooser.GetRoot (szPath); szPath.TrimLeft(); szPath.TrimRight(); szPath.TrimRight(L'\\'); } if (szGroup.IsEmpty() || (bCheckPath && szPath.IsEmpty())) GetDescendantWindow(IDOK, FALSE)->EnableWindow(FALSE); else GetDescendantWindow(IDOK, FALSE)->EnableWindow(TRUE); } void CSecGroupPath::OnSecGroupUpdate() { //the group in the edit box is about to change. //this means we can no longer trust the sid that we may have m_fValidSid = FALSE; SetOKState(); } //we try to get a sid and domain for the group specified //if we can't, we simply ignore the error and sit tight. void CSecGroupPath::OnSecGroupKillFocus() { BOOL bStatus; CString szGroup; WCHAR* szWindowText = NULL; WCHAR szDom[MAX_PATH]; DWORD dwDomLen = MAX_PATH; WCHAR* szAcct; PSID Sid = NULL; DWORD dwSidLen = 0; SID_NAME_USE eUse; DWORD Status; CHourglass hourglass; //LookupAccountName takes a while BOOL fDomainSupplied = FALSE; //if we already have a valid sid, there is nothing to worry. if (m_fValidSid) goto KillFocusEnd; //we don't have a valid sid, so we try to get one from the data in the //group box m_EditSecGroup.GetWindowText (szGroup); szGroup.TrimLeft(); szGroup.TrimRight(); if (szGroup.IsEmpty()) goto KillFocusEnd; ULONG ulNoChars; ulNoChars = wcslen( (LPCWSTR)szGroup )+1; szWindowText = new WCHAR[ulNoChars]; if ( szWindowText == NULL ) { goto KillFocusEnd; } //get the account name from the window HRESULT hr; hr = StringCchCopy (szWindowText, ulNoChars, (LPCWSTR) szGroup); ASSERT(SUCCEEDED(hr)); szAcct = wcsrchr (szWindowText, '\\'); if (!szAcct) { szAcct = szWindowText; } else { *szAcct++ = 0; //advance it so that it now points to the account //and szWindowText will now refer to the supplied domain fDomainSupplied = TRUE; } do { bStatus = LookupAccountName (NULL, szAcct, Sid, &dwSidLen, szDom, &dwDomLen, &eUse); if (!bStatus) { Status = GetLastError(); if (ERROR_INSUFFICIENT_BUFFER != Status) goto KillFocusEnd; //we just ignore the error for now LocalFree(Sid); Sid = (PSID) LocalAlloc (LPTR, dwSidLen); if (NULL == Sid) goto KillFocusEnd; //we just ignore the error for now continue; } break; } while (1); //we have the sid if we are here //make sure it represents a group switch (eUse) { case SidTypeGroup: case SidTypeWellKnownGroup: case SidTypeAlias: break; default: goto KillFocusEnd; } //also make sure that if a domain was supplied, it matches what we //got back if (fDomainSupplied && (0 != lstrcmpi (szWindowText, szDom))) goto KillFocusEnd; //if we are here, then we have the sid for a group if (STATUS_SUCCESS != GetStringFromSid (Sid, m_szSidStr)) goto KillFocusEnd; //we were finally successful in getting the sid in a string format m_szSidStr.MakeLower(); szGroup = szDom; if (!szGroup.IsEmpty()) szGroup += '\\'; szGroup += szAcct; m_EditSecGroup.SetWindowText ((LPCTSTR) szGroup); m_fValidSid = TRUE; KillFocusEnd: LocalFree(Sid); if ( szWindowText != NULL ) { delete [] szWindowText; } return; } void CSecGroupPath::OnPathTweak (WPARAM wParam, LPARAM lParam) { m_bPathValid = (BOOL) wParam; m_iCurrType = (LONG) lParam; SetOKState(); } LONG CSecGroupPath::OnHelp (WPARAM wParam, LPARAM lParam) { LONG lResult = 0; CString szHelpFile; szHelpFile.LoadString(IDS_HELP_FILE); ::WinHelp((HWND)(((LPHELPINFO)lParam)->hItemHandle), (LPCTSTR) szHelpFile, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_aHelpIDMap_IDD_SECPATH); return lResult; } LONG CSecGroupPath::OnContextMenu (WPARAM wParam, LPARAM lParam) { AFX_MANAGE_STATE (AfxGetStaticModuleState()); LONG lResult = 0; CString szHelpFile; szHelpFile.LoadString(IDS_HELP_FILE); ::WinHelp((HWND)wParam, (LPCTSTR)szHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID)g_aHelpIDMap_IDD_SECPATH); return lResult; }