Hi,
I'm trying to validate a user's windows credentials on a computer that's not joined to the domain. It seems like this should be possible to do using the SSPI API, but I haven't been able to get it to work.
I included the code that I've been trying (resource cleanup omitted for brevity). These are the important pieces of information:
Domain Controller: control.dundermifflin.com
Domain: DUNDERMIFFLIN
User: jim_halpert
Pass: beesly
(I'm testing on an air-gapped network, so there isn't any DNS conflict with the real dundermifflin.com.)
The error I get is SEC_E_LOGON_DENIED. I'm positive that the username and password are correct, since I can logon with that user with other applications. Can anyone point me in the right direction?
#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 );
}