Einzelnen Beitrag anzeigen

Benutzerbild von Remko
Remko

Registriert seit: 10. Okt 2006
Ort: 's-Hertogenbosch, Die Niederlande
222 Beiträge
 
RAD-Studio 2010 Arc
 
#22

Re: LSALogonUser und Authentifikation (nichts komplexes!)

  Alt 12. Aug 2007, 21:57
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:
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.
Maybe you'll need unit uWinStation to compile:
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] = 'xthen
  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.
  Mit Zitat antworten Zitat