|
|
/*****************************************************************************/
/* 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; }
|