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.
568 lines
16 KiB
568 lines
16 KiB
/*****************************************************************************/
|
|
|
|
/* Copyright (c) 1999-2001 Microsoft Corporation, All Rights Reserved /
|
|
/*****************************************************************************/
|
|
|
|
|
|
/*
|
|
* SecurityDescriptor.cpp - implementation file for CSecureFile class.
|
|
*
|
|
* Created: 12-14-1997 by Sanjeev Surati
|
|
* (based on classes from Windows NT Security by Nik Okuntseff)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include "AccessEntry.h" // CAccessEntry class
|
|
#include "AccessEntryList.h"
|
|
#include "aclapi.h"
|
|
#include "DACL.h" // CDACL class
|
|
#include "SACL.h" // CSACL class
|
|
|
|
|
|
#include "SecurityDescriptor.h"
|
|
#include "securefile.h"
|
|
#include "tokenprivilege.h"
|
|
#include "ImpLogonUser.h"
|
|
#include "AdvApi32Api.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::CSecureFile
|
|
//
|
|
// Default class constructor.
|
|
//
|
|
// Inputs:
|
|
// None.
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// None.
|
|
//
|
|
// Comments:
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
CSecureFile::CSecureFile()
|
|
: CSecurityDescriptor(),
|
|
m_strFileName()
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::CSecureFile
|
|
//
|
|
// Alternate Class CTOR
|
|
//
|
|
// Inputs:
|
|
// LPCTSTR pszFileName - The FileName to handle
|
|
// security for.
|
|
// BOOL fGetSACL - Should we get the SACL?
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// None.
|
|
//
|
|
// Comments:
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
CSecureFile::CSecureFile( LPCTSTR pszFileName, BOOL fGetSACL /*= TRUE*/ )
|
|
: CSecurityDescriptor(),
|
|
m_strFileName()
|
|
{
|
|
SetFileName( pszFileName );
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::CSecureFile
|
|
//
|
|
// Alternate Class CTOR
|
|
//
|
|
// Inputs:
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// None.
|
|
//
|
|
// Comments:
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
CSecureFile::CSecureFile
|
|
(
|
|
LPCTSTR a_pszFileName,
|
|
CSid* a_psidOwner,
|
|
bool a_fOwnerDefaulted,
|
|
CSid* a_psidGroup,
|
|
bool a_fGroupDefaulted,
|
|
CDACL* a_pDacl,
|
|
bool a_fDaclDefaulted,
|
|
bool a_fDaclAutoInherited,
|
|
CSACL* a_pSacl,
|
|
bool a_fSaclDefaulted,
|
|
bool a_fSaclAutoInherited
|
|
)
|
|
: CSecurityDescriptor(a_psidOwner,
|
|
a_fOwnerDefaulted,
|
|
a_psidGroup,
|
|
a_fGroupDefaulted,
|
|
a_pDacl,
|
|
a_fDaclDefaulted,
|
|
a_fDaclAutoInherited,
|
|
a_pSacl,
|
|
a_fSaclDefaulted,
|
|
a_fSaclAutoInherited)
|
|
{
|
|
m_strFileName = a_pszFileName;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::CSecureFile
|
|
//
|
|
// Alternate Class CTOR
|
|
//
|
|
// Inputs:
|
|
// LPCTSTR pszFileName - The FileName to handle
|
|
// security for.
|
|
//
|
|
// PSECURITY_DESCRIPTOR pSD - The Security Descriptor to associate with this file
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// None.
|
|
//
|
|
// Comments:
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
CSecureFile::CSecureFile( LPCTSTR pszFileName, PSECURITY_DESCRIPTOR pSD )
|
|
: CSecurityDescriptor(),
|
|
m_strFileName()
|
|
{
|
|
if ( InitSecurity( pSD ) )
|
|
{
|
|
m_strFileName = pszFileName;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::~CSecureFile
|
|
//
|
|
// Class Destructor.
|
|
//
|
|
// Inputs:
|
|
// None.
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// None.
|
|
//
|
|
// Comments:
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
CSecureFile::~CSecureFile( void )
|
|
{
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::SetFileName
|
|
//
|
|
// Public Entry point to set which file/directory this instance
|
|
// of the class is to supply security for.
|
|
//
|
|
// Inputs:
|
|
// LPCTSTR pszFileName - The FileName to handle
|
|
// security for.
|
|
// BOOL fGetSACL - Should we get the SACL?
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// DWORD ERROR_SUCCESS if successful
|
|
//
|
|
// Comments:
|
|
//
|
|
// This will clear any previously set filenames and/or security
|
|
// information.
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
DWORD CSecureFile::SetFileName( LPCTSTR pszFileName, BOOL fGetSACL /*= TRUE*/ )
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
SECURITY_INFORMATION siFlags = OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
|
|
|
// GetFileSecurity uses DCOM long logon ids. If we are connected from a remote machine,
|
|
// even though we might be the same user as the local logged on user, the long id will be
|
|
// different, and GetFileSecurity will give an access denied. Hence the following
|
|
// impersonation of the connected user. Note also that this impersonation must be
|
|
// done prior to setting the SE_SECURITY_NAME privilage, otherwise we would set that
|
|
// privilage for one person, then impersonate another, who probably wouldn't have it!
|
|
// This phenomenon can be observed most easily when asking to see an instance of
|
|
// win32_logicalfilesecuritysetting of a root directory of a mapped drive, on a machine
|
|
// that we have remoted into via wbem.
|
|
|
|
#ifdef NTONLY
|
|
// NOTE: THE FOLLOWING PRESENTS A SECURITY BREACH, AND SHOULD BE REMOVED.
|
|
bool fImp = false;
|
|
|
|
CImpersonateLoggedOnUser icu;
|
|
if(icu.Begin())
|
|
{
|
|
fImp = true;
|
|
}
|
|
#endif
|
|
|
|
// We must have the security privilege enabled in order to access the object's SACL
|
|
CTokenPrivilege securityPrivilege( SE_SECURITY_NAME );
|
|
BOOL fDisablePrivilege = FALSE;
|
|
|
|
if ( fGetSACL )
|
|
{
|
|
fDisablePrivilege = ( securityPrivilege.Enable() == ERROR_SUCCESS );
|
|
siFlags |= SACL_SECURITY_INFORMATION;
|
|
}
|
|
|
|
|
|
// Determine the length needed for self-relative SD
|
|
DWORD dwLengthNeeded = 0;
|
|
|
|
BOOL fSuccess = ::GetFileSecurity( pszFileName,
|
|
siFlags,
|
|
NULL,
|
|
0,
|
|
&dwLengthNeeded );
|
|
|
|
dwError = ::GetLastError();
|
|
|
|
// It is possible that the user lacked the permissions required to obtain the SACL,
|
|
// even though we set the token's SE_SECURITY_NAME privilege. So if we obtained an
|
|
// access denied error, try it again, this time without requesting the SACL.
|
|
if(dwError == ERROR_ACCESS_DENIED || dwError == ERROR_PRIVILEGE_NOT_HELD)
|
|
{
|
|
siFlags = OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
|
|
fSuccess = ::GetFileSecurity(pszFileName,
|
|
siFlags,
|
|
NULL,
|
|
0,
|
|
&dwLengthNeeded);
|
|
dwError = ::GetLastError();
|
|
}
|
|
|
|
// The only expected error at this point is insuficient buffer
|
|
if ( !fSuccess && ERROR_INSUFFICIENT_BUFFER == dwError )
|
|
{
|
|
PSECURITY_DESCRIPTOR pSD = NULL;
|
|
try
|
|
{
|
|
pSD = malloc( dwLengthNeeded );
|
|
|
|
if ( NULL != pSD )
|
|
{
|
|
|
|
// Now obtain security descriptor
|
|
if ( ::GetFileSecurity( pszFileName,
|
|
siFlags,
|
|
pSD,
|
|
dwLengthNeeded,
|
|
&dwLengthNeeded ) )
|
|
{
|
|
|
|
dwError = ERROR_SUCCESS;
|
|
|
|
if ( InitSecurity( pSD ) )
|
|
{
|
|
m_strFileName = pszFileName;
|
|
}
|
|
else
|
|
{
|
|
dwError = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
|
|
// free up the security descriptor
|
|
free( pSD );
|
|
|
|
} // IF NULL != pSD
|
|
}
|
|
catch(...)
|
|
{
|
|
if(pSD != NULL)
|
|
{
|
|
free(pSD);
|
|
pSD = NULL;
|
|
}
|
|
throw;
|
|
}
|
|
|
|
} // IF INSUFFICIENTBUFFER
|
|
|
|
// Cleanup the Name Privilege as necessary.
|
|
if ( fDisablePrivilege )
|
|
{
|
|
securityPrivilege.Enable(FALSE);
|
|
}
|
|
|
|
#ifdef NTONLY
|
|
if(fImp)
|
|
{
|
|
icu.End();
|
|
}
|
|
#endif
|
|
|
|
return dwError;
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::WriteAcls
|
|
//
|
|
// Protected entry point called by CSecurityDescriptor when
|
|
// a user Applies Security and wants to apply security for
|
|
// the DACL and/or SACL.
|
|
//
|
|
// Inputs:
|
|
// PSECURITY_DESCRIPTOR pAbsoluteSD - Security
|
|
// descriptor to apply to
|
|
// the file.
|
|
// SECURITY_INFORMATION securityinfo - Flags
|
|
// indicating which ACL(s)
|
|
// to set.
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// DWORD ERROR_SUCCESS if successful
|
|
//
|
|
// Comments:
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
DWORD CSecureFile::WriteAcls( PSECURITY_DESCRIPTOR pAbsoluteSD, SECURITY_INFORMATION securityinfo )
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
// We must have the security privilege enabled in order to access the object's SACL
|
|
|
|
CTokenPrivilege securityPrivilege( SE_SECURITY_NAME );
|
|
BOOL fDisablePrivilege = FALSE;
|
|
|
|
if ( securityinfo & SACL_SECURITY_INFORMATION || securityinfo & PROTECTED_SACL_SECURITY_INFORMATION || securityinfo & UNPROTECTED_SACL_SECURITY_INFORMATION)
|
|
{
|
|
fDisablePrivilege = ( securityPrivilege.Enable() == ERROR_SUCCESS );
|
|
}
|
|
|
|
#if NTONLY >= 5
|
|
// CAdvApi32Api *t_pAdvApi32 = NULL;
|
|
// CActrl t_actrlAccess;
|
|
// CActrl t_actrlAudit;
|
|
//
|
|
//
|
|
// if((dwError = ConfigureActrlAudit(t_actrlAudit, pAbsoluteSD)) == ERROR_SUCCESS && (dwError = ConfigureActrlAccess(t_actrlAccess, pAbsoluteSD)) == ERROR_SUCCESS)
|
|
// {
|
|
// t_pAdvApi32 = (CAdvApi32Api*) CResourceManager::sm_TheResourceManager.GetResource(g_guidAdvApi32Api, NULL);
|
|
// if(t_pAdvApi32 != NULL)
|
|
// {
|
|
// t_pAdvApi32->SetNamedSecurityInfoEx(m_strFileName,
|
|
// SE_FILE_OBJECT,
|
|
// securityinfo,
|
|
// NULL,
|
|
// t_actrlAccess,
|
|
// t_actrlAudit,
|
|
// NULL, //owner (not specified in securityinfo)
|
|
// NULL, //group (not specified in securityinfo)
|
|
// NULL, //callback function
|
|
// &dwError);
|
|
// CResourceManager::sm_TheResourceManager.ReleaseResource(g_guidAdvApi32Api, t_pAdvApi32);
|
|
// t_pAdvApi32 = NULL;
|
|
// }
|
|
// }
|
|
|
|
// This is new new and improved (hah!) NT5 way. The following is more efficient (although more lines of
|
|
// code in *this* module) than making use of our CSecurityDescriptor class to extract all this stuff.
|
|
|
|
// Need to see if the control flags specify dacl/sacl protection. If so, impacts what we set in the securityinfo structure.
|
|
|
|
|
|
// NEXT FEW LINES AND RELATED LINES NOT REQUIRED AS THE NEW APPROACH, WITH THE NEW PROTECTED_DACL_SECURITY_INFORMATION flag in the SECURITY_INFORMATION
|
|
// structure is to not have to, ever, touch or get the control flags (hence, for instance, the call to SetSecurityDescriptorControl in SecurityDescriptor.cpp
|
|
// is now superfluous.
|
|
//
|
|
// SECURITY_DESCRIPTOR_CONTROL Control;
|
|
// DWORD dwRevision = 0;
|
|
//
|
|
// if(GetSecurityDescriptorControl(pAbsoluteSD, &Control, &dwRevision))
|
|
// {
|
|
// // We got the control structure; now see about dacl/sacl protection, and alter securityinfo accordingly...
|
|
// if(Control & SE_DACL_PROTECTED)
|
|
// {
|
|
// securityinfo |= PROTECTED_DACL_SECURITY_INFORMATION;
|
|
// }
|
|
// if(Control & SE_SACL_PROTECTED)
|
|
// {
|
|
// securityinfo |= PROTECTED_SACL_SECURITY_INFORMATION;
|
|
// }
|
|
|
|
PACL pDACL = NULL;
|
|
BOOL fDACLPresent = FALSE;
|
|
BOOL fDACLDefaulted = FALSE;
|
|
// Need to get the PDACL and PSACL if they exist...
|
|
if(::GetSecurityDescriptorDacl(pAbsoluteSD, &fDACLPresent, &pDACL, &fDACLDefaulted))
|
|
{
|
|
PACL pSACL = NULL;
|
|
BOOL fSACLPresent = FALSE;
|
|
BOOL fSACLDefaulted = FALSE;
|
|
if(::GetSecurityDescriptorSacl(pAbsoluteSD, &fSACLPresent, &pSACL, &fSACLDefaulted))
|
|
{
|
|
// Now need the owner...
|
|
PSID psidOwner = NULL;
|
|
BOOL bTemp;
|
|
if(::GetSecurityDescriptorOwner(pAbsoluteSD, &psidOwner, &bTemp))
|
|
{
|
|
PSID psidGroup = NULL;
|
|
// Now need the group...
|
|
if(::GetSecurityDescriptorGroup(pAbsoluteSD, &psidGroup, &bTemp))
|
|
{
|
|
dwError = ::SetNamedSecurityInfo((LPWSTR)(LPCWSTR)m_strFileName,
|
|
SE_FILE_OBJECT,
|
|
securityinfo,
|
|
psidOwner,
|
|
psidGroup,
|
|
pDACL,
|
|
pSACL);
|
|
}
|
|
else // couldn't get group
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
}
|
|
else // couldn't get owner
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
} // couldn't get sacl
|
|
else
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
} // couldn't get dacl
|
|
else
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
// } // couldn't get control
|
|
// else
|
|
// {
|
|
// dwError = ::GetLastError();
|
|
// }
|
|
|
|
|
|
#else
|
|
|
|
if(!::SetFileSecurity(TOBSTRT(m_strFileName),
|
|
securityinfo,
|
|
pAbsoluteSD))
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
// Cleanup the Name Privilege as necessary.
|
|
if ( fDisablePrivilege )
|
|
{
|
|
securityPrivilege.Enable(FALSE);
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Function: CSecureFile::WriteOwner
|
|
//
|
|
// Protected entry point called by CSecurityDescriptor when
|
|
// a user Applies Security and wants to apply security for
|
|
// the owner.
|
|
//
|
|
// Inputs:
|
|
// PSECURITY_DESCRIPTOR pAbsoluteSD - Security
|
|
// descriptor to apply to
|
|
// the file.
|
|
//
|
|
// Outputs:
|
|
// None.
|
|
//
|
|
// Returns:
|
|
// DWORD ERROR_SUCCESS if successful
|
|
//
|
|
// Comments:
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
DWORD CSecureFile::WriteOwner( PSECURITY_DESCRIPTOR pAbsoluteSD )
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
#if NTONLY >= 5
|
|
SECURITY_INFORMATION securityinfo = OWNER_SECURITY_INFORMATION;
|
|
PSID psidOwner = NULL;
|
|
BOOL bTemp;
|
|
if(::GetSecurityDescriptorOwner(pAbsoluteSD, &psidOwner, &bTemp))
|
|
{
|
|
dwError = ::SetNamedSecurityInfo((LPWSTR)(LPCWSTR)m_strFileName,
|
|
SE_FILE_OBJECT,
|
|
securityinfo,
|
|
psidOwner,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
#else
|
|
// Open with the appropriate access, set the security and leave
|
|
if ( !::SetFileSecurity(TOBSTRT(m_strFileName),
|
|
OWNER_SECURITY_INFORMATION,
|
|
pAbsoluteSD))
|
|
{
|
|
dwError = ::GetLastError();
|
|
}
|
|
#endif
|
|
return dwError;
|
|
}
|
|
|
|
DWORD CSecureFile::AllAccessMask( void )
|
|
{
|
|
// File specific All Access Mask
|
|
return FILE_ALL_ACCESS;
|
|
}
|