Obtener el último inicio de sesión del usuario actual

8 minutos de lectura

Obtener el ultimo inicio de sesion del usuario actual
señor aleph

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);
}

  • ¿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

1647655747 288 Obtener el ultimo inicio de sesion del usuario actual
Oleg

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);
    }
}

  • Gracias Oleg. El nivel 11 devuelve exactamente el mismo error. Hasta ahora no he encontrado una respuesta en ninguna parte sobre por qué se devuelve este error, incluso cuando el usuario SÍ existe. Intenté algo similar a lo que acabas de sugerir (verifica codeproject.com/KB/system/logonsessions.aspx) y sigo teniendo problemas con las diferentes estructuras y mensajes de error que sugieren que no tengo suficiente memoria. ¿Tienes un fragmento de trabajo? Gracias

    – Señor Aleph

    30 de julio de 2010 a las 18:27

  • Encontré un error en su código y publiqué más ejemplos de otros códigos después de llevar a mi hija a la cama.

    – Oleg

    30 de julio de 2010 a las 20:15

  • Probé con la versión Unicode pero me sale el mismo error. El último fragmento que publicaste parece funcionar. Ahora necesito averiguar cómo obtener el último inicio de sesión para el usuario “anterior” al de ahora, cada vez que inicia sesión, el tiempo de inicio de sesión se sobrescribe con la sesión actual. Entonces, si la estación de trabajo estaba bloqueada o en un protector de pantalla y registro, el último inicio de sesión sería el momento en que inicié sesión. ahora

    – Señor Aleph

    2 de agosto de 2010 a las 15:02

  • El sistema operativo no puede protocolizar todas las verificaciones de la contraseña de los usuarios. Se guarda solo cuando se verificó la contraseña de los usuarios. En algunos protocolos como Kerberos, el ticket de inicio de sesión puede caducar y debe renovarse antes de que caduque. Un problema más, que después del inicio de sesión, la cuenta se puede deshabilitar o eliminar. En el caso de que se muestre la hora de la última verificación de contraseña, el inicio de sesión de los usuarios más o menos verificados. Si necesita otro tiempo de inicio de sesión, puede usar notificaciones como ISensNetwork o implementar su propio administrador de credenciales msdn.microsoft.com/en-us/library/aa374792.aspx.

    – Oleg

    2 de agosto de 2010 a las 15:38

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad