Windows2000 服务器端应用程序开发设计指南-存取控制(3)

表10-7 安全对象的特定安全函数

尽管表10-7中每个对象的建立对象函数不同,只有少数的函数被要求设定及取得系统中所有安全对象类型的安全性资讯。


 

说明

有为特定对象类型取得及设定安全性的其他函数,例如GetFileSecurity及SetKernelObjectSecurity。然而,由于GetFileSecurity及SetKernelObjectSecurity等函数变得更容易使用,而且在Windows 2000中提供了更多完整的继承模组实作对象,使得特定函数不再是取得及设定对象安全性的惯用方式。可能的话,您应该使用这些函数。


 

读取对象的安全性资讯

 

只有 读取 对象的安全性资讯不为常见的任务,通常您会执行它,如此您就可以使用某些方法去修改安全性。然而,了解如何读取对象的安全性会大大地简化更多修改对象安全性的常见工作,所以我们在这里讨论这个主题。

您可能会猜想到并非每个人都可以读取对象的安全性。就像其他在安全对象上执行的任务一般,读取其本身安全性资讯的能力是安全的。为了要达成读取安全性资讯的目的,以下所列条件的其中一或两个必须为真:

  1. 您是这个对象的拥有者。
  2. 对象之DACL中的ACE或者您所属的群组,授予您READ_CONTROL标准权利(请参阅 表10-13 )。

 

如果这些条件都不为真,则您没有读取对象安全性的权利。若任何一个为真,当您取得对象的handle时,可以在用来取得handle的函数存取要求参数中,要求READ_CONTROL存取,系统将会给您一个handle。以下的程序代码片段显示为了读取文件安全性资讯而取得handle的范例:

HANDLE hFile = CreateFile(TEXT("C:\\Test\\Test.txt"), READ_CONTROL, 0,  

NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if ((hFile == INVALID_HANDLE_VALUE) &&

GetLastError() == ERROR_ACCESS_DENIED){

// 您没有对这个文件的READ_CONTROL存取权限

}

如果这个C:\Test\Test.txt文件存在并常驻在NTFS磁盘上,则此程序代码片段将会产生作用。若您符合了两个条件之一,则此程序代码将会使您取得一个有效的文件handle,您可以用它来读取对象的安全性。

现在您拥有了某个安全对象的handle,例如文件,让我们经由呼叫GetSecurityInfo函数,并使用此handle去撷取对象的安全性资讯:

DWORD GetSecurityInfo(

HANDLE hHandle,

SE_OBJECT_TYPE objType,

SECURITY_INFORMATION secInfo,

PSID *ppsidOwner,

PSID *ppsidGroup,

PACL *ppDACL,

PACL *ppSACL,

PSECURITY_DESCRIPTOR *ppSecurityDescriptor);

 


 

说明

您可能会从表10-7中想到GetSecurityInfo函数是被用来为Windows的大多数安全对象撷取安全性资讯。它确实是个非常有弹性且有用的函数。


 

使用GetSecurityInfo时,您会传递一个handle到已经以READ_CONTROL存取并开启的对象中,以视为hHandle参数之内容。objType参数是个列举的型态,指出handle代表的安全对象类型。表10-1显示可与此函数一起被使用的不同列举值。举例来说,假如您传递了文件的handle为GetSecurityInfo的hHandle参数,您必须传递此列举值SE_FILE_OBJECT为objType参数。

secInfo参数则指出在对象的安全描述项中,您要系统传回的资讯。还记得一个对象的安全描述项保存了一个拥有者、群组、DACL及SACL,经由传递表10-8中的任意组合值,可以使用GetSecurityInfo以撷取任何或所有这些资讯。

 表10-8 可被传递给GetSecurityInfo之secInfo参数SECURITY_INFORMATION值
叙述
DACL_SECURITY_INFORMATION 指出您想要撷取安全对象的DACL资讯
SACL_SECURITY_INFORMATION 指出您想要撷取安全对象的SACL资讯
OWNER_SECURITY_INFORMATION 指出您想要撷取安全对象的拥有者资讯
GROUP_SECURITY_INFORMATION 指出您想要撷取安全对象的群组资讯

 

ppsidOwner、ppsidGroup、ppDACL及ppSACL参数是选择性的。假如您要系统传回指向拥有者的SID、群组SID、DACL或对象的SACL指标,可以传递PSID的位址或者PACL变数给任何或所有这些参数。然而,您必须传递NULL给未经传递适当的标记为secInfo参数所要求的任何资讯。无论如何,您可以传递NULL给任何或所有这些参数。

最后一个参数是指向SECURITY_DESCRIPTOR结构的指标位址,它是强制性的。系统使用LocalAlloc分派一个够大的缓冲器以持有对这个对象要求的安全性资讯,并且放置一个指标指向变数中的安全描述项,其位址在ppSecurityDescriptor中提供(当您结束对象的安全描述项时,传递ppSecurityDescriptor参数中被传回的值到LocalFree是必要的)。


 

说明

假如您应该传递PSID的位址或PACL变数为ppsidOwner、ppsidGroup、ppDACL或ppSACL参数,系统会传回指向ppSecurityDescriptor中传回的部分安全描述项位址。这就是为什么这些参数是选择性的原因。


 

您不用在呼叫GetSecurityInfo后又呼叫GetLastError,因为GetSecurityInfo会直接传回错误程序代码。假如GetSecurityInfo执行成功,它会传回ERROR_SUCCESS。常见的错误值是ERROR_ACCESS_DENIED,指出您的handle不是以READ_CONTROL存取开启,而ERROR_INVALID_HANDLE则指出您传递了不符合的handle及对象类型值给hHandle及objType参数。

以下的程序代码可以与先前的程序代码片段一起使用(请参阅 先前程序代码片段 ),它使用CreateFile开启文件的handle、撷取DACL及文件C:\Test\Test.txt的对象拥有者资讯。

PSECURITY_DESCRIPTOR pSD;  

PSID pSID;

PACL pDACL;

ULONG lErr = GetSecurityInfo(hFile, SE_FILE_OBJECT,

DACL_SECURITY_INFORMATION, &pSID, NULL, &pDACL, NULL, &pSD);

if (lErr != ERROR_SUCCESS){

// 错误实例

}

// 在这执行工作

// 清理

LocalFree(pSD);

CloseHandle(hFile);

在这个范例中,成功地呼叫GetSecurityInfo后,pSID及pDACL变数会指向由pSD变数传回之缓冲器所包含的SID及DACL结构。传递由pSD或pDACL中传回的指标到LocalFree是不必要且不正确的,因为当pSD变数传回的指标被传递到LocalFree时,整个安全描述项将被释放。

您已从第九章中学习了SIDs及指向SIDs的指标,并与所讨论到的LookupAccountSid及CopySid函数一起使用从GetSecurityInfo传回的拥有者SID。

在仔细分析安全对象的DACL前,我想要先介绍GetSecurityInfo的姊妹函数—GetNamedSecurityInfo。GetSecurityInfo要求一个安全对象的handle,而GetNamedSecurityInfo则要求系统之安全对象的文字名称,其定义如下:

DWORD GetNamedSecurityInfo(

LPTSTR pObjectName,

SE_OBJECT_TYPE objType,

SECURITY_INFORMATION secInfo,

PSID *ppsidOwner,

PSID *ppsidGroup,

PACL *ppDACL,

PACL *ppSACL,

PSECURITY_DESCRIPTOR *ppSecurityDescriptor);

请注意此函数只有第一个参数与GetSecurityInfo不同,这个参数取得一个指向包含系统之对象名称字串的指标。系统中的安全对象较少被命名。此函数有时候比GetSecurityInfo更方便,因为它不要求您先取得对象的handle。有关可以使用GetNamedSecurityInfo撷取安全性的对象清单,请参阅 表格10-7 。

经由使用GetNamedSecurityInfo而建立较小的程序代码片段,先前所提的两个程序代码片段可以被合并:

PSECURITY_DESCRIPTOR pSD;  

PSID pSID;

PACL pDACL;

ULONG lErr = GetNamedSecurityInfo(TEXT("C:\\Test\\Test.txt"),

SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, &pSID, NULL,

&pDACL,NULL, &pSD);

if (lErr != ERROR_SUCCESS){

// 错误实例

}

// 清理

LocalFree(pSD);

 


 

说明

截至目前为止,我所展示的范例已经使用了C:\Test\Test.txt文件来说明如何撷取对象的安全性资讯。GetNamedSecurityInfo及GetSecurityInfo两者都可以被用来为其他安全对象撷取安全性,包括登录机码、核心对象及使用者对象。有关安全对象的特定安全函数,请参阅 表10-7 。


 

GetSecurityInfo及GetNamedSecurityInfo可让您传递指标变数的位址,以撷取拥有者SID位址、群组SID、DACL或被传回之安全描述项中的SACL。然而,如果您只撷取对象的安全描述项,则您可能对如何撷取这些资讯感到疑惑。您可以使用GetSecurityDescriptorOwner、GetSecurityDescriptorGroup、GetSecurityDescriptorDacl及GetSecurityDescriptorSacl函数,撷取指向安全描述项内部资料结构的指标。我将在本章稍后的〈安全私人对象〉一节中,进一步讨论这些函数。

DACL剖析

 

我们已经讨论过如何撷取指向安全对象的DACL指标部份,现在是开始揭开读取DACL方式的时候。请记得DACL是个存取控制清单(ACL),而ACL多于指出信任成员拒绝或允许存取的存取控制项目(ACEs)清单。

安全描述项的DACL可以被设定成NULL,以指出目前没有特定对象的DACL,因此被称为「NULL DACL」。如果对象拥有NULL DACL,则所有存取会被暗地授予所有系统的信任成员。


 

说明

当对象拥有当前的DACL时,所有对对象的存取皆会被暗地拒绝,除非明确地允许。有时候对象会有空的DACL,而这不该与NULL DACL混淆。一个空的对象表示任何人(除了拥有者)都无法对此对象做存取。另一方面,一个NULL DACL允许所有的存取给所有信任成员。


 

假如有当前的DACL,则撷取DACL中相关ACEs的资讯可能是必需的。首先,您必须经由呼叫GetAclInformation,以找出DACL包含多少ACEs:

BOOL GetAclInformation(

PACL pACL,

PVOID pACLInformation,

DWORD dwACLInformationLength,

ACL_INFORMATION_CLASS aclInformationClass);

此函数可让您撷取经由pACL参数传递到这个函数的DACL(或是SACL)相关资讯。您应该传递结构的位址以取得ACL资讯为pACLInformation参数,而结构的长度则为dwACLInformationLength参数。AclInformationClass参数是个列举型态,它指出被传回的资讯类型,也定义您应该传递哪种结构类型为pACLInformation参数。表10-9列出AclInformationClass参数的可能值。

 表10-9 ACL_INFORMATION_CLASS列举型态
列举值结构定义
AclRevisionInformation ACL_REVISION_INFORMATION 传回ACL修订资讯
AclSizeInformation ACL_SIZE_INFORMATION 传回ACL大小的资讯,包括ACE总数
posted @ 2013-02-27 11:17  csafu  阅读(146)  评论(0)    收藏  举报