![]() |
LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Liste der Anhänge anzeigen (Anzahl: 2)
Hallo,
ich hab ein Problem mit LsaEnumerateLogonSessions. Ich hab hier das Forum schon durchwühlt und war froh, als ich Informationen gefunden habe, wie ich die eingeloggten User Sessions auflisten kann. Das habe ich dann mit Hilfe des Forums und der MSDN umgesetzt und vorerst auch keinen Fehler festgestellt. Dann musste ich allerdings feststellen, das nicht immer das richtige Ergebniss ausgegeben wird. Und zwar immer dann wenn ein User (Benutzer1) sich anmeldet, abmeldet und ein anderer User (Benutzer2) sich anmeldet. Wenn Benutzer2 jetzt mein Programm ausführt, liefert mir LsaEnumerateLogonSessions auch noch Benutzer1 in der Liste mit. Kann man mit LsaEnumerateLogonSessions auch herausbekommen welche User sich abgemeldet haben? Ich dachte es werden nur die angemeldeten User angezeigt. Hier mein Code (in meinem Formular nutze ich AllocConsole um mit WriteLn die Infos ausgeben zu lassen:
Delphi-Quellcode:
Im Anhang das Ergebnis der Console, wo beide User angezeigt werden. Ich möchte gern nur das Ergebnis aus dem TaskManager haben, der nur die angemeldeten User anzeigt.uses Windows, SysUtils; type PLuid = ^LUID; _LUID = record LowPart: DWORD; HighPart: LongInt; end; LUID = _LUID; USHORT = Word; _LSA_UNICODE_STRING = record Length: USHORT; MaximumLength: USHORT; Buffer: LPWSTR; end; LSA_UNICODE_STRING = _LSA_UNICODE_STRING; _SECURITY_LOGON_TYPE = ( Interactive = 2, Network, Batch, Service, Proxy, Unlock, NetworkCleartext, NewCredentials, RemoteInteractive, CachedInteractive, CachedRemoteInteractive); SECURITY_LOGON_TYPE = _SECURITY_LOGON_TYPE; TSecurityLogonType = SECURITY_LOGON_TYPE; PSECURITY_LOGON_SESSION_DATA = ^SECURITY_LOGON_SESSION_DATA; _SECURITY_LOGON_SESSION_DATA = record Size: ULONG; LogonId: LUID; UserName: LSA_UNICODE_STRING; LogonDomain: LSA_UNICODE_STRING; AuthenticationPackage: LSA_UNICODE_STRING; LogonType: SECURITY_LOGON_TYPE; Session: ULONG; Sid: PSID; LogonTime: LARGE_INTEGER; LogonServer: LSA_UNICODE_STRING; DnsDomainName: LSA_UNICODE_STRING; Upn: LSA_UNICODE_STRING; end; SECURITY_LOGON_SESSION_DATA = _SECURITY_LOGON_SESSION_DATA; TSecurityLogonSessionData = SECURITY_LOGON_SESSION_DATA; function LsaNtStatusToWinError(Status: cardinal): ULONG; stdcall; external 'Advapi32.dll'; function LsaEnumerateLogonSessions(LogonSessionCount: PULONG; LogonSessionList: PLUID): LongInt; stdcall; external 'Secur32.dll'; function LsaGetLogonSessionData(LogonId: PLUID; var ppLogonSessionData: PSECURITY_LOGON_SESSION_DATA): ULONG; stdcall; external 'Secur32.dll'; function LsaFreeReturnBuffer(Buffer: Pointer): ULONG; stdcall; external 'Secur32.dll'; implementation ... procedure TForm1.Button3Click(Sender: TObject); var iRes: Integer; Count: Cardinal; List: PLUID; Test: LUID; SessionData: PSECURITY_LOGON_SESSION_DATA; i: Integer; tc64: Int64; ldt: TDateTime; SIDInfo: TSIDInfo; begin // based on // http://www.delphipraxis.net/90606-den-aktiven-benutzer-bzw-status-des-benutzers-bekommen.html // get list of sessions iRes:= LsaNtStatusToWinError(LsaEnumerateLogonSessions(@Count, @List)); // check result of list if (iRes = ERROR_SUCCESS) then begin // no error // check count of list if (Count > 0) then begin // min 1 session WriteLn(Format('Count: %d', [Count])); WriteLn(''); // enumerate list for i := 0 to Count - 1 do begin // for each item in list get session data iRes := LsaNtStatusToWinError(LsaGetLogonSessionData(List, SessionData)); // test, display item in list, also if result is not successfull Test := List^; Writeln(Format('Session %d: %u %u', [i, Test.LowPart, Test.HighPart])); // check result of sessiondata if (iRes = ERROR_SUCCESS) then begin // only interactive users if SessionData.LogonType in [Interactive] then begin // write infos WriteLn(Format(' LogonId: %d', [Int64(SessionData.LogonId)])); WriteLn(Format(' UserName: %s', [String(SessionData.UserName.Buffer)])); WriteLn(Format(' LogonDomain: %s', [String(SessionData.LogonDomain.Buffer)])); WriteLn(Format(' Session: %d', [SessionData.Session])); WriteLn(Format(' SID: %s %s', [SIDToName(SessionData.Sid), SIDToStrSID(SessionData.Sid)])); WriteLn(Format(' LogonServer: %s', [String(SessionData.LogonServer.Buffer)])); WriteLn(Format(' LogonType: %d', [Integer(SessionData.LogonType)])); tc64 := GetTickCount64; ldt := FileTimeToDateTime(SessionData.LogonTime); WriteLn(Format(' LogonTime: DateTime: %s Unix: %u', [DateTimeToStr(ldt), DateTimeToUnixTrunc(ldt)])); WriteLn(Format(' TickCount: ms: %u', [tc64])); // get sid info if GetSIDInfo(SessionData.Sid, SIDInfo) then begin // is user if (SIDInfo.SIDType = SidTypeUser) then begin // write sid infos WriteLn(Format(' SIDInfo.Name: %s', [SIDInfo.Name])); WriteLn(Format(' SIDInfo.ReferenceDomainName: %s', [SIDInfo.ReferenceDomainName])); WriteLn(Format(' SIDInfo.SIDType: %u', [Integer(SIDInfo.SIDType)])); end; end; end; // free sessiondata iRes := LsaNtStatusToWinError(LsaFreeReturnBuffer(SessionData)); if (iRes <> ERROR_SUCCESS) then begin // error free sessiondata WriteLn(SysErrorMessage(iRes)); end; end else begin // error sessiondata WriteLn(SysErrorMessage(iRes)); end; // space WriteLn(''); // inc list Inc(List); end; end else begin // no sessions found WriteLn('No Sessions'); end; // free list iRes := LsaNtStatusToWinError(LsaFreeReturnBuffer(List)); if (iRes <> ERROR_SUCCESS) then begin // error free list WriteLn(SysErrorMessage(iRes)); end; end else begin // error list sessions WriteLn(SysErrorMessage(iRes)); end; end; Kann mir jemand helfen oder mir Erklären was da LsaEnumerateLogonSessions macht. Ich habe LsaEnumerateLogonSessions genommen, da ich mit LsaGetLogonSessionData auch die LogOn Zeit ermitteln kann. Jetzt müsste ich nur noch alle aktiven Sessions herausfiltern. Nur wie??? Nachvollziehen kann ich das unter WinXP SP3 und Win7 SP1 mit Delphi 2009. Gruß, Marco. |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Teste mal logonsessions.exe von Sysinternals.
|
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Ok hab ich gemacht. Ist das gleiche Resultat.
Ich denke das LsaEnumerateLogonSessions für mich nicht die Richtige funktion ist. Ich möchte gern alle Sessions der zur Zeit angemeldeten Benutzer mit Namen und Uhrzeit des Logons ermittel. Und LsaEnumerateLogonSessions liefert mir leider auch Sessions, deren Benutzer schon längst abgemeldet sind. |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Zitat:
Hier noch ohne Uhrzeit des Logins; aber die lässt sich - etwas aufwändiger zwar - anders ermitteln:
Code:
Beispiel:
type
TWKSTA_USER_INFO_0 = record username: PWideChar; end; PTWKSTA_USER_INFO_0 = ^TWKSTA_USER_INFO_0; function NetWkstaUserEnum(servername: PWideChar; level: DWORD; var bufptr: Pointer; prefmaxlen: DWORD; var entriesread: PDWord; var totalentries: PDWord; var resumehandle: PDWord): Longint; stdcall; external 'netapi32.dll' Name 'NetWkstaUserEnum'; function EnumNetUsers(Users: TStrings): TWKSTA_USER_INFO_0; const STR_ERROR_ACCESS_DENIED = 'User does not have access to the requested information.'; STR_ERROR_MORE_DATA = 'Specify a buffer large enough to receive all entries.'; STR_ERROR_INVALID_LEVEL = 'Parameter "level" has been set invalid.'; var UI: PTWKSTA_USER_INFO_0; HostInfo: Pointer; ElTotal: PDWord; ElCount: PDWord; Resume: PDWord; Error: Longint; i: Integer; begin Resume := 0; NetWkstaUserEnum(nil, 0, HostInfo, 0, ElCount, ElTotal, Resume); Error := NetWkstaUserEnum(nil, 0, HostInfo, 256 * Integer(ElTotal), ElCount, ElTotal, Resume); case Error of ERROR_ACCESS_DENIED: Result.UserName := STR_ERROR_ACCESS_DENIED; ERROR_MORE_DATA: Result.UserName := STR_ERROR_MORE_DATA; ERROR_INVALID_LEVEL: Result.UserName := STR_ERROR_INVALID_LEVEL; else if HostInfo <> nil then begin Result := TWKSTA_USER_INFO_0(HostInfo^); UI := PTWKSTA_USER_INFO_0(HostInfo); for i := 1 to DWord(ElCount) do begin Users.Add(UI^.username); inc(UI); end; end else begin Result.UserName := '<???>'; end; end; end;
Code:
procedure TForm1.Button1Click(Sender: TObject);
var HostInfo: TWKSTA_USER_INFO_0; ActiveUsers: TStringlist; i: integer; wrkstr: string; begin ActiveUsers := TStringlist.Create; try HostInfo := EnumNetUsers(ActiveUsers); wrkstr := 'Users currently logged in:'#13#10; for i := 1 to ActiveUsers.count - 1 do wrkstr := wrkstr + ActiveUsers[i] + #13#10; Showmessage(wrkstr); finally ActiveUsers.Free; end; end; |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Ich hab gerade versucht alles mit WTSEnumerateSessions nachzubauen. Da bekomme ich auch nur die richtigen Sessions zurück. Da dachte ich nun ok ich hole mir dann mit WTSQuerySessionInformation und dem Parameter WTSSessionInfoEx auch die Logon Zeit mit, aber in der MSDN steht das
Zitat:
Naja ich werd auf eine Kombination mit LsaEnumerateLogonSessions und WTSEnumerateSessions zurückgreifen. Mit LsaEnumerateLogonSessions alle Sessions und Zeiten holen und mit WTSEnumerateSessions die angemeldeten User filtern. Irgendwie nicht zufriedenstellend. Ich denke das auch NetWkstaUserEnum nicht ganz das richtige ist. Zitat:
Wenn jemand ne bessere Idee hat nur immer her damit. Ärgerlich das bei LsaEnumerateLogonSessions keine LOGOFF Zeit ermittelt werden kann. |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Hab grad gesehen das sich die Sessions von LsaEnumerateLogonSessions nur durch die LogonId unterscheden und die SessionID gleich bleibt. So kann ich ja nicht einmal anhand der Sessions von WTSEnumerateSessions die Sessions filtern.
Kennt sich jemand mit der LogonID aus? Ist das eine fortlaufende Nummer? Kann man immer von der höchsten Nummer auf die letzte Session eines User schließen? Wäre sehr dankbar für informationen. ... :wall: |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Zitat:
In der NetAPI Funktion NetWkstaUserEnum() kannst Du über den Parameter "level" 2 Optionen steuern: Mit level = 0 werden explizit alle gerade aktiv am lokalen Rechner angemeldeten Benutzer ermittelt; die zwar grundsätzlich am System angemeldeten, aber gerade nicht aktiv eingeloggten Benutzer werden nicht berücksichtigt. Mit level=1 dagegen wird nur der zum aktiven Desktop gehörige Benutzer und dieser mit zusätzlichen Angaben ausgegeben. Absolut wichtig zu beachten ist dabei nur die richtige Verwendung der jeweiligen Records zur Auswertung der zurückgelieferten Bufferpointer. Die mit level 0 erreichbare Option war doch genau Dein (ursprüngliches) Anliegen ? Wo liegt also jetzt Dein Problem ? Hast Du das denn, so wie in meinem Beispiel vorgeschlagen, wenigstens einmal praktisch versucht, bevor Du die Verwendung von NetWkstaUserEnum() allein mit Hinweis auf das MS-Zitat verwirfst ? Leider sind mit NetWkstaUserEnum() aber keine Angaben zur LogonTime des jeweiligen Benutzers zu erhalten. Eine Möglichkeit dazu wäre jedoch durch gegenseitigen Abgleich der beiden, mit NetWkstaUserEnum() und mit LsaEnumerateLogonSessions() erhaltenen Listen. Die LsaEnumerateLogonSessions()-Liste filterst Du nach den Benutzernamen, die in der NetWkstaUserEnum()-Liste ausgeworfen sind, und kämest somit über die zugehörigen Details der LsaEnumerateLogonSessions()-Liste an die jeweiligen LogonTime(s) aller aktiv angemeldeten Benutzer. Nachteil dieses Weges: um an die Details der Sessions in der LsaEnumerateLogonSessions()-Liste zu kommen, muss man diese Funktion mit Adminrechten vornehmen. NetWkstaUserEnum() dagegen benötigt keine Adminrechte. |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Liste der Anhänge anzeigen (Anzahl: 1)
Ich werde die Methode mit NetWkstaUserEnum auch noch versuchen, nur habe ich gerade ein anderes Problem festgestellt.
Wenn ich alle angemeldeten Sessions (aktiv oder gerade nicht aktiv) ermittelt habe brauche ich unbedingt noch die Logon Zeit. Selbst wenn ich mit NetWkstaUserEnum oder WTSEnumerateSessions die Session ID ermittelt habe bringt mir das nichts. Da die SessionID LsaEnumerateLogonSessions für die User gleich bleibt und ich somit nicht die richtigen Eintrag filtern kann. Siehe Bild, User Test war zweimal angemeldet, ist zur Zeit nicht angemeldet und hat immer die Session ID 0. Welche Logon Zeit ist die richtige? Mir bringt es also nichts (hab ich auch erst heute gemerkt) wenn ich über eine andere Funktion die Session ID ermitteln kann, diese dann aber nicht eindeutig einer Logon Zeit zuordnen kann. Oder jemand kennt noch eine andere Methode wie ich von einer Session die Logon Zeit auslesen kann. Adminrechte sind kein Problem, die abfrage läuft in einem Dienst und der hat Systemrechte. Um nocheinmal mein Problem zu schildern: - ich benötige alle angemeldeten Benutzer Sessions (das geht) - ich benötige die Logon Zeit der jeweiligen Session oder - ich finde heraus, welcher Einträge von LsaEnumerateLogonSessions abgemeldet sind (wiel finde ich im Internet darüber leider nicht, z.B.: LogonID) Mal sehen was ich noch alles finde. Probiere erstmal NetWkstaUserEnum aus. Auch ja ich möchte gern als Minimum WinXP unterstützen. |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Liste der Anhänge anzeigen (Anzahl: 2)
Zitat:
Es handelt sich dabei um den tatsächlichen letzten Loginzeitpunkt. Hatte sich der Benutzer aktiv am System angemeldet, sich jedoch zwischenzeitlich entfernt ohne sich auszuloggen, so dass der Account im Hintergrund geöffnet blieb, und musste sich dann wieder anmelden, um in den an sich immer noch geöffneten Account zu gelangen, dann ist der letzte Loginzeitpunkt genau diese neue Anmeldung. Hier der Code zur der Abfrage der Loginzeiten, wie er (bei mir) unter WinXP Professional reibungslos werkelt:
Code:
Und angehängt der komplette Code der MainUnit im Source sowie - mit geringen Änderungen des Programmlayouts - kompiliert unter D7:
Use Variants, ActiveDs_TLB, COMObj, Ole2, adshlp;
Var ActiveUsers: TStringlist; ComputerName: Olevariant; UserName: Olevariant; UserDomain: Olevariant; function UserLoggedIn(Username: string): string; var target: string; UserObj: Olevariant; LoggedIn: Olevariant; begin target := format('WinNT://%s/%s', [ComputerName, UserName]); UserObj := ADsHlp.GetObject(target); try LoggedIn := UserObj.LastLogin; result := string(LoggedIn); finally UserObj := Unassigned; end; end; function GetActiveUsers: TStringlist; var HostInfo: TWKSTA_USER_INFO_0; WshNetWork: Olevariant; i: integer; LogIn: string; begin result := TStringlist.create; WshNetWork := CreateOleObject('WScript.Network'); try ComputerName := WshNetWork.Computername; UserName := WshNetWork.UserName; UserDomain := WshNetWork.UserDomain; finally WshNetWork := UnAssigned; end; ActiveUsers := TStringlist.Create; try HostInfo := EnumNetUsers(ActiveUsers); for i := 1 to ActiveUsers.count - 1 do begin logIn := UserLoggedIn(ActiveUsers[i]); result.add(format('Name: %s, last Login: %s', [ActiveUsers[i],logIn])); end; finally ActiveUsers.Free; end; end; |
AW: LsaEnumerateLogonSessions gibt nicht eingeloggte User in Liste aus
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,
vielen Dank erstmal für die ganzen Vorschläge. Aber die Ermittlung über NetWkstaUserEnum und COMObjects des Active Directory ist für mich nicht das richtige. Zumindest liefern diese Funktionen nicht die richtigen Ergebnisse (siehe Anhang erstes Bild). Da sind zwei Benutzerkonten (Besitzer und Test1, Test1 hatte sich heute zweimal angemeldet und richtig abgemeldet) angemeldet und eine Anwendung wurde mit "Ausführen als ..." über ein drittes Benutzerkonto (Test2) gestartet. Beide Möglichkeiten zeigen mir alle drei (oder vier) Sessions an. Ich möchte aber nur die zwei angemeldeten Sessions ermitteln (wie im Taskmanager). Vielleicht nochmal zum Verständnis was für mich "angemeldet" bedeutet und welche Logon Zeit ich gern hätte. Angemeldet bedeutet für mich das sich ein Benutzer (auch per Remote) anmeldet und aber auch die Benutzerkonten die gerade nicht aktiv sind (Verbindung getrennt, Remotedesktop schließen oder Benutzerwechsel). Und als Logon Zeit hätte ich gern die erste Anmeldezeit, nicht die Zeit der "reaktivierung der Session". Nicht so wie es mir über das COMObjects des Active Directory ermittelt wird (auch hier dauert der Aufruf einfach zu lang). Ein "reaktivieren" der Session ist für mich also kein "anmelden". Dies scheint mir LsaEnumerateLogonSessions auch alles liefern zu können, nur fehlen mir ein paar Anhaltspunkte was ich dort alles ausgeben/ermitteln kann. Hier mal einAuszug aus dem Ergebnis:
Code:
Wie man sieht werden hier auch Sessions angezeigt, bei denen sich der User richtig abgemeldet hat. Keine Ahnung warum die da nicht gelöscht werden. Ich dachte ich kann Anhand der LogonID ermitteln, welches das letzte, für mich richtige, Login ist.
Session #1: 11300521 0 // Low und Hi der LUID (LUID = Int64)
LogonId: 11300521 // wie der Name sagt die LogonID UserName: Test1 // Name LogonDomain: CLIENTLE01 LogonType: Interactive (2) Session: 2 // SessionID SID: Test1 S-1-5-21-854245398-73586283-1177238915-1010 LogonTime: DateTime: 09.01.2012 13:40:02 Unix: 1326116402 TickCount: ms: 19905815 // TickCount64 LogonServer: CLIENTLE01 DnsDomainName: Upn: SIDInfo.Name: Test1 // SID Informationen lese ich nahand der SID nach SIDInfo.ReferenceDomainName: CLIENTLE01 SIDInfo.SIDType: SidTypeUser (1) WtsConnectState: WTSDisconnected (4) // WTS Status lese ich Anhand der SessionID nach Session #5: 9694340 0 LogonId: 9694340 UserName: Test1 LogonDomain: CLIENTLE01 LogonType: Interactive (2) Session: 1 SID: Test1 S-1-5-21-854245398-73586283-1177238915-1010 LogonTime: DateTime: 09.01.2012 13:10:38 Unix: 1326114638 TickCount: ms: 19905859 LogonServer: CLIENTLE01 DnsDomainName: Upn: SIDInfo.Name: Test1 SIDInfo.ReferenceDomainName: CLIENTLE01 SIDInfo.SIDType: SidTypeUser (1) WtsConnectState: WTSDown (8) Ich denke ich werde jetzt alle doppelten Sessions von LsaEnumerateLogonSessions filtern und hierbei nur die mit dem größten LogonTime als gültig betrachten. Ich habe gehofft das mir jemand genauer sagen kann was LsaEnumerateLogonSessions liefert (aus der MSDN werd ich nicht wirklich schlau) und warum auch "alte" Sessions noch als Duplikat angezeigt werden. Ich werde veruchen die Ergebnisse von LsaEnumerateLogonSessions mit der Zeit und anhand der ermittelten Sessions von WTSEnumerateSessions zu filtern. Das Ergebnis werde ich dann posten. Wäre nur schön, wenn jemand meine Annahmen bestätigen oder wiederlegen kann. Gruß, Marco. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:42 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 by Thomas Breitkreuz