python - 调用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> ?
解决方案
如何确保为每个用户创建一个文件夹 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;
}
推荐阅读
- c# - MVVM 中三态变量的 XAML 触发器
- javascript - 加载另一个 API 数据的 1 个 API
- kubernetes - Shovel(在 kubernetes 中作为服务运行)无法连接到 kafka(在 kubernetes 中作为服务运行)
- botframework - 如何确保多个 Bot Builder V4 bot 实例一次处理一条用户消息?
- intellij-idea - 在 IntelliJ 中将文件名复制到剪贴板的最快方法是什么?
- javascript - dc.js 折线图 - 用户可选择的 BINS 和日期范围
- android - 数据库sqlite。更新不丢失数据
- wordpress - Wordpress 按多个元键排序
- mysql - 选择并求和具有相似行的所有记录满足条件的唯一行
- algorithm - 最大流算法运行时间