我正在尝试在未加入域的计算机上验证用户的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 );
}
答案 0 :(得分:2)
这不起作用,因为您在不知道control.dundermifflin.com域的同一台机器上。
如果要确认用户名和密码,最简单的方法是对实际域中的计算机进行身份验证。它可以像“net use \ dc \ netlogon / u:username password”一样简单,但是你没有提到它是否必须通过SSPI完成。如果是,您需要在DC上找到要进行身份验证的服务。例如,您可以使用LDAP。
另一种可行的方法是告诉您的非域名计算机您尝试访问的域名。这可以通过使用ksetup工具完成。它允许您为您拥有的域配置KDC主机名。查看/ AddKdc选项。这将让Kerberos知道对于提供的域(也称为域),它应该转到为KDC请求提供的主机名。
我希望这会有所帮助。