![]() |
Starting a Interactive Process in Vista using TService
Hallo,
I hope it's not a problem if i type in English. Im have a TService application, running on windows vista. All i want to do is create a process(lets say notepad.exe) and display that on the logged in users desktop. As most of you know, in Vista Services run on a completely different environment, which is non interactive to the user, so basically all processes started inside the service will be invisible to the user. After reading A LOT of forums and reading alot about this, i saw a few examples using LSALogonUser and CreateProcessAsUser... But i couldnt get any of them to work... Ive downloaded some source form this forum, pasted that in a service, but it still doesnt work... It does work when i paste it in a Normal Win32 VCL Application, then the process starts correctly, so it's clear that something is wrong, here is my code, please any advice would be much appreciated.
Delphi-Quellcode:
unit uMain; interface uses JwaWindows,SvcMgr, SysUtils, JwaWinType, JwaWinBase, JwaWinNT, JwaNtSecApi, JwaNTStatus, JwaNative, JwaUserEnv, JwaWinSta, JwaWtsApi32, Dialogs, uWinStation; const DNLEN = 15; UNLEN = 256; type TAuthInfo = record Header: MSV1_0_INTERACTIVE_LOGON; Domain: array[0..DNLEN] of WideChar; User: array[0..UNLEN] of WideChar; Password: array[0..UNLEN] of WideChar; end; type TService1 = class(TService) procedure ServiceStart(Sender: TService; var Started: Boolean); private { Private declarations } public function GetServiceController: TServiceController; override; { Public declarations } end; var Service1: TService1; implementation {$R *.DFM} procedure ServiceController(CtrlCode: DWord); stdcall; begin Service1.Controller(CtrlCode); end; function TService1.GetServiceController: TServiceController; begin Result := ServiceController; end; Procedure LsaInitUnicodeString(Var LsaString: TLsaUnicodeString; Const WS: WideString); Begin FillChar(LsaString, SizeOf(LsaString), 0); If WS <> '' Then Begin LsaString.Length:=Length(WS) * SizeOf(WideChar); LsaString.MaximumLength:=LsaString.Length + SizeOf(WideChar); LsaString.Buffer:=PWideChar(WS); End; End; procedure GetLogonSID(hToken: THandle; var ppsid: PSID); var dwLength: DWORD; ptg : ^TOKEN_GROUPS; i : integer; begin dwLength := 0; ptg := nil; try // Get required buffer size and allocate the TOKEN_GROUPS buffer. if not GetTokenInformation(hToken, TokenGroups, ptg, 0, dwLength) then begin if GetLastError <> ERROR_INSUFFICIENT_BUFFER then begin ShowMessage('GetTokenInformation failed'); Exit; end; ptg := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwLength); if ptg = nil then begin Exit; end; // Get the token group information from the access token. if not GetTokenInformation(hToken, TokenGroups, ptg, dwLength, dwLength) then begin Exit; end; // Loop through the groups to find the logon SID. for i := 0 to ptg.GroupCount-1 do begin if ptg.Groups[i].Attributes and SE_GROUP_LOGON_ID = SE_GROUP_LOGON_ID then begin // Found the logon SID; make a copy of it. dwLength := GetLengthSid(ptg.Groups[i].Sid); ppsid := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwLength); if ppsid = nil then begin Exit; end; if not CopySid(dwLength, ppsid, ptg.Groups[i].Sid) then begin // raise exception.Create(Format('CopySid: %s', [SysErrorMessage(GetLastError)])); HeapFree(GetProcessHeap, 0, ppsid); Exit; end; Break; end; end; end; finally // Free the buffer for the token groups. if ptg <> nil then begin HeapFree(GetProcessHeap, 0, ptg); end; end; end; procedure TService1.ServiceStart(Sender: TService; var Started: Boolean); var hToken: THandle; si: _STARTUPINFOA; pi: _PROCESS_INFORMATION; Res: NTSTATUS; hLSA: THandle; LSAString: _LSA_STRING; AuthenticationPackage: ULONG; AuthentificationInfo: TAuthInfo; pProfileBuffer: Pointer; LogonID: JwaWinType.LUID; hLsaToken: THandle; QuotaLimits: QUOTA_LIMITS; SubStatus: Integer; wsDomain: WideString; wsUser: WideString; wsPwd: WideString; TokenSource: TOKEN_SOURCE; dwReturnLength: ULONG; Mode: LSA_OPERATIONAL_MODE; pGroups: PTOKEN_GROUPS; AdminSid: PSid; dwSizeSid: Cardinal; dwSizeDomain: Cardinal; SidType: TSidNameUse; Domain: String; MaxGroups: Integer; bRes: Longbool; begin ZeroMemory(@si, SizeOf(si)); si.cb := SizeOf(si); si.lpDesktop := nil; if WTSQueryUserToken(WtsGetActiveConsoleSessionID, hToken) then begin RtlInitString(@LsaString, PCSZ(PChar('Winlogon'))); Res := LsaRegisterLogonProcess(LsaString, hLSA, @Mode); if Failed(Res) then begin ShowMessageFmt('LsaRegisterLogonProcess: %s', [SysErrorMessage(LsaNtStatusToWinError(Res))]); end; RtlInitString(@LsaString,PCSZ(PChar(MSV1_0_PACKAGE_NAME))); Res := LsaLookupAuthenticationPackage(hLSA, LSAString, AuthenticationPackage); if Failed(Res) then begin ShowMessageFmt('LookupAuthPackage: %s', [SysErrorMessage(LsaNtStatusToWinError(Res))]); end; TokenSource.SourceName := '**ANON**'; if not AllocateLocallyUniqueId(TokenSource.SourceIdentifier) then begin ShowMessageFmt('AllocLocUniqueId: %s', [SysErrorMessage(GetLastError)]); end; // The number of TOKEN_GROUPS we're going to insert MaxGroups := 2; // Reserve memory for MaxGroups numbur of PTOKEN_GROUPS pGroups := PTOKEN_GROUPS(GlobalAlloc(GPTR, sizeof(_SID_AND_ATTRIBUTES) * MaxGroups)); pGroups^.GroupCount := MaxGroups; // Get the Logon Sid and it to the LocalGroups parameter of LsaLogonUser // The Logon Sid has the form S-1-5-5-XXXXXXXX-YYYYYYYY // We need it to obtain access to the user's desktop GetLogonSid(hToken, pGroups^.Groups[0].Sid); pGroups^.Groups[0].Attributes := SE_GROUP_MANDATORY or SE_GROUP_ENABLED or SE_GROUP_ENABLED_BY_DEFAULT or SE_GROUP_LOGON_ID; // Now get the Administrator's SID dwSizeSid := 0; dwSizeDomain := 0; bRes := LookupAccountName(nil, 'Administrator', nil, dwSizeSid, nil, dwSizeDomain, SidType); if (not bRes) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then begin // Reserve memory AdminSid := AllocMem(dwSizeSid); SetLength(Domain, dwSizeDomain); // Lookup Sid from Accountname // Assuming that the Admin account has not been renamed! bRes := LookUpAccountName(nil, 'Administrator', AdminSid, dwSizeSid, PChar(Domain), dwSizeDomain, SidType); if not bRes then begin // Cleanup FreeMem(AdminSid); AdminSid := nil; end; end else begin RaiseLastOSError; end; ShowMessageFmt('Administrator Sid: %s, Domain: %s', [SidToStr(AdminSid), Domain]); // Add the Administrator's sid to pGroups pGroups^.Groups[MaxGroups -1].Sid := AdminSid; pGroups^.Groups[MaxGroups -1].Attributes := SE_GROUP_MANDATORY or SE_GROUP_ENABLED or SE_GROUP_ENABLED_BY_DEFAULT or SE_GROUP_LOGON_ID; // Fill the AuthentificationInfo structure // First convert the EDITs to WideString wsDomain:= ''; wsUser:= 'username'; wsPwd:= 'password'; // Fill with zeros RtlZeroMemory(@AuthentificationInfo, sizeof(AuthentificationInfo)); AuthentificationInfo.Header.MessageType := MsV1_0InteractiveLogon; // AuthentificationInfo.Header.MessageType := MsV1_0NetworkLogon; // Copy the strings into a buffer. RtlCopyMemory(@AuthentificationInfo.Domain, @wsDomain[1], sizeof(WideChar) * Length(wsDomain)); RtlCopyMemory(@AuthentificationInfo.User, @wsUser[1], sizeof(WideChar) * Length(wsUser)); RtlCopyMemory(@AuthentificationInfo.Password, @wsPwd[1], sizeof(WideChar) * Length(wsPwd)); // Now set which buffer we want to use (the arrays of WideChar from the struct) RtlInitUnicodeString(@AuthentificationInfo.Header.LogonDomainName, AuthentificationInfo.Domain); RtlInitUnicodeString(@AuthentificationInfo.Header.UserName, AuthentificationInfo.User); RtlInitUnicodeString(@AuthentificationInfo.Header.Password, AuthentificationInfo.Password); Res := JwaNtSecApi.LsaLogonUser(hLSA, LsaString, RemoteInteractive, AuthenticationPackage, @AuthentificationInfo, SizeOf(AuthentificationInfo), pGroups, @TokenSource, pProfileBuffer, dwReturnLength, LogonID, hLSAToken, QuotaLimits, SubStatus); if Failed(Res) then begin ShowMessageFmt('LsaLogonUser: %s', [SysErrorMessage(LsaNtStatusToWinError(Res))]); end; ZeroMemory(@si, SizeOf(si)); si.cb := SizeOf(si); si.lpReserved := nil; si.lpDesktop := nil; si.dwFlags := STARTF_USESHOWWINDOW;; si.wShowWindow := SW_SHOWNORMAL; if not CreateProcessAsUser(hLsaToken, nil, PChar('notepad.exe'), nil, nil, False, NORMAL_PRIORITY_CLASS or CREATE_NEW_PROCESS_GROUP, nil, nil, &si, &pi) then begin ShowMessageFmt('CreateProcessAsUser: %s', [SysErrorMessage(GetLastError)]); end else begin end; // Cleanup CloseHandle(hToken); FreeMem(AdminSid); LsaDeregisterLogonProcess(hLSA); LsaFreeReturnBuffer(pProfileBuffer); end; Self.DoStop; end; end. |
Re: Sal iemand my kan help?
Guten Morgen,
wie wäre es mit deutsch oder englisch, so verstehe ich nicht die Bohne. Grüße Klaus |
Re: Sal iemand my kan help?
hi Fanix.
Ich bin ein klitzekleines wenig des niederländischen mächtig, aber was ein interaktiver gezüchteter (fokken?) Desktop ist weiss ich nun doch nicht? Bitte versuche es mal auf englisch oder Deutsch. Dann können Dir sicher viel mehr Leute helfen. |
Re: Starting a Interactive Process in Vista using TService
Ah, english is much better. ;-)
I don't think that what you want is possible in the Vista Security System in the way you think of it. Nevertheless, while I was looking for some samples about WCF i came across an interesting article on Codeproject: ![]() I know, this is a .NET article, but he author uses a out of process com+ component to start an application in the users context out of a service on a vista machine. The technology he used should be the same with a win/32 service. |
Re: Starting a Interactive Process in Vista using TService
Zitat:
|
Re: Starting a Interactive Process in Vista using TService
Is SetThreadDesktop still working in Vista? you can try to set a thread to the users desktop and then create the process in that thread.
|
Re: Starting a Interactive Process in Vista using TService
Why does your service need to run an interactive application? In many instances, if there is the need for a service to trigger user interaction, a separate application is run on the user's desktop (mostly with a TNA icon). The service can then contact this GUI application which will perform the needed actions. You may want to have a look at
![]() |
Re: Starting a Interactive Process in Vista using TService
You do not need LsaLogonUser at all.
You already use WTSQueryUserToken which gives you a token, that can be used for CreateProcessAsUser. That token leads to a process that is started in the logonsession of the user. Parameter lpStartupInfo (member lpDesktop) you can provide a windowsstation and desktop where the new application is put ("winsta0\default"). That should work. |
Re: Starting a Interactive Process in Vista using TService
Zitat:
|
Re: Starting a Interactive Process in Vista using TService
You can´t start a GUI application from a service in Vista.
To display GUI from service you must start a non visible application with the service and this application have to start the GUI elements. If you need data of interaction you have to implement communication between service and non-visible application e.g. TCP. [Service] <------> [Non-Visible-App] <------> [GUI-App] |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz