Проверка учетных данных пользователя Windows в другом домене
Я пытаюсь проверить учетные данные пользователя Windows на компьютере, который не подключен к домену. Кажется, что это должно быть возможно сделать с использованием SSPI API, но я не смог заставить его работать.
Я включил код, который я пробовал (очистка ресурса для краткости опущена). Это важные части информации:
Контроллер домена: control.dundermifflin.com
Домен: ДУНДЕРМИФФЛИН
Пользователь: jim_halpert
Пасс: beesly
(Я тестирую в сети с воздушным зазором, поэтому нет никакого конфликта DNS с настоящим dundermifflin.com.)
Я получаю ошибку SEC_E_LOGON_DENIED. Я уверен, что имя пользователя и пароль верны, так как я могу войти в систему этого пользователя с помощью других приложений. Может кто-то указать мне верное направление?
#include <Windows.h>
#define SECURITY_WIN32
#include <Security.h>
#include <crtdbg.h>
#pragma comment( lib, "Secur32.lib" )
int main()
{
SEC_CHAR* principal = "HOST/control.dundermifflin.com";
SEC_CHAR* spn = NULL;
SEC_CHAR* domain = "DUNDERMIFFLIN";
SEC_CHAR* user = "jim_halpert";
SEC_CHAR* pass = "beesly";
/////////////////////////////////////////////
// Fill out the authentication information //
/////////////////////////////////////////////
SEC_WINNT_AUTH_IDENTITY auth;
auth.Domain = reinterpret_cast<unsigned char*>( domain );
auth.DomainLength = strlen( domain );
auth.User = reinterpret_cast<unsigned char*>( user );
auth.UserLength = strlen( user );
auth.Password = reinterpret_cast<unsigned char*>( pass );
auth.PasswordLength = strlen( pass );
auth.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
////////////////////////////////////////////
// Allocate the client and server buffers //
////////////////////////////////////////////
char clientOutBufferData[8192];
char serverOutBufferData[8192];
SecBuffer clientOutBuffer;
SecBufferDesc clientOutBufferDesc;
SecBuffer serverOutBuffer;
SecBufferDesc serverOutBufferDesc;
///////////////////////////////////////////
// Get the client and server credentials //
///////////////////////////////////////////
CredHandle clientCredentials;
CredHandle serverCredentials;
SECURITY_STATUS status;
status = ::AcquireCredentialsHandle( principal,
"Negotiate",
SECPKG_CRED_OUTBOUND,
NULL,
&auth,
NULL,
NULL,
&clientCredentials,
NULL );
_ASSERT( status == SEC_E_OK );
status = ::AcquireCredentialsHandle( principal,
"Negotiate",
SECPKG_CRED_INBOUND,
NULL,
NULL,
NULL,
NULL,
&serverCredentials,
NULL );
_ASSERT( status == SEC_E_OK );
//////////////////////////////////////
// Initialize the security contexts //
//////////////////////////////////////
CtxtHandle clientContext = {};
unsigned long clientContextAttr = 0;
CtxtHandle serverContext = {};
unsigned long serverContextAttr = 0;
/////////////////////////////
// Clear the client buffer //
/////////////////////////////
clientOutBuffer.BufferType = SECBUFFER_TOKEN;
clientOutBuffer.cbBuffer = sizeof clientOutBufferData;
clientOutBuffer.pvBuffer = clientOutBufferData;
clientOutBufferDesc.cBuffers = 1;
clientOutBufferDesc.pBuffers = &clientOutBuffer;
clientOutBufferDesc.ulVersion = SECBUFFER_VERSION;
///////////////////////////////////
// Initialize the client context //
///////////////////////////////////
status = InitializeSecurityContext( &clientCredentials,
NULL,
spn,
0,
0,
SECURITY_NATIVE_DREP,
NULL,
0,
&clientContext,
&clientOutBufferDesc,
&clientContextAttr,
NULL );
_ASSERT( status == SEC_I_CONTINUE_NEEDED );
/////////////////////////////
// Clear the server buffer //
/////////////////////////////
serverOutBuffer.BufferType = SECBUFFER_TOKEN;
serverOutBuffer.cbBuffer = sizeof serverOutBufferData;
serverOutBuffer.pvBuffer = serverOutBufferData;
serverOutBufferDesc.cBuffers = 1;
serverOutBufferDesc.pBuffers = &serverOutBuffer;
serverOutBufferDesc.ulVersion = SECBUFFER_VERSION;
//////////////////////////////////////////////////////
// Accept the client security context on the server //
//////////////////////////////////////////////////////
status = AcceptSecurityContext( &serverCredentials,
NULL,
&clientOutBufferDesc,
0,
SECURITY_NATIVE_DREP,
&serverContext,
&serverOutBufferDesc,
&serverContextAttr,
NULL );
_ASSERT( status == SEC_I_CONTINUE_NEEDED );
/////////////////////////////
// Clear the client buffer //
/////////////////////////////
clientOutBuffer.BufferType = SECBUFFER_TOKEN;
clientOutBuffer.cbBuffer = sizeof clientOutBufferData;
clientOutBuffer.pvBuffer = clientOutBufferData;
clientOutBufferDesc.cBuffers = 1;
clientOutBufferDesc.pBuffers = &clientOutBuffer;
clientOutBufferDesc.ulVersion = SECBUFFER_VERSION;
///////////////////////////////////////
// Give the client the server buffer //
///////////////////////////////////////
status = InitializeSecurityContext( &clientCredentials,
&clientContext,
spn,
0,
0,
SECURITY_NATIVE_DREP,
&serverOutBufferDesc,
0,
&clientContext,
&clientOutBufferDesc,
&clientContextAttr,
NULL );
_ASSERT( status == SEC_E_OK );
//////////////////////////////////////////////////////
// Accept the client security context on the server //
//////////////////////////////////////////////////////
status = AcceptSecurityContext( &serverCredentials,
&serverContext,
&clientOutBufferDesc,
0,
SECURITY_NATIVE_DREP,
&serverContext,
&serverOutBufferDesc,
&serverContextAttr,
NULL );
_ASSERT( status == SEC_E_LOGON_DENIED );
}
1 ответ
Это не сработает, так как вы находитесь на той же машине, которая не знает о домене control.dundermifflin.com.
Если вы хотите подтвердить имя пользователя и пароль, самый простой способ - пройти аутентификацию на компьютере в реальном домене. Это может быть так же просто, как "net use \dc\netlogon /u: пароль пользователя", но вы не упомянули, нужно ли это делать через SSPI. Если это так, вам нужно найти сервис на DC для аутентификации. Вы можете использовать LDAP например.
Другой способ, который может работать, - сообщить своей машине, не входящей в домен, о домене, который вы пытаетесь получить. Это можно сделать с помощью инструмента ksetup. Это позволит вам настроить имя хоста KDC для вашего домена. Посмотрите на параметр /AddKdc. Это даст Kerberos знать, что для предоставленной области (он же домена) он должен перейти к имени хоста, указанному для запросов KDC.
Надеюсь, это поможет.