Note that there are some explanatory texts on larger screens.

plurals
  1. POCreateProcessAsUser from service and user security issues
    primarykey
    data
    text
    <p>I have a windows service that launches my application. This service is a Scheduler, to perform some custom actions defined by end-users.</p> <p>It runs as LocalSystem account, and will launch my application (that has windows).</p> <p>For this I use the functions <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa378184%28v=vs.85%29.aspx" rel="nofollow">LogongUser</a>, <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb762281%28v=vs.85%29.aspx" rel="nofollow">LoadUserProfile</a>, <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms682429%28v=vs.85%29.aspx" rel="nofollow">CreateProcessAsUser</a>. This works perfectly <strong>but only if</strong> the user, to <strong>log on</strong>, is member of Administrators group.</p> <p>I cannot leave the user as an Administrator, he needs to be a default user (member of Users group).</p> <p>As administrator it runs fine from the service. But when the process starts as a default user, it terminates abnormally with:</p> <pre><code>ExitCode: 0xC0000142 STATUS_DLL_INIT_FAILED Message: {DLL Initialization Failed} Initialization of the dynamic link library %hs failed. The process is terminating abnormally. </code></pre> <p>If I logon with that user (member of Users group) and launch the application manually, everything goes fine.</p> <p>I have not figured out what is the library that is causing the problem. I checked the system event log, but there is no logs. I already tried to <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa378612%28v=vs.85%29.aspx" rel="nofollow">ImporsonateLoggedOnUser</a> but without success.</p> <p>This is the code:</p> <pre><code>type TProcessRec = record Token: Cardinal; ProfileInfo: TProfileInfo; Job: Cardinal; Environment: Pointer; ProcessInfo: TProcessInformation; WinStat: HWINSTA; end; TProcess = class private fProcess: TProcessRec; public constructor Create(aUser, aDomain, aPassword, aCommand, aWorkingDir: string; aUtil: TJJWServiceUtil); destructor Destroy; override; procedure Terminate(aExitCode: Cardinal); function getExitCode: Cardinal; end; constructor TProcess.Create(aUser, aDomain, aPassword, aCommand, aWorkingDir: string; aUtil: TJJWServiceUtil); type TCreateProcessFuncType = (cpAsUser, cpWithLogon); const DES_CREATION_TYPE: array [TCreateProcessFuncType] of string = ('CreateProcessAsUser', 'CreateProcessWithLogon'); var sa: TSecurityAttributes; si: TStartupInfo; limits : TJobObjectExtendedLimitInformation; wUser, wDomain, wPassword, wCommand, wWorkingDir: WideString; creationType: TCreateProcessFuncType; begin // se estiver rodando com a conta LocalSystem (em serviço de windows) if IsPrivilegeEnabled(SE_TCB_NAME) or IsPrivilegeEnabled(SE_INCREASE_QUOTA_NAME) then creationType := cpAsUser else creationType := cpWithLogon; aUtil.debug('ENV: ' + AnsiReplaceStr(GetEnvironmentVariable('PATH'), '%', '%%')); aUtil.debug('Criando novo processo em modo: ' + DES_CREATION_TYPE[creationType]); FillChar(fProcess, SizeOf(fProcess), 0); FillChar(sa, SizeOf(sa), 0); sa.nLength := SizeOf(sa); FillChar(si, SizeOf(si), 0); si.cb := SizeOf(si); case creationType of cpAsUser: begin aUtil.debug('Efetuando o login do usuário %s', [aUser]); // login if not LogonUser(PChar(aUser), PChar(aDomain), PChar(aPassword), LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, fProcess.Token) then RaiseLastOSError; try aUtil.debug('Carrengado o profile do usuário %s', [aUser]); // carrega o profile do usuário fProcess.ProfileInfo.dwSize := SizeOf(fProcess.ProfileInfo); fProcess.ProfileInfo.dwFlags := PI_NOUI; fProcess.ProfileInfo.lpUserName := PChar(aUser); if not LoadUserProfile(fProcess.Token, fProcess.ProfileInfo) then RaiseLastOSError; try aUtil.debug('Criando o bloco de variáveis de ambiente do usuário %s', [aUser]); // variaveis de ambiente if not CreateEnvironmentBlock(fProcess.Environment, fProcess.Token, false) then RaiseLastOSError; aUtil.debug('Criando o JOB para associar o processo filho ao processo pai'); // job para associar fProcess.Job := CreateJobObject(@sa, nil); if fProcess.Job = 0 then RaiseLastOSError; try // limita o job para matar o seu processo caso o processo pai termine antes FillChar(Limits,SizeOf(Limits),0); with Limits,BasicLimitInformation do LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE or JOB_OBJECT_LIMIT_BREAKAWAY_OK; if not SetInformationJobObject(fProcess.Job, JobObjectExtendedLimitInformation, @limits, SizeOf(limits)) then RaiseLastOSError; try fProcess.WinStat := CreateWindowStation(SCHEDULER_WINSTAT, 0, 0, nil); if fProcess.WinStat = 0 then RaiseLastOSError; si.lpDesktop := PChar(SCHEDULER_WINSTAT); aUtil.debug('Criando o processo: %s', [aCommand]); // processo! if not CreateProcessAsUser( fProcess.Token, nil, PChar(aCommand), @sa, nil, false, CREATE_SUSPENDED or CREATE_BREAKAWAY_FROM_JOB or NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP or CREATE_UNICODE_ENVIRONMENT, fProcess.Environment, PChar(aWorkingDir), si, fProcess.ProcessInfo) then RaiseLastOSError; try aUtil.debug('Associando o JOB ao processo filho'); // associa ao processo do plugin o JOB (gruda nele!) if not AssignProcessToJobObject(fProcess.Job, fProcess.ProcessInfo.hProcess) then RaiseLastOSError; // VOA PROCESSO, VOA! if ResumeThread(fProcess.ProcessInfo.hThread) = $FFFFFFFF then RaiseLastOSError; aUtil.debug('Processo disparado'); except TerminateProcess(fProcess.ProcessInfo.hProcess, Cardinal(-1)); CloseHandle(fProcess.ProcessInfo.hThread); CloseHandle(fProcess.ProcessInfo.hProcess); FillChar(fProcess.ProcessInfo, SizeOf(fProcess.ProcessInfo), 0); raise; end; except DestroyEnvironmentBlock(fProcess.Environment); fProcess.Environment := nil; raise; end; except CloseHandle(fProcess.Job); fProcess.Job := 0; raise; end; except UnloadUserProfile(fProcess.Token, fProcess.ProfileInfo.hProfile); FillChar(fProcess.ProfileInfo, SizeOf(fProcess.ProfileInfo), 0); raise; end; except CloseHandle(fProcess.Token); fProcess.Token := 0; raise; end; end; ////////////////////////////////////////////////////////////////////////////// cpWithLogon: begin wUser := aUser; wDomain := aDomain; wPassword := aPassword; wCommand := aCommand; wWorkingDir := aWorkingDir; aUtil.debug('Disparando o processo: %s', [aCommand]); // o CreateProcessWithLogon já cria um JOB para evitar // que o processo fique órfão no limbo if not CreateProcessWithLogon( PWideChar(wUser), PWideChar(wDomain), PWideChar(wPassword), LOGON_WITH_PROFILE, nil, PWideChar(wCommand), NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP, nil, PWideChar(wWorkingDir), si, fProcess.ProcessInfo ) then RaiseLastOSError; end; end; end; destructor TProcess.Destroy; begin if fProcess.ProcessInfo.hProcess &gt; 0 then begin if getExitCode = STILL_ACTIVE then TerminateProcess(fProcess.ProcessInfo.hProcess, Cardinal(-1)); CloseHandle(fProcess.ProcessInfo.hThread); CloseHandle(fProcess.ProcessInfo.hProcess); end; if fProcess.Environment &lt;&gt; nil then DestroyEnvironmentBlock(fProcess.Environment); if fProcess.Job &gt; 0 then CloseHandle(fProcess.Job); if fProcess.ProfileInfo.hProfile &gt; 0 then UnloadUserProfile(fProcess.Token, fProcess.ProfileInfo.hProfile); if fProcess.Token &gt; 0 then CloseHandle(fProcess.Token); if fProcess.WinStat &gt; 0 then CloseWindowStation(fProcess.WinStat); FillChar(fProcess, SizeOf(fProcess), 0); inherited; end; function TProcess.getExitCode: Cardinal; begin if not GetExitCodeProcess(fProcess.ProcessInfo.hProcess, Result) then RaiseLastOSError; end; </code></pre> <hr> <p>This can be usefull</p> <blockquote> <p><a href="http://msdn.microsoft.com/en-us/library/aa379608%28VS.85%29.aspx" rel="nofollow">Starting an Interactive Client Process in C++</a> </p> </blockquote>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload