Проверка учетных данных пользователя Windows в другом домене - PullRequest
2 голосов
/ 11 августа 2009

Я пытаюсь проверить учетные данные пользователя Windows на компьютере, который не присоединен к домену. Похоже, что это возможно сделать с помощью SSPI API, но я не смог заставить его работать.

Я включил код, который я пробовал (очистка ресурса для краткости опущена). Вот важные части информации:

Контроллер домена: control.dundermifflin.com
Домен: DUNDERMIFFLIN
Пользователь: jim_halpert
Pass: 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 Ответ

2 голосов
/ 11 августа 2009

Это не сработает, так как вы находитесь на той же машине, которая не знает о домене control.dundermifflin.com.

Если вы хотите подтвердить имя пользователя и пароль, самый простой способ - пройти аутентификацию на компьютере в реальном домене. Это может быть так же просто, как «net use \ dc \ netlogon / u: пароль пользователя», но вы не упомянули, нужно ли это делать через SSPI. Если это так, вам нужно найти сервис на DC для аутентификации. Вы можете использовать LDAP, например.

Еще один способ, с помощью которого можно работать, - сообщить своей не доменной машине о домене, который вы пытаетесь получить. Это можно сделать с помощью инструмента ksetup. Это позволит вам настроить имя хоста KDC для вашего домена. Посмотрите на параметр / AddKdc. Это даст Kerberos знать, что для предоставленной области (он же домена) он должен перейти к имени хоста, указанному для запросов KDC.

Надеюсь, это поможет.

...