Zhang
Zhang

Reputation: 3356

How do I create a file with LPSECURITY_ATTRIBUTES by using CreateFile on Windows?

Here's CreateFile doc.

I want to create a file via CreateFile with SECURITY_ATTRIBUTES, when I create it under a windows account user A, the file shouldn't be accessed by another windows user B.

I found this Creating a Security Descriptor for a New Object in C++

But still couldn't figure it out how to assgin a certain user.

Upvotes: 0

Views: 2207

Answers (1)

Strive Sun
Strive Sun

Reputation: 6289

But still couldn't figure it out how to assgin a certain user.

You need to get the SID of a certain user first.

Here is some steps,

  1. Validate the input parameters.
  2. Create buffers for the SID and the domain name that may be large enough.
  3. In a loop, call LookupAccountName to retrieve the SID for the account name supplied. If the buffer for the SID or the buffer for the domain name is not large enough, the buffer size needed is returned in cbSid or cchDomainName, respectively, and a new buffer is allocated before the next call to LookupAccountName. Note that the information is retrieved on the local system when the lpSystemName parameter is set to NULL.
  4. Free the memory allocated for the domain name buffer.

Then pass the SID to the SetEntriesInAclA function,

The SetEntriesInAcl function creates a new access control list (ACL) by merging new access control or audit control information into an existing ACL structure.

Modified code:

#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.\n", 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.\n");
                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.\n");
                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\n", dwErrorCode);
            hr = HRESULT_FROM_WIN32(dwErrorCode);
            break;
        }
    }

    delete[] wszDomainName;
    return hr;
}

void main()
{
    PSID sid;
    GetSid(L"strives", &sid); // enter a user name
    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\n"), GetLastError());
        goto Cleanup;
    }

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

    if (!InitializeSecurityDescriptor(pSD,
        SECURITY_DESCRIPTOR_REVISION))
    {
        _tprintf(_T("InitializeSecurityDescriptor Error %u\n"),
            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\n"),
            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\n"));
    }
   
Cleanup:

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

}

You can verify by checking the properties of the file.

enter image description here

Upvotes: 3

Related Questions