2093 lines
73 KiB
C++
2093 lines
73 KiB
C++
/**********************************************************************/
|
|
/** Microsoft Windows/NT **/
|
|
/** Copyright(c) Microsoft Corp., 1991 **/
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
|
|
NTFSAcl.cxx
|
|
|
|
This file contains the implementation for the NT File System ACL
|
|
Editor. It is just a front end for the Generic ACL Editor that is
|
|
specific to the NTFS.
|
|
|
|
FILE HISTORY:
|
|
Johnl 30-Dec-1991 Created
|
|
|
|
*/
|
|
|
|
#include <ntincl.hxx>
|
|
extern "C"
|
|
{
|
|
#include <ntioapi.h>
|
|
#include <ntseapi.h>
|
|
}
|
|
|
|
#include <ntmasks.hxx>
|
|
|
|
#define INCL_NETCONS
|
|
#define INCL_NETLIB
|
|
#define INCL_WINDOWS
|
|
#define INCL_NETERRORS
|
|
#define INCL_DOSERRORS
|
|
#define INCL_NETACCESS // For NET_ACCESS_1 reference
|
|
#define INCL_NETUSE
|
|
#include <lmui.hxx>
|
|
|
|
#define INCL_BLT_CONTROL
|
|
#define INCL_BLT_DIALOG
|
|
#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 <fsenum.hxx>
|
|
#include <errmap.hxx>
|
|
|
|
#include <lmodev.hxx>
|
|
#include <lmoacces.hxx>
|
|
|
|
|
|
extern "C"
|
|
{
|
|
#include <netlib.h> // For NetpGetPrivilege
|
|
#include <mpr.h>
|
|
#include <npapi.h>
|
|
}
|
|
#include <wfext.h>
|
|
#include <fmx.hxx>
|
|
|
|
extern "C"
|
|
{
|
|
#include <sedapi.h>
|
|
#include <helpnums.h>
|
|
}
|
|
|
|
|
|
#include <cncltask.hxx>
|
|
#include <uiassert.hxx>
|
|
#include <ipermapi.hxx>
|
|
#include <permprg.hxx>
|
|
#include <permstr.hxx>
|
|
#include <ntfsacl.hxx>
|
|
|
|
DWORD SedCallback( HWND hwndParent,
|
|
HANDLE hInstance,
|
|
ULONG_PTR ulCallbackContext,
|
|
PSECURITY_DESCRIPTOR psecdesc,
|
|
PSECURITY_DESCRIPTOR psecdescNewObjects,
|
|
BOOLEAN fApplyToSubContainers,
|
|
BOOLEAN fApplyToSubObjects,
|
|
LPDWORD StatusReturn
|
|
) ;
|
|
|
|
|
|
typedef struct _NTFS_CALLBACK_INFO
|
|
{
|
|
HWND hwndFMXOwner ;
|
|
enum SED_PERM_TYPE sedpermtype ;
|
|
} NTFS_CALLBACK_INFO ;
|
|
|
|
void InitializeNTFSGenericMapping( PGENERIC_MAPPING pNTFSGenericMapping,
|
|
BOOL fIsDirectory ) ;
|
|
|
|
APIERR GetSecurity( const TCHAR * pszFileName,
|
|
BUFFER * pbuffSecDescData,
|
|
enum SED_PERM_TYPE sedpermtype,
|
|
BOOL * pfAuditPrivAdjusted ) ;
|
|
|
|
APIERR CompareNTFSSecurityIntersection( HWND hwndFMX,
|
|
enum SED_PERM_TYPE sedpermtype,
|
|
PSECURITY_DESCRIPTOR psecdesc,
|
|
BOOL * pfOwnerEqual,
|
|
BOOL * pfACLEqual,
|
|
NLS_STR * pnlsFailingFile,
|
|
PGENERIC_MAPPING pGenericMapping,
|
|
PGENERIC_MAPPING pGenericMappingObjects,
|
|
BOOL fMapGenAll,
|
|
BOOL fIsContainer ) ;
|
|
|
|
/* 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 msgidFilePermNames[] =
|
|
{
|
|
IDS_FILE_PERM_SPEC_READ,
|
|
IDS_FILE_PERM_SPEC_WRITE,
|
|
IDS_FILE_PERM_SPEC_EXECUTE,
|
|
|
|
IDS_FILE_PERM_SPEC_DELETE,
|
|
IDS_FILE_PERM_SPEC_CHANGE_PERM,
|
|
IDS_FILE_PERM_SPEC_CHANGE_OWNER,
|
|
|
|
IDS_FILE_PERM_GEN_NO_ACCESS,
|
|
IDS_FILE_PERM_GEN_READ,
|
|
IDS_FILE_PERM_GEN_MODIFY,
|
|
IDS_FILE_PERM_GEN_ALL
|
|
} ;
|
|
|
|
SED_APPLICATION_ACCESS sedappaccessFilePerms[] =
|
|
{
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, FILE_PERM_SPEC_READ, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, FILE_PERM_SPEC_WRITE, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, FILE_PERM_SPEC_EXECUTE, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, FILE_PERM_SPEC_DELETE, 0, NULL },
|
|
//{ SED_DESC_TYPE_RESOURCE_SPECIAL, FILE_PERM_SPEC_READ_PERM, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, FILE_PERM_SPEC_CHANGE_PERM, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, FILE_PERM_SPEC_CHANGE_OWNER, 0, NULL },
|
|
|
|
{ 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(sedappaccessFilePerms)/sizeof(SED_APPLICATION_ACCESS))
|
|
|
|
/* The following two arrays define the permission names for NT directories. 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 msgidDirPermNames[] =
|
|
{
|
|
IDS_DIR_PERM_SPEC_READ,
|
|
IDS_DIR_PERM_SPEC_WRITE,
|
|
IDS_DIR_PERM_SPEC_EXECUTE,
|
|
IDS_DIR_PERM_SPEC_DELETE,
|
|
IDS_DIR_PERM_SPEC_CHANGE_PERM,
|
|
IDS_DIR_PERM_SPEC_CHANGE_OWNER,
|
|
|
|
IDS_DIR_PERM_GEN_NO_ACCESS,
|
|
IDS_DIR_PERM_GEN_LIST,
|
|
IDS_DIR_PERM_GEN_READ,
|
|
IDS_DIR_PERM_GEN_DEPOSIT,
|
|
IDS_DIR_PERM_GEN_PUBLISH,
|
|
IDS_DIR_PERM_GEN_MODIFY,
|
|
IDS_DIR_PERM_GEN_ALL,
|
|
|
|
IDS_NEWFILE_PERM_SPEC_READ,
|
|
IDS_NEWFILE_PERM_SPEC_WRITE,
|
|
IDS_NEWFILE_PERM_SPEC_EXECUTE,
|
|
IDS_NEWFILE_PERM_SPEC_DELETE,
|
|
IDS_NEWFILE_PERM_SPEC_CHANGE_PERM,
|
|
IDS_NEWFILE_PERM_SPEC_CHANGE_OWNER
|
|
} ;
|
|
|
|
SED_APPLICATION_ACCESS sedappaccessDirPerms[] =
|
|
{
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, DIR_PERM_SPEC_READ, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, DIR_PERM_SPEC_WRITE, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, DIR_PERM_SPEC_EXECUTE, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, DIR_PERM_SPEC_DELETE, 0, NULL },
|
|
//{ SED_DESC_TYPE_RESOURCE_SPECIAL, DIR_PERM_SPEC_READ_PERM, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, DIR_PERM_SPEC_CHANGE_PERM, 0, NULL },
|
|
{ SED_DESC_TYPE_RESOURCE_SPECIAL, DIR_PERM_SPEC_CHANGE_OWNER,0, NULL },
|
|
|
|
{ SED_DESC_TYPE_CONT_AND_NEW_OBJECT, DIR_PERM_GEN_NO_ACCESS,NEWFILE_PERM_GEN_NO_ACCESS, NULL },
|
|
{ SED_DESC_TYPE_CONT_AND_NEW_OBJECT, DIR_PERM_GEN_LIST, NEWFILE_PERM_GEN_LIST, NULL },
|
|
{ SED_DESC_TYPE_CONT_AND_NEW_OBJECT, DIR_PERM_GEN_READ, NEWFILE_PERM_GEN_READ, NULL },
|
|
{ SED_DESC_TYPE_CONT_AND_NEW_OBJECT, DIR_PERM_GEN_DEPOSIT, NEWFILE_PERM_GEN_DEPOSIT, NULL },
|
|
{ SED_DESC_TYPE_CONT_AND_NEW_OBJECT, DIR_PERM_GEN_PUBLISH, NEWFILE_PERM_GEN_PUBLISH, NULL },
|
|
{ SED_DESC_TYPE_CONT_AND_NEW_OBJECT, DIR_PERM_GEN_MODIFY, NEWFILE_PERM_GEN_MODIFY, NULL },
|
|
{ SED_DESC_TYPE_CONT_AND_NEW_OBJECT, DIR_PERM_GEN_ALL, NEWFILE_PERM_GEN_ALL, NULL },
|
|
|
|
{ SED_DESC_TYPE_NEW_OBJECT_SPECIAL, NEWFILE_PERM_SPEC_READ, 0, NULL },
|
|
{ SED_DESC_TYPE_NEW_OBJECT_SPECIAL, NEWFILE_PERM_SPEC_WRITE, 0, NULL },
|
|
{ SED_DESC_TYPE_NEW_OBJECT_SPECIAL, NEWFILE_PERM_SPEC_EXECUTE, 0, NULL },
|
|
{ SED_DESC_TYPE_NEW_OBJECT_SPECIAL, NEWFILE_PERM_SPEC_DELETE, 0, NULL },
|
|
{ SED_DESC_TYPE_NEW_OBJECT_SPECIAL, NEWFILE_PERM_SPEC_CHANGE_PERM, 0, NULL },
|
|
{ SED_DESC_TYPE_NEW_OBJECT_SPECIAL, NEWFILE_PERM_SPEC_CHANGE_OWNER, 0, NULL }
|
|
} ;
|
|
|
|
#define COUNT_DIRPERMS_ARRAY (sizeof(sedappaccessDirPerms)/sizeof(SED_APPLICATION_ACCESS))
|
|
|
|
/* The following two arrays define the auditting names for NT directories and
|
|
* directories.
|
|
*/
|
|
MSGID msgidFileAuditNames[] =
|
|
{
|
|
IDS_FILE_AUDIT_READ,
|
|
IDS_FILE_AUDIT_WRITE,
|
|
IDS_FILE_AUDIT_EXECUTE,
|
|
IDS_FILE_AUDIT_DELETE,
|
|
IDS_FILE_AUDIT_CHANGE_PERM,
|
|
IDS_FILE_AUDIT_CHANGE_OWNER
|
|
} ;
|
|
|
|
SED_APPLICATION_ACCESS sedappaccessFileAudits[] =
|
|
{
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_READ, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_WRITE, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_EXECUTE, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_DELETE, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_CHANGE_PERM, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_CHANGE_OWNER,0, NULL }
|
|
} ;
|
|
|
|
#define COUNT_FILE_AUDITPERMS_ARRAY (sizeof(sedappaccessFileAudits)/sizeof(SED_APPLICATION_ACCESS))
|
|
|
|
|
|
/* The following two arrays define the auditting names for NT directories and
|
|
* directories.
|
|
*/
|
|
MSGID msgidDirAuditNames[] =
|
|
{
|
|
IDS_DIR_AUDIT_READ,
|
|
IDS_DIR_AUDIT_WRITE,
|
|
IDS_DIR_AUDIT_EXECUTE,
|
|
IDS_DIR_AUDIT_DELETE,
|
|
IDS_DIR_AUDIT_CHANGE_PERM,
|
|
IDS_DIR_AUDIT_CHANGE_OWNER
|
|
} ;
|
|
|
|
SED_APPLICATION_ACCESS sedappaccessDirAudits[] =
|
|
{
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_READ, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_WRITE, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_EXECUTE, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_DELETE, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_CHANGE_PERM, 0, NULL },
|
|
{ SED_DESC_TYPE_AUDIT, FILE_AUDIT_CHANGE_OWNER,0, NULL }
|
|
} ;
|
|
|
|
#define COUNT_DIR_AUDITPERMS_ARRAY (sizeof(sedappaccessDirAudits)/sizeof(SED_APPLICATION_ACCESS))
|
|
|
|
|
|
extern HINSTANCE hModule; // Exported from libmain
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: EditNTFSAcl
|
|
|
|
SYNOPSIS: This Procedure prepares the structures necessary for the
|
|
generic ACL editor, specifically for NT FS (FileSystem)
|
|
ACLs.
|
|
|
|
ENTRY: hwndParent - Parent window handle, this should be the
|
|
FMX Window handle
|
|
pszServer - Name of server the resource resides on
|
|
(in the form "\\server")
|
|
pszResource - Fully qualified name of resource we will
|
|
edit (suitable for passing to GetFileSecurity)
|
|
sedpermtype - either SED_ACCESSES or SED_AUDITS
|
|
fIsFile - TRUE if the resource is a file, FALSE if the
|
|
resource is a directory
|
|
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES: We assume we are dealing with an NTFS volume by the time
|
|
this function is called.
|
|
|
|
HISTORY:
|
|
Johnl 25-Dec-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
APIERR EditNTFSAcl( HWND hwndParent,
|
|
const TCHAR * pszServer,
|
|
const TCHAR * pszResource,
|
|
enum SED_PERM_TYPE sedpermtype,
|
|
BOOL fIsFile )
|
|
{
|
|
APIERR err ;
|
|
BUFFER buffSecDescData( 1024 ) ;
|
|
BOOL fCantRead = FALSE ; // Did we read the Owner?
|
|
BOOL fCantWrite = FALSE ; // Is it read only?
|
|
BOOL fPrivAdjusted = FALSE ; // Do we need to restore our token?
|
|
BOOL fCheckSecurity= TRUE ; // Check security unless bad intersection
|
|
const TCHAR * pszSecCheckFile = pszResource ;
|
|
|
|
do { // error breakout
|
|
|
|
PSECURITY_DESCRIPTOR pSecurityDesc = NULL ;
|
|
|
|
switch ( err = ::GetSecurity( pszResource,
|
|
&buffSecDescData,
|
|
sedpermtype,
|
|
&fPrivAdjusted ) )
|
|
{
|
|
case ERROR_ACCESS_DENIED:
|
|
fCantRead = TRUE ;
|
|
|
|
//
|
|
// If they can't read the SACL then they don't have the privilege
|
|
//
|
|
if ( sedpermtype == SED_AUDITS )
|
|
{
|
|
err = ERROR_PRIVILEGE_NOT_HELD ;
|
|
break ;
|
|
}
|
|
|
|
err = NERR_Success ;
|
|
break ;
|
|
|
|
case NO_ERROR:
|
|
pSecurityDesc = (PSECURITY_DESCRIPTOR) buffSecDescData.QueryPtr() ;
|
|
break ;
|
|
|
|
default:
|
|
break ;
|
|
}
|
|
if ( err )
|
|
break ;
|
|
|
|
GENERIC_MAPPING NTFSGenericMapping ;
|
|
InitializeNTFSGenericMapping( &NTFSGenericMapping, !fIsFile ) ;
|
|
|
|
FMX fmx( hwndParent ) ;
|
|
BOOL fIsMultiSelect = fmx.QuerySelCount() > 1 ;
|
|
|
|
//
|
|
// We may need to substitute our own security descriptor here
|
|
// depending on the intersection of security descriptors because
|
|
// we can't set a NULL owner on a self relative security descriptor
|
|
// (which we will most likely get).
|
|
//
|
|
OS_SECURITY_DESCRIPTOR ossecdesc( fIsMultiSelect ?
|
|
pSecurityDesc : NULL, TRUE ) ;
|
|
OS_ACL osacl( NULL ) ;
|
|
DEC_STR nlsSelectCount( fmx.QuerySelCount() ) ;
|
|
if ( fIsMultiSelect )
|
|
{
|
|
BOOL fOwnerEqual = FALSE, fACLEqual = FALSE ;
|
|
NLS_STR nlsFailingFile ;
|
|
MSGID idsPromptToContinue = IDS_BAD_INTERSECTION ;
|
|
if ( fCantRead ||
|
|
(err = ossecdesc.QueryError()) ||
|
|
(err = nlsSelectCount.QueryError()) ||
|
|
(err = CompareNTFSSecurityIntersection( hwndParent,
|
|
sedpermtype,
|
|
pSecurityDesc,
|
|
&fOwnerEqual,
|
|
&fACLEqual,
|
|
&nlsFailingFile,
|
|
&NTFSGenericMapping,
|
|
&NTFSGenericMapping,
|
|
TRUE,
|
|
!fIsFile )) )
|
|
{
|
|
//
|
|
// If we didn't have access to read one of the security
|
|
// descriptors, then give the user the option of continuing
|
|
//
|
|
if ( fCantRead || err == ERROR_ACCESS_DENIED )
|
|
{
|
|
pszResource = fCantRead ? pszResource :
|
|
nlsFailingFile.QueryPch() ;
|
|
idsPromptToContinue = IERR_MULTI_SELECT_AND_CANT_READ ;
|
|
fCantRead = TRUE ;
|
|
err = NERR_Success ;
|
|
}
|
|
else
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Substitute the blank security descriptor only if we need to
|
|
//
|
|
if ( !fACLEqual || !fOwnerEqual || fCantRead )
|
|
{
|
|
pSecurityDesc = ossecdesc.QueryDescriptor() ;
|
|
}
|
|
|
|
if ( !fACLEqual || fCantRead )
|
|
{
|
|
switch ( ::MsgPopup( hwndParent,
|
|
(MSGID) idsPromptToContinue,
|
|
MPSEV_WARNING,
|
|
MP_YESNO,
|
|
pszResource,
|
|
nlsFailingFile,
|
|
MP_YES ))
|
|
{
|
|
case IDYES:
|
|
{
|
|
if ( (err = ossecdesc.SetDACL( TRUE, &osacl )) ||
|
|
(err = ossecdesc.SetSACL( TRUE, &osacl )) ||
|
|
(err = ossecdesc.SetOwner( FALSE, NULL, 0 )) ||
|
|
(err = ossecdesc.SetGroup( FALSE, NULL, 0 )) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
//
|
|
// We've just made the ACL equal. Note that we don't
|
|
// check the security if the ACLs aren't equal (some
|
|
// may allow access, others may not).
|
|
//
|
|
fACLEqual = TRUE ;
|
|
fCantRead = FALSE ;
|
|
fCheckSecurity = FALSE ;
|
|
}
|
|
break ;
|
|
|
|
case IDNO:
|
|
default:
|
|
break ;
|
|
}
|
|
}
|
|
if ( err || !fACLEqual || fCantRead )
|
|
break ;
|
|
|
|
if ( !fOwnerEqual &&
|
|
(err = ossecdesc.SetOwner( FALSE, NULL, 0 )) )
|
|
{
|
|
break ;
|
|
}
|
|
} // if IsMultiSelect
|
|
|
|
|
|
/* Retrieve the resource strings appropriate for the type of object we
|
|
* are looking at
|
|
*/
|
|
|
|
MSGID msgidTypeName = fIsFile ? IDS_FILE : IDS_DIRECTORY ;
|
|
MSGID msgidApplySubCont = sedpermtype == SED_ACCESSES ?
|
|
IDS_NT_ASSIGN_PERM_TITLE:
|
|
IDS_NT_ASSIGN_AUDITS_TITLE ;
|
|
MSGID msgidApplySubObj =sedpermtype == SED_ACCESSES ?
|
|
IDS_NT_ASSIGN_FILE_PERM_TITLE :
|
|
IDS_NT_ASSIGN_FILE_AUDITS_TITLE ;
|
|
|
|
RESOURCE_STR nlsTypeName( msgidTypeName ) ;
|
|
RESOURCE_STR nlsSpecial( fIsFile ? IDS_NT_FILE_SPECIAL_ACCESS :
|
|
IDS_NT_DIR_SPECIAL_ACCESS ) ;
|
|
RESOURCE_STR nlsDefaultPermName( fIsFile ? IDS_FILE_PERM_GEN_READ :
|
|
IDS_DIR_PERM_GEN_READ ) ;
|
|
RESOURCE_STR nlsHelpFileName ( IDS_FILE_PERM_HELP_FILE ) ;
|
|
RESOURCE_STR nlsResourceName ( fIsFile ? IDS_FILE_MULTI_SEL :
|
|
IDS_DIRECTORY_MULTI_SEL ) ;
|
|
|
|
NLS_STR nlsApplyToSubCont ;
|
|
NLS_STR nlsApplyToSubObj ;
|
|
NLS_STR nlsSpecialNewObj ;
|
|
NLS_STR nlsApplyToSubContConfirmation ;
|
|
|
|
/* We only need the ApplyTo title and the NewObjSpecial strings if
|
|
* this resource is a directory.
|
|
*/
|
|
if ( !fIsFile )
|
|
{
|
|
if ( (err = nlsApplyToSubCont.Load( msgidApplySubCont )) ||
|
|
(err = nlsApplyToSubObj.Load( msgidApplySubObj )) ||
|
|
(err = nlsSpecialNewObj.Load(IDS_NT_NEWOBJ_SPECIAL_ACCESS)) ||
|
|
(err = nlsApplyToSubContConfirmation.Load( IDS_TREE_APPLY_WARNING )))
|
|
{
|
|
/* Fall through
|
|
*/
|
|
}
|
|
}
|
|
|
|
if ( err ||
|
|
( err = nlsTypeName.QueryError() ) ||
|
|
( err = nlsSpecial.QueryError() ) ||
|
|
( err = nlsDefaultPermName.QueryError()) ||
|
|
( err = nlsHelpFileName.QueryError()) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
//
|
|
// Replace the resource name with the "X files selected" string
|
|
// if we are in a multi-select situation
|
|
//
|
|
if ( fIsMultiSelect )
|
|
{
|
|
if ( (err = nlsResourceName.QueryError()) ||
|
|
(err = nlsResourceName.InsertParams( nlsSelectCount )))
|
|
{
|
|
break ;
|
|
}
|
|
pszResource = nlsResourceName.QueryPch() ;
|
|
}
|
|
|
|
SED_OBJECT_TYPE_DESCRIPTOR sedobjdesc ;
|
|
SED_HELP_INFO sedhelpinfo ;
|
|
|
|
sedhelpinfo.pszHelpFileName = (LPWSTR) nlsHelpFileName.QueryPch() ;
|
|
|
|
sedobjdesc.Revision = SED_REVISION1 ;
|
|
sedobjdesc.IsContainer = !fIsFile ;
|
|
sedobjdesc.AllowNewObjectPerms = !fIsFile ;
|
|
sedobjdesc.MapSpecificPermsToGeneric = TRUE ;
|
|
sedobjdesc.GenericMapping = &NTFSGenericMapping ;
|
|
sedobjdesc.GenericMappingNewObjects = &NTFSGenericMapping ;
|
|
sedobjdesc.HelpInfo = &sedhelpinfo ;
|
|
sedobjdesc.ObjectTypeName = (LPTSTR) nlsTypeName.QueryPch() ;
|
|
sedobjdesc.ApplyToSubContainerTitle = (LPTSTR) nlsApplyToSubCont.QueryPch() ;
|
|
sedobjdesc.ApplyToObjectsTitle = (LPTSTR) nlsApplyToSubObj.QueryPch() ;
|
|
sedobjdesc.ApplyToSubContainerConfirmation
|
|
= (LPTSTR) nlsApplyToSubContConfirmation.QueryPch() ;
|
|
sedobjdesc.SpecialObjectAccessTitle = (LPTSTR) nlsSpecial.QueryPch() ;
|
|
sedobjdesc.SpecialNewObjectAccessTitle = (LPTSTR) nlsSpecialNewObj.QueryPch() ;
|
|
|
|
/* Now we need to load the global arrays with the permission names
|
|
* from the resource file.
|
|
*/
|
|
UINT cArrayItems ;
|
|
MSGID * msgidPermNames ;
|
|
PSED_APPLICATION_ACCESS pappaccess ;
|
|
ULONG hcMainDlg, hcSpecial, hcNewItemSpecial, hcAddUser,
|
|
hcAddMemberLG, hcAddMemberGG, hcAddSearch ;
|
|
ACCESS_MASK WriteAccessReq ;
|
|
|
|
// NTRAID#NTBUG9-574280-2002/03/07-artm Prefast: Local declaration hides function level declaration.
|
|
// A little tricky to figure out, but this declaration probably is unintentional. The code
|
|
// outside the scope of the do{}while() loop that checks fPrivAdjusted will never be
|
|
// executed b/c fPrivAdjusted is always set to FALSE outside the loop.
|
|
//
|
|
// This function appears to be used.
|
|
BOOL fPrivAdjusted = FALSE;
|
|
ULONG ulAuditPriv = SE_SECURITY_PRIVILEGE ;
|
|
|
|
switch ( sedpermtype )
|
|
{
|
|
case SED_ACCESSES:
|
|
hcAddUser = HC_SED_USER_BROWSER_DIALOG ;
|
|
hcAddMemberLG = HC_SED_USER_BROWSER_LOCALGROUP ;
|
|
hcAddMemberGG = HC_SED_USER_BROWSER_GLOBALGROUP ;
|
|
hcAddSearch = HC_SED_USER_BROWSER_FINDUSER ;
|
|
WriteAccessReq = WRITE_DAC ;
|
|
|
|
if ( fIsFile )
|
|
{
|
|
cArrayItems = COUNT_FILEPERMS_ARRAY ;
|
|
msgidPermNames = msgidFilePermNames ;
|
|
pappaccess = sedappaccessFilePerms ;
|
|
hcMainDlg = HC_SED_NT_FILE_PERMS_DLG ;
|
|
hcSpecial = HC_SED_NT_SPECIAL_FILES_FM ;
|
|
}
|
|
else
|
|
{
|
|
cArrayItems = COUNT_DIRPERMS_ARRAY ;
|
|
msgidPermNames = msgidDirPermNames ;
|
|
pappaccess = sedappaccessDirPerms ;
|
|
hcMainDlg = HC_SED_NT_DIR_PERMS_DLG ;
|
|
hcSpecial = HC_SED_NT_SPECIAL_DIRS_FM ;
|
|
hcNewItemSpecial = HC_SED_NT_SPECIAL_NEW_FILES_FM ;
|
|
}
|
|
break ;
|
|
|
|
case SED_AUDITS:
|
|
hcAddUser = HC_SED_USER_BROWSER_AUDIT_DLG ;
|
|
hcAddMemberLG = HC_SED_USER_BR_AUDIT_LOCALGROUP ;
|
|
hcAddMemberGG = HC_SED_USER_BR_AUDIT_GLOBALGROUP ;
|
|
hcAddSearch = HC_SED_USER_BR_AUDIT_FINDUSER ;
|
|
WriteAccessReq = ACCESS_SYSTEM_SECURITY ;
|
|
|
|
if ( fCheckSecurity )
|
|
{
|
|
if (err = ::NetpGetPrivilege( 1, &ulAuditPriv ) )
|
|
{
|
|
break ;
|
|
}
|
|
else
|
|
fPrivAdjusted = TRUE ;
|
|
}
|
|
|
|
if ( fIsFile )
|
|
{
|
|
cArrayItems = COUNT_FILE_AUDITPERMS_ARRAY ;
|
|
msgidPermNames = msgidFileAuditNames ;
|
|
pappaccess = sedappaccessFileAudits ;
|
|
hcMainDlg = HC_SED_NT_FILE_AUDITS_DLG ;
|
|
}
|
|
else
|
|
{
|
|
cArrayItems = COUNT_DIR_AUDITPERMS_ARRAY ;
|
|
msgidPermNames = msgidDirAuditNames ;
|
|
pappaccess = sedappaccessDirAudits ;
|
|
hcMainDlg = HC_SED_NT_DIR_AUDITS_DLG ;
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
UIASSERT(!SZ("Bad permission type")) ;
|
|
err = ERROR_GEN_FAILURE ;
|
|
break ;
|
|
}
|
|
if ( err )
|
|
break ;
|
|
|
|
if ( fCheckSecurity )
|
|
{
|
|
BOOL fCanWrite ;
|
|
if ( err = ::CheckFileSecurity( pszSecCheckFile,
|
|
WriteAccessReq,
|
|
&fCanWrite ) )
|
|
{
|
|
break ;
|
|
}
|
|
fCantWrite = !fCanWrite ;
|
|
|
|
if ( fPrivAdjusted )
|
|
NetpReleasePrivilege() ;
|
|
}
|
|
|
|
/* 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() ;
|
|
sedhelpinfo.aulHelpContext[HC_MAIN_DLG] = hcMainDlg ;
|
|
sedhelpinfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] = hcSpecial ;
|
|
sedhelpinfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] = hcNewItemSpecial ;
|
|
sedhelpinfo.aulHelpContext[HC_ADD_USER_DLG] = hcAddUser ;
|
|
sedhelpinfo.aulHelpContext[HC_ADD_USER_MEMBERS_LG_DLG] = hcAddMemberLG ;
|
|
sedhelpinfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] = hcAddMemberGG ;
|
|
sedhelpinfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] = hcAddSearch ;
|
|
|
|
|
|
|
|
DWORD dwSedReturnStatus ;
|
|
NTFS_CALLBACK_INFO callbackinfo ;
|
|
callbackinfo.hwndFMXOwner = hwndParent ;
|
|
|
|
switch ( sedpermtype )
|
|
{
|
|
case SED_ACCESSES:
|
|
callbackinfo.sedpermtype= SED_ACCESSES ;
|
|
err = SedDiscretionaryAclEditor( hwndParent,
|
|
::hModule,
|
|
(LPTSTR) pszServer,
|
|
&sedobjdesc,
|
|
&SedAppAccesses,
|
|
(LPTSTR) pszResource,
|
|
(PSED_FUNC_APPLY_SEC_CALLBACK) SedCallback,
|
|
(ULONG_PTR) &callbackinfo,
|
|
pSecurityDesc,
|
|
(BOOLEAN)fCantRead,
|
|
(BOOLEAN)fCantWrite,
|
|
&dwSedReturnStatus,
|
|
0 ) ;
|
|
break ;
|
|
|
|
case SED_AUDITS:
|
|
callbackinfo.sedpermtype = SED_AUDITS ;
|
|
err = SedSystemAclEditor( hwndParent,
|
|
::hModule,
|
|
(LPTSTR) pszServer,
|
|
&sedobjdesc,
|
|
&SedAppAccesses,
|
|
(LPTSTR) pszResource,
|
|
(PSED_FUNC_APPLY_SEC_CALLBACK) SedCallback,
|
|
(ULONG_PTR) &callbackinfo,
|
|
pSecurityDesc,
|
|
fCantRead || fCantWrite,
|
|
&dwSedReturnStatus,
|
|
0 ) ;
|
|
break ;
|
|
|
|
default:
|
|
UIASSERT(!SZ("Bad type") ) ;
|
|
err = ERROR_GEN_FAILURE ;
|
|
break ;
|
|
}
|
|
if ( err )
|
|
break ;
|
|
|
|
} while (FALSE) ;
|
|
|
|
/* We need to revert to ourselves if we were doing auditting
|
|
*/
|
|
if ( fPrivAdjusted )
|
|
{
|
|
APIERR errTmp = NetpReleasePrivilege() ;
|
|
if ( errTmp )
|
|
{
|
|
DBGEOL("::EditNTFSAcl - Warning: NetpReleasePrivilege return error "
|
|
<< errTmp ) ;
|
|
}
|
|
}
|
|
|
|
TRACEEOL(SZ("::EditNTFSAcl returning error code ") << (ULONG) err ) ;
|
|
|
|
if ( err )
|
|
{
|
|
::MsgPopup( hwndParent, (MSGID) err ) ;
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: SedCallback
|
|
|
|
SYNOPSIS: Security Editor callback for the NTFS ACL Editor
|
|
|
|
ENTRY: See sedapi.hxx
|
|
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES: The callback context should be the FMX Window handle. This
|
|
is so we can support setting permissions on multiple files/
|
|
directories if we ever decide to do that.
|
|
|
|
HISTORY:
|
|
Johnl 17-Mar-1992 Filled out
|
|
|
|
********************************************************************/
|
|
|
|
|
|
DWORD SedCallback( HWND hwndParent,
|
|
HANDLE hInstance,
|
|
ULONG_PTR ulCallbackContext,
|
|
PSECURITY_DESCRIPTOR psecdesc,
|
|
PSECURITY_DESCRIPTOR psecdescNewObjects,
|
|
BOOLEAN fApplyToSubContainers,
|
|
BOOLEAN fApplyToSubObjects,
|
|
LPDWORD StatusReturn
|
|
)
|
|
{
|
|
UNREFERENCED( hInstance ) ;
|
|
APIERR err = NO_ERROR ;
|
|
NTFS_CALLBACK_INFO *pcallbackinfo = (NTFS_CALLBACK_INFO *)ulCallbackContext;
|
|
HWND hwndFMXWindow = pcallbackinfo->hwndFMXOwner ;
|
|
OS_SECURITY_INFORMATION osSecInfo ;
|
|
BOOL fDepthFirstTraversal = TRUE ;
|
|
BOOL fApplyToDirContents = FALSE ;
|
|
BOOL fIsFile ;
|
|
BOOL fBlowAwayDACLOnCont = FALSE ;
|
|
NLS_STR nlsSelItem( 128 ) ;
|
|
RESOURCE_STR nlsCancelDialogTitle( IDS_CANCEL_TASK_APPLY_DLG_TITLE ) ;
|
|
BOOL fPrivAdjusted = FALSE;
|
|
|
|
if ( (err = nlsSelItem.QueryError()) ||
|
|
(err = nlsCancelDialogTitle.QueryError()) ||
|
|
(err = ::GetSelItem( hwndFMXWindow, 0, &nlsSelItem, &fIsFile )) )
|
|
{
|
|
*StatusReturn = SED_STATUS_FAILED_TO_MODIFY ;
|
|
::MsgPopup( hwndParent, (MSGID) err ) ;
|
|
return err ;
|
|
}
|
|
|
|
switch ( pcallbackinfo->sedpermtype )
|
|
{
|
|
case SED_ACCESSES:
|
|
osSecInfo.SetDACLReference( TRUE ) ;
|
|
fApplyToDirContents = !fIsFile && fApplyToSubObjects ;
|
|
|
|
//
|
|
// Check to see if we should do a depth first or breadth first
|
|
// traversal of the selected directory. If we have traverse
|
|
// on the directory already, then do depth first. If we don't,
|
|
// then do a breadth first and hope we are granting ourselves
|
|
// traverse.
|
|
//
|
|
if ( fApplyToSubContainers || fApplyToDirContents )
|
|
{
|
|
if ( err = ::CheckFileSecurity( nlsSelItem,
|
|
FILE_TRAVERSE | FILE_LIST_DIRECTORY,
|
|
&fDepthFirstTraversal ))
|
|
{
|
|
DBGEOL("SedCallBack - ::CheckFileSecurity failed with error " << err ) ;
|
|
*StatusReturn = SED_STATUS_FAILED_TO_MODIFY ;
|
|
::MsgPopup( hwndParent, (MSGID) err ) ;
|
|
return err ;
|
|
}
|
|
TRACEEOL("SedCallBack - Depth first = " << fDepthFirstTraversal ) ;
|
|
}
|
|
break ;
|
|
|
|
case SED_AUDITS:
|
|
{
|
|
osSecInfo.SetSACLReference( TRUE ) ;
|
|
fApplyToDirContents = !fIsFile && fApplyToSubObjects ;;
|
|
ULONG ulAuditPriv = SE_SECURITY_PRIVILEGE ;
|
|
|
|
if (err = ::NetpGetPrivilege( 1, &ulAuditPriv ) )
|
|
{
|
|
break ;
|
|
}
|
|
else
|
|
fPrivAdjusted = TRUE ;
|
|
}
|
|
break ;
|
|
|
|
case SED_OWNER:
|
|
|
|
osSecInfo.SetOwnerReference( TRUE ) ;
|
|
|
|
//
|
|
// Do a breadth first traversal since taking ownership grants
|
|
// additional privileges
|
|
//
|
|
fDepthFirstTraversal = FALSE ;
|
|
|
|
//
|
|
// Containers and objects get the same security descriptor
|
|
//
|
|
psecdescNewObjects = psecdesc ;
|
|
|
|
if ( !fIsFile )
|
|
{
|
|
switch ( ::MsgPopup( hwndParent,
|
|
IDS_OWNER_APPLY_TO_DIR_PROMPT,
|
|
MPSEV_INFO,
|
|
MP_YESNOCANCEL ))
|
|
{
|
|
case IDYES:
|
|
fApplyToSubContainers = TRUE ;
|
|
fApplyToSubObjects = TRUE ;
|
|
fBlowAwayDACLOnCont = TRUE ;
|
|
fApplyToDirContents = TRUE ;
|
|
break ;
|
|
|
|
case IDNO:
|
|
fApplyToSubContainers = FALSE ;
|
|
fApplyToSubObjects = FALSE ;
|
|
fBlowAwayDACLOnCont = FALSE ;
|
|
fApplyToDirContents = FALSE ;
|
|
break ;
|
|
|
|
case IDCANCEL:
|
|
default:
|
|
*StatusReturn = SED_STATUS_FAILED_TO_MODIFY ;
|
|
return ERROR_GEN_FAILURE ; // any nonzero error code
|
|
}
|
|
}
|
|
|
|
break ;
|
|
|
|
default:
|
|
UIASSERT( FALSE ) ;
|
|
*StatusReturn = SED_STATUS_FAILED_TO_MODIFY ;
|
|
return ERROR_GEN_FAILURE ;
|
|
}
|
|
|
|
FMX fmx( hwndFMXWindow );
|
|
UINT uiCount = fmx.QuerySelCount() ;
|
|
BOOL fDismissDlg = TRUE ;
|
|
|
|
//
|
|
// QuerySelCount only returns the number of selections in the files window,
|
|
// thus if the focus is in the directory window, then we will just make
|
|
// the selection count one for out "for" loop.
|
|
//
|
|
if ( fmx.QueryFocus() == FMFOCUS_TREE )
|
|
{
|
|
uiCount = 1 ;
|
|
}
|
|
|
|
//
|
|
// If we only have to apply permissions to a single item or we are
|
|
// taking ownership of a file, then just
|
|
// do it w/o bringing up the cancel task dialog.
|
|
//
|
|
if ( uiCount == 1 &&
|
|
!fApplyToSubContainers &&
|
|
!fApplyToSubObjects &&
|
|
!fApplyToDirContents )
|
|
{
|
|
// Try Admins Group First
|
|
OS_SECURITY_DESCRIPTOR osSecAdmin;
|
|
OS_SID ossidAdmins;
|
|
|
|
NT_ACCOUNTS_UTILITY::QuerySystemSid( UI_SID_Admins,
|
|
&ossidAdmins );
|
|
osSecAdmin.SetOwner(ossidAdmins);
|
|
osSecAdmin.SetGroup(ossidAdmins);
|
|
|
|
//
|
|
// CODEWORK We skip this hack unless taking ownership. Note that the
|
|
// osSecAdmin and ossidAdmins should also be removed.
|
|
//
|
|
if ( SED_OWNER != pcallbackinfo->sedpermtype
|
|
|| !::SetFileSecurity( (LPTSTR) nlsSelItem.QueryPch(),
|
|
osSecInfo,
|
|
osSecAdmin.QueryDescriptor() ) )
|
|
{// if it fails try owner account
|
|
if ( !::SetFileSecurity( (LPTSTR) nlsSelItem.QueryPch(),
|
|
osSecInfo,
|
|
psecdesc ) )
|
|
{
|
|
err = ::GetLastError() ;
|
|
}
|
|
}
|
|
if ( err )
|
|
{
|
|
DBGEOL("NTFS SedCallback - Error " << (ULONG)err << " applying security to " <<
|
|
nlsSelItem ) ;
|
|
::MsgPopup( hwndParent, (MSGID) err ) ;
|
|
*StatusReturn = SED_STATUS_FAILED_TO_MODIFY ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NTFS_TREE_APPLY_CONTEXT Ctxt( nlsSelItem, osSecInfo ) ;
|
|
Ctxt.State = APPLY_SEC_FMX_SELECTION ;
|
|
Ctxt.hwndFMXWindow = hwndFMXWindow ;
|
|
Ctxt.sedpermtype = pcallbackinfo->sedpermtype ;
|
|
Ctxt.iCurrent = 0 ;
|
|
Ctxt.uiCount = uiCount ;
|
|
Ctxt.fDepthFirstTraversal = fDepthFirstTraversal ;
|
|
Ctxt.fApplyToDirContents = fApplyToDirContents ;
|
|
Ctxt.fBlowAwayDACLOnCont = fBlowAwayDACLOnCont ;
|
|
Ctxt.StatusReturn = StatusReturn ;
|
|
Ctxt.psecdesc = psecdesc ;
|
|
Ctxt.psecdescNewObjects = psecdescNewObjects ;
|
|
Ctxt.fApplyToSubContainers= fApplyToSubContainers ;
|
|
Ctxt.fApplyToSubObjects = fApplyToSubObjects ;
|
|
|
|
NTFS_CANCEL_TREE_APPLY CancelTreeApply( hwndParent,
|
|
&Ctxt,
|
|
nlsCancelDialogTitle ) ;
|
|
|
|
if ( (err = CancelTreeApply.QueryError()) ||
|
|
(err = CancelTreeApply.Process( &fDismissDlg )) )
|
|
{
|
|
*StatusReturn = SED_STATUS_FAILED_TO_MODIFY ;
|
|
::MsgPopup( hwndParent, (MSGID) err ) ;
|
|
}
|
|
}
|
|
|
|
if ( !err )
|
|
{
|
|
//
|
|
// Refresh the file manager window if permissions is updated
|
|
// (Take ownership of a tree also writes a new DACL)
|
|
//
|
|
if ( pcallbackinfo->sedpermtype == SED_ACCESSES ||
|
|
pcallbackinfo->sedpermtype == SED_OWNER )
|
|
{
|
|
fmx.Refresh();
|
|
}
|
|
|
|
if ( *StatusReturn == 0 )
|
|
*StatusReturn = SED_STATUS_MODIFIED ;
|
|
}
|
|
|
|
if ( fPrivAdjusted )
|
|
{
|
|
APIERR errTmp = NetpReleasePrivilege() ;
|
|
if ( errTmp )
|
|
{
|
|
DBGEOL("::EditNTFSAcl - Warning: NetpReleasePrivilege return error "
|
|
<< errTmp ) ;
|
|
}
|
|
}
|
|
|
|
if ( !err && !fDismissDlg )
|
|
{
|
|
//
|
|
// Don't dismiss the dialog if the user canceled the tree
|
|
// apply. This tells the ACL editor not to dismiss the permissions
|
|
// dialog (or auditing or owner).
|
|
//
|
|
err = ERROR_GEN_FAILURE ;
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CANCEL_TREE_APPLY::DoOneItem
|
|
|
|
SYNOPSIS: This is the time slice call for the tree apply
|
|
|
|
ENTRY: ulContext - Context passed to the constructor
|
|
|
|
RETURNS: NERR_Success if this time slice was successful, error
|
|
code otherwise (which will be displayed to the user).
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
Johnl 22-Oct-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
APIERR CANCEL_TREE_APPLY::DoOneItem( ULONG_PTR ulContext,
|
|
BOOL *pfContinue,
|
|
BOOL *pfDisplayErrors,
|
|
MSGID *pmsgidAlternateMessage )
|
|
{
|
|
TREE_APPLY_CONTEXT * pCtxt = (TREE_APPLY_CONTEXT*) ulContext ;
|
|
*pfDisplayErrors = TRUE ;
|
|
*pfContinue = TRUE ;
|
|
APIERR err = NERR_Success ;
|
|
APIERR errTrav = NERR_Success;
|
|
BOOL fSuccess ;
|
|
|
|
switch ( pCtxt->State )
|
|
{
|
|
case APPLY_SEC_IN_FS_ENUM:
|
|
{
|
|
UIASSERT( pCtxt->pfsenum != NULL ) ;
|
|
|
|
fSuccess = pCtxt->pfsenum->Next() ;
|
|
|
|
NLS_STR nlsFileName ;
|
|
if ( (err = nlsFileName.QueryError()) ||
|
|
(err = pCtxt->pfsenum->QueryName( &nlsFileName )))
|
|
{
|
|
break ;
|
|
}
|
|
|
|
REQUIRE( UpdateStatus( nlsFileName ) == NERR_Success ) ;
|
|
|
|
//
|
|
// Only write the security if the enumeration was successful
|
|
//
|
|
if ( fSuccess )
|
|
{
|
|
ApplySecurity:
|
|
err = WriteSecurity( ulContext,
|
|
nlsFileName,
|
|
!(pCtxt->pfsenum->QueryAttr()&_A_SUBDIR),
|
|
pfContinue ) ;
|
|
if ( !*pfContinue )
|
|
{
|
|
delete pCtxt->pfsenum ;
|
|
pCtxt->pfsenum = NULL ;
|
|
}
|
|
|
|
//
|
|
// Report any traversal errors after attempting to apply
|
|
// security to the container we failed to traverse
|
|
//
|
|
|
|
if ( errTrav )
|
|
err = errTrav;
|
|
|
|
break ;
|
|
}
|
|
else if ((err = pCtxt->pfsenum->QueryLastError()) != ERROR_NO_MORE_FILES)
|
|
{
|
|
*pmsgidAlternateMessage = IDS_CANCEL_TASK_TRAV_ERROR_MSG ;
|
|
|
|
//
|
|
// Apply security even in the error case if we're not at the
|
|
// selected directory. This handles the case of hitting a no
|
|
// access directory as the only selection
|
|
//
|
|
|
|
if ( pCtxt->pfsenum->QueryTotalFiles() )
|
|
{
|
|
errTrav = err;
|
|
goto ApplySecurity;
|
|
}
|
|
|
|
//
|
|
// falls through and deletes the enumerator
|
|
//
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Running out of files is a success error code
|
|
//
|
|
err = NERR_Success ;
|
|
TRACEEOL("SedCallBack - Traversed " << pCtxt->pfsenum->QueryTotalFiles() <<
|
|
" files and directories") ;
|
|
}
|
|
delete pCtxt->pfsenum ;
|
|
pCtxt->pfsenum = NULL ;
|
|
pCtxt->State = APPLY_SEC_FMX_POST_FS_ENUM ;
|
|
}
|
|
break ;
|
|
|
|
|
|
case APPLY_SEC_FMX_POST_FS_ENUM:
|
|
//
|
|
// Apply security to the container after everything under this has
|
|
// been applied if we are doing a depth first traversal.
|
|
//
|
|
if ( pCtxt->fDepthFirstTraversal )
|
|
{
|
|
UpdateStatus( pCtxt->nlsSelItem ) ;
|
|
if ( err = WriteSecurity( ulContext,
|
|
pCtxt->nlsSelItem,
|
|
pCtxt->fIsSelFile,
|
|
pfContinue ))
|
|
{
|
|
// Fall through
|
|
}
|
|
}
|
|
pCtxt->State = APPLY_SEC_FMX_SELECTION ;
|
|
break ;
|
|
|
|
case APPLY_SEC_FMX_SELECTION:
|
|
|
|
/* Have we went through all of the selected items?
|
|
*/
|
|
if ( pCtxt->iCurrent >= pCtxt->uiCount )
|
|
{
|
|
*pfContinue = FALSE ;
|
|
break ;
|
|
}
|
|
|
|
/* Get the current selection and apply the permissions
|
|
*/
|
|
if (err = ::GetSelItem( pCtxt->hwndFMXWindow,
|
|
pCtxt->iCurrent++,
|
|
&pCtxt->nlsSelItem,
|
|
&pCtxt->fIsSelFile ) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
//
|
|
// If we're doing the breadthfirst traversal, then apply to the
|
|
// container before traversing, else apply after traversing.
|
|
// If it's a file, then always apply.
|
|
//
|
|
if (( !pCtxt->fDepthFirstTraversal || pCtxt->fIsSelFile ) ||
|
|
( (!pCtxt->fApplyToSubContainers && !pCtxt->fApplyToDirContents) &&
|
|
!pCtxt->fIsSelFile ))
|
|
{
|
|
UpdateStatus( pCtxt->nlsSelItem ) ;
|
|
if ( err = WriteSecurity( ulContext,
|
|
pCtxt->nlsSelItem,
|
|
pCtxt->fIsSelFile,
|
|
pfContinue ))
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the user checked the apply to tree box or apply to existing file
|
|
// checkbox and this is a container then apply the
|
|
// permissions down the sub-tree optionally to files
|
|
//
|
|
if ( (pCtxt->fApplyToSubContainers || pCtxt->fApplyToDirContents)
|
|
&& !pCtxt->fIsSelFile )
|
|
{
|
|
UpdateStatus( pCtxt->nlsSelItem ) ;
|
|
|
|
//
|
|
// Determine whether we should apply permissions to both
|
|
// directories and files, directories only or files only
|
|
//
|
|
enum FILE_TYPE filetype ;
|
|
switch ((pCtxt->fApplyToSubContainers << 1) + pCtxt->fApplyToDirContents )
|
|
{
|
|
case 3:
|
|
filetype = FILTYP_ALL_FILES ;
|
|
break ;
|
|
|
|
case 2:
|
|
filetype = FILTYP_DIRS ;
|
|
break ;
|
|
|
|
case 1:
|
|
filetype = FILTYP_FILES ;
|
|
break ;
|
|
|
|
default:
|
|
UIASSERT( FALSE ) ;
|
|
}
|
|
|
|
pCtxt->pfsenum = new W32_FS_ENUM( pCtxt->nlsSelItem,
|
|
SZ("*.*"),
|
|
filetype,
|
|
pCtxt->fDepthFirstTraversal,
|
|
pCtxt->fApplyToSubContainers ?
|
|
0xffffffff : 0 ) ;
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
if ( pCtxt == NULL ||
|
|
(err = pCtxt->pfsenum->QueryError() ))
|
|
{
|
|
break ;
|
|
}
|
|
//
|
|
// Next time around, start doing the enumeration
|
|
//
|
|
pCtxt->State = APPLY_SEC_IN_FS_ENUM ;
|
|
}
|
|
break ;
|
|
}
|
|
|
|
if ( err && *pCtxt->StatusReturn == 0 )
|
|
{
|
|
*pCtxt->StatusReturn = (pCtxt->iCurrent-1 ? SED_STATUS_NOT_ALL_MODIFIED :
|
|
SED_STATUS_FAILED_TO_MODIFY);
|
|
}
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: NTFS_CANCEL_TREE_APPLY::WriteSecurity
|
|
|
|
SYNOPSIS: Write security to an NTFS volume
|
|
|
|
ENTRY: ulContext - Pointer to NTFS_TREE_APPLY_CONTEXT
|
|
pszFileName - File to apply to
|
|
fIsFile - TRUE if object, FALSE if container
|
|
pfContinue - Set to FALSE if the apply should be
|
|
terminated.
|
|
|
|
RETURNS: NERR_Success if successful, error code otherwise
|
|
|
|
HISTORY:
|
|
Johnl 23-Oct-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
APIERR NTFS_CANCEL_TREE_APPLY::WriteSecurity( ULONG_PTR ulContext,
|
|
const TCHAR * pszFileName,
|
|
BOOL fIsFile,
|
|
BOOL * pfContinue )
|
|
{
|
|
APIERR err = NERR_Success ;
|
|
NTFS_TREE_APPLY_CONTEXT * pCtxt = (NTFS_TREE_APPLY_CONTEXT*) ulContext ;
|
|
SECURITY_INFORMATION SecInfoTmp = (SECURITY_INFORMATION) pCtxt->osSecInfo ;
|
|
*pfContinue = TRUE ;
|
|
|
|
//
|
|
// If any of the "container" flags are set and we are looking at a
|
|
// file, then use the object security descriptor, else use the container
|
|
// /object security descriptor.
|
|
//
|
|
PSECURITY_DESCRIPTOR psecdescTmp = fIsFile &&
|
|
(pCtxt->fApplyToSubContainers ||
|
|
pCtxt->fApplyToSubObjects ||
|
|
pCtxt->fApplyToDirContents) ?
|
|
pCtxt->psecdescNewObjects :
|
|
pCtxt->psecdesc ;
|
|
|
|
//
|
|
// Taking ownership also optionally blows away the DACL at the user's
|
|
// request
|
|
//
|
|
if ( !fIsFile && (pCtxt->sedpermtype == SED_OWNER) )
|
|
{
|
|
OS_ACL osDACL ;
|
|
OS_ACE osACE ;
|
|
OS_SID ossidUser ;
|
|
OS_SECURITY_DESCRIPTOR ossecdesc( psecdescTmp, TRUE ) ;
|
|
|
|
if ( (err = osDACL.QueryError()) ||
|
|
(err = osACE.QueryError()) ||
|
|
(err = ossidUser.QueryError()) ||
|
|
(err = ossecdesc.QueryError()) ||
|
|
(err = NT_ACCOUNTS_UTILITY::QuerySystemSid( UI_SID_CurrentProcessOwner,
|
|
&ossidUser )) )
|
|
{
|
|
// Fall through
|
|
}
|
|
|
|
if ( !err )
|
|
{
|
|
//
|
|
// Put an ACE that grants full control and that will be
|
|
// inherited to new objects and new containers on this
|
|
// container. The SID is the currently logged on user.
|
|
//
|
|
osACE.SetType( ACCESS_ALLOWED_ACE_TYPE ) ;
|
|
osACE.SetInheritFlags( OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE ) ;
|
|
osACE.SetAccessMask( GENERIC_ALL ) ;
|
|
|
|
if ( (err = osACE.SetSID( ossidUser )) ||
|
|
(err = osDACL.AddACE( 0, osACE )) ||
|
|
(err = ossecdesc.SetDACL( TRUE, &osDACL )) )
|
|
{
|
|
// Fall through
|
|
}
|
|
}
|
|
|
|
if ( !err)
|
|
{
|
|
OS_SECURITY_DESCRIPTOR osSecAdmin;
|
|
OS_SID ossidAdmins;
|
|
NT_ACCOUNTS_UTILITY::QuerySystemSid( UI_SID_Admins,
|
|
&ossidAdmins );
|
|
osSecAdmin.SetOwner(ossidAdmins);
|
|
osSecAdmin.SetGroup(ossidAdmins);
|
|
osSecAdmin.SetDACL( TRUE, &osDACL );
|
|
// Try Admins Group First
|
|
if ( !::SetFileSecurity( (LPTSTR) pszFileName,
|
|
SecInfoTmp,
|
|
osSecAdmin.QueryDescriptor() ) )
|
|
{
|
|
// if it fails try owner account
|
|
if (!::SetFileSecurity( (LPTSTR) pszFileName, // Take ownership
|
|
SecInfoTmp,
|
|
ossecdesc ))
|
|
{
|
|
err = ::GetLastError() ;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Now check if they have traversal permission. If they do, then
|
|
// leave the ACL alone, else ask them if they want to blow away the
|
|
// DACL
|
|
//
|
|
BOOL fCanTraverse ;
|
|
if ( !err &&
|
|
!(err = ::CheckFileSecurity( (LPTSTR) pszFileName,
|
|
FILE_TRAVERSE | FILE_LIST_DIRECTORY,
|
|
&fCanTraverse )) &&
|
|
!fCanTraverse )
|
|
{
|
|
switch ( ::MsgPopup( this,
|
|
IDS_OWNER_NUKE_DACL_WARNING,
|
|
MPSEV_INFO,
|
|
MP_YES| MP_CANCEL,
|
|
pszFileName ))
|
|
{
|
|
case IDYES:
|
|
|
|
|
|
if ( !::SetFileSecurity( (LPTSTR) pszFileName, // Blow away DACL
|
|
DACL_SECURITY_INFORMATION,
|
|
ossecdesc ))
|
|
{
|
|
err = ::GetLastError() ;
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
case IDNO:
|
|
case IDCANCEL:
|
|
*pfContinue = FALSE ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
else // if ( !fIsFile && (pCtxt->sedpermtype == SED_OWNER) )
|
|
{
|
|
if ((pCtxt->sedpermtype == SED_OWNER))
|
|
{
|
|
OS_SECURITY_DESCRIPTOR osSecAdmin;
|
|
OS_SID ossidAdmins;
|
|
NT_ACCOUNTS_UTILITY::QuerySystemSid( UI_SID_Admins,
|
|
&ossidAdmins );
|
|
osSecAdmin.SetOwner(ossidAdmins);
|
|
osSecAdmin.SetGroup(ossidAdmins);
|
|
|
|
// Try Admins Group First
|
|
if ( !::SetFileSecurity( (LPTSTR) pszFileName,
|
|
SecInfoTmp,
|
|
osSecAdmin.QueryDescriptor() ) )
|
|
{
|
|
// if it fails try owner account
|
|
if ( !::SetFileSecurity( (LPTSTR) pszFileName,
|
|
SecInfoTmp,
|
|
psecdescTmp ))
|
|
{
|
|
err = ::GetLastError() ;
|
|
}
|
|
}
|
|
}
|
|
else if ( !::SetFileSecurity( (LPTSTR) pszFileName,
|
|
SecInfoTmp,
|
|
psecdescTmp ))
|
|
{
|
|
err = ::GetLastError() ;
|
|
}
|
|
}
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CompareNTFSSecurityIntersection
|
|
|
|
SYNOPSIS: Determines if the files/dirs currently selected have
|
|
equivalent security descriptors
|
|
|
|
ENTRY: hwndFMX - FMX Hwnd used for getting selection
|
|
sedpermtype - Interested in DACL or SACL
|
|
psecdesc - Baseline security descriptor to compare against
|
|
pfOwnerEqual - Set to TRUE if all the owners are equal
|
|
pfACLEqual - Set to TRUE if all of the DACLs/SACLs are
|
|
equal. If FALSE, then pfOwnerEqual should be ignored
|
|
|
|
RETURNS: NERR_Success if successful, error code otherwise
|
|
|
|
NOTES: The first non-equal ACL causes the function to exit.
|
|
|
|
On a 20e with 499 files selected locally, it took 35.2 minutes
|
|
to read the security descriptors from the disk and 14 seconds
|
|
to determine the intersection. So even though the Compare
|
|
method uses an n^2 algorithm, it only takes up 0.6% of the
|
|
wait time.
|
|
|
|
HISTORY:
|
|
Johnl 05-Nov-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
APIERR CompareNTFSSecurityIntersection( HWND hwndFMX,
|
|
enum SED_PERM_TYPE sedpermtype,
|
|
PSECURITY_DESCRIPTOR psecdesc,
|
|
BOOL * pfOwnerEqual,
|
|
BOOL * pfACLEqual,
|
|
NLS_STR * pnlsFailingFile,
|
|
PGENERIC_MAPPING pGenericMapping,
|
|
PGENERIC_MAPPING pGenericMappingObjects,
|
|
BOOL fMapGenAll,
|
|
BOOL fIsContainer )
|
|
{
|
|
TRACEEOL("::CompareNTFSSecurityIntersection - Entered @ " << ::GetTickCount()/100) ;
|
|
|
|
FMX fmx( hwndFMX );
|
|
UIASSERT( fmx.QuerySelCount() > 1 ) ;
|
|
APIERR err ;
|
|
OS_SECURITY_DESCRIPTOR ossecdesc1( psecdesc ) ;
|
|
UINT cSel = fmx.QuerySelCount() ;
|
|
|
|
NLS_STR nlsSel( PATHLEN ) ;
|
|
BUFFER buffSecDescData( 1024 ) ;
|
|
if ( (err = nlsSel.QueryError()) ||
|
|
(err = buffSecDescData.QueryError()) )
|
|
{
|
|
return err ;
|
|
}
|
|
|
|
*pfOwnerEqual = TRUE ;
|
|
*pfACLEqual = TRUE ;
|
|
|
|
for ( UINT i = 1 ; i < cSel ; i++ )
|
|
{
|
|
if ( (err = ::GetSelItem( hwndFMX, i, &nlsSel, NULL )) ||
|
|
(err = ::GetSecurity( nlsSel,
|
|
&buffSecDescData,
|
|
sedpermtype,
|
|
NULL )) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
BOOL fACLEqual = FALSE ;
|
|
BOOL fOwnerEqual = FALSE ;
|
|
PSECURITY_DESCRIPTOR psecdesc2 = (PSECURITY_DESCRIPTOR)
|
|
buffSecDescData.QueryPtr() ;
|
|
|
|
OS_SECURITY_DESCRIPTOR ossecdesc2( psecdesc2 ) ;
|
|
if ( (err = ossecdesc2.QueryError()) ||
|
|
(err = ossecdesc1.Compare( &ossecdesc2,
|
|
&fOwnerEqual,
|
|
NULL,
|
|
sedpermtype == SED_ACCESSES ?
|
|
&fACLEqual : NULL,
|
|
sedpermtype == SED_AUDITS ?
|
|
&fACLEqual : NULL ,
|
|
pGenericMapping,
|
|
pGenericMappingObjects,
|
|
fMapGenAll,
|
|
fIsContainer )) )
|
|
|
|
{
|
|
break ;
|
|
}
|
|
|
|
if ( !fACLEqual )
|
|
{
|
|
*pfACLEqual = FALSE ;
|
|
return pnlsFailingFile->CopyFrom( nlsSel ) ;
|
|
}
|
|
|
|
if ( *pfOwnerEqual && !fOwnerEqual )
|
|
{
|
|
*pfOwnerEqual = FALSE ;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Some errors aren't fatal (like ERROR_ACCESS_DENIED)
|
|
//
|
|
APIERR errtmp = pnlsFailingFile->CopyFrom( nlsSel ) ;
|
|
if ( errtmp )
|
|
err = errtmp ;
|
|
|
|
TRACEEOL("::CompareNTFSSecurityIntersection - Left @ " << ::GetTickCount()/100) ;
|
|
return err ;
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: EditOwnerInfo
|
|
|
|
SYNOPSIS: This function sets up the parameters for calling the
|
|
SedTakeOwnership API.
|
|
|
|
ENTRY: hwndFMXWindow - Window handle received by the File manager
|
|
extensions.
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
Johnl 13-Feb-1992 Implemented with real code
|
|
|
|
********************************************************************/
|
|
|
|
void EditOwnerInfo( HWND hwndFMXWindow )
|
|
{
|
|
AUTO_CURSOR cursorHourGlass ;
|
|
|
|
APIERR err = NERR_Success;
|
|
BOOL fIsFile ;
|
|
BOOL fCantRead = FALSE ; // Did we read the Owner?
|
|
BOOL fCantWrite = FALSE ; // Can we write the owner?
|
|
UINT uiCount ;
|
|
NLS_STR nlsSelItem;
|
|
|
|
|
|
PSECURITY_DESCRIPTOR psecdesc = NULL ;
|
|
BUFFER buffSecDescData( 1024 ) ;
|
|
RESOURCE_STR nlsHelpFileName( IDS_FILE_PERM_HELP_FILE ) ;
|
|
|
|
if ( ( err = buffSecDescData.QueryError() )
|
|
|| ( err = nlsHelpFileName.QueryError() )
|
|
)
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) err ) ;
|
|
return ;
|
|
}
|
|
|
|
FMX fmx( hwndFMXWindow );
|
|
|
|
/* If the focus is in tree portion of the filemanager (left pane) then
|
|
* one directory is selected.
|
|
*/
|
|
uiCount = (fmx.QueryFocus() == FMFOCUS_TREE ? 1 : fmx.QuerySelCount()) ;
|
|
DBGEOL( SZ("::EditOwnerInfo - ") << uiCount << SZ(" files selected")) ;
|
|
|
|
BOOL fIsNTFS ;
|
|
BOOL fIsLocal ;
|
|
NLS_STR nlsServer( RMLEN ) ;
|
|
if ( (err = ::GetSelItem( hwndFMXWindow, 0, &nlsSelItem, &fIsFile )) ||
|
|
(err = ::IsNTFS( nlsSelItem, &fIsNTFS )) ||
|
|
(err = nlsServer.QueryError()))
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) err ) ;
|
|
return ;
|
|
}
|
|
|
|
err = ::TargetServerFromDosPath( nlsSelItem,
|
|
&fIsLocal,
|
|
&nlsServer );
|
|
|
|
if ( err == NERR_InvalidDevice )
|
|
{
|
|
NLS_STR nlsDrive( nlsSelItem );
|
|
ISTR istr( nlsDrive );
|
|
|
|
err = nlsDrive.QueryError();
|
|
if ( err == NERR_Success )
|
|
{
|
|
istr += 2;
|
|
nlsDrive.DelSubStr( istr );
|
|
|
|
err = WNetFMXEditPerm( (LPWSTR) nlsDrive.QueryPch(),
|
|
hwndFMXWindow,
|
|
WNPERM_DLG_OWNER );
|
|
}
|
|
}
|
|
|
|
if ( err != NERR_Success )
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) err );
|
|
return;
|
|
}
|
|
|
|
if ( !fIsNTFS )
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) IERR_OWNER_NOT_NTFS_VOLUME ) ;
|
|
return ;
|
|
}
|
|
|
|
/* We display the filename and get the security descriptor
|
|
* if there is only 1 item selected
|
|
*/
|
|
if ( uiCount == 1)
|
|
{
|
|
switch ( err = ::GetSecurity( nlsSelItem,
|
|
&buffSecDescData,
|
|
SED_OWNER,
|
|
NULL ) )
|
|
{
|
|
case NO_ERROR:
|
|
psecdesc = (PSECURITY_DESCRIPTOR) buffSecDescData.QueryPtr() ;
|
|
break ;
|
|
|
|
case ERROR_ACCESS_DENIED:
|
|
err = NERR_Success ;
|
|
fCantRead = TRUE ;
|
|
psecdesc = NULL ;
|
|
break ;
|
|
|
|
default:
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) err ) ;
|
|
return ;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
MSGID msgidObjType = 0, msgidObjName = 0 ;
|
|
if ( uiCount > 1 )
|
|
{
|
|
msgidObjType = IDS_FILES_AND_DIRS ;
|
|
}
|
|
else
|
|
{
|
|
if ( fIsFile )
|
|
msgidObjType = IDS_FILE ;
|
|
else
|
|
msgidObjType = IDS_DIRECTORY ;
|
|
|
|
BOOL fPrivAdjusted = FALSE;
|
|
ULONG ulOwnerPriv = SE_TAKE_OWNERSHIP_PRIVILEGE ;
|
|
|
|
if ( (err = ::NetpGetPrivilege( 1, &ulOwnerPriv )) &&
|
|
(err != ERROR_PRIVILEGE_NOT_HELD) )
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) err ) ;
|
|
return ;
|
|
}
|
|
else
|
|
{
|
|
BOOL fCanWrite ;
|
|
if ( err = ::CheckFileSecurity( nlsSelItem,
|
|
WRITE_OWNER,
|
|
&fCanWrite ))
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) err ) ;
|
|
::NetpReleasePrivilege() ;
|
|
return ;
|
|
}
|
|
|
|
fCantWrite = !fCanWrite ;
|
|
::NetpReleasePrivilege() ;
|
|
}
|
|
}
|
|
|
|
RESOURCE_STR nlsTypeName( msgidObjType ) ;
|
|
if ( (err = nlsSelItem.QueryError() ) ||
|
|
(err = nlsTypeName.QueryError()) )
|
|
{
|
|
::MsgPopup( hwndFMXWindow, (MSGID) err ) ;
|
|
return ;
|
|
}
|
|
|
|
NTFS_CALLBACK_INFO callbackinfo ;
|
|
callbackinfo.hwndFMXOwner = hwndFMXWindow ;
|
|
callbackinfo.sedpermtype= SED_OWNER ;
|
|
|
|
DWORD dwSedStatus ;
|
|
|
|
SED_HELP_INFO sedhelpinfo ;
|
|
sedhelpinfo.pszHelpFileName = (LPWSTR) nlsHelpFileName.QueryPch() ;
|
|
sedhelpinfo.aulHelpContext[HC_MAIN_DLG] = HC_TAKEOWNERSHIP_DIALOG ;
|
|
|
|
err = SedTakeOwnership( hwndFMXWindow,
|
|
::hModule,
|
|
fIsLocal ? NULL : (LPTSTR) nlsServer.QueryPch(),
|
|
(LPTSTR) nlsTypeName.QueryPch(),
|
|
uiCount==1 ? (LPTSTR)nlsSelItem.QueryPch() : NULL,
|
|
uiCount,
|
|
SedCallback,
|
|
(ULONG_PTR) &callbackinfo,
|
|
psecdesc,
|
|
(BOOLEAN)fCantRead,
|
|
(BOOLEAN)fCantWrite,
|
|
&dwSedStatus,
|
|
&sedhelpinfo,
|
|
0
|
|
) ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ::GetSecurity
|
|
|
|
SYNOPSIS: Retrieves a security descriptor from an NTFS file/directory
|
|
|
|
ENTRY: pszFileName - Name of file/dir to get security desc. for
|
|
pbuffSecDescData - Buffer to store the data into
|
|
sedpermtype - Are we getting audit/access info
|
|
pfAuditPrivAdjusted - Set to TRUE if audit priv was enabled.
|
|
Set this to NULL if the privilege has already been adjusted
|
|
|
|
RETURNS: NERR_Success if successful, error code otherwise
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
Johnl 05-Nov-1992 Broke out
|
|
|
|
********************************************************************/
|
|
|
|
APIERR GetSecurity( const TCHAR * pszFileName,
|
|
BUFFER * pbuffSecDescData,
|
|
enum SED_PERM_TYPE sedpermtype,
|
|
BOOL * pfAuditPrivAdjusted )
|
|
{
|
|
OS_SECURITY_INFORMATION osSecInfo ;
|
|
DWORD dwLengthNeeded ;
|
|
APIERR err = NERR_Success ;
|
|
|
|
if ( pfAuditPrivAdjusted )
|
|
*pfAuditPrivAdjusted = FALSE ;
|
|
|
|
do { // error breakout
|
|
if ( (err = pbuffSecDescData->QueryError()) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
switch ( sedpermtype )
|
|
{
|
|
case SED_ACCESSES:
|
|
osSecInfo.SetDACLReference() ;
|
|
//
|
|
// Fall through, we want the owner and group if we are getting
|
|
// the DACL
|
|
//
|
|
|
|
case SED_OWNER:
|
|
osSecInfo.SetOwnerReference() ;
|
|
osSecInfo.SetGroupReference() ;
|
|
break ;
|
|
|
|
case SED_AUDITS:
|
|
osSecInfo.SetSACLReference() ;
|
|
|
|
if ( pfAuditPrivAdjusted != NULL )
|
|
{
|
|
/* We will need to enable the SeAuditPrivilege to read/write the
|
|
* SACL for NT.
|
|
*/
|
|
ULONG ulAuditPriv = SE_SECURITY_PRIVILEGE ;
|
|
if ( err = ::NetpGetPrivilege( 1, &ulAuditPriv ))
|
|
{
|
|
break ;
|
|
}
|
|
*pfAuditPrivAdjusted = TRUE ;
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
UIASSERT(FALSE) ;
|
|
err = ERROR_GEN_FAILURE ;
|
|
break ;
|
|
}
|
|
if ( err )
|
|
break ;
|
|
|
|
//
|
|
// Try once with a 1k buffer, if it doesn't fit then we will try again
|
|
// with the known required size which should succeed unless another
|
|
// error occurs, in which case we bail.
|
|
//
|
|
BOOL fCantRead = FALSE ; // Did we read the ACL?
|
|
PSECURITY_DESCRIPTOR pSecurityDesc = NULL ;
|
|
if (!::GetFileSecurity( (LPTSTR) pszFileName,
|
|
osSecInfo,
|
|
(PSECURITY_DESCRIPTOR)pbuffSecDescData->QueryPtr(),
|
|
pbuffSecDescData->QuerySize(),
|
|
&dwLengthNeeded ))
|
|
{
|
|
err = ::GetLastError() ;
|
|
switch ( err )
|
|
{
|
|
case ERROR_INSUFFICIENT_BUFFER:
|
|
{
|
|
err = pbuffSecDescData->Resize( (UINT) dwLengthNeeded ) ;
|
|
if ( err )
|
|
break ;
|
|
|
|
/* If this guy fails then we bail
|
|
*/
|
|
if (!::GetFileSecurity( (LPTSTR) pszFileName,
|
|
osSecInfo,
|
|
(PSECURITY_DESCRIPTOR)pbuffSecDescData->QueryPtr(),
|
|
pbuffSecDescData->QuerySize(),
|
|
&dwLengthNeeded ))
|
|
{
|
|
err = ::GetLastError() ;
|
|
break ;
|
|
}
|
|
}
|
|
break ;
|
|
|
|
default:
|
|
/* Fall through to the next switch statement which is the error
|
|
* handler for this block
|
|
*/
|
|
break ;
|
|
}
|
|
}
|
|
} while ( FALSE ) ;
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: InitializeNTFSGenericMapping
|
|
|
|
SYNOPSIS: Initializes the passed generic mapping structure
|
|
appropriately depending on whether this is a file
|
|
or a directory.
|
|
|
|
ENTRY: pNTFSGenericMapping - Pointer to GENERIC_MAPPING to be init.
|
|
fIsDirectory - TRUE if directory, FALSE if file
|
|
|
|
EXIT:
|
|
|
|
RETURNS:
|
|
|
|
NOTES: Note that Delete Child was removed from Generic Write.
|
|
|
|
HISTORY:
|
|
Johnl 27-Feb-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
void InitializeNTFSGenericMapping( PGENERIC_MAPPING pNTFSGenericMapping,
|
|
BOOL fIsDirectory )
|
|
{
|
|
UNREFERENCED( fIsDirectory ) ;
|
|
pNTFSGenericMapping->GenericRead = FILE_GENERIC_READ ;
|
|
pNTFSGenericMapping->GenericWrite = FILE_GENERIC_WRITE ;
|
|
pNTFSGenericMapping->GenericExecute = FILE_GENERIC_EXECUTE ;
|
|
pNTFSGenericMapping->GenericAll = FILE_ALL_ACCESS ;
|
|
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ::IsNTFS
|
|
|
|
SYNOPSIS: This function checks the given resource and attempts to
|
|
determine if it points to an NTFS partition.
|
|
|
|
ENTRY: pszResource - Pointer to file/directory name (may be UNC)
|
|
|
|
pfIsNTFS - Pointer to BOOL that will receive the results
|
|
|
|
RETURNS: NERR_Success if successful, error code otherwise
|
|
|
|
NOTES:
|
|
|
|
HISTORY:
|
|
Johnl 08-May-1992 Created
|
|
|
|
********************************************************************/
|
|
|
|
APIERR IsNTFS( const TCHAR * pszResource, BOOL * pfIsNTFS )
|
|
{
|
|
UIASSERT( pszResource != NULL && pfIsNTFS != NULL ) ;
|
|
|
|
*pfIsNTFS = FALSE ;
|
|
APIERR err = NERR_Success ;
|
|
DWORD dwAttributes;
|
|
TCHAR szResourceTemp[2 * MAX_PATH]; // Allow for long computer and share names
|
|
|
|
do { // error breakout
|
|
lstrcpyn( szResourceTemp, pszResource, sizeof(szResourceTemp) / sizeof(TCHAR) );
|
|
|
|
// Strip the path to root form, acceptable to GetVolumeInformation
|
|
if ((szResourceTemp[0] == TEXT('\\')) && (szResourceTemp[1] == TEXT('\\')))
|
|
{
|
|
// It's a UNC path. Find the fourth backslash (if there is
|
|
// one) and truncate after that character
|
|
int cBackslashes = 2;
|
|
TCHAR* pChar = &(szResourceTemp[2]);
|
|
|
|
while ((*pChar) && (cBackslashes < 4))
|
|
{
|
|
if (*pChar == TEXT('\\'))
|
|
{
|
|
cBackslashes++;
|
|
}
|
|
|
|
pChar = CharNext(pChar);
|
|
}
|
|
|
|
if (*pChar)
|
|
{
|
|
*pChar = TEXT('\0');
|
|
}
|
|
else
|
|
{
|
|
// A bogus path was passed in
|
|
err = ERROR_FILE_NOT_FOUND;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// It's a drive-based path. Truncate after the first three
|
|
// characters ("x:\")
|
|
szResourceTemp[3] = TEXT('\0');
|
|
}
|
|
|
|
if ( FALSE == GetVolumeInformation( szResourceTemp,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwAttributes,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
// If we failed because we were denied access, then
|
|
// we can probably assume the filesystem supports ACLs
|
|
if ( GetLastError() == ERROR_ACCESS_DENIED )
|
|
{
|
|
DBGEOL("::IsNTFS - Unable to determine volume information "
|
|
<< " (access denied) assuming the file system is NTFS") ;
|
|
*pfIsNTFS = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Otherwise, set an error code and break out
|
|
err = GetLastError();
|
|
DBGEOL("::IsNTFS - GetVolumeInformation failed with error "
|
|
<< (ULONG) err ) ;
|
|
break;
|
|
}
|
|
|
|
TRACEEOL("::IsNTFS - File system attributes are " << (HEX_STR) dwAttributes ) ;
|
|
|
|
if ( dwAttributes & FS_PERSISTENT_ACLS )
|
|
{
|
|
*pfIsNTFS = TRUE;
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
return err ;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CheckFileSecurity
|
|
|
|
SYNOPSIS: Checks to see if the current user has access to the file or
|
|
directory
|
|
|
|
ENTRY: pszFileName - File or directory name
|
|
DesiredAccess - Access to check for
|
|
pfAccessGranted - Set to TRUE if access was granted
|
|
|
|
RETURNS: NERR_Success if successful, error code otherwise
|
|
|
|
NOTES: If the check requires enabled privileges, they must be enabled
|
|
before this call.
|
|
|
|
HISTORY:
|
|
Johnl 15-Jan-1993 Created
|
|
|
|
********************************************************************/
|
|
|
|
APIERR CheckFileSecurity( const TCHAR * pszFileName,
|
|
ACCESS_MASK DesiredAccess,
|
|
BOOL * pfAccessGranted )
|
|
{
|
|
APIERR err = NERR_Success ;
|
|
*pfAccessGranted = TRUE ;
|
|
|
|
do { // error breakout
|
|
|
|
//
|
|
// Convert the DOS device name ("X:\") to an NT device name
|
|
// (looks something like "\dosdevices\X:\")
|
|
//
|
|
int cbFileName = strlenf( pszFileName ) * sizeof( TCHAR ) ;
|
|
UNICODE_STRING UniStrNtFileName ;
|
|
::memsetf( (PVOID)&UniStrNtFileName, '\0', sizeof(UniStrNtFileName) );
|
|
|
|
if (!RtlDosPathNameToNtPathName_U( pszFileName,
|
|
&UniStrNtFileName,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
UIASSERT( FALSE ) ;
|
|
err = ERROR_NOT_ENOUGH_MEMORY ;
|
|
break ;
|
|
}
|
|
|
|
OBJECT_ATTRIBUTES oa ;
|
|
IO_STATUS_BLOCK StatusBlock ;
|
|
InitializeObjectAttributes( &oa,
|
|
&UniStrNtFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
0,
|
|
0 );
|
|
|
|
|
|
//
|
|
// Check to see if we have permission/privilege to read the security
|
|
//
|
|
HANDLE hFile ;
|
|
if ( (err = ERRMAP::MapNTStatus(::NtOpenFile(
|
|
&hFile,
|
|
DesiredAccess,
|
|
&oa,
|
|
&StatusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
0 ))) )
|
|
{
|
|
|
|
TRACEEOL("CheckFileSecurity - check failed with error " << err <<
|
|
" with desired access " << (HEX_STR) DesiredAccess ) ;
|
|
|
|
if ( err == ERROR_ACCESS_DENIED )
|
|
{
|
|
*pfAccessGranted = FALSE ;
|
|
err = NERR_Success ;
|
|
}
|
|
}
|
|
else
|
|
::NtClose( hFile ) ;
|
|
|
|
if (UniStrNtFileName.Buffer != 0)
|
|
RtlFreeUnicodeString( &UniStrNtFileName );
|
|
|
|
} while ( FALSE ) ;
|
|
|
|
return err ;
|
|
}
|