mf/samplegrabber: Handle paused state.
[wine.git] / dlls / msv1_0 / main.c
blobdf9d0dd0f1ab4d7871c8de9014ea67ff9b640ca7
1 /*
2 * Copyright 2005, 2006 Kai Blin
3 * Copyright 2021 Hans Leidekker for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <wchar.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winternl.h"
28 #include "sspi.h"
29 #include "ntsecapi.h"
30 #include "ntsecpkg.h"
31 #include "rpc.h"
32 #include "wincred.h"
33 #include "lmwksta.h"
34 #include "lmapibuf.h"
35 #include "lmerr.h"
37 #include "wine/debug.h"
38 #include "unixlib.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
42 static HINSTANCE instance;
43 static ULONG ntlm_package_id;
44 static LSA_DISPATCH_TABLE lsa_dispatch;
46 const struct ntlm_funcs *ntlm_funcs = NULL;
48 #define NTLM_CAPS \
49 ( SECPKG_FLAG_INTEGRITY \
50 | SECPKG_FLAG_PRIVACY \
51 | SECPKG_FLAG_TOKEN_ONLY \
52 | SECPKG_FLAG_CONNECTION \
53 | SECPKG_FLAG_MULTI_REQUIRED \
54 | SECPKG_FLAG_IMPERSONATION \
55 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
56 | SECPKG_FLAG_NEGOTIABLE \
57 | SECPKG_FLAG_LOGON \
58 | SECPKG_FLAG_RESTRICTED_TOKENS )
60 #define NTLM_MAX_BUF 1904
62 static const SecPkgInfoW ntlm_package_info =
64 NTLM_CAPS,
66 RPC_C_AUTHN_WINNT,
67 NTLM_MAX_BUF,
68 (SEC_WCHAR *)L"NTLM",
69 (SEC_WCHAR *)L"NTLM Security Package"
72 static inline const char *debugstr_as( const STRING *str )
74 if (!str) return "<null>";
75 return debugstr_an( str->Buffer, str->Length );
78 static inline const char *debugstr_us( const UNICODE_STRING *str )
80 if (!str) return "<null>";
81 return debugstr_wn( str->Buffer, str->Length / sizeof(WCHAR) );
84 static NTSTATUS NTAPI ntlm_LsaApInitializePackage( ULONG package_id, LSA_DISPATCH_TABLE *dispatch,
85 LSA_STRING *database, LSA_STRING *confidentiality,
86 LSA_STRING **package_name )
88 LSA_STRING *str;
89 char *ptr;
91 TRACE( "%08x, %p, %s, %s, %p\n", package_id, dispatch, debugstr_as(database), debugstr_as(confidentiality),
92 package_name );
94 if (!ntlm_funcs && __wine_init_unix_lib( instance, DLL_PROCESS_ATTACH, NULL, &ntlm_funcs ))
96 ERR( "no NTLM support, expect problems\n" );
97 return STATUS_UNSUCCESSFUL;
100 if (!(str = dispatch->AllocateLsaHeap( sizeof(*str) + sizeof("NTLM" )))) return STATUS_NO_MEMORY;
101 ptr = (char *)(str + 1);
102 memcpy( ptr, "NTLM", sizeof("NTLM") );
103 RtlInitString( str, ptr );
105 ntlm_package_id = package_id;
106 lsa_dispatch = *dispatch;
108 *package_name = str;
109 return STATUS_SUCCESS;
112 static NTSTATUS NTAPI ntlm_SpInitialize( ULONG_PTR package_id, SECPKG_PARAMETERS *params,
113 LSA_SECPKG_FUNCTION_TABLE *lsa_function_table )
115 TRACE( "%lu, %p, %p\n", package_id, params, lsa_function_table );
117 if (!ntlm_funcs && __wine_init_unix_lib( instance, DLL_PROCESS_ATTACH, NULL, &ntlm_funcs ))
119 ERR( "no NTLM support, expect problems\n" );
120 return STATUS_UNSUCCESSFUL;
122 return STATUS_SUCCESS;
125 static NTSTATUS NTAPI ntlm_SpGetInfo( SecPkgInfoW *info )
127 TRACE( "%p\n", info );
128 *info = ntlm_package_info;
129 return STATUS_SUCCESS;
132 static char *get_username_arg( const WCHAR *user, int user_len )
134 static const char arg[] = "--username=";
135 int len = sizeof(arg);
136 char *ret;
138 len += WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, user, user_len, NULL, 0, NULL, NULL );
139 if (!(ret = malloc( len ))) return NULL;
140 memcpy( ret, arg, sizeof(arg) - 1 );
141 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, user, user_len, ret + sizeof(arg) - 1,
142 len - sizeof(arg) + 1, NULL, NULL );
143 ret[len - 1] = 0;
144 return ret;
147 static char *get_domain_arg( const WCHAR *domain, int domain_len )
149 static const char arg[] = "--domain=";
150 int len = sizeof(arg);
151 char *ret;
153 len += WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain, domain_len, NULL, 0, NULL, NULL );
154 if (!(ret = malloc( len ))) return NULL;
155 memcpy( ret, arg, sizeof(arg) - 1 );
156 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain, domain_len, ret + sizeof(arg) - 1,
157 len - sizeof(arg) + 1, NULL, NULL );
158 ret[len - 1] = 0;
159 return ret;
162 #define WINE_NO_CACHED_CREDENTIALS 0x10000000
163 static NTSTATUS NTAPI ntlm_SpAcquireCredentialsHandle( UNICODE_STRING *principal, ULONG cred_use, LUID *logon_id,
164 void *auth_data, void *get_key_fn, void *get_key_arg,
165 LSA_SEC_HANDLE *handle, TimeStamp *expiry )
167 SECURITY_STATUS status = SEC_E_INSUFFICIENT_MEMORY;
168 struct ntlm_cred *cred = NULL;
169 WCHAR *domain = NULL, *user = NULL, *password = NULL;
170 SEC_WINNT_AUTH_IDENTITY_W *id = NULL;
172 TRACE( "%s, 0x%08x, %p, %p, %p, %p, %p, %p\n", debugstr_us(principal), cred_use, logon_id, auth_data,
173 get_key_fn, get_key_arg, cred, expiry );
175 switch (cred_use & ~SECPKG_CRED_RESERVED)
177 case SECPKG_CRED_INBOUND:
178 if (!(cred = malloc( sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY;
179 cred->mode = MODE_SERVER;
180 cred->username_arg = NULL;
181 cred->domain_arg = NULL;
182 cred->password = NULL;
183 cred->password_len = 0;
184 cred->no_cached_credentials = 0;
186 *handle = (LSA_SEC_HANDLE)cred;
187 status = SEC_E_OK;
188 break;
190 case SECPKG_CRED_OUTBOUND:
191 if (!(cred = malloc( sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY;
193 cred->mode = MODE_CLIENT;
194 cred->username_arg = NULL;
195 cred->domain_arg = NULL;
196 cred->password = NULL;
197 cred->password_len = 0;
198 cred->no_cached_credentials = (cred_use & WINE_NO_CACHED_CREDENTIALS);
200 if ((id = auth_data))
202 int domain_len = 0, user_len = 0, password_len = 0;
203 if (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
205 if (id->DomainLength)
207 domain_len = MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, NULL, 0 );
208 if (!(domain = malloc( sizeof(WCHAR) * domain_len ))) goto done;
209 MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, domain, domain_len );
211 if (id->UserLength)
213 user_len = MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, NULL, 0 );
214 if (!(user = malloc( sizeof(WCHAR) * user_len ))) goto done;
215 MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, user, user_len );
217 if (id->PasswordLength)
219 password_len = MultiByteToWideChar( CP_ACP, 0,(char *)id->Password, id->PasswordLength, NULL, 0 );
220 if (!(password = malloc( sizeof(WCHAR) * password_len ))) goto done;
221 MultiByteToWideChar( CP_ACP, 0, (char *)id->Password, id->PasswordLength, password, password_len );
224 else
226 domain = id->Domain;
227 domain_len = id->DomainLength;
228 user = id->User;
229 user_len = id->UserLength;
230 password = id->Password;
231 password_len = id->PasswordLength;
234 TRACE( "username is %s\n", debugstr_wn(user, user_len) );
235 TRACE( "domain name is %s\n", debugstr_wn(domain, domain_len) );
237 cred->username_arg = get_username_arg( user, user_len );
238 cred->domain_arg = get_domain_arg( domain, domain_len );
239 if (password_len)
241 cred->password_len = WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len,
242 NULL, 0, NULL, NULL );
243 if (!(cred->password = malloc( cred->password_len ))) goto done;
244 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len, cred->password,
245 cred->password_len, NULL, NULL );
249 *handle = (LSA_SEC_HANDLE)cred;
250 status = SEC_E_OK;
251 break;
253 case SECPKG_CRED_BOTH:
254 FIXME( "SECPKG_CRED_BOTH not supported\n" );
255 status = SEC_E_UNSUPPORTED_FUNCTION;
256 break;
258 default:
259 status = SEC_E_UNKNOWN_CREDENTIALS;
260 break;
263 done:
264 if (id && (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI))
266 free( domain );
267 free( user );
268 free( password );
270 if (status != SEC_E_OK) free( cred );
271 return status;
274 static NTSTATUS NTAPI ntlm_SpFreeCredentialsHandle( LSA_SEC_HANDLE handle )
276 struct ntlm_cred *cred = (struct ntlm_cred *)handle;
278 TRACE( "%lx\n", handle );
280 if (!cred) return SEC_E_OK;
282 cred->mode = MODE_INVALID;
283 if (cred->password) memset( cred->password, 0, cred->password_len );
284 free( cred->password );
285 free( cred->username_arg );
286 free( cred->domain_arg );
287 free( cred );
288 return SEC_E_OK;
291 static BOOL get_cached_credential( const UNICODE_STRING *target, CREDENTIALW **cred )
293 const WCHAR *ptr, *host;
294 WCHAR *hostonly;
295 size_t len;
296 BOOL ret;
298 if (!target) return FALSE;
300 len = target->Length / sizeof(WCHAR);
301 if ((host = wmemchr( target->Buffer, '/', len )))
303 host++;
304 len -= host - target->Buffer;
305 if (!(ptr = wmemchr( host, ':', len ))) ptr = wmemchr( host, '/', len );
306 if (!ptr) ptr = host + len;
308 else
310 host = target->Buffer;
311 ptr = host + len;
314 if (!(hostonly = malloc( (ptr - host + 1) * sizeof(WCHAR) ))) return FALSE;
315 memcpy( hostonly, host, (ptr - host) * sizeof(WCHAR) );
316 hostonly[ptr - host] = 0;
318 ret = CredReadW( hostonly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred );
319 free( hostonly );
320 return ret;
323 static UINT encode_base64( const char *bin, unsigned int len, char *base64 )
325 static const char base64enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
326 UINT n = 0, x;
328 while (len > 0)
330 /* first 6 bits, all from bin[0] */
331 base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
332 x = (bin[0] & 3) << 4;
334 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
335 if (len == 1)
337 base64[n++] = base64enc[x];
338 base64[n++] = '=';
339 base64[n++] = '=';
340 break;
342 base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
343 x = (bin[1] & 0x0f) << 2;
345 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
346 if (len == 2)
348 base64[n++] = base64enc[x];
349 base64[n++] = '=';
350 break;
352 base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
354 /* last 6 bits, all from bin[2] */
355 base64[n++] = base64enc[bin[2] & 0x3f];
356 bin += 3;
357 len -= 3;
359 base64[n] = 0;
360 return n;
363 static inline char decode_char( char c )
365 if (c >= 'A' && c <= 'Z') return c - 'A';
366 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
367 if (c >= '0' && c <= '9') return c - '0' + 52;
368 if (c == '+') return 62;
369 if (c == '/') return 63;
370 return 64;
373 static unsigned int decode_base64( const char *base64, unsigned int len, char *buf )
375 unsigned int i = 0;
376 char c0, c1, c2, c3;
377 const char *p = base64;
379 while (len > 4)
381 if ((c0 = decode_char( p[0] )) > 63) return 0;
382 if ((c1 = decode_char( p[1] )) > 63) return 0;
383 if ((c2 = decode_char( p[2] )) > 63) return 0;
384 if ((c3 = decode_char( p[3] )) > 63) return 0;
385 if (buf)
387 buf[i + 0] = (c0 << 2) | (c1 >> 4);
388 buf[i + 1] = (c1 << 4) | (c2 >> 2);
389 buf[i + 2] = (c2 << 6) | c3;
391 len -= 4;
392 i += 3;
393 p += 4;
395 if (p[2] == '=')
397 if ((c0 = decode_char( p[0] )) > 63) return 0;
398 if ((c1 = decode_char( p[1] )) > 63) return 0;
399 if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
400 i++;
402 else if (p[3] == '=')
404 if ((c0 = decode_char( p[0] )) > 63) return 0;
405 if ((c1 = decode_char( p[1] )) > 63) return 0;
406 if ((c2 = decode_char( p[2] )) > 63) return 0;
407 if (buf)
409 buf[i + 0] = (c0 << 2) | (c1 >> 4);
410 buf[i + 1] = (c1 << 4) | (c2 >> 2);
412 i += 2;
414 else
416 if ((c0 = decode_char( p[0] )) > 63) return 0;
417 if ((c1 = decode_char( p[1] )) > 63) return 0;
418 if ((c2 = decode_char( p[2] )) > 63) return 0;
419 if ((c3 = decode_char( p[3] )) > 63) return 0;
420 if (buf)
422 buf[i + 0] = (c0 << 2) | (c1 >> 4);
423 buf[i + 1] = (c1 << 4) | (c2 >> 2);
424 buf[i + 2] = (c2 << 6) | c3;
426 i += 3;
428 return i;
431 struct md4_ctx
433 unsigned int buf[4];
434 unsigned int i[2];
435 unsigned char in[64];
436 unsigned char digest[16];
439 void WINAPI MD4Init( struct md4_ctx * );
440 void WINAPI MD4Update( struct md4_ctx *, const char *, unsigned int );
441 void WINAPI MD4Final( struct md4_ctx * );
443 static void create_ntlm1_session_key( const char *secret, unsigned int len, char *session_key )
445 struct md4_ctx ctx;
446 char hash[16];
448 MD4Init( &ctx );
449 MD4Update( &ctx, secret, len );
450 MD4Final( &ctx );
451 memcpy( hash, ctx.digest, 16 );
453 MD4Init( &ctx );
454 MD4Update( &ctx, hash, 16 );
455 MD4Final( &ctx );
456 memcpy( session_key, ctx.digest, 16 );
459 struct md5_ctx
461 unsigned int i[2];
462 unsigned int buf[4];
463 unsigned char in[64];
464 unsigned char digest[16];
467 void WINAPI MD5Init( struct md5_ctx * );
468 void WINAPI MD5Update( struct md5_ctx *, const char *, unsigned int );
469 void WINAPI MD5Final( struct md5_ctx * );
471 static void calc_ntlm2_subkey( const char *session_key, const char *magic, char *subkey )
473 struct md5_ctx ctx;
475 MD5Init( &ctx );
476 MD5Update( &ctx, session_key, 16 );
477 MD5Update( &ctx, magic, strlen(magic) + 1 );
478 MD5Final( &ctx );
479 memcpy( subkey, ctx.digest, 16 );
482 static const char client_to_server_sign_constant[] = "session key to client-to-server signing key magic constant";
483 static const char client_to_server_seal_constant[] = "session key to client-to-server sealing key magic constant";
484 static const char server_to_client_sign_constant[] = "session key to server-to-client signing key magic constant";
485 static const char server_to_client_seal_constant[] = "session key to server-to-client sealing key magic constant";
487 static void create_ntlm2_subkeys( struct ntlm_ctx *ctx )
489 if (ctx->mode == MODE_CLIENT)
491 calc_ntlm2_subkey( ctx->session_key, client_to_server_sign_constant, ctx->crypt.ntlm2.send_sign_key );
492 calc_ntlm2_subkey( ctx->session_key, client_to_server_seal_constant, ctx->crypt.ntlm2.send_seal_key );
493 calc_ntlm2_subkey( ctx->session_key, server_to_client_sign_constant, ctx->crypt.ntlm2.recv_sign_key );
494 calc_ntlm2_subkey( ctx->session_key, server_to_client_seal_constant, ctx->crypt.ntlm2.recv_seal_key );
496 else
498 calc_ntlm2_subkey( ctx->session_key, server_to_client_sign_constant, ctx->crypt.ntlm2.send_sign_key );
499 calc_ntlm2_subkey( ctx->session_key, server_to_client_seal_constant, ctx->crypt.ntlm2.send_seal_key );
500 calc_ntlm2_subkey( ctx->session_key, client_to_server_sign_constant, ctx->crypt.ntlm2.recv_sign_key );
501 calc_ntlm2_subkey( ctx->session_key, client_to_server_seal_constant, ctx->crypt.ntlm2.recv_seal_key );
506 * The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack,
507 * which in turn is based on public domain code by Wei Dai
509 static void arc4_init( struct arc4_info *info, const char *key, unsigned int len )
511 unsigned int key_idx = 0, state_idx = 0, i, a;
513 info->x = info->y = 0;
514 for (i = 0; i < 256; i++) info->state[i] = i;
516 for (i = 0; i < 256; i++)
518 a = info->state[i];
519 state_idx += key[key_idx] + a;
520 state_idx &= 0xff;
521 info->state[i] = info->state[state_idx];
522 info->state[state_idx] = a;
523 if (++key_idx >= len) key_idx = 0;
527 static void arc4_process( struct arc4_info *info, char *buf, unsigned int len )
529 char *state = info->state;
530 unsigned int x = info->x, y = info->y, a, b;
532 while (len--)
534 x = (x + 1) & 0xff;
535 a = state[x];
536 y = (y + a) & 0xff;
537 b = state[y];
538 state[x] = b;
539 state[y] = a;
540 *buf++ ^= state[(a + b) & 0xff];
543 info->x = x;
544 info->y = y;
547 static int get_buffer_index( SecBufferDesc *desc, ULONG type )
549 int idx;
550 for (idx = 0; idx < desc->cBuffers; idx++)
552 if (desc->pBuffers[idx].BufferType == type) return idx;
554 return -1;
557 static NTSTATUS NTAPI ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA_SEC_HANDLE ctx_handle,
558 UNICODE_STRING *target, ULONG ctx_req, ULONG data_rep,
559 SecBufferDesc *input, LSA_SEC_HANDLE *new_ctx_handle,
560 SecBufferDesc *output, ULONG *ctx_attr, TimeStamp *expiry,
561 BOOLEAN *mapped_ctx, SecBuffer *ctx_data )
563 NTSTATUS status = SEC_E_INSUFFICIENT_MEMORY;
564 struct ntlm_ctx *ctx = NULL;
565 char *buf, *bin, *want_flags = NULL, *username = NULL, *domain = NULL, *password = NULL;
566 unsigned int len, bin_len;
567 int idx;
569 TRACE( "%lx, %lx, %s, 0x%08x, %u, %p, %p, %p, %p, %p, %p, %p\n", cred_handle, ctx_handle, debugstr_us(target),
570 ctx_req, data_rep, input, new_ctx_handle, output, ctx_attr, expiry, mapped_ctx, ctx_data );
572 /* when communicating with the client there can be the following reply packets:
573 * YR <base64 blob> should be sent to the server
574 * PW should be sent back to helper with base64 encoded password
575 * AF <base64 blob> client is done, blob should be sent to server with KK prefixed
576 * GF <string list> a string list of negotiated flags
577 * GK <base64 blob> base64 encoded session key
578 * BH <char reason> something broke
580 * The squid cache size is 2010 chars and that's what ntlm_auth uses */
582 if (!(buf = malloc( NTLM_MAX_BUF ))) return SEC_E_INSUFFICIENT_MEMORY;
583 if (!(bin = malloc( NTLM_MAX_BUF ))) goto done;
585 if (!ctx_handle && !input)
587 char *argv[5];
588 int password_len = 0;
589 struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
591 if (!cred || cred->mode != MODE_CLIENT)
593 status = SEC_E_INVALID_HANDLE;
594 goto done;
597 argv[0] = (char *)"ntlm_auth";
598 argv[1] = (char *)"--helper-protocol=ntlmssp-client-1";
599 if (!cred->username_arg && !cred->domain_arg)
601 WKSTA_USER_INFO_1 *ui = NULL;
602 NET_API_STATUS ret;
603 CREDENTIALW *cached;
605 if (get_cached_credential( target, &cached ))
607 WCHAR *p;
608 if ((p = wcschr( cached->UserName, '\\' )))
610 if (!(domain = get_domain_arg( cached->UserName, p - cached->UserName ))) goto done;
611 p++;
613 else
615 if (!(domain = get_domain_arg( NULL, 0 ))) goto done;
616 p = cached->UserName;
618 if (!(username = get_username_arg( p, -1 ))) goto done;
620 if (cached->CredentialBlobSize)
622 password_len = WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, (WCHAR *)cached->CredentialBlob,
623 cached->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL );
624 if (!(password = malloc( password_len ))) goto done;
625 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, (WCHAR *)cached->CredentialBlob,
626 cached->CredentialBlobSize / sizeof(WCHAR), password, password_len, NULL, NULL );
628 CredFree( cached );
630 argv[2] = username;
631 argv[3] = domain;
632 argv[4] = NULL;
634 else
636 ret = NetWkstaUserGetInfo( NULL, 1, (BYTE **)&ui );
637 if (ret != NERR_Success || !ui || cred->no_cached_credentials)
639 status = SEC_E_NO_CREDENTIALS;
640 goto done;
642 if (!(username = get_username_arg( ui->wkui1_username, -1 ))) goto done;
643 NetApiBufferFree( ui );
644 TRACE("using cached credentials\n");
646 argv[2] = username;
647 argv[3] = (char *)"--use-cached-creds";
648 argv[4] = NULL;
651 else
653 argv[2] = cred->username_arg;
654 argv[3] = cred->domain_arg;
655 argv[4] = NULL;
658 if ((status = ntlm_funcs->fork( argv, &ctx )) != SEC_E_OK) goto done;
659 status = SEC_E_INSUFFICIENT_MEMORY;
661 ctx->mode = MODE_CLIENT;
662 memset( ctx->session_key, 0, sizeof(ctx->session_key) );
664 /* generate the dummy session key = MD4(MD4(password))*/
665 if (password || cred->password)
667 WCHAR *passwordW;
668 len = MultiByteToWideChar( CP_ACP, 0, password ? password : cred->password,
669 password ? password_len : cred->password_len, NULL, 0 );
670 if (!(passwordW = malloc( len * sizeof(WCHAR) ))) goto done;
671 MultiByteToWideChar( CP_ACP, 0, password ? password : cred->password,
672 password ? password_len : cred->password_len, passwordW, len );
674 create_ntlm1_session_key( (const char *)passwordW, len * sizeof(WCHAR), ctx->session_key );
675 free( passwordW );
678 /* allocate space for a maximum string of
679 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL NTLMSSP_FEATURE_SESSION_KEY"
681 if (!(want_flags = malloc( 73 ))) goto done;
682 strcpy( want_flags, "SF" );
683 if (ctx_req & ISC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
684 if ((ctx_req & ISC_REQ_INTEGRITY) || (ctx_req & ISC_REQ_REPLAY_DETECT) ||
685 (ctx_req & ISC_REQ_SEQUENCE_DETECT)) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
687 if (ctx_req & ISC_REQ_CONNECTION) ctx->attrs |= ISC_RET_CONNECTION;
688 if (ctx_req & ISC_REQ_EXTENDED_ERROR) ctx->attrs |= ISC_RET_EXTENDED_ERROR;
689 if (ctx_req & ISC_REQ_MUTUAL_AUTH) ctx->attrs |= ISC_RET_MUTUAL_AUTH;
690 if (ctx_req & ISC_REQ_USE_DCE_STYLE) ctx->attrs |= ISC_RET_USED_DCE_STYLE;
691 if (ctx_req & ISC_REQ_DELEGATE) ctx->attrs |= ISC_RET_DELEGATE;
692 if (ctx_req & ISC_REQ_STREAM) FIXME( "ISC_REQ_STREAM\n" );
694 /* use cached credentials if no password was given, fall back to an empty password on failure */
695 if (!password && !cred->password)
697 strcpy( buf, "OK" );
698 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
700 /* if the helper replied with "PW" using cached credentials failed */
701 if (!strncmp( buf, "PW", 2 ))
703 TRACE( "using cached credentials failed\n" );
704 strcpy( buf, "PW AA==" );
706 else strcpy( buf, "OK" ); /* just do a noop on the next run */
708 else
710 strcpy( buf, "PW " );
711 encode_base64( password ? password : cred->password, password ? password_len : cred->password_len, buf + 3 );
714 TRACE( "sending to ntlm_auth: %s\n", debugstr_a(buf) );
715 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
716 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf) );
718 if (strlen( want_flags ) > 2)
720 TRACE( "want flags are %s\n", debugstr_a(want_flags) );
721 strcpy( buf, want_flags );
722 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
723 if (!strncmp( buf, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
726 strcpy( buf, "YR" );
727 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
728 TRACE( "ntlm_auth returned %s\n", buf );
729 if (strncmp( buf, "YR ", 3 ))
731 status = SEC_E_INTERNAL_ERROR;
732 goto done;
734 bin_len = decode_base64( buf + 3, len - 3, bin );
736 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
737 status = SEC_I_CONTINUE_NEEDED;
739 else /* !ctx_handle && !input */
741 if (!input || ((idx = get_buffer_index( input, SECBUFFER_TOKEN )) == -1))
743 status = SEC_E_INVALID_TOKEN;
744 goto done;
747 ctx = (struct ntlm_ctx *)ctx_handle;
748 if (!ctx || ctx->mode != MODE_CLIENT)
750 status = SEC_E_INVALID_HANDLE;
751 goto done;
754 if (!input->pBuffers[idx].pvBuffer || input->pBuffers[idx].cbBuffer > NTLM_MAX_BUF)
756 status = SEC_E_INVALID_TOKEN;
757 goto done;
759 bin_len = input->pBuffers[idx].cbBuffer;
760 memcpy( bin, input->pBuffers[idx].pvBuffer, bin_len );
762 strcpy( buf, "TT " );
763 encode_base64( bin, bin_len, buf + 3 );
764 TRACE( "server sent: %s\n", debugstr_a(buf) );
766 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len ))) goto done;
767 TRACE( "ntlm_auth returned: %s\n", debugstr_a(buf) );
769 if (strncmp( buf, "KK ", 3 ) && strncmp( buf, "AF ", 3 ))
771 status = SEC_E_INVALID_TOKEN;
772 goto done;
774 bin_len = decode_base64( buf + 3, len - 3, bin );
776 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
777 status = SEC_E_OK;
780 if (!output || ((idx = get_buffer_index( output, SECBUFFER_TOKEN )) == -1))
782 if (!ctx_handle && !input) *new_ctx_handle = 0;
783 status = SEC_E_BUFFER_TOO_SMALL;
784 goto done;
787 if (ctx_req & ISC_REQ_ALLOCATE_MEMORY)
789 /* freed with secur32.FreeContextBuffer */
790 if (!(output->pBuffers[idx].pvBuffer = RtlAllocateHeap( GetProcessHeap(), 0, bin_len )))
792 status = SEC_E_INSUFFICIENT_MEMORY;
793 goto done;
795 output->pBuffers[idx].cbBuffer = bin_len;
797 else if (output->pBuffers[idx].cbBuffer < bin_len)
799 if (!ctx_handle && !input) *new_ctx_handle = 0;
800 status = SEC_E_BUFFER_TOO_SMALL;
801 goto done;
804 if (!output->pBuffers[idx].pvBuffer)
806 if (!ctx_handle && !input) *new_ctx_handle = 0;
807 status = SEC_E_INTERNAL_ERROR;
808 goto done;
811 output->pBuffers[idx].cbBuffer = bin_len;
812 memcpy( output->pBuffers[idx].pvBuffer, bin, bin_len );
813 if (status == SEC_E_OK)
815 strcpy( buf, "GF" );
816 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
817 if (len < 3) ctx->flags = 0;
818 else sscanf( buf + 3, "%x", &ctx->flags );
820 strcpy( buf, "GK" );
821 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
823 if (!strncmp( buf, "BH", 2 )) TRACE( "no key negotiated\n" );
824 else if (!strncmp( buf, "GK ", 3 ))
826 bin_len = decode_base64( buf + 3, len - 3, bin );
827 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
828 memcpy( ctx->session_key, bin, bin_len );
831 arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
832 ctx->crypt.ntlm.seq_no = 0;
833 create_ntlm2_subkeys( ctx );
834 arc4_init( &ctx->crypt.ntlm2.send_arc4info, ctx->crypt.ntlm2.send_seal_key, 16 );
835 arc4_init( &ctx->crypt.ntlm2.recv_arc4info, ctx->crypt.ntlm2.recv_seal_key, 16 );
836 ctx->crypt.ntlm2.send_seq_no = 0;
837 ctx->crypt.ntlm2.recv_seq_no = 0;
840 done:
841 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) ntlm_funcs->cleanup( ctx );
842 free( username );
843 free( domain );
844 free( password );
845 free( buf );
846 free( bin );
847 free( want_flags );
849 TRACE( "returning %08x\n", status );
850 return status;
853 static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA_SEC_HANDLE ctx_handle,
854 SecBufferDesc *input, ULONG ctx_req, ULONG data_rep,
855 LSA_SEC_HANDLE *new_ctx_handle, SecBufferDesc *output,
856 ULONG *ctx_attr, TimeStamp *expiry, BOOLEAN *mapped_ctx,
857 SecBuffer *ctx_data )
859 NTSTATUS status = SEC_E_INSUFFICIENT_MEMORY;
860 struct ntlm_ctx *ctx = NULL;
861 char *buf, *bin, *want_flags = NULL;
862 unsigned int len, bin_len;
864 TRACE( "%lx, %lx, %08x, %u, %p, %p, %p, %p, %p, %p, %p\n", cred_handle, ctx_handle, ctx_req, data_rep, input,
865 new_ctx_handle, output, ctx_attr, expiry, mapped_ctx, ctx_data );
866 if (ctx_req) FIXME( "ignoring flags %08x\n", ctx_req );
868 if (!(buf = malloc( NTLM_MAX_BUF ))) return SEC_E_INSUFFICIENT_MEMORY;
869 if (!(bin = malloc( NTLM_MAX_BUF ))) goto done;
871 if (!ctx_handle)
873 struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
874 char *argv[3];
876 if (!cred || cred->mode != MODE_SERVER)
878 status = SEC_E_INVALID_HANDLE;
879 goto done;
882 if (!input || input->cBuffers < 1)
884 status = SEC_E_INCOMPLETE_MESSAGE;
885 goto done;
888 if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
890 status = SEC_E_INVALID_TOKEN;
891 goto done;
893 else bin_len = input->pBuffers[0].cbBuffer;
895 argv[0] = (char *)"ntlm_auth";
896 argv[1] = (char *)"--helper-protocol=squid-2.5-ntlmssp";
897 argv[2] = NULL;
898 if ((status = ntlm_funcs->fork( argv, &ctx )) != SEC_E_OK) goto done;
899 ctx->mode = MODE_SERVER;
901 if (!(want_flags = malloc( 73 )))
903 status = SEC_E_INSUFFICIENT_MEMORY;
904 goto done;
906 strcpy( want_flags, "SF" );
907 if (ctx_req & ASC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
908 if (ctx_req & ASC_REQ_CONNECTION)
910 strcat( want_flags, " NTLMSSP_FEATURE_SESSION_KEY" );
911 ctx->attrs |= ASC_RET_CONNECTION;
913 if (ctx_req & ASC_REQ_INTEGRITY) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
914 if (ctx_req & ASC_REQ_ALLOCATE_MEMORY) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
915 if (ctx_req & ASC_REQ_EXTENDED_ERROR) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
916 if (ctx_req & ASC_REQ_MUTUAL_AUTH) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
917 if (ctx_req & ASC_REQ_REPLAY_DETECT) FIXME( "ASC_REQ_REPLAY_DETECT\n" );
918 if (ctx_req & ASC_REQ_SEQUENCE_DETECT) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
919 if (ctx_req & ASC_REQ_STREAM) FIXME( "ASC_REQ_STREAM\n" );
921 if (strlen( want_flags ) > 3)
923 TRACE( "want flags are %s\n", debugstr_a(want_flags) );
924 strcpy( buf, want_flags );
925 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
926 if (!strncmp( buf, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
929 memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
930 strcpy( buf, "YR " );
931 encode_base64( bin, bin_len, buf + 3 );
933 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
934 TRACE( "ntlm_auth returned %s\n", buf );
935 if (strncmp( buf, "TT ", 3))
937 status = SEC_E_INTERNAL_ERROR;
938 goto done;
940 bin_len = decode_base64( buf + 3, len - 3, bin );
942 if (!output || output->cBuffers < 1)
944 status = SEC_E_INSUFFICIENT_MEMORY;
945 goto done;
947 output->pBuffers[0].cbBuffer = bin_len;
948 output->pBuffers[0].BufferType = SECBUFFER_DATA;
949 memcpy( output->pBuffers[0].pvBuffer, bin, bin_len );
951 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
952 status = SEC_I_CONTINUE_NEEDED;
954 else
956 if (!input || input->cBuffers < 1)
958 status = SEC_E_INCOMPLETE_MESSAGE;
959 goto done;
962 ctx = (struct ntlm_ctx *)ctx_handle;
963 if (!ctx || ctx->mode != MODE_SERVER)
965 status = SEC_E_INVALID_HANDLE;
966 goto done;
969 if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
971 status = SEC_E_INVALID_TOKEN;
972 goto done;
974 else bin_len = input->pBuffers[0].cbBuffer;
975 memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
977 strcpy( buf, "KK " );
978 encode_base64( bin, bin_len, buf + 3 );
980 TRACE( "client sent %s\n", debugstr_a(buf) );
981 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
982 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf) );
984 /* At this point, we get a NA if the user didn't authenticate, but a BH if ntlm_auth could not
985 * connect to winbindd. Apart from running Wine as root, there is no way to fix this for now,
986 * so just handle this as a failed login. */
987 if (strncmp( buf, "AF ", 3 ))
989 if (!strncmp( buf, "NA ", 3 ))
991 status = SEC_E_LOGON_DENIED;
992 goto done;
994 else
996 const char err_v3[] = "BH NT_STATUS_ACCESS_DENIED";
997 const char err_v4[] = "BH NT_STATUS_UNSUCCESSFUL";
999 if ((len >= strlen(err_v3) && !strncmp( buf, err_v3, strlen(err_v3) )) ||
1000 (len >= strlen(err_v4) && !strncmp( buf, err_v4, strlen(err_v4) )))
1002 TRACE( "connection to winbindd failed\n" );
1003 status = SEC_E_LOGON_DENIED;
1005 else status = SEC_E_INTERNAL_ERROR;
1006 goto done;
1009 output->pBuffers[0].cbBuffer = 0;
1011 strcpy( buf, "GF" );
1012 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1013 if (len < 3) ctx->flags = 0;
1014 else sscanf( buf + 3, "%x", &ctx->flags );
1016 strcpy( buf, "GK" );
1017 if ((status = ntlm_funcs->chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1019 if (!strncmp( buf, "BH", 2 )) TRACE( "no key negotiated\n" );
1020 else if (!strncmp( buf, "GK ", 3 ))
1022 bin_len = decode_base64( buf + 3, len - 3, bin );
1023 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
1024 memcpy( ctx->session_key, bin, bin_len );
1027 if (len < 3) memset( ctx->session_key, 0 , 16 );
1028 else
1030 if (!strncmp( buf, "BH ", 3 ))
1032 TRACE( "helper sent %s\n", debugstr_a(buf + 3) );
1033 /*FIXME: generate dummy session key = MD4(MD4(password))*/
1034 memset( ctx->session_key, 0 , 16 );
1036 else if (!strncmp( buf, "GK ", 3 ))
1038 bin_len = decode_base64( buf + 3, len - 3, bin );
1039 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
1040 memcpy( ctx->session_key, bin, 16 );
1043 arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
1044 ctx->crypt.ntlm.seq_no = 0;
1046 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
1047 status = SEC_E_OK;
1050 done:
1051 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) ntlm_funcs->cleanup( ctx );
1052 free( buf );
1053 free( bin );
1054 free( want_flags );
1056 TRACE( "returning %08x\n", status );
1057 return status;
1060 static NTSTATUS NTAPI ntlm_SpDeleteContext( LSA_SEC_HANDLE handle )
1062 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1064 TRACE( "%lx\n", handle );
1066 if (!ctx) return SEC_E_INVALID_HANDLE;
1067 ntlm_funcs->cleanup( ctx );
1068 return SEC_E_OK;
1071 static SecPkgInfoW *build_package_info( const SecPkgInfoW *info )
1073 SecPkgInfoW *ret;
1074 DWORD size_name = (wcslen(info->Name) + 1) * sizeof(WCHAR);
1075 DWORD size_comment = (wcslen(info->Comment) + 1) * sizeof(WCHAR);
1077 if (!(ret = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*ret) + size_name + size_comment ))) return NULL;
1078 ret->fCapabilities = info->fCapabilities;
1079 ret->wVersion = info->wVersion;
1080 ret->wRPCID = info->wRPCID;
1081 ret->cbMaxToken = info->cbMaxToken;
1082 ret->Name = (SEC_WCHAR *)(ret + 1);
1083 memcpy( ret->Name, info->Name, size_name );
1084 ret->Comment = (SEC_WCHAR *)((char *)ret->Name + size_name);
1085 memcpy( ret->Comment, info->Comment, size_comment );
1086 return ret;
1089 static NTSTATUS NTAPI ntlm_SpQueryContextAttributes( LSA_SEC_HANDLE handle, ULONG attr, void *buf )
1091 TRACE( "%lx, %u, %p\n", handle, attr, buf );
1093 if (!handle) return SEC_E_INVALID_HANDLE;
1095 switch (attr)
1097 #define X(x) case (x) : FIXME(#x" stub\n"); break
1098 X(SECPKG_ATTR_ACCESS_TOKEN);
1099 X(SECPKG_ATTR_AUTHORITY);
1100 X(SECPKG_ATTR_DCE_INFO);
1101 X(SECPKG_ATTR_KEY_INFO);
1102 X(SECPKG_ATTR_LIFESPAN);
1103 X(SECPKG_ATTR_NAMES);
1104 X(SECPKG_ATTR_NATIVE_NAMES);
1105 X(SECPKG_ATTR_PACKAGE_INFO);
1106 X(SECPKG_ATTR_PASSWORD_EXPIRY);
1107 X(SECPKG_ATTR_SESSION_KEY);
1108 X(SECPKG_ATTR_STREAM_SIZES);
1109 X(SECPKG_ATTR_TARGET_INFORMATION);
1110 case SECPKG_ATTR_FLAGS:
1112 SecPkgContext_Flags *flags = (SecPkgContext_Flags *)buf;
1113 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1115 flags->Flags = 0;
1116 if (ctx->flags & FLAG_NEGOTIATE_SIGN) flags->Flags |= ISC_RET_INTEGRITY;
1117 if (ctx->flags & FLAG_NEGOTIATE_SEAL) flags->Flags |= ISC_RET_CONFIDENTIALITY;
1118 return SEC_E_OK;
1120 case SECPKG_ATTR_SIZES:
1122 SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)buf;
1123 sizes->cbMaxToken = NTLM_MAX_BUF;
1124 sizes->cbMaxSignature = 16;
1125 sizes->cbBlockSize = 0;
1126 sizes->cbSecurityTrailer = 16;
1127 return SEC_E_OK;
1129 case SECPKG_ATTR_NEGOTIATION_INFO:
1131 SecPkgContext_NegotiationInfoW *info = (SecPkgContext_NegotiationInfoW *)buf;
1132 if (!(info->PackageInfo = build_package_info( &ntlm_package_info ))) return SEC_E_INSUFFICIENT_MEMORY;
1133 info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE;
1134 return SEC_E_OK;
1136 #undef X
1137 default:
1138 FIXME( "unknown attribute %u\n", attr );
1139 break;
1142 return SEC_E_UNSUPPORTED_FUNCTION;
1145 static SECPKG_FUNCTION_TABLE ntlm_table =
1147 ntlm_LsaApInitializePackage,
1148 NULL, /* LsaLogonUser */
1149 NULL, /* CallPackage */
1150 NULL, /* LogonTerminated */
1151 NULL, /* CallPackageUntrusted */
1152 NULL, /* CallPackagePassthrough */
1153 NULL, /* LogonUserEx */
1154 NULL, /* LogonUserEx2 */
1155 ntlm_SpInitialize,
1156 NULL, /* SpShutdown */
1157 ntlm_SpGetInfo,
1158 NULL, /* AcceptCredentials */
1159 ntlm_SpAcquireCredentialsHandle,
1160 NULL, /* SpQueryCredentialsAttributes */
1161 ntlm_SpFreeCredentialsHandle,
1162 NULL, /* SaveCredentials */
1163 NULL, /* GetCredentials */
1164 NULL, /* DeleteCredentials */
1165 ntlm_SpInitLsaModeContext,
1166 ntlm_SpAcceptLsaModeContext,
1167 ntlm_SpDeleteContext,
1168 NULL, /* ApplyControlToken */
1169 NULL, /* GetUserInfo */
1170 NULL, /* GetExtendedInformation */
1171 ntlm_SpQueryContextAttributes,
1172 NULL, /* SpAddCredentials */
1173 NULL, /* SetExtendedInformation */
1174 NULL, /* SetContextAttributes */
1175 NULL, /* SetCredentialsAttributes */
1176 NULL, /* ChangeAccountPassword */
1177 NULL, /* QueryMetaData */
1178 NULL, /* ExchangeMetaData */
1179 NULL, /* GetCredUIContext */
1180 NULL, /* UpdateCredentials */
1181 NULL, /* ValidateTargetInfo */
1182 NULL, /* PostLogonUser */
1185 NTSTATUS NTAPI SpLsaModeInitialize( ULONG lsa_version, ULONG *package_version, SECPKG_FUNCTION_TABLE **table,
1186 ULONG *table_count )
1188 TRACE( "%08x, %p, %p, %p\n", lsa_version, package_version, table, table_count );
1190 *package_version = SECPKG_INTERFACE_VERSION;
1191 *table = &ntlm_table;
1192 *table_count = 1;
1193 return STATUS_SUCCESS;
1196 static NTSTATUS NTAPI ntlm_SpInstanceInit( ULONG version, SECPKG_DLL_FUNCTIONS *dll_functions, void **user_functions )
1198 TRACE( "%08x, %p, %p\n", version, dll_functions, user_functions );
1199 return STATUS_SUCCESS;
1202 struct hmac_md5_ctx
1204 struct md5_ctx ctx;
1205 char outer_padding[64];
1208 static void hmac_md5_init( struct hmac_md5_ctx *ctx, const char *key, unsigned int key_len )
1210 char inner_padding[64], tmp_key[16];
1211 unsigned int i;
1213 if (key_len > 64)
1215 struct md5_ctx tmp_ctx;
1217 MD5Init( &tmp_ctx );
1218 MD5Update( &tmp_ctx, key, key_len );
1219 MD5Final( &tmp_ctx );
1220 memcpy( tmp_key, tmp_ctx.digest, 16 );
1222 key = tmp_key;
1223 key_len = 16;
1226 memset( inner_padding, 0, 64 );
1227 memset( ctx->outer_padding, 0, 64 );
1228 memcpy( inner_padding, key, key_len );
1229 memcpy( ctx->outer_padding, key, key_len );
1231 for (i = 0; i < 64; i++)
1233 inner_padding[i] ^= 0x36;
1234 ctx->outer_padding[i] ^= 0x5c;
1237 MD5Init( &ctx->ctx );
1238 MD5Update( &ctx->ctx, inner_padding, 64 );
1241 static void hmac_md5_update( struct hmac_md5_ctx *ctx, const char *buf, unsigned int len )
1243 MD5Update( &ctx->ctx, buf, len );
1246 static void hmac_md5_final( struct hmac_md5_ctx *ctx, char *digest )
1248 struct md5_ctx outer_ctx;
1249 char inner_digest[16];
1251 MD5Final( &ctx->ctx );
1252 memcpy( inner_digest, ctx->ctx.digest, 16 );
1254 MD5Init( &outer_ctx );
1255 MD5Update( &outer_ctx, ctx->outer_padding, 64 );
1256 MD5Update( &outer_ctx, inner_digest, 16 );
1257 MD5Final( &outer_ctx );
1259 memcpy( digest, outer_ctx.digest, 16 );
1262 static SECURITY_STATUS create_signature( struct ntlm_ctx *ctx, unsigned int flags, SecBufferDesc *msg, int idx,
1263 enum sign_direction dir, BOOL encrypt )
1265 unsigned int i, sign_version = 1;
1266 char *sig = msg->pBuffers[idx].pvBuffer;
1268 if (flags & FLAG_NEGOTIATE_NTLM2 && flags & FLAG_NEGOTIATE_SIGN)
1270 char digest[16], seq_no[4];
1271 struct hmac_md5_ctx hmac_md5;
1273 if (dir == SIGN_SEND)
1275 seq_no[0] = (ctx->crypt.ntlm2.send_seq_no >> 0) & 0xff;
1276 seq_no[1] = (ctx->crypt.ntlm2.send_seq_no >> 8) & 0xff;
1277 seq_no[2] = (ctx->crypt.ntlm2.send_seq_no >> 16) & 0xff;
1278 seq_no[3] = (ctx->crypt.ntlm2.send_seq_no >> 24) & 0xff;
1279 ctx->crypt.ntlm2.send_seq_no++;
1281 hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.send_sign_key, 16 );
1283 else
1285 seq_no[0] = (ctx->crypt.ntlm2.recv_seq_no >> 0) & 0xff;
1286 seq_no[1] = (ctx->crypt.ntlm2.recv_seq_no >> 8) & 0xff;
1287 seq_no[2] = (ctx->crypt.ntlm2.recv_seq_no >> 16) & 0xff;
1288 seq_no[3] = (ctx->crypt.ntlm2.recv_seq_no >> 24) & 0xff;
1289 ctx->crypt.ntlm2.recv_seq_no++;
1291 hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.recv_sign_key, 16 );
1294 hmac_md5_update( &hmac_md5, seq_no, 4 );
1295 for (i = 0; i < msg->cBuffers; ++i)
1297 if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
1298 hmac_md5_update( &hmac_md5, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
1300 hmac_md5_final( &hmac_md5, digest );
1302 if (encrypt && flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1304 if (dir == SIGN_SEND)
1305 arc4_process( &ctx->crypt.ntlm2.send_arc4info, digest, 8 );
1306 else
1307 arc4_process( &ctx->crypt.ntlm2.recv_arc4info, digest, 8 );
1310 sig[0] = (sign_version >> 0) & 0xff;
1311 sig[1] = (sign_version >> 8) & 0xff;
1312 sig[2] = (sign_version >> 16) & 0xff;
1313 sig[3] = (sign_version >> 24) & 0xff;
1314 memcpy( sig + 4, digest, 8 );
1315 memcpy( sig + 12, seq_no, 4 );
1317 msg->pBuffers[idx].cbBuffer = 16;
1318 return SEC_E_OK;
1321 if (flags & FLAG_NEGOTIATE_SIGN)
1323 unsigned int crc = 0;
1325 for (i = 0; i < msg->cBuffers; ++i)
1327 if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
1328 crc = RtlComputeCrc32( crc, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
1331 sig[0] = (sign_version >> 0) & 0xff;
1332 sig[1] = (sign_version >> 8) & 0xff;
1333 sig[2] = (sign_version >> 16) & 0xff;
1334 sig[3] = (sign_version >> 24) & 0xff;
1335 memset( sig + 4, 0, 4 );
1336 sig[8] = (crc >> 0) & 0xff;
1337 sig[9] = (crc >> 8) & 0xff;
1338 sig[10] = (crc >> 16) & 0xff;
1339 sig[11] = (crc >> 24) & 0xff;
1340 sig[12] = (ctx->crypt.ntlm.seq_no >> 0) & 0xff;
1341 sig[13] = (ctx->crypt.ntlm.seq_no >> 8) & 0xff;
1342 sig[14] = (ctx->crypt.ntlm.seq_no >> 16) & 0xff;
1343 sig[15] = (ctx->crypt.ntlm.seq_no >> 24) & 0xff;
1344 ctx->crypt.ntlm.seq_no++;
1346 if (encrypt) arc4_process( &ctx->crypt.ntlm.arc4info, sig + 4, 12 );
1347 return SEC_E_OK;
1350 if (flags & FLAG_NEGOTIATE_ALWAYS_SIGN || !flags)
1352 /* create dummy signature */
1353 memset( msg->pBuffers[idx].pvBuffer, 0, 16 );
1354 memset( msg->pBuffers[idx].pvBuffer, 1, 1 );
1355 msg->pBuffers[idx].cbBuffer = 16;
1356 return SEC_E_OK;
1359 return SEC_E_UNSUPPORTED_FUNCTION;
1362 static NTSTATUS NTAPI ntlm_SpMakeSignature( LSA_SEC_HANDLE handle, ULONG qop, SecBufferDesc *msg, ULONG msg_seq_no )
1364 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1365 int idx;
1367 TRACE( "%lx, 0x%08x, %p, %u\n", handle, qop, msg, msg_seq_no );
1368 if (qop) FIXME( "ignoring quality of protection %08x\n", qop );
1369 if (msg_seq_no) FIXME( "ignoring message sequence number %u\n", msg_seq_no );
1371 if (!handle) return SEC_E_INVALID_HANDLE;
1372 if (!msg || !msg->pBuffers || msg->cBuffers < 2 || (idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1)
1373 return SEC_E_INVALID_TOKEN;
1374 if (msg->pBuffers[idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1376 return create_signature( ctx, ctx->flags, msg, idx, SIGN_SEND, TRUE );
1379 static NTSTATUS verify_signature( struct ntlm_ctx *ctx, unsigned int flags, SecBufferDesc *msg, int idx )
1381 NTSTATUS status;
1382 unsigned int i;
1383 SecBufferDesc desc;
1384 SecBuffer *buf;
1385 char sig[16];
1387 if (!(buf = malloc( msg->cBuffers * sizeof(*buf) ))) return SEC_E_INSUFFICIENT_MEMORY;
1388 desc.ulVersion = SECBUFFER_VERSION;
1389 desc.cBuffers = msg->cBuffers;
1390 desc.pBuffers = buf;
1392 for (i = 0; i < msg->cBuffers; i++)
1394 if (msg->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1396 buf[i].BufferType = SECBUFFER_TOKEN;
1397 buf[i].cbBuffer = 16;
1398 buf[i].pvBuffer = sig;
1400 else
1402 buf[i].BufferType = msg->pBuffers[i].BufferType;
1403 buf[i].cbBuffer = msg->pBuffers[i].cbBuffer;
1404 buf[i].pvBuffer = msg->pBuffers[i].pvBuffer;
1408 if ((status = create_signature( ctx, flags, &desc, idx, SIGN_RECV, TRUE )) == SEC_E_OK)
1410 if (memcmp( (char *)buf[idx].pvBuffer + 8, (char *)msg->pBuffers[idx].pvBuffer + 8, 8 ))
1411 status = SEC_E_MESSAGE_ALTERED;
1414 free( buf );
1415 return status;
1418 static NTSTATUS NTAPI ntlm_SpVerifySignature( LSA_SEC_HANDLE handle, SecBufferDesc *msg, ULONG msg_seq_no, ULONG *qop )
1420 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1421 int idx;
1423 TRACE( "%lx, %p, %u, %p\n", handle, msg, msg_seq_no, qop );
1424 if (msg_seq_no) FIXME( "ignoring message sequence number %u\n", msg_seq_no );
1426 if (!handle) return SEC_E_INVALID_HANDLE;
1427 if (!msg || !msg->pBuffers || msg->cBuffers < 2 || (idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1)
1428 return SEC_E_INVALID_TOKEN;
1429 if (msg->pBuffers[idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1431 return verify_signature( ctx, ctx->flags, msg, idx );
1434 static NTSTATUS NTAPI ntlm_SpSealMessage( LSA_SEC_HANDLE handle, ULONG qop, SecBufferDesc *msg, ULONG msg_seq_no )
1436 int token_idx, data_idx;
1437 struct ntlm_ctx *ctx;
1439 TRACE( "%lx, %08x, %p %u\n", handle, qop, msg, msg_seq_no );
1440 if (qop) FIXME( "ignoring quality of protection %08x\n", qop );
1441 if (msg_seq_no) FIXME( "ignoring message sequence number %u\n", msg_seq_no );
1443 if (!handle) return SEC_E_INVALID_HANDLE;
1445 if (!msg || !msg->pBuffers || msg->cBuffers < 2 ||
1446 (token_idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1 ||
1447 (data_idx = get_buffer_index( msg, SECBUFFER_DATA )) == -1) return SEC_E_INVALID_TOKEN;
1449 if (msg->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1451 ctx = (struct ntlm_ctx *)handle;
1452 if (ctx->flags & FLAG_NEGOTIATE_NTLM2 && ctx->flags & FLAG_NEGOTIATE_SEAL)
1454 create_signature( ctx, ctx->flags, msg, token_idx, SIGN_SEND, FALSE );
1456 arc4_process( &ctx->crypt.ntlm2.send_arc4info, msg->pBuffers[data_idx].pvBuffer,
1457 msg->pBuffers[data_idx].cbBuffer );
1458 if (ctx->flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1459 arc4_process( &ctx->crypt.ntlm2.send_arc4info, (char *)msg->pBuffers[token_idx].pvBuffer + 4, 8 );
1461 else
1463 char *sig = msg->pBuffers[token_idx].pvBuffer;
1465 create_signature( ctx, ctx->flags | FLAG_NEGOTIATE_SIGN, msg, token_idx, SIGN_SEND, FALSE );
1467 arc4_process( &ctx->crypt.ntlm.arc4info, msg->pBuffers[data_idx].pvBuffer, msg->pBuffers[data_idx].cbBuffer );
1468 arc4_process( &ctx->crypt.ntlm.arc4info, sig + 4, 12 );
1470 if (ctx->flags & FLAG_NEGOTIATE_ALWAYS_SIGN || !ctx->flags) memset( sig + 4, 0, 4 );
1473 return SEC_E_OK;
1476 static NTSTATUS NTAPI ntlm_SpUnsealMessage( LSA_SEC_HANDLE handle, SecBufferDesc *msg, ULONG msg_seq_no, ULONG *qop )
1478 int token_idx, data_idx;
1479 struct ntlm_ctx *ctx;
1481 TRACE( "%lx, %p, %u, %p\n", handle, msg, msg_seq_no, qop );
1482 if (msg_seq_no) FIXME( "ignoring message sequence number %u\n", msg_seq_no );
1484 if (!handle) return SEC_E_INVALID_HANDLE;
1486 if (!msg || !msg->pBuffers || msg->cBuffers < 2 ||
1487 (token_idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1 ||
1488 (data_idx = get_buffer_index( msg, SECBUFFER_DATA )) == -1) return SEC_E_INVALID_TOKEN;
1490 if (msg->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1492 ctx = (struct ntlm_ctx *)handle;
1493 if (ctx->flags & FLAG_NEGOTIATE_NTLM2 && ctx->flags & FLAG_NEGOTIATE_SEAL)
1494 arc4_process( &ctx->crypt.ntlm2.recv_arc4info, msg->pBuffers[data_idx].pvBuffer,
1495 msg->pBuffers[data_idx].cbBuffer );
1496 else
1497 arc4_process( &ctx->crypt.ntlm.arc4info, msg->pBuffers[data_idx].pvBuffer,
1498 msg->pBuffers[data_idx].cbBuffer);
1500 /* make sure we use a session key for the signature check, SealMessage always does that,
1501 even in the dummy case */
1502 return verify_signature( ctx, ctx->flags | FLAG_NEGOTIATE_SIGN, msg, token_idx );
1505 static SECPKG_USER_FUNCTION_TABLE ntlm_user_table =
1507 ntlm_SpInstanceInit,
1508 NULL, /* SpInitUserModeContext */
1509 ntlm_SpMakeSignature,
1510 ntlm_SpVerifySignature,
1511 ntlm_SpSealMessage,
1512 ntlm_SpUnsealMessage,
1513 NULL, /* SpGetContextToken */
1514 NULL, /* SpQueryContextAttributes */
1515 NULL, /* SpCompleteAuthToken */
1516 NULL, /* SpDeleteContext */
1517 NULL, /* SpFormatCredentialsFn */
1518 NULL, /* SpMarshallSupplementalCreds */
1519 NULL, /* SpExportSecurityContext */
1520 NULL /* SpImportSecurityContext */
1523 NTSTATUS NTAPI SpUserModeInitialize( ULONG lsa_version, ULONG *package_version, SECPKG_USER_FUNCTION_TABLE **table,
1524 ULONG *table_count )
1526 TRACE( "%08x, %p, %p, %p\n", lsa_version, package_version, table, table_count );
1528 *package_version = SECPKG_INTERFACE_VERSION;
1529 *table = &ntlm_user_table;
1530 *table_count = 1;
1531 return STATUS_SUCCESS;
1534 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved )
1536 switch (reason)
1538 case DLL_PROCESS_ATTACH:
1539 instance = hinst;
1540 DisableThreadLibraryCalls( hinst );
1541 break;
1542 case DLL_PROCESS_DETACH:
1543 break;
1545 return TRUE;