精通
英语
和
开源
,
擅长
开发
与
培训
,
胸怀四海
第一信赖
The result should be a table with three columns: SID, (deny | allow | audit | alarm) inheritance, and ACCESS_MASK.
If the ACL is a system access control list, you would not get allow / deny entries. Instead you will audit / alarm entries in the SACL. To make your walker function read from SACLs as well as DACLs, extend your walker to handle the audit and alarm ACE structs (the walker function given in the sample code can handle SACLs equally as well as DACLs).如果ACL是系统访问控制列表,则不会获得允许/拒绝条目。相反,您将在SACL中审核/警报条目。为了使您的助手功能可以从SACL和DACL中读取,请扩展助手以处理审计和警报ACE struct(示例代码中给出的助手功能可以与DACL一样处理SACL)。
void ReadDacl(const ATL::CDacl &pDacl)
{
UINT i = 0;
for(i = 0; i < pDacl.GetAceCount(); i++)
{
ATL::CSid pSid;
ACCESS_MASK pMask = 0;
BYTE pType = 0, pFlags = 0;
const_cast(pDacl).GetAclEntry
(i, &pSid, &pMask, &pType, &pFlags);
std::wcout << pSid.AccountName() << _T(": ");
switch (pType)
{
case ACCESS_ALLOWED_ACE_TYPE:
std::wcout << _T("allow");
break;
case ACCESS_DENIED_ACE_TYPE:
std::wcout << _T("deny");
break;
case SYSTEM_AUDIT_ACE_TYPE:
std::wcout << _T("audit");
break;
case SYSTEM_ALARM_ACE_TYPE:
std::wcout << _T("alarm");
break;
/* ... TODO: Repeat for the other structures */
default:
std::wcout << _T("Unknown");
break;
}
std::wcout << _T(": ");
if(pFlags & INHERITED_ACE)
std::wcout << _T("Inherited: ");
std::wcout << std::hex <<
pMask << std::dec << std::endl;
}
std::wcout << std::endl;
}
Figure 18: Reading and printing a discretionary access control list.
A naive implementation of this would be to look up your username in the security descriptor and directly check which accesses are granted and which are denied (GetEffectiveRightsFromAcl() can help). There are two problems using this technique.
一个简单的实现是在安全描述符中查找您的用户名,并直接检查哪些访问被授予和拒绝(GetEffectiveRightsFromAcl()可以提供帮助)。使用此技术存在两个问题。
The only reliable way of checking this is to actually perform the action (i.e. open the file and read it). If you succeed, you are granted access. If you fail with an error 5, you are denied access. However, if you really must...唯一可靠的检查方法是实际执行操作(即打开文件并读取文件)。如果成功,则将授予您访问权限。如果失败并显示错误5,则将拒绝访问。但是,如果您真的必须...
To check if a security descriptor grants you access, you require a call to the AccessCheck() API. The AccessCheck() API is a simplified form of the AccessCheckByTypeResultListAndAuditAlarmByHandle() API. The AccessCheckByTypeResultListAndAuditAlarmByHandle() forms the heart of the entire Windows Access Control Model. All the security APIs and objects are just a way to configure the behaviour of this little API (okay, maybe not so little!). But for our purposes, AccessCheck() should suffice. AccessCheck() may at first sight seem intimidating, but if you look at it closely, it just takes in three parameters, the security descriptor, You (your thread token), and what action you desire (the wanted access mask). The rest of AccessCheck() are just Out parameters.要检查安全描述符是否授予您访问权限,您需要调用AccessCheck()API。该AccessCheck()API是一个简化形式AccessCheckByTypeResultListAndAuditAlarmByHandle()的API。这些AccessCheckByTypeResultListAndAuditAlarmByHandle()表格构成了整个Windows访问控制模型的核心。所有安全性API和对象只是配置此小型API行为的一种方式(好的,也许不是那么少!)。但就我们的目的而言,AccessCheck()应该足够了。AccessCheck()乍看之下似乎有些令人生畏,但如果仔细观察,它只需要三个参数,即安全描述符,You(您的线程令牌)和所需的操作(所需的访问掩码)。其余的AccessCheck()只是Out参数。
You'd think that Windows can make it easier for you by making these three parameters optional. Why can't AccessCheck() just get the current thread token as default, then you pass in the filename, and AccessCheck() will look up its security descriptor itself. That's just one In parameter. Oh wait, that's just CreateFile()! That leads us back to what we first said.
您可能会认为Windows通过使这三个参数为可选可以使您更轻松。为什么AccessCheck()不能仅将当前线程令牌作为默认值,然后传入文件名,然后AccessCheck()查找其安全描述符本身。那只是一个In参数。哦,等等,就是这样CreateFile()!这使我们回到了我们最初所说的话。
Actually, AccessCheck() requires you to supply a fourth parameter, the GENERIC_MAPPING structure. This structure maps the object specific ACLs (like GENERIC_READ) into object specific rights (like FILE_GENERIC_READ). The reason why AccessCheck() needs a GENERIC_MAPPING is because it makes a call to the AreAllAccessesGranted() function, and this requires you to supply a GENERIC_MAPPING structure. Larry Osterman offers a more complete reason why the GENERIC_MAPPING is required.
实际上,AccessCheck()需要您提供第四个参数,即GENERIC_MAPPING结构。此结构将特定于对象的ACL(如GENERIC_READ)映射到特定于对象的权限(如FILE_GENERIC_READ)。AccessCheck()需要GENERIC_MAPPING的原因是因为它调用了AreAllAccessesGranted()函数,并且这需要您提供GENERIC_MAPPING结构。拉里·奥斯特曼(Larry Osterman) 提供了要求使用的更完整的原因GENERIC_MAPPING。
As was discussed in part 1, it is possible to make the access check yourself. The ten steps involved were:如第1部分所述,可以自己进行访问检查。涉及的十个步骤是:
To compare two ACCESS_MASKs, simply NOT one of the ACCESS_MASKs, then AND the two variables together. The result should be zero if you are granted access, otherwise you should be denied. Or you can make a call to AreAllAccessesGranted() to help you. (This API has the advantage of helping you fix-up generic access rights.)要比较两个ACCESS_MASKs,只需NOT之一,然后AND两个变量一起即可。如果您被授予访问权限,则结果应为零,否则应被拒绝。或者,您可以致电AreAllAccessesGranted()寻求帮助。(此API的优点是可以帮助您修复通用访问权限。)
You could perform the 11 above steps, or you can use the AccessCheck() provided function. There isn't anything special that Windows 2000 or ATL provides to make this task easier; this technique is the same for all operating systems.
您可以执行上述11个步骤,也可以使用AccessCheck()提供的功能。Windows 2000或ATL并没有提供任何使此任务更容易的特殊功能。对于所有操作系统,此技术都是相同的。
{
ATL::CAccessToken ProcToken, ImpersonationToken;
ProcToken.GetEffectiveToken(TOKEN_QUERY |
TOKEN_DUPLICATE | TOKEN_IMPERSONATE);
ProcToken.CreateImpersonationToken(&ImpersonationToken);
{
BOOL AccessStatus = FALSE;
DWORD GrantedAccess = 0, PrivilegeSetLength = 0,
DesiredAccess = FILE_GENERIC_WRITE;
GENERIC_MAPPING GenericMapping =
{
READ_CONTROL | FILE_READ_DATA |
FILE_READ_ATTRIBUTES | FILE_READ_EA,
FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |
FILE_WRITE_DATA | FILE_APPEND_DATA,
READ_CONTROL | FILE_READ_ATTRIBUTES |
FILE_EXECUTE,
FILE_ALL_ACCESS
} ;
::AccessCheck(const_cast
(OutSecDesc.GetPSECURITY_DESCRIPTOR()),
ImpersonationToken.GetHandle(), DesiredAccess, &GenericMapping,
NULL, &PrivilegeSetLength,
&GrantedAccess, &AccessStatus);
ATL::CAutoVectorPtr PrivilegeSet
(new BYTE[PrivilegeSetLength]);
::AccessCheck(const_cast
(OutSecDesc.GetPSECURITY_DESCRIPTOR()),
ImpersonationToken.GetHandle(), DesiredAccess,
&GenericMapping, reinterpret_cast
(static_cast(PrivilegeSet)),
&PrivilegeSetLength, &GrantedAccess,
&AccessStatus);
if(AccessStatus == TRUE)
{
std::wcout << std::hex <<
GrantedAccess==DesiredAccess << std::dec;
}
}
}
Figure 19: Verifying if a security descriptor grants you access to an object
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州市文化路47号院1号楼4层(47-1楼位于文化路和红专路十字路口东北角,郑州大学工学院招待所南边,工学院科技报告厅西边。)