不同域上的Windows用户凭据验证

时间:2009-08-10 22:41:38

标签: c++ windows credentials sspi

我正在尝试在未加入域的计算机上验证用户的Windows凭据。看起来这应该可以使用SSPI API,但我无法让它工作。

我包含了我一直在尝试的代码(为简洁起见省略了资源清理)。这些是重要的信息:

域控制器: control.dundermifflin.com
域名: DUNDERMIFFLIN
用户: jim_halpert
通过: beesly

(我正在测试一个气隙网络,因此与真正的dundermifflin.com没有任何DNS冲突。)

我得到的错误是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 个答案:

答案 0 :(得分:2)

这不起作用,因为您在不知道control.dundermifflin.com域的同一台机器上。

如果要确认用户名和密码,最简单的方法是对实际域中的计算机进行身份验证。它可以像“net use \ dc \ netlogon / u:username password”一样简单,但是你没有提到它是否必须通过SSPI完成。如果是,您需要在DC上找到要进行身份验证的服务。例如,您可以使用LDAP。

另一种可行的方法是告诉您的非域名计算机您尝试访问的域名。这可以通过使用ksetup工具完成。它允许您为您拥有的域配置KDC主机名。查看/ AddKdc选项。这将让Kerberos知道对于提供的域(也称为域),它应该转到为KDC请求提供的主机名。

我希望这会有所帮助。