获取当前用户的上次登录

Mr *_*eph 4 c windows authentication

我试图让当前用户上次登录.我可能是当前的会议,也可能是之前的会议.
我正在调用GetUserName()来获取当前用户名.我将其提供给NetUserGetInfo()以尝试获取上次登录时间.所有这些都失败,错误2221(未找到用户).当我尝试使用"管理员"时,它可以工作.即使我对用户名进行硬编码,也会返回2221.这就是我使用的内容:

nStatus = NetUserGetInfo(NULL, L"administrator", dwLevel, (LPBYTE *) & pBuf);
Run Code Online (Sandbox Code Playgroud)

如何获得当前用户的上次登录时间?

谢谢,代码随时欢迎.

这是我目前使用的完整代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

Ole*_*leg 7

你可以尝试使用其他级别为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".所有功能都是在没有本地登录的时候引入的.因此,您只能在域控制器上使用NetUserGetInfoNULL作为第一个参数.因此,如果您使用域帐户登录,则应该调用,或者更好地获取域控制器的名称,并使用此名称(以两个反斜杠开头)作为第一个参数.如果您使用本地工作站帐户登录,您的程序应该可以工作,但帐户似乎我必须是UNICODE字符串NetGetDCNameNetGetAnyDCNameDsGetDcNameNetUserGetInfo像L"管理员"而不是"管理员".顺便说一句,如果我在Windows 7 64位计算机上本地登录,您的程序可以毫无问题地工作.代码

nStatus = NetUserGetInfo(NULL, L"administrator", dwLevel, (LPBYTE *) & pBuf);
Run Code Online (Sandbox Code Playgroud)

也有效.

我再说一遍,在我看来,获得用户上次登录的最佳方式是使用LSA(本地安全机构)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);
    }
}
Run Code Online (Sandbox Code Playgroud)