首页 > 解决方案 > 调用win32 API CreateProcessWithLogonW时如何创建用户文件夹

问题描述

语境

我有一个 Windows 桌面程序,可供不同类型的用户角色使用。每个用户角色都有自己的一组受限视图和操作,这取决于其他用户操作的结果。该程序与 API 通信,并通过 Windows 身份验证完成身份验证。为了端到端地测试程序,无论是手动还是在管道步骤中,同一程序的多个实例需要在不同的用户下同时运行。

容器暂时不是一种选择。我正在编写一个使用 ctypes.windll.advapi32.CreateProcessWithLogonW 以指定用户身份运行程序的 Python 脚本。

问题

当使用 dwLogonFlags 等于 LOGON_WITH_PROFILE 调用 CreateProcessWithLogonW 时,会创建一个文件夹 C:\Users\TEMP。在程序会话期间创建的所有文件都存储在该文件夹下。该文件夹在程序终止时被销毁。

当 dwLogonFlags 等于 LOGON_NETCREDENTIALS_ONLY 调用 CreateProcessWithLogonW 时,不会创建文件夹。在程序会话期间创建的所有文件都存储在 C:\Users<调用 CreateProcessWithLogonW 的登录用户的用户名> 验证仅在程序启动并进行第一次 API 调用后完成,符合此标志的文档。

这两种选择都不理想,因为不同的用户需要在会话期间存储自己的数据。

问题

如何确保为每个用户创建一个文件夹 C:\Users<username> ?

标签: pythonpython-3.xwindowswinapictypes

解决方案


如何确保为每个用户创建一个文件夹 C:\Users ?

您可以使用CreateDirectory函数并指定SECURITY_ATTRIBUTES结构来创建文件夹。

lpSecurityDescriptor:指向 SECURITY_DESCRIPTOR 结构的指针,该结构控制对对象的访问。如果此成员的值为 NULL,则为对象分配与调用进程的访问令牌关联的默认安全描述符。这与通过分配 NULL 自由访问控制列表 (DACL) 授予每个人访问权限不同。默认情况下,进程的访问令牌中的默认 DACL 只允许访问令牌所代表的用户访问。

您可以将权限分配给不同的用户,例如限制访问或写入。

C++ 示例:

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

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

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"strive", &sid);
    DWORD dwRes, dwDisposition;
    PACL pACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea;
    SECURITY_ATTRIBUTES sa;
    BOOL l = 0;
    // 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.
    l = CreateDirectory(L"C:\\Users\\strive", &sa);
 
Cleanup:
    if (pACL)
        LocalFree(pACL);
    if (pSD)
        LocalFree(pSD);
    return;
}

推荐阅读