【问题标题】:How to use CreateProcessWithLogonW from a service application?如何从服务应用程序使用 CreateProcessWithLogonW?
【发布时间】:2017-05-09 14:20:09
【问题描述】:

我需要从 Windows 服务运行命令行应用程序,以另一个 Windows 用户身份执行它(通过提供 domain\userpassword)。

我以这种方式将 Windows API CreateProcessWithLogonW() 包装在我自己的 RunAppAsAnotherWindowsUser() 函数中:

function CreateProcessWithLogonW(
  lpUsername,
  lpDomain,
  lpPassword: PWideChar;
  dwLogonFlags: DWORD;
  lpApplicationName: PWideChar;
  lpCommandLine: PWideChar;
  dwCreationFlags: DWORD;
  lpEnvironment: Pointer;
  lpCurrentDirectory: PWideChar;
  lpStartupInfo: PStartupInfoW;
  lpProcessInformation: PProcessInformation
): BOOL; stdcall; external 'advapi32.dll';

function RunAppAsAnotherWindowsUser(const User, Domain, PW, Application, CmdLineParams: WideString): LongWord;    

const
  LOGON_WITH_PROFILE = $00000001;

implementation

function RunAppAsAnotherWindowsUser(const User, Domain, PW, Application, CmdLineParams: WideString): LongWord;
var
  si           : TStartupInfoW;
  pif          : TProcessInformation;
begin
  ZeroMemory(@si, sizeof(si));
  si.cb := sizeof(si);
  si.dwFlags := STARTF_USESHOWWINDOW;
  si.wShowWindow := 1;

  SetLastError(0);
  CreateProcessWithLogonW(PWideChar(User), PWideChar(Domain), PWideChar(PW),
    LOGON_WITH_PROFILE, nil, PWideChar(Application+' '+CmdLineParams),
    CREATE_DEFAULT_ERROR_MODE, nil, nil, @si, @pif);
  Result := GetLastError;
end;

上面是adapted from here

当我从我为测试而创建的 Win32 VCL 应用程序中使用RunAppAsAnotherWindowsUser () 时,它工作正常。当我从 Windows 服务调用它时,它不起作用。

我将this page 读作advised here,但在我的情况下,我没有交互式进程,因为我的命令行应用程序只是执行数据库查询并写入临时文件。

我尝试将服务作为本地系统而不是域管理员运行,但行为是相同的。

该服务是作为服务构建的 IntraWeb(用于 Web 的 VCL)应用程序。作为 exe 构建的相同应用程序可以正常工作。我写这篇文章只是为了解释我工作的背景。

您能帮我找出问题吗?

【问题讨论】:

  • 您遇到的实际问题是什么?你收到错误代码了吗?如果有,是哪一个?请更具体一点?
  • 服务在隔离会话中运行,您应该在控制台或用户会话中启动该进程。
  • 我试图以用户身份运行进程(实际上是作为 pc 管理员),这解决了部分问题实际上 GetLastError(参考上面的代码)为 0(所以没有错误),而之前是 5 点(回复@RemyLebeau)。无论如何,我使用 RunAppAsAnotherWindowsUser 运行的 exe 无法写入文件,即使我对专用文件夹中的每个人都设置了完全访问权限。无论如何,现在只是一个问题或权限。以用户身份运行服务器是一个重要的进步,现在我必须与 windows 文件夹权限作斗争(这真的不那么明显)。

标签: delphi service delphi-10-seattle


【解决方案1】:

您应该从服务启动用户会话中的进程(在物理 PC 上通常是控制台会话)。从 Windows Vista 开始就是这种情况:

服务始终在会话 0 中运行。在 Windows Vista 之前,第一个 登录用户也被分配到会话 0。现在,会话 0 是 专为服务和其他应用程序保留 与交互式用户会话相关联。 (第一个登录的用户 连接到会话 1,第二个登录用户连接到 会话 2,依此类推。)会话 0 不支持进程 与用户互动。

请参阅here,了解我博客上使用Jedi Apilib 的一个非常基本的示例。

来自这个博客:

uses JwaWinbase, JwaWtsApi32;       

var hToken: THandle; 
  si: _STARTUPINFOA; 
  pi: _PROCESS_INFORMATION; 
var  Ret: Cardinal; 
  sTitle: string; 
  sMsg: string; 
begin 
  ZeroMemory(@si, SizeOf(si)); 
  si.cb := SizeOf(si); 
  si.lpDesktop := nil;       

  if WTSQueryUserToken(WtsGetActiveConsoleSessionID, hToken) then 
  begin 
    if CreateProcessAsUser(hToken, nil, 'notepad.exe', nil, nil, False, 
      0, nil, nil, si, pi) then 
    begin 
      // Do some stuff 
    end; 
  end; 
end;

【讨论】:

  • 嗨,但是由于我需要使用 CreateProcessWithLogonW 而不是 CreateProcessAsUser,我该怎么做,因为 CreateProcessWithLogonW 没有令牌作为参数?
  • 使用 LogonUser (msdn.microsoft.com/en-us/library/windows/desktop/…) 获取令牌句柄,然后使用 SetTokenInformation (msdn.microsoft.com/en-us/library/windows/desktop/…) 更改 sessionid。将令牌传递给CreateProcessAsUser。当然必须有一个登录用户,在服务会话中你不能启动交互式进程。
  • 为什么需要调用 CreateProcessWithLogon?不能冒充用户并在用户的上下文中执行所需的代码吗?
猜你喜欢
  • 2013-12-13
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-22
  • 2017-06-21
  • 1970-01-01
相关资源
最近更新 更多