The opinions expressed herein are my own personal opinions. They are not necessarily fact or sactioned by any other person or organization. If you disagree that's your right. It's also my right to not care.
© Copyright 2009, Chris Tacke
A question came up in todays CF chat about authenticating a CE device to a domain. While I don't have ready-made CF code for it (though that might be an interesting task) here's a C version:
#include <WINDOWS.H> #include <SECURITY.H> #include <SSPI.H> #define SEC_PACKAGE _T("Microsoft Unified Security Protocol Provider") typedef struct _AUTH_SEQ { BOOL fInitialized; BOOL fHaveCredHandle; BOOL fHaveCtxtHandle; CredHandle hcred; struct _SecHandle hctxt; } AUTH_SEQ, *PAUTH_SEQ; BOOL GenClientContext(PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity, PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone); BOOL GenServerContext(PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone); BOOL WINAPI SSPLogonUser(LPTSTR szDomain, LPTSTR szUser, LPTSTR szPassword); TCHAR *lpszUserName = _T("ctacke"); TCHAR *lpszDomainName = _T("mydomain"); TCHAR *lpszPassword = _T("mypassword"); int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPWSTR lpCmdLine, int nCmShow) { return SSPLogonUser(lpszDomainName, lpszUserName, lpszPassword); } BOOL GenClientContext(PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity, PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) { DEBUGMSG(TRUE, (_T("+GenServerContext\r\n"))); SECURITY_STATUS ss; TimeStamp tsExpiry; SecBufferDesc sbdOut; SecBuffer sbOut; SecBufferDesc sbdIn; SecBuffer sbIn; ULONG fContextAttr; if (!pAS->fInitialized) { DEBUGMSG(TRUE, (_T("Calling AcquireCredentialsHandle..."))); ss = AcquireCredentialsHandle(NULL, SEC_PACKAGE, SECPKG_CRED_OUTBOUND, NULL, pAuthIdentity, NULL, NULL, &pAS->hcred, &tsExpiry); if (ss < 0) { DEBUGMSG(TRUE, (_T("failed with 0x%08x\r\n"), ss)); return FALSE; } DEBUGMSG(TRUE, (_T("ok\r\n"))); if(ss < 0) { fprintf(stderr, "AcquireCredentialsHandle failed with %08X\n", ss); return FALSE; } pAS->fHaveCredHandle = TRUE; } // Prepare output buffer sbdOut.ulVersion = 0; sbdOut.cBuffers = 1; sbdOut.pBuffers = &sbOut; sbOut.cbBuffer = *pcbOut; sbOut.BufferType = SECBUFFER_TOKEN; sbOut.pvBuffer = pOut; // Prepare input buffer if (pAS->fInitialized) { sbdIn.ulVersion = 0; sbdIn.cBuffers = 1; sbdIn.pBuffers = &sbIn; sbIn.cbBuffer = cbIn; sbIn.BufferType = SECBUFFER_TOKEN; sbIn.pvBuffer = pIn; } ss = InitializeSecurityContext(&pAS->hcred, pAS->fInitialized ? &pAS->hctxt : NULL, NULL, 0, 0, SECURITY_NATIVE_DREP, pAS->fInitialized ? &sbdIn : NULL, 0, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry); if (ss < 0) { // fprintf(stderr, "InitializeSecurityContext failed with %08X\n", ss); return FALSE; } pAS->fHaveCtxtHandle = TRUE; // If necessary, complete token if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) { ss = CompleteAuthToken(&pAS->hctxt, &sbdOut); if (ss < 0) { fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss); return FALSE; } } *pcbOut = sbOut.cbBuffer; if (!pAS->fInitialized) pAS->fInitialized = TRUE; *pfDone = !(ss == SEC_I_CONTINUE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE ); DEBUGMSG(TRUE, (_T("-GenServerContext\r\n"))); return TRUE; } /////////////////////////////////////////////////////////////////////////////// BOOL GenServerContext(PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) { DEBUGMSG(TRUE, (_T("+GenServerContext\r\n"))); SECURITY_STATUS ss; TimeStamp tsExpiry; SecBufferDesc sbdOut; SecBuffer sbOut; SecBufferDesc sbdIn; SecBuffer sbIn; ULONG fContextAttr; if (!pAS->fInitialized) { DEBUGMSG(TRUE, (_T("Calling AcquireCredentialsHandle..."))); ss = AcquireCredentialsHandle(NULL, SEC_PACKAGE, SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &pAS->hcred, &tsExpiry); if (ss < 0) { DEBUGMSG(TRUE, (_T("failed with 0x%08x\r\n"), ss)); return FALSE; } DEBUGMSG(TRUE, (_T("ok\r\n"))); pAS->fHaveCredHandle = TRUE; } // Prepare output buffer sbdOut.ulVersion = 0; sbdOut.cBuffers = 1; sbdOut.pBuffers = &sbOut; sbOut.cbBuffer = *pcbOut; sbOut.BufferType = SECBUFFER_TOKEN; sbOut.pvBuffer = pOut; // Prepare input buffer sbdIn.ulVersion = 0; sbdIn.cBuffers = 1; sbdIn.pBuffers = &sbIn; sbIn.cbBuffer = cbIn; sbIn.BufferType = SECBUFFER_TOKEN; sbIn.pvBuffer = pIn; DEBUGMSG(TRUE, (_T("Calling AcceptSecurityContext..."))); ss = AcceptSecurityContext(&pAS->hcred, pAS->fInitialized ? &pAS->hctxt : NULL, &sbdIn, 0, SECURITY_NATIVE_DREP, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry); if (ss < 0) { DEBUGMSG(TRUE, (_T("failed with 0x%08x\r\n"), ss)); return FALSE; } DEBUGMSG(TRUE, (_T("ok\r\n"))); pAS->fHaveCtxtHandle = TRUE; // If necessary, complete token if (ss == SEC_I_COMPLETE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE) { DEBUGMSG(TRUE, (_T("Calling CompleteAuthToken..."))); ss = CompleteAuthToken(&pAS->hctxt, &sbdOut); if (ss < 0) { DEBUGMSG(TRUE, (_T("failed with 0x%08x\r\n"), ss)); return FALSE; } DEBUGMSG(TRUE, (_T("ok\r\n"))); } *pcbOut = sbOut.cbBuffer; if (!pAS->fInitialized) pAS->fInitialized = TRUE; *pfDone = !(ss = SEC_I_CONTINUE_NEEDED || ss == SEC_I_COMPLETE_AND_CONTINUE); DEBUGMSG(TRUE, (_T("-GenServerContext\r\n"))); return TRUE; } /////////////////////////////////////////////////////////////////////////////// BOOL WINAPI SSPLogonUser(LPTSTR szDomain, LPTSTR szUser, LPTSTR szPassword) { DEBUGMSG(TRUE, (_T("\r\n+SSPLogonUser\r\n"))); AUTH_SEQ asServer = {0}; AUTH_SEQ asClient = {0}; BOOL fDone = FALSE; BOOL fResult = FALSE; DWORD cbOut = 0; DWORD cbIn = 0; DWORD cbMaxToken = 0; PVOID pClientBuf = NULL; PVOID pServerBuf = NULL; SecPkgInfo *pSPI = NULL; HMODULE hModule = NULL; SECURITY_STATUS ss; SEC_WINNT_AUTH_IDENTITY ai; ULONG packages = 0; PSecPkgInfo pPackageInfo = NULL; __try { EnumerateSecurityPackages(&packages, &pPackageInfo); DEBUGMSG(TRUE, (_T(" Available security packages:\r\n"))); for(UINT i = 0 ; i < packages ; i++) { DEBUGMSG(TRUE, (_T("\t%s\r\n"), pPackageInfo[i].Name)); } DEBUGMSG(TRUE, (_T("\r\n"))); DEBUGMSG(TRUE, (_T("Calling FreeContextBuffer..."))); ss =FreeContextBuffer(pPackageInfo); if(ss != SEC_E_OK) { DEBUGMSG(TRUE, (_T("failed with 0x%08x\r\n"), ss)); __leave; } DEBUGMSG(TRUE, (_T("ok\r\n"))); // Get max token size DEBUGMSG(TRUE, (_T("Calling QuerySecurityPackageInfo..."))); ss = QuerySecurityPackageInfo(SEC_PACKAGE, &pSPI); if(ss != SEC_E_OK) { DEBUGMSG(TRUE, (_T("failed with 0x%08x\r\n"), ss)); __leave; } DEBUGMSG(TRUE, (_T("ok\r\n"))); cbMaxToken = pSPI->cbMaxToken; DEBUGMSG(TRUE, (_T("Calling FreeContextBuffer..."))); ss =FreeContextBuffer(pSPI); if(ss != SEC_E_OK) { DEBUGMSG(TRUE, (_T("failed with 0x%08x\r\n"), ss)); __leave; } DEBUGMSG(TRUE, (_T("ok\r\n"))); // Allocate buffers for client and server messages DEBUGMSG(TRUE, (_T("Allocating heaps..."))); pClientBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken); pServerBuf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbMaxToken); DEBUGMSG(TRUE, (_T("ok\r\n"))); // Initialize auth identity structure ZeroMemory(&ai, sizeof(ai)); ai.Domain = szDomain; ai.DomainLength = _tcslen(szDomain); ai.User = szUser; ai.UserLength = _tcslen(szUser); ai.Password = szPassword; ai.PasswordLength = _tcslen(szPassword); ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; // Prepare client message (negotiate) . cbOut = cbMaxToken; DEBUGMSG(TRUE, (_T("Calling GenClientContext\r\n"))); if (!GenClientContext(&asClient, &ai, NULL, 0, pClientBuf, &cbOut, &fDone)) __leave; // Prepare server message (challenge) . cbIn = cbOut; cbOut = cbMaxToken; DEBUGMSG(TRUE, (_T("Calling GenServerContext\r\n"))); if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut, &fDone)) __leave; // Most likely failure: AcceptServerContext fails with SEC_E_LOGON_DENIED // in the case of bad szUser or szPassword. // Unexpected Result: Logon will succeed if you pass in a bad szUser and // the guest account is enabled in the specified domain. // Prepare client message (authenticate) . cbIn = cbOut; cbOut = cbMaxToken; DEBUGMSG(TRUE, (_T("Calling GenClientContext\r\n"))); if (!GenClientContext(&asClient, &ai, pServerBuf, cbIn, pClientBuf, &cbOut, &fDone)) __leave; // Prepare server message (authentication) . cbIn = cbOut; cbOut = cbMaxToken; DEBUGMSG(TRUE, (_T("Calling GenServerContext\r\n"))); if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut, &fDone)) __leave; fResult = TRUE; } __finally { // Clean up resources if (asClient.fHaveCtxtHandle) { DEBUGMSG(TRUE, (_T("Calling DeleteSecurityContext\r\n"))); DeleteSecurityContext(&asClient.hctxt); } if (asClient.fHaveCredHandle) { DEBUGMSG(TRUE, (_T("Calling FreeCredentialsHandle\r\n"))); FreeCredentialsHandle(&asClient.hcred); } if (asServer.fHaveCtxtHandle) { DEBUGMSG(TRUE, (_T("Calling DeleteSecurityContext\r\n"))); DeleteSecurityContext(&asServer.hctxt); } if (asServer.fHaveCredHandle) { DEBUGMSG(TRUE, (_T("Calling FreeCredentialsHandle\r\n"))); FreeCredentialsHandle(&asServer.hcred); } DEBUGMSG(TRUE, (_T("Freeing heaps..."))); HeapFree(GetProcessHeap(), 0, pClientBuf); HeapFree(GetProcessHeap(), 0, pServerBuf); DEBUGMSG(TRUE, (_T("ok\r\n"))); } DEBUGMSG(TRUE, (_T("-SSPLogonUser\r\n"))); return fResult; }
Remember Me