window权限 及c++实现 【网摘】(转)

时间:2024-03-17 14:57:12

from : http://blog.csdn.net/zipper9527/article/details/6256459

http://www.lihuasoft.net/article/show.php?id=755

http://www.360doc.com/content/07/0404/15/21275_430071.shtml

 

以程序的方式操纵NTFS 的文件权限

Windows NT/2K/XP版本的操作系统都支持 NTFS 格式的文件系统,这是一个有安全性质的文件系统,你可以通过 Windows 的资源管理器来设置对每个目录和 文件的用户访问权限。这里我就不对 NTFS 的安全性进行讲述了,我默认你对 NTFS 的文件目录的安全设置有了一定的了解。在这里,我将向你介绍使用  Windows 的 API 函数来操纵 NTFS 的文件权限。


一、理论和术语

 

在Windows NT/2K?XP 下的对象,不一定是文件系统,还有其它的一些对象,如:进程、命名管道、打印机、网络共享、或是注册表等等,都可以设置用户访问权限。在  Windows 系统中,其是用一个安全描述符( Security Descriptors )的结构来保存其权限的设置信息,简称为 SD ,其在 Windows SDK中的结构名是“ SECURITY_DESCRIPTOR ”,这是包括了安全设置信息的结构体。一个安全描述符包含以下信息:

一个安全标识符(Security identifiers) ,其标识了该信息是哪个对象的,也就是用于记录安全对象的 ID 。简称为: SID 。

一 个DACL ( Discretionary Access Control List ),其指出了允许和拒绝某用户或用户组的存取控制列表。 当一个进程需要访问安全对象,系统就会检查 DACL 来决定进程的访问权。如果一个对象没有 DACL ,那么就是说这个对象是任何人都可以拥有完全的访问权 限。

一个SACL ( System Access Control List ),其指出了在该对象上的一组存取方式(如,读、写、运行等)的存取控制权限细节的列表。还有其自身的一些控制位。

DACL和 SACL 构成了整个存取控制列表 Access Control List ,简称 ACL , ACL 中的每一项,我们叫做 ACE ( Access Control Entry ), ACL 中的每一个 ACE 。

 

我们的程序不用直接维护SD 这个结构,这个结构由系统维护。我们只用使用 Windows  提供的相关的 API 函数来取得并设置 SD 中的信息就行了。不过这些 API 函数只有 Windows NT/2K/XP 才支持。

 

安全对象Securable Object 是拥有 SD 的 Windows 的对象。所有的被命名的 Windows 的对象都是安全对象。一些没有命名的对象是安全对象,如:进程和线程,也有 安全描述符 SD 。在对大多数的创建安全对象的操作中都需要你传递一个 SD 的参数,如: CreateFile 和 CreateProcess 函数。另 外,Windows 还提供了一系列有关安全对象的安全信息的存取函数,以供你取得对象上的安全设置,或修改对象上的安全设置。 如:GetNamedSecurityInfo, SetNamedSecurityInfo , GetSecurityInfo, SetSecurityInfo 。

 

下图说明了,安全对象和DACL 以及访问者之间的联系(来源于 MSDN )。注意, DACL 表中的每个 ACE 的顺序是有意义的,如果前面的 Allow(或 denied ) ACE 通过了,那么,系统就不会检查后面的 ACE 了。

 

系统会按照顺序依次检查所有的ACE 规则,如下面的条件满足,则退出:

1、 如果一个 Access-Denied 的 ACE 明显地拒绝了请求者。

2、 如果某 Access-Allowed 的 ACE 明显地同意了请求者。

3、 全部的 ACE 都检查完了,但是没有一条 ACE 明显地允许或是拒绝请求者,那么系统将使用默认值,拒绝请求者的访问。

更多的理论和描述,请参看MSDN 。

 

二、实践与例程

 

1、  例程一:创建一个有权限设置的目录

 

#include <windows.h>

 

void main(void)

{

  SECURITY_ATTRIBUTES sa;  //和文件有关的安全结构

  SECURITY_DESCRIPTOR sd;  //声明一个 SD

 

  BYTE aclBuffer[1024];

  PACL pacl=(PACL)&aclBuffer; //声明一个 ACL ,长度是 1024

 

  BYTE sidBuffer[100];

  PSID psid=(PSID) &sidBuffer;  //声明一个 SID ,长度是 100

 

  DWORD sidBufferSize = 100;

  char domainBuffer[80];

  DWORD domainBufferSize = 80;

  SID_NAME_USE snu;

  HANDLE file;

 

  //初始化一个 SD

  InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);

  //初始化一个 ACL

  InitializeAcl(pacl, 1024, ACL_REVISION);

  //查找一个用户 hchen ,并取该用户的 SID

  LookupAccountName(0, "hchen", psid,

      &sidBufferSize, domainBuffer,

      &domainBufferSize, &snu);

  //设置该用户的 Access-Allowed 的 ACE ,其权限为“所有权限”

AddAccessAllowedAce(pacl, ACL_REVISION, GENERIC_ALL, psid);

//把 ACL 设置到 SD 中

  SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE);

 

  //把 SD 放到文件安全结构 SA 中

  sa.nLength = sizeof(SECURITY_ATTRIBUTES);

  sa.bInheritHandle = FALSE;

  sa.lpSecurityDescriptor = &sd;

 

  //创建文件

  file = CreateFile("c://testfile",

    0, 0, &sa, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);

  CloseHandle(file);

}

 

 

这 个例子我是从网上找来的,改了改。其中使用到的关键的API 函数,我都把其加粗了。从程序中我们可以看到,我们先初始化了一个 SD 和一个 ACL,然后调用  LookupAccountName 取得用户的 SID ,然后通过这个 SID ,对 ACL 中加入一个有允许访问权限的 ACE ,然后再把整个 ACL 设置到SD  中。最后,组织文件安全描述的 SA 结构,并调用 CreateFile 创建文件。如果你的操作系统是 NTFS ,那么,你可以看到你创建出来的文件的安全属性 的样子:

 

 

这个程序旨在说明如何生成一个新的SD 和 ACL 的用法,其有四个地方的不足和不清:

 

1、 对于 ACL 和 SID 的声明采用了硬编码的方式指定其长度。

2、 对于 API 函数,没有出错处理。

3、 没有说明如何修改已有文件或目录的安全设置。

4、 没有说明安全设置的继承性。

 

对于这些我将在下个例程中讲述。

 

2、  例程二、为目录增加一个安全设置项

 

在我把这个例程序例出来以前,请允许我多说一下。

 

1、  对于文件、目录、命令管道,我们不一定要使用 GetNamedSecurityInfo 和 SetNamedSecurityInfo 函数,我们可以使用其 专用函数 GetFileSecurity和 SetFileSecurity 函数来取得或设置文件对象的 SD ,以设置其访问权限。需要使用这两个函数并不容 易,正如前面我们所说的,我们还需要处理 SD参数,要处理 SD ,就需要处理 DACL 和 ACE ,以及用户的相关 SID ,于是,一系统列的函数就被这两个函数 带出来了。

2、  对于上一个例子中的使用硬编码指定 SID 的处理方法是。调用 LookupAccountName 函数时,先把 SID , Domain 名的参数传为空  NULL ,于是 LookupAccountName 会返回用户的 SID 的长度和 Domain 名的长度,于是你可以根据这个长度分配内存,然后再次调用  LookupAccountName 函数。于是就可以达到到态分配内存的效果。对于 ACL 也一样。

3、  对于给文件的 ACL 中增加一个 ACE 条目,一般的做法是先取出文件上的 ACL ,逐条取出 ACE ,和现需要增加的 ACE 比较,如果有冲突,则删除已有的  ACE ,把新加的 ACE 添置到最后。这里的最后,应该是非继承而来的 ACE 的最后。关于 ACL 继承, NTFS 中,你可以设置文件和目录是否继承于其父目录 的设置。在程序中同样可以设置。

还是请看例程,这个程序比较长,来源于MSDN ,我做了一点点修改,并把自己的理解加在注释中,所以,请注意代码中的注释:

#include <windows.h>

#include <tchar.h>

#include <stdio.h>

//使用 Windows 的 HeapAlloc 函数进行动态内存分配

#define myheapalloc(x) (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, x))

#define myheapfree(x) (HeapFree(GetProcessHeap(), 0, x))

typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)(

  IN PSECURITY_DESCRIPTOR pSecurityDescriptor,

  IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,

  IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet);

typedef BOOL (WINAPI *AddAccessAllowedAceExFnPtr)(

 PACL pAcl,

 DWORD dwAceRevision,

 DWORD AceFlags,

 DWORD AccessMask,

 PSID pSid

);

BOOL AddAccessRights(TCHAR *lpszFileName, TCHAR *lpszAccountName,

   DWORD dwAccessMask) {

  // 声明 SID 变量

  SID_NAME_USE  snuType;

  // 声明和 LookupAccountName 相关的变量(注意,全为 0 ,要在程序中动态分配)

  TCHAR *    szDomain    = NULL;

  DWORD     cbDomain    = 0;

  LPVOID     pUserSID    = NULL;

  DWORD     cbUserSID   = 0;

  // 和文件相关的安全描述符  SD  的变量

  PSECURITY_DESCRIPTOR pFileSD = NULL;   // 结构变量

  DWORD     cbFileSD    = 0;    // SD的 size

  // 一个新的 SD 的变量,用于构造新的 ACL (把已有的 ACL 和需要新加的 ACL 整合起来)

  SECURITY_DESCRIPTOR newSD;

  // 和 ACL  相关的变量

  PACL      pACL      = NULL;

  BOOL      fDaclPresent;

  BOOL      fDaclDefaulted;

  ACL_SIZE_INFORMATION AclInfo;

  // 一个新的  ACL  变量

  PACL      pNewACL    = NULL; //结构指针变量

  DWORD     cbNewACL    = 0;   //ACL的 size

  // 一个临时使用的  ACE  变量

  LPVOID     pTempAce    = NULL;

  UINT      CurrentAceIndex = 0; //ACE在 ACL 中的位置

  UINT      newAceIndex = 0; //新添的 ACE 在 ACL 中的位置

  //API函数的返回值,假设所有的函数都返回失败。

  BOOL      fResult;

  BOOL      fAPISuccess;

  SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;

  // 下面的两个函数是新的 API 函数,仅在 Windows 2000 以上版本的操作系统支持。

  // 在此将从 Advapi32.dll 文件中动态载入。如果你使用 VC++ 6.0 编译程序,而且你想

  // 使用这两个函数的静态链接。则请为你的编译加上: /D_WIN32_WINNT=0x0500

  // 的编译参数。并且确保你的 SDK 的头文件和 lib 文件是最新的。

  SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl = NULL;

  AddAccessAllowedAceExFnPtr _AddAccessAllowedAceEx = NULL;

  __try {

   //

   // STEP 1: 通过用户名取得 SID

   //   在这一步中 LookupAccountName 函数被调用了两次,第一次是取出所需要

   // 的内存的大小,然后,进行内存分配。第二次调用才是取得了用户的帐户信息。

   // LookupAccountName同样可以取得域用户或是用户组的信息。(请参看 MSDN )

   //

   fAPISuccess = LookupAccountName(NULL, lpszAccountName,

      pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);

   // 以上调用 API 会失败,失败原因是内存不足。并把所需要的内存大小传出。

   // 下面是处理非内存不足的错误。

   if (fAPISuccess)

     __leave;

   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {

     _tprintf(TEXT("LookupAccountName() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   pUserSID = myheapalloc(cbUserSID);

   if (!pUserSID) {

     _tprintf(TEXT("HeapAlloc() failed. Error %d/n"), GetLastError());

     __leave;

   }

   szDomain = (TCHAR *) myheapalloc(cbDomain * sizeof(TCHAR));

   if (!szDomain) {

     _tprintf(TEXT("HeapAlloc() failed. Error %d/n"), GetLastError());

     __leave;

   }

   fAPISuccess = LookupAccountName(NULL, lpszAccountName,

      pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);

   if (!fAPISuccess) {

     _tprintf(TEXT("LookupAccountName() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   //

   // STEP 2: 取得文件(目录)相关的安全描述符 SD

   //   使用 GetFileSecurity 函数取得一份文件 SD 的拷贝,同样,这个函数也

    // 是被调用两次,第一次同样是取 SD 的内存长度。注意, SD 有两种格式:自相关的

    // ( self-relative )和 完全的( absolute ), GetFileSecurity 只能取到“自

    // 相关的”,而 SetFileSecurity 则需要完全的。这就是为什么需要一个新的 SD ,

    // 而不是直接在 GetFileSecurity 返回的 SD 上进行修改。因为“自相关的”信息

    // 是不完整的。

   fAPISuccess = GetFileSecurity(lpszFileName,

      secInfo, pFileSD, 0, &cbFileSD);

   // 以上调用 API 会失败,失败原因是内存不足。并把所需要的内存大小传出。

   // 下面是处理非内存不足的错误。

   if (fAPISuccess)

     __leave;

   else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {

     _tprintf(TEXT("GetFileSecurity() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   pFileSD = myheapalloc(cbFileSD);

   if (!pFileSD) {

     _tprintf(TEXT("HeapAlloc() failed. Error %d/n"), GetLastError());

     __leave;

   }

   fAPISuccess = GetFileSecurity(lpszFileName,

      secInfo, pFileSD, cbFileSD, &cbFileSD);

   if (!fAPISuccess) {

     _tprintf(TEXT("GetFileSecurity() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   //

   // STEP 3: 初始化一个新的 SD

   //

   if (!InitializeSecurityDescriptor(&newSD,

      SECURITY_DESCRIPTOR_REVISION)) {

     _tprintf(TEXT("InitializeSecurityDescriptor() failed.")

      TEXT("Error %d/n"), GetLastError());

     __leave;

   }

   //

   // STEP 4: 从 GetFileSecurity  返回的 SD 中取 DACL

   //

   if (!GetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL,

      &fDaclDefaulted)) {

     _tprintf(TEXT("GetSecurityDescriptorDacl() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   //

   // STEP 5: 取  DACL 的内存 size

   //   GetAclInformation可以提供 DACL 的内存大小。只传入一个类型为

   // ACL_SIZE_INFORMATION的 structure 的参数,需 DACL 的信息,是为了

   // 方便我们遍历其中的 ACE 。

   AclInfo.AceCount = 0; // Assume NULL DACL.

   AclInfo.AclBytesFree = 0;

   AclInfo.AclBytesInUse = sizeof(ACL);

   if (pACL == NULL)

     fDaclPresent = FALSE;

   // 如果 DACL 不为空,则取其信息。(大多数情况下“自关联”的 DACL 为空)

   if (fDaclPresent) {      

     if (!GetAclInformation(pACL, &AclInfo,

        sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {

      _tprintf(TEXT("GetAclInformation() failed. Error %d/n"),

         GetLastError());

      __leave;

     }

   }

   //

   // STEP 6: 计算新的 ACL 的 size

   //  计算的公式是:原有的 DACL 的 size 加上需要添加的一个 ACE 的 size ,以

   // 及加上一个和 ACE 相关的 SID 的 size ,最后减去两个字节以获得精确的大小。

   cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE)

      + GetLengthSid(pUserSID) - sizeof(DWORD);

   //

   // STEP 7: 为新的 ACL 分配内存

   //

   pNewACL = (PACL) myheapalloc(cbNewACL);

   if (!pNewACL) {

     _tprintf(TEXT("HeapAlloc() failed. Error %d/n"), GetLastError());

     __leave;

   }

   //

   // STEP 8: 初始化新的 ACL 结构

   //

   if (!InitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {

     _tprintf(TEXT("InitializeAcl() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   //

   // STEP 9 如果文件(目录)  DACL  有数据,拷贝其中的 ACE 到新的 DACL 中

   //

   //   下面的代码假设首先检查指定文件(目录)是否存在的 DACL ,如果有的话,

   // 那么就拷贝所有的 ACE 到新的 DACL 结构中,我们可以看到其遍历的方法是采用

   // ACL_SIZE_INFORMATION结构中的 AceCount 成员来完成的。在这个循环中,

   // 会按照默认的 ACE 的顺序来进行拷贝( ACE 在 ACL 中的顺序是很关键的),在拷

   // 贝过程中,先拷贝非继承的 ACE (我们知道 ACE 会从上层目录中继承下来)

   //

   newAceIndex = 0;

   if (fDaclPresent && AclInfo.AceCount) {

     for (CurrentAceIndex = 0;

        CurrentAceIndex < AclInfo.AceCount;

        CurrentAceIndex++) {

      //

      // STEP 10: 从 DACL 中取 ACE

      //

      if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {

        _tprintf(TEXT("GetAce() failed. Error %d/n"),

           GetLastError());

        __leave;

      }

      //

      // STEP 11: 检查是否是非继承的 ACE

      //   如果当前的 ACE 是一个从父目录继承来的 ACE ,那么就退出循环。

      // 因为,继承的 ACE 总是在非继承的 ACE 之后,而我们所要添加的 ACE

      // 应该在已有的非继承的 ACE 之后,所有的继承的 ACE 之前。退出循环

      // 正是为了要添加一个新的 ACE 到新的 DACL 中,这后,我们再把继承的

      // ACE拷贝到新的 DACL 中。

      //

      if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags

        & INHERITED_ACE)

        break;

      //

      // STEP 12: 检查要拷贝的 ACE 的 SID 是否和需要加入的 ACE 的 SID 一样,

      // 如果一样,那么就应该废掉已存在的 ACE ,也就是说,同一个用户的存取

      // 权限的设置的 ACE ,在 DACL 中应该唯一。这在里,跳过对同一用户已设置

      // 了的 ACE ,仅是拷贝其它用户的 ACE 。

      //

      if (EqualSid(pUserSID,

        &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))

        continue;

      //

      // STEP 13: 把 ACE 加入到新的 DACL 中

      //  下面的代码中,注意  AddAce  函数的第三个参数,这个参数的意思是

      // ACL中的索引值,意为要把 ACE 加到某索引位置之后,参数 MAXDWORD 的

       // 意思是确保当前的 ACE 是被加入到最后的位置。

      //

      if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,

         ((PACE_HEADER) pTempAce)->AceSize)) {

        _tprintf(TEXT("AddAce() failed. Error %d/n"),

           GetLastError());

        __leave;

      }

      newAceIndex++;

     }

   }

 

  //

  // STEP 14: 把一个  access-allowed  的 ACE  加入到新的 DACL 中

  //   前面的循环拷贝了所有的非继承且 SID 为其它用户的 ACE ,退出循环的第一件事

  // 就是加入我们指定的 ACE 。请注意首先先动态装载了一个 AddAccessAllowedAceEx

  // 的 API 函数,如果装载不成功,就调用 AddAccessAllowedAce 函数。前一个函数仅

  // 在 Windows 2000 以后的版本支持, NT 则没有,我们为了使用新版本的函数,我们首

  // 先先检查一下当前系统中可不可以装载这个函数,如果可以则就使用。使用动态链接

  // 比使用静态链接的好处是,程序运行时不会因为没有这个 API 函数而报错。

  //

  // Ex版的函数多出了一个参数 AceFlag (第三人参数),用这个参数我们可以来设置一

  // 个叫 ACE_HEADER 的结构,以便让我们所设置的 ACE 可以被其子目录所继承下去,而

  // AddAccessAllowedAce函数不能定制这个参数,在 AddAccessAllowedAce 函数

  // 中,其会把 ACE_HEADER 这个结构设置成非继承的。

  //

   _AddAccessAllowedAceEx = (AddAccessAllowedAceExFnPtr)

      GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),

      "AddAccessAllowedAceEx");

   if (_AddAccessAllowedAceEx) {

      if (!_AddAccessAllowedAceEx(pNewACL, ACL_REVISION2,

       CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE ,

        dwAccessMask, pUserSID)) {

       _tprintf(TEXT("AddAccessAllowedAceEx() failed. Error %d/n"),

          GetLastError());

       __leave;

     }

   }else{

     if (!AddAccessAllowedAce(pNewACL, ACL_REVISION2,

        dwAccessMask, pUserSID)) {

       _tprintf(TEXT("AddAccessAllowedAce() failed. Error %d/n"),

          GetLastError());

       __leave;

     }

   }

   //

   // STEP 15: 按照已存在的 ACE 的顺序拷贝从父目录继承而来的 ACE

   //

   if (fDaclPresent && AclInfo.AceCount) {

     for (;

       CurrentAceIndex < AclInfo.AceCount;

       CurrentAceIndex++) {

      //

      // STEP 16: 从文件(目录)的 DACL 中继续取 ACE

      //

      if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {

        _tprintf(TEXT("GetAce() failed. Error %d/n"),

           GetLastError());

        __leave;

      }

      //

      // STEP 17: 把 ACE 加入到新的 DACL 中

      //

      if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce,

         ((PACE_HEADER) pTempAce)->AceSize)) {

        _tprintf(TEXT("AddAce() failed. Error %d/n"),

           GetLastError());

        __leave;

      }

     }

   }

   //

   // STEP 18: 把新的 ACL 设置到新的 SD 中

   //

   if (!SetSecurityDescriptorDacl(&newSD, TRUE, pNewACL,

      FALSE)) {

     _tprintf(TEXT("SetSecurityDescriptorDacl() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   //

   // STEP 19: 把老的 SD 中的控制标记再拷贝到新的 SD 中,我们使用的是一个叫

   // SetSecurityDescriptorControl() 的 API 函数,这个函数同样只存在于

   // Windows 2000以后的版本中,所以我们还是要动态地把其从 advapi32.dll

   // 中载入,如果系统不支持这个函数,那就不拷贝老的 SD 的控制标记了。

   //

   _SetSecurityDescriptorControl =(SetSecurityDescriptorControlFnPtr)

      GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),

      "SetSecurityDescriptorControl");

   if (_SetSecurityDescriptorControl) {

     SECURITY_DESCRIPTOR_CONTROL controlBitsOfInterest = 0;

     SECURITY_DESCRIPTOR_CONTROL controlBitsToSet = 0;

     SECURITY_DESCRIPTOR_CONTROL oldControlBits = 0;

     DWORD dwRevision = 0;

     if (!GetSecurityDescriptorControl(pFileSD, &oldControlBits,

      &dwRevision)) {

      _tprintf(TEXT("GetSecurityDescriptorControl() failed.")

         TEXT("Error %d/n"), GetLastError());

      __leave;

     }

     if (oldControlBits & SE_DACL_AUTO_INHERITED) {

      controlBitsOfInterest =

        SE_DACL_AUTO_INHERIT_REQ |

        SE_DACL_AUTO_INHERITED ;

      controlBitsToSet = controlBitsOfInterest;

     }

     else if (oldControlBits & SE_DACL_PROTECTED) {

      controlBitsOfInterest = SE_DACL_PROTECTED;

      controlBitsToSet = controlBitsOfInterest;

     }    

     if (controlBitsOfInterest) {

      if (!_SetSecurityDescriptorControl(&newSD,

        controlBitsOfInterest,

        controlBitsToSet)) {

        _tprintf(TEXT("SetSecurityDescriptorControl() failed.")

           TEXT("Error %d/n"), GetLastError());

        __leave;

      }

     }

   }

   //

   // STEP 20: 把新的 SD 设置设置到文件的安全属性中(千山万水啊,终于到了)

   //

   if (!SetFileSecurity(lpszFileName, secInfo,

      &newSD)) {

     _tprintf(TEXT("SetFileSecurity() failed. Error %d/n"),

        GetLastError());

     __leave;

   }

   fResult = TRUE;

  } __finally {

   //

   // STEP 21: 释放已分配的内存,以免 Memory Leak

   //

   if (pUserSID) myheapfree(pUserSID);

   if (szDomain) myheapfree(szDomain);

   if (pFileSD) myheapfree(pFileSD);

   if (pNewACL) myheapfree(pNewACL);

  }

  return fResult;

}

--------------------------------------------------------------------------------

int _tmain(int argc, TCHAR *argv[]) {

  if (argc < 3) {

   _tprintf(TEXT("usage: /"%s/" <FileName> <AccountName>/n"), argv[0]);

   return 1;

  }

  // argv[1] – 文件(目录)名

  // argv[2] – 用户(组)名

  // GENERIC_ALL表示所有的权限,其是一系列的 NTFS 权限的或

  //   NTFS的文件权限很细,还请参看 MSDN 。

  if (!AddAccessRights(argv[1], argv[2], GENERIC_ALL)) {

   _tprintf(TEXT("AddAccessRights() failed./n"));

   return 1;

  }

  else {

   _tprintf(TEXT("AddAccessRights() succeeded./n"));

   return 0;

  }

}

 

三、 一些相关的API 函数

 

通过以上的示例,相信你已知道如何操作NTFS 文件安全属性了,还有一些 API 函数需要介绍一下。

1、 如果你要加入一个 Access-Denied  的 ACE ,你可以使用 AddAccessDeniedAce 函数

2、 如果你要删除一个 ACE ,你可以使用 DeleteAce 函数

3、 如果你要检查你所设置的 ACL 是否合法,你可以使用 IsValidAcl 函数,同样,对于 SD 的合法也有一个叫 IsValidSecurityDescriptor 的函数

 

Windows XP权限整合应用全解

如果要删除某个用户对加密文件的访问权限,那么只需选中此用户后点击“删除”按钮即可。作为 微软  第 一个稳定且安全的操作系统,Windows XP 经过几年的磨合过渡期,终于以超过 Windows 系列操作系统 50% 的用户占有量成为目前用户使用最多的操作系统。在慢慢熟悉了 Windows XP 后,人们逐渐开始不满足基本的系统应用了,他们更加渴望学习一些较深入且实用的知识,以便能让系统充分发挥出 Windows XP 的高级性能。

  因此本文以Windows XP Professional 版本为平台,引领大家感受一下 Windows XP 在“权限”方面的设计魅力!

  一、什么是权限

  Windows XP 提供了非常细致的权限控制项,能够精确定制用户对资源的访问控制能力,大多数的权限从其名称上就可以基本了解其所能实现的内容。

   “权限”(Permission) 是针对资源而言的。也就是说,设置权限只能是以资源为对象,即“设置某个文件夹有哪些用户可以拥有相应的权限”,而不 能是以用户为主,即“设置某个用户可以对哪些资源拥有权限”。这就意味着“权限”必须针对“资源”而言,脱离了资源去谈权限毫无意义──在提到权限的具体 实施时,“某个资源”是必须存在的。

  利用权限可以控制资源被访问的方式,如User 组的成员对某个资源拥有“读取”操作权限、 Administrators 组成员拥有“读取 + 写入 + 删除”操作权限等。

   值得一提的是,有一些Windows 用户往往会将“权力”与“权限”两个非常相似的概念搞混淆,这里做一下简单解释:“权力” (Right) 主要是针对 用户而言的。“权力”通常包含“登录权力” (Logon Right) 和“特权” (Privilege) 两种。登录权力决定了用户如何登录到计算机,如是否采用本地交互式登录、是否为网络登录等。特权则是一系列 权力的总称,这些权力主要用于帮助用户对系统进行管理,如是否允许用户安装或加载驱动程序等。显然,权力与权限有本质上的区别。

  二、安全标识符、访问控制列表、安全主体

   说到Windows XP 的权限,就不能不说说“安全标识符” (Security Identifier, SID) 、“访问控制列表” (Access Control List , ACL) 和安全主体(Security Principal) 这三个与其息息相关的设计了。

  1. 安全标识符

  在 Windows XP 中,系统是通过 SID 对用户进行识别的,而不是很多用户认为的“用户名称”。 SID 可以应用于系统内的所有用户、组、服务或计算机,因为 SID 是一个 具有惟一性、绝对不会重复产生的数值,所以,在删除了一个账户 ( 如名为“ A ”的账户 ) 后,再次创建这个“ A ”账户时,前一个 A 与后一个 A 账户的 SID 是不 相同的。这种设计使得账户的权限得到了最基础的保护,盗用权限的情况也就彻底杜绝了。

  查看用户、组、服务或计算机 的SID 值,可以使用“ Whoami ”工具来执行,该工具包含在 Windows XP 安装光盘的“ Support/Tools ”目录中,双击执行该目录下的“ Setup ”文件后,将会有包括 Whoami 工具在内的一系列命令行工具拷贝 到“ X:/Program Files/Support Tools ”目录中。此后在任意一个命令提示符窗口中都可以执行“ Whoami /all ”命令来查看当前用户的全部信息。

  2. 访问控制列表 (ACL)

  访问控制列表是权限的核心技术。顾名思义,这是一个权限列表,用于定义特定用户对某个资源的访问权限,实际上这就是Windows XP 对资源进行保护时所使用的一个标准。

   在访问控制列表中,每一个用户或用户组都对应一组访问控制项(Access Control Entry, ACE) ,这一点只需在“组或用户名称”列表中选择不同的用户或组时,通过下方的权限列表设置项是不同的这一点就可以看出来。显然,所有用户或用户组的权 限访问设置都将会在这里被存储下来,并允许随时被有权限进行修改的用户进行调整,如取消某个用户对某个资源的“写入”权限。

  3. 安全主体 (Security Principal)

  在Windows XP 中,可以将用户、用户组、计算机或服务都看成是一个安全主体,每个安全主体都拥有相对应的账户名称和 SID 。根据系统架构的不同,账户的管理方式也有所不同──本地账户被本地的 SAM 管理;域的账户则会被活动目录进行管理……

  一般来说,权限的指派过程实际上就是为某个资源指定安全主体( 即用户、用户组等 ) 可以拥有怎样的操作过程。因为用户组包括多个用户,所以大多数情况下,为资源指派权限时建议使用用户组来完成,这样可以非常方便地完成统一管理。

  三、权限的四项基本原则

  在Windows XP 中,针对权限的管理有四项基本原则,即:拒绝优于允许原则、权限最小化原则、累加原则和权限继承性原则。这四项基本原则对于权限的设置来说,将会起到非常重要的作用,下面就来了解一下:

  1. 拒绝优于允许原则

   “拒绝优于允许”原则是一条非常重要且基础性的原则,它可以非常完美地处理好因用户在用户组的归属方面引起的权限“纠纷”,例如,“shyzhong ” 这个用户既属于“ shyzhongs ”用户组,也属于“ xhxs ”用户组,当我们对“ xhxs ”组中某个资源进行“写入”权限的集中分配( 即针对用户组进 行 ) 时,这个时候该组中的“ shyzhong ”账户将自动拥有“写入”的权限。

  但令人奇怪的是, “shyzhong ”账户明明拥有对这个资源的“写入”权限,为什么实际操作中却无法执行呢?原来,在“ shyzhongs ”组中同样也对 “ shyzhong ”用户进行了针对这个资源的权限设置,但设置的权限是“拒绝写入”。基于“拒绝优于允许”的原则,“ shyzhong ”在 “ shyzhongs”组中被 “拒绝写入”的权限将优先于“ xhxs ”组中被赋予的允许“写入”权限被执行。因此,在实际操作中,“ shyzhong ”用户无法对这个资源进行“写入” 操作。

  2. 权限最小化原则

  Windows XP 将“保持用户最小的权限”作为一个基本原则进行执行,这一点是非常有必要的。这条原则可以确保资源得到最大的安全保障。这条原则可以尽量让用户不能访问或不必要访问的资源得到有效的权限赋予限制。

   基于这条原则,在实际的权限赋予操作中,我们就必须为资源明确赋予允许或拒绝操作的权限。例如系统中新建的受限用户“shyzhong ”在默认状态下对 “ DOC ”目录是没有任何权限的,现在需要为这个用户赋予对“ DOC ”目录有“读取”的权限,那么就必须在“ DOC ”目录的权限列表中为 “ shyzhong ”用户添加“读取”权限。

  3. 权限继承性原则

  权限 继承性原则可以让资源的权限设置变得更加简单。假设现在有个“DOC ”目录,在这个目录中有“ DOC01 ”、“ DOC02 ”、“ DOC03”等子目录,现 在需要对 DOC 目录及其下的子目录均设置“ shyzhong ”用户有“写入”权限。因为有继承性原则,所以只需对“ DOC ”目录设置“shyzhong ” 用户有“写入”权限,其下的所有子目录将自动继承这个权限的设置。

  4. 累加原则

  这个原则比较好理解,假设现在“zhong ”用户既属于“ A ”用户组,也属于“ B ”用户组,它在 A 用户组的权限是“读取”,在“ B ”用户组中的权限是“写入”,那么根据累加原则,“ zhong ”用户的实际权限将会是“读取 + 写入”两种。

  显然,“拒绝优于允许”原则是用于解决权限设置上的冲突问题的;“权限最小化”原则是用于保障资源安全的;“权限继承性”原则是用于“自动化”执行权限设置的;而“累加原则”则是让权限的设置更加灵活多变。几个原则各有所用,缺少哪一项都会给权限的设置带来很多麻烦!

   注意:在Windows XP 中,“ Administrators ”组的全部成员都拥有“取得所有者身份” (Take Ownership) 的权力,也就是管理员组的成员可以从其他用户手中“夺取”其身份的权力,例如受限用户“ shyzhong ”建立了一个 DOC 目录,并 只赋予自己拥有读取权力,这看似周到的权限设置,实际上,“ Administrators ”组的全部成员将可以通过“夺取所有权”等方法获得这个权限。

  四、资源权限高级应用

  以文件与文件夹的权限为例,依据是否被共享到网络上,其权限可以分为NTFS 权限与共享权限两种,这两种权限既可以单独使用,也可以相辅使用。两者之间既能够相互制约,也可以相互补充。下面来看看如何进行设置:

  1.NTFS 权限

  首先我们要知道:只要是存在NTFS 磁盘分区上的文件夹或文件,无论是否被共享,都具有此权限。此权限对于使用 FAT16/FAT32 文件系统的文件与文件夹无效!

  NTFS 权限有两大要素:一是标准访问权限;二是特别访问权限。前者将一些常用的系统权限选项比较笼统地组成 6 种“套餐型”的权限,即:完全控制、修改、读取和运行、列出文件夹目录、读取、写入。

   在大多数的情况下,“标准权限”是可以满足管理需要的,但对于权限管理要求严格的环境,它往往就不能令管理员们满意了,如只想赋予某用户有建立文件夹的 权限,却没有建立文件的权限;如只能删除当前目录中的文件,却不能删除当前目录中的子目录的权限等……这个时候,就可以让拥有所有权限选项的“特别权限” 来大显身手了。也就是说,特别权限不再使用“套餐型”,而是使用可以允许用户进行“菜单型”的细节化权限管理选择了。

  那么如何设置标准访问权限呢?以对一个在NTFS 分区中的名为“ zhiguo ”的文件夹进行设置标准访问权限为例,可以按照如下方法进行操作:

   因为NTFS 权限需要在资源属性页面的“安全”选项卡设置界面中进行,而 Windows XP 在安装后默认状态下是没有激活“安全”选项卡设置功能的,所以需要首先启用系统中的“安全”选项卡。方法是:依次点击“开始”→“设置”→“控制面 板”,双击“文件夹选项”,在“查看”标签页设置界面上的“高级设置”选项列表中清除“使用简单文件共享 ( 推荐 ) ”选项前的复选框后点击“应用”按钮即 可。

  设置完毕后就可以右键点击“zhiguo ”文件夹,在弹出的快捷菜单中选择“共享与安全”,在“ zhiguo  属性”窗口中就可以看见“安全”选项卡的存在了。针对资源进行 NTFS 权限设置就是通过这个选项卡来实现的,此时应首先在“组或用户名称”列表中选择需要 赋予权限的用户名组 ( 这里选择“ zhong ”用户 ) ,接着在下方的“ zhong  的权限”列表中设置该用户可以拥有的权限即可。

  下面简单解释一下六个权限选项的含义:

  ①完全控制(Full Control) :该权限允许用户对文件夹、子文件夹、文件进行全权控制,如修改资源的权限、获取资源的所有者、删除资源的权限等,拥有完全控制权限就等于拥有了其他所有的权限;

  ②修改(Modify) :该权限允许用户修改或删除资源,同时让用户拥有写入及读取和运行权限;

  ③读取和运行(Read & Execute) :该权限允许用户拥有读取和列出资源目录的权限,另外也允许用户在资源中进行移动和遍历,这使得用户能够直接访问子文件夹与文件,即使用户没有权限访问这个路径;

  ④列出文件夹目录(List Folder Contents) :该权限允许用户查看资源中的子文件夹与文件名称;

  ⑤读取(Read) :该权限允许用户查看该文件夹中的文件以及子文件夹,也允许查看该文件夹的属性、所有者和拥有的权限等;

  ⑥写入(Write) :该权限允许用户在该文件夹中创建新的文件和子文件夹,也可以改变文件夹的属性、查看文件夹的所有者和权限等。

   如果在“组或用户名称”列表中没有所需的用户或组,那么就需要进行相应的添加操作了,方法如下:点击“添加”按钮后,在出现的“选择用户和组”对话框 中,既可以直接在“输入对象名称来选择”文本区域中输入用户或组的名称( 使用“计算机名 / 用户名”这种方式 ) ,也可以点击“高级”按钮,在弹出的对话框中 点击“立即查找”按钮让系统列出当前系统中所有的用户组和用户名称列表。此时再双击选择所需用户或组将其加入即可。如图 2 所示。

   如果想删除某个用户组或用户的话,只需在“组或用户名称”列表中选中相应的用户或用户组后,点击下方的“删除”按钮即可。但实际上,这种删除并不能确保 被删除的用户或用户组被拒绝访问某个资源,因此,如果希望拒绝某个用户或用户组访问某个资源,还要在“组或用户名称”列表中选择相应的用户名用户组后,为 其选中下方的“拒绝”复选框即可。

  那么如何设置特殊权限呢?假设现在需要对一个名为“zhiguo ”的目录赋予 “ zhong ”用户对其具有“读取”、“建立文件和目录”的权限,基于安全考虑,又决定取消该账户的“删除”权限。此时,如果使用“标准权限”的话,将无 法完成要求,而使用特别权限则可以很轻松地完成设置。

   首先,右键点击“zhiguo ”目录,在右键快捷菜单中选择“共享与安全”项,随后在“安全”选项卡设置界面中选中“ zhong ”用户并点击下方的“高 级”按钮,在弹出的对话框中点击清空“从父项继承那些可以应用到子对象的权限项目,包括那些在此明确定义的项目”项选中状态,这样可以断开当前权限设置与 父级权限设置之前的继承关系。在随即弹出的“安全”对话框中点击“复制”或“删除”按钮后 ( 点击“复制”按钮可以首先复制继承的父级权限设置,然后再断开 继承关系 ) ,接着点击“应用”按钮确认设置,再选中“ zhong ”用户并点击“编辑”按钮,在弹出的“ zhong 的权限项目”对话框中请首先点击“全部清 除”按钮,接着在“权限”列表中选择“遍历文件夹 / 运行文件”、“列出文件夹 / 读取数据”、“读取属性”、“创建文件 / 写入数据”、“创建文件夹 / 附加数 据”、“读取权限”几项,最后点击“确定”按钮结束设置。

  在经过上述设置后,“zhong ”用户在对“ zhiguo ”进行删除操作时,就会弹出提示框警告操作不能成功的提示了。显然,相对于标准访问权限设置上的笼统,特别访问权限则可以实现更具体、全面、精确的权限设置。

  为了大家更好地理解特殊权限列表中的权限含义,以便做出更精确的权限设置,下面简单解释一下其含义:

   ⑴遍历文件夹/ 运行文件 (Traverse Folder/Execute File) :该权限允许用户在文件夹及其子文件夹之间移动 ( 遍历 ) ,即使这些文件夹本身没有访问权限。注意:只有当在“组策略”中 ( “计算机配置”→ “ Windows 设置”→“安全设置”→“本地策略”→“用户权利指派” ) 将“跳过遍历检查”项授予了特定的用户或用户组,该项权限才能起作用。默认状态 下,包括“ Administrators ”、“ Users ”、“ Everyone ”等在内的组都可以使用该权限。对于文件来说,拥了这项权限后,用户可以 执行该程序文件。但是,如果仅为文件夹设置了这项权限的话,并不会让用户对其中的文件带上“执行”的权限;

  ⑵列出文件/ 读取数据 (List Folder/Read Data) :该权限允许用户查看文件夹中的文件名称、子文件夹名称和查看文件中的数据;

  ⑶读取属性(Read Attributes) :该权限允许用户查看文件或文件夹的属性 ( 如系统、只读、隐藏等属性 ) ;

  ⑷读取扩展属性(Read Extended Attributes) :该权限允许查看文件或文件夹的扩展属性,这些扩展属性通常由程序所定义,并可以被程序修改;

  ⑸创建文件/ 写入属性 (Create Files/Write Data) :该权限允许用户在文件夹中创建新文件,也允许将数据写入现有文件并覆盖现有文件中的数据;

  ⑹创建文件夹/ 附加数据 (Create Folder/Append Data) :该权限允许用户在文件夹中创建新文件夹或允许用户在现有文件的末尾添加数据,但不能对文件现有的数据进行覆盖、修改,也不能删除数据;

  ⑺写入属性(Write Attributes) :该权限允许用户改变文件或文件夹的属性;

  ⑻写入扩展属性(Write Extended Attributes) :该权限允许用户对文件或文件夹的扩展属性进行修改;

  ⑼删除子文件夹及文件(Delete Subfolders and Files) :该权限允许用户删除文件夹中的子文件夹或文件,即使在这些子文件夹和文件上没有设置删除权限;

  ⑽删除(Delete) :该权限允许用户删除当前文件夹和文件,如果用户在该文件或文件夹上没有删除权限,但是在其父级的文件夹上有删除子文件及文件夹权限,那么就仍然可以删除它;

  ⑾读取权限(Read Permissions) :该权限允许用户读取文件或文件夹的权限列表;

  ⑿更改权限(Change Permissions) :该权限允许用户改变文件或文件夹上的现有权限;

  ⒀取得所有权(Take Ownership) :该权限允许用户获取文件或文件夹的所有权,一旦获取了所有权,用户就可以对文件或文件夹进行全权控制。

   这里需要单独说明一下“修改”权限与“写入”权限的区别:如果仅仅对一个文件拥有修改权限,那么,不仅可以对该文件数据进行写入和附加,而且还可以创建 新文件或删除现有文件。而如果仅仅对一个文件拥有写入权限,那么既可以对文件数据进行写入和附加,也可以创建新文件,但是不能删除文件。也就是说,有写入 权限不等于具有删除权限,但拥有修改权限,就等同于拥有删除和写入权限。

  2. 共享权限 (Shared Permission)

   只要是共享出来的文件夹就一定具有此权限。如该文件夹存在于NTFS 分区中,那么它将同时具有 NTFS 权限与共享权限,如果这个资源同时拥有NTFS 和 共享两种权限,那么系统中对权限的具体实施将以两种权限中的“较严格的权限”为准──这也是“拒绝优于允许”原则的一种体现!

  例如,某个共享资源的NTFS 权限设置为完全控制,而共享权限设置为读取,那么远程用户就只能使用“读取”权限对共享资源进行访问了。

   注意:如果是FAT16/FAT32 文件系统中的共享文件夹,那么将只能受到共享权限的保护,这样一来就容易产生安全性漏洞。这是因为共享权限只能够限 制从网络*问资源的用户,并无法限制直接登录本机的人,即用户只要能够登录本机,就可以任意修改、删除 FAT16/FAT32 分区中的数据了。因此,从 安全角度来看,我们是不推荐在 Windows XP 中使用 FAT16/FAT32 分区的。

  设置共享权限很简单,在 右键选中并点击一个文件夹后,在右键快捷菜单中选择“共享与安全”项,在弹出的属性对话框“共享”选项卡设置界面中点击选中“共享该文件夹”项即可,这将 使共享资源使用默认的权限设置( 即“ Everyone ”用户拥有读取权限 ) 。如果想具体设置共享权限,那么请点击“权限”按钮,在打开的对话框中可以看到 权限列表中有“完全控制”、“更改”和“读取”三项权限可供选择。

  下面先简单介绍一下这三个权限的含义:

  ①完全控制:允许用户创建、读取、写入、重命名、删除当前文件夹中的文件以及子文件夹,另外,也可以修改该文件夹中的NTFS 访问权限和夺取所有权;

  ②更改:允许用户读取、写入、重命名和删除当前文件夹中的文件和子文件夹,但不能创建新文件;

  ③读取:允许用户读取当前文件夹的文件和子文件夹,但是不能进行写入或删除操作。

  说完了权限的含义,我们就可以点击“添加”按钮,将需要设置权限的用户或用户组添加进来了。在缺省情况下,当添加新的组或用户时,该组或用户将具备“读取”(Read) 权限,我们可以根据实际情况在下方的权限列表中进行复选框的选择与清空。

   接着再来说说令很多读者感到奇怪的“组和用户名称”列表中的“Everyone ”组的含义。在 Windows 2000 中,这个组因为包含了“Anonymous Logon ”组,所以它表示“每个人”的意思。但在 Windows XP 中,请注意──这个组因为只包括“ Authenticated Users ”和“ Guests ”两个组,而不再包括“ Anonymous Logon ”组,所以它表示了“可访问计算机的所有用户”,而不再是“每个人”!请注意这是有区别的,“可访问计算机的所有用户”意味着必须是通过认证的 用户,而“每个人”则不必考虑用户是否通过了认证。从安全方面来看,这一点是直接导致安全隐患是否存在关键所在!

   当然,如果想在Windows XP 中实现 Windows 2000 中那种“ Everyone ”设计机制,那么可以通过编辑“本地安全策略”来实现,方法是:在“运行”栏中输入“ Secpol.msc ”命令打开 “安全设置”管理单元,依次展开“安全设置”→“本地策略”,然后进入“安全选项”,双击右侧的“网络访问:让‘每个人’权限应用于匿名用户”项,然后选 择“已启用”项既可。

  注意:在Windows XP Professional 中,最多可以同时有 10 个用户通过网络登录 ( 指使用认证账户登录的用户,对于访问由 IIS 提供的 Web 服务的用户没有限制 ) 方式使用某一台计算机提供的共享资源。

  3. 资源复制或移动时权限的变化与处理

  在权限的应用中,不可避免地会遇到设置了权限后的资源需要复制或移动的情况,那么这个时候资源相应的权限会发生怎样的变化呢?下面来了解一下:

  (1) 复制资源时

  在复制资源时,原资源的权限不会发生变化,而新生成的资源,将继承其目标位置父级资源的权限。

  (2) 移动资源时

   在移动资源时,一般会遇到两种情况,一是如果资源的移动发生在同一驱动器内,那么对象保留本身原有的权限不变( 包括资源本身权限及原先从父级资源中继承 的权限 ) ;二是如果资源的移动发生在不同的驱动器之间,那么不仅对象本身的权限会丢失,而且原先从父级资源中继承的权限也会被从目标位置的父级资源继承的 权限所替代。实际上,移动操作就是首先进行资源的复制,然后从原有位置删除资源的操作。

  (3) 非 NTFS 分区

  上述复制或移动资源时产生的权限变化只是针对NTFS 分区上而言的,如果将资源复制或移动到非 NTFS 分区 ( 如 FAT16/FAT32 分区 ) 上,那么所有的权限均会自动全部丢失。

  4. 资源所有权的高级管理

   有时我们会发现当前登录的用户无法对某个资源进行任何操作,这是什么原因呢?其实这种常见的现象很有可能是因为对某个资源进行的NTFS 权限设置得不够 完善导致的──这将会造成所有人 ( 包括“ Administrator ”组成员 ) 都无法访问资源,例如不小心将“ zhiguo ”这个文件夹的所有用户都删除 了,这将会导致所有用户都无法访问这个文件夹,此时很多朋友就会束手无策了,其实通过使用更改所有权的方法就可以很轻松地解决这类权限问题了。

   首先,我们需要检查一下资源的所有者是谁,如果想查看某个资源( 如 sony 目录 ) 的用户所有权的话,那么只需使用“ dir sony /q ”命令就可以了。在反馈信息的第一行就可以看到用户是谁了,例如第一行的信息是“ lovebook/zhong ”,那么意思就是 lovebook 这台 计算机中的“ zhong ”用户。

  如果想在图形界面中查看所有者是谁,那么需要进入资源的属性对话框,点击“安全”选项卡设置界面中的“高级”按钮,在弹出的“( 用户名 ) 高级安全设置”界面中点击“所有者”选项卡,从其中的“目前该项目的所有者”列表中就可以看到当前资源的所有者是谁了。

  如果想将所有者更改用户,那么只需在“将所有者更改为”列表中选择目标用户名后,点击“确定”按钮即可。此外,也可以直接在“安全”选项卡设置界面中点击“添加”按钮添加一个用户并赋予相应的权限后,让这个用户来获得当前文件夹的所有权。

  注意:查看所有者究竟对资源拥有什么样的权限,可点击进入“有效权限”选项卡设置界面,从中点击“选择”按钮添加当前资源的所有者后,就可以从下方的列表中权限选项的勾取状态来获知了。

  五、程序使用权限设定

  Windows XP 操作系统在文件管理方面功能设计上颇为多样、周全和智能化。这里通过“程序文件使用权限”设置、将“加密文件授权多个用户可以访问”和了解系统日志的访问权限三个例子给大家解释一下如何进行日常应用。

  1. 程序文件权限设定

  要了解Windows XP 中关于程序文件的访问权限,我们应首先来了解一下 Windows XP 在这方面的两个设计,一是组策略中 软件  限制策略的设计;二是临时分配程序文件使用权限的设计。

  (1) 软件限制策略

   在“运行”栏中输入“Gpedit.msc ”命令打开组策略窗口后,在“计算机配置”→“ Windows 设置”→“安全设置”分支中,右键选中“软件限 制策略”分支,在弹出的快捷菜单中选择新建一个策略后,就可以从“软件限制策略”分支下新出现的“安全级别”中看到有两种安全级别的存在了。

  这两条安全级别对于程序文件与用户权限之前是有密切联系的:

  ①不允许的:从其解释中可以看出,无论用户的访问权如何,软件都不会运行;

   ②不受限的:这是默认的安全级别,其解释为“软件访问权由用户的访问权来决定”。显然,之所以在系统中可以设置各种权限,是因为有这个默认安全策略在背 后默默支持的缘故。如果想把“不允许的" 安全级别设置为默认状态,只需双击进入其属性界面后点击“设为默认值”按钮即可。

  (2) 临时分配程序文件

   为什么要临时分配程序文件的管理权限呢?这是因为在Windows XP 中,有许多很重要的程序都是要求用户具有一定的管理权限才能使用的,因此在使用权限不足以使用某些程序的账户时,为了能够使用程序,我们就需要为自己 临时分配一个访问程序的管理权限了。为程序分配临时管理权限的方法很简单:右键点击要运行的程序图标,在弹出的快捷菜单中选择“运行方式”,在打开的“运 行身份”对话框中选中“下列用户”选项,在“用户名”和“密码”右侧的文本框中指定用户及密码即可。

  显然,这个临时切换程序文件管理权限的设计是十分有必要的,它可以很好地起到保护系统的目的。

  2. 授权多个用户访问加密文件

  Windows XP 在 EFS 上的改进之一就是可以允许多个用户访问加密文件,这些用户既可以是本地用户,也可以是域用户或受信任域的用户。由于无法将证书颁发给用户组,而只能颁发给用户,所以只能授权单个的账户访问加密文件,而用户组将不能被授权。

  要授权加密文件可以被多个用户访问,可以按照如下方法进行操作:

   选中已经加密的文件,用鼠标右键点击该加密文件,选择“属性”,在打开的属性对话框中“常规”选项卡下点击“高级”按钮,打开加密文件的高级属性对话 框,点击其中的“详细信息”按钮( 加密文件夹此按钮无效 ) ,在打开的对话框中点击“添加”按钮添加一个或多个新用户即可 ( 如果计算机加入了域,则还可以点 击“寻找用户”按钮在整个域范围内寻找用户 ) 。

  3. 日志的访问权限

   什么是日志?我们可以将日志理解为系统日记,这本“日记”可以按系统管理员预先的设定,自动将系统中发生的所有事件都一一记录在案,供管理员查询。既然 日志信息具有如此重要的参考作用,那么就应该做好未经授权的用户修改或查看的权限控制。因此,我们非常有必要去了解一下日志的访问权限在Windows XP 中是怎样设计的。一般来说, Administrators 、 SYSTEM 、 Everyone 三种类型的账户可以访问日志。

  这三种类型的账户对不同类型的日志拥有不同的访问权限,下面来看一下表格中具体的说明,请注意“√”表示拥有此权限;“×”表示无此权限。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

对应用程序日志的权限

 

账户

 

读取

 

写入

 

清除

 

Administrators

 

 

 

 

 

SYSTEM

 

 

 

 

 

Everyone

 

 

 

×

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

对安全日志的权限

 

账户

 

读取

 

写入

 

清除

 

Administrators

 

 

×

 

 

 

SYSTEM

 

 

 

 

 

Everyone

 

×

 

×

 

×

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

对系统日志的权限

 

账户

 

读取

 

写入

 

清除

 

Administrators

 

 

 

 

 

SYSTEM

 

 

 

 

 

Everyone

 

 

×

 

×

  通过对比,可以看出SYSTEM拥有的权限最高,可以对任意类型的日志进行读写和清除操作;Everyone用户则可以读取应用程序和系统日 志,但对安全日志无法读取。这是因为安全日志相对其他几种类型的日志在安全性方面的要求要高一些,只有SYSTEM能够对之写入。

  如果想为其他用户赋予管理审核安全日志的权限,那么可以在“运行”栏中输入“Gpedit.msc”命令打开组策略编辑器窗口后,依次进入“计 算机配置”→“Windows设置”→“安全设置”→“本地策略”→“用户权利指派”,双击右侧的“管理审核和安全日志”项,在弹出的对话框中添加所需的 用户即可。

  六、内置安全主体与权限

  在Windows XP中,有一群不为人知的用户,它们的作用是可以让我们指派权限到某种“状态”的用户(如“匿名用户”、“网络用户”)等,而不是某个特定的用户或组(如 “zhong”、“CPCW”这类用户)。这样一来,对用户权限的管理就更加容易精确控制了。这群用户在Windows XP中,统一称为内置安全主体。下面让我们来了解一下:

  1.安全主体的藏身之处

  下面假设需要为一个名为“zhiguo”的目录设置内置安全主体中的“Network”类用户权限为例,看看这群“默默无闻”的用户藏身在系统何处。

  首先进入“zhiguo”目录属性界面的“安全”选项卡设置界面,点击其中的“添加”按钮,在弹出的“选择用户或组”对话框中点击“对象类型”按钮。在弹出对话框中只保留列表中的“内置安全主体”项,并点击“确定”按钮。

  在接下来的对话框中点击“高级”按钮,然后在展开的对话框中点击“立即查找”按钮,就可以看到内置安全主体中包含的用户列表了。

 

  2.安全主体作用说明

  虽然内置安全主体有很多,但正常能在权限设置中使用到的并不多,所以下面仅说明其中几个较重要的:

  ①Anonymous Logon:任何没有经过Windows XP验证程序(Authentication),而以匿名方式登录域的用户均属于此组;

  ②Authenticated Users:与前项相反,所有经过Windows XP验证程序登录的用户均属于此组。设置权限和用户权力时,可考虑用此项代替Everyone组;

  ③BATCH:这个组包含任何访问这台计算机的批处理程序(Batch Process);

  ④DIALUP:任何通过拨号网络登录的用户;

  ⑤Everyone:指所有经验证登录的用户及来宾(Guest);

  ⑥Network:任何通过网络登录的用户;

  ⑦Interactive:指任何直接登录本机的用户;

  ⑧Terminal server user:指任何通过终端服务登录的用户。

  ……

  在明白了内置安全主体的作用后,在进行权限的具体指派时就可以让权限的应用精确程度更高、权限的应用效果更加高效。显然,Windows XP中设置此类账户是十分有必要的,毕竟计算机是以应用为主,以应用类型进行账户分类,必然会使权限的管理不再混乱,管理更加合理!

 

Windows XP权限整合应用全解(二)

接着再来说说令很多读者感到奇怪的" 组和用户名称" 列表中的"Everyone" 组的含义。在Windows 2000 中,这个组因为包含了"Anonymous Logon" 组,所以它表示" 每个人" 的意思。但在Windows XP 中,请注意── 这个组因为只包括"Authenticated Users" 和"Guests" 两个组,而不再包括"Anonymous Logon" 组,所以它表示了" 可访问计算机的所有用户" ,而不再是" 每个人" !请注意这是有区别的," 可访问计算机的所有用户" 意味着必须是通过认证的用户,而" 每个人" 则不必考虑用户是否通过了认证。从安全方面来看,这一点是直接导致安全隐患是否存在关键所在! 

    当然,如果想在Windows XP 中实现Windows 2000 中那种"Everyone" 设计机制,那么可以通过编辑" 本地安全策略" 来实现,方法是:在" 运行" 栏中输入"Secpol.msc" 命令打开" 安全设置" 管理单元,依次展开" 安全设置"→" 本地策略" ,然后进入" 安全选项" ,双击右侧的" 网络访问:让‘ 每个人’ 权限应用于匿名 
用户" 项,然后选择" 已启用" 项即可。 

    注意:在Windows XP Professional 中,最多可以同时有10 个用户通过网络登录( 指使用认证账户登录的用户,对于访问由IIS 提供的Web 服务的用户没有限制) 方式使用某一台计算机提供的共享资源。 

3. 资源复制或移动时权限的变化与处理 

    在权限的应用中,不可避免地会遇到设置了权限后的资源需要复制或移动的情况,那么这个时候资源相应的权限会发生怎样的变化呢?下面来了解一下: 

(1) 复制资源时 

   在复制资源时,原资源的权限不会发生变化,而新生成的资源,将继承其目标位置父级资源的权限。 

(2) 移动资源时 

    在移动资源时,一般会遇到两种情况,一是如果资源的移动发生在同一驱动器内,那么对象保留本身原有的权限不变( 包括资源本身权限及原先从父级资源中继承的权限) ;二是如果资源的移动发生在不同的驱动器之间,那么不仅对象本身的权限会丢失,而且原先从父级资 源中继承的权限也会被从目标位置的父级资源继承的权限所替代。实际上,移动操作就是首先进行资源的复制,然后从原有位置删除资源的操作。 

(3) 非NTFS 分区 

    上述复制或移动资源时产生的权限变化只是针对NTFS 分区上而言的,如果将资源复制或移动到非NTFS 分区( 如FAT16/FAT32 分区) 上,那么所有的权限均会自动全部丢失。 

4. 资源所有权的高级管理 

    有时我们会发现当前登录的用户无法对某个资源进行任何操作,这是什么原因呢?其实这种常见的现象很有可能是因为对某个资源进行的NTFS 权限设置得不够完善导致的── 这将会造成所有人( 包括 "Administrator" 组成员) 都无法访问资源,例如不小心将"zhiguo" 这个文件夹的所有用户都删除了,这将会导致所有用户都无法访问这个文件夹,此时很多朋友就会束手无策了,其实通过使用更改所有权的方法就可以很轻松地解决这类权限问题了。 

   首先,我们需要检查一下资源的所有者是谁,如果想查看某个资源( 如sony 目录) 的用户所有权的话,那么只需使用"dir sony /q" 命令就可以了。在反馈信息的第一行就可以看到用户是谁了,例如第一行的信息是"lovebook/zhong" ,那么意思就是lovebook 这台计算机中的"zhong" 用户。 
    如果想在图形界面中查看所有者是谁,那么需要进入资源的属性对话框,点击" 安全" 选项卡设置界面中的" 高级" 按钮,在弹出的"( 用户名) 高级安全设置" 界面中点击" 所有者" 选项卡,从其中的" 目前该项目的所有者" 列表中就可以看到当前资源的所有者是谁了。 

    如果想将所有者更改用户,那么只需在" 将所有者更改为" 列表中选择目标用户名后,点击" 确定" 按钮即可。此外,也可以直接在" 安全" 选项卡设置界面中点击" 添加" 按钮添加一个用户并赋予相应的权限后,让这个用户来获得当前文件夹的所有权。 

    注意:查看所有者究竟对资源拥有什么样的权限,可点击进入" 有效权限" 选项卡设置界面,从中点击" 选择" 按钮添加当前资源的所有者后,就可以从下方的列表中权限选项的勾取状态来获知了。 

五、程序使用权限设定 

    Windows XP 操作系统在文件管理方面功能设计上颇为多样、周全和智能化。这里通过" 程序文件使用权限" 设置、将" 加密文件授权多个用户可以访问" 和了解系统日志的访问权限三个例子给大家解释一下如何进行日常应用。 

1. 程序文件权限设定 

    要了解Windows XP 中关于程序文件的访问权限,我们应首先来了解一下Windows XP 在这方面的两个设计, 
一、是组策略中软件限制策略的设计; 
二、是临时分配程序文件使用权限的设计。 

(1) 软件限制策略 

    在" 运行" 栏中输入 "Gpedit.msc" 命令打开组策略窗口后,在" 计算机配置"→"Windows 设置"→" 安全设置" 分支中,右键选中" 软件限制策略" 分 
支,在弹出的快捷菜单中选择新建一个策略后,就可以从" 软件限制策略" 分支下新出现的" 安全级别" 中看到有两种安全级别的存在了。 

    这两条安全级别对于程序文件与用户权限之前是有密切联系的: 

① 不允许的:从其解释中可以看出,无论用户的访问权如何,软件都不会运行; 

② 不受限的:这是默认的安全级别,其解释为 " 软件访问权由用户的访问权来决定" 。显然,之所以在系统中可以设置各种权限,是因为有这个默认安全策略在背后默默支持的缘故。如果想把" 不允许的" 安全级别设置为默认状态,只需双击进入其属性界面后点击" 设为默认值" 按钮即可。 

(2) 临时分配程序文件 

    为什么要临时分配程序文件的管理权限呢?这是因为在Windows XP 中,有许多很重要的程序都是要求用户具有一定的管理权限才能使用的,因此在使用权限不足以使用某些程序的账户时,为了能够使用程序,我们就需要为自己临时分配一个访问程序的管理权限了。为程序分配临时管理权限的方法很简单:右键点击要运行的程序图标, 在弹出的快捷菜单中选择" 运行方式" ,在打开的" 运行身份" 对话框中选中" 下列用户" 选项,在" 用户名" 和" 密码" 右侧的文本框中指定用户及密码即可。 

    显然,这个临时切换程序文件管理权限的设计是十分有必要的,它可以很好地起到保护系统的目的。 

2. 授权多个用户访问加密文件 

    Windows XP 在EFS 上的改进之一就是可以允许多个用户访问加密文件,这些用户既可以是本地用户,也可以是域用户或受信任域的用户。由于无法将证书颁发给用户组,而只能颁发给用户,所以只能授权单个的账户访问加密文件,而用户组将不能被授权。 

    要授权加密文件可以被多个用户访问,可以按照如下方法进行操作: 

    选中已经加密的文件,用鼠标右键点击该加密文件,选择" 属性" ,在打开的属性对话框中" 常规" 选项卡下点击" 高级" 按钮,打开加密文件的高级属性对话框,点击其中的" 详细信息" 按钮( 加密文件夹此按钮无效) ,在打开的对话框中点击" 添加" 按钮添加一个或多个新用户即可( 如果计算机加入了域,则还可以点击" 寻找用户" 按钮在整个域范围内寻找用户) 。 

    如果要删除某个用户对加密文件的访问权限,那么只需选中此用户后点击" 删除" 按钮即可。 

3. 日志的访问权限 

    什么是日志?我们可以将日志理解为系统日记,这本" 日记" 可以按系统管理员预先的设定,自动将系统中发生的所有事件都一一记录在案,供管理员查询。既然日志信息具有如此重要的参考作用,那么就应该做好未经授权的用户修改或查看的权限控制。因此,我们非常有必要去了解一下日志的访问权限在Windows XP 中是怎样设计的。一般来说,Administrators 、SYSTEM 、Everyone 三种类型的账户可以访问日志。 

    这三种类型的账户对不同类型的日志拥有不同的访问权限,下面来看一下表格中具体的说明,请注意"√" 表示拥有此权限;"×" 表示无此权限。 

    通过对比,可以看出SYSTEM 拥有的权限最高,可以对任意类型的日志进行读写和清除操作;Everyone 用户则可以读取应用程序和系统日志,但对安全日志无法读取。这是因为安全日志相对其他几种类型的日志在安全性方面的要求要高一些,只有SYSTEM 能够对之写入。 

    如果想为其他用户赋予管理审核安全日志的权限,那么可以在" 运行" 栏中输入"Gpedit.msc" 命令打开组策略编辑器窗口后,依次进入" 计算机配置"→"Windows 设置"→" 安全设置 "→" 本地策略"→" 用户权利指派" ,双击右侧的" 管理审核和安全日志" 项,在弹出的对话框中添加所需的用户即可。 

六、内置安全主体与权限 

    在Windows XP 中,有一群不为人知的用户,它们的作用是可以让我们指派权限到某种" 状态" 的用户( 如" 匿名用户" 、" 网络用户") 等,而不是某个特定的用户或组( 如 "zhong" 、"CPCW" 这类用户) 。这样一来,对用户权限的管理就更加容易精确控制了。这群用户在Windows XP 中,统一称 

    为内置安全主体。下面让我们来了解一下 
1. 安全主体的藏身之处 
    下面假设需要为一个名为"zhiguo" 的目录设置内置安全主体中的"Network" 类用户权限为例,看看这群" 默默无闻" 的用户藏身在系统何处。 
    首先进入"zhiguo" 目录属性界面的" 安全" 选项卡设置界面,点击其中的" 添加" 按钮,在弹出的" 选择用户或组" 对话框中点击" 对象类型" 按钮。 
    在弹出对话框中只保留列表中的" 内置安全主体" 项,并点击" 确定" 按钮。 
    在接下来的对话框中点击" 高级" 按钮,然后在展开的对话框中点击" 立即查找" 按钮,就可以看到内置安全主体中包含的用户列表了。 
2. 安全主体作用说明 
    虽然内置安全主体有很多,但正常能在权限设置中使用到的并不多,所以下面仅说明其中几个较重要的: 
①Anonymous Logon :任何没有经过Windows XP 验证程序(Authentication) ,而以匿名方式登录域的用户均属于此组; 
②Authenticated Users :与前项相反,所有经过Windows XP 验证程序登录的用户均属于此组。设置权限和用户权力时,可考虑用此项代替 
Everyone 组; 
③BATCH :这个组包含任何访问这台计算机的批处理程序(Batch Process) ; 
④DIALUP :任何通过拨号网络登录的用户; 
⑤Everyone :指所有经验证登录的用户及来宾(Guest) ; 
⑥Network :任何通过网络登录的用户; 
⑦Interactive :指任何直接登录本机的用户; 
⑧Terminal server user :指任何通过终端服务登录的用户。