本文说明如何构造安全描述符,以授予给定组对内核对象的访问权限,使该对象能够在以不同用户帐户运行的进程之间共享。
更多信息
有时,服务必须创建可由运行在不同用户帐户下的进程访问的内核对象。要允许以这种方式共享对象,服务必须使用明确授权用户对象访问权限的安全描述符来创建对象。或者,安全描述符可以授予对整个用户组的访问权限。
本文中的示例代码非常特定,因为它授予经过身份验证的用户 组对互斥体的访问权限。这段代码使用了大量的安全 API 来构造互斥体的安全描述符。有关这些安全函数的完整文档,请参阅 MSDN Library 中 Platform SDK 文档的“Access Control”(访问控制)部分:您必须完全了解这些调用(通常情况下还包括访问控制技术),以便针对其他用户、组和内核对象改编代码。
出于说明目的,此示例代码使用了通用访问权限。这些通用权限利用了可用于所有内核对象的通用映射。在实际的应用程序中,创建对象时最好使用对象特定的访问权限。
给定的资源管理器在映射到对象特定的访问权限时,可能会解释给定的通用权限集,以包括其他标准访问权限。例如,为互斥体指定 GENERIC_READ、GENERIC_WRITE 和 GENERIC_EXECUTE 权限相当于指定对象特定的权限 MUTEX_MODIFY_STATE 和 SYNCHRONIZE。因此,其他线程要想获得互斥体的句柄,只能通过在 OpenMutex() 中为 dwDesiredAccess 参数指定 MUTEX_MODIFY_STATE 和/或 SYNCHRONIZE。使用 MUTEX_ALL_ACCESS 打开互斥体的尝试将失败,并显示错误代码 5 (ERROR_ACCESS_DENIED)。
本文中的示例代码非常特定,因为它授予经过身份验证的用户 组对互斥体的访问权限。这段代码使用了大量的安全 API 来构造互斥体的安全描述符。有关这些安全函数的完整文档,请参阅 MSDN Library 中 Platform SDK 文档的“Access Control”(访问控制)部分:您必须完全了解这些调用(通常情况下还包括访问控制技术),以便针对其他用户、组和内核对象改编代码。
示例代码
以下示例代码说明了如何构造安全描述符,以授予经过身份验证的用户 组 GENERIC_READ、GENERIC_WRITE 和 GENERIC_EXECUTE 权限。新构造的安全描述符随即应用于互斥体。出于说明目的,此示例代码使用了通用访问权限。这些通用权限利用了可用于所有内核对象的通用映射。在实际的应用程序中,创建对象时最好使用对象特定的访问权限。
给定的资源管理器在映射到对象特定的访问权限时,可能会解释给定的通用权限集,以包括其他标准访问权限。例如,为互斥体指定 GENERIC_READ、GENERIC_WRITE 和 GENERIC_EXECUTE 权限相当于指定对象特定的权限 MUTEX_MODIFY_STATE 和 SYNCHRONIZE。因此,其他线程要想获得互斥体的句柄,只能通过在 OpenMutex() 中为 dwDesiredAccess 参数指定 MUTEX_MODIFY_STATE 和/或 SYNCHRONIZE。使用 MUTEX_ALL_ACCESS 打开互斥体的尝试将失败,并显示错误代码 5 (ERROR_ACCESS_DENIED)。
#include <windows.h>
#include <stdio.h>
// The following function initializes the supplied security descriptor
// with a DACL that grants the Authenticated Users group GENERIC_READ,
// GENERIC_WRITE, and GENERIC_EXECUTE access.
//
// The function returns NULL if any of the access control APIs fail.
// Otherwise, it returns a PVOID pointer that should be freed by calling
// FreeRestrictedSD() after the security descriptor has been used to
// create the object.
PVOID BuildRestrictedSD(PSECURITY_DESCRIPTOR pSD) {
DWORD dwAclLength;
PSID pAuthenticatedUsersSID = NULL;
PACL pDACL = NULL;
BOOL bResult = FALSE;
PACCESS_ALLOWED_ACE pACE = NULL;
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
__try {
// initialize the security descriptor
if (!InitializeSecurityDescriptor(pSD,
SECURITY_DESCRIPTOR_REVISION)) {
printf("InitializeSecurityDescriptor() failed with error %d\n",
GetLastError());
__leave;
}
// obtain a sid for the Authenticated Users Group
if (!AllocateAndInitializeSid(&siaNT, 1,
SECURITY_AUTHENTICATED_USER_RID, 0, 0, 0, 0, 0, 0, 0,
&pAuthenticatedUsersSID)) {
printf("AllocateAndInitializeSid() failed with error %d\n",
GetLastError());
__leave;
}
// NOTE:
//
// The Authenticated Users group includes all user accounts that
// have been successfully authenticated by the system. If access
// must be restricted to a specific user or group other than
// Authenticated Users, the SID can be constructed using the
// LookupAccountSid() API based on a user or group name.
// calculate the DACL length
dwAclLength = sizeof(ACL)
// add space for Authenticated Users group ACE
+ sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)
+ GetLengthSid(pAuthenticatedUsersSID);
// allocate memory for the DACL
pDACL = (PACL) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
dwAclLength);
if (!pDACL) {
printf("HeapAlloc() failed with error %d\n", GetLastError());
__leave;
}
// initialize the DACL
if (!InitializeAcl(pDACL, dwAclLength, ACL_REVISION)) {
printf("InitializeAcl() failed with error %d\n",
GetLastError());
__leave;
}
// add the Authenticated Users group ACE to the DACL with
// GENERIC_READ, GENERIC_WRITE, and GENERIC_EXECUTE access
if (!AddAccessAllowedAce(pDACL, ACL_REVISION,
GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
pAuthenticatedUsersSID)) {
printf("AddAccessAllowedAce() failed with error %d\n",
GetLastError());
__leave;
}
// set the DACL in the security descriptor
if (!SetSecurityDescriptorDacl(pSD, TRUE, pDACL, FALSE)) {
printf("SetSecurityDescriptorDacl() failed with error %d\n",
GetLastError());
__leave;
}
bResult = TRUE;
} __finally {
if (pAuthenticatedUsersSID) FreeSid(pAuthenticatedUsersSID);
}
if (bResult == FALSE) {
if (pDACL) HeapFree(GetProcessHeap(), 0, pDACL);
pDACL = NULL;
}
return (PVOID) pDACL;
}
// The following function frees memory allocated in the
// BuildRestrictedSD() function
VOID FreeRestrictedSD(PVOID ptr) {
if (ptr) HeapFree(GetProcessHeap(), 0, ptr);
return;
}
void main(void)
{
SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;
PVOID ptr;
HANDLE hMutex;
// build a restricted security descriptor
ptr = BuildRestrictedSD(&sd);
if (!ptr) {
printf("BuildRestrictedSD() failed\n");
return;
}
// create a mutex using the security descriptor
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = &sd;
sa.bInheritHandle = FALSE;
hMutex = CreateMutex(&sa, FALSE, "RestrictedMutex");
if (!hMutex)
printf("CreateMutex() failed with error %d\n", GetLastError());
// free the memory allocated by BuildRestrictedSD
FreeRestrictedSD(ptr);
// use the mutex ...
printf("Press the return key to close the mutex handle...\n");
getchar();
// close the mutex handle
CloseHandle(hMutex);
}