2015-10-06 63 views
0

我已經在我的實驗室中的所有計算機上運行了服務,並且需要能夠同時登錄到所有計算機。C++服務 - 模擬用戶登錄

所有的計算機都有相同的用戶名,所以這不是問題。 但我無法找到以編程方式啓動登錄的方法。我已閱讀有關LogonUser()及其同行,但他們似乎沒有我需要的功能。 有沒有人有任何建議,我怎麼可以從c + +服務做到這一點?

+0

所以,你的意思是,在計算機用鍵盤/鼠標/屏幕登錄之前坐着的人有同樣的效果嗎? – deviantfan

+0

@deviantfan是的,沒錯 – Phixle

+1

爲什麼你需要這個?服務本身不能可編程地登錄到本地工作站上的交互式桌面。 WinLogon屏幕(用戶登錄的內容)在安全桌面上運行,無法跨會話訪問(出於明顯的安全原因)。服務可以在需要模擬該用戶訪問安全對象(文件,註冊表,管道等)時登錄到用戶帳戶。 –

回答

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(可從Microsoft網站)在所有實驗室機器上運行代碼,然後psshutdown(同上)重新啓動它們。一旦他們開始登錄過程,您可以清除自動登錄。

毫無疑問,您可以輕鬆地將相同的方法適用於服務。如果你想避免重啓,你需要implement a credential provider。我最後一次看到這個文檔令人痛心地稀少,但這可能有所改善。您可能也對pGINA感興趣,這是一個開源的證書提供者,可能作爲一個例子很有用。 (或者,據我所知,可能已經包含了你想要的功能!)

+0

非常感謝,看起來這是我會堅持的方法,直到我可以深入到這些參考:) – Phixle