|
|
#include <windows.h>
#define SECURITY_WIN32
#include <sspi.h>
#include <issperr.h>
#include <security.h>
#define SSP_SPM_NT_DLL "security.dll"
#define SSP_SPM_WIN95_DLL "secur32.dll"
#define MAX_OUTPUT_BUFFER 4096
SEC_WINNT_AUTH_IDENTITY SecId; HINSTANCE hSecLib; PSecurityFunctionTable pFuncTbl = NULL;
// Preliminary func calls.
VOID InitializeSecurityInterface(BOOL fDirect); BOOL HaveDigest();
// 3 Main SSPI calls.
// AcquireCredentialsHandle
SECURITY_STATUS ACH(PCredHandle phCred);
// InitializeSecurityContext
SECURITY_STATUS ISC(PCredHandle phCred, PCtxtHandle phCtxt, PCtxtHandle phNewCtxt, DWORD fContextReq, LPSTR szChallenge, LPSTR szResponse, LPSTR szUser, LPSTR szPass);
// FreeCredentialsHandle
SECURITY_STATUS FCH(PCredHandle phCred);
//--------------------------------------
// main
//--------------------------------------
INT main() { DWORD dwReturn = 0; SECURITY_STATUS ssResult;
// Get (global) dispatch table.
InitializeSecurityInterface(FALSE); // Check to see if we have digest.
if (!HaveDigest()) { dwReturn = 1; goto exit; } // Credential handle and pointer.
CredHandle hCred; CtxtHandle hCtxt; // **** Call AcquireCredentialsHandle with no credential ***
ACH(&hCred);
// Challenge and response buffers. As usual, we dump into an
// output buffer allocated on the stack.
LPSTR szChallenge; CHAR szResponse[MAX_OUTPUT_BUFFER];
// First call to ISC is with zero input, expecting a 0 DWORD output buffer, as
// we expect with POP clients
szChallenge = NULL;
// Make first call to ISC with null input - expect DWORD 0 output.
ssResult = ISC( &hCred, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt, // Output context.
0, // flags auth from cache, but not meaningful here.
szChallenge, // NULL Server challenge header.
szResponse, // Response buffer.
NULL, // No user needed.
NULL); // No pass needed.
// Expect 0 DWORD output and SEC_I_CONTINUE_NEEDED.
if (ssResult != SEC_I_CONTINUE_NEEDED) { DebugBreak(); }
// Free cred handle.
FCH(&hCred); // Re-acquire cred handle.
ACH(&hCred);
// Now setup challenge from server for realm "Microsoft Passport" which will use the
// credentials user="[email protected]", pass = "jpoley"
szChallenge = "realm=\"Microsoft Passport\", algorithm = \"MD5-sess\", qop=\"auth\", nonce=\"0123456789abcdef\""; // Authenticate using user = "[email protected]", pass = "jpoley"
ssResult = ISC( &hCred, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt, // Output context.
ISC_REQ_USE_SUPPLIED_CREDS, // Use the credentials supplied.
szChallenge, // Server challenge header.
szResponse, // Response buffer,
"[email protected]", // user
"jpoley" // pass
);
// We have just successfully authenticated for [email protected]. In doing so,
// we have created a credential for [email protected] in the digest cred cache.
if (ssResult != SEC_E_OK) { DebugBreak(); } // Free cred handle.
FCH(&hCred); // Re-acquire cred handle.
ACH(&hCred);
// Quick confirmation that we have a credential for "[email protected],
// we'll attempt to auth to a "Microsoft Passport" challenge without supplying
// any creds - this should pull jpoley creds from
// the cache and authomatically generate an auth header.
ssResult = ISC( &hCred, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt, // Output context.
0, // auth from cache
szChallenge, // Server challenge header.
szResponse, // Response buffer,
NULL, // Not passing user
NULL // Not passing in pass
); // Should have authed successfully.
if (ssResult != SEC_E_OK) { DebugBreak(); } // Free cred handle.
FCH(&hCred); // Re-acquire cred handle.
ACH(&hCred);
// Now setup a challange from server for realm "Microsoft Passport (we'll use
// the previouse one but this time we wish to authyenticate on behalf of a new
// user "[email protected]" and we DON'T HAVE A PASSWORD.
szChallenge = "realm=\"Microsoft Passport\", algorithm = \"MD5-sess\", qop=\"auth\", nonce=\"0123456789abcdef\""; // Authenticate
ssResult = ISC( &hCred, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt, // Output context.
0, // Auth from cache.
szChallenge, // Server challenge header.
szResponse, // Response buffer,
"[email protected]", // user
NULL // No password!
); // We didn't have any credentials, so we better not have succeeded.
if (ssResult != SEC_E_NO_CREDENTIALS) { DebugBreak(); } // Free cred handle.
FCH(&hCred); // Re-acquire cred handle.
ACH(&hCred);
// Prompt for credentials for [email protected]. Since the challenge contains the
// realm "Microsoft Passport", the credential created here will overwrite the
// credential created for [email protected], and generate the authorization string.
ssResult = ISC( &hCred, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt, // Output context.
ISC_REQ_PROMPT_FOR_CREDS, // prompt for creds for [email protected]
szChallenge, // Server challenge header.
szResponse, // Response buffer.
"[email protected]", // user to prompt for.
NULL // Again, no password, we're prompting.
);
// We should have succeeded in collecting creds for [email protected] and
// generating the authorization string.
if (ssResult != SEC_E_OK) { DebugBreak(); }
// Free cred handle.
FCH(&hCred); // Re-acquire cred handle.
ACH(&hCred); // Quick confirmation that we have a credential for "[email protected]"
// we'll attempt to auth to a "Microsoft Passport" challenge without supplying
// any creds - this should pull alex creds from
// the cache and authomatically generate an auth header.
ssResult = ISC( &hCred, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt, // Output context.
0, // auth from cache
szChallenge, // Server challenge header.
szResponse, // Response buffer,
NULL, // Not passing user
NULL // Not passing in pass
); // Should have authed successfully.
if (ssResult != SEC_E_OK) { DebugBreak(); } // Free cred handle.
FCH(&hCred); if (hSecLib) FreeLibrary(hSecLib);
exit: return dwReturn; }
// Main SSPI calls.
//--------------------------------------
// ACH
//--------------------------------------
SECURITY_STATUS ACH(PCredHandle phCred) { SECURITY_STATUS ssResult; // ***** SSPI CALL *****
ssResult = (*(pFuncTbl->AcquireCredentialsHandleA)) (NULL, // pszPrinciple NULL
"Digest", // pszPackageName (Package name)
SECPKG_CRED_OUTBOUND, // dwCredentialUse (client call)
NULL, // pvLogonID (not used)
NULL, // pAuthData (not used)
NULL, // pGetKeyFn (not used)
0, // pvGetKeyArgument (not used)
phCred, // phCredential (credential returned)
NULL); // PTimeStamp (not used)
return ssResult; }
//--------------------------------------
// ISC
//--------------------------------------
SECURITY_STATUS ISC(PCredHandle phCred, PCtxtHandle phCtxt, PCtxtHandle phNewCtxt, DWORD fContextReq, LPSTR szChallenge, LPSTR szResponse, LPSTR szUser, LPSTR szPass)
{
// If the client is not passing in user/pass
// (ie, normal operation) then the count of
// buffers passed in is always 1.
#define SEC_BUFFER_NUM_NORMAL_BUFFERS 1
// These are the indicese specifically expected
// by the digest package
#define SEC_BUFFER_CHALLENGE_INDEX 0
#define SEC_BUFFER_USERNAME_INDEX 1
#define SEC_BUFFER_PASSWORD_INDEX 2
#define SEC_BUFFER_NUM_EXTENDED_BUFFERS 3
SECURITY_STATUS ssResult; // Input buffers and descriptor.
SecBuffer sbIn[SEC_BUFFER_NUM_EXTENDED_BUFFERS]; SecBufferDesc sbdIn; PSecBufferDesc psbdIn;
// Calling with challenge; expect SEC_E_OK or SEC_E_NO_CREDENTIALS
if (szChallenge) { // Setup the challenge input buffer always (0th buffer)
sbIn[SEC_BUFFER_CHALLENGE_INDEX].pvBuffer = szChallenge; sbIn[SEC_BUFFER_CHALLENGE_INDEX].cbBuffer = strlen(szChallenge); sbIn[SEC_BUFFER_CHALLENGE_INDEX].BufferType = SECBUFFER_TOKEN;
// If we have a user, setup the user buffer (1st buffer)
sbIn[SEC_BUFFER_USERNAME_INDEX].pvBuffer = szUser ? szUser : NULL; sbIn[SEC_BUFFER_USERNAME_INDEX].cbBuffer = szUser ? strlen(szUser) : NULL; sbIn[SEC_BUFFER_USERNAME_INDEX].BufferType = SECBUFFER_TOKEN; // If we have a password, setup the password buffer (2nd buffer for
// a total of 3 buffers passed in (challenge + user + pass)
sbIn[SEC_BUFFER_PASSWORD_INDEX].pvBuffer = szPass ? szPass : NULL; sbIn[SEC_BUFFER_PASSWORD_INDEX].cbBuffer = szPass ? strlen(szPass) : NULL; sbIn[SEC_BUFFER_PASSWORD_INDEX].BufferType = SECBUFFER_TOKEN; sbdIn.pBuffers = sbIn; // If either or both user and pass passed in, set num input buffers to 3
// (SEC_BUFFER_NUM_EXTENDED_BUFFERS)
if (szUser || szPass) sbdIn.cBuffers = SEC_BUFFER_NUM_EXTENDED_BUFFERS;
// else we're just passing in the one challenge buffer (0th buffer as usual)
else sbdIn.cBuffers = SEC_BUFFER_NUM_NORMAL_BUFFERS;
psbdIn = &sbdIn;
} else { // Calling withOUT challenge; expect SEC_I_CONTINUE_NEEDED;
psbdIn = NULL; }
// Output buffer and descriptor.
SecBuffer sbOut[1]; SecBufferDesc sbdOut; sbOut[0].pvBuffer = szResponse; sbOut[0].cbBuffer = MAX_OUTPUT_BUFFER; sbOut[0].BufferType = SECBUFFER_TOKEN; sbdOut.pBuffers = sbOut; sbdOut.cBuffers = 1;
// ***** SSPI CALL *****
ssResult = (*(pFuncTbl->InitializeSecurityContextA)) (phCred, // phCredential (from AcquireCredentialsHandle)
phCtxt, // phContext (NULL on first call, phNewCtxt on subsequent calls).
NULL, // pszTargetName (not used)
fContextReq, // fContextReq (auth from cache, prompt or auth using supplied creds)
0, // Reserved1 (not used)
0, // TargetDataRep (not used)
psbdIn, // PSecBufDesc (input buffer descriptor)
0, // Reserved2 (not used)
phNewCtxt, // phNewContext (should be passed back as phCtxt on subsequent calls)
&sbdOut, // pOutput (output buffer descriptor)
NULL, // pfContextAttr (pfContextAttr, not used)
NULL); // ptsExpiry (not used)
return ssResult; }
//--------------------------------------
// FCH
//--------------------------------------
SECURITY_STATUS FCH(PCredHandle phCred) { SECURITY_STATUS ssResult; // ***** SSPI CALL *****
ssResult = (*(pFuncTbl->FreeCredentialsHandle))(phCred); return ssResult; }
// Utility calls.
//--------------------------------------
// InitializeSecurityInterface
//--------------------------------------
VOID InitializeSecurityInterface(BOOL fDirect) { INIT_SECURITY_INTERFACE addrProcISI = NULL; OSVERSIONINFO VerInfo; CHAR szDLL[MAX_PATH];
if (!fDirect) { VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
GetVersionEx (&VerInfo); if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { lstrcpy (szDLL, SSP_SPM_NT_DLL); } else if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { lstrcpy (szDLL, SSP_SPM_WIN95_DLL); } } else { strcpy(szDLL, "d:\\nt\\private\\inet\\digest\\objd\\i386\\digest.dll"); } hSecLib = LoadLibrary (szDLL); addrProcISI = (INIT_SECURITY_INTERFACE) GetProcAddress( hSecLib, SECURITY_ENTRYPOINT_ANSI); pFuncTbl = (*addrProcISI)(); }
//--------------------------------------
// HaveDigest
//--------------------------------------
BOOL HaveDigest() { SECURITY_STATUS ssResult; DWORD cPackages; PSecPkgInfoA pSecPkgInfo; BOOL fHaveDigest;
// ***** SSPI call *****
ssResult = (*(pFuncTbl->EnumerateSecurityPackagesA))(&cPackages, &pSecPkgInfo);
// Check if we have digest.
fHaveDigest = FALSE; if (ssResult == SEC_E_OK) { for (DWORD i = 0; i < cPackages; i++) { if (strcmp(pSecPkgInfo[i].Name, "Digest") == 0) { fHaveDigest = TRUE; break; } } } return fHaveDigest; }
|