windows-nt/Source/XPSP1/NT/admin/netui/shellui/share/shareacl.cxx
2020-09-26 16:20:57 +08:00

712 lines
20 KiB
C++

/**********************************************************************/
/** Microsoft Windows/NT **/
/** Copyright(c) Microsoft Corp., 1991 **/
/**********************************************************************/
/*
ShareAcl.cxx
This file contains the implementation for the Shares Acl
Editor. It is just a front end for the Generic ACL Editor that is
specific to Shares,.
FILE HISTORY:
ChuckC 06-Aug-1992 Culled from NTFSACL.CXX
Yi-HsinS 09-Oct-1992 Added ulHelpContext to EditShareAcl
Yi-HsinS 20-Nov-1992 Make ntlanman.dll link dynamically to
acledit.dll ( not statically ).
DavidHov 17-Oct-1993 Made pSedDiscretionaryEditor extern "C"
because mangling on Alpha didn't
equate to that in LIBMAIN.CXX
*/
#include <ntincl.hxx>
extern "C"
{
#include <ntioapi.h>
#include <ntseapi.h>
#include <helpnums.h>
}
#define INCL_NETCONS
#define INCL_WINDOWS
#define INCL_NETERRORS
#define INCL_DOSERRORS
#define INCL_NETSHARE
#define _WINNETWK_
#include <lmui.hxx>
#undef _WINNETWK_
#define INCL_BLT_MSGPOPUP
#include <blt.hxx>
#include <dbgstr.hxx>
#include <string.hxx>
#include <strnumer.hxx>
#include <security.hxx>
#include <ntacutil.hxx>
#include <uibuffer.hxx>
#include <strlst.hxx>
#include <errmap.hxx>
extern "C"
{
#include <sedapi.h>
#include <sharedlg.h>
#include <lmapibuf.h>
}
#include <uiassert.hxx>
#include <shareacl.hxx>
typedef DWORD (*PSEDDISCRETIONARYACLEDITOR)( HWND, HANDLE, LPWSTR,
PSED_OBJECT_TYPE_DESCRIPTOR, PSED_APPLICATION_ACCESSES,
LPWSTR, PSED_FUNC_APPLY_SEC_CALLBACK, ULONG_PTR, PSECURITY_DESCRIPTOR,
BOOLEAN, BOOLEAN, LPDWORD, DWORD );
extern HMODULE hmodAclEditor;
extern "C"
{
// BUGBUG: This needs to be in a header file so mangling will
// work properly
extern PSEDDISCRETIONARYACLEDITOR pSedDiscretionaryAclEditor;
}
#define ACLEDIT_DLL_STRING SZ("acledit.dll")
#define SEDDISCRETIONARYACLEDITOR_STRING ("SedDiscretionaryAclEditor")
/*
* declare the callback routine based on typedef in sedapi.h.
* CODEWORK - that file should declare for us!
*/
DWORD SedCallback( HWND hwndParent,
HANDLE hInstance,
ULONG_PTR ulCallbackContext,
PSECURITY_DESCRIPTOR psecdesc,
PSECURITY_DESCRIPTOR psecdescNewObjects,
BOOLEAN fApplyToSubContainers,
BOOLEAN fApplyToSubObjects,
LPDWORD StatusReturn
) ;
/*
* structure for callback function's usage.
* all we do today during callback is set the
* Dacl to be passed back to the Shared dialog,
* and set a flag to tell us if the user actually
* did anything. The flag is FALSE as long as the
* user hits cancel.
*/
typedef struct _SHARE_CALLBACK_INFO
{
OS_SECURITY_DESCRIPTOR * pOsSecDesc ;
BOOL fSecDescModified ;
} SHARE_CALLBACK_INFO ;
/*
* routine that sets up the right generic mappings
*/
void InitializeShareGenericMapping( PGENERIC_MAPPING pSHAREGenericMapping ) ;
/* The following two arrays define the permission names for NT Files. Note
* that each index in one array corresponds to the index in the other array.
* The second array will be modifed to contain a string pointer pointing to
* the corresponding IDS_* in the first array.
*/
MSGID msgidSharePermNames[] =
{
IDS_SHARE_PERM_GEN_NO_ACCESS,
IDS_SHARE_PERM_GEN_READ,
IDS_SHARE_PERM_GEN_MODIFY,
IDS_SHARE_PERM_GEN_ALL
} ;
SED_APPLICATION_ACCESS sedappaccessSharePerms[] =
{
{ SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_NO_ACCESS, 0, NULL },
{ SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_READ, 0, NULL },
{ SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_MODIFY, 0, NULL },
{ SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_ALL, 0, NULL }
} ;
#define COUNT_FILEPERMS_ARRAY (sizeof(sedappaccessSharePerms)/sizeof(SED_APPLICATION_ACCESS))
/*******************************************************************
NAME: EditShareAcl
SYNOPSIS: This Procedure prepares the structures necessary for the
generic ACL editor, specifically for NT Shares.
ENTRY: hwndParent - Parent window handle
pszServer - Name of server the resource resides on
(in the form "\\server")
pszResource - Fully qualified name of resource we will
edit, basically a share name.
pfSecDescModified - used to return to share dialog if
the User cancelled or hit OK.
ppOsSEcDesc - pointer to pointer to OS_SECURITY_DESCRIPTOR.
*ppOsSecDesc is NULL if this is a new share or a share
without any security descriptor, in which case we create
one.
EXIT:
RETURNS:
NOTES: We assume we are dealing with a SHARE by the time
this function is called.
HISTORY:
ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code.
Yi-HsinS 09-Oct-1992 Added ulHelpContextBase
********************************************************************/
APIERR EditShareAcl( HWND hwndParent,
const TCHAR * pszServer,
const TCHAR * pszResource,
BOOL * pfSecDescModified,
OS_SECURITY_DESCRIPTOR ** ppOsSecDesc,
ULONG ulHelpContextBase )
{
UIASSERT(pszServer) ;
UIASSERT(pszResource) ;
UIASSERT(ppOsSecDesc) ;
UIASSERT(pfSecDescModified) ;
APIERR err = NERR_Success; // JonN 01/27/00: PREFIX bug 444914
do { // error breakout
/*
* if we *ppsecdesc is NULL, this is new share or a share with no
* security descriptor.
* we go and create a new (default) security descriptor.
*/
if (!*ppOsSecDesc)
{
APIERR err = ::CreateDefaultAcl(ppOsSecDesc) ;
if (err != NERR_Success)
break ;
}
/* Retrieve the resource strings appropriate for the type of object we
* are looking at
*/
RESOURCE_STR nlsTypeName( IDS_SHARE ) ;
RESOURCE_STR nlsDefaultPermName( IDS_SHARE_PERM_GEN_READ ) ;
if ( ( err = nlsTypeName.QueryError() ) ||
( err = nlsDefaultPermName.QueryError()) )
{
break ;
}
/*
* other misc stuff we need pass to security editor
*/
SED_OBJECT_TYPE_DESCRIPTOR sedobjdesc ;
SED_HELP_INFO sedhelpinfo ;
GENERIC_MAPPING SHAREGenericMapping ;
// setup mappings
InitializeShareGenericMapping( &SHAREGenericMapping ) ;
// setup help
RESOURCE_STR nlsHelpFileName( ulHelpContextBase == HC_UI_SHELL_BASE
? IDS_SHELLHELPFILENAME
: IDS_SMHELPFILENAME ) ;
if ( err = nlsHelpFileName.QueryError() )
{
DBGEOL("::EditShareAcl - Failed to retrieve help file name") ;
break ;
}
sedhelpinfo.pszHelpFileName = (LPWSTR) nlsHelpFileName.QueryPch() ;
sedhelpinfo.aulHelpContext[HC_MAIN_DLG] = ulHelpContextBase +
HC_NTSHAREPERMS ;
sedhelpinfo.aulHelpContext[HC_ADD_USER_DLG] = ulHelpContextBase +
HC_SHAREADDUSER ;
sedhelpinfo.aulHelpContext[HC_ADD_USER_MEMBERS_LG_DLG] =
ulHelpContextBase +
HC_SHAREADDUSER_LOCALGROUP ;
sedhelpinfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] =
ulHelpContextBase +
HC_SHAREADDUSER_GLOBALGROUP ;
sedhelpinfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] =
ulHelpContextBase +
HC_SHAREADDUSER_FINDUSER ;
// These are not used, set to zero
sedhelpinfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] = 0 ;
sedhelpinfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] = 0 ;
// setup the object description
sedobjdesc.Revision = SED_REVISION1 ;
sedobjdesc.IsContainer = FALSE ;
sedobjdesc.AllowNewObjectPerms = FALSE ;
sedobjdesc.MapSpecificPermsToGeneric = TRUE ;
sedobjdesc.GenericMapping = &SHAREGenericMapping ;
sedobjdesc.GenericMappingNewObjects = &SHAREGenericMapping ;
sedobjdesc.HelpInfo = &sedhelpinfo ;
sedobjdesc.ObjectTypeName = (LPTSTR)nlsTypeName.QueryPch();
sedobjdesc.SpecialObjectAccessTitle = NULL ;
/* Now we need to load the global arrays with the permission names
* from the resource file.
*/
UINT cArrayItems = COUNT_FILEPERMS_ARRAY ;
MSGID * msgidPermNames = msgidSharePermNames ;
PSED_APPLICATION_ACCESS pappaccess = sedappaccessSharePerms ;
/* Loop through each permission title retrieving the text from the
* resource file and setting the pointer in the array. The memory
* will be deleted when strlistPermNames is destructed.
*/
STRLIST strlistPermNames ;
for ( UINT i = 0 ; i < cArrayItems ; i++ )
{
RESOURCE_STR * pnlsPermName = new RESOURCE_STR( msgidPermNames[i]) ;
err = (pnlsPermName==NULL) ? ERROR_NOT_ENOUGH_MEMORY :
pnlsPermName->QueryError() ;
if ( err ||
(err = strlistPermNames.Add( pnlsPermName )) )
{
delete pnlsPermName ;
break ;
}
pappaccess[i].PermissionTitle = (LPTSTR) pnlsPermName->QueryPch() ;
}
if ( err )
break ;
SED_APPLICATION_ACCESSES SedAppAccesses ;
SedAppAccesses.Count = cArrayItems ;
SedAppAccesses.AccessGroup = pappaccess ;
SedAppAccesses.DefaultPermName = (LPTSTR)nlsDefaultPermName.QueryPch() ;
DWORD dwSedReturnStatus ;
/*
* pass this along so when the call back function is called,
* we can set it.
*/
SHARE_CALLBACK_INFO callbackinfo ;
callbackinfo.pOsSecDesc = *ppOsSecDesc ;
callbackinfo.fSecDescModified = FALSE ;
if ( ::hmodAclEditor == NULL )
{
::hmodAclEditor = ::LoadLibraryEx( ACLEDIT_DLL_STRING,
NULL,
LOAD_WITH_ALTERED_SEARCH_PATH );
if ( ::hmodAclEditor == NULL )
{
err = ::GetLastError();
break;
}
::pSedDiscretionaryAclEditor = (PSEDDISCRETIONARYACLEDITOR)
::GetProcAddress( ::hmodAclEditor,
SEDDISCRETIONARYACLEDITOR_STRING );
if ( ::pSedDiscretionaryAclEditor == NULL )
{
err = ::GetLastError();
break;
}
}
UIASSERT( ::pSedDiscretionaryAclEditor != NULL );
err = (*pSedDiscretionaryAclEditor)( hwndParent,
NULL, // dont need instance
(LPWSTR) pszServer,
&sedobjdesc,
&SedAppAccesses,
(LPWSTR) pszResource,
(PSED_FUNC_APPLY_SEC_CALLBACK) SedCallback,
(ULONG_PTR) &callbackinfo,
(*ppOsSecDesc)->QueryDescriptor(),
FALSE, // always can read
FALSE, // If we can read, we can write
&dwSedReturnStatus,
0 ) ;
if (err)
break ;
*pfSecDescModified = callbackinfo.fSecDescModified ;
} while (FALSE) ;
return err ;
}
/*******************************************************************
NAME: SedCallback
SYNOPSIS: Security Editor callback for the SHARE ACL Editor
ENTRY: See sedapi.hxx
EXIT:
RETURNS:
NOTES: Normally, the callback is expected to perform the 'apply'.
In this case, since the object may not exist yet, we defer
the 'apply' till the user hits OK in the Shares dialog.
All the CallBack does is simply save away that precious
modified ACL in the OS_SECURITY_DESCRIPTOR object we were
given in the first place.
HISTORY:
ChuckC 10-Aug-1992 Created
********************************************************************/
DWORD SedCallback( HWND hwndParent,
HANDLE hInstance,
ULONG_PTR ulCallbackContext,
PSECURITY_DESCRIPTOR psecdesc,
PSECURITY_DESCRIPTOR psecdescNewObjects,
BOOLEAN fApplyToSubContainers,
BOOLEAN fApplyToSubObjects,
LPDWORD StatusReturn
)
{
UNREFERENCED( hInstance ) ;
UNREFERENCED( psecdescNewObjects ) ;
UNREFERENCED( fApplyToSubObjects ) ;
UNREFERENCED( fApplyToSubContainers ) ;
UNREFERENCED( StatusReturn ) ;
APIERR err = NO_ERROR ;
OS_SECURITY_DESCRIPTOR * pOsSecDesc =
((SHARE_CALLBACK_INFO *)ulCallbackContext)->pOsSecDesc ;
do { // error breakout loop
OS_SECURITY_DESCRIPTOR osNewSecDesc (psecdesc) ;
if (err = osNewSecDesc.QueryError())
break ;
BOOL fDaclPresent ;
OS_ACL * pOsDacl ;
if (err = osNewSecDesc.QueryDACL(&fDaclPresent, &pOsDacl))
break ;
// set the new DACL
err = pOsSecDesc->SetDACL(TRUE, pOsDacl) ;
} while (FALSE) ;
if ( err )
::MsgPopup( hwndParent, (MSGID) err ) ;
else
((SHARE_CALLBACK_INFO *)ulCallbackContext)->fSecDescModified = TRUE ;
return err ;
}
/*******************************************************************
NAME: InitializeShareGenericMapping
SYNOPSIS: Initializes the passed generic mapping structure
for shares
ENTRY: pSHAREGenericMapping - Pointer to GENERIC_MAPPING to be init.
EXIT:
RETURNS:
NOTES: There currently is no public definition, replace if one
ever becomes available.
HISTORY:
ChuckC 10-Aug-1992 Created
********************************************************************/
void InitializeShareGenericMapping( PGENERIC_MAPPING pSHAREGenericMapping )
{
pSHAREGenericMapping->GenericRead = FILE_GENERIC_READ ;
pSHAREGenericMapping->GenericWrite = FILE_GENERIC_WRITE ;
pSHAREGenericMapping->GenericExecute = FILE_GENERIC_EXECUTE ;
pSHAREGenericMapping->GenericAll = FILE_ALL_ACCESS ;
}
/*******************************************************************
NAME: CreateDefaultAcl
SYNOPSIS: Create a default ACL for either a new share or for
a share that dont exist.
ENTRY:
EXIT:
RETURNS: NERR_Success if OK, api error otherwise.
NOTES:
HISTORY:
ChuckC 10-Aug-1992 Created
********************************************************************/
APIERR CreateDefaultAcl( OS_SECURITY_DESCRIPTOR ** ppOsSecDesc )
{
UIASSERT(ppOsSecDesc) ;
APIERR err ;
OS_ACL aclDacl ;
OS_ACE osace ;
OS_SECURITY_DESCRIPTOR * pOsSecDesc ;
*ppOsSecDesc = NULL ; // empty it.
do
{ // error breakout
/*
* make sure we constructed OK
*/
if ( (err = aclDacl.QueryError()) ||
(err = osace.QueryError()) )
{
break ;
}
/*
* create it! use NULL to mean we build it ourselves.
*/
pOsSecDesc = new OS_SECURITY_DESCRIPTOR(NULL) ;
if (pOsSecDesc == NULL)
{
err = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
if (err = pOsSecDesc->QueryError())
{
break ;
}
/*
* This sets up an ACE with Generic all access
*/
osace.SetAccessMask( GENERIC_ALL ) ;
osace.SetInheritFlags( 0 ) ;
osace.SetType( ACCESS_ALLOWED_ACE_TYPE ) ;
#if 0
//
// The server should set the owner/group before we get the security
// descriptor so we don't need to do this anymore
//
/*
* now set the group and owner to be the Administrators.
* need create Adminstrators SID.
*/
OS_SID ossidBuiltin ;
if (err = NT_ACCOUNTS_UTILITY::QuerySystemSid( UI_SID_BuiltIn,
&ossidBuiltin ))
{
break ;
}
OS_SID ossidAdmin (ossidBuiltin.QueryPSID(),
(ULONG)DOMAIN_ALIAS_RID_ADMINS) ;
if (err = ossidAdmin.QueryError())
break ;
if ( (err = pOsSecDesc->SetGroup( ossidAdmin, TRUE )) ||
(err = pOsSecDesc->SetOwner( ossidAdmin, TRUE )) )
{
break ;
}
#endif
/*
* create a world SID, and add this to the full access ACE.
* then put the ACE in the ACL, and the ACL in the Security
* descriptor.
*/
OS_SID ossidWorld ;
if ( (err = ossidWorld.QueryError()) ||
(err = NT_ACCOUNTS_UTILITY::QuerySystemSid(
UI_SID_World,
&ossidWorld )) ||
(err = osace.SetSID( ossidWorld )) ||
(err = aclDacl.AddACE( 0, osace )) ||
(err = pOsSecDesc->SetDACL( TRUE, &aclDacl )) )
{
break ;
}
/*
* all set, set the security descriptor
*/
*ppOsSecDesc = pOsSecDesc ;
} while (FALSE) ;
return err ;
}
/*******************************************************************
NAME: GetSharePerm
SYNOPSIS: CAll the NETAPI to retrieve existing Security Descriptor
from the Share.
ENTRY:
EXIT:
RETURNS: NERR_Success if OK, api error otherwise.
NOTES: CODEWORK. This should be a LMOBJ thing when we have time.
Currently just direct call to NETAPI.
HISTORY:
ChuckC 10-Aug-1992 Created
********************************************************************/
APIERR GetSharePerm (const TCHAR * pszServer,
const TCHAR * pszShare,
OS_SECURITY_DESCRIPTOR ** ppOsSecDesc )
{
#ifndef WIN32
#error This is currently NOT 16 bit compatible.
#endif
APIERR err ;
LPBYTE pBuffer ;
PSECURITY_DESCRIPTOR psecdesc ;
OS_SECURITY_DESCRIPTOR * pOsSecDesc ;
/*
* call API to get the security descriptor
*/
err = NetShareGetInfo((LPTSTR) pszServer,
(LPTSTR) pszShare,
502,
&pBuffer) ;
if (err != NERR_Success)
return err ;
if (*ppOsSecDesc)
delete *ppOsSecDesc ;
*ppOsSecDesc = NULL ;
/*
* if no such thang, just say none. we'll create later as need.
*/
psecdesc = ((SHARE_INFO_502 *)pBuffer)->shi502_security_descriptor ;
if (!psecdesc)
{
NetApiBufferFree(pBuffer) ;
return NERR_Success ;
}
do { // error break out loop
// create a new security descriptor
pOsSecDesc = new OS_SECURITY_DESCRIPTOR(NULL) ;
if (pOsSecDesc == NULL)
{
err = ERROR_NOT_ENOUGH_MEMORY ;
break ;
}
if (err = pOsSecDesc->QueryError())
{
break ;
}
/*
* create alias to the security descriptor we go from the API
*/
OS_SECURITY_DESCRIPTOR osShareSecDesc (psecdesc) ;
if (err = osShareSecDesc.QueryError())
break ;
/*
* make copy of it for use by security editor
*/
if ( (err = pOsSecDesc->Copy( osShareSecDesc )) )
{
break ;
}
} while (FALSE) ;
if (err == NERR_Success)
*ppOsSecDesc = pOsSecDesc ;
NetApiBufferFree(pBuffer) ;
return err ;
}
/*******************************************************************
NAME: SetSharePerm
SYNOPSIS: CAll the NETAPI to set the Security Descriptor
for the Share.
ENTRY:
EXIT:
RETURNS: NERR_Success if OK, api error otherwise.
NOTES: CODEWORK. This should be a LMOBJ thing when we have time.
Currently just direct call to NETAPI.
HISTORY:
ChuckC 10-Aug-1992 Created
********************************************************************/
APIERR SetSharePerm (const TCHAR * pszServer,
const TCHAR * pszShare,
const OS_SECURITY_DESCRIPTOR * pOsSecDesc )
{
#ifndef WIN32
#error This is currently NOT 16 bit compatible.
#endif
APIERR err ;
SHARE_INFO_1501 shareinfo1501 ;
::ZeroMemory(&shareinfo1501,
sizeof(shareinfo1501)); // JonN 01/27/00: PREFIX bug 444913
shareinfo1501.shi1501_security_descriptor =
pOsSecDesc->QueryDescriptor() ;
/*
* call API to get the security descriptor
*/
err = NetShareSetInfo((LPTSTR) pszServer,
(LPTSTR) pszShare,
1501,
(LPBYTE)&shareinfo1501,
NULL) ;
return err ;
}