Estoy tratando de obtener el último inicio de sesión del usuario actual. Podría ser esta sesión actual o podría ser una anterior a esa.
Llamo a GetUserName() para obtener el nombre de usuario actual. Lo introduzco en NetUserGetInfo() para intentar obtener la última hora de inicio de sesión. Todo esto falla con el error 2221 (usuario no encontrado). Cuando probé con “administrador” funciona. Incluso cuando codifico mi nombre de usuario, devuelve un 2221. Esto es lo que estoy usando:
nStatus = NetUserGetInfo(NULL, L"administrator", dwLevel, (LPBYTE *) & pBuf);
¿Cómo puede obtener la última hora de inicio de sesión del usuario actual?
gracias, el código siempre es bienvenido.
Aquí está el código completo que estoy usando actualmente:
DWORD dwLevel = 2;
NET_API_STATUS nStatus;
LPTSTR sStringSid = NULL;
LPUSER_INFO_0 pBuf = NULL;
LPUSER_INFO_2 pBuf2 = NULL;
WCHAR UserName[256];
DWORD nUserName = sizeof(UserName);
if(GetUserName(UserName, &nUserName))
{
printf("information for %ls\n", UserName);
nStatus = NetUserGetInfo(NULL, UserName, dwLevel, (LPBYTE *) & pBuf);
if (nStatus == NERR_Success)
{
pBuf2 = (LPUSER_INFO_2) pBuf;
printf("\tUser account name: %ls\n", pBuf2->usri2_name);
printf("\tLast logon (seconds since January 1, 1970 GMT): %d\n", pBuf2->usri2_last_logon);
printf("\tLast logoff (seconds since January 1, 1970 GMT): %d\n", pBuf2->usri2_last_logoff);
}
else
fprintf(stderr, "NetUserGetinfo failed with error: %d\n", nStatus);
if (pBuf != NULL)
NetApiBufferFree(pBuf);
}
Puede intentar usar otro nivel como 2, por ejemplo, 11.
También puedes probar LsaGetLogonSessionData
(ver http://msdn.microsoft.com/en-us/library/aa378290.aspx). la estructura SECURITY_LOGON_SESSION_DATA
tiene una gran cantidad de información que puede ser útil para usted. los LUID
(el primer parámetro de LsaGetLogonSessionData
) puedes obtener de GetTokenInformation
con TokenStatistics
y obten AuthenticationId
campo de la TOKEN_STATISTICS
estructura
ACTUALIZADO: Leí con más atención tu código y ahora veo tu principal error. Función NetUserGetInfo
es muy viejo. Existe en la época anterior a Windows NT 3.1. El grupo de funciones que Microsoft denominó ahora “Administración de red” tiene el nombre de “API de LAN Manager”. Todas las funciones se introdujeron en el momento en que no existe un inicio de sesión local. Entonces puedes usar NetUserGetInfo
con NULL como primer parámetro solo en un controlador de dominio. Entonces, en el caso de que inicie sesión con la cuenta de dominio, debe llamar NetGetDCName
, NetGetAnyDCName
o mejor DsGetDcName
para obtener el nombre de un controlador de dominio y usar este nombre (comenzado con dos barras invertidas) como el primer parámetro de NetUserGetInfo
. Si inicia sesión con una cuenta de estación de trabajo local, su programa debería funcionar, pero la cuenta me parece debe ser una cadena UNICODE como L”Administrador” y no “Administrador”. Por cierto, si inicio sesión localmente en mi computadora con Windows 7 de 64 bits, su programa funciona sin ningún problema. El código
nStatus = NetUserGetInfo(NULL, L"administrator", dwLevel, (LPBYTE *) & pBuf);
funciona también.
Repito entonces, en mi opinión, la mejor manera de obtener el último inicio de sesión del usuario es el uso de la API LSA (Autoridad de seguridad local) como LsaGetLogonSessionData
. Cómo prometí que escribí para ti un ejemplo de código que muestra cómo usar LsaGetLogonSessionData
C ª:
#include <windows.h>
#include <Ntsecapi.h>
#include <Sddl.h>
#include <tchar.h>
#include <stdio.h>
//#include <ntstatus.h>
#include <malloc.h>
#include <strsafe.h>
#pragma comment (lib, "Secur32.lib")
#pragma comment (lib, "strsafe.lib")
// The following constant may be defined by including NtStatus.h.
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#endif
// The LSA authentication functions are available in Unicode only.
BOOL GetLogonLUID (LUID *pLuid)
{
BOOL bSuccess;
HANDLE hThread = NULL;
DWORD cbReturnLength;
TOKEN_STATISTICS ts;
__try {
bSuccess = OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hThread); // TOKEN_QUERY_SOURCE
if (!bSuccess)
__leave;
cbReturnLength = sizeof(TOKEN_STATISTICS);
bSuccess = GetTokenInformation (hThread, TokenStatistics, &ts, sizeof(TOKEN_STATISTICS), &cbReturnLength);
if (bSuccess)
*pLuid = ts.AuthenticationId;
}
__finally {
if (hThread)
CloseHandle (hThread);
}
return bSuccess;
}
void PrintUnicodeString (LPCTSTR pszPrefix, LSA_UNICODE_STRING lsaString)
{
if (lsaString.MaximumLength >= lsaString.Length + sizeof(WCHAR) &&
lsaString.Buffer[lsaString.Length/sizeof(WCHAR)] == L'\0')
_tprintf (TEXT("%s: %ls\n"), pszPrefix, lsaString.Buffer);
else if (lsaString.Length <= STRSAFE_MAX_CCH * sizeof(TCHAR)) {
LPWSTR sz = (LPWSTR) _alloca (lsaString.Length + sizeof(WCHAR));
StringCbCopyNW (sz, lsaString.Length + sizeof(WCHAR), lsaString.Buffer, lsaString.Length);
_tprintf (TEXT("%s: %ls\n"), pszPrefix, sz);
}
}
void PrintLogonType (SECURITY_LOGON_TYPE type)
{
if (type < Interactive || type > CachedUnlock)
// This is used to specify an undefied logon type
_tprintf (TEXT("LogonType: UndefinedLogonType\n"));
else {
static LPTSTR szTypes[] = {
TEXT("Interactive"), // Interactively logged on (locally or remotely)
TEXT("Network"), // Accessing system via network
TEXT("Batch"), // Started via a batch queue
TEXT("Service"), // Service started by service controller
TEXT("Proxy"), // Proxy logon
TEXT("Unlock"), // Unlock workstation
TEXT("NetworkCleartext"), // Network logon with cleartext credentials
TEXT("NewCredentials"), // Clone caller, new default credentials
TEXT("RemoteInteractive"), // Remote, yet interactive. Terminal server
TEXT("CachedInteractive"), // Try cached credentials without hitting the net.
// The types below only exist in Windows Server 2003 and greater
TEXT("CachedRemoteInteractive"), // Same as RemoteInteractive, this is used internally for auditing purpose
TEXT("CachedUnlock") // Cached Unlock workstation
};
_tprintf (TEXT("LogonType: %s\n"), szTypes[(int)type-Interactive]);
}
}
void PrintFilefime (LPCTSTR pszPrefix, const FILETIME *lpFileTime)
{
SYSTEMTIME st;
FILETIME ft;
BOOL bSuccess;
TCHAR szTime[1024], szDate[1024];
bSuccess = FileTimeToLocalFileTime (lpFileTime, &ft);
if (!bSuccess)
return;
bSuccess = FileTimeToSystemTime (&ft, &st);
if (!bSuccess)
return;
if (GetDateFormat (LOCALE_USER_DEFAULT, // or LOCALE_CUSTOM_UI_DEFAULT
DATE_SHORTDATE,
&st, NULL, szDate, sizeof(szDate)/sizeof(TCHAR)) > 0) {
if (GetTimeFormat (LOCALE_USER_DEFAULT, // or LOCALE_CUSTOM_UI_DEFAULT
0, &st, NULL, szTime, sizeof(szTime)/sizeof(TCHAR)) > 0) {
_tprintf (TEXT("%s: %s, %s\n"), pszPrefix, szDate, szTime);
}
}
}
int main()
{
LUID LogonLuid; // LOGONID_CURRENT
PSECURITY_LOGON_SESSION_DATA pLogonSessionData = NULL;
LPWSTR pszSid = NULL;
NTSTATUS ntStatus;
GetLogonLUID (&LogonLuid);
__try {
ntStatus = LsaGetLogonSessionData (&LogonLuid, &pLogonSessionData);
if (ntStatus == STATUS_SUCCESS) {
if (pLogonSessionData->UserName.Length)
PrintUnicodeString (TEXT("UserName"), pLogonSessionData->UserName);
if (pLogonSessionData->LogonDomain.Length)
PrintUnicodeString (TEXT("LogonDomain"), pLogonSessionData->LogonDomain);
if (pLogonSessionData->AuthenticationPackage.Length)
PrintUnicodeString (TEXT("AuthenticationPackage"), pLogonSessionData->AuthenticationPackage);
PrintLogonType ((SECURITY_LOGON_TYPE)pLogonSessionData->LogonType);
_tprintf (TEXT("Session: %d\n"), pLogonSessionData->Session);
if (ConvertSidToStringSidW (pLogonSessionData->Sid, &pszSid))
_tprintf (TEXT("Sid: %ls\n"), pszSid);
if (pLogonSessionData->LogonTime.QuadPart)
PrintFilefime (TEXT("LogonTime"), (const FILETIME *)&pLogonSessionData->LogonTime);
if (pLogonSessionData->LogonServer.Length)
PrintUnicodeString (TEXT("LogonServer"), pLogonSessionData->LogonServer);
if (pLogonSessionData->DnsDomainName.Length)
PrintUnicodeString (TEXT("DnsDomainName"), pLogonSessionData->DnsDomainName);
if (pLogonSessionData->Upn.Length)
PrintUnicodeString (TEXT("Upn"), pLogonSessionData->Upn);
// one can dump more information like HomeDirectory, ProfilePath and so on
// if _WIN32_WINNT >= 0x0600 and user login a domain
}
}
__finally {
if (pLogonSessionData)
LsaFreeReturnBuffer(pLogonSessionData);
if (pszSid)
pszSid = (LPTSTR)LocalFree (pszSid);
}
}
¿Que lenguaje? Parece c/c++.
– ChrisF
♦
30 de julio de 2010 a las 13:22
Escribí sobre eso. Es C
– Señor Aleph
30 de julio de 2010 a las 13:28
¿La máquina en la que está ejecutando esto es independiente o forma parte de un dominio de Windows?
– torak
30 de julio de 2010 a las 14:23
depende. Puede estar conectado a un dominio o no. Si este último uso un usuario local, pero todavía no funciona
– Señor Aleph
30 de julio de 2010 a las 15:09