![]() |
LSALogonUser und Authentifikation (nichts komplexes!)
hi
Wer kenn die Funktion ![]()
Code:
Es geht hier weniger um die Frage über die Funktion selbst, als mehr über das Problem, dass der Parameter AuthenticationInformation gut definiert werden muss.
NTSTATUS LsaLogonUser(
HANDLE LsaHandle, PLSA_STRING OriginName, SECURITY_LOGON_TYPE LogonType, ULONG AuthenticationPackage, PVOID AuthenticationInformation, ULONG AuthenticationInformationLength, PTOKEN_GROUPS LocalGroups, PTOKEN_SOURCE SourceContext, PVOID* ProfileBuffer, PULONG ProfileBufferLength, PLUID LogonId, PHANDLE Token, PQUOTA_LIMITS Quotas, PNTSTATUS SubStatus ); Für den interaktiven standard login verwendet man dazu ![]() Die Struktur muss jedoch eine Besonderheit aufweißen. Und zwar müssen die Unicode Strings direkt unterhalb der Struktur im Speicher stehen. Die Strings in der Struktur sind wiederum eine Struktur ![]() Tja, das muss man erstmal wissen. Wie man das macht? Ich habe mal Keith Brown gefragt. Und es stellte sich heraus, dass die Funktion LSALogonUser bereits als "Funktion aus der Hölle" bekannt ist. Es gibt dazu einen Link : ![]() Den Quelltext habe ich nach Delphi übersetzt, allerdings ohne Erfolg.
Delphi-Quellcode:
Es ist doch so richtig übersetzt oder? Erst bitte drüber nachdenken, dann weiterlesen.
procedure _initUnicodeString(target : PUNICODE_STRING; source : PWideChar; cbMax : USHORT );
begin target.Length := cbMax ;//-2;//- sizeof(source^); //bei -2 und cbMax = 0 gibts nen integer unterlauf (=große Zahl, also lassen wirs) target.MaximumLength := cbMax; target.Buffer := source; end; function Create_MSV1_0_INTERACTIVE_LOGON( MessageType : MSV1_0_LOGON_SUBMIT_TYPE; LogonDomainName, UserName, Password : WideString; out authLen : Cardinal) : PMSV1_0_INTERACTIVE_LOGON; var iSize,i1 : Integer; uniStr : UNICODE_STRING; p : PWCHAR; cbHeader, cbDom, cbUser, cbPass : Integer; pDom, pUser, pPass : PWChar; const iUSHORT = sizeof(USHORT); iWCHAR = sizeof(WideChar); begin cbHeader := sizeof(MSV1_0_INTERACTIVE_LOGON); cbDom := Length(LogonDomainName) * iWCHAR; cbUser := Length(UserName) * iWCHAR; cbPass := Length(Password) * iWCHAR; iSize := cbHeader + cbDom + cbUser + cbPass; authLen := iSize; result := PMSV1_0_INTERACTIVE_LOGON(LocalAlloc(LMEM_ZEROINIT or LMEM_FIXED, iSize)); result.MessageType := MessageType; p := PWCHAR(result); Inc(Integer(p)); pDom := p; pUser := PWChar(Integer(p) + cbDom); pPass := PWChar(Integer(p) + cbDom + cbUser); CopyMemory(pDom, @LogonDomainName[1], cbDom); CopyMemory(pUser, @UserName[1], cbUser); CopyMemory(pPass, @Password[1], cbPass); _initUnicodeString(@result.LogonDomainName, pDom, cbDom); _initUnicodeString(@result.UserName, pUser , cbUser); _initUnicodeString(@result.Password, pPass , cbPass); end; Bin mir nicht sicher. Jedoch habe ich eine Änderung machen müssen bei :
Delphi-Quellcode:
durch
Inc(Integer(p));
Delphi-Quellcode:
Danach hat der Aufruf von LSALogon funktioniert.
Inc(Integer(p),cbHeader);
Meiner Meinung nach, zeigt der erste Code mit Inc, nur an den Anfang der Struktur - jedoch nicht ans Ende. Wer hat nun Recht? |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Das sind doch zwei ganz unterschiedliche Anweisung. Einmal wird der Zeiger nur um 1 Byte weiter geschoben und beim anderen Inc() wird der Zeiger um cbHeader weiter geschoben. Somit zeigt der Zeiger beim zweiten Inc() auf das Byte nach der Struktur.
Bei dem C++ Quellcode erhöht er das ganze um eins, aber dabei ist der Pointer aber typisiert, somit erhöht er um 1*SizeOf(Typ). Gleiches mach auch Inc() in Delphi, dazu müsste aber der Pointer den entsprechenden Typ haben. Somit ist sein Code korrekt. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
boha, du hast tatsächlich Recht. Das ist mir garnicht aufgefallen. Es wird tatsächlich implizit die Zeigervariable ans Ende gesetzt.
Naja, wenn ich das Update der Security Library rausbringe, dann muss man sich damit nicht rumschlagen. Zumindest für den Login durch das Windows Auth Paket (kein Kerberos) |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
I've put up some sample code for LsaLogonUser recently on DP:
![]() |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
You forgot to use CreateEnvironmentBlock to set the correct env. for the user.
The function LsaLogonUser is helpful for adding the user to a group for this session. But is it possible without using CreateToken to change privileges? Its nearly the same code I produced some days ago without knowing yours :D However I wrapped the LSA functions in my Security Library classes so its easier to use. I will publish it when the time is right. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
For my purpose I didn't need user environment :-) I put up the sample code because I struggled on it for a while. Essentially the sample is a translation of Gary Nebbet's sample. You do need to have the SeTcbPrivilege (Act as part of the operation system) and enable it. This corresponds with
![]() I see LsaLogonUser as an easy (and Vista compatible way) of launching something on the user's desktop from a service (In general services run under the SYSTEM account which has SeTcpPrivilege). Because you obtain the user's LogonSid you need not worry about setting ACL's on the user's desktop etc. Other purposes could be to acquire admin permissions to the launched application. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Do I understand correctly? Your code will run not as a service but as a normal process that can be used by a logged on user?
I tested my program as a service : 1. I logged on the current logged on user - but I needed to add the new logged on user SID to the windows station+desktop DACL to run a graphic process. 2. the CreateEnv... parameter must be set to the users envir. - otherwise the env. was set to the local system env. which lead to terrible result - I killed the explorer on purpose and started it again in the command line I created by that service. The result was that this user could no more start explorer with winlogon. It always used the local system. I restarted windows and logged on - but only the command line was started. All I could do was to use an partition image I created. Thus I test such a program in a VM. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Zitat:
Zitat:
Zitat:
If you simply want to start a process from a service and run this on the user's desktop (or even a specific terminal sessions desktop) I use this:
Delphi-Quellcode:
This sample start a process in Terminal Session 3 but you can use WTSGetActiveConsoleSession for obtaining the logged on users session ID.
procedure TService1.ServiceStart(Sender: TService; var Started: Boolean);
var hToken: THandle; si: _STARTUPINFOA; pi: _PROCESS_INFORMATION; begin ZeroMemory(@si, SizeOf(si)); si.cb := SizeOf(si); si.lpDesktop := nil; if WTSQueryUserToken(3, hToken) then begin if CreateProcessAsUser(hToken, nil, 'cmd.exe', nil, nil, False, CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP, nil, nil, si, pi) then begin // Do some stuff end; end; Self.DoStop; end; |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
All I wanted to do is :
1. Logon as a power user (without debug privileges) 2. Start a service that is already installed. 3. Connect to service and supply an admin password and process user token. 4. The process checks the password and logs on the user with debug privilege and add the user to the debug users for this session. Then it starts a given program (e.g. delphi). Maybe this should also work in a remote desktop session. Now I can debug services or anything else. However MSVC++ 2003 does not run in debug mode without debug privileges - but MSVC++ 2005 does. Taskmanager is another example. So I get rid of the powerful debug privilege which can be used by a virus for example. Thats all. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Sure: Suppose you poweruser is called Joe.
Let your service find the LogonSid for Joe. Use LsaLogonUser to start your process (eg Delphi) (eg with the supplied credentials). Include in the PTOKEN_GROUPS both the (local) admin sid and Joe's LogonSid. The process has full access to Joe's desktop without the need to set ACL's because you "are" Joe. Because the process has also Admin's SID you also have his privilegs. If wanted replace admin by a special user with debug privileges. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Zitat:
It also does not work to add the group debug users because the privilege is not added. I tested it. I created successfully a new token with debug privilege (using NTCreateToken), but this needs the users LUID (which can be created by CreateLogonSession) - however I can find the users LUID by LsaGetLogonSessionData.
Delphi-Quellcode:
By the way:function GetUserNameLUID(const username : WideString) : TLuid; var ws : WideString; res, i, lsCount : Cardinal; lsLUIDS : PLuid; LUIDarray : array of TLUID absolute lsLUIDS; pLogonSessionData : PSECURITY_LOGON_SESSION_DATA; begin result.LowPart := 0; result.HighPart := 0; LsaEnumerateLogonSessions(@lsCount,lsLUIDS); try for i := 0 to lsCount-1 do begin res := LsaGetLogonSessionData(@LUIDarray[i], pLogonSessionData); if (res = 0) then begin if (CompareText(pLogonSessionData.UserName.Buffer, userName) = 0) and (CompareText(pLogonSessionData.AuthenticationPackage.Buffer, 'NTLM') = 0) then begin result := pLogonSessionData.LogonId; LsaFreeReturnBuffer(pLogonSessionData); LsaFreeReturnBuffer(lsLUIDS); exit; end; LsaFreeReturnBuffer(pLogonSessionData); end; end; finally LsaFreeReturnBuffer(lsLUIDS); end; end; Did you see my post ![]() |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
I don't mean adding Joe the Administrators group rather the process you started with LsaLogonUser runs with admin permissions!
I thought that (zw)NTCreateToken was no longer possible in Vista :-( Please look at my sample again, the way I understand your question it's does precisely what you want! Make it a service so you don't have to give a user SeTcbPrivilege... |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Zitat:
Zitat:
Zitat:
|
Re: LSALogonUser und Authentifikation (nichts komplexes!)
1. Define a special user with Debug privilege.
2. Joe is logged an and requests your service app a "debug session" 3. Service starts process with Joe's LogonSid and the Debug users SID 4. The process (and only the process) runs with debug privilege. Joe is the "owner" of this process. What do we miss? |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Okay that works - adding a special User (not group), add Debug privs to it (gpedit.msc) and add the user to the groups parameter.
Now she has debug privs. By the way. I cannot run a graphic programm (like regedit) without changing the window station DACL. I tried your suggestion and added the LogonSID (retrieved by your second sample code GetLogonSid) to the groups. However the started application cannot paint to desktop. The window is drawn transparent. I retrieved the WinStation DACL in that newly started process - and always get an Access denied (5). Ok its no use - I have to add the new user to the winstation DACL - however I cannot retrieve the DACL without admin privs.
Delphi-Quellcode:
(* function GetLogonSID(const hWinStation : HWINSTA{TWindowStation}) : TSecurityID; {TODO: Use TWindowStation (if implemented) instead} var hAWinst : HWINSTA; logonSID : PSID; dwSize : Cardinal; begin haWinst := hWinStation; if (hWinStation = 0) or (hWinStation = INVALID_HANDLE_VALUE) then hAWinst := OpenWindowStation( 'winsta0', FALSE, READ_CONTROL, //READ_CONTROL or WRITE_DAC ); result := nil; if not GetUserObjectInformation(hAWinst, UOI_USER_SID, nil,0, dwSize) then begin // GetUserObjectInformation returns required size GetMem(LogonSid, dwSize + 1); if not GetUserObjectInformation(hAWinst, UOI_USER_SID, LogonSid, dwSize, dwSize) then begin raise ESMWinCallFailedException.CreateFmtWinCall( 'Call to GetUserObjectInformation failed. ', 'GetLogonSID', '', 'USM_KnownSID.pas', 0, true, 'GetUserObjectInformation',[]); end; if logonSID <> nil then begin result := TSecurityID.Create(logonSID); FreeMem(logonSID); end; end; if (hWinStation <> 0) and (hWinStation <> INVALID_HANDLE_VALUE) then CloseWindowStation(hAWinst); end; *) function GetUserNameLUID(const username : WideString) : TLuid; var ws : WideString; res, i, lsCount : Cardinal; lsLUIDS : PLuid; LUIDarray : array of TLUID absolute lsLUIDS; pLogonSessionData : PSECURITY_LOGON_SESSION_DATA; begin result.LowPart := 0; result.HighPart := 0; LsaEnumerateLogonSessions(@lsCount,lsLUIDS); try for i := 0 to lsCount-1 do begin res := LsaGetLogonSessionData(@LUIDarray[i], pLogonSessionData); if (res = 0) then begin if (CompareText(pLogonSessionData.UserName.Buffer, userName) = 0) and (CompareText(pLogonSessionData.AuthenticationPackage.Buffer, 'NTLM') = 0) then begin result := pLogonSessionData.LogonId; LsaFreeReturnBuffer(pLogonSessionData); LsaFreeReturnBuffer(lsLUIDS); exit; end; LsaFreeReturnBuffer(pLogonSessionData); end; end; finally LsaFreeReturnBuffer(lsLUIDS); end; end; procedure ServiceController(CtrlCode: DWord); stdcall; begin RunWithDebugService.Controller(CtrlCode); end; function TRunWithDebugService.GetServiceController: TServiceController; begin Result := ServiceController; end; procedure UpdateWindowStation(usertoken : TSecurityToken); var aDACL : TDAccessControlList; s : String; lpEnv : Pointer; hwinstaold, hAWinst : HWINSTA; hADesk : HDESK; anOwner, aGroup : TSecurityID; desktopDACL : TDAccessControlList; aSACL : TSAccessControlList; aPriv : TPrivilege; begin //http://msdn2.microsoft.com/en-us/library/aa379608.aspx hAWinst := OpenWindowStation( 'winsta0', FALSE, GENERIC_ALL //damit auch später ShowMessage noch funkz - nach SetProcessWindowStation //READ_CONTROL or WRITE_DAC ); hwinstaold := GetProcessWindowStation(); // To get the correct default desktop, set the caller's // window station to the interactive window station. if not SetProcessWindowStation(hAWinst) then raise ESMWinCallFailedException.CreateFmtEx('SetProcessWindowStation ', '','','USM_Token.pas', 0,true,[]); hADesk := OpenDesktop( 'default', 0, FALSE, READ_CONTROL or WRITE_DAC or DESKTOP_WRITEOBJECTS or DESKTOP_READOBJECTS); if hADesk = 0 then raise ESMWinCallFailedException.CreateFmtEx('OpenDesktop ', '','','USM_Token.pas', 0,true,[]); TSecureGeneralObject.GetSecurityInfo( hAWinst,SE_WINDOW_OBJECT,[sif_DACL_SECURITY_INFORMATION],anOwner,aGroup,desktopDACL,aSACL); desktopDACL.Add(TDiscretionaryAccessControlEntryAllow.Create(nil,TAF_ThisFolderAndSubFoldersAndFiles,GENERIC_ALL,usertoken.GetTokenUser,false)); TSecureGeneralObject.SetSecurityInfo( hAWinst,SE_WINDOW_OBJECT,[sif_DACL_SECURITY_INFORMATION],anOwner,aGroup,desktopDACL,aSACL); TSecureGeneralObject.GetSecurityInfo( hADesk,SE_WINDOW_OBJECT,[sif_DACL_SECURITY_INFORMATION],anOwner,aGroup,desktopDACL,aSACL); desktopDACL.Add(TDiscretionaryAccessControlEntryAllow.Create(nil,TAF_ThisFolderAndSubFoldersAndFiles,GENERIC_ALL,usertoken.GetTokenUser,false)); TSecureGeneralObject.SetSecurityInfo( hADesk,SE_WINDOW_OBJECT,[sif_DACL_SECURITY_INFORMATION],anOwner,aGroup,desktopDACL,aSACL); // Restore the caller's window station. SetProcessWindowStation(hwinstaold); end; function DumpEnvironmentW(lpEnvironment: Pointer) : WideString; var Env: PWideChar; begin result := ''; Env := lpEnvironment; while (lstrlenW(Env) > 0) do begin if WideString(Env)[1] <> '=' then result := result + #13#10 + WideString(Env); Env := PWideChar(DWORD(Env) + DWORD(lstrlenW(Env) + 1) * DWORD(sizeof(Env^))); end; // Delete(result,1,2) end; procedure TRunWithDebugService.ServiceExecute(Sender: TService); var tokenSYSTEM : TSecurityToken; userLUID : TLUID; res : Cardinal; lsaHandle : THandle; lsaSecurityMode : LSA_OPERATIONAL_MODE; SecurityLSA : TSecurityLSA; logonData : MSV1_0_INTERACTIVE_LOGON; plogonData : PMSV1_0_INTERACTIVE_LOGON; aLocalGroups: TSecurityIDList; SourceContext: TTokenSource; aProfileBuffer: PMSV1_0_INTERACTIVE_PROFILE;//Pointer; afProfileBufferLength: Cardinal; aTokenLuid: TLUID; aToken: TSecurityToken; aQuotaLimits: QUOTA_LIMITS; aSubStatus: NTSTATUS; authLen : Cardinal; si: STARTUPINFOW; pif: PROCESS_INFORMATION; lpEnv : Pointer; ws : WideString; aLogonSid : TSecurityID; begin // ShowMessage('Starting service'); //EnablePrivilege(SE_TCB_NAME,pst_Enable); InitWellKnownSIDs; SecurityLSA := TSecurityLSA.Create('RunWithDebug'); try logonData.MessageType := MsV1_0InteractiveLogon; plogonData := Create_MSV1_0_INTERACTIVE_LOGON( logonData.MessageType, '', 'DelphiTester', 'pass',authLen); aLocalGroups := TSecurityIDList.Create(true); aLogonSid := GetLogonSID; ShowMessage(aLogonSid.GetText(true)); aLocalGroups.Add(aLogonSid); aLocalGroups.Add(TSecurityID.Create('','DebuggerUser')); aLocalGroups.Add(AdministratorsSID); SourceContext.SourceName := 'NTLM'; SourceContext.SourceIdentifier := LOCALSERVICE_LUID; aProfileBuffer := nil; afProfileBufferLength := sizeof(aProfileBuffer); SecurityLSA.LsaLogonUser( 'NTLM',//nOriginName: String; jwaWindows.Interactive,//aLogonType: SECURITY_LOGON_TYPE; MSV1_0_PACKAGE_NAME,//anAuthenticationPackageName : String; plogonData,//anAuthenticationInformation: Pointer; authLen,//anAuthenticationInformationLength: Cardinal; aLocalGroups,//aLocalGroups: TSecurityIDList; SourceContext,//aSourceContext: TTokenSource; Pointer(aProfileBuffer),//aProfileBuffer: Pointer; afProfileBufferLength,//out afProfileBufferLength: Cardinal; aTokenLuid,//out aTokenLuid: TLUID; aToken,//out aToken: TSecurityToken; aQuotaLimits,//out aQuotaLimits: QUOTA_LIMITS; aSubStatus//out SubStatus: NTSTATUS); ); FillChar(si,sizeof(si),0); si.cb := SizeOf(startupinfo); si.dwFlags := STARTF_USESHOWWINDOW; si.wShowWindow := SW_SHOW; si.lpReserved := nil; // UpdateWindowStation(aToken); // hier nun das Token nehmen um ein neues token zu erstellen mit dem debugrecht tokenSYSTEM := TSecurityToken.CreateTokenEffective(TOKEN_ALL_ACCESS); tokenSYSTEM.RevertToSelf; try ShowMessage(aToken.TokenUser.GetText(true)); lpEnv := nil; if not CreateEnvironmentBlock(@lpEnv,aToken.TokenHandle,true) then raise ESMWinCallFailedException.CreateFmtEx('CreateEnvironmentBlock ', 'CreateEnvironmentBlock',ClassName,'USM_Token.pas', 0,true,[]); //ShowMessage(DumpEnvironmentW(lpEnv)); if not createprocessasuserw(aToken.TokenHandle,('c:\windows\system32\cmd.exe'){'e:\whoami.exe'},nil,nil,nil,true,CREATE_UNICODE_ENVIRONMENT,lpEnv,nil,si,pif) then raise ESMWinCallFailedException.CreateFmtEx('createprocessasuser ', 'createprocessasuserw',ClassName,'USM_Token.pas', 0,true,[]); finally ShowMessage('OK'); LsaFreeReturnBuffer(aProfileBuffer); CloseHandle(aToken.TokenHandle); //ShowMessage(tokenSYSTEM.GetTokenStatistics.GetText); userLUID := GetUserNameLUID('dezipaitor'); end; except on E : Exception do ShowMessage(E.Message); end; SecurityLSA.Free; end; |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Can you show me your code?
Maybe the difference is that you run from a service, so if you get the Logged On User Sid you get the SID from the account that your service runs under. You need to get the Login Sid from the Interactive User. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
ok..but can you show me how to achieve that?
|
Re: LSALogonUser und Authentifikation (nichts komplexes!)
The function GetLogonSid takes a hToken as first parameter. Why not pass it the token from some exe (say explorer.exe) that run's in the user's context?
Or maybe my alternative GetLogonSid, that should probably work in case of in interactive service (pre-vista). Or maybe it can be adapted to acquire the right hWinstation somehow...
Delphi-Quellcode:
I got some other ideas but I have to look into that (will be continued)
// Alternative way to get the Logon Sid
procedure GetLogonSid(var LogonSid: pSid); var hWinstation: HWINSTA; dwSize : Cardinal; begin // Open the WindowStation hWinstation := OpenWindowStation('winsta0', False, READ_CONTROL); if hWinstation = 0 then begin ShowMessageFmt('OpenWindowStation: %s', [SysErrorMessage(GetLastError)]); Exit; end; // GetUserObjectInformation returns required size in dwSizeNeeded if not GetUserObjectInformation(hWinStation, UOI_USER_SID, nil, 0, dwSize) then begin // GetUserObjectInformation returns required size GetMem(LogonSid, dwSize + 1); if not GetUserObjectInformation(hWinStation, UOI_USER_SID, LogonSid, dwSize, dwSize) then begin ShowMessageFmt('GetUserObjectInformation: %s', [SysErrorMessage(GetLastError)]); Exit; end; end; // Cleanup CloseWindowStation(hWinStation); end; |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
I'm using that already - to add this SID to the groups of the new logon token does not work. Believe me.
|
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Try this:
Delphi-Quellcode:
Use this GetLogonSid:
if WTSQueryUserToken(WtsGetActiveConsoleSessionID, hToken) then
begin GetLogonSid(hToken, LogonSid);
Delphi-Quellcode:
Continue on with LsaLogonUser
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; |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Actually I get this login SID, which is definitly a Session Logon ID :
(S-1-5-5-0-946199) I translated your source :D- I hope it correct.
Delphi-Quellcode:
And the code that replaces the old one :
constructor TSecurityToken.CreateWTSQueryUserToken(SessionID : Cardinal {= INVALID_HANDLE_VALUE});
begin Self.Create; fShared := FALSE; if SessionID = INVALID_HANDLE_VALUE then SessionID := WtsGetActiveConsoleSessionID; fAccessMask := TOKEN_ALL_ACCESS; if not WTSQueryUserToken(SessionID, fTokenHandle) then raise ESMWinCallFailedException.CreateFmtEx('A call to WTSQueryUserToken failed. ', 'WTSQueryUserToken',ClassName,'USM_Token.pas', 0,true,[]); end; function GetLogonSID(aToken: TSecurityToken) : TSecurityID; var i : integer; ptg : TSecurityIDList; begin result := nil; ptg := aToken.GetTokenGroups; // Loop through the groups to find the logon SID. for i := 0 to ptg.Count-1 do begin if (ptg[i].Attributes and SE_GROUP_LOGON_ID) = SE_GROUP_LOGON_ID then begin // Found the logon SID; make a copy of it. result := TSecurityID.Create(ptg[i].CreateCopyOfSID); Break; end; end; end;
Delphi-Quellcode:
var WTSToken := TSecurityToken;
aLocalGroups : TSecurityID; ... WTSToken := TSecurityToken.CreateWTSQueryUserToken(); aLocalGroups := TSecurityIDList.Create(true); aLogonSid := GetLogonSID(WTSToken); ShowMessage('aLogonSid: '+ aLogonSid.GetText(true)); aLocalGroups.Add(aLogonSid); aLocalGroups.Add(TSecurityID.Create('','DebuggerUser')); aLocalGroups.Add(AdministratorsSID); |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
This works for me (adapt username and password to something of your liking):
It uses dialogs to give some debug info when something goes wrong (make service interactive to see the messageboxes), offcourse you can remove these in the final version.
Delphi-Quellcode:
Maybe you'll need unit uWinStation to compile:
unit uMain;
interface uses Windows, 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: _LUID; hLsaToken: THandle; QuotaLimits: QUOTA_LIMITS; SubStatus: Integer; wsDomain: WideString; wsUser: WideString; wsPwd: WideString; TokenSource: TOKEN_SOURCE; dwReturnLength: DWORD; 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; // 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 := 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.
Delphi-Quellcode:
unit uWinStation;
interface uses SysUtils, Dialogs, JwaWinType, JwaWinBase, JwaWinNT, JwaNtSecApi, JwaNTStatus, JwaNative, JwaWinUser, JwaWinError; function StartInteractiveClientProcess(const lpszUsername: PAnsiChar; const lpszDomain: PAnsiChar; const lpszPassword: PAnsiChar; const lpCommandLine: PChar): Boolean; function GetLogonSID(hToken: THandle; var ppsid: PSID): Boolean; function AddAceToWindowStation(hwinsta: HWINSTA; psid: PSID): Boolean; function AddAceToDesktop(hdesktop: HDESK; ps: PSID): Boolean; function SIDToStr (sid : PSID) : string; procedure StrToSid (const sidName : string; sid : PSid; sidLen : DWORD); implementation const DESKTOP_ALL = DESKTOP_READOBJECTS or DESKTOP_CREATEWINDOW or DESKTOP_CREATEMENU or DESKTOP_HOOKCONTROL or DESKTOP_JOURNALRECORD or DESKTOP_JOURNALPLAYBACK or DESKTOP_ENUMERATE or DESKTOP_WRITEOBJECTS or DESKTOP_SWITCHDESKTOP or STANDARD_RIGHTS_REQUIRED; WINSTA_ALL = WINSTA_ENUMDESKTOPS or WINSTA_READATTRIBUTES or WINSTA_ACCESSCLIPBOARD or WINSTA_CREATEDESKTOP or WINSTA_WRITEATTRIBUTES or WINSTA_ACCESSGLOBALATOMS or WINSTA_EXITWINDOWS or WINSTA_ENUMERATE or WINSTA_READSCREEN or STANDARD_RIGHTS_REQUIRED; GENERIC_ACCESS = GENERIC_READ or GENERIC_WRITE or GENERIC_EXECUTE or GENERIC_ALL; HEAP_ZERO_MEMORY = 8; ACL_REVISION = 2; ACCESS_ALLOWED_ACE_TYPE = 0; CONTAINER_INHERIT_ACE = 2; INHERIT_ONLY_ACE = 8; OBJECT_INHERIT_ACE = 1; NO_PROPAGATE_INHERIT_ACE = 4; SE_GROUP_LOGON_ID = $C0000000; type ACL_SIZE_INFORMATION = record AceCount: DWORD; AclBytesInUse: DWORD; AclBytesFree: DWORD; end; ACE_HEADER = record AceType: BYTE; AceFlags: BYTE; AceSize: WORD; end; PACE_HEADER = ^ACE_HEADER; ACCESS_ALLOWED_ACE = record Header: ACE_HEADER; Mask: ACCESS_MASK; SidStart: DWORD; end; function SIDToStr (sid : PSID) : string; var psia : PSIDIdentifierAuthority; dwSubAuthorities : DWORD; dwSidRev : DWORD; dwCounter : DWORD; begin dwSidRev := SID_REVISION; if IsValidSid (sid) then begin psia := GetSidIdentifierAuthority (sid); dwSubAuthorities := GetSidSubAuthorityCount (sid)^; result := Format ('S-%u-', [dwSidRev]); if (psia^.Value[0] <> 0) or (psia^.Value[1] <> 0) then result := result + format ('0x%02x%02x%02x%02x%02x%02x',[ psia^.Value [0], psia^.Value [1], psia^.Value [2], psia^.Value [3], psia^.Value [4], psia^.Value [5]]) else result := result + format ('%u', [DWORD (psia^.Value [5]) + DWORD (psia^.Value [4] shl 8) + DWORD (psia^.Value [3] shl 16) + DWORD (psia^.Value [2] shl 24)]); for dwCounter := 0 to dwSubAuthorities - 1 do result := result + Format ('-%u', [GetSidSubAuthority (sid, dwCounter)^]) end else raise Exception.Create ('Invalid SID'); end; procedure StrToSid (const sidName : string; sid : PSid; sidLen : DWORD); var ps : PChar; pn : PChar; p : PChar; pa : PChar; valueStr : string; psia : PSIDIdentifierAuthority; i : DWORD; d : DWORD; authorityCount : DWORD; begin (* typedef struct _SID { BYTE Revision; BYTE SubAuthorityCount; SID_IDENTIFIER_AUTHORITY IdentifierAuthority; #ifdef MIDL_PASS [size_is(SubAuthorityCount)] DWORD SubAuthority[*]; #else // MIDL_PASS DWORD SubAuthority[ANYSIZE_ARRAY]; *) if not ((Length (sidName) > 3) and (sidName [1] = 'S') and (sidName [2] = '-')) then raise Exception.Create ('Bad SID'); if sidLen < sizeof (_SID_IDENTIFIER_AUTHORITY) + 2 then raise Exception.Create ('Bad SID'); ps := PChar (sid); pn := PChar (sidName); Inc (pn, 2); p := StrScan (pn, '-'); if not Assigned (p) then raise Exception.Create ('Bad SID'); p^ := #0; ps^ := char (StrToInt (pn)); // Revision Inc (ps); pa := ps; // Save authority count position Inc (ps); pn := p + 1; p := StrScan (pn, '-'); if not Assigned (p) then raise Exception.Create ('Bad SID'); p^ := #0; valueStr := pn; if Length (valueStr) < 1 then raise Exception.Create ('Bad SID'); psia := PSIDIdentifierAuthority (ps); Inc (ps, sizeof (_SID_IDENTIFIER_AUTHORITY)); Dec (sidLen, 2 + sizeof (_SID_IDENTIFIER_AUTHORITY)); if valueStr [1] = 'x' then begin if Length (valueStr) <> 14 then raise Exception.Create ('Bad SID'); psia^.value [0] := StrToInt ('$' + Copy (valueStr, 3, 2)); psia^.value [1] := StrToInt ('$' + Copy (valueStr, 5, 2)); psia^.value [2] := StrToInt ('$' + Copy (valueStr, 7, 2)); psia^.value [3] := StrToInt ('$' + Copy (valueStr, 9, 2)); psia^.value [4] := StrToInt ('$' + Copy (valueStr, 11, 2)); psia^.value [5] := StrToInt ('$' + Copy (valueStr, 13, 2)) end else begin psia^.value [0] := 0; psia^.value [1] := 0; i := StrToInt (valueStr); d := i shl 24; psia^.value [2] := d and $ff; d := i shl 16; psia^.value [3] := d and $ff; d := i shl 8; psia^.value [4] := d and $ff; psia^.value [5] := i and $ff; end; pn := p + 1; authorityCount := 0; while lstrlen (pn) > 0 do begin p := StrScan (pn, '-'); if Assigned (p) then begin p^ := #0; i := StrToInt (pn); pn := p + 1 end else begin i := StrToInt (pn); pn := pn + lstrlen (pn) end; if sidLen < sizeof (DWORD) then raise Exception.Create ('Bad SID'); PDWORD (ps)^ := i; Inc (ps, sizeof (DWORD)); Dec (sidLen, sizeof (DWORD)); Inc (authorityCount); end; pa^ := char (authorityCount); if not IsValidSID (sid) then raise Exception.Create ('Bad SID'); end; function AddAceToWindowStation(hwinsta: HWINSTA; psid: PSID): Boolean; var si: SECURITY_INFORMATION; psd, psdNew: PSECURITY_DESCRIPTOR; dwSidSize, dwSdSizeNeeded, dwNewAclSize: DWORD; bDaclPresent, bDaclExist: LongBool; pdacl, pNewAcl: PACL; aclSizeInfo: ACL_SIZE_INFORMATION; i: integer; pTempAce: PACE_HEADER; pace: ^ACCESS_ALLOWED_ACE; begin Result := False; si := DACL_SECURITY_INFORMATION; pace := nil; psd := nil; dwSidSize := 0; pNewAcl := nil; psdNew := nil; // Obtain the DACL for the window station. try if not GetUserObjectSecurity(hwinsta, si, psd, dwSidSize, dwSdSizeNeeded) then begin if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin psd := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded); if psd = nil then Exit; psdNew := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded); if psdNew = nil then Exit; dwSidSize := dwSdSizeNeeded; if not GetUserObjectSecurity(hwinsta, si, psd, dwSidSize, dwSdSizeNeeded) then Exit; end else begin Exit; end; end; // Create a new DACL. if not InitializeSecurityDescriptor(psdNew, SECURITY_DESCRIPTOR_REVISION) then Exit; // Get the DACL from the security descriptor. if not GetSecurityDescriptorDacl(psd, bDaclPresent, pdacl, bDaclExist) then Exit; // Initialize the ACL. ZeroMemory(@aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION)); aclSizeInfo.AclBytesInUse := SizeOf(ACL); // Call only if the DACL is not NULL. if pdacl <> nil then begin // get the file ACL size info if not GetAclInformation(pdacl, @aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION), AclSizeInformation) then Exit; end; // Compute the size of the new ACL. dwNewAclSize := aclSizeInfo.AclBytesInUse + (2 * SizeOf(ACCESS_ALLOWED_ACE)) + (2 * GetLengthSid(psid)) - (2 * SizeOf(DWORD)); // Allocate memory for the new ACL. pNewAcl := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwNewAclSize); if pNewAcl = nil then Exit; // Initialize the new DACL. if not InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION) then Exit; // If DACL is present, copy it to a new DACL. if bDaclPresent then begin // Copy the ACEs to the new ACL. if aclSizeInfo.AceCount > 0 then begin for i := 0 to aclSizeInfo.AceCount - 1 do begin // Get an ACE. if not GetAce(pdacl, i, Pointer(pTempAce)) then Exit; // Add the ACE to the new ACL. if not AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, pTempAce.AceSize) then Exit; end; end; end; // Add the first ACE to the window station. pace := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, SizeOf(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - SizeOf(DWORD)); if pace = nil then Exit; pace.Header.AceType := ACCESS_ALLOWED_ACE_TYPE; pace.Header.AceFlags := CONTAINER_INHERIT_ACE or INHERIT_ONLY_ACE or OBJECT_INHERIT_ACE; pace.Header.AceSize := SizeOf(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) - SizeOf(DWORD); pace.Mask := GENERIC_ACCESS; if not CopySid(GetLengthSid(psid), @pace.SidStart, psid) then Exit; if not AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pace, pace.Header.AceSize) then Exit; // Add the second ACE to the window station. pace.Header.AceFlags := NO_PROPAGATE_INHERIT_ACE; pace.Mask := WINSTA_ALL; if not AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pace, pace.Header.AceSize) then Exit; // Set a new DACL for the security descriptor. if not SetSecurityDescriptorDacl(psdNew, True, pNewAcl, False) then Exit; // Set the new security descriptor for the window station. if not SetUserObjectSecurity(hwinsta, si, psdNew) then Exit; // Indicate success. Result := True; finally // Free the allocated buffers. if pace <> nil then HeapFree(GetProcessHeap, 0, pace); if pNewAcl <> nil then HeapFree(GetProcessHeap, 0, pNewAcl); if psd <> nil then HeapFree(GetProcessHeap, 0, psd); if psdNew <> nil then HeapFree(GetProcessHeap, 0, psdNew); end; end; function GetLogonSID(hToken: THandle; var ppsid: PSID): Boolean; var dwLength: DWORD; ptg: ^TOKEN_GROUPS; i: integer; begin Result := False; dwLength := 0; ptg := nil; try // Verify the parameter passed in is not NULL. // if ppsid = nil then // Exit; // 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; Result := True; end; finally // Free the buffer for the token groups. if ptg <> nil then begin HeapFree(GetProcessHeap, 0, ptg); end; end; end; function AddAceToDesktop(hdesktop: HDESK; ps: PSID): Boolean; var aclSizeInfo: ACL_SIZE_INFORMATION; bDaclExist, bDaclPresent: LongBool; dwNewAclSize, dwSidSize, dwSdSizeNeeded: DWORD; pdacl, pNewAcl: PACL; psd, psdNew: PSECURITY_DESCRIPTOR; pTempAce: PACE_HEADER; si: SECURITY_INFORMATION; i: integer; begin Result := False; psd := nil; psdNew := nil; pNewAcl := nil; si := DACL_SECURITY_INFORMATION; dwSidSize := 0; try // Obtain the security descriptor for the desktop object. if not GetUserObjectSecurity(hdesktop, si, psd, dwSidSize, dwSdSizeNeeded) then begin if GetLastError = ERROR_INSUFFICIENT_BUFFER then begin psd := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded); if psd = nil then Exit; psdNew := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwSdSizeNeeded); if psdNew = nil then Exit; dwSidSize := dwSdSizeNeeded; if not GetUserObjectSecurity(hdesktop, si, psd, dwSidSize, dwSdSizeNeeded) then Exit; end else begin Exit; end; end; // Create a new security descriptor. if not InitializeSecurityDescriptor(psdNew, SECURITY_DESCRIPTOR_REVISION) then Exit; // Obtain the DACL from the security descriptor. if not GetSecurityDescriptorDacl(psd, bDaclPresent, pdacl, bDaclExist) then Exit; // Initialize. ZeroMemory(@aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION)); aclSizeInfo.AclBytesInUse := SizeOf(ACL); // Call only if NULL DACL. if pdacl <> nil then begin // Determine the size of the ACL information. if not GetAclInformation(pdacl, @aclSizeInfo, SizeOf(ACL_SIZE_INFORMATION), AclSizeInformation) then Exit; end; // Compute the size of the new ACL. dwNewAclSize := aclSizeInfo.AclBytesInUse + SizeOf(ACCESS_ALLOWED_ACE) + GetLengthSid(ps) - SizeOf(DWORD); // Allocate buffer for the new ACL. pNewAcl := HeapAlloc(GetProcessHeap, HEAP_ZERO_MEMORY, dwNewAclSize); if pNewAcl = nil then Exit; // Initialize the new ACL. if not InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION) then Exit; // If DACL is present, copy it to a new DACL. if bDaclPresent then begin // Copy the ACEs to the new ACL. if aclSizeInfo.AceCount > 0 then begin for i := 0 to aclSizeInfo.AceCount - 1 do begin // Get an ACE. if not GetAce(pdacl, i, Pointer(pTempAce)) then Exit; // Add the ACE to the new ACL. if not AddAce(pNewAcl, ACL_REVISION, MAXDWORD, pTempAce, pTempAce.AceSize) then Exit; end; end; end; // Add ACE to the DACL. if not AddAccessAllowedAce(pNewAcl, ACL_REVISION, DESKTOP_ALL, ps) then Exit; // Set new DACL to the new security descriptor. if not SetSecurityDescriptorDacl(psdNew, True, pNewAcl, False) then Exit; // Set the new security descriptor for the desktop object. if not SetUserObjectSecurity(hdesktop, si, psdNew) then Exit; // Indicate success. Result := True; finally // Free buffers. if pNewAcl <> nil then HeapFree(GetProcessHeap, 0, pNewAcl); if psd <> nil then HeapFree(GetProcessHeap(), 0, psd); if psdNew <> nil then HeapFree(GetProcessHeap(), 0, psdNew); end; end; function StartInteractiveClientProcess(const lpszUsername: PAnsiChar; const lpszDomain: PAnsiChar; const lpszPassword: PAnsiChar; const lpCommandLine: PChar): Boolean; var hToken : THandle; hdesktop : HDESK; hwinst : HWINSTA; hwinstSave: HWINSTA; pi : PROCESS_INFORMATION; pS : PSID; si : STARTUPINFO; begin Result := False; hdesktop := 0; hwinst := 0; hwinstSave := 0; pS := nil; // try // Log the client on to the local computer. // if not LogonUser(lpszUsername, lpszDomain, lpszPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, hToken) then if not LogonUser(lpszUsername, lpszDomain, lpszPassword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, hToken) then begin ShowMessageFmt('Logonuser failed: %s', [SysErrorMessage(GetLastError)]); Result := False; // raise exception.create(Format('LogonUser: %s', [SysErrorMessage(GetLastError)])); Exit; end; OutputDebugString(PChar(Format('LogonUser: %s', [SysErrorMessage(GetLastError)]))); // Save a handle to the caller's current window station. hwinstSave := GetProcessWindowStation; if hwinstSave = 0 then begin raise exception.create(Format('GetProcessWindowStation: %s', [SysErrorMessage(GetLastError)])); Exit; end; OutputDebugString(PChar(Format('GetProcessWindowStation: %s', [SysErrorMessage(GetLastError)]))); //\Sessions\2\Windows\WindowStations\WinSta0\Default // Get a handle to the interactive window station. hwinst := OpenWindowStation('WinSta0', False, READ_CONTROL or WRITE_DAC); if hwinst = 0 then begin raise exception.create(Format('OpenWindowStation: %s', [SysErrorMessage(GetLastError)])); Exit; end; OutputDebugString(PChar(Format('OpenWindowStation: %s', [SysErrorMessage(GetLastError)]))); // To get the correct default desktop, set the caller's // window station to the interactive window station. if not SetProcessWindowStation(hwinst) then begin raise exception.create(Format('SetProcessWindowStation(hwinst): %s', [SysErrorMessage(GetLastError)])); Exit; end; OutputDebugString(PChar(Format('SetProcessWindowStation(hwinst): %s', [SysErrorMessage(GetLastError)]))); // Get a handle to the interactive desktop. hdesktop := OpenDesktop('default', 0, False, READ_CONTROL or WRITE_DAC or DESKTOP_WRITEOBJECTS or DESKTOP_READOBJECTS); if hdesktop = 0 then begin raise exception.create(Format('OpenDesktop: %s', [SysErrorMessage(GetLastError)])); Exit; end; OutputDebugString(PChar(Format('OpenDesktop: %s', [SysErrorMessage(GetLastError)]))); // Restore the caller's window station. if not SetProcessWindowStation(hwinstSave) then begin raise exception.create(Format('SetProcessWindowStation(hwinstSave): %s', [SysErrorMessage(GetLastError)])); Exit; end; // Get the SID for the client's logon session. if not GetLogonSID(hToken, pS) then begin raise exception.create(Format('GetLogonSID: %s', [SysErrorMessage(GetLastError)])); Exit; end; // Allow logon SID full access to interactive window station. if not AddAceToWindowStation(hwinst, pS) then begin raise exception.create(Format('AddAceToWindowStation: %s', [SysErrorMessage(GetLastError)])); Exit; end; // Allow logon SID full access to interactive desktop. if not AddAceToDesktop(hdesktop, pS) then begin raise exception.create(Format('AddAceToDesktop: %s', [SysErrorMessage(GetLastError)])); Exit; end; // Impersonate client to ensure access to executable file. if not ImpersonateLoggedOnUser(hToken) then begin raise exception.create(Format('ImpersonateLoggedOnUser: %s', [SysErrorMessage(GetLastError)])); Exit; end; // Initialize the STARTUPINFO structure. // Specify that the process runs in the interactive desktop. ZeroMemory(@si, SizeOf(STARTUPINFO)); si.cb := SizeOf(STARTUPINFO); si.lpDesktop := PChar('Sessions\3\Windows\WindowStations\WinSta0\Default'); // Launch the process in the client's logon session. Result := CreateProcessAsUser(hToken, nil, lpCommandLine, nil, nil, False, // handles are not inheritable NORMAL_PRIORITY_CLASS or CREATE_NEW_CONSOLE, nil, nil, si, pi); // End impersonation of client. RevertToSelf(); if Result and (pi.hProcess <> INVALID_HANDLE_VALUE) then begin WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); end; if pi.hThread <> INVALID_HANDLE_VALUE then begin CloseHandle(pi.hThread); end; Result := True; // finally if hwinstSave <> 0 then begin SetProcessWindowStation(hwinstSave); end; // Free the buffer for the logon SID. if pS <> nil then begin HeapFree(GetProcessHeap, 0, pS); end; // Close the handles to the interactive window station and desktop. if hwinst <> 0 then begin CloseWindowStation(hwinst); end; if hdesktop <> 0 then begin CloseDesktop(hdesktop); end; // Close the handle to the client's access token. if hToken <> INVALID_HANDLE_VALUE then begin CloseHandle(hToken); end; end; //end; end. |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Okay thats great.
I reread your code and found the problem : I forgot to add the attributes :D
Delphi-Quellcode:
pGroups^.Groups[0].Attributes := SE_GROUP_MANDATORY or
SE_GROUP_ENABLED or SE_GROUP_ENABLED_BY_DEFAULT or SE_GROUP_LOGON_ID;
Delphi-Quellcode:
aLocalGroups := TSecurityIDList.Create(true);
aLogonSid := GetLogonSID(WTSToken); [b]OR[/b] aLogonSid := GetLogonSID(); aLocalGroups.Add(aLogonSid); aLogonSid.Attributes := SE_GROUP_MANDATORY or SE_GROUP_ENABLED or SE_GROUP_ENABLED_BY_DEFAULT or SE_GROUP_LOGON_ID; You see both versions of GetLogonSID are working. Question: Do I have to set the attributes for the my special debugger user ?
Delphi-Quellcode:
I get debug privileges but cannot bring the taskmanager to enable "show processes of all users" .
aLocalGroups.Add(TSecurityID.Create('','DebuggerUser'));
('C:\WINDOWS\system32\taskmgr.exe') Only this works:
Delphi-Quellcode:
aSID := AdministratorsSID;
aLocalGroups.Add(aSID); aSID.Attributes := SE_GROUP_MANDATORY or SE_GROUP_ENABLED or SE_GROUP_ENABLED_BY_DEFAULT or SE_GROUP_LOGON_ID; |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Just remembered something: GetWtsActiveConsoleSessionID is for XP/2003 and higher. On lower versions the functions doesn't exist and the active console session is always session id 0. If you want to be safe wrap the function and do an OS check and return 0 if NT or 2000.
|
Re: LSALogonUser und Authentifikation (nichts komplexes!)
The WTA function family is one more class to be implemented.
OMG the security library grows and grows and grows and did I mention "grows" ? |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
LOL
BTW Don't forget to look at my JwaWinSta in that case, it has got some undocumented Terminal Server stuff (shadow sessions, connect to other sessions and obtaining login and idle time for terminal server sessions). |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
I know your unit - its part of the jedi api lib - I converted it :D
I developed a desktop class named ![]() I did this also for winstation - but without implementation - only interface section is available (if I could even find it). |
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Guys, you are notorious! Get a life! :mrgreen: :zwinker:
|
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Zitat:
|
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Zitat:
|
Re: LSALogonUser und Authentifikation (nichts komplexes!)
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:40 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