|
|
#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"
struct DIGEST_PKG_DATA { LPSTR szAppCtx; LPSTR szUserCtx; };
#define SIG_DIGEST 'HTUA'
DIGEST_PKG_DATA PkgData; SEC_WINNT_AUTH_IDENTITY_EXA SecIdExA;
PSecurityFunctionTable g_pFuncTbl = NULL;
HINSTANCE hSecLib;
//----------------------------------------------------------------------------
// 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, "digest.dll"); } hSecLib = LoadLibrary (szDLL); addrProcISI = (INIT_SECURITY_INTERFACE) GetProcAddress( hSecLib, SECURITY_ENTRYPOINT_ANSI); g_pFuncTbl = (*addrProcISI)(); }
//----------------------------------------------------------------------------
// HaveDigest
//----------------------------------------------------------------------------
BOOL HaveDigest() { SECURITY_STATUS ssResult; DWORD cPackages; PSecPkgInfoA pSecPkgInfo; BOOL fHaveDigest;
// ***** SSPI call *****
ssResult = (*(g_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; }
//----------------------------------------------------------------------------
// LogonToDigestPkg
//----------------------------------------------------------------------------
SECURITY_STATUS LogonToDigestPkg(LPSTR szAppCtx, LPSTR szUserCtx, PCredHandle phCred) { SECURITY_STATUS ssResult; // Logon with szAppCtx = szUserCtx = NULL.
PkgData.szAppCtx = PkgData.szUserCtx = NULL; memset(&SecIdExA, 0, sizeof(SEC_WINNT_AUTH_IDENTITY_EXA));
PkgData.szAppCtx = szAppCtx; PkgData.szUserCtx = szUserCtx;
SecIdExA.Version = sizeof(SEC_WINNT_AUTH_IDENTITY_EXA); SecIdExA.User = (unsigned char*) &PkgData; SecIdExA.UserLength = sizeof(DIGEST_PKG_DATA);
// ***** SSPI CALL *****
ssResult = (*(g_pFuncTbl->AcquireCredentialsHandleA)) (NULL, // pszPrinciple NULL
"Digest", // pszPackageName (Package name)
SECPKG_CRED_OUTBOUND, // dwCredentialUse (Credentials aren't pulled from OS)
NULL, // pvLogonID (not used)
&SecIdExA, // pAuthData ptr to g_PkgData
NULL, // pGetKeyFn (not used)
0, // pvGetKeyArgument (not used)
phCred, // phCredential (credential returned)
NULL); // PTimeStamp (not used)
return ssResult; }
//----------------------------------------------------------------------------
// LogoffOfDigestPkg
//----------------------------------------------------------------------------
SECURITY_STATUS LogoffOfDigestPkg(PCredHandle phCred) { SECURITY_STATUS ssResult; // ***** SSPI CALL *****
ssResult = (*(g_pFuncTbl->FreeCredentialsHandle))(phCred); return ssResult; }
//----------------------------------------------------------------------------
// Authenticate
//----------------------------------------------------------------------------
SECURITY_STATUS DoAuthenticate(PCredHandle phCred, PCtxtHandle phCtxt, PCtxtHandle phNewCtxt, DWORD fContextReq, LPSTR szHeader, LPSTR szRealm, LPSTR szHost, LPSTR szUrl, LPSTR szMethod, LPSTR szUser, LPSTR szPass, LPSTR szNonce, HWND hWnd, LPSTR szResponse) { SECURITY_STATUS ssResult; // Input buffers and descriptor.
SecBuffer sbIn[10]; SecBufferDesc sbdIn; sbdIn.pBuffers = sbIn; sbdIn.cBuffers = 10; sbIn[0].pvBuffer = szHeader; // Challenge header
sbIn[1].pvBuffer = szRealm; // realm if preauth
sbIn[2].pvBuffer = szHost; // host
sbIn[3].pvBuffer = szUrl; // url
sbIn[4].pvBuffer = szMethod; // http method
sbIn[5].pvBuffer = szUser; // username (optional)
sbIn[6].pvBuffer = szPass; // password (optional, not used currently)
sbIn[7].pvBuffer = szNonce; // nonce
sbIn[8].pvBuffer = NULL; // nonce count not passed in.
sbIn[9].pvBuffer = &hWnd; // window handle.
// Output buffer and descriptor.
SecBuffer sbOut[1]; SecBufferDesc sbdOut; sbdOut.pBuffers = sbOut; sbdOut.cBuffers = 1; // Set output buffer.
sbOut[0].pvBuffer = szResponse;
// ***** SSPI CALL *****
ssResult = (*(g_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)
&sbdIn, // 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; }
VOID PrimeCredCache(CredHandle CredHandle, LPSTR szRealm, LPSTR szUser, LPSTR szPass) { DWORD ssResult; CtxtHandle hCtxt;
SecBufferDesc sbdIn; SecBuffer sbIn[3]; hCtxt.dwLower = CredHandle.dwLower; hCtxt.dwUpper = CredHandle.dwUpper;
sbIn[0].pvBuffer = szRealm; sbIn[0].cbBuffer = strlen(szRealm); sbIn[1].pvBuffer = szUser; sbIn[1].cbBuffer = strlen(szUser); sbIn[2].pvBuffer = szPass; sbIn[2].cbBuffer = strlen(szPass);
sbdIn.cBuffers = 3; sbdIn.pBuffers = sbIn;
ssResult = (*(g_pFuncTbl->ApplyControlToken))(&hCtxt, &sbdIn);
}
//----------------------------------------------------------------------------
// main
//----------------------------------------------------------------------------
#ifdef UNIX
#define main prog_main
int main(int argc, char **argv);
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pszCmdLine, int nCmdShow) { extern int __argc; extern char **__argv; return main(__argc, __argv); } int main(int argc, char **argv) #else
INT main() #endif
{
#define IDENTITY_1 "Alice"
#define IDENTITY_2 "Bob"
DWORD dwReturn = 0; SECURITY_STATUS ssResult;
// Get (global) dispatch table.
InitializeSecurityInterface(TRUE); // Check to see if we have digest.
if (!HaveDigest()) { dwReturn = 1; goto exit; } // Credential handle and pointer.
CredHandle hCred1, hCred2, hCred3; CtxtHandle hCtxt1, hCtxt2, hCtxt3;
// Three apps logon using the same keys (appctx, userctx, both NULL);
// These sessions will be used for authentication.
LogonToDigestPkg(NULL, IDENTITY_1, &hCred1); LogonToDigestPkg(NULL, IDENTITY_1, &hCred2); LogonToDigestPkg(NULL, IDENTITY_1, &hCred3);
// Three more apps also logon using the same keys.
// we will prime the password cache with credentials for these apps
// and expect to be able to share the credentials via the auth dialog.
CredHandle hCred4, hCred5, hCred6;
LogonToDigestPkg(NULL, IDENTITY_1, &hCred4); LogonToDigestPkg(NULL, IDENTITY_1, &hCred5); LogonToDigestPkg(NULL, IDENTITY_1, &hCred6); PrimeCredCache(hCred4, "[email protected]", "Wilma", "password"); PrimeCredCache(hCred5, "[email protected]", "Betty", "passwordxxxx"); PrimeCredCache(hCred6, "[email protected]", "Pebbles", "passwordxxxxx");
// Finally, three more apps also logon using a different logon key (identity)
// we will prime the password cache with credentials for these apps
// Because of the different logon key we should never see these creds.
CredHandle hCred7, hCred8, hCred9; LogonToDigestPkg(NULL, IDENTITY_2, &hCred7); LogonToDigestPkg(NULL, IDENTITY_2, &hCred8); LogonToDigestPkg(NULL, IDENTITY_2, &hCred9); PrimeCredCache(hCred7, "[email protected]", "Fred", "password"); PrimeCredCache(hCred8, "[email protected]", "Barney", "passwordxxxx"); PrimeCredCache(hCred9, "[email protected]", "Bam Bam", "passwordxxxxxxxx"); //-------------------------------------------------------------------------------------------------------------
// App 1 makes a request from a server, does not have credentials and must prompt
// before finally succeeding.
// Challenge from server.
LPSTR szChallenge; // szChallenge = "realm=\"[email protected]\", ms-message = \"foo\", ms-message-lang = \"bar\", ms-trustmark = \"baz\", stale = FALSE, qop=\"auth,auth-int\", nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
szChallenge = "realm=\"[email protected]\", stale = FALSE, qop=\"auth,auth-int\", nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
// Package will dump response into this buffer.
CHAR szResponse[4096]; // First try at authenticating.
ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt1, // Output context.
0, // auth from cache.
szChallenge, // Server challenge header.
NULL, // no realm since not preauth.
"www.foo.com", // Host.
"/bar/baz/boz/bif.html", // Url.
"GET", // Method.
NULL, // no Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
// Expect to not have credentials the first time - prompt.
if (ssResult == SEC_E_NO_CREDENTIALS) { ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
&hCtxt1, // Ctxt from previous call
&hCtxt1, // Output context (same as from previous).
ISC_REQ_PROMPT_FOR_CREDS, // prompt
szChallenge, // Server challenge
NULL, // No realm
"www.foo.com", // Host
"/bar/baz/boz/bif.html", // Url
"GET", // Method
NULL, // no username
NULL, // no password
NULL, // no nonce
GetDesktopWindow(), // desktop window
szResponse); // Response buffer
}
//-------------------------------------------------------------------------------------------------------------
// App 2 makes a request to the same server and gets challenged for the same realm. First auth attempt will
// not be successful since this is the first challenge this session, so it will have to prompt for credentials.
// When prompting, because it shares credentials with App1, the drop-down will contain App1's credentials.
ssResult = DoAuthenticate( &hCred2, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt2, // Output context.
0, // auth from cache.
szChallenge, // Server challenge header.
NULL, // no realm since not preauth.
"www.foo.com", // Host.
"/bar/baz/boz/bif.html", // Url.
"GET", // Method.
NULL, // no Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
// Generate the confirmation dialog and auth. User can choose App1's creds or enter new credentials.
if (ssResult == SEC_E_NO_CREDENTIALS) { ssResult = DoAuthenticate( &hCred2, // Cred from logging on.
&hCtxt2, // Ctxt from previous call
&hCtxt2, // Output context (same as from previous).
ISC_REQ_PROMPT_FOR_CREDS, // prompt
szChallenge, // Server challenge
NULL , // No realm
"www.foo.com", // Host
"/bar/baz/boz/bif.html", // Url
"GET", // Method
NULL, // no username
NULL, // no password
NULL, // no nonce
GetDesktopWindow(), // desktop window
szResponse); // Response buffer
}
//-------------------------------------------------------------------------------------------------------------
// App 3 makes a request to the same server and gets challenged for the same realm. First auth attempt will
// not be successful since this is the first challenge this session, so it will have to prompt for credentials.
// When prompting, because it shares credentials with App1 and App2 the drop-down could show two choices if
// App2 entered new credentials (or just one if App2 chose to use App1's credential).
ssResult = DoAuthenticate( &hCred3, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt3, // Output context.
0, // auth from cache.
szChallenge, // Server challenge header.
NULL, // no realm since not preauth.
"www.foo.com", // Host.
"/bar/baz/boz/bif.html", // Url.
"GET", // Method.
NULL, // no Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
// Generate the confirmation dialog and auth. User can choose App1's creds or enter new credentials.
if (ssResult == SEC_E_NO_CREDENTIALS) { ssResult = DoAuthenticate( &hCred3, // Cred from logging on.
&hCtxt3, // Ctxt from previous call
&hCtxt3, // Output context (same as from previous).
ISC_REQ_PROMPT_FOR_CREDS, // prompt
szChallenge, // Server challenge
NULL , // No realm
"www.foo.com", // Host
"/bar/baz/boz/bif.html", // Url
"GET", // Method
NULL, // no username
NULL, // no password
NULL, // no nonce
GetDesktopWindow(), // desktop window
szResponse); // Response buffer
}
//-------------------------------------------------------------------------------------------------------------
// App2 preauthenticates to "[email protected]" for a new url. Note that the credential that will be used
// for preauthentication is whatever App2 chose or entered previously. The same would be true for
// App1 or App3.
ssResult = DoAuthenticate( &hCred2, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt2, // Output context.
0, // auth (preauth)
NULL, // No challenge header
"[email protected]", // Realm for preauth.
"www.foo.com", // Host.
"/bar/baz.gif", // Url
"GET", // Method.
NULL, // no sername
NULL, // no password.
NULL, // no nonce
NULL, // no hwnd
szResponse); // Response buffer.
//-------------------------------------------------------------------------------------------------------------
// App3 made another request to the same server but did not preauthenticate. It got challenged for the
// same realm and can authenticate without prompting because it has credentials for that realm.
szChallenge = "realm=\"[email protected]\", stale = TRUE, qop=\"auth,auth-int\", nonce=\"abcdefge8b11d0f600bfb0c093\", opaque=\"efghijklmnopc403ebaf9f0171e9517f40e41\"";
ssResult = DoAuthenticate( &hCred3, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt3, // Output context.
0, // auth
szChallenge, // Challenge from server.
NULL, // no realm
"www.foo.com", // Host.
"/bar/baz.htm", // Url
"GET", // Method.
NULL, // no username
NULL, // no password
NULL, // no nonce
NULL, // no hwnd
szResponse); // Response buffer.
//-------------------------------------------------------------------------------------------------------------
// App1 authenticates for an md5-sess challenge.
szChallenge = "realm=\"[email protected]\", algorithm=\"md5-sess\", stale = TRUE, qop=\"auth,auth-int\", nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt1, // Output context.
0, // auth from cache.
szChallenge, // Server challenge header.
NULL, // no realm since not preauth.
"www.foo.com", // Host.
"/bar/baz/boz/bif.html", // Url.
"GET", // Method.
NULL, // no Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
//-------------------------------------------------------------------------------------------------------------
// App1 preauthenticates for 10 documents using md5-sess
DWORD i; CHAR szBuf[1024]; for (i = 0; i < 10; i++) { wsprintf(szBuf, "/bar/baz/boz/%x.html", i); ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt1, // Output context.
0, // auth from cache.
NULL, // Server challenge header.
"[email protected]", // realm.
"www.foo.com", // Host.
szBuf, // Url.
"GET", // Method.
NULL, // no Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
}
//-------------------------------------------------------------------------------------------------------------
// App1 received a new md5-sess challenge.
szChallenge = "realm=\"[email protected]\", algorithm=\"md5-sess\", stale = TRUE, qop=\"auth,auth-int\", nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"";
ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt1, // Output context.
0, // auth from cache.
szChallenge, // Server challenge header.
NULL, // no realm since not preauth.
"www.foo.com", // Host.
"/bar/baz/boz/bif.html", // Url.
"GET", // Method.
NULL, // no Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
//-------------------------------------------------------------------------------------------------------------
// App1 preauths using new md5-sess
for (i = 0; i < 10; i++) { wsprintf(szBuf, "/bar/baz/boz/%x.html", i); ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt1, // Output context.
0, // auth from cache.
NULL, // Server challenge header.
"[email protected]", // realm.
"www.foo.com", // Host.
szBuf, // Url.
"GET", // Method.
NULL, // no Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
}
szChallenge = "realm=\"Microsoft.Passport\", algorithm=MD5-sess, qop=\"auth\", nonce=ykjOzYDMxMzY4kjOEFkUSVkTB5kM6QUQSJVROFkTyojM6QzY0QGNhJmNjVDNhFGZiZjM3I2MiFWO3MDZyQTNyY2M";
ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt1, // Output context.
0, // auth from cache.
szChallenge, // Server challenge header.
NULL, // no realm since not preauth.
"darrenan2", // Host.
"/passport/protected/test.asp", // Url.
"GET", // Method.
"darrenan2", // Given Username
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
ssResult = DoAuthenticate( &hCred1, // Cred from logging on.
NULL, // Ctxt not specified first time.
&hCtxt1, // Output context.
ISC_REQ_PROMPT_FOR_CREDS, // auth from cache.
szChallenge, // Server challenge header.
NULL, // no realm since not preauth.
"darrenan2", // Host.
"/passport/protected/test.asp", // Url.
"GET", // Method.
"darrenan2", // Given username.
NULL, // no Password.
NULL, // no nonce
NULL, // don't need hwnd for auth.
szResponse); // Response buffer.
// Logoff all three sessions
ssResult = LogoffOfDigestPkg(&hCred1); ssResult = LogoffOfDigestPkg(&hCred2); ssResult = LogoffOfDigestPkg(&hCred3); ssResult = LogoffOfDigestPkg(&hCred4); ssResult = LogoffOfDigestPkg(&hCred5); ssResult = LogoffOfDigestPkg(&hCred6); ssResult = LogoffOfDigestPkg(&hCred7); ssResult = LogoffOfDigestPkg(&hCred8); ssResult = LogoffOfDigestPkg(&hCred9); if (hSecLib) FreeLibrary(hSecLib);
exit: return dwReturn; }
|