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

转自:http://mickorguo.blog.163.com/blog/static/62194802007412282866/

ACL_SIZE_INFORMATION结构最常与GetAclInformation一起使用,其定义如下:

typedef struct _ACL_SIZE_INFORMATION {

DWORD AceCount;

DWORD AclBytesInUse;

DWORD AclBytesFree;

}ACL_SIZE_INFORMATION;

以下的程序代码片段撷取了C:\Test\Text.txt文件之DACL中的ACES数量。

PSECURITY_DESCRIPTOR pSD;  

PACL pDACL;

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

SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,

&pDACL, NULL, &pSD);

if (lErr != ERROR_SUCCESS){

// 错误实例

}

ACL_SIZE_INFORMATION aclSize = {0};

if(pDACL != NULL){

if(!GetAclInformation(pDACL, &aclSize, sizeof(aclSize),

  AclSizeInformation)){

  // 错误实例

}

}

ULONG nAceCount = aclSize.AceCount;

 


 

说明

假如C:\Test\Test.txt文件存在FAT磁盘上,或是它没有DACL,系统会在pDACL变数中传回NULL。这就是为什么在呼叫GetAclInformation之前测试NULL是很重要的原因。传递NULL指标值到GetAclInformation中,会导致违规存取的情形。


 

拥有DACL中的ACEs数量后,可以使用这个资讯去撷取个别的ACEs。GetAce的呼叫方式如下。

BOOL GetAce(

PACL pACL,

DWORD dwACEIndex,

PVOID *pACE);

这个函数简单地取得指标,指向ACL、您想要取得ACE以0为基础的索引、以及储存DACL中指向ACE的指标的指标变数位址。

请注意pace参数是PVOID类型。这是因为一些不同的ACE类型属于DACL,而每个类型都由一种不同的结构表示。GetAce被用来撷取每个类型。然而,ACLs可以包含任何数量的ACEs及任何ACE类型的组合,所以在您用GetAce撷取ACE前,不可能知道ACEs的类型。

尽管撷取ACE总数及ACE本身是简单的,研读DACL的真正工作变成去认识不同类型的ACEs。

认识ACEs

 

有些不同的ACE类型可以被分割成两个广泛的类型:标准ACEs及对象ACEs。您可以在每一组中找到允许、拒绝存取和稽核存取的ACE类型。每个ACE类型必定会分享共同的属性-即其结构第一个成员为ACE_HEADER类型,定义如下:

typedef struct _ACE_HEADER {

BYTE AceType;

BYTE AceFlags;

USHORT AceSize;

}ACE_HEADER;

ACE标头对于读取DACL来说是重要的,因为当您从GetAce撷取指向ACE的指标时,在读取ACE的标头前,并不知道ACE的类型或是组成ACE的结构类型。

如您所猜测的,ACE标头的AceType成员指出了标头代表的ACE类型。表10-10列出了AceType可能的值。这六种ACE类型可在Windows 2000中使用。

 表10-10 ACE类型
ACE类型叙述
ACCESS_ALLOWED_ACE_TYPE 在DACL中使用,指出一组明确地授予给信任成员的存取权利,使用ACCESS_ ALLOWED_ACE结构。
ACCESS_DENIED_ACE_TYPE 在DACL中使用,指出一组明确地拒绝给予信任成员的存取权利,使用ACCESS_ DENIED_ACE结构。
SYSTEM_AUDIT_ACE_TYPE 在SACL(请参阅〈 稽核及SACL 〉一节)中使用,指出要求一组信任成员时,可能会产生稽核事件的存取权利,使用SYSTEM_AUDIT_ACE结构。
ACCESS_ALLOWED_OBJECT_ACE_TYPE 在目录服务对象的DACL中使用,指出一组明确授予代表Active Directory中某个对象之信任成员的存取权利,使用ACCESS_ALLOWED_OBJECT_ACE结构。
ACCESS_DENIED_OBJECT_ACE_TYPE 在目录服务对象的DACL中使用。指出一组明确拒绝给予代表Active Directory中某个对象之信任成员的存取权利,使用ACCESS_DENIED_OBJECT_ACE结构。
SYSTEM_AUDIT_OBJECT_ACE_TYPE 在目录服务对象的SACL(请参阅〈 稽核及SACL 〉一节)中使用,指出要求一组信任成员时,可能产生稽核事件的存取权利,使用SYSTEM_AUDIT_OBJECT_ ACE结构。

 

ACE_HEADE结构的AceFlags成员包含关于ACE的继承及稽核资讯。AceFlag成员将是表10-11中某些值的组合。图10-2 。

ACE结构的最后一个成员是SidStart,它指出ACE拒绝、允许或稽核存取这个对象的信任成员帐户的SID起点。这个成员需要稍作讨论。

请记得SID(在第九章讨论过)是个可变长度的二进制结构,它指出系统的信任成员帐户。因为每个ACE包含SID,ACE结构也是一个可变长度的结构。SidStart成员是一个包含在ACE中的SID起点的预留位置。SidStart值(及类型)是不恰当且不应该被存取的,因为它实际上是SID结构的第一对位元组。

您可能会发现以下的巨集指令对于从ACE结构取得SID是很有用的:

#define PSIDFromPACE(pACE)((PSID)(&((pACE)->SidStart)))

这个特殊的巨集指令取得指向任何ACE结构的指标-即对象或标准ACE-并且传回指向ACE的SID结构的指标。

标准ACE类型被分成叁种不同的结构,当您为ACL建立ACEs时,主要被用来作为逻辑的预留位置。然而,因为每个ACE结构是完全相同的,从DACL读取ACEs时,常见的情形是只编写使用其中一个ACE类型的程序代码,而不使用ACE_HEADER结构的AceType成员来维护ACE类型。以下的函数使用了此种技巧,并印出DACL中每个ACE的资讯:

void DumpACL( PACL pACL ){  

__try{

  if (pACL == NULL){

   _tprintf(TEXT("NULL DACL\n"));

   __leave;

  }

  ACL_SIZE_INFORMATION aclSize = {0};

  if (!GetAclInformation(pACL, &aclSize, sizeof(aclSize),

   AclSizeInformation))

   __leave;

  _tprintf(TEXT("ACL ACE count: %d\n"), aclSize.AceCount);

  struct{

   BYTE lACEType;

   PTSTR pszTypeName;

  }aceTypes[6] == {

   {ACCESS_ALLOWED_ACE_TYPE, TEXT("ACCESS_ALLOWED_ACE_TYPE")},

   {ACCESS_DENIED_ACE_TYPE, TEXT("ACCESS_DENIED_ACE_TYPE")},

   {SYSTEM_AUDIT_ACE_TYPE,TEXT("SYSTEM_AUDIT_ACE_TYPE")},

   {ACCESS_ALLOWED_OBJECT_ACE_TYPE,

    TEXT("ACCESS_ALLOWED_OBJECT_ACE_TYPE")},

   {ACCESS_DENIED_OBJECT_ACE_TYPE,

    TEXT("ACCESS_DENIED_OBJECT_ACE_TYPE")},

   {SYSTEM_AUDIT_OBJECT_ACE_TYPE,

    TEXT("SYSTEM_AUDIT_OBJECT_ACE_TYPE")}};

struct{

  ULONG lACEFlag;

  PTSTR pszFlagName;

}aceFlags [7 ] =={

  {INHERITED_ACE, TEXT("INHERITED_ACE")},

  {CONTAINER_INHERIT_ACE, TEXT("CONTAINER_INHERIT_ACE")},

   {OBJECT_INHERIT_ACE, TEXT("OBJECT_INHERIT_ACE")},

   {INHERIT_ONLY_ACE, TEXT("INHERIT_ONLY_ACE")},

   {NO_PROPAGATE_INHERIT_ACE, TEXT("NO_PROPAGATE_INHERIT_ACE")},

   {FAILED_ACCESS_ACE_FLAG, TEXT("FAILED_ACCESS_ACE_FLAG")},

   {SUCCESSFUL_ACCESS_ACE_FLAG,

    TEXT("SUCCESSFUL_ACCESS_ACE_FLAG")}};

  for (ULONG lIndex = 0; lIndex < aclSize.AceCount; lIndex++){

   ACCESS_ALLOWED_ACE* pACE;

   if (!GetAce(pACL, lIndex, (PVOID*)&pACE))

    __leave;

   _tprintf(TEXT("\nACE #%d\n"), lIndex);

   ULONG lIndex2 = 6;

   PTSTR pszString = TEXT("Unknown ACE Type");

   while (lIndex2--){

    if(pACE->Header.AceType == aceTypes [lIndex2 ].lACEType){

     pszString = aceTypes[lIndex2].pszTypeName;

    }

   }

   _tprintf(TEXT(" ACE Type =\n  \t%s\n"), pszString);

   _tprintf(TEXT("  ACE Flags = \n"));

   lIndex2 = 7;

   while (lIndex2--){

    if ((pACE->Header.AceFlags &aceFlags [lIndex2 ].lACEFlag)

     !=0)

     _tprintf(TEXT("  \t%s\n"),

      aceFlags[lIndex2].pszFlagName);

   }

   _tprintf(TEXT(" ACE Mask ((32->0)=\n \t "));

   lIndex2 = (ULONG)1<<31;

   while (lIndex2){

    _tprintf(((pACE->Mask &lIndex2) != 0)?TEXT("1"):TEXT("0"));

    lIndex2>>=1;

   }

   TCHAR szName[1024];

   TCHAR szDom[1024];

   PSID pSID = PSIDFromPACE(pACE);

   SID_NAME_USE sidUse;

   ULONG lLen1 = 1024, lLen2 = 1024;

   if (!LookupAccountSid(NULL, pSID,

    szName, &lLen1, szDom, &lLen2, &sidUse))

    lstrcpy(szName, TEXT("Unknown"));

   PTSTR pszSID;

   if (!ConvertSidToStringSid(pSID, &pszSID))

    __leave;

   _tprintf(TEXT("\n  ACE SID = \n  \t%s (%s)\n"), pszSID, szName);

   LocalFree(pszSID);

  }

}__finally{}

}

ACEs的所有ACE类型倾印了ACCESS_ALLOWED_ACE结构,这个结构对任何标准ACE类型(尽管这个函数对对象ACEs将失去作用)都能作用,因为所有标准ACE结构都相同。

以下的程序片段可以与DumpACL函数一起被用来显示NTFS共享目录中的ACEs:

PSECURITY_DESCRIPTOR pSD;  

PACL pDACL;

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

SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL,

&pDACL, NULL, &pSD);

if (lErr == ERROR_SUCCESS){

DumpACL(pDACL);

}

 


 

说明

DumpACL范例函数说明了如何读取DACL中的ACE资讯。您会在自己编写的程序代码中发现像这样有用的程序代码。您也会发现以DumpACL函数作为除错工具是很有帮助的,尤其是当您开始编写程序代码去修改安全对象的DACL时。在您作了修改的前后,使用它来倾印对象的DACL内容,以查看您的程序代码是否产生了所要求的结果。

这种技巧胜过使用浏览器的安全属性页检视安全性,因为系统的使用者介面不会逐字显示对象的ACE资讯。事实上,使用者介面不会显示没有事先在DACL中适当地安排ACEs顺序的DACL。


 

因为ACE结构的性质可让您发现它对定义一个表示每个ACE类型的Union很有帮助。于是就一个指向Union类型的指标来说,您可以处理从GetAce传回的ACEs。

以下的程序代码显示一个使用此类技巧的范例:

typedef union _ACE_UNION{

ACE_HEADER aceHeader;

ACCESS_ALLOWED_ACE aceAllowed;

ACCESS_DENIED_ACE aceDenied;

SYSTEM_AUDIT_ACE aceAudit;

}*PACE_UNION;

PACE_UNION pACE ;

GetAce(pDACL, 0, (PVOID*)&pACE);

switch (pACE->aceHeader.AceType){

.

.

.

 

 对象ACEs 除非您要编写保护及修改Active Directory对象安全性的程序代码,否则您不可能会在自己的应用程序中使用对象ACEs。然而,Active Directory是Windows 2000的一个重要元件,了解它保护对象安全的方法并没有害处。我们不会花太多时间在这个主题上,此处的说明只是为了避免混淆您对标准ACEs的认识。

就像标准ACES一样,对象ACEs有叁种结构:拒绝、允许及稽核信任成员存取权利。以下是对象ACEs的结构:

typedef struct _ACCESS_ALLOWED_OBJECT_ACE {

ACE_HEADER  Header;

ACCESS_ MASK Mask;

DWORD Flags;

GUID ObjectType;

GUID InheritedObjectType;

DWORD SidStart;

} ACCESS_ALLOWED_OBJECT_ACE, *PACCESS_ALLOWED_OBJECT_ACE;

typedef struct _ACCESS_DENIED_OBJECT_ACE {

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD Flags;

GUID ObjectType;

GUID InheritedObjectType;

DWORD SidStart;

} ACCESS_DENIED_OBJECT_ACE, *PACCESS_DENIED_OBJECT_ACE;

typedef struct _SYSTEM_AUDIT_OBJECT_ACE {

ACE_HEADER Header;

ACCESS_MASK Mask;

DWORD Flags;

GUID ObjectType;

GUID InheritedObjectType;

DWORD SidStart;

} SYSTEM_AUDIT_OBJECT_ACE, *PSYSTEM_AUDIT_OBJECT_ACE;

就像标准ACEs一样,除了附加的Flags、ObjectType及InheritedObjectType成员外,每个结构类型及结构的成员都相同。

注意不要把对象ACE结构的Flags成员与ACE_HEADER结构的AceFlags成员混淆了。Flags成员可以为0或是表10-12中任何值的组合。


 

说明

和Win32 SDK中类似的结构不同,表10-12中的标记不指出结构中是否有使用ObjectType及InheritedObjectType成员,而是指出这些成员是否真的存在于结构中!

没有固定成员清单的结构被称为 定形的(amorphous) 。每个对象ACE结构都是无定形的,在Win32 SDK中是非常罕见的结构。这显然是对象ACEs最难处理的一面。


posted @ 2013-02-27 11:14  csafu  阅读(112)  评论(0)    收藏  举报