Windows NT 4.0 source code leak
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

//
// 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();
}