我們編寫服務(wù)程序的時候可能會創(chuàng)建具名內(nèi)核對象如互斥量, 信號量, 事件, 文件映射, 等等, 然后, 這個有名字的內(nèi)核對象可能在某一個具體的用戶賬號內(nèi)運行的程序被訪問到, 甚至是受限的用戶帳戶內(nèi)運行的程序. 這時就會出現(xiàn)創(chuàng)建不了該具名內(nèi)核對象的現(xiàn)象, 錯誤碼為 "拒絕訪問".
經(jīng)過反復(fù)查閱資料, 我給出一個解決方案, 就是在創(chuàng)建內(nèi)核對象之前, 先創(chuàng)建一個屬于 everyone 群組的權(quán)限為完全控制的安全描述符, 然后將這個安全描述符作為創(chuàng)建內(nèi)核對象的函數(shù)的必須的參數(shù)傳入. 這樣, 整個正在運行的操作系統(tǒng)的任何進程都能訪問這個內(nèi)核對象了.
代碼如下:
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
{
// 為內(nèi)建的 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;
}
// 分配內(nèi)存給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;
}
// 我們現(xiàn)在有一個空的安全描述項
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
{
// 假如我們包括一個現(xiàn)存的 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 結(jié)構(gòu)大小, 減去 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 結(jié)構(gòu)本身
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 閱讀(1518)
評論(0) 編輯 收藏 引用