3
* $Id: sspwin32.c,v 1.2 2006/09/09 15:29:59 serassio Exp $
5
* AUTHOR: Guido Serassio <serassio@squid-cache.org>
6
* inspired by previous work by Robert Collins, Francesco Chemolli.
8
* SQUID Web Proxy Cache http://www.squid-cache.org/
9
* ----------------------------------------------------------
11
* Squid is the result of efforts by numerous individuals from
12
* the Internet community; see the CONTRIBUTORS file for full
13
* details. Many organizations have provided support for Squid's
14
* development; see the SPONSORS file for full details. Squid is
15
* Copyrighted (C) 2001 by the Regents of the University of
16
* California; see the COPYRIGHT file for full details. Squid
17
* incorporates software developed and/or copyrighted by other
18
* sources; see the CREDITS file for full details.
20
* This program is free software; you can redistribute it and/or modify
21
* it under the terms of the GNU General Public License as published by
22
* the Free Software Foundation; either version 2 of the License, or
23
* (at your option) any later version.
25
* This program is distributed in the hope that it will be useful,
26
* but WITHOUT ANY WARRANTY; without even the implied warranty of
27
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
* GNU General Public License for more details.
30
* You should have received a copy of the GNU General Public License
31
* along with this program; if not, write to the Free Software
32
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
41
typedef struct _AUTH_SEQ {
46
TimeStamp hcredLifeTime;
47
struct _SecHandle hctxt;
48
TimeStamp hctxtLifeTime;
49
} AUTH_SEQ, *PAUTH_SEQ;
51
BOOL GenClientContext(PAUTH_SEQ, PSEC_WINNT_AUTH_IDENTITY, PVOID, DWORD, PVOID, PDWORD, PBOOL);
52
BOOL GenServerContext(PAUTH_SEQ, PVOID, DWORD, PVOID, PDWORD, PBOOL, char *);
54
static HMODULE hModule;
55
static int NTLM_mode = SSP_BASIC;
56
static char * SSP_Package_InUse;
57
SECURITY_STATUS SecurityStatus = SEC_E_OK;
59
static DWORD cbMaxToken = 0;
60
static PVOID pClientBuf = NULL;
61
static PVOID pServerBuf = NULL;
63
static AUTH_SEQ NTLM_asServer = {0};
65
BOOL Use_Unicode = FALSE;
66
BOOL NTLM_LocalCall = FALSE;
68
/* Function pointers */
69
ACCEPT_SECURITY_CONTEXT_FN _AcceptSecurityContext = NULL;
70
ACQUIRE_CREDENTIALS_HANDLE_FN _AcquireCredentialsHandle = NULL;
71
COMPLETE_AUTH_TOKEN_FN _CompleteAuthToken = NULL;
72
DELETE_SECURITY_CONTEXT_FN _DeleteSecurityContext = NULL;
73
FREE_CONTEXT_BUFFER_FN _FreeContextBuffer = NULL;
74
FREE_CREDENTIALS_HANDLE_FN _FreeCredentialsHandle = NULL;
75
INITIALIZE_SECURITY_CONTEXT_FN _InitializeSecurityContext = NULL;
76
QUERY_SECURITY_PACKAGE_INFO_FN _QuerySecurityPackageInfo = NULL;
78
QUERY_CONTEXT_ATTRIBUTES_FN_W _QueryContextAttributes = NULL;
80
QUERY_CONTEXT_ATTRIBUTES_FN_A _QueryContextAttributes = NULL;
83
void UnloadSecurityDll(void)
85
if (NTLM_asServer.fHaveCtxtHandle)
86
_DeleteSecurityContext(&NTLM_asServer.hctxt);
87
if (NTLM_asServer.fHaveCredHandle)
88
_FreeCredentialsHandle(&NTLM_asServer.hcred);
93
xfree(SSP_Package_InUse);
97
_AcceptSecurityContext = NULL;
98
_AcquireCredentialsHandle = NULL;
99
_CompleteAuthToken = NULL;
100
_DeleteSecurityContext = NULL;
101
_FreeContextBuffer = NULL;
102
_FreeCredentialsHandle = NULL;
103
_InitializeSecurityContext = NULL;
104
_QuerySecurityPackageInfo = NULL;
105
_QueryContextAttributes = NULL;
111
HMODULE LoadSecurityDll(int mode, char * SSP_Package)
113
TCHAR lpszDLL[MAX_PATH];
114
OSVERSIONINFO VerInfo;
115
PSecPkgInfo pSPI = NULL;
118
* Find out which security DLL to use, depending on
119
* whether we are on NT or 2000 or XP or 2003 Server
120
* We have to use security.dll on Windows NT 4.0.
121
* All other operating systems, we have to use Secur32.dll
124
if ((mode != SSP_BASIC) && (mode != SSP_NTLM))
127
VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
128
if (!GetVersionEx (&VerInfo)) { /* If this fails, something has gone wrong */
131
if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
132
VerInfo.dwMajorVersion == 4 &&
133
VerInfo.dwMinorVersion == 0)
135
lstrcpy (lpszDLL, _T(WINNT_SECURITY_DLL));
137
lstrcpy (lpszDLL, _T(WIN2K_SECURITY_DLL));
139
hModule = LoadLibrary(lpszDLL);
142
_AcceptSecurityContext = (ACCEPT_SECURITY_CONTEXT_FN)
143
GetProcAddress(hModule, "AcceptSecurityContext");
144
if (!_AcceptSecurityContext) {
150
_AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN)
151
GetProcAddress(hModule, "AcquireCredentialsHandleW");
153
_AcquireCredentialsHandle = (ACQUIRE_CREDENTIALS_HANDLE_FN)
154
GetProcAddress(hModule, "AcquireCredentialsHandleA");
156
if (!_AcquireCredentialsHandle) {
161
_CompleteAuthToken = (COMPLETE_AUTH_TOKEN_FN)
162
GetProcAddress(hModule, "CompleteAuthToken");
163
if (!_CompleteAuthToken) {
168
_DeleteSecurityContext = (DELETE_SECURITY_CONTEXT_FN)
169
GetProcAddress(hModule, "DeleteSecurityContext");
170
if (!_DeleteSecurityContext) {
175
_FreeContextBuffer = (FREE_CONTEXT_BUFFER_FN)
176
GetProcAddress(hModule, "FreeContextBuffer");
177
if (!_FreeContextBuffer) {
182
_FreeCredentialsHandle = (FREE_CREDENTIALS_HANDLE_FN)
183
GetProcAddress(hModule, "FreeCredentialsHandle");
184
if (!_FreeCredentialsHandle) {
190
_InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN)
191
GetProcAddress(hModule, "InitializeSecurityContextW");
193
_InitializeSecurityContext = (INITIALIZE_SECURITY_CONTEXT_FN)
194
GetProcAddress(hModule, "InitializeSecurityContextA");
196
if (!_InitializeSecurityContext) {
202
_QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN)
203
GetProcAddress(hModule, "QuerySecurityPackageInfoW");
205
_QuerySecurityPackageInfo = (QUERY_SECURITY_PACKAGE_INFO_FN)
206
GetProcAddress(hModule, "QuerySecurityPackageInfoA");
208
if (!_QuerySecurityPackageInfo) {
214
_QueryContextAttributes = (QUERY_CONTEXT_ATTRIBUTES_FN_W)
215
GetProcAddress(hModule, "QueryContextAttributesW");
217
_QueryContextAttributes = (QUERY_CONTEXT_ATTRIBUTES_FN_A)
218
GetProcAddress(hModule, "QueryContextAttributesA");
220
if (!_QueryContextAttributes) {
225
/* Get max token size */
226
_QuerySecurityPackageInfo((SEC_CHAR*)_T(SSP_Package), &pSPI);
227
cbMaxToken = pSPI->cbMaxToken;
228
_FreeContextBuffer(pSPI);
230
/* Allocate buffers for client and server messages */
231
pClientBuf = xcalloc(cbMaxToken, sizeof(char));
232
pServerBuf = xcalloc(cbMaxToken, sizeof(char));
233
SSP_Package_InUse = xstrdup(SSP_Package);
239
BOOL GenClientContext(PAUTH_SEQ pAS, PSEC_WINNT_AUTH_IDENTITY pAuthIdentity,
240
PVOID pIn, DWORD cbIn, PVOID pOut, PDWORD pcbOut, PBOOL pfDone)
243
* Routine Description:
245
* Optionally takes an input buffer coming from the server and returns
246
* a buffer of information to send back to the server. Also returns
247
* an indication of whether or not the context is complete.
250
* Returns TRUE if successful; otherwise FALSE.
253
SecBufferDesc sbdOut;
259
if (!pAS->fInitialized) {
260
SecurityStatus = _AcquireCredentialsHandle(NULL, (SEC_CHAR*) _T(SSP_Package_InUse),
261
SECPKG_CRED_OUTBOUND, NULL, (NTLM_mode == SSP_NTLM) ? NULL : pAuthIdentity, NULL, NULL,
262
&pAS->hcred, &tsExpiry);
263
if (SecurityStatus < 0)
265
pAS->fHaveCredHandle = TRUE;
268
/* Prepare output buffer */
269
sbdOut.ulVersion = 0;
271
sbdOut.pBuffers = &sbOut;
272
sbOut.cbBuffer = *pcbOut;
273
sbOut.BufferType = SECBUFFER_TOKEN;
274
sbOut.pvBuffer = pOut;
276
/* Prepare input buffer */
277
if (pAS->fInitialized) {
280
sbdIn.pBuffers = &sbIn;
281
sbIn.cbBuffer = cbIn;
282
sbIn.BufferType = SECBUFFER_TOKEN;
285
SecurityStatus = _InitializeSecurityContext(&pAS->hcred,
286
pAS->fInitialized ? &pAS->hctxt : NULL, NULL, 0, 0,
287
SECURITY_NATIVE_DREP, pAS->fInitialized ? &sbdIn : NULL,
288
0, &pAS->hctxt, &sbdOut, &fContextAttr, &tsExpiry);
289
if (SecurityStatus < 0)
291
pAS->fHaveCtxtHandle = TRUE;
293
/* If necessary, complete token */
294
if (SecurityStatus == SEC_I_COMPLETE_NEEDED || SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE) {
295
SecurityStatus = _CompleteAuthToken(&pAS->hctxt, &sbdOut);
296
if (SecurityStatus < 0)
299
*pcbOut = sbOut.cbBuffer;
300
if (!pAS->fInitialized)
301
pAS->fInitialized = TRUE;
302
*pfDone = !(SecurityStatus == SEC_I_CONTINUE_NEEDED
303
|| SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE );
308
BOOL GenServerContext(PAUTH_SEQ pAS, PVOID pIn, DWORD cbIn, PVOID pOut,
309
PDWORD pcbOut, PBOOL pfDone, char * credentials)
312
* Routine Description:
314
* Takes an input buffer coming from the client and returns a buffer
315
* to be sent to the client. Also returns an indication of whether or
316
* not the context is complete.
320
* Returns TRUE if successful; otherwise FALSE.
323
SecBufferDesc sbdOut;
328
SecPkgContext_Names namebuffer;
330
if (!pAS->fInitialized) {
331
SecurityStatus = _AcquireCredentialsHandle(NULL, (SEC_CHAR*) _T(SSP_Package_InUse),
332
SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL, &pAS->hcred,
333
&pAS->hcredLifeTime);
335
fprintf(stderr, "AcquireCredentialsHandle returned: %x\n", SecurityStatus);
337
if (SecurityStatus < 0) {
339
fprintf(stderr, "AcquireCredentialsHandle failed: %x\n", SecurityStatus);
343
pAS->fHaveCredHandle = TRUE;
346
/* Prepare output buffer */
347
sbdOut.ulVersion = 0;
349
sbdOut.pBuffers = &sbOut;
350
sbOut.cbBuffer = *pcbOut;
351
sbOut.BufferType = SECBUFFER_TOKEN;
352
sbOut.pvBuffer = pOut;
354
/* Prepare input buffer */
357
sbdIn.pBuffers = &sbIn;
358
sbIn.cbBuffer = cbIn;
359
sbIn.BufferType = SECBUFFER_TOKEN;
361
SecurityStatus = _AcceptSecurityContext(&pAS->hcred,
362
pAS->fInitialized ? &pAS->hctxt : NULL, &sbdIn, (NTLM_mode == SSP_NTLM) ? ASC_REQ_DELEGATE : 0,
363
SECURITY_NATIVE_DREP, &pAS->hctxt, &sbdOut, &fContextAttr,
364
&pAS->hctxtLifeTime);
366
fprintf(stderr, "AcceptSecurityContext returned: %x\n", SecurityStatus);
368
if (SecurityStatus < 0) {
370
fprintf(stderr, "AcceptSecurityContext failed: %x\n", SecurityStatus);
374
pAS->fHaveCtxtHandle = TRUE;
376
/* If necessary, complete token */
377
if (SecurityStatus == SEC_I_COMPLETE_NEEDED || SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE) {
378
SecurityStatus = _CompleteAuthToken(&pAS->hctxt, &sbdOut);
380
fprintf(stderr, "CompleteAuthToken returned: %x\n", SecurityStatus);
382
if (SecurityStatus < 0) {
384
fprintf(stderr, "CompleteAuthToken failed: %x\n", SecurityStatus);
390
if ((credentials != NULL) &&
391
!(SecurityStatus == SEC_I_CONTINUE_NEEDED || SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE)) {
392
SecurityStatus = _QueryContextAttributes(&pAS->hctxt, SECPKG_ATTR_NAMES, &namebuffer);
394
fprintf(stderr, "QueryContextAttributes returned: %x\n", SecurityStatus);
396
if (SecurityStatus < 0) {
398
fprintf(stderr, "QueryContextAttributes failed: %x\n", SecurityStatus);
402
strncpy(credentials, namebuffer.sUserName, SSP_MAX_CRED_LEN);
405
*pcbOut = sbOut.cbBuffer;
406
if (!pAS->fInitialized)
407
pAS->fInitialized = TRUE;
408
*pfDone = !(SecurityStatus == SEC_I_CONTINUE_NEEDED
409
|| SecurityStatus == SEC_I_COMPLETE_AND_CONTINUE);
414
BOOL WINAPI SSP_LogonUser(PTSTR szUser, PTSTR szPassword, PTSTR szDomain)
416
AUTH_SEQ asServer = {0};
417
AUTH_SEQ asClient = {0};
419
BOOL fResult = FALSE;
423
SEC_WINNT_AUTH_IDENTITY ai;
429
/* Initialize auth identity structure */
430
ZeroMemory(&ai, sizeof(ai));
431
ai.Domain = szDomain;
432
ai.DomainLength = lstrlen(szDomain);
434
ai.UserLength = lstrlen(szUser);
435
ai.Password = szPassword;
436
ai.PasswordLength = lstrlen(szPassword);
437
#if defined(UNICODE) || defined(_UNICODE)
438
ai.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
440
ai.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
443
/* Prepare client message (negotiate) */
445
if (!GenClientContext(&asClient, &ai, NULL, 0, pClientBuf, &cbOut, &fDone))
448
/* Prepare server message (challenge) */
451
if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
454
/* Most likely failure: AcceptServerContext fails with SEC_E_LOGON_DENIED
455
* in the case of bad szUser or szPassword.
456
* Unexpected Result: Logon will succeed if you pass in a bad szUser and
457
* the guest account is enabled in the specified domain.
460
/* Prepare client message (authenticate) */
463
if (!GenClientContext(&asClient, &ai, pServerBuf, cbIn, pClientBuf, &cbOut,
467
/* Prepare server message (authentication) */
470
if (!GenServerContext(&asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
476
/* Clean up resources */
477
if (asClient.fHaveCtxtHandle)
478
_DeleteSecurityContext(&asClient.hctxt);
479
if (asClient.fHaveCredHandle)
480
_FreeCredentialsHandle(&asClient.hcred);
481
if (asServer.fHaveCtxtHandle)
482
_DeleteSecurityContext(&asServer.hctxt);
483
if (asServer.fHaveCredHandle)
484
_FreeCredentialsHandle(&asServer.hcred);
490
const char * WINAPI SSP_MakeChallenge(PVOID PNegotiateBuf, int NegotiateLen)
493
PVOID fResult = NULL;
496
ntlm_challenge * challenge;
497
const char * encoded = NULL;
499
if (NTLM_asServer.fHaveCtxtHandle)
500
_DeleteSecurityContext(&NTLM_asServer.hctxt);
501
if (NTLM_asServer.fHaveCredHandle)
502
_FreeCredentialsHandle(&NTLM_asServer.hcred);
504
NTLM_LocalCall = FALSE;
506
memcpy(pClientBuf, PNegotiateBuf, NegotiateLen);
507
ZeroMemory(pServerBuf, cbMaxToken);
508
ZeroMemory(&NTLM_asServer, sizeof(NTLM_asServer));
513
/* Prepare server message (challenge) */
516
if (!GenServerContext(&NTLM_asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
519
fResult = pServerBuf;
521
if (fResult != NULL) {
522
challenge = (ntlm_challenge *) fResult;
523
Use_Unicode = NEGOTIATE_UNICODE & challenge->flags;
524
NTLM_LocalCall = NEGOTIATE_THIS_IS_LOCAL_CALL & challenge->flags;
525
encoded = base64_encode_bin((char *) fResult, cbOut);
531
BOOL WINAPI SSP_ValidateNTLMCredentials(PVOID PAutenticateBuf, int AutenticateLen, char * credentials)
534
BOOL fResult = FALSE;
538
memcpy(pClientBuf, PAutenticateBuf, AutenticateLen);
539
ZeroMemory(pServerBuf, cbMaxToken);
544
/* Prepare server message (authentication) */
545
cbIn = AutenticateLen;
547
if (!GenServerContext(&NTLM_asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
548
&fDone, credentials))
557
const char * WINAPI SSP_MakeNegotiateBlob(PVOID PNegotiateBuf, int NegotiateLen, PBOOL fDone, int * Status, char * credentials)
561
const char * encoded = NULL;
563
if (NTLM_asServer.fHaveCtxtHandle)
564
_DeleteSecurityContext(&NTLM_asServer.hctxt);
565
if (NTLM_asServer.fHaveCredHandle)
566
_FreeCredentialsHandle(&NTLM_asServer.hcred);
568
memcpy(pClientBuf, PNegotiateBuf, NegotiateLen);
569
ZeroMemory(pServerBuf, cbMaxToken);
570
ZeroMemory(&NTLM_asServer, sizeof(NTLM_asServer));
575
/* Prepare server message (challenge) */
578
if (!GenServerContext(&NTLM_asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
579
fDone, credentials)) {
585
if (pServerBuf != NULL && cbOut > 0)
586
encoded = base64_encode_bin((char *) pServerBuf, cbOut);
591
const char * WINAPI SSP_ValidateNegotiateCredentials(PVOID PAutenticateBuf, int AutenticateLen, PBOOL fDone, int * Status, char * credentials)
595
const char * encoded = NULL;
597
memcpy(pClientBuf, PAutenticateBuf, AutenticateLen);
598
ZeroMemory(pServerBuf, cbMaxToken);
603
/* Prepare server message (authentication) */
604
cbIn = AutenticateLen;
606
if (!GenServerContext(&NTLM_asServer, pClientBuf, cbIn, pServerBuf, &cbOut,
607
fDone, credentials)) {
613
if (pServerBuf != NULL && cbOut > 0)
614
encoded = base64_encode_bin((char *) pServerBuf, cbOut);