Получить последний вход текущего пользователя - PullRequest
4 голосов
/ 30 июля 2010

Я пытаюсь получить последний вход текущего пользователя. Я мог бы быть этим текущим сеансом или это может быть один до этого.
Я звоню GetUserName (), чтобы получить текущее имя пользователя. Я передаю это в NetUserGetInfo (), чтобы попытаться получить время последнего входа в систему. Все это не с ошибкой 2221 (пользователь не найден). Когда я пытался с "администратором" это работает. Даже когда я жестко кодирую свое имя пользователя, оно возвращает 2221. Это то, что я использую:

nStatus = NetUserGetInfo(NULL, L"administrator", dwLevel, (LPBYTE *) & pBuf);

Как узнать время последнего входа текущего пользователя?

спасибо, код всегда приветствуется.

Вот полный код, который я сейчас использую:

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

1 Ответ

7 голосов
/ 30 июля 2010

Вы можете попробовать использовать другой уровень как 2, например 11.

Вы также можете попробовать LsaGetLogonSessionData (см. http://msdn.microsoft.com/en-us/library/aa378290.aspx). Структура SECURITY_LOGON_SESSION_DATA имеет много информации, которая может бытьполезно для вас. LUID (первый параметр LsaGetLogonSessionData), который можно получить из GetTokenInformation с помощью TokenStatistics и получить AuthenticationId поле структуры TOKEN_STATISTICS.

ОБНОВЛЕНО : Я более внимательно прочитал ваш код и теперь вижу вашу главную ошибку. Функция NetUserGetInfo очень старая. Она существует во времена, предшествующие Windows NT 3.1. Группа функций, которую Microsoft назвала теперь «Управление сетью», имеетимя «LAN Manager API». Все функции были введены в то время, когда не существует локального входа. Таким образом, вы можете использовать NetUserGetInfo с NULL в качестве первого параметра только на контроллере домена . Так что вв случае, если вы входите в систему с учетной записью домена, вы должны позвонить NetGetDCName, NetGetAnyDCName или лучше DsGetDcName, чтобы получить имя контроллера домена и использовать это имя (начинающееся с двух обратных косых черт) в качестве первого параметра NetUserGetInfo.Если вы войдете с местнымУчетная запись рабочей станции, ваша программа должна работать, но учетная запись мне кажется должна быть UNICODE string , как L "Администратор", а не "Администратор".Кстати, если я вхожу локально на моем Windows 7 64-битном компьютере, ваша программа работает без проблем.Код

nStatus = NetUserGetInfo(NULL, L"administrator", dwLevel, (LPBYTE *) & pBuf);

также работает.

Я повторяю, по моему мнению, лучший способ получить последний вход пользователя в систему - это использовать LSA (Local Security Authority) API, например LsaGetLogonSessionData.Как обещал я написал для вас пример кода, который показывает, как использовать 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...