Thema: Delphi LsaLogonUser beispiel

Einzelnen Beitrag anzeigen

Benutzerbild von Remko
Remko

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

LsaLogonUser beispiel

  Alt 14. Feb 2007, 10:04
Sorry for writing in English but although I can read German writing in it is more difficult.

I took me quite a while to get code below working (Thanks for the help Olli). So I am posting this some sample code as it might be usefull for others. It's a sample on how to use MSDN-Library durchsuchenLsaLogonUser
The special thing about LsaLogonUser is the LocalGroups parameter, you can add the user to one or more localgroups for the duration of the session.

The sample code adds the logon sid of the user that starts the sample program, therefore we have access to the desktop. This is a lot easier than the sample code from MSDN [msdn]Starting an Interactive Client Process in C++[/msdn] and besides it will also work in Terminal Server sessions and under Windows Vista.

The sample also retrieves the Administrator Sid's and adds this, so the process gets Admin access.

To use LsaLogonUser you need the SeTcbPrivilege (Act as part of the Operating System).

Delphi-Quellcode:
...

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, JwaWinType, JwaWinBase, JwaWinNT, JwaNtSecApi, JwaNTStatus,
  JwaNative, JwaUserEnv, JwaWinSta, StdCtrls, ExtCtrls,
  JwaProfInfo, JwaSDDL;

...

var Res: NTSTATUS;
    hLSA: THandle;
    LSAString: _LSA_STRING;
    AuthenticationPackage: ULONG;
    AuthentificationInfo: TAuthInfo;
    hToken: THandle;
    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;
    pi: PROCESS_INFORMATION;
    si: STARTUPINFO;
// SessionID: Cardinal; // Only needed when starting a process in another terminal session
    pGroups: PTOKEN_GROUPS;
    AdminSid: PSid;
    dwSizeSid: Cardinal;
    dwSizeDomain: Cardinal;
    SidType: TSidNameUse;
    Domain: String;
    MaxGroups: Integer;
    bRes: Longbool;
begin

  // Enable Act as part of the Operating System token
  if not OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken) then
  begin
    raise exception.create(SysErrorMessage(GetLastError));
  end;
  if not EnablePrivilege(hToken, 'SeTcbPrivilege', true) then
  begin
    ShowMessageFmt('SeTcbPrivilege: %s', [SysErrorMessage(GetLastError)]);
  end;

  if ImpersonateCheckBox.Checked then
  begin
    // Enable Impersonation token
    if not EnablePrivilege(hToken, 'SeImpersonatePrivilege', true) then
    begin
      ShowMessageFmt('SeImpersonatePrivilege: %s', [SysErrorMessage(GetLastError)]);
    end;
    CloseHandle(hToken);
  end;

(*
    // Get the SessionID of our session
    // Only needed if we want to start the process in another session
    if not ProcessIdToSessionID(GetCurrentProcessId, SessionID) then
    begin
      ShowMessageFmt('ProcessIdToSessionID: %s', [SysErrorMessage(GetLastError)]);
    end;

*)


  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 and open Token from CurrentProcess
  if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, hToken)) then
  begin

    // 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;
    // Cleanup
    CloseHandle(hToken);
  end;

  // 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:= DomainEdit.Text;
  wsUser:= UserNameEdit.Text;
  wsPwd:= PasswordEdit.Text;

  // Fill with zeros
  RtlZeroMemory(@AuthentificationInfo, sizeof(AuthentificationInfo));
  AuthentificationInfo.Header.MessageType := MsV1_0InteractiveLogon;

  // 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;

(*
    // Set the token to the user's Terminal Session
    // Only needed if we want to start the process in another session
    if not SetTokenInformation(hLsaToken, TokenSessionId, @SessionID, SizeOf(SessionID)) then
    begin
      ShowMessageFmt('SetTokenInformation: %s', [SysErrorMessage(GetLastError)]);
    end;

*)


  if ImpersonateCheckBox.Checked then
  begin

    if not ImpersonateLoggedOnUser(hLSAToken) then
    begin
      ShowMessageFmt('ImpersonateLoggedOnUser: %s', [SysErrorMessage(GetLastError)]);
    end;

  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(ProcessEdit.Text), 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
  FreeMem(AdminSid);
  LsaDeregisterLogonProcess(hLSA);
  LsaFreeReturnBuffer(pProfileBuffer);
  RevertToSelf;
end;
Delphi-Quellcode:
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;

(*
//  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;

*)
Angehängte Dateien
Dateityp: zip lsalogon_434.zip (178,9 KB, 123x aufgerufen)
  Mit Zitat antworten Zitat