mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1114 lines
27 KiB
1114 lines
27 KiB
//
|
|
// permissi.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
|
|
extern "C"
|
|
{
|
|
#define _NTSEAPI_ // We already have the security API hdrs
|
|
#include <getuser.h>
|
|
|
|
//
|
|
// Unable to include ntrtl.h in mfc app because of
|
|
// duplicate definitions, so we specify the prototypes
|
|
// here.
|
|
//
|
|
typedef LONG NTSTATUS;
|
|
|
|
NTSYSAPI
|
|
ULONG
|
|
NTAPI
|
|
RtlLengthSid (
|
|
PSID Sid
|
|
);
|
|
|
|
NTSYSAPI
|
|
NTSTATUS
|
|
NTAPI
|
|
RtlCopySid (
|
|
ULONG DestinationSidLength,
|
|
PSID DestinationSid,
|
|
PSID SourceSid
|
|
);
|
|
}
|
|
|
|
#include "catscfg.h"
|
|
#include "permissi.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
//
|
|
// Global Array of predefined rights. This is the order
|
|
// in which they will show up the rights combo box. This
|
|
// order is important, as indices from that combo box
|
|
// map directly to this array.
|
|
//
|
|
RIGHTS rgServiceRights[] =
|
|
{
|
|
//
|
|
// Resource Str ID Service Access Mask Descr.
|
|
// ==========================================================================
|
|
#ifdef GATEWAY
|
|
{ IDS_FTP_READ, ACC_FTP, GATEWAY_SERVICE_READ_ACCESS }, // FTP Read
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FTP Write permission removed -- 10/27/1995
|
|
//
|
|
//{ IDS_FTP_WRITE, ACC_FTP, GATEWAY_SERVICE_WRITE_ACCESS }, // FTP Write
|
|
|
|
{ IDS_FTP, ACC_FTP, GATEWAY_SERVICE_READ_ACCESS
|
|
| GATEWAY_SERVICE_WRITE_ACCESS}, // FTP R&W
|
|
|
|
{ IDS_GOPHER, ACC_GOPHER, GATEWAY_SERVICE_READ_ACCESS }, // Gopher
|
|
{ IDS_WEB, ACC_W3, GATEWAY_SERVICE_READ_ACCESS
|
|
| GATEWAY_SERVICE_WRITE_ACCESS}, // WWW
|
|
#else
|
|
{ IDS_MSN, ACC_MSN, MSN_SERVICE_READ_ACCESS
|
|
| MSN_SERVICE_WRITE_ACCESS}, // MSN
|
|
#endif
|
|
};
|
|
|
|
#define NUM_RIGHTS (sizeof(rgServiceRights) / sizeof(rgServiceRights[0]))
|
|
|
|
//
|
|
// Initialize static strings
|
|
//
|
|
LPCTSTR CAccessEntry::lpstrServiceNames[ACC_COUNT] =
|
|
{
|
|
#ifdef GATEWAY
|
|
FTP_SERVICE_NAME_W,
|
|
GOPHER_SERVICE_NAME_W,
|
|
W3_SERVICE_NAME_W,
|
|
#else
|
|
MSN_SERVICE_NAME_W,
|
|
#endif
|
|
};
|
|
|
|
//
|
|
// Get a full user name and picture ID
|
|
//
|
|
BOOL
|
|
CAccessEntry::LookupAccountSid(
|
|
CString &strFullUserName,
|
|
int & nPictureID,
|
|
PSID pSid,
|
|
LPCTSTR lpstrSystemName /* OPTIONAL */
|
|
)
|
|
{
|
|
DWORD cbUserName = PATHLEN * sizeof(TCHAR);
|
|
DWORD cbRefDomainName = PATHLEN * sizeof(TCHAR);
|
|
|
|
CString strUserName;
|
|
CString strRefDomainName;
|
|
SID_NAME_USE SidToNameUse;
|
|
|
|
LPTSTR lpUserName = strUserName.GetBuffer(PATHLEN);
|
|
LPTSTR lpRefDomainName = strRefDomainName.GetBuffer(PATHLEN);
|
|
BOOL fLookUpOK = ::LookupAccountSid(lpstrSystemName, pSid, lpUserName,
|
|
&cbUserName, lpRefDomainName, &cbRefDomainName, &SidToNameUse);
|
|
|
|
strUserName.ReleaseBuffer();
|
|
strRefDomainName.ReleaseBuffer();
|
|
|
|
strFullUserName.Empty();
|
|
|
|
if (fLookUpOK)
|
|
{
|
|
//
|
|
// BUGBUG: Is this hardcoded string ok?
|
|
//
|
|
if (!strRefDomainName.IsEmpty()
|
|
&& strRefDomainName.CompareNoCase(_T("BUILTIN")))
|
|
{
|
|
strFullUserName += strRefDomainName;
|
|
strFullUserName += "\\";
|
|
}
|
|
strFullUserName += strUserName;
|
|
|
|
nPictureID = SidToNameUse;
|
|
}
|
|
else
|
|
{
|
|
strFullUserName.LoadString(IDS_UNKNOWN_USER);
|
|
nPictureID = SidTypeUnknown;
|
|
}
|
|
|
|
//
|
|
// SID_NAME_USE is 1-based
|
|
//
|
|
--nPictureID ;
|
|
|
|
return fLookUpOK;
|
|
}
|
|
|
|
//
|
|
// CAccessEntry
|
|
//
|
|
CAccessEntry::CAccessEntry(
|
|
LPACCESS_ENTRY lpAccessEntry,
|
|
LPCTSTR lpstrSystemName,
|
|
BOOL fResolveSID // Yes, if we want to resolve it now
|
|
)
|
|
: m_pSid(NULL),
|
|
m_fDirty(FALSE),
|
|
m_fUpdates(UPD_NONE),
|
|
m_fSIDResolved(FALSE),
|
|
m_nPictureID(SidTypeUnknown-1), // SID_NAME_USE is 1-based
|
|
m_lpstrSystemName(NULL),
|
|
m_strUserName()
|
|
{
|
|
//
|
|
// Allocate a new copy of the sid.
|
|
//
|
|
DWORD cbSize = ::RtlLengthSid(lpAccessEntry->UserID);
|
|
m_pSid = (PSID)::LocalAlloc(LPTR, cbSize);
|
|
DWORD err = ::RtlCopySid(cbSize, m_pSid, lpAccessEntry->UserID);
|
|
ASSERT(err == ERROR_SUCCESS);
|
|
|
|
SetAccessMask(lpAccessEntry);
|
|
|
|
if (lpstrSystemName != NULL)
|
|
{
|
|
m_lpstrSystemName = new TCHAR[::lstrlen(lpstrSystemName)+1];
|
|
::lstrcpy(m_lpstrSystemName, lpstrSystemName);
|
|
}
|
|
|
|
if (fResolveSID)
|
|
{
|
|
ResolveSID();
|
|
}
|
|
}
|
|
|
|
CAccessEntry::CAccessEntry(
|
|
ACCESS_MASK accPermissions,
|
|
PSID pSid,
|
|
LPCTSTR lpstrSystemName,
|
|
BOOL fResolveSID
|
|
)
|
|
: m_pSid(NULL),
|
|
m_fDirty(FALSE),
|
|
m_fUpdates(UPD_NONE),
|
|
m_fSIDResolved(FALSE),
|
|
m_nPictureID(SidTypeUnknown-1), // SID_NAME_USE is 1-based
|
|
m_strUserName(),
|
|
m_lpstrSystemName(NULL),
|
|
m_accMask(accPermissions)
|
|
{
|
|
//
|
|
// Allocate a new copy of the sid.
|
|
//
|
|
DWORD cbSize = ::RtlLengthSid(pSid);
|
|
m_pSid = (PSID)::LocalAlloc(LPTR, cbSize);
|
|
DWORD err = ::RtlCopySid(cbSize, m_pSid, pSid);
|
|
ASSERT(err == ERROR_SUCCESS);
|
|
|
|
if (lpstrSystemName != NULL)
|
|
{
|
|
m_lpstrSystemName = new TCHAR[::lstrlen(lpstrSystemName)+1];
|
|
::lstrcpy(m_lpstrSystemName, lpstrSystemName);
|
|
}
|
|
|
|
if (fResolveSID)
|
|
{
|
|
ResolveSID();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up our copy of the SID in the destructor
|
|
//
|
|
CAccessEntry::~CAccessEntry()
|
|
{
|
|
TRACEEOLID(_T("Destroying our copy of the SID"));
|
|
ASSERT(m_pSid != NULL);
|
|
::LocalFree(m_pSid);
|
|
if (m_lpstrSystemName != NULL)
|
|
{
|
|
delete m_lpstrSystemName;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Look up the user name and type
|
|
//
|
|
BOOL
|
|
CAccessEntry::ResolveSID()
|
|
{
|
|
//
|
|
// Even if it fails, it will be considered
|
|
// resolved
|
|
//
|
|
m_fSIDResolved = TRUE;
|
|
|
|
return CAccessEntry::LookupAccountSid(m_strUserName,
|
|
m_nPictureID, m_pSid, m_lpstrSystemName);
|
|
}
|
|
|
|
//
|
|
// SetAccessMask
|
|
//
|
|
void
|
|
CAccessEntry::SetAccessMask(
|
|
LPACCESS_ENTRY lpAccessEntry
|
|
)
|
|
{
|
|
m_accMask = lpAccessEntry->AccessRights;
|
|
}
|
|
|
|
//
|
|
// Do a comparison of the two
|
|
// by comparing their SIDs
|
|
//
|
|
BOOL
|
|
CAccessEntry::operator ==(
|
|
const CAccessEntry & acc
|
|
) const
|
|
{
|
|
return ::EqualSid(acc.m_pSid, m_pSid);
|
|
}
|
|
|
|
//
|
|
// Direct comparison with a SID
|
|
//
|
|
BOOL
|
|
CAccessEntry::operator ==(
|
|
const PSID pSid
|
|
) const
|
|
{
|
|
return ::EqualSid(pSid, m_pSid);
|
|
}
|
|
|
|
|
|
//
|
|
// Add permissions to this entry
|
|
//
|
|
void
|
|
CAccessEntry::AddPermissions(
|
|
ACCESS_MASK accNewPermissions
|
|
)
|
|
{
|
|
m_accMask |= accNewPermissions;
|
|
m_fDirty = TRUE;
|
|
m_fUpdates |= UPD_CHANGED;
|
|
}
|
|
|
|
//
|
|
// Remove permissions from this entry
|
|
//
|
|
void
|
|
CAccessEntry::RemovePermissions(
|
|
ACCESS_MASK accPermissions
|
|
)
|
|
{
|
|
m_accMask &= ~accPermissions;
|
|
m_fDirty = TRUE;
|
|
m_fUpdates |= UPD_CHANGED;
|
|
}
|
|
|
|
//
|
|
// Mark the entry as being newly added for this session.
|
|
// This is important, in case this entry later gets
|
|
// deleted in this session. Since we don't call the
|
|
// api's until OK is pressed, the entry will never have
|
|
// existed in the database, and therefore no API needs
|
|
// to be called for it.
|
|
//
|
|
void
|
|
CAccessEntry::MarkEntryAsNew()
|
|
{
|
|
m_fDirty = TRUE;
|
|
m_fUpdates |= UPD_ADDED;
|
|
}
|
|
|
|
void
|
|
CAccessEntry::MarkEntryAsClean()
|
|
{
|
|
m_fDirty = FALSE;
|
|
m_fUpdates = UPD_NONE;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// CAccessEntryListBox - a listbox of user SIDs
|
|
//
|
|
IMPLEMENT_DYNAMIC(CAccessEntryListBox, CListBoxEx);
|
|
|
|
const int CAccessEntryListBox::nBitmaps = 8;
|
|
|
|
CAccessEntryListBox::CAccessEntryListBox (
|
|
int nTab
|
|
)
|
|
{
|
|
SetTabs(nTab);
|
|
}
|
|
|
|
void
|
|
CAccessEntryListBox::SetTabs(
|
|
int nTab
|
|
)
|
|
{
|
|
m_nTab = nTab;
|
|
}
|
|
|
|
void
|
|
CAccessEntryListBox::DrawItemEx(
|
|
CListBoxExDrawStruct& ds
|
|
)
|
|
{
|
|
CAccessEntry * p = (CAccessEntry *)ds.m_ItemData;
|
|
ASSERT(p != NULL);
|
|
|
|
CDC * pBmpDC = (CDC *)&ds.m_pResources->DcBitMap();
|
|
int bmh = ds.m_pResources->BitmapHeight();
|
|
int bmw = ds.m_pResources->BitmapWidth();
|
|
|
|
//
|
|
// Display a user bitmap
|
|
//
|
|
int nOffset = p->QueryPictureID();
|
|
int bm_h = (ds.m_Sel) ? 0 : bmh;
|
|
int bm_w = bmw * nOffset;
|
|
ds.m_pDC->BitBlt( ds.m_Rect.left+1, ds.m_Rect.top, bmw, bmh,
|
|
pBmpDC, bm_w, bm_h, SRCCOPY );
|
|
|
|
ASSERT(p->IsSIDResolved());
|
|
|
|
ColumnText(ds.m_pDC, ds.m_Rect.left + bmw + 3, ds.m_Rect.top,
|
|
ds.m_Rect.right, ds.m_Rect.bottom, (LPCTSTR)p->QueryUserName());
|
|
|
|
/*
|
|
ColumnText(ds.m_pDC, ds.m_Rect.left + bmw + 3, ds.m_Rect.top, m_nTab,
|
|
ds.m_Rect.bottom, p->QueryUserName());
|
|
|
|
ColumnText(ds.m_pDC, ds.m_Rect.left + m_nTab, ds.m_Rect.top,
|
|
ds.m_Rect.right, ds.m_Rect.bottom, _T("(FrFwWrWwGrGw)"));
|
|
*/
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// CPermissionsPage property page
|
|
//
|
|
IMPLEMENT_DYNCREATE(CPermissionsPage, INetPropertyPage)
|
|
|
|
CPermissionsPage::CPermissionsPage(
|
|
INetPropertySheet * pSheet
|
|
)
|
|
: INetPropertyPage(CPermissionsPage::IDD, pSheet,
|
|
::GetModuleHandle(CATSCFG_DLL_NAME)),
|
|
m_ListBoxRes(
|
|
IDB_ACLUSERS,
|
|
CAccessEntryListBox::nBitmaps
|
|
),
|
|
m_strServer(GetConfig().GetPrimaryServer()),
|
|
m_err(0)
|
|
{
|
|
#ifdef _DEBUG
|
|
afxMemDF |= checkAlwaysMemDF;
|
|
#endif // _DEBUG
|
|
|
|
//{{AFX_DATA_INIT(CPermissionsPage)
|
|
// NOTE: the ClassWizard will add member initialization here
|
|
//}}AFX_DATA_INIT
|
|
|
|
m_list_Services.AttachResources( &m_ListBoxRes );
|
|
|
|
LPTSTR lpPath = m_strHelpFile.GetBuffer(256);
|
|
::GetModuleFileName(::GetModuleHandle(CATSCFG_DLL_NAME), lpPath, 255);
|
|
LPTSTR lp2 = _tcsrchr( lpPath, _T('.'));
|
|
ASSERT(lp2 != NULL);
|
|
*lp2 = '\0';
|
|
m_strHelpFile.ReleaseBuffer();
|
|
m_strHelpFile += _T(".HLP");
|
|
}
|
|
|
|
CPermissionsPage::~CPermissionsPage()
|
|
{
|
|
}
|
|
|
|
void
|
|
CPermissionsPage::DoDataExchange(
|
|
CDataExchange* pDX
|
|
)
|
|
{
|
|
CPropertyPage::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CPermissionsPage)
|
|
DDX_Control(pDX, IDC_BUTTON_REMOVE_PERM_SERVICE, m_button_RemoveService);
|
|
DDX_Control(pDX, IDC_BUTTON_ADD_PERM_SERVICE, m_button_AddService);
|
|
DDX_Control(pDX, IDC_COMBO_RIGHTS, m_combo_Rights);
|
|
DDX_Control(pDX, IDC_STATIC_SERVICE_RIGHTS, m_static_ServiceRights);
|
|
DDX_Control(pDX, IDC_STATIC_SERVICE_NAME, m_static_ServiceName);
|
|
//}}AFX_DATA_MAP
|
|
|
|
DDX_Control(pDX, IDC_LIST_SERVICE_PERMISSIONS, m_list_Services);
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CPermissionsPage, CPropertyPage)
|
|
//{{AFX_MSG_MAP(CPermissionsPage)
|
|
ON_BN_CLICKED(IDC_BUTTON_ADD_PERM_SERVICE, OnButtonAddPermService)
|
|
ON_BN_CLICKED(IDC_BUTTON_REMOVE_PERM_SERVICE, OnButtonRemovePermService)
|
|
ON_CBN_SELCHANGE(IDC_COMBO_RIGHTS, OnSelchangeComboRights)
|
|
ON_LBN_SELCHANGE(IDC_LIST_SERVICE_PERMISSIONS, OnSelchangeListServicePermissions)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
//
|
|
// Add a user to the service list. The return value
|
|
// is the what would be its listbox index.
|
|
//
|
|
void
|
|
CPermissionsPage::AddUserPermissions(
|
|
int nService,
|
|
LPUSERDETAILS pusdtNewUser,
|
|
ACCESS_MASK accPermissions
|
|
)
|
|
{
|
|
ASSERT(nService >= 0 && nService < ACC_COUNT);
|
|
//
|
|
// Look it up in the list to see if it exists already
|
|
//
|
|
CObListIter obli( m_obSID[nService] );
|
|
CAccessEntry * pAccessEntry;
|
|
|
|
while( pAccessEntry = (CAccessEntry *) obli.Next() )
|
|
{
|
|
if (*pAccessEntry == pusdtNewUser->psidUser)
|
|
{
|
|
TRACEEOLID(_T("Found existing account -- adding permissions"));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pAccessEntry == NULL)
|
|
{
|
|
TRACEEOLID(_T("This account did not yet exist -- adding new one"));
|
|
|
|
pAccessEntry = new CAccessEntry(accPermissions,
|
|
pusdtNewUser->psidUser, (LPCTSTR)m_strServer, TRUE);
|
|
pAccessEntry->MarkEntryAsNew();
|
|
m_obSID[nService].AddTail(pAccessEntry);
|
|
}
|
|
else
|
|
{
|
|
pAccessEntry->AddPermissions(accPermissions);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set tabs in listboxes
|
|
//
|
|
void
|
|
CPermissionsPage::SetListTabs()
|
|
{
|
|
RECT rc1, rc2;
|
|
m_static_ServiceName.GetWindowRect(&rc1);
|
|
m_static_ServiceRights.GetWindowRect(&rc2);
|
|
m_list_Services.SetTabs(rc2.left - rc1.left - 1);
|
|
}
|
|
|
|
//
|
|
// Fill a listbox with entries from
|
|
// the oblist.
|
|
//
|
|
// Entries will not be shown if the deleted
|
|
// flag is set, or if their access mask
|
|
// does not fit with the requested
|
|
// access mask.
|
|
//
|
|
void
|
|
CPermissionsPage::FillListBox(
|
|
CAccessEntryListBox & list,
|
|
CObOwnedList &obl,
|
|
ACCESS_MASK accMask
|
|
)
|
|
{
|
|
CObListIter obli( obl );
|
|
CAccessEntry * pAccessEntry;
|
|
|
|
//
|
|
// Remember the selection.
|
|
//
|
|
int nCurSel = list.GetCurSel();
|
|
|
|
list.SetRedraw(FALSE);
|
|
list.ResetContent();
|
|
int cItems = 0;
|
|
|
|
for ( /**/ ; pAccessEntry = (CAccessEntry *) obli.Next() ; cItems++ )
|
|
{
|
|
if (pAccessEntry->HasAppropriateAccess(accMask))
|
|
{
|
|
list.AddItem( pAccessEntry );
|
|
}
|
|
}
|
|
|
|
list.SetRedraw(TRUE);
|
|
list.SetCurSel(nCurSel);
|
|
}
|
|
|
|
//
|
|
// For each member of the list, resolve
|
|
// the SID into a username.
|
|
//
|
|
void
|
|
CPermissionsPage::ResolveList(
|
|
CObOwnedList &obl
|
|
)
|
|
{
|
|
CObListIter obli( obl );
|
|
CAccessEntry * pAccessEntry;
|
|
|
|
while( pAccessEntry = (CAccessEntry *) obli.Next() )
|
|
{
|
|
if (!pAccessEntry->IsSIDResolved())
|
|
{
|
|
pAccessEntry->ResolveSID();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build the ACL list for the indicated
|
|
// service.
|
|
//
|
|
NET_API_STATUS
|
|
CPermissionsPage::BuildList(
|
|
CObOwnedList &obl,
|
|
LPCTSTR lpstrServer,
|
|
int nService,
|
|
BOOL fResolveSID
|
|
)
|
|
{
|
|
NET_API_STATUS err = 0;
|
|
ASSERT(nService >= 0 && nService < ACC_COUNT);
|
|
LPCTSTR lpstrService = CAccessEntry::lpstrServiceNames[nService];
|
|
LPACCESS_LIST AceList = NULL;
|
|
|
|
obl.RemoveAll();
|
|
|
|
TRACEEOLID(_T("Get ACLs for ") << lpstrService );
|
|
BeginWaitCursor();
|
|
err = ENUM_USER_ACCESS(
|
|
(LPTSTR)lpstrServer,
|
|
(LPTSTR)lpstrService,
|
|
&AceList
|
|
);
|
|
EndWaitCursor();
|
|
TRACEEOLID(_T("Service returned ") << m_err );
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
return err;
|
|
}
|
|
|
|
if (fResolveSID)
|
|
{
|
|
//
|
|
// Start an hourglass, because SID Lookup could take
|
|
// some time.
|
|
//
|
|
BeginWaitCursor();
|
|
}
|
|
TRY
|
|
{
|
|
for (DWORD i = 0; i < AceList->NumEntries; ++i)
|
|
{
|
|
obl.AddTail(new CAccessEntry(
|
|
&(AceList->AccessEntries[i]), lpstrServer, fResolveSID));
|
|
}
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
err = ::GetLastError();
|
|
}
|
|
END_CATCH_ALL
|
|
|
|
if (fResolveSID)
|
|
{
|
|
EndWaitCursor();
|
|
}
|
|
|
|
//
|
|
// This is OK even if it's NULL
|
|
//
|
|
FREE_MEMORY((LPTSTR)lpstrServer, AceList);
|
|
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// Fill the combo box with rights
|
|
//
|
|
void
|
|
CPermissionsPage::FillComboBox()
|
|
{
|
|
CString str;
|
|
|
|
for (int i = 0; i < NUM_RIGHTS; ++i)
|
|
{
|
|
ASSERT(rgServiceRights[i].nService >= 0
|
|
&& rgServiceRights[i].nService < ACC_COUNT);
|
|
|
|
VERIFY(str.LoadString(rgServiceRights[i].nName));
|
|
m_combo_Rights.AddString((LPCTSTR)str);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill the service listbox depending on the
|
|
// selection in the "rights" combo box
|
|
//
|
|
void
|
|
CPermissionsPage::FillServiceListBox(
|
|
int nService,
|
|
ACCESS_MASK accMask
|
|
)
|
|
{
|
|
ASSERT(nService >= 0 && nService < ACC_COUNT);
|
|
FillListBox(m_list_Services, m_obSID[nService], accMask);
|
|
}
|
|
|
|
//
|
|
// Enable/disable controls depending on
|
|
// what's selected in the users listbox
|
|
//
|
|
void
|
|
CPermissionsPage::SetControlStates()
|
|
{
|
|
//
|
|
// Remove button available only
|
|
// if there's a selection in the
|
|
// listbox.
|
|
//
|
|
m_button_RemoveService.EnableWindow(m_list_Services.GetCurSel() != LB_ERR);
|
|
}
|
|
|
|
//
|
|
// CPermissionsPage message handlers
|
|
//
|
|
BOOL
|
|
CPermissionsPage::OnInitDialog()
|
|
{
|
|
#define BUILD_LIST(obl, svc, resSID) \
|
|
m_err = BuildList(obl, (LPCTSTR)m_strServer, svc, resSID); \
|
|
if (m_err != ERROR_SUCCESS) \
|
|
{ \
|
|
break; \
|
|
}
|
|
|
|
INetPropertyPage::OnInitDialog();
|
|
|
|
ASSERT(SingleServerSelected()); // That's all that's supported now.
|
|
|
|
SetListTabs();
|
|
FillComboBox();
|
|
|
|
if (SingleServerSelected())
|
|
{
|
|
TRACEEOLID(_T("Getting Gateway ACLs on server ") << m_strServer);
|
|
|
|
do
|
|
{
|
|
//
|
|
// The first list we build
|
|
// will be fully resolved +------------+
|
|
// Subsequent ones will be |
|
|
// resolved later. |
|
|
// | |
|
|
#ifdef GATEWAY
|
|
BUILD_LIST(m_obSID[ACC_FTP], ACC_FTP, TRUE);
|
|
BUILD_LIST(m_obSID[ACC_GOPHER], ACC_GOPHER, TRUE);
|
|
BUILD_LIST(m_obSID[ACC_W3], ACC_W3, TRUE);
|
|
#else
|
|
BUILD_LIST(m_obSID[ACC_MSN], ACC_MSN, TRUE);
|
|
#endif
|
|
}
|
|
while(FALSE);
|
|
|
|
if (m_err != ERROR_SUCCESS)
|
|
{
|
|
::DisplayMessage(m_err, MB_OK | MB_ICONHAND);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Select the first right in the combobox, and
|
|
// display the users as appropriate.
|
|
//
|
|
m_combo_Rights.SetCurSel(0);
|
|
OnSelchangeComboRights();
|
|
|
|
SetControlStates();
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
//
|
|
// Save the information
|
|
//
|
|
NET_API_STATUS
|
|
CPermissionsPage::SaveInfo(
|
|
BOOL fUpdateData
|
|
)
|
|
{
|
|
if (!IsDirty() || (fUpdateData && !UpdateData(TRUE)))
|
|
{
|
|
return NO_ERROR;
|
|
}
|
|
|
|
TRACEEOLID(_T("Saving Catapult permissions page now..."));
|
|
|
|
//
|
|
// CODEWORK: Right now I call a single API for every changed
|
|
// entry. This is not efficient, as multiple entries
|
|
// can be set with a single API call, I'll worry
|
|
// about this post-beta, however.
|
|
|
|
//
|
|
// Multi-selection not implemented yet
|
|
//
|
|
NET_API_STATUS err = 0;
|
|
ACCESS_ENTRY Ace;
|
|
ACCESS_LIST AceList;
|
|
|
|
//
|
|
// Loop through each service list:
|
|
//
|
|
for (int i = 0; i < ACC_COUNT; ++i)
|
|
{
|
|
CObListIter obli( m_obSID[i] );
|
|
CAccessEntry * pAccessEntry;
|
|
LPCTSTR lpstrService = CAccessEntry::lpstrServiceNames[i];
|
|
|
|
while( pAccessEntry = (CAccessEntry *) obli.Next() )
|
|
{
|
|
if (pAccessEntry->IsDirty())
|
|
{
|
|
TRACEEOLID(_T("Found dirty entry ")
|
|
<< pAccessEntry->QueryUserName());
|
|
//
|
|
// Ok, so this item has changed in some fashion.
|
|
// check to see if he has any rights at all, if
|
|
// not, we can delete him entirely.
|
|
//
|
|
if (!pAccessEntry->HasSomeAccess())
|
|
{
|
|
TRACEEOLID(_T("Getting ready to delete ")
|
|
<< pAccessEntry->QueryUserName());
|
|
//
|
|
// However, if this guy was new for this
|
|
// session, he never existed in the database anyway,
|
|
// so there's no need to do anything about him.
|
|
//
|
|
if (pAccessEntry->IsNew())
|
|
{
|
|
TRACEEOLID(_T("Entry didn't exist in database yet anyway"));
|
|
}
|
|
else
|
|
{
|
|
TRACEEOLID(_T("Deleting item"));
|
|
#ifdef GATEWAY
|
|
Ace.AccessRights = GATEWAY_SERVICE_READ_ACCESS;
|
|
#else
|
|
Ace.AccessRights = MSN_SERVICE_READ_ACCESS;
|
|
#endif
|
|
Ace.UserID = pAccessEntry->GetSid();
|
|
AceList.NumEntries = 1;
|
|
AceList.AccessEntries = &Ace;
|
|
|
|
err = DELETE_USER_ACCESS(
|
|
(LPTSTR)(LPCTSTR)m_strServer,
|
|
(LPTSTR)lpstrService,
|
|
&AceList
|
|
);
|
|
TRACEEOLID(_T("API Returned ") << err);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
VERIFY(m_obSID[i].Remove (pAccessEntry));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// ok, it's dirty, and has some permissions. Add the
|
|
// guy, and everything will be ok. Whatever permissions
|
|
// he had before will be overwritten anyway.
|
|
//
|
|
TRACEEOLID(_T("Adding item"));
|
|
Ace.AccessRights = pAccessEntry->QueryAccessMask();
|
|
Ace.UserID = pAccessEntry->GetSid();
|
|
AceList.NumEntries = 1;
|
|
AceList.AccessEntries = &Ace;
|
|
|
|
err = ADD_USER_ACCESS(
|
|
(LPTSTR)(LPCTSTR)m_strServer,
|
|
(LPTSTR)lpstrService,
|
|
&AceList
|
|
);
|
|
TRACEEOLID(_T("API Returned ") << err);
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The entry is now in sync with the database.
|
|
//
|
|
pAccessEntry->MarkEntryAsClean();
|
|
}
|
|
}
|
|
}
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
::DisplayMessage(err, MB_OK | MB_ICONHAND);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Mark page as clean
|
|
//
|
|
SetModified(FALSE);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
//
|
|
// All change messages map to this function
|
|
//
|
|
void
|
|
CPermissionsPage::OnItemChanged()
|
|
{
|
|
SetModified( TRUE );
|
|
}
|
|
|
|
//
|
|
// Bring up the Add Users and Groups dialogs from netui
|
|
//
|
|
void
|
|
CPermissionsPage::OnButtonAddPermService()
|
|
{
|
|
USERBROWSER ub;
|
|
CString strTitle;
|
|
DWORD err = ERROR_SUCCESS;
|
|
|
|
//
|
|
// The selection in the combo box always is
|
|
// the index of the rights array.
|
|
//
|
|
int nCurSel = m_combo_Rights.GetCurSel();
|
|
ASSERT(nCurSel >= 0 && nCurSel < NUM_RIGHTS);
|
|
int nService = rgServiceRights[nCurSel].nService;
|
|
ASSERT(nService >= 0 && nService < ACC_COUNT);
|
|
ACCESS_MASK accPermissions = rgServiceRights[nCurSel].accMask;
|
|
|
|
//
|
|
// Title for the dialog
|
|
//
|
|
VERIFY(strTitle.LoadString(IDS_ADD_SVC_PERM));
|
|
|
|
ub.ulStructSize = sizeof(ub);
|
|
ub.fUserCancelled = FALSE;
|
|
ub.fExpandNames = FALSE;
|
|
ub.hwndOwner = this->m_hWnd;
|
|
ub.pszTitle = (LPTSTR)(LPCTSTR)strTitle;
|
|
ub.pszInitialDomain = (LPTSTR)(LPCTSTR)m_strServer;
|
|
ub.Flags = USRBROWS_INCL_EVERYONE
|
|
| USRBROWS_SHOW_ALL;
|
|
ub.pszHelpFileName = (LPTSTR)(LPCTSTR)m_strHelpFile;
|
|
|
|
HUSERBROW hUserBrowser = ::OpenUserBrowser( &ub );
|
|
if (hUserBrowser == NULL)
|
|
{
|
|
err = ::GetLastError();
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
::DisplayMessage(err, MB_OK | MB_ICONHAND);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!ub.fUserCancelled)
|
|
{
|
|
//
|
|
// Selected users are granted the new privilege
|
|
//
|
|
TRY
|
|
{
|
|
//
|
|
// We break out of this loop ourselves
|
|
//
|
|
for ( ;; )
|
|
{
|
|
LPUSERDETAILS pusdtNewUser;
|
|
DWORD cbSize;
|
|
|
|
//
|
|
// First call should always fail, but tell
|
|
// us the size required.
|
|
//
|
|
cbSize = 0;
|
|
EnumUserBrowserSelection( hUserBrowser, NULL, &cbSize);
|
|
err = ::GetLastError();
|
|
if (err == ERROR_NO_MORE_ITEMS)
|
|
{
|
|
//
|
|
// All done
|
|
//
|
|
err = ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (err != ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
break;
|
|
}
|
|
|
|
err = ERROR_SUCCESS;
|
|
|
|
//
|
|
// The EnumUserBrowserSelection API has a bug in which
|
|
// the size returned might actually by insufficient.
|
|
//
|
|
cbSize += 100;
|
|
TRACEEOLID(_T("Enum structure size requested is ") << cbSize);
|
|
pusdtNewUser = (LPUSERDETAILS)new BYTE[cbSize];
|
|
if (pusdtNewUser == NULL)
|
|
{
|
|
err = ::GetLastError();
|
|
break;
|
|
}
|
|
|
|
|
|
if (!EnumUserBrowserSelection(hUserBrowser,pusdtNewUser,&cbSize))
|
|
{
|
|
err = ::GetLastError();
|
|
break;
|
|
}
|
|
|
|
TRACEEOLID(_T("Adding user ") << pusdtNewUser->pszAccountName);
|
|
AddUserPermissions(nService, pusdtNewUser, accPermissions);
|
|
|
|
delete [] pusdtNewUser;
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
CATCH_ALL(e)
|
|
{
|
|
TRACEEOLID(_T("Exception generated while enumerating users"));
|
|
err = ::GetLastError();
|
|
}
|
|
END_CATCH_ALL
|
|
}
|
|
|
|
if (err != ERROR_SUCCESS)
|
|
{
|
|
::DisplayMessage(err);
|
|
}
|
|
|
|
FillServiceListBox(nService, accPermissions);
|
|
OnItemChanged();
|
|
SetControlStates();
|
|
|
|
::CloseUserBrowser(hUserBrowser);
|
|
}
|
|
|
|
//
|
|
// The remove button has been pressed. Take
|
|
// away the currently selected right from
|
|
// the unit in question.
|
|
//
|
|
void
|
|
CPermissionsPage::OnButtonRemovePermService()
|
|
{
|
|
//
|
|
// The selection in the combo box always is
|
|
// the index of the rights array.
|
|
//
|
|
int nCurSel = m_combo_Rights.GetCurSel();
|
|
ASSERT(nCurSel >= 0 && nCurSel < NUM_RIGHTS);
|
|
int nService = rgServiceRights[nCurSel].nService;
|
|
ASSERT(nService >= 0 && nService < ACC_COUNT);
|
|
ACCESS_MASK accPermissions = rgServiceRights[nCurSel].accMask;
|
|
|
|
nCurSel = m_list_Services.GetCurSel();
|
|
CAccessEntry * pAccessEntry = m_list_Services.GetItem(nCurSel);
|
|
ASSERT(pAccessEntry != NULL);
|
|
pAccessEntry->RemovePermissions(accPermissions);
|
|
|
|
m_list_Services.DeleteString(nCurSel);
|
|
if (nCurSel)
|
|
{
|
|
--nCurSel;
|
|
}
|
|
m_list_Services.SetCurSel(nCurSel);
|
|
|
|
OnItemChanged();
|
|
SetControlStates();
|
|
}
|
|
|
|
//
|
|
// Respond to a change in the combo box selection,
|
|
// and display all the users in the listbox that
|
|
// match the criteria that fits the package of
|
|
// rights.
|
|
//
|
|
void
|
|
CPermissionsPage::OnSelchangeComboRights()
|
|
{
|
|
//
|
|
// The selection in the combo box indicates the
|
|
// index of global rights package array at the top
|
|
// of this file.
|
|
//
|
|
int nCurSel = m_combo_Rights.GetCurSel();
|
|
|
|
//
|
|
// It's impossible to have no selection in this combobox.
|
|
//
|
|
ASSERT(nCurSel >= 0 && nCurSel < NUM_RIGHTS);
|
|
ASSERT(rgServiceRights[nCurSel].nService >= 0
|
|
&& rgServiceRights[nCurSel].nService < ACC_COUNT);
|
|
|
|
//
|
|
// Display all entries in the listbox that fit the
|
|
// required criteria of the combo box selection.
|
|
//
|
|
FillServiceListBox(
|
|
rgServiceRights[nCurSel].nService,
|
|
rgServiceRights[nCurSel].accMask
|
|
);
|
|
|
|
SetControlStates();
|
|
}
|
|
|
|
void
|
|
CPermissionsPage::OnSelchangeListServicePermissions()
|
|
{
|
|
SetControlStates();
|
|
}
|