分享

C语言中为文件设置安全属性(WIN)

 战神之家 2014-11-06
[c-sharp] view plaincopy
  1. #include <windows.h>  
  2.  
  3. #include <tchar.h>  
  4.  
  5. #include <stdio.h>  
  6.   
  7. //使用Windows的HeapAlloc函数进行动态内存分配  
  8. #define myheapalloc(x) (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, x))  
  9. #define myheapfree(x) (HeapFree(GetProcessHeap(), 0, x))  
  10. typedef BOOL (WINAPI *SetSecurityDescriptorControlFnPtr)(  
  11. IN                      PSECURITY_DESCRIPTOR pSecurityDescriptor,  
  12. IN                      SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,  
  13. IN                      SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet);  
  14.   
  15. typedef BOOL (WINAPI *AddAccessAllowedAceExFnPtr)(PACL pAcl,  
  16.         DWORD dwAceRevision, DWORD AceFlags, DWORD AccessMask, PSID pSid);  
  17.   
  18. BOOL AddAccessRights(TCHAR *lpszFileName, TCHAR *lpszAccountName, DWORD dwAccessMask);  
  19.   
  20.   
  21. int main(int argc, TCHAR *argv[]) {  
  22.     if (argc < 3) {  
  23.         _tprintf(TEXT("usage: /"%s/" <FileName> <AccountName>/n"), argv[0]);  
  24.         return 1;  
  25.     }  
  26.     // argv[1] – 文件(目录)名  
  27.     // argv[2] – 用户(组)名  
  28.     // GENERIC_ALL表示所有的权限,其是一系列的NTFS权限的或  
  29.     // NTFS的文件权限很细,还请参看MSDN。  
  30.     if (!AddAccessRights(argv[1], argv[2], GENERIC_ALL)) {  
  31.         _tprintf(TEXT("AddAccessRights() failed./n"));  
  32.         return 1;  
  33.     } else {  
  34.         _tprintf(TEXT("AddAccessRights() succeeded./n"));  
  35.         return 0;  
  36.     }  
  37. }  
  38.   
  39. BOOL AddAccessRights(TCHAR *lpszFileName, TCHAR *lpszAccountName, DWORD dwAccessMask) {  
  40.     // 声明SID变量  
  41.     SID_NAME_USE snuType;  
  42.     // 声明和LookupAccountName相关的变量(注意,全为0,要在程序中动态分配)  
  43.     TCHAR * szDomain= NULL;  
  44.     DWORD cbDomain = 0;  
  45.     LPVOID pUserSID= NULL;  
  46.     DWORD cbUserSID = 0;  
  47.     // 和文件相关的安全描述符 SD 的变量  
  48.     PSECURITY_DESCRIPTOR pFileSD= NULL; // 结构变量  
  49.     DWORD cbFileSD = 0; // SD的size  
  50.     // 一个新的SD的变量,用于构造新的ACL(把已有的ACL和需要新加的ACL整合起来)  
  51.     SECURITY_DESCRIPTOR newSD;  
  52.     // 和ACL 相关的变量  
  53.     PACL pACL= NULL;  
  54.     BOOL fDaclPresent;  
  55.     BOOL fDaclDefaulted;  
  56.     ACL_SIZE_INFORMATION AclInfo;  
  57.     // 一个新的 ACL 变量  
  58.     PACL pNewACL= NULL; //结构指针变量  
  59.     DWORD cbNewACL = 0; //ACL的size  
  60.     // 一个临时使用的 ACE 变量  
  61.     LPVOID pTempAce= NULL;  
  62.     UINT CurrentAceIndex = 0; //ACE在ACL中的位置  
  63.     UINT newAceIndex = 0; //新添的ACE在ACL中的位置  
  64.     //API函数的返回值,假设所有的函数都返回失败。  
  65.     BOOL fResult;  
  66.     BOOL fAPISuccess;  
  67.     SECURITY_INFORMATION secInfo= DACL_SECURITY_INFORMATION;  
  68.     // 下面的两个函数是新的API函数,仅在Windows 2000以上版本的操作系统支持。   
  69.     // 在此将从Advapi32.dll文件中动态载入。如果你使用VC++ 6.0编译程序,而且你想  
  70.     // 使用这两个函数的静态链接。则请为你的编译加上:/D_WIN32_WINNT=0x0500  
  71.     // 的编译参数。并且确保你的SDK的头文件和lib文件是最新的。  
  72.     SetSecurityDescriptorControlFnPtr _SetSecurityDescriptorControl= NULL;  
  73.     AddAccessAllowedAceExFnPtr _AddAccessAllowedAceEx= NULL;  
  74.       
  75.     // ##########################################################  
  76.     // STEP 1: 通过用户名取得SID  
  77.     // 在这一步中LookupAccountName函数被调用了两次,第一次是取出所需要  
  78.     // 的内存的大小,然后,进行内存分配。第二次调用才是取得了用户的帐户信息。  
  79.     // LookupAccountName同样可以取得域用户或是用户组的信息。(请参看MSDN)  
  80.     // ##########################################################  
  81.     fAPISuccess = LookupAccountName(NULL, lpszAccountName,  
  82.             pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);  
  83.     // 以上调用API会失败,失败原因是内存不足。并把所需要的内存大小传出。  
  84.     // 下面是处理非内存不足的错误。  
  85.     if (fAPISuccess)  
  86.         return FALSE;  
  87.     else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {  
  88.         _tprintf(TEXT("LookupAccountName() failed. Error %ld/n"), GetLastError());  
  89.         return FALSE;  
  90.     }  
  91.     pUserSID = myheapalloc(cbUserSID);  
  92.     if (!pUserSID) {  
  93.         _tprintf(TEXT("HeapAlloc() failed. Error %ld/n"), GetLastError());  
  94.         return FALSE;  
  95.     }  
  96.     szDomain = (TCHAR *) myheapalloc(cbDomain * sizeof(TCHAR));  
  97.     if (!szDomain) {  
  98.         _tprintf(TEXT("HeapAlloc() failed. Error %ld/n"), GetLastError());  
  99.         return FALSE;  
  100.     }  
  101.     fAPISuccess = LookupAccountName(NULL, lpszAccountName,  
  102.             pUserSID, &cbUserSID, szDomain, &cbDomain, &snuType);  
  103.     if (!fAPISuccess) {  
  104.         _tprintf(TEXT("LookupAccountName() failed. Error %ld/n"), GetLastError());  
  105.         return FALSE;  
  106.     }  
  107.       
  108.     // ##########################################################  
  109.     // STEP 2: 取得文件(目录)相关的安全描述符SD  
  110.     // 使用GetFileSecurity函数取得一份文件SD的拷贝,同样,这个函数也  
  111.     // 是被调用两次,第一次同样是取SD的内存长度。注意,SD有两种格式:自相关的  
  112.     // (self-relative)和 完全的(absolute),GetFileSecurity只能取到“自  
  113.     // 相关的”,而SetFileSecurity则需要完全的。这就是为什么需要一个新的SD,  
  114.     // 而不是直接在GetFileSecurity返回的SD上进行修改。因为“自相关的”信息  
  115.     // 是不完整的。  
  116.     // ##########################################################  
  117.     fAPISuccess = GetFileSecurity(lpszFileName, secInfo, pFileSD, 0, &cbFileSD);  
  118.     // 以上调用API会失败,失败原因是内存不足。并把所需要的内存大小传出。  
  119.     // 下面是处理非内存不足的错误。  
  120.     if (fAPISuccess)  
  121.         return FALSE;  
  122.     else if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {  
  123.         _tprintf(TEXT("GetFileSecurity() failed. Error %ld/n"), GetLastError());  
  124.         return FALSE;  
  125.     }  
  126.     pFileSD = myheapalloc(cbFileSD);  
  127.     if (!pFileSD) {  
  128.         _tprintf(TEXT("HeapAlloc() failed. Error %ld/n"), GetLastError());  
  129.         return FALSE;  
  130.     }  
  131.     fAPISuccess = GetFileSecurity(lpszFileName, secInfo, pFileSD, cbFileSD, &cbFileSD);  
  132.     if (!fAPISuccess) {  
  133.         _tprintf(TEXT("GetFileSecurity() failed. Error %ld/n"), GetLastError());  
  134.         return FALSE;  
  135.     }  
  136.     puts("STEP 2");  
  137.       
  138.     // ##########################################################  
  139.     // STEP 3: 初始化一个新的SD  
  140.     // ##########################################################  
  141.     if (!InitializeSecurityDescriptor(&newSD, SECURITY_DESCRIPTOR_REVISION)) {  
  142.         _tprintf(TEXT("InitializeSecurityDescriptor() failed.")  
  143.                 TEXT("Error %ld/n"), GetLastError());  
  144.         return FALSE;  
  145.     }  
  146.     puts("STEP 3");  
  147.       
  148.     // ##########################################################  
  149.     // STEP 4: 从GetFileSecurity 返回的SD中取DACL  
  150.     // ##########################################################  
  151.     if (!GetSecurityDescriptorDacl(pFileSD, &fDaclPresent, &pACL, &fDaclDefaulted)) {  
  152.         _tprintf(TEXT("GetSecurityDescriptorDacl() failed. Error %ld/n"), GetLastError());  
  153.         return FALSE;  
  154.     }  
  155.     puts("STEP 4");  
  156.       
  157.     // ##########################################################  
  158.     // STEP 5: 取 DACL的内存size  
  159.     // GetAclInformation可以提供DACL的内存大小。只传入一个类型为  
  160.     // ACL_SIZE_INFORMATION的structure的参数,需DACL的信息,是为了  
  161.     // 方便我们遍历其中的ACE。  
  162.     // ##########################################################  
  163.     AclInfo.AceCount = 0; // Assume NULL DACL.  
  164.     AclInfo.AclBytesFree = 0;  
  165.     AclInfo.AclBytesInUse = sizeof(ACL);  
  166.     if (pACL == NULL)  
  167.         fDaclPresent = FALSE;  
  168.     // 如果DACL不为空,则取其信息。(大多数情况下“自关联”的DACL为空)  
  169.     if (fDaclPresent) {  
  170.         if (!GetAclInformation(pACL, &AclInfo, sizeof(ACL_SIZE_INFORMATION), AclSizeInformation)) {  
  171.             _tprintf(TEXT("GetAclInformation() failed. Error %ld/n"), GetLastError());  
  172.             return FALSE;  
  173.         }  
  174.     }  
  175.     puts("STEP 5");  
  176.       
  177.     // ##########################################################  
  178.     // STEP 6: 计算新的ACL的size  
  179.     // 计算的公式是:原有的DACL的size加上需要添加的一个ACE的size,以  
  180.     // 及加上一个和ACE相关的SID的size,最后减去两个字节以获得精确的大小。  
  181.     // ##########################################################  
  182.     cbNewACL = AclInfo.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pUserSID) - sizeof(DWORD);  
  183.     puts("STEP 6");  
  184.       
  185.     // ##########################################################  
  186.     // STEP 7: 为新的ACL分配内存  
  187.     // ##########################################################  
  188.     pNewACL = (PACL) myheapalloc(cbNewACL);  
  189.     if (!pNewACL) {  
  190.         _tprintf(TEXT("HeapAlloc() failed. Error %ld/n"), GetLastError());  
  191.         return FALSE;  
  192.     }  
  193.     puts("STEP 7");  
  194.       
  195.     // ##########################################################  
  196.     // STEP 8: 初始化新的ACL结构  
  197.     // ##########################################################  
  198.     if (!InitializeAcl(pNewACL, cbNewACL, ACL_REVISION2)) {  
  199.         _tprintf(TEXT("InitializeAcl() failed. Error %ld/n"), GetLastError());  
  200.         return FALSE;  
  201.     }  
  202.     puts("STEP 8");  
  203.       
  204.     // ##########################################################  
  205.     // STEP 9 如果文件(目录) DACL 有数据,拷贝其中的ACE到新的DACL中  
  206.     //   
  207.     // 下面的代码假设首先检查指定文件(目录)是否存在的DACL,如果有的话,  
  208.     // 那么就拷贝所有的ACE到新的DACL结构中,我们可以看到其遍历的方法是采用  
  209.     // ACL_SIZE_INFORMATION结构中的AceCount成员来完成的。在这个循环中,  
  210.     // 会按照默认的ACE的顺序来进行拷贝(ACE在ACL中的顺序是很关键的),在拷  
  211.     // 贝过程中,先拷贝非继承的ACE(我们知道ACE会从上层目录中继承下来)  
  212.     // ##########################################################  
  213.     newAceIndex = 0;  
  214.     if (fDaclPresent && AclInfo.AceCount) {  
  215.         for (CurrentAceIndex = 0; CurrentAceIndex < AclInfo.AceCount; CurrentAceIndex++) {  
  216.             // ##########################################################  
  217.             // STEP 10: 从DACL中取ACE  
  218.             // ##########################################################  
  219.             if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {  
  220.                 _tprintf(TEXT("GetAce() failed. Error %ld/n"), GetLastError());  
  221.                 return FALSE;  
  222.             }  
  223.             puts("STEP 10");  
  224.               
  225.             // ##########################################################  
  226.             // STEP 11: 检查是否是非继承的ACE  
  227.             // 如果当前的ACE是一个从父目录继承来的ACE,那么就退出循环。  
  228.             // 因为,继承的ACE总是在非继承的ACE之后,而我们所要添加的ACE  
  229.             // 应该在已有的非继承的ACE之后,所有的继承的ACE之前。退出循环  
  230.             // 正是为了要添加一个新的ACE到新的DACL中,这后,我们再把继承的  
  231.             // ACE拷贝到新的DACL中。  
  232.             // ##########################################################  
  233.             if (((ACCESS_ALLOWED_ACE *)pTempAce)->Header.AceFlags & INHERITED_ACE)  
  234.                 break;  
  235.               
  236.             // ##########################################################  
  237.             // STEP 12: 检查要拷贝的ACE的SID是否和需要加入的ACE的SID一样,  
  238.             // 如果一样,那么就应该废掉已存在的ACE,也就是说,同一个用户的存取  
  239.             // 权限的设置的ACE,在DACL中应该唯一。这在里,跳过对同一用户已设置  
  240.             // 了的ACE,仅是拷贝其它用户的ACE。  
  241.             // ##########################################################  
  242.               
  243.             if (EqualSid(pUserSID, &(((ACCESS_ALLOWED_ACE *)pTempAce)->SidStart)))  
  244.                 continue;  
  245.               
  246.             // ##########################################################  
  247.             // STEP 13: 把ACE加入到新的DACL中  
  248.             // 下面的代码中,注意 AddAce 函数的第三个参数,这个参数的意思是   
  249.             // ACL中的索引值,意为要把ACE加到某索引位置之后,参数MAXDWORD的  
  250.             // 意思是确保当前的ACE是被加入到最后的位置。  
  251.             // ##########################################################  
  252.             if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER) pTempAce)->AceSize)) {  
  253.                 _tprintf(TEXT("AddAce() failed. Error %ld/n"), GetLastError());  
  254.                 return FALSE;  
  255.             }  
  256.             newAceIndex++;  
  257.         }  
  258.     }  
  259.     // ##########################################################  
  260.     // STEP 14: 把一个 access-allowed 的ACE 加入到新的DACL中  
  261.     // 前面的循环拷贝了所有的非继承且SID为其它用户的ACE,退出循环的第一件事  
  262.     // 就是加入我们指定的ACE。请注意首先先动态装载了一个AddAccessAllowedAceEx  
  263.     // 的API函数,如果装载不成功,就调用AddAccessAllowedAce函数。前一个函数仅  
  264.     // 在Windows 2000以后的版本支持,NT则没有,我们为了使用新版本的函数,我们首  
  265.     // 先先检查一下当前系统中可不可以装载这个函数,如果可以则就使用。使用动态链接  
  266.     // 比使用静态链接的好处是,程序运行时不会因为没有这个API函数而报错。  
  267.     //   
  268.     // Ex版的函数多出了一个参数AceFlag(第三人参数),用这个参数我们可以来设置一  
  269.     // 个叫ACE_HEADER的结构,以便让我们所设置的ACE可以被其子目录所继承下去,而   
  270.     // AddAccessAllowedAce函数不能定制这个参数,在AddAccessAllowedAce函数  
  271.     // 中,其会把ACE_HEADER这个结构设置成非继承的。  
  272.     // ##########################################################  
  273.     _AddAccessAllowedAceEx = (AddAccessAllowedAceExFnPtr) GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),  
  274.     "AddAccessAllowedAceEx");  
  275.     if (_AddAccessAllowedAceEx) {  
  276.         if (!_AddAccessAllowedAceEx(pNewACL, ACL_REVISION2,   
  277.         CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE, dwAccessMask, pUserSID)) {  
  278.             _tprintf(TEXT("AddAccessAllowedAceEx() failed. Error %ld/n"), GetLastError());  
  279.             return FALSE;  
  280.         }  
  281.     } else {  
  282.         if (!AddAccessAllowedAce(pNewACL, ACL_REVISION2, dwAccessMask, pUserSID)) {  
  283.             _tprintf(TEXT("AddAccessAllowedAce() failed. Error %ld/n"), GetLastError());  
  284.             return FALSE;  
  285.         }  
  286.     }  
  287.       
  288.     // ##########################################################  
  289.     // STEP 15: 按照已存在的ACE的顺序拷贝从父目录继承而来的ACE  
  290.     // ##########################################################  
  291.     if (fDaclPresent && AclInfo.AceCount) {  
  292.         for (; CurrentAceIndex < AclInfo.AceCount; CurrentAceIndex++) {  
  293.             // ##########################################################  
  294.             // STEP 16: 从文件(目录)的DACL中继续取ACE  
  295.             // ##########################################################  
  296.             if (!GetAce(pACL, CurrentAceIndex, &pTempAce)) {  
  297.                 _tprintf(TEXT("GetAce() failed. Error %ld/n"), GetLastError());  
  298.                 return FALSE;  
  299.             }  
  300.             //   
  301.             // STEP 17: 把ACE加入到新的DACL中  
  302.             //   
  303.             if (!AddAce(pNewACL, ACL_REVISION, MAXDWORD, pTempAce, ((PACE_HEADER) pTempAce)->AceSize)) {  
  304.                 _tprintf(TEXT("AddAce() failed. Error %ld/n"), GetLastError());  
  305.                 return FALSE;  
  306.             }  
  307.         }  
  308.     }  
  309.     // ##########################################################  
  310.     // STEP 18: 把新的ACL设置到新的SD中  
  311.     // ##########################################################  
  312.     if (!SetSecurityDescriptorDacl(&newSD, TRUE, pNewACL, FALSE)) {  
  313.         _tprintf(TEXT("SetSecurityDescriptorDacl() failed. Error %ld/n"), GetLastError());  
  314.         return FALSE;  
  315.     }  
  316.     // ##########################################################  
  317.     // STEP 19: 把老的SD中的控制标记再拷贝到新的SD中,我们使用的是一个叫   
  318.     // SetSecurityDescriptorControl() 的API函数,这个函数同样只存在于  
  319.     // Windows 2000以后的版本中,所以我们还是要动态地把其从advapi32.dll   
  320.     // 中载入,如果系统不支持这个函数,那就不拷贝老的SD的控制标记了。  
  321.     // ##########################################################  
  322.     _SetSecurityDescriptorControl =(SetSecurityDescriptorControlFnPtr) GetProcAddress(GetModuleHandle(TEXT("advapi32.dll")),  
  323.     "SetSecurityDescriptorControl");  
  324.     if (_SetSecurityDescriptorControl) {  
  325.         SECURITY_DESCRIPTOR_CONTROL controlBitsOfInterest = 0;  
  326.         SECURITY_DESCRIPTOR_CONTROL controlBitsToSet = 0;  
  327.         SECURITY_DESCRIPTOR_CONTROL oldControlBits = 0;  
  328.         DWORD dwRevision = 0;  
  329.         if (!GetSecurityDescriptorControl(pFileSD, &oldControlBits, &dwRevision)) {  
  330.             _tprintf(TEXT("GetSecurityDescriptorControl() failed.")  
  331.                     TEXT("Error %ld/n"), GetLastError());  
  332.             return FALSE;  
  333.         }  
  334.         if (oldControlBits & SE_DACL_AUTO_INHERITED) {  
  335.             controlBitsOfInterest = SE_DACL_AUTO_INHERIT_REQ |  
  336.             SE_DACL_AUTO_INHERITED;  
  337.             controlBitsToSet = controlBitsOfInterest;  
  338.         } else if (oldControlBits & SE_DACL_PROTECTED) {  
  339.             controlBitsOfInterest = SE_DACL_PROTECTED;  
  340.             controlBitsToSet = controlBitsOfInterest;  
  341.         }  
  342.         if (controlBitsOfInterest) {  
  343.             if (!_SetSecurityDescriptorControl(&newSD, controlBitsOfInterest, controlBitsToSet)) {  
  344.                 _tprintf(TEXT("SetSecurityDescriptorControl() failed.")  
  345.                         TEXT("Error %ld/n"), GetLastError());  
  346.                 return FALSE;  
  347.             }  
  348.         }  
  349.     }  
  350.     // ##########################################################  
  351.     // STEP 20: 把新的SD设置设置到文件的安全属性中  
  352.     // ##########################################################  
  353.     if (!SetFileSecurity(lpszFileName, secInfo, &newSD)) {  
  354.         _tprintf(TEXT("SetFileSecurity() failed. Error %ld/n"), GetLastError());  
  355.         return FALSE;  
  356.     }  
  357.     fResult = TRUE;  
  358.     // ##########################################################  
  359.     // STEP 21: 释放已分配的内存,以免Memory Leak  
  360.     // ##########################################################  
  361.     if (pUserSID)  
  362.         myheapfree(pUserSID);  
  363.     if (szDomain)  
  364.         myheapfree(szDomain);  
  365.     if (pFileSD)  
  366.         myheapfree(pFileSD);  
  367.     if (pNewACL)  
  368.         myheapfree(pNewACL);  
  369.     return fResult;  
  370. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多