--------------------- PatchSet 4495 Date: 2002/07/16 08:35:13 Author: serassio Branch: cygwin-svc-2_5 Tag: (none) Log: Added WIN32 native NTLM authenticator Members: include/sspwin32.h:1.1->1.1.2.1 lib/Makefile.am:1.4->1.4.6.1 lib/sspwin32.c:1.1->1.1.2.1 --- /dev/null Wed Feb 14 01:00:00 2007 +++ squid/include/sspwin32.h Wed Feb 14 01:00:02 2007 @@ -0,0 +1,45 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli, Robert Collins and Andrew Doran + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +#ifndef _LIBSSPWIN32_H_ +#define _LIBSSPWIN32_H_ +#define SECURITY_WIN32 +#define NTLM_PACKAGE_NAME "NTLM" + +#ifdef _SQUID_CYGWIN_ +#include +#define _T(x) TEXT(x) +#else +#include +#endif +#include +#include +#include + +#define WINNT_SECURITY_DLL "security.dll" +#define WIN9X_SECURITY_DLL "secur32.dll" + +#define SSP_BASIC 1 +#define SSP_NTLM 2 + +HMODULE LoadSecurityDll(int); +void UnloadSecurityDll(void); +BOOL WINAPI SSPLogonUser(PTSTR, PTSTR, PTSTR); + +extern SECURITY_STATUS ss; + +#endif /* LIBSSPWIN32_H_ */ Index: squid/lib/Makefile.am =================================================================== RCS file: /cvsroot/squid-sf//squid/lib/Makefile.am,v retrieving revision 1.4 retrieving revision 1.4.6.1 diff -u -r1.4 -r1.4.6.1 --- squid/lib/Makefile.am 21 Nov 2001 23:48:57 -0000 1.4 +++ squid/lib/Makefile.am 16 Jul 2002 08:35:13 -0000 1.4.6.1 @@ -21,6 +21,7 @@ @LIBDLMALLOC@ \ libmiscutil.a \ libntlmauth.a \ + libsspwin32.a \ @LIBREGEX@ EXTRA_libmiscutil_a_SOURCES = \ md5.c \ @@ -57,5 +58,7 @@ ntlmauth.c libntlmauth_a_LIBADD = \ @LIBOBJS@ +libsspwin32_a_SOURCES = \ + sspwin32.c -INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/src -I$(top_builddir)/src --- /dev/null Wed Feb 14 01:00:00 2007 +++ squid/lib/sspwin32.c Wed Feb 14 01:00:02 2007 @@ -0,0 +1,411 @@ +/* + * (C) 2002 Guido Serassio + * Based on previous work of Francesco Chemolli, Robert Collins + * + * Distributed freely under the terms of the GNU General Public License, + * version 2. See the file COPYING for licensing details + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + */ + +#include "squid.h" +#include "sspwin32.h" + + + +typedef struct _AUTH_SEQ { + BOOL fInitialized; + BOOL fHaveCredHandle; + BOOL fHaveCtxtHandle; + CredHandle hcred; + struct _SecHandle hctxt; +} AUTH_SEQ, *PAUTH_SEQ; + +static HMODULE hModule; +static int NTLM_mode = SSP_BASIC; +SECURITY_STATUS ss = SEC_E_OK; + +/* Function pointers */ +ACCEPT_SECURITY_CONTEXT_FN _AcceptSecurityContext = NULL; +ACQUIRE_CREDENTIALS_HANDLE_FN _AcquireCredentialsHandle = NULL; +COMPLETE_AUTH_TOKEN_FN _CompleteAuthToken = NULL; +DELETE_SECURITY_CONTEXT_FN _DeleteSecurityContext = NULL; +FREE_CONTEXT_BUFFER_FN _FreeContextBuffer = NULL; +FREE_CREDENTIALS_HANDLE_FN _FreeCredentialsHandle = NULL; +INITIALIZE_SECURITY_CONTEXT_FN _InitializeSecurityContext = NULL; +QUERY_SECURITY_PACKAGE_INFO_FN _QuerySecurityPackageInfo = NULL; + + +void UnloadSecurityDll(void) +{ + if (hModule) + FreeLibrary(hModule); + _AcceptSecurityContext = NULL; + _AcquireCredentialsHandle = NULL; + _CompleteAuthToken = NULL; + _DeleteSecurityContext = NULL; + _FreeContextBuffer = NULL; + _FreeCredentialsHandle = NULL; + _InitializeSecurityContext = NULL; + _QuerySecurityPackageInfo = NULL; + hModule = NULL; +} + + +HMODULE LoadSecurityDll(int mode) +{ + TCHAR lpszDLL[MAX_PATH]; + OSVERSIONINFO VerInfo; +/* + * Find out which security DLL to use, depending on + * whether we are on NT or Win95 or 2000 or XP or .NET Server + * We have to use security.dll on Windows NT 4.0. + * All other operating systems, we have to use Secur32.dll + */ + hModule = NULL; + if ((mode != SSP_BASIC) && (mode != SSP_NTLM)) + return hModule; + NTLM_mode = mode; + VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + if (!GetVersionEx (&VerInfo)) { /* If this fails, something has gone wrong */ + return hModule; + } + if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT && + VerInfo.dwMajorVersion == 4 && + VerInfo.dwMinorVersion == 0) + { + lstrcpy (lpszDLL, _T(WINNT_SECURITY_DLL)); + } else { + lstrcpy (lpszDLL, _T(WIN9X_SECURITY_DLL)); + } + hModule = LoadLibrary(lpszDLL); + if (!hModule) + return hModule; + _AcceptSecurityContext = (ACCEPT_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "AcceptSecurityContext"); + if (!_AcceptSecurityContext) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +#ifdef UNICODE + _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN) + GetProcAddress(hModule, "AcquireCredentialsHandleW"); +#else + _AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN) + GetProcAddress(hModule, "AcquireCredentialsHandleA"); +#endif + if (!_AcquireCredentialsHandle) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +/* CompleteAuthToken is not present on Windows 9x Secur32.dll + * Do not check for the availablity of the function if it is NULL + */ + _CompleteAuthToken = (COMPLETE_AUTH_TOKEN_FN) + GetProcAddress(hModule, "CompleteAuthToken"); + _DeleteSecurityContext = (DELETE_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "DeleteSecurityContext"); + if (!_DeleteSecurityContext) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } + _FreeContextBuffer = (FREE_CONTEXT_BUFFER_FN) + GetProcAddress(hModule, "FreeContextBuffer"); + if (!_FreeContextBuffer) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } + _FreeCredentialsHandle = (FREE_CREDENTIALS_HANDLE_FN) + GetProcAddress(hModule, "FreeCredentialsHandle"); + if (!_FreeCredentialsHandle) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +#ifdef UNICODE + _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "InitializeSecurityContextW"); +#else + _InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN) + GetProcAddress(hModule, "InitializeSecurityContextA"); +#endif + if (!_InitializeSecurityContext) { + UnloadSecurityDll(); + hModule = NULL; + return hModule; + } +#ifdef UNICODE + _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN) + GetProcAddress(hModule, "QuerySecurityPackageInfoW"); +#else + _QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN) + GetProcAddress(hModule, "QuerySecurityPackageInfoA"); +#endif + if (!_QuerySecurityPackageInfo) { + UnloadSecurityDll(); + hModule = NULL; + } + return hModule; +} + + +BOOL GenClientContext(PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity, + PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone) +{ +/* + * Routine Description: + * + * Optionally takes an input buffer coming from the server and returns + * a buffer of information to send back to the server. Also returns + * an indication of whether or not the context is complete. + * + * Return Value: + * Returns TRUE if successful; otherwise FALSE. + */ + TimeStamp tsExpiry; + SecBufferDesc sbdOut; + SecBuffer sbOut; + SecBufferDesc sbdIn; + SecBuffer sbIn; + ULONG fContextAttr; + + if (!pAS->fInitialized) { + ss = _AcquireCredentialsHandle(NULL, _T(NTLM_PACKAGE_NAME), + SECPKG_CRED_OUTBOUND, NULL, (NTLM_mode == SSP_NTLM) ? NULL : pAuthIdentity, NULL, NULL, + &pAS->hcred, &tsExpiry); + 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) { + if (_CompleteAuthToken) { + ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut); + if (ss < 0) { + fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss); + return FALSE; + } + } else { + fprintf (stderr, "CompleteAuthToken not supported.\n"); + return FALSE; + } + } + *pcbOut = sbOut.cbBuffer; + if (!pAS->fInitialized) + pAS->fInitialized = TRUE; + *pfDone = !(ss == SEC_I_CONTINUE_NEEDED + || ss == SEC_I_COMPLETE_AND_CONTINUE ); + return TRUE; +} + + +BOOL GenServerContext(PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut, + PDWORD pcbOut, PBOOL pfDone) +{ +/* + * Routine Description: + * + * Takes an input buffer coming from the client and returns a buffer + * to be sent to the client. Also returns an indication of whether or + * not the context is complete. + * + * Return Value: + * + * Returns TRUE if successful; otherwise FALSE. + */ + + TimeStamp tsExpiry; + SecBufferDesc sbdOut; + SecBuffer sbOut; + SecBufferDesc sbdIn; + SecBuffer sbIn; + ULONG fContextAttr; + + if (!pAS->fInitialized) { + ss = _AcquireCredentialsHandle(NULL, _T("NTLM"), + SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &pAS->hcred, + &tsExpiry); + 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 */ + sbdIn.ulVersion = 0; + sbdIn.cBuffers = 1; + sbdIn.pBuffers = &sbIn; + sbIn.cbBuffer = cbIn; + sbIn.BufferType = SECBUFFER_TOKEN; + sbIn.pvBuffer = pIn; + ss = _AcceptSecurityContext(&pAS->hcred, + pAS->fInitialized ? &pAS->hctxt : NULL, &sbdIn, (NTLM_mode == SSP_NTLM) ? ASC_REQ_DELEGATE : 0, + SECURITY_NATIVE_DREP, &pAS->hctxt, &sbdOut, &fContextAttr, + &tsExpiry); + if (ss < 0) { + fprintf(stderr, "AcceptSecurityContext 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) { + if (_CompleteAuthToken) { + ss = _CompleteAuthToken(&pAS->hctxt, &sbdOut); + if (ss < 0) { + fprintf(stderr, "CompleteAuthToken failed with %08X\n", ss); + return FALSE; + } + } else { + fprintf (stderr, "CompleteAuthToken not supported.\n"); + return FALSE; + } + } + *pcbOut = sbOut.cbBuffer; + if (!pAS->fInitialized) + pAS->fInitialized = TRUE; + *pfDone = !(ss = SEC_I_CONTINUE_NEEDED + || ss == SEC_I_COMPLETE_AND_CONTINUE); + return TRUE; +} + + +BOOL WINAPI SSPLogonUser(PTSTR szUser, PTSTR szPassword, PTSTR szDomain) +{ + 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; + PSecPkgInfo pSPI = NULL; + + SEC_WINNT_AUTH_IDENTITY ai; + + do { + if (!hModule) + break; + /* Get max token size */ + _QuerySecurityPackageInfo(_T("NTLM"), &pSPI); + cbMaxToken = pSPI->cbMaxToken; + _FreeContextBuffer(pSPI); + + /* Allocate buffers for client and server messages */ + pClientBuf = xcalloc(cbMaxToken, sizeof(char)); + pServerBuf = xcalloc(cbMaxToken, sizeof(char)); + + /* Initialize auth identity structure */ + ZeroMemory(&ai, sizeof(ai)); + ai.Domain = szDomain; + ai.DomainLength = lstrlen(szDomain); + ai.User = szUser; + ai.UserLength = lstrlen(szUser); + ai.Password = szPassword; + ai.PasswordLength = lstrlen(szPassword); +#if defined(UNICODE) || defined(_UNICODE) + ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; +#else + ai.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; +#endif + + /* Prepare client message (negotiate) */ + cbOut = cbMaxToken; + if (!GenClientContext(&asClient, &ai, NULL, 0, pClientBuf, &cbOut, &fDone)) + break; + + /* Prepare server message (challenge) */ + cbIn = cbOut; + cbOut = cbMaxToken; + if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut, + &fDone)) + break; +/* 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; + if (!GenClientContext(&asClient, &ai, pServerBuf, cbIn, pClientBuf, &cbOut, + &fDone)) + break; + + /* Prepare server message (authentication) */ + cbIn = cbOut; + cbOut = cbMaxToken; + if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut, + &fDone)) + break; + fResult = TRUE; + } while(0); + + /* Clean up resources */ + if (asClient.fHaveCtxtHandle) + _DeleteSecurityContext(&asClient.hctxt); + if (asClient.fHaveCredHandle) + _FreeCredentialsHandle(&asClient.hcred); + if (asServer.fHaveCtxtHandle) + _DeleteSecurityContext(&asServer.hctxt); + if (asServer.fHaveCredHandle) + _FreeCredentialsHandle(&asServer.hcred); + xfree(pClientBuf); + xfree(pServerBuf); + + return fResult; +}