win32

需要首先获取特定用户的SID。

这是一些步骤,

  1. 验证输入参数。
  2. 为可能足够大的SID和域名创建缓冲区。
  3. 在循环中,调用LookupAccountName以检索提供的帐户名的SID。如果SID的缓冲区或域名的缓冲区不够大,则分别cbSid或中返回所需的缓冲区大小cchDomainName,并在下一次调用之前分配一个新的缓冲区LookupAccountName请注意,当lpSystemName参数设置为NULL时,将在本地系统上检索信息 
  4. 释放分配给域名缓冲区的内存。

然后将SID传递给SetEntriesInAclA函数,


SetEntriesInAcl函数通过将新的访问控制或审核控制信息合并到现有ACL结构中来创建新的访问控制列表(ACL)。

这是传递给SetEntriesInAcl的结构参数,

 ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = GENERIC_ALL;  //权限设置
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_USER; //特定的对象
    ea.Trustee.ptstrName = (LPTSTR)sid; //特定用户的sid

    // Create a new ACL that contains the new ACEs.
    dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);

完整代码:

#pragma comment(lib, "advapi32.lib")

#include <windows.h>
#include <stdio.h>
#include <aclapi.h>
#include <tchar.h>
#include <mq.h.>

HRESULT GetSid(
    LPCWSTR wszAccName,
    PSID* ppSid
)
{

    // Validate the input parameters.  
    if (wszAccName == NULL || ppSid == NULL)
    {
        return MQ_ERROR_INVALID_PARAMETER;
    }

    // Create buffers that may be large enough.  
    // If a buffer is too small, the count parameter will be set to the size needed.  
    const DWORD INITIAL_SIZE = 32;
    DWORD cbSid = 0;
    DWORD dwSidBufferSize = INITIAL_SIZE;
    DWORD cchDomainName = 0;
    DWORD dwDomainBufferSize = INITIAL_SIZE;
    WCHAR* wszDomainName = NULL;
    SID_NAME_USE eSidType;
    DWORD dwErrorCode = 0;
    HRESULT hr = MQ_OK;

    // Create buffers for the SID and the domain name.  
    *ppSid = (PSID) new BYTE[dwSidBufferSize];
    if (*ppSid == NULL)
    {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(*ppSid, 0, dwSidBufferSize);
    wszDomainName = new WCHAR[dwDomainBufferSize];
    if (wszDomainName == NULL)
    {
        return MQ_ERROR_INSUFFICIENT_RESOURCES;
    }
    memset(wszDomainName, 0, dwDomainBufferSize * sizeof(WCHAR));

    // Obtain the SID for the account name passed.  
    for (; ; )
    {

        // Set the count variables to the buffer sizes and retrieve the SID.  
        cbSid = dwSidBufferSize;
        cchDomainName = dwDomainBufferSize;
        if (LookupAccountNameW(
            NULL,            // Computer name. NULL for the local computer  
            wszAccName,
            *ppSid,          // Pointer to the SID buffer. Use NULL to get the size needed,  
            &cbSid,          // Size of the SID buffer needed.  
            wszDomainName,   // wszDomainName,  
            &cchDomainName,
            &eSidType
        ))
        {
            if (IsValidSid(*ppSid) == FALSE)
            {
                wprintf(L"The SID for %s is invalid.
", wszAccName);
                dwErrorCode = MQ_ERROR;
            }
            break;
        }
        dwErrorCode = GetLastError();

        // Check if one of the buffers was too small.  
        if (dwErrorCode == ERROR_INSUFFICIENT_BUFFER)
        {
            if (cbSid > dwSidBufferSize)
            {

                // Reallocate memory for the SID buffer.  
                wprintf(L"The SID buffer was too small. It will be reallocated.
");
                FreeSid(*ppSid);
                *ppSid = (PSID) new BYTE[cbSid];
                if (*ppSid == NULL)
                {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(*ppSid, 0, cbSid);
                dwSidBufferSize = cbSid;
            }
            if (cchDomainName > dwDomainBufferSize)
            {

                // Reallocate memory for the domain name buffer.  
                wprintf(L"The domain name buffer was too small. It will be reallocated.
");
                delete[] wszDomainName;
                wszDomainName = new WCHAR[cchDomainName];
                if (wszDomainName == NULL)
                {
                    return MQ_ERROR_INSUFFICIENT_RESOURCES;
                }
                memset(wszDomainName, 0, cchDomainName * sizeof(WCHAR));
                dwDomainBufferSize = cchDomainName;
            }
        }
        else
        {
            wprintf(L"LookupAccountNameW failed. GetLastError returned: %d
", dwErrorCode);
            hr = HRESULT_FROM_WIN32(dwErrorCode);
            break;
        }
    }

    delete[] wszDomainName;
    return hr;
}

void main()
{
    PSID sid;
    GetSid(L"strive", &sid);
    DWORD dwRes, dwDisposition;
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea;
    SECURITY_ATTRIBUTES sa;
    HANDLE lRes = NULL;
    // Initialize an EXPLICIT_ACCESS structure for an ACE.
    // The ACE will allow Everyone read access to the key.
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = GENERIC_ALL;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
    ea.Trustee.ptstrName = (LPTSTR)sid;

    // Create a new ACL that contains the new ACEs.
    dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
    if (ERROR_SUCCESS != dwRes)
    {
        _tprintf(_T("SetEntriesInAcl Error %u
"), GetLastError());
        goto Cleanup;
    }

    // Initialize a security descriptor.  
    pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR,
        SECURITY_DESCRIPTOR_MIN_LENGTH);
    if (NULL == pSD)
    {
        _tprintf(_T("LocalAlloc Error %u
"), GetLastError());
        goto Cleanup;
    }

    if (!InitializeSecurityDescriptor(pSD,
        SECURITY_DESCRIPTOR_REVISION))
    {
        _tprintf(_T("InitializeSecurityDescriptor Error %u
"),
            GetLastError());
        goto Cleanup;
    }

    // Add the ACL to the security descriptor. 
    if (!SetSecurityDescriptorDacl(pSD,
        TRUE,     // bDaclPresent flag   
        pACL,
        FALSE))   // not a default DACL 
    {
        _tprintf(_T("SetSecurityDescriptorDacl Error %u
"),
            GetLastError());
        goto Cleanup;
    }

    // Initialize a security attributes structure.
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = pSD;
    sa.bInheritHandle = FALSE;

    // Use the security attributes to set the security descriptor 
    // when you create a key.
    lRes =  CreateFile(_T("D:\File.txt"), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
        &sa, OPEN_ALWAYS, 0, NULL);
    if (lRes != NULL)
    {
        _tprintf(_T("Create file success
"));
    }
   
Cleanup:

    if (pACL)
        LocalFree(pACL);
    if (pSD)
        LocalFree(pSD);
    if (lRes)
       CloseHandle(lRes);
    return;

}

结果: 创建了一个文本,我们可以检查文本的属性来验证是否成功。

文档参考: 在C ++中为新对象创建安全描述符

                    C-C++ Code Example: Creating a Security Descriptor

拓展:

我们可以使用SetNamedSecurityInfo函数,将访问权限限制为特定的用户帐户和/或组。 不过如果具有足够权限的合适用户帐户运行您的应用程序(或与此相关的任何应用程序),或者您的应用程序(或其他应用程序)冒充了该帐户,则它将能够访问该文件。

案例参考: 使用C ++制作具有仅用户可以查看和编辑的权限的文件

关于ACL和ACE的详细介绍: 关于Windows安全权限的学习(三)

部分内容(防止丢失):

一个安全描述符包含以下安全信息:

  • 两个安全标识符(Security identifiers),简称为SID,分别是OwnerSid和GroupSid. 所谓SID就是每次当我们创建一个用户或一个组的时候,系统会分配给改用户或组一个唯一SID,当你重新安装系统后,也会得到一个唯一的SID。SID是唯一的,不随用户的删除而分配到另外的用户使用。
    请记住,SID永远都是唯一的SIF是由计算机名、当前时间、当前用户态线程的CPU耗费时间的总和三个参数决定以保证它的唯一性。
      例:   S-1-5-21-1763234323-3212657521-1234321321-500
  • 一个DACL(Discretionary Access Control List),其指出了允许和拒绝某用户或用户组的存取控制列表。 当一个进程需要访问安全对象,系统就会检查DACL来决定进程的访问权。如果一个对象没有DACL,那么就是说这个对象是任何人都可以拥有完全的访问权限。
  • 一个SACL(System Access Control List),其指出了在该对象上的一组存取方式(如,读、写、运行等)的存取控制权限细节的列表。
  • 还有其自身的一些控制位。SECURITY_DESCRIPTOR_CONTROL

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

原文地址:https://www.cnblogs.com/strive-sun/p/14173054.html