C 从其他用户运行进程
我正在尝试从windows服务执行在本地管理员帐户下运行的进程。这台机器是Windows 7,它使用的是 代码在C 从其他用户运行进程,c,winapi,windows-7,terminal-services,C,Winapi,Windows 7,Terminal Services,我正在尝试从windows服务执行在本地管理员帐户下运行的进程。这台机器是Windows 7,它使用的是 代码在WTSQueryUserToken上失败,错误代码=5 首先,我尝试从当前线程获取令牌,然后调用SetPrivilege以启用SE_DEBUG_NAME和SE_TCB_NAME特权。然后调用WTSQueryUserToken,但得到错误5 我想澄清一下: 当服务处于本地系统(localSystem)下时,即使不需要调用SetPrivilege,该代码也可以完美地工作。现在的问题是,我需
WTSQueryUserToken
上失败,错误代码=5
首先,我尝试从当前线程获取令牌,然后调用SetPrivilege
以启用SE_DEBUG_NAME
和SE_TCB_NAME
特权。然后调用WTSQueryUserToken
,但得到错误5
我想澄清一下:
当服务处于本地系统(localSystem)下时,即使不需要调用SetPrivilege,该代码也可以完美地工作。现在的问题是,我需要移动服务以在本地管理员用户下运行
知道我错过了什么吗
守则:
BOOL T_Ex_RunProgram (DWORD sessionId, LPCWSTR targetPath)
{
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("T_Ex_RunProgram: sessionId = %d, targetPath = \"%S\"\n", sessionId, targetPath);
}
#endif
HANDLE htoken;
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &htoken))
{
if (GetLastError() == ERROR_NO_TOKEN)
{
if (!ImpersonateSelf(SecurityImpersonation))
{
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("ImpersonateSelf::RunProgram: dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
return FALSE;
}
if(!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, FALSE, &htoken))
{
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("OpenThreadToken::RunProgram: dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
return FALSE;
}
}
else{
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("OpenThreadToken::RunProgram: GetLastError return unexpected dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
return FALSE;
}
}
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("Before SetPrivilege(SE_DEBUG_NAME)::RunProgram\n");
}
#endif
// enable SeDebugPrivilege
if(!SetPrivilege(htoken, SE_DEBUG_NAME, TRUE))
{
// close token handle
CloseHandle(htoken);
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("SetPrivilege::RunProgram((SE_DEBUG_NAME): dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
return FALSE;
}
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("Before SetPrivilege(SE_TCB_NAME)::RunProgram\n");
}
#endif
// enable SeDebugPrivilege
if(!SetPrivilege(htoken, SE_TCB_NAME, TRUE))
{
// close token handle
CloseHandle(htoken);
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("SetPrivilege(SE_TCB_NAME)::RunProgram: dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
return FALSE;
}
BOOL b = WTSQueryUserToken (sessionId, &htoken);
if (!b)
{
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("T_Ex_RunProgram: WTSQueryUserToken failed. dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
return FALSE;
}
LPWSTR userName, userName1;
DWORD userNameLength;
b = WTSQuerySessionInformationW (WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &userName, &userNameLength);
if (b)
{
userName1 = _wcsdup (userName);
WTSFreeMemory (userName);
}
else
{
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("T_Ex_RunProgram: WTSQuerySessionInformation failed: dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
return FALSE;
}
b = RunProgramWithToken (htoken, userName1, targetPath,sessionId);
DWORD dwreturnErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("Before SetPrivilege(SE_DEBUG_NAME,FALSE)::RunProgram\n");
}
#endif
// enable SeDebugPrivilege
if(!SetPrivilege(htoken, SE_DEBUG_NAME, FALSE))
{
// close token handle
CloseHandle(htoken);
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("SetPrivilege::RunProgram((SE_DEBUG_NAME,FALSE): dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
}
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("Before SetPrivilege(SE_TCB_NAME,FALSE)::RunProgram\n");
}
#endif
// enable SeDebugPrivilege
if(!SetPrivilege(htoken, SE_TCB_NAME, FALSE))
{
// close token handle
CloseHandle(htoken);
DWORD dwErr = GetLastError();
#ifdef DEBUG
if(g_pLog)
{
g_pLog->Format ("SetPrivilege(SE_TCB_NAME,FALSE)::RunProgram: dwErr = %d\n", dwErr);
}
#endif
SetLastError(dwErr);
}
free (userName1);
CloseHandle (htoken);
if (!b)
SetLastError (dwreturnErr);
return b;
}
BOOL SetPrivilege( HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)
{
TOKEN_PRIVILEGES tp;
LUID luid;
if ( !LookupPrivilegeValue(
NULL, // lookup privilege on local system
lpszPrivilege, // privilege to lookup
&luid ) ) // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %u\n", GetLastError() );
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
else
tp.Privileges[0].Attributes = 0;
// Enable the privilege or disable all privileges.
if ( !AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES) NULL,
(PDWORD) NULL) )
{
printf("AdjustTokenPrivileges error: %u\n", GetLastError() );
return FALSE;
}
if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
{
printf("The token does not have the specified privilege. \n");
return FALSE;
}
return TRUE;
}
WTSQueryUserToken上的代码失败,错误代码=5。。。知道我错过了什么吗
我认为这篇MSDN文章可能对您有用:。根据这篇文章,在使用WTSQueryUserToken
时,您应该调用以下命令:
WTSQueryUserToken (WTSGetActiveConsoleSessionId (), &hToken);
然后使用调用CreateProcessAsUser
中检索到的令牌
在您使用
TOKEN\u ADJUST\u PRIVILEGES | TOKEN\u QUERY
调用OpenThreadToken
时,您可以临时将其增加为类似TOKEN\u ALL\u ACCESS
的值,直到您解决了问题(如果您仍然需要进行调用)。请参阅MSDN上的 通常,您只需要SE_DEBUG_NAME
或SE_TCB_NAME
中的一个。但您可能需要启用SE\u ASSIGNPRIMARYTOKEN\u NAME
。这是一个可以让你替换主进程令牌的令牌,它是“用进程做任何你想做的事”这一神圣三位一体中的第三个令牌。请参见MSDN上的。目标用户帐户可能需要一些登录权限。事件日志(eventvwr
)应包含更多信息和详细信息。另外,对于初学者,请参阅知识库文章。它应该能让你了解更多信息。另外,你使用的Windows版本是什么。这是服务器2008吗?终端服务在XP和2003(可能还有其他)中的行为略有不同,它可能会帮助其他人帮助您。您说的是“本地管理员帐户”。该帐户是否已启用(我以为默认情况下已禁用)。您能否在MSDN博客上尝试使用LocalSystem
,以隔离问题?还说明它需要SE\u TCB\u NAME
。这对我来说似乎有点太重了,但在您可以测试减少特权之前,请使用它。@Joseph:WTSQueryUserToken()
仅在LocalSystem
帐户中有效。该函数同样说明:“要成功调用此函数,调用应用程序必须在LocalSystem帐户的上下文中运行,并具有SE_TCB_NAME权限。”获取会话用户令牌的另一种方法是从会话中运行的进程中提取令牌,例如explorer.exe
。我已经尝试过了,现在再次尝试,使用WTSGetActiveConsoleSessionId()和TOKEN\u ALL\u访问,仍然是WTSQueryUserToken返回错误5!您可以使用用户登录的任何会话,它不必是“活动”会话(连接到物理键盘/鼠标/监视器的会话)。例如,当没有用户在本地登录时,“活动”会话可能会显示WinLogon
桌面。但是您可以为远程登录的用户获取用户令牌。WTSGetActiveConsoleSessionId()
获取本地控制台上活动的会话ID。这适用于快速用户切换,即用户在物理控制台上来回切换,但不适用于终端服务,即用户未连接到控制台。因此,如果您允许远程登录计算机,您不能依靠WTSGetActiveConsoleSessionId()
本身,您可能必须使用WTSEnumerateSessions()
来查找用户登录的活动会话。伙计们,sessionID不是问题,此代码在没有SetPrivilege的情况下工作,当服务处于本地系统下时。现在的问题是,我需要将服务移动到本地管理员用户下运行。