我们编写服务程序的时候可能会创建具名内核对象如互斥量, 信号量, 事件, 文件映射, 等等, 然后, 这个有名字的内核对象可能在某一个具体的用户账号内运行的程序被访问到, 甚至是受限的用户帐户内运行的程序. 这时就会出现创建不了该具名内核对象的现象, 错误码为 "拒绝访问".
经过反复查阅资料, 我给出一个解决方案, 就是在创建内核对象之前, 先创建一个属于 everyone 群组的权限为完全控制的安全描述符, 然后将这个安全描述符作为创建内核对象的函数的必须的参数传入. 这样, 整个正在运行的操作系统的任何进程都能访问这个内核对象了.
代码如下:
typedef struct SDSTUFF
{
PSID psidEveryone;
PACL pDACL;
PSECURITY_DESCRIPTOR pSD;
} SDSTUFF;
typedef union _ACE_UNION{
ACE_HEADER aceHeader;
ACCESS_ALLOWED_ACE aceAllowed;
ACCESS_DENIED_ACE aceDenied;
SYSTEM_AUDIT_ACE aceAudit;
} * PACE_UNION;
ULONG CalculateACLSize(PACL pACLOld, PSID* ppSidArray, int nNumSids, PACE_UNION * ppACEs, int nNumACEs);
EXTERN_C BOOL CreateEveryoneSD(OUT SDSTUFF * pSDStuff)
{
BOOL bResult = FALSE;
PSID psidArray[2] = { 0 };
ULONG lACLSize = 0;
do
{
// 为内建的 Everyone 群组建立一个 SID
SID_IDENTIFIER_AUTHORITY sidAuth = SECURITY_WORLD_SID_AUTHORITY;
if (NULL == pSDStuff) {
break;
}
if (!AllocateAndInitializeSid( &sidAuth, 1, SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &pSDStuff->psidEveryone ))
{
break;
}
// 我们建立两个ACEs,两者都使用 Everyone 群组
psidArray[0] = pSDStuff->psidEveryone;
psidArray[1] = pSDStuff->psidEveryone;
// 取得新ACL的大小
lACLSize = CalculateACLSize(NULL, psidArray, 2, NULL, 0);
if (0 == lACLSize){
break;
}
// 分配内存给ACL
pSDStuff->pDACL = (PACL)HeapAlloc(GetProcessHeap(), 0, lACLSize);
if (pSDStuff->pDACL == NULL){
break;
}
// 初始化ACL
if (!InitializeAcl(pSDStuff->pDACL, lACLSize, ACL_REVISION)){
break;
}
// 加入允许的ACE
if (!AddAccessAllowedAce(pSDStuff->pDACL, ACL_REVISION,
STANDARD_RIGHTS_ALL|SPECIFIC_RIGHTS_ALL, psidArray[1]))
{
GetLastError(); //错误
break;
}
// 分配空间给安全描述项
pSDStuff->pSD = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
if (pSDStuff->pSD == NULL){
break;
}
// 我们现在有一个空的安全描述项
if (!InitializeSecurityDescriptor(pSDStuff->pSD, SECURITY_DESCRIPTOR_REVISION)) {
break;
}
// 我们的 DACL
if (!SetSecurityDescriptorDacl(pSDStuff->pSD, TRUE, pSDStuff->pDACL, FALSE)) {
break;
}
bResult = TRUE;
} while(FALSE);
return bResult;
}
EXTERN_C BOOL ClearupEveryoneSD(IN SDSTUFF stSDStuff)
{
// 清除
HeapFree(GetProcessHeap(), 0, stSDStuff.pSD);
HeapFree(GetProcessHeap(), 0, stSDStuff.pDACL);
FreeSid(stSDStuff.psidEveryone);
return TRUE;
}
ULONG CalculateACLSize(PACL pACLOld, PSID* ppSidArray, int nNumSids, PACE_UNION* ppACEs, int nNumACEs)
{
ULONG lACLSize = 0;
do
{
// 假如我们包括一个现存的 ACL, 那么找出它的大小
if (pACLOld != NULL){
ACL_SIZE_INFORMATION aclSize = { 0 };
if(!GetAclInformation(pACLOld, &aclSize, sizeof(aclSize), AclSizeInformation)){
break;
}
lACLSize = aclSize.AclBytesInUse;
}
if (ppSidArray != NULL) {
// 逐步浏览每个SID
while (nNumSids--) {
// 假如SID无效, 那么就跳出
if (!IsValidSid(ppSidArray[nNumSids])) {
lACLSize = 0;
break;
}
// 取得 SID 的长度
lACLSize += GetLengthSid(ppSidArray[nNumSids]);
// 加入ACE 结构大小, 减去 SidStart 成员的大小
lACLSize += sizeof(ACCESS_ALLOWED_ACE) - sizeof(((ACCESS_ALLOWED_ACE*)0)->SidStart);
}
if(0 == lACLSize) { break; }
}
if (ppACEs != NULL) {
// 逐步浏览每个ACE
while (nNumACEs--){
// 取得SIDs长度
lACLSize += ppACEs[nNumACEs]->aceHeader.AceSize;
}
}
// 加入 ACL 结构本身
lACLSize += sizeof(ACL);
} while (FALSE);
return (lACLSize);
}
希望这段代码能对被同样问题困扰的人有所帮助. 对它的使用极其简单:
SECURITY_ATTRIBUTES sa = {0};
SDSTUFF stSDStuff = { 0 };
CreateEveryoneSD(&stSDStuff);
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = stSDStuff.pSD;
g_hMap = CreateFileMapping(INVALID_HANDLE_VALUE, // Current file handle.
&sa, // Default security.
PAGE_READWRITE, // Read/write permission.
0, // Max. object size.
ulCodeLen, // Size of hFile.
"xxxxxxxxxxxxxxxxxxxxxxx"); // Name of mapping object.
ClearupEveryoneSD(stSDStuff);
posted on 2008-07-30 09:23
free2000fly 阅读(1515)
评论(0) 编辑 收藏 引用