在某些场景下,需要判断当前程序对某文件或文件夹是否写权限。比如没有管理员权限,是不能向系统敏感路径(比如C:\Windows\System32、C:\Program Files等)创建文件或者改写这些路径中的文件。
我们可以通过以下代码判断对目标文件或者文件夹是否有写权限:
// 将要检测的权限GENERIC_XXXXXX传递给dwGenericAccessMask,可检测对
// 文件或者文件夹的权限
BOOL CanAccessFile( CUIString strPath, DWORD dwGenericAccessMask )
{
CUIString strLog;
strLog.Format( _T("[CanAccessFile]strPath: %s, dwGenericAccessMask: %d"), strPath, dwGenericAccessMask );
WriteUpdateLog( strLog );
DWORD dwSize = 0;
PSECURITY_DESCRIPTOR psd = NULL;
SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
WriteUpdateLog( _T("[CanAccessFile]GetFileSecurity - NULL") );
// 获取文件权限信息结构体大小
BOOL bRet = GetFileSecurity( strPath, si, psd, 0, &dwSize );
if ( bRet || GetLastError() != ERROR_INSUFFICIENT_BUFFER )
{
strLog.Format( _T("[CanAccessFile]GetFileSecurity - NULL failed, GetLastError: %d"), GetLastError() );
WriteUpdateLog( strLog );
return FALSE;
}
char* pBuf = new char[dwSize];
ZeroMemory( pBuf, dwSize );
psd = (PSECURITY_DESCRIPTOR)pBuf;
strLog.Format( _T("[CanAccessFile]GetFileSecurity - dwSize: %d"), dwSize );
WriteUpdateLog( strLog );
// 获取文件权限信息结构体大小
bRet = GetFileSecurity( strPath, si, psd, dwSize, &dwSize );
if ( !bRet )
{
strLog.Format( _T("[CanAccessFile]GetFileSecurity - dwSize failed, GetLastError: %d"), GetLastError() );
WriteUpdateLog( strLog );
delete []pBuf;
return FALSE;
}
WriteUpdateLog( _T("[CanAccessFile]OpenProcessToken") );
HANDLE hToken = NULL;
if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken ) )
{
strLog.Format( _T("[CanAccessFile]OpenProcessToken failed, GetLastError: %d"), GetLastError() );
WriteUpdateLog( strLog );
delete []pBuf;
return FALSE;
}
WriteUpdateLog( _T("[CanAccessFile]DuplicateToken") );
// 模拟令牌
HANDLE hImpersonatedToken = NULL;
if( !DuplicateToken( hToken, SecurityImpersonation, &hImpersonatedToken ) )
{
strLog.Format( _T("[CanAccessFile]DuplicateToken failed, GetLastError: %d"), GetLastError() );
WriteUpdateLog( strLog );
delete []pBuf;
CloseHandle( hToken );
return FALSE;
}
WriteUpdateLog( _T("[CanAccessFile]MapGenericMask") );
// 在检测是否有某个权限时,将GENERIC_WRITE等值传给本函数的第二个参数dwGenericAccessMask
// GENERIC_WRITE等参数在调用CreateFile创建文件时会使用到,下面调用MapGenericMask将
// GENERIC_WRITE等转换成FILE_GENERIC_WRITE等
// 将GENERIC_XXXXXX转换成FILE_GENERIC_XXXXXX
GENERIC_MAPPING genMap;
genMap.GenericRead = FILE_GENERIC_READ;
genMap.GenericWrite = FILE_GENERIC_WRITE;
genMap.GenericExecute = FILE_GENERIC_EXECUTE;
genMap.GenericAll = FILE_ALL_ACCESS;
MapGenericMask( &dwGenericAccessMask, &genMap );
WriteUpdateLog( _T("[CanAccessFile]AccessCheck") );
// 调用AccessCheck来检测是否有指定的权限
PRIVILEGE_SET privileges = { 0 };
DWORD dwGrantedAccess = 0;
DWORD privLength = sizeof(privileges);
BOOL bGrantedAccess = FALSE;
if( AccessCheck( psd, hImpersonatedToken, dwGenericAccessMask,
&genMap, &privileges, &privLength, &dwGrantedAccess, &bGrantedAccess ) )
{
strLog.Format( _T("[CanAccessFile]AccessCheck succeed, dwGenericAccessMask: %d, dwGrantedAccess: %d, bGrantedAccess: %d, "),
dwGenericAccessMask, dwGrantedAccess, bGrantedAccess );
WriteUpdateLog( strLog );
if ( bGrantedAccess )
{
if ( dwGenericAccessMask == dwGrantedAccess )
{
bGrantedAccess = TRUE;
}
else
{
bGrantedAccess = FALSE;
}
}
else
{
bGrantedAccess = FALSE;
}
}
else
{
strLog.Format( _T("[CanAccessFile]AccessCheck failed, GetLastError: %d"), GetLastError() );
WriteUpdateLog( strLog );
bGrantedAccess = FALSE;
}
strLog.Format( _T("[CanAccessFile]bGrantedAccess: %d"), bGrantedAccess );
WriteUpdateLog( strLog );
delete []pBuf;
CloseHandle( hImpersonatedToken );
CloseHandle( hToken );
return bGrantedAccess;
}
比如我们判断当前程序对C:\Windows\System32路径是否有写权限,可以这样来调回上面封装的函数:
BOOL bCanWrite = CanAccessFile( _T("C:\\Windows\\System32"), GENERIC_WRITE );
第二个参数传入GENERIC_WRITE即可。