让我根据德里克的建议重新解释我的问题。
在Windows Vista / 7/8 / 8.1中,任务计划程序可以在本地用户帐户的安全上下文中执行任务,而无需存储本地帐户用户密码。当任务同时具有“运行是否登录用户”和“不存储密码”选项时,就是这种情况。唯一的限制是选择了上述选项的任务无法访问加密文件或网络资源。
我需要在独立计算机上开发一个高度可信的应用程序(作为本地系统执行),该应用程序在本地用户帐户的安全上下文中执行某些任务,而不存储本地帐户用户密码,这些任务不需要访问网络资源或本地加密文件。模拟已登录的本地用户帐户不是一个选项,即使系统重新启动且用户未登录系统,我也需要运行该应用程序。
由于任务调度程序可以执行我需要的操作,这意味着必须有一个能够在不提供用户密码的情况下创建本地用户访问令牌的API。 有谁知道这个api是什么?
非常感谢您提供的任何帮助。
P.s。:机器是独立的,不是域名加入的。
答案 0 :(得分:5)
迟到总比没有好。 您建立了与LSA服务器的连接,您搜索" Negotiate"身份验证包,您创建一个身份验证信息结构,作为登录类型,填充标识用户(S4U)登录服务的常量MsV1_0S4ULogon。 使用S4U登录时,系统不会存储密码,也无法访问网络或加密文件。 需要SeTcbPrivilege权限才能为模拟目的创建令牌。 如果您以管理员身份执行程序,默认情况下,该程序没有SeTcbPrivilege权限,程序将返回成功但创建的令牌不是主令牌,只能用于识别目的。
#include "stdafx.h"
#include <Windows.h>
#include <Ntsecapi.h>
#include <stdio.h>
#include <Userenv.h>
size_t wcsByteLen(const wchar_t* str);
void InitUnicodeString(UNICODE_STRING& str, const wchar_t* value, BYTE* buffer, size_t& offset);
//#define NEGOSSP_NAME_A "Negotiate"
int main(int argc, char * argv[])
{
HANDLE lsa;
ULONG Flags = MSV1_0_S4U_LOGON_FLAG_CHECK_LOGONHOURS;
DWORD len;
TOKEN_STATISTICS tokenstats;
LsaConnectUntrusted(&lsa);
const wchar_t* domain = L"Computer_name";
const wchar_t* user = L"User_name";
// prepare the authentication info
ULONG authInfoSize = sizeof(MSV1_0_S4U_LOGON) + wcsByteLen(user) + wcsByteLen(domain);
BYTE* authInfoBuf = new BYTE[authInfoSize];
MSV1_0_S4U_LOGON* authInfo = (MSV1_0_S4U_LOGON*)authInfoBuf;
// https://msdn.microsoft.com/en-us/aa378764
authInfo->MessageType = MsV1_0S4ULogon;
/*authInfo->Flags = Flags;*/
size_t offset = sizeof(MSV1_0_S4U_LOGON);
InitUnicodeString(authInfo->UserPrincipalName, user, authInfoBuf, offset);
InitUnicodeString(authInfo->DomainName, domain, authInfoBuf, offset);
// find the Negotiate security package
char packageNameRaw[] = "Negotiate";
LSA_STRING packageName;
packageName.Buffer = packageNameRaw;
packageName.Length = packageName.MaximumLength = (USHORT)strlen(packageName.Buffer);
ULONG packageId;
NTSTATUS stao_05 = LsaLookupAuthenticationPackage(lsa, &packageName, &packageId);
// create a test origin and token source
LSA_STRING origin = {};
origin.Buffer = _strdup("Test");
origin.Length = (USHORT)strlen(origin.Buffer);
origin.MaximumLength = origin.Length;
TOKEN_SOURCE source = {};
strcpy_s(source.SourceName, "Test");
bool test = AllocateLocallyUniqueId(&source.SourceIdentifier);
void* profileBuffer;
DWORD profileBufLen;
LUID luid;
HANDLE token;
QUOTA_LIMITS qlimits;
NTSTATUS subStatus;
NTSTATUS status = LsaLogonUser(lsa, &origin, Batch, packageId, authInfo, authInfoSize, NULL, &source, &profileBuffer, &profileBufLen, &luid, &token, &qlimits, &subStatus);
if (status == ERROR_SUCCESS)
{
if (GetTokenInformation(token, TokenStatistics, &tokenstats, sizeof(TOKEN_STATISTICS), &len) == TRUE)
{
switch (tokenstats.TokenType)
{
case TokenPrimary: printf("Token type: %s\n", "Primary");
break;
case TokenImpersonation: printf("Token type: %s\n", "Impersonation");
break;
}
switch (tokenstats.ImpersonationLevel)
{
case SecurityAnonymous: printf("Impersonation level: %s\n", "Anonymous");
break;
case SecurityIdentification: printf("Impersonation level: %s\n", "Identification");
break;
case SecurityImpersonation: printf("Impersonation level: %s\n", "Impersonation");
break;
case SecurityDelegation: printf("Impersonation level: %s\n", "Delegation");
break;
}
}
}
else
{
ULONG err = LsaNtStatusToWinError(status);
printf("LsaLogonUser failed: %x\n", status);
return 1;
}
}
size_t wcsByteLen(const wchar_t* str)
{
return wcslen(str) * sizeof(wchar_t);
}
void InitUnicodeString(UNICODE_STRING& str, const wchar_t* value, BYTE* buffer, size_t& offset)
{
size_t size = wcsByteLen(value);
str.Length = str.MaximumLength = (USHORT)size;
str.Buffer = (PWSTR)(buffer + offset);
memcpy(str.Buffer, value, size);
offset += size;
}