C ++服务 - 模拟用户登录

时间:2015-10-06 21:52:32

标签: c++ winapi service login

我的实验室中的所有计算机上都运行了一项服务,并且需要能够同时登录所有计算机。

所有计算机都具有相同的用户名,因此这不是问题。 但我找不到以编程方式启动登录的方法。我读过LogonUser()及其对应的内容,但它们似乎没有我需要的功能。 有没有人对如何从c ++服务中做到这一点有任何建议?

1 个答案:

答案 0 :(得分:0)

唯一直接,受支持的方法是使用自动登录功能。主要缺点是需要重启机器。

以下是我使用的代码(请注意,我们的帐户域“scms”是硬编码的,因此您需要更改该位):

#define _WIN32_WINNT 0x0601

#include <windows.h>
#include <Ntsecapi.h>

#include <stdio.h>
#include <wchar.h>

void setAutologon(void);

void clearAutologon(void);

WCHAR username[128];
WCHAR password[128];

int main(int argc, char ** argv) 
{
    if (argc == 2 && _stricmp(argv[1], "-clear") == 0)
    {
        clearAutologon();
        return 0;
    }

    if (argc != 3)
    {
        printf("Syntax: autologon username password\n");
        return 1;
    }

    swprintf_s(username, _countof(username), L"%hs", argv[1]);
    swprintf_s(password, _countof(password), L"%hs", argv[2]);
    setAutologon();
    return 0;
}

void fail(char * errmsg, DWORD err) 
{
    // Oops.  It didn't work.
    printf(errmsg, err);
    if (err == 0) err = 1;
    exit(err);
}

void storePassword(BOOL store_password) 
{
    LSA_OBJECT_ATTRIBUTES loa;

    LSA_HANDLE lh;

    LSA_UNICODE_STRING name;
    static const wchar_t name_buffer[] = L"DefaultPassword";

    LSA_UNICODE_STRING data;

    DWORD dw;

    loa.Length = sizeof(loa);
    loa.RootDirectory = NULL;
    loa.ObjectName = NULL;
    loa.Attributes = 0;
    loa.SecurityDescriptor = NULL;
    loa.SecurityQualityOfService = NULL;

    if ((dw = LsaOpenPolicy(NULL, &loa, POLICY_CREATE_SECRET, &lh)) != 0) fail("Error %u opening LSA policy.", LsaNtStatusToWinError(dw));

    name.Buffer = (wchar_t *)name_buffer;
    name.MaximumLength = name.Length = sizeof(name_buffer) - sizeof(*name_buffer);

    if (!store_password) 
    {
        if ((dw = LsaStorePrivateData(lh, &name, NULL)) != 0) fail("Error %u clearing stored password.", LsaNtStatusToWinError(dw));
        return;
    }

    data.Buffer = password;
    data.MaximumLength = data.Length = wcslen(password) * sizeof(*password);

    if ((dw = LsaStorePrivateData(lh, &name, &data)) != 0) fail("Error %u storing password.", LsaNtStatusToWinError(dw));

    LsaClose(lh);

    return;

}

void setAutologon() 
{
    LONG i;
    HKEY h;

    i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_WOW64_64KEY | KEY_SET_VALUE, &h);
    if (i != ERROR_SUCCESS) fail("Unable to open Winlogon subkey (error %u).", i);

    i = RegSetValueEx(h, L"DefaultUserName", 0, REG_SZ, (CONST BYTE *)username, (wcslen(username)+1)*2);
    if (i != ERROR_SUCCESS) fail("Unable to set default logon user name (error %u).", i);

    storePassword(TRUE);

    i = RegSetValueEx(h, L"DefaultDomainName", 0, REG_SZ, (CONST BYTE *)L"scms", 10);
    if (i != ERROR_SUCCESS) fail("Unable to set default domain name (error %u).", i);

    i = RegSetValueEx(h, L"AutoAdminLogon", 0, REG_SZ, (CONST BYTE *)L"1", 2);
    if (i != ERROR_SUCCESS) fail("Unable to set automatic logon flag (error %u).", i);

    i = RegSetValueEx(h, L"ForceAutoLogon", 0, REG_SZ, (CONST BYTE *)L"1", 2);
    if (i != ERROR_SUCCESS) fail("Unable to set forced automatic logon flag (error %u).", i);
}

void clearAutologon(void) 
{
    LONG i;
    HKEY h;

    i = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0, KEY_WOW64_64KEY | KEY_SET_VALUE, &h);
    if (i != ERROR_SUCCESS) fail("Unable to open Winlogon subkey (error %u).", i);

    i = RegSetValueEx(h, L"DefaultUserName", 0, REG_SZ, "", 1);
    if (i != ERROR_SUCCESS) fail("Unable to set default logon user name (error %u).", i);

    storePassword(FALSE);

    // In case the automatic logon was set by the previous version of rpwd or by
    // some other means, we clear the registry setting for DefaultPassword as well.

    i = RegDeleteValue(h, L"DefaultPassword");
    if (i != ERROR_SUCCESS && i != ERROR_FILE_NOT_FOUND) fail("Unable to remove default logon password (error %u).", i);

    i = RegDeleteValue(h, L"ForceAutoLogon");
    if (i != ERROR_SUCCESS && i != ERROR_FILE_NOT_FOUND) fail("Unable to remove force logon flag (error %u).", i);

    i = RegSetValueEx(h, L"AutoAdminLogon", 0, REG_SZ, (CONST BYTE *)"0", 2);
    if (i != ERROR_SUCCESS) fail("Unable to clear automatic logon flag (error %u).", i);
}

我使用psexec(可从MS网站获得)在所有实验室计算机上运行代码,并使用psshutdown(同上)重新启动它们。一旦他们开始登录过程,您就可以清除自动登录。

毫无疑问,您可以轻松地将相同的方法应用于服务中。

如果您想避免重启,则需要implement a credential provider。我最后一次调查这个文档是令人沮丧的稀疏,但这可能有所改善。您可能还对pGINA感兴趣,{{3}}是一个开源凭证提供程序,可能很有用。 (或者,据我所知,可能已包含您想要的功能!)