ddraw/tests: Add a test for drawing to a flippable surface.
[wine.git] / dlls / msv1_0 / main.c
blob53d8f1b6415ed8b34b3e47b68b95798f2ed0669b
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 "wincrypt.h"
34 #include "lmwksta.h"
35 #include "lmapibuf.h"
36 #include "lmerr.h"
38 #include "wine/debug.h"
39 #include "unixlib.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
43 static ULONG ntlm_package_id;
44 static LSA_DISPATCH_TABLE lsa_dispatch;
46 static NTSTATUS ntlm_check_version(void)
48 return WINE_UNIX_CALL( unix_check_version, NULL );
51 static void ntlm_cleanup( struct ntlm_ctx *ctx )
53 WINE_UNIX_CALL( unix_cleanup, ctx );
56 static NTSTATUS ntlm_chat( struct ntlm_ctx *ctx, char *buf, unsigned int buflen, unsigned int *retlen )
58 struct chat_params params = { ctx, buf, buflen, retlen };
60 return WINE_UNIX_CALL( unix_chat, &params );
63 static NTSTATUS ntlm_fork( struct ntlm_ctx *ctx, char **argv )
65 struct fork_params params = { ctx, argv };
67 return WINE_UNIX_CALL( unix_fork, &params );
70 #define NTLM_CAPS \
71 ( SECPKG_FLAG_INTEGRITY \
72 | SECPKG_FLAG_PRIVACY \
73 | SECPKG_FLAG_TOKEN_ONLY \
74 | SECPKG_FLAG_CONNECTION \
75 | SECPKG_FLAG_MULTI_REQUIRED \
76 | SECPKG_FLAG_IMPERSONATION \
77 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
78 | SECPKG_FLAG_NEGOTIABLE \
79 | SECPKG_FLAG_LOGON \
80 | SECPKG_FLAG_RESTRICTED_TOKENS )
82 #define NTLM_MAX_BUF 1904
84 static const SecPkgInfoW ntlm_package_info =
86 NTLM_CAPS,
88 RPC_C_AUTHN_WINNT,
89 NTLM_MAX_BUF,
90 (SEC_WCHAR *)L"NTLM",
91 (SEC_WCHAR *)L"NTLM Security Package"
94 static inline const char *debugstr_as( const STRING *str )
96 if (!str) return "<null>";
97 return debugstr_an( str->Buffer, str->Length );
100 static inline const char *debugstr_us( const UNICODE_STRING *str )
102 if (!str) return "<null>";
103 return debugstr_wn( str->Buffer, str->Length / sizeof(WCHAR) );
106 static NTSTATUS NTAPI ntlm_LsaApInitializePackage( ULONG package_id, LSA_DISPATCH_TABLE *dispatch,
107 LSA_STRING *database, LSA_STRING *confidentiality,
108 LSA_STRING **package_name )
110 LSA_STRING *str;
111 char *ptr;
113 TRACE( "%#lx, %p, %s, %s, %p\n", package_id, dispatch, debugstr_as(database), debugstr_as(confidentiality),
114 package_name );
116 if (ntlm_check_version())
118 ERR( "no NTLM support, expect problems\n" );
119 return STATUS_UNSUCCESSFUL;
122 if (!(str = dispatch->AllocateLsaHeap( sizeof(*str) + sizeof("NTLM" )))) return STATUS_NO_MEMORY;
123 ptr = (char *)(str + 1);
124 memcpy( ptr, "NTLM", sizeof("NTLM") );
125 RtlInitString( str, ptr );
127 ntlm_package_id = package_id;
128 lsa_dispatch = *dispatch;
130 *package_name = str;
131 return STATUS_SUCCESS;
134 static NTSTATUS NTAPI ntlm_SpInitialize( ULONG_PTR package_id, SECPKG_PARAMETERS *params,
135 LSA_SECPKG_FUNCTION_TABLE *lsa_function_table )
137 TRACE( "%#Ix, %p, %p\n", package_id, params, lsa_function_table );
139 if (ntlm_check_version())
141 ERR( "no NTLM support, expect problems\n" );
142 return STATUS_UNSUCCESSFUL;
144 return STATUS_SUCCESS;
147 static NTSTATUS NTAPI ntlm_SpGetInfo( SecPkgInfoW *info )
149 TRACE( "%p\n", info );
150 *info = ntlm_package_info;
151 return STATUS_SUCCESS;
154 static char *get_username_arg( const WCHAR *user, int user_len )
156 static const char arg[] = "--username=";
157 int len = sizeof(arg);
158 char *ret;
160 len += WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, user, user_len, NULL, 0, NULL, NULL );
161 if (!(ret = malloc( len ))) return NULL;
162 memcpy( ret, arg, sizeof(arg) - 1 );
163 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, user, user_len, ret + sizeof(arg) - 1,
164 len - sizeof(arg) + 1, NULL, NULL );
165 ret[len - 1] = 0;
166 return ret;
169 static char *get_domain_arg( const WCHAR *domain, int domain_len )
171 static const char arg[] = "--domain=";
172 int len = sizeof(arg);
173 char *ret;
175 len += WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain, domain_len, NULL, 0, NULL, NULL );
176 if (!(ret = malloc( len ))) return NULL;
177 memcpy( ret, arg, sizeof(arg) - 1 );
178 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain, domain_len, ret + sizeof(arg) - 1,
179 len - sizeof(arg) + 1, NULL, NULL );
180 ret[len - 1] = 0;
181 return ret;
184 #define WINE_NO_CACHED_CREDENTIALS 0x10000000
185 static NTSTATUS NTAPI ntlm_SpAcquireCredentialsHandle( UNICODE_STRING *principal, ULONG cred_use, LUID *logon_id,
186 void *auth_data, void *get_key_fn, void *get_key_arg,
187 LSA_SEC_HANDLE *handle, TimeStamp *expiry )
189 SECURITY_STATUS status = SEC_E_INSUFFICIENT_MEMORY;
190 struct ntlm_cred *cred = NULL;
191 WCHAR *domain = NULL, *user = NULL, *password = NULL;
192 SEC_WINNT_AUTH_IDENTITY_W *id = NULL;
194 TRACE( "%s, %#lx, %p, %p, %p, %p, %p, %p\n", debugstr_us(principal), cred_use, logon_id, auth_data,
195 get_key_fn, get_key_arg, cred, expiry );
197 switch (cred_use & ~SECPKG_CRED_RESERVED)
199 case SECPKG_CRED_INBOUND:
200 if (!(cred = malloc( sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY;
201 cred->mode = MODE_SERVER;
202 cred->username_arg = NULL;
203 cred->domain_arg = NULL;
204 cred->password = NULL;
205 cred->password_len = 0;
206 cred->no_cached_credentials = 0;
208 *handle = (LSA_SEC_HANDLE)cred;
209 status = SEC_E_OK;
210 break;
212 case SECPKG_CRED_OUTBOUND:
213 if (!(cred = malloc( sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY;
215 cred->mode = MODE_CLIENT;
216 cred->username_arg = NULL;
217 cred->domain_arg = NULL;
218 cred->password = NULL;
219 cred->password_len = 0;
220 cred->no_cached_credentials = (cred_use & WINE_NO_CACHED_CREDENTIALS);
222 if ((id = auth_data))
224 int domain_len = 0, user_len = 0, password_len = 0;
225 if (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
227 if (id->DomainLength)
229 domain_len = MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, NULL, 0 );
230 if (!(domain = malloc( sizeof(WCHAR) * domain_len ))) goto done;
231 MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, domain, domain_len );
233 if (id->UserLength)
235 user_len = MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, NULL, 0 );
236 if (!(user = malloc( sizeof(WCHAR) * user_len ))) goto done;
237 MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, user, user_len );
239 if (id->PasswordLength)
241 password_len = MultiByteToWideChar( CP_ACP, 0,(char *)id->Password, id->PasswordLength, NULL, 0 );
242 if (!(password = malloc( sizeof(WCHAR) * password_len ))) goto done;
243 MultiByteToWideChar( CP_ACP, 0, (char *)id->Password, id->PasswordLength, password, password_len );
246 else
248 domain = id->Domain;
249 domain_len = id->DomainLength;
250 user = id->User;
251 user_len = id->UserLength;
252 password = id->Password;
253 password_len = id->PasswordLength;
256 TRACE( "username is %s\n", debugstr_wn(user, user_len) );
257 TRACE( "domain name is %s\n", debugstr_wn(domain, domain_len) );
259 cred->username_arg = get_username_arg( user, user_len );
260 cred->domain_arg = get_domain_arg( domain, domain_len );
261 if (password_len)
263 cred->password_len = WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len,
264 NULL, 0, NULL, NULL );
265 if (!(cred->password = malloc( cred->password_len ))) goto done;
266 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len, cred->password,
267 cred->password_len, NULL, NULL );
271 *handle = (LSA_SEC_HANDLE)cred;
272 status = SEC_E_OK;
273 break;
275 case SECPKG_CRED_BOTH:
276 FIXME( "SECPKG_CRED_BOTH not supported\n" );
277 status = SEC_E_UNSUPPORTED_FUNCTION;
278 break;
280 default:
281 status = SEC_E_UNKNOWN_CREDENTIALS;
282 break;
285 done:
286 if (id && (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI))
288 free( domain );
289 free( user );
290 free( password );
292 if (status != SEC_E_OK) free( cred );
293 return status;
296 static NTSTATUS NTAPI ntlm_SpFreeCredentialsHandle( LSA_SEC_HANDLE handle )
298 struct ntlm_cred *cred = (struct ntlm_cred *)handle;
300 TRACE( "%#Ix\n", handle );
302 if (!cred) return SEC_E_OK;
304 cred->mode = MODE_INVALID;
305 if (cred->password) memset( cred->password, 0, cred->password_len );
306 free( cred->password );
307 free( cred->username_arg );
308 free( cred->domain_arg );
309 free( cred );
310 return SEC_E_OK;
313 static BOOL get_cached_credential( const UNICODE_STRING *target, CREDENTIALW **cred )
315 const WCHAR *ptr, *host;
316 WCHAR *hostonly;
317 size_t len;
318 BOOL ret;
320 if (!target) return FALSE;
322 len = target->Length / sizeof(WCHAR);
323 if ((host = wmemchr( target->Buffer, '/', len )))
325 host++;
326 len -= host - target->Buffer;
327 if (!(ptr = wmemchr( host, ':', len ))) ptr = wmemchr( host, '/', len );
328 if (!ptr) ptr = host + len;
330 else
332 host = target->Buffer;
333 ptr = host + len;
336 if (!(hostonly = malloc( (ptr - host + 1) * sizeof(WCHAR) ))) return FALSE;
337 memcpy( hostonly, host, (ptr - host) * sizeof(WCHAR) );
338 hostonly[ptr - host] = 0;
340 ret = CredReadW( hostonly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred );
341 free( hostonly );
342 return ret;
345 static UINT encode_base64( const char *bin, unsigned int len, char *base64 )
347 static const char base64enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
348 UINT n = 0, x;
350 while (len > 0)
352 /* first 6 bits, all from bin[0] */
353 base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
354 x = (bin[0] & 3) << 4;
356 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
357 if (len == 1)
359 base64[n++] = base64enc[x];
360 base64[n++] = '=';
361 base64[n++] = '=';
362 break;
364 base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
365 x = (bin[1] & 0x0f) << 2;
367 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
368 if (len == 2)
370 base64[n++] = base64enc[x];
371 base64[n++] = '=';
372 break;
374 base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
376 /* last 6 bits, all from bin[2] */
377 base64[n++] = base64enc[bin[2] & 0x3f];
378 bin += 3;
379 len -= 3;
381 base64[n] = 0;
382 return n;
385 static inline char decode_char( char c )
387 if (c >= 'A' && c <= 'Z') return c - 'A';
388 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
389 if (c >= '0' && c <= '9') return c - '0' + 52;
390 if (c == '+') return 62;
391 if (c == '/') return 63;
392 return 64;
395 static unsigned int decode_base64( const char *base64, unsigned int len, char *buf )
397 unsigned int i = 0;
398 char c0, c1, c2, c3;
399 const char *p = base64;
401 while (len > 4)
403 if ((c0 = decode_char( p[0] )) > 63) return 0;
404 if ((c1 = decode_char( p[1] )) > 63) return 0;
405 if ((c2 = decode_char( p[2] )) > 63) return 0;
406 if ((c3 = decode_char( p[3] )) > 63) return 0;
407 if (buf)
409 buf[i + 0] = (c0 << 2) | (c1 >> 4);
410 buf[i + 1] = (c1 << 4) | (c2 >> 2);
411 buf[i + 2] = (c2 << 6) | c3;
413 len -= 4;
414 i += 3;
415 p += 4;
417 if (p[2] == '=')
419 if ((c0 = decode_char( p[0] )) > 63) return 0;
420 if ((c1 = decode_char( p[1] )) > 63) return 0;
421 if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
422 i++;
424 else if (p[3] == '=')
426 if ((c0 = decode_char( p[0] )) > 63) return 0;
427 if ((c1 = decode_char( p[1] )) > 63) return 0;
428 if ((c2 = decode_char( p[2] )) > 63) return 0;
429 if (buf)
431 buf[i + 0] = (c0 << 2) | (c1 >> 4);
432 buf[i + 1] = (c1 << 4) | (c2 >> 2);
434 i += 2;
436 else
438 if ((c0 = decode_char( p[0] )) > 63) return 0;
439 if ((c1 = decode_char( p[1] )) > 63) return 0;
440 if ((c2 = decode_char( p[2] )) > 63) return 0;
441 if ((c3 = decode_char( p[3] )) > 63) return 0;
442 if (buf)
444 buf[i + 0] = (c0 << 2) | (c1 >> 4);
445 buf[i + 1] = (c1 << 4) | (c2 >> 2);
446 buf[i + 2] = (c2 << 6) | c3;
448 i += 3;
450 return i;
453 struct md4_ctx
455 unsigned int buf[4];
456 unsigned int i[2];
457 unsigned char in[64];
458 unsigned char digest[16];
461 void WINAPI MD4Init( struct md4_ctx * );
462 void WINAPI MD4Update( struct md4_ctx *, const char *, unsigned int );
463 void WINAPI MD4Final( struct md4_ctx * );
465 static void create_ntlm1_session_key( const char *secret, unsigned int len, char *session_key )
467 struct md4_ctx ctx;
468 char hash[16];
470 MD4Init( &ctx );
471 MD4Update( &ctx, secret, len );
472 MD4Final( &ctx );
473 memcpy( hash, ctx.digest, 16 );
475 MD4Init( &ctx );
476 MD4Update( &ctx, hash, 16 );
477 MD4Final( &ctx );
478 memcpy( session_key, ctx.digest, 16 );
481 struct md5_ctx
483 unsigned int i[2];
484 unsigned int buf[4];
485 unsigned char in[64];
486 unsigned char digest[16];
489 void WINAPI MD5Init( struct md5_ctx * );
490 void WINAPI MD5Update( struct md5_ctx *, const char *, unsigned int );
491 void WINAPI MD5Final( struct md5_ctx * );
493 static void calc_ntlm2_subkey( const char *session_key, const char *magic, char *subkey )
495 struct md5_ctx ctx;
497 MD5Init( &ctx );
498 MD5Update( &ctx, session_key, 16 );
499 MD5Update( &ctx, magic, strlen(magic) + 1 );
500 MD5Final( &ctx );
501 memcpy( subkey, ctx.digest, 16 );
504 static const char client_to_server_sign_constant[] = "session key to client-to-server signing key magic constant";
505 static const char client_to_server_seal_constant[] = "session key to client-to-server sealing key magic constant";
506 static const char server_to_client_sign_constant[] = "session key to server-to-client signing key magic constant";
507 static const char server_to_client_seal_constant[] = "session key to server-to-client sealing key magic constant";
509 static void create_ntlm2_subkeys( struct ntlm_ctx *ctx )
511 if (ctx->mode == MODE_CLIENT)
513 calc_ntlm2_subkey( ctx->session_key, client_to_server_sign_constant, ctx->crypt.ntlm2.send_sign_key );
514 calc_ntlm2_subkey( ctx->session_key, client_to_server_seal_constant, ctx->crypt.ntlm2.send_seal_key );
515 calc_ntlm2_subkey( ctx->session_key, server_to_client_sign_constant, ctx->crypt.ntlm2.recv_sign_key );
516 calc_ntlm2_subkey( ctx->session_key, server_to_client_seal_constant, ctx->crypt.ntlm2.recv_seal_key );
518 else
520 calc_ntlm2_subkey( ctx->session_key, server_to_client_sign_constant, ctx->crypt.ntlm2.send_sign_key );
521 calc_ntlm2_subkey( ctx->session_key, server_to_client_seal_constant, ctx->crypt.ntlm2.send_seal_key );
522 calc_ntlm2_subkey( ctx->session_key, client_to_server_sign_constant, ctx->crypt.ntlm2.recv_sign_key );
523 calc_ntlm2_subkey( ctx->session_key, client_to_server_seal_constant, ctx->crypt.ntlm2.recv_seal_key );
528 * The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack,
529 * which in turn is based on public domain code by Wei Dai
531 static void arc4_init( struct arc4_info *info, const char *key, unsigned int len )
533 unsigned int key_idx = 0, state_idx = 0, i, a;
535 info->x = info->y = 0;
536 for (i = 0; i < 256; i++) info->state[i] = i;
538 for (i = 0; i < 256; i++)
540 a = info->state[i];
541 state_idx += key[key_idx] + a;
542 state_idx &= 0xff;
543 info->state[i] = info->state[state_idx];
544 info->state[state_idx] = a;
545 if (++key_idx >= len) key_idx = 0;
549 static void arc4_process( struct arc4_info *info, char *buf, unsigned int len )
551 char *state = info->state;
552 unsigned int x = info->x, y = info->y, a, b;
554 while (len--)
556 x = (x + 1) & 0xff;
557 a = state[x];
558 y = (y + a) & 0xff;
559 b = state[y];
560 state[x] = b;
561 state[y] = a;
562 *buf++ ^= state[(a + b) & 0xff];
565 info->x = x;
566 info->y = y;
569 static int get_buffer_index( SecBufferDesc *desc, ULONG type )
571 int idx;
572 for (idx = 0; idx < desc->cBuffers; idx++)
574 if (desc->pBuffers[idx].BufferType == type) return idx;
576 return -1;
579 static NTSTATUS NTAPI ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA_SEC_HANDLE ctx_handle,
580 UNICODE_STRING *target, ULONG ctx_req, ULONG data_rep,
581 SecBufferDesc *input, LSA_SEC_HANDLE *new_ctx_handle,
582 SecBufferDesc *output, ULONG *ctx_attr, TimeStamp *expiry,
583 BOOLEAN *mapped_ctx, SecBuffer *ctx_data )
585 NTSTATUS status = SEC_E_INSUFFICIENT_MEMORY;
586 struct ntlm_ctx *ctx = NULL;
587 char *buf, *bin, *want_flags = NULL, *username = NULL, *domain = NULL, *password = NULL;
588 unsigned int len, bin_len;
589 int idx;
591 TRACE( "%#Ix, %#Ix, %s, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle, ctx_handle, debugstr_us(target),
592 ctx_req, data_rep, input, new_ctx_handle, output, ctx_attr, expiry, mapped_ctx, ctx_data );
594 /* when communicating with the client there can be the following reply packets:
595 * YR <base64 blob> should be sent to the server
596 * PW should be sent back to helper with base64 encoded password
597 * AF <base64 blob> client is done, blob should be sent to server with KK prefixed
598 * GF <string list> a string list of negotiated flags
599 * GK <base64 blob> base64 encoded session key
600 * BH <char reason> something broke
602 * The squid cache size is 2010 chars and that's what ntlm_auth uses */
604 if (!(buf = malloc( NTLM_MAX_BUF ))) return SEC_E_INSUFFICIENT_MEMORY;
605 if (!(bin = malloc( NTLM_MAX_BUF ))) goto done;
607 if (!ctx_handle && !input)
609 char *argv[5];
610 int password_len = 0;
611 struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
613 if (!cred || cred->mode != MODE_CLIENT)
615 status = SEC_E_INVALID_HANDLE;
616 goto done;
619 argv[0] = (char *)"ntlm_auth";
620 argv[1] = (char *)"--helper-protocol=ntlmssp-client-1";
621 if (!cred->username_arg && !cred->domain_arg)
623 WKSTA_USER_INFO_1 *ui = NULL;
624 NET_API_STATUS ret;
625 CREDENTIALW *cached;
627 if (get_cached_credential( target, &cached ))
629 WCHAR *p;
630 if ((p = wcschr( cached->UserName, '\\' )))
632 if (!(domain = get_domain_arg( cached->UserName, p - cached->UserName ))) goto done;
633 p++;
635 else
637 if (!(domain = get_domain_arg( NULL, 0 ))) goto done;
638 p = cached->UserName;
640 if (!(username = get_username_arg( p, -1 ))) goto done;
642 if (cached->CredentialBlobSize)
644 password_len = WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, (WCHAR *)cached->CredentialBlob,
645 cached->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL );
646 if (!(password = malloc( password_len ))) goto done;
647 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, (WCHAR *)cached->CredentialBlob,
648 cached->CredentialBlobSize / sizeof(WCHAR), password, password_len, NULL, NULL );
650 CredFree( cached );
652 argv[2] = username;
653 argv[3] = domain;
654 argv[4] = NULL;
656 else
658 ret = NetWkstaUserGetInfo( NULL, 1, (BYTE **)&ui );
659 if (ret != NERR_Success || !ui || cred->no_cached_credentials)
661 status = SEC_E_NO_CREDENTIALS;
662 goto done;
664 if (!(username = get_username_arg( ui->wkui1_username, -1 ))) goto done;
665 NetApiBufferFree( ui );
666 TRACE("using cached credentials\n");
668 argv[2] = username;
669 argv[3] = (char *)"--use-cached-creds";
670 argv[4] = NULL;
673 else
675 argv[2] = cred->username_arg;
676 argv[3] = cred->domain_arg;
677 argv[4] = NULL;
680 if (!(ctx = calloc( 1, sizeof(*ctx) ))) goto done;
682 if ((status = ntlm_fork( ctx, argv )) != SEC_E_OK) goto done;
683 status = SEC_E_INSUFFICIENT_MEMORY;
685 ctx->mode = MODE_CLIENT;
686 memset( ctx->session_key, 0, sizeof(ctx->session_key) );
688 /* generate the dummy session key = MD4(MD4(password))*/
689 if (password || cred->password)
691 WCHAR *passwordW;
692 len = MultiByteToWideChar( CP_ACP, 0, password ? password : cred->password,
693 password ? password_len : cred->password_len, NULL, 0 );
694 if (!(passwordW = malloc( len * sizeof(WCHAR) ))) goto done;
695 MultiByteToWideChar( CP_ACP, 0, password ? password : cred->password,
696 password ? password_len : cred->password_len, passwordW, len );
698 create_ntlm1_session_key( (const char *)passwordW, len * sizeof(WCHAR), ctx->session_key );
699 free( passwordW );
702 /* allocate space for a maximum string of
703 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL NTLMSSP_FEATURE_SESSION_KEY"
705 if (!(want_flags = malloc( 73 ))) goto done;
706 strcpy( want_flags, "SF" );
707 if (ctx_req & ISC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
708 if ((ctx_req & ISC_REQ_INTEGRITY) || (ctx_req & ISC_REQ_REPLAY_DETECT) ||
709 (ctx_req & ISC_REQ_SEQUENCE_DETECT)) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
711 if (ctx_req & ISC_REQ_CONNECTION) ctx->attrs |= ISC_RET_CONNECTION;
712 if (ctx_req & ISC_REQ_EXTENDED_ERROR) ctx->attrs |= ISC_RET_EXTENDED_ERROR;
713 if (ctx_req & ISC_REQ_MUTUAL_AUTH) ctx->attrs |= ISC_RET_MUTUAL_AUTH;
714 if (ctx_req & ISC_REQ_USE_DCE_STYLE) ctx->attrs |= ISC_RET_USED_DCE_STYLE;
715 if (ctx_req & ISC_REQ_DELEGATE) ctx->attrs |= ISC_RET_DELEGATE;
716 if (ctx_req & ISC_REQ_STREAM) FIXME( "ISC_REQ_STREAM\n" );
718 /* use cached credentials if no password was given, fall back to an empty password on failure */
719 if (!password && !cred->password)
721 strcpy( buf, "OK" );
722 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
724 /* if the helper replied with "PW" using cached credentials failed */
725 if (!strncmp( buf, "PW", 2 ))
727 TRACE( "using cached credentials failed\n" );
728 strcpy( buf, "PW AA==" );
730 else strcpy( buf, "OK" ); /* just do a noop on the next run */
732 else
734 strcpy( buf, "PW " );
735 encode_base64( password ? password : cred->password, password ? password_len : cred->password_len, buf + 3 );
738 TRACE( "sending to ntlm_auth: %s\n", debugstr_a(buf) );
739 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
740 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf) );
742 if (strlen( want_flags ) > 2)
744 TRACE( "want flags are %s\n", debugstr_a(want_flags) );
745 strcpy( buf, want_flags );
746 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
747 if (!strncmp( buf, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
750 strcpy( buf, "YR" );
751 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
752 TRACE( "ntlm_auth returned %s\n", buf );
753 if (strncmp( buf, "YR ", 3 ))
755 status = SEC_E_INTERNAL_ERROR;
756 goto done;
758 bin_len = decode_base64( buf + 3, len - 3, bin );
760 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
761 status = SEC_I_CONTINUE_NEEDED;
763 else /* !ctx_handle && !input */
765 if (!input || ((idx = get_buffer_index( input, SECBUFFER_TOKEN )) == -1))
767 status = SEC_E_INVALID_TOKEN;
768 goto done;
771 ctx = (struct ntlm_ctx *)ctx_handle;
772 if (!ctx || ctx->mode != MODE_CLIENT)
774 status = SEC_E_INVALID_HANDLE;
775 goto done;
778 if (!input->pBuffers[idx].pvBuffer || input->pBuffers[idx].cbBuffer > NTLM_MAX_BUF)
780 status = SEC_E_INVALID_TOKEN;
781 goto done;
783 bin_len = input->pBuffers[idx].cbBuffer;
784 memcpy( bin, input->pBuffers[idx].pvBuffer, bin_len );
786 strcpy( buf, "TT " );
787 encode_base64( bin, bin_len, buf + 3 );
788 TRACE( "server sent: %s\n", debugstr_a(buf) );
790 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len ))) goto done;
791 TRACE( "ntlm_auth returned: %s\n", debugstr_a(buf) );
793 if (strncmp( buf, "KK ", 3 ) && strncmp( buf, "AF ", 3 ))
795 status = SEC_E_INVALID_TOKEN;
796 goto done;
798 bin_len = decode_base64( buf + 3, len - 3, bin );
800 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
801 status = SEC_E_OK;
804 if (!output || ((idx = get_buffer_index( output, SECBUFFER_TOKEN )) == -1))
806 if (!ctx_handle && !input) *new_ctx_handle = 0;
807 status = SEC_E_BUFFER_TOO_SMALL;
808 goto done;
811 if (ctx_req & ISC_REQ_ALLOCATE_MEMORY)
813 /* freed with secur32.FreeContextBuffer */
814 if (!(output->pBuffers[idx].pvBuffer = RtlAllocateHeap( GetProcessHeap(), 0, bin_len )))
816 status = SEC_E_INSUFFICIENT_MEMORY;
817 goto done;
819 output->pBuffers[idx].cbBuffer = bin_len;
821 else if (output->pBuffers[idx].cbBuffer < bin_len)
823 if (!ctx_handle && !input) *new_ctx_handle = 0;
824 status = SEC_E_BUFFER_TOO_SMALL;
825 goto done;
828 if (!output->pBuffers[idx].pvBuffer)
830 if (!ctx_handle && !input) *new_ctx_handle = 0;
831 status = SEC_E_INTERNAL_ERROR;
832 goto done;
835 output->pBuffers[idx].cbBuffer = bin_len;
836 memcpy( output->pBuffers[idx].pvBuffer, bin, bin_len );
837 if (status == SEC_E_OK)
839 strcpy( buf, "GF" );
840 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
841 if (len < 3) ctx->flags = 0;
842 else sscanf( buf + 3, "%x", &ctx->flags );
844 strcpy( buf, "GK" );
845 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
847 if (!strncmp( buf, "BH", 2 )) TRACE( "no key negotiated\n" );
848 else if (!strncmp( buf, "GK ", 3 ))
850 bin_len = decode_base64( buf + 3, len - 3, bin );
851 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
852 memcpy( ctx->session_key, bin, bin_len );
855 arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
856 ctx->crypt.ntlm.seq_no = 0;
857 create_ntlm2_subkeys( ctx );
858 arc4_init( &ctx->crypt.ntlm2.send_arc4info, ctx->crypt.ntlm2.send_seal_key, 16 );
859 arc4_init( &ctx->crypt.ntlm2.recv_arc4info, ctx->crypt.ntlm2.recv_seal_key, 16 );
860 ctx->crypt.ntlm2.send_seq_no = 0;
861 ctx->crypt.ntlm2.recv_seq_no = 0;
864 done:
865 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED && !ctx_handle && !input)
867 ntlm_cleanup( ctx );
868 free( ctx );
870 free( username );
871 free( domain );
872 free( password );
873 free( buf );
874 free( bin );
875 free( want_flags );
877 TRACE( "returning %#lx\n", status );
878 return status;
881 static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA_SEC_HANDLE ctx_handle,
882 SecBufferDesc *input, ULONG ctx_req, ULONG data_rep,
883 LSA_SEC_HANDLE *new_ctx_handle, SecBufferDesc *output,
884 ULONG *ctx_attr, TimeStamp *expiry, BOOLEAN *mapped_ctx,
885 SecBuffer *ctx_data )
887 NTSTATUS status = SEC_E_INSUFFICIENT_MEMORY;
888 struct ntlm_ctx *ctx = NULL;
889 char *buf, *bin, *want_flags = NULL;
890 unsigned int len, bin_len;
892 TRACE( "%#Ix, %#Ix, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle, ctx_handle, ctx_req, data_rep, input,
893 new_ctx_handle, output, ctx_attr, expiry, mapped_ctx, ctx_data );
894 if (ctx_req) FIXME( "ignoring flags %#lx\n", ctx_req );
896 if (!(buf = malloc( NTLM_MAX_BUF ))) return SEC_E_INSUFFICIENT_MEMORY;
897 if (!(bin = malloc( NTLM_MAX_BUF ))) goto done;
899 if (!ctx_handle)
901 struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
902 char *argv[3];
904 if (!cred || cred->mode != MODE_SERVER)
906 status = SEC_E_INVALID_HANDLE;
907 goto done;
910 if (!input || input->cBuffers < 1)
912 status = SEC_E_INCOMPLETE_MESSAGE;
913 goto done;
916 if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
918 status = SEC_E_INVALID_TOKEN;
919 goto done;
921 else bin_len = input->pBuffers[0].cbBuffer;
923 if (!(ctx = calloc( 1, sizeof(*ctx) ))) goto done;
925 argv[0] = (char *)"ntlm_auth";
926 argv[1] = (char *)"--helper-protocol=squid-2.5-ntlmssp";
927 argv[2] = NULL;
928 if ((status = ntlm_fork( ctx, argv )) != SEC_E_OK) goto done;
929 ctx->mode = MODE_SERVER;
931 if (!(want_flags = malloc( 73 )))
933 status = SEC_E_INSUFFICIENT_MEMORY;
934 goto done;
936 strcpy( want_flags, "SF" );
937 if (ctx_req & ASC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
938 if (ctx_req & ASC_REQ_CONNECTION)
940 strcat( want_flags, " NTLMSSP_FEATURE_SESSION_KEY" );
941 ctx->attrs |= ASC_RET_CONNECTION;
943 if (ctx_req & ASC_REQ_INTEGRITY) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
944 if (ctx_req & ASC_REQ_ALLOCATE_MEMORY) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
945 if (ctx_req & ASC_REQ_EXTENDED_ERROR) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
946 if (ctx_req & ASC_REQ_MUTUAL_AUTH) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
947 if (ctx_req & ASC_REQ_REPLAY_DETECT) FIXME( "ASC_REQ_REPLAY_DETECT\n" );
948 if (ctx_req & ASC_REQ_SEQUENCE_DETECT) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
949 if (ctx_req & ASC_REQ_STREAM) FIXME( "ASC_REQ_STREAM\n" );
951 if (strlen( want_flags ) > 3)
953 TRACE( "want flags are %s\n", debugstr_a(want_flags) );
954 strcpy( buf, want_flags );
955 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
956 if (!strncmp( buf, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
959 memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
960 strcpy( buf, "YR " );
961 encode_base64( bin, bin_len, buf + 3 );
963 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
964 TRACE( "ntlm_auth returned %s\n", buf );
965 if (strncmp( buf, "TT ", 3))
967 status = SEC_E_INTERNAL_ERROR;
968 goto done;
970 bin_len = decode_base64( buf + 3, len - 3, bin );
972 if (!output || output->cBuffers < 1)
974 status = SEC_E_INSUFFICIENT_MEMORY;
975 goto done;
977 output->pBuffers[0].cbBuffer = bin_len;
978 output->pBuffers[0].BufferType = SECBUFFER_DATA;
979 memcpy( output->pBuffers[0].pvBuffer, bin, bin_len );
981 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
982 status = SEC_I_CONTINUE_NEEDED;
984 else
986 if (!input || input->cBuffers < 1)
988 status = SEC_E_INCOMPLETE_MESSAGE;
989 goto done;
992 ctx = (struct ntlm_ctx *)ctx_handle;
993 if (!ctx || ctx->mode != MODE_SERVER)
995 status = SEC_E_INVALID_HANDLE;
996 goto done;
999 if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
1001 status = SEC_E_INVALID_TOKEN;
1002 goto done;
1004 else bin_len = input->pBuffers[0].cbBuffer;
1005 memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
1007 strcpy( buf, "KK " );
1008 encode_base64( bin, bin_len, buf + 3 );
1010 TRACE( "client sent %s\n", debugstr_a(buf) );
1011 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1012 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf) );
1014 /* At this point, we get a NA if the user didn't authenticate, but a BH if ntlm_auth could not
1015 * connect to winbindd. Apart from running Wine as root, there is no way to fix this for now,
1016 * so just handle this as a failed login. */
1017 if (strncmp( buf, "AF ", 3 ))
1019 if (!strncmp( buf, "NA ", 3 ))
1021 status = SEC_E_LOGON_DENIED;
1022 goto done;
1024 else
1026 const char err_v3[] = "BH NT_STATUS_ACCESS_DENIED";
1027 const char err_v4[] = "BH NT_STATUS_UNSUCCESSFUL";
1029 if ((len >= strlen(err_v3) && !strncmp( buf, err_v3, strlen(err_v3) )) ||
1030 (len >= strlen(err_v4) && !strncmp( buf, err_v4, strlen(err_v4) )))
1032 TRACE( "connection to winbindd failed\n" );
1033 status = SEC_E_LOGON_DENIED;
1035 else status = SEC_E_INTERNAL_ERROR;
1036 goto done;
1039 output->pBuffers[0].cbBuffer = 0;
1041 strcpy( buf, "GF" );
1042 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1043 if (len < 3) ctx->flags = 0;
1044 else sscanf( buf + 3, "%x", &ctx->flags );
1046 strcpy( buf, "GK" );
1047 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1049 if (!strncmp( buf, "BH", 2 )) TRACE( "no key negotiated\n" );
1050 else if (!strncmp( buf, "GK ", 3 ))
1052 bin_len = decode_base64( buf + 3, len - 3, bin );
1053 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
1054 memcpy( ctx->session_key, bin, bin_len );
1057 if (len < 3) memset( ctx->session_key, 0 , 16 );
1058 else
1060 if (!strncmp( buf, "BH ", 3 ))
1062 TRACE( "helper sent %s\n", debugstr_a(buf + 3) );
1063 /*FIXME: generate dummy session key = MD4(MD4(password))*/
1064 memset( ctx->session_key, 0 , 16 );
1066 else if (!strncmp( buf, "GK ", 3 ))
1068 bin_len = decode_base64( buf + 3, len - 3, bin );
1069 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
1070 memcpy( ctx->session_key, bin, 16 );
1073 arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
1074 ctx->crypt.ntlm.seq_no = 0;
1076 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
1077 status = SEC_E_OK;
1080 done:
1081 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED && !ctx_handle)
1083 ntlm_cleanup( ctx );
1084 free( ctx );
1086 free( buf );
1087 free( bin );
1088 free( want_flags );
1090 TRACE( "returning %#lx\n", status );
1091 return status;
1094 static NTSTATUS NTAPI ntlm_SpDeleteContext( LSA_SEC_HANDLE handle )
1096 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1098 TRACE( "%#Ix\n", handle );
1100 if (!ctx) return SEC_E_INVALID_HANDLE;
1101 ntlm_cleanup( ctx );
1102 free( ctx );
1103 return SEC_E_OK;
1106 static SecPkgInfoW *build_package_info( const SecPkgInfoW *info )
1108 SecPkgInfoW *ret;
1109 DWORD size_name = (wcslen(info->Name) + 1) * sizeof(WCHAR);
1110 DWORD size_comment = (wcslen(info->Comment) + 1) * sizeof(WCHAR);
1112 if (!(ret = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*ret) + size_name + size_comment ))) return NULL;
1113 ret->fCapabilities = info->fCapabilities;
1114 ret->wVersion = info->wVersion;
1115 ret->wRPCID = info->wRPCID;
1116 ret->cbMaxToken = info->cbMaxToken;
1117 ret->Name = (SEC_WCHAR *)(ret + 1);
1118 memcpy( ret->Name, info->Name, size_name );
1119 ret->Comment = (SEC_WCHAR *)((char *)ret->Name + size_name);
1120 memcpy( ret->Comment, info->Comment, size_comment );
1121 return ret;
1124 static NTSTATUS NTAPI ntlm_SpQueryContextAttributes( LSA_SEC_HANDLE handle, ULONG attr, void *buf )
1126 TRACE( "%#Ix, %lu, %p\n", handle, attr, buf );
1128 if (!handle) return SEC_E_INVALID_HANDLE;
1130 switch (attr)
1132 #define X(x) case (x) : FIXME(#x" stub\n"); break
1133 X(SECPKG_ATTR_ACCESS_TOKEN);
1134 X(SECPKG_ATTR_AUTHORITY);
1135 X(SECPKG_ATTR_DCE_INFO);
1136 X(SECPKG_ATTR_LIFESPAN);
1137 X(SECPKG_ATTR_NAMES);
1138 X(SECPKG_ATTR_NATIVE_NAMES);
1139 X(SECPKG_ATTR_PACKAGE_INFO);
1140 X(SECPKG_ATTR_PASSWORD_EXPIRY);
1141 X(SECPKG_ATTR_STREAM_SIZES);
1142 X(SECPKG_ATTR_TARGET_INFORMATION);
1143 case SECPKG_ATTR_FLAGS:
1145 SecPkgContext_Flags *flags = (SecPkgContext_Flags *)buf;
1146 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1148 flags->Flags = 0;
1149 if (ctx->flags & FLAG_NEGOTIATE_SIGN) flags->Flags |= ISC_RET_INTEGRITY;
1150 if (ctx->flags & FLAG_NEGOTIATE_SEAL) flags->Flags |= ISC_RET_CONFIDENTIALITY;
1151 return SEC_E_OK;
1153 case SECPKG_ATTR_SIZES:
1155 SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)buf;
1156 sizes->cbMaxToken = NTLM_MAX_BUF;
1157 sizes->cbMaxSignature = 16;
1158 sizes->cbBlockSize = 0;
1159 sizes->cbSecurityTrailer = 16;
1160 return SEC_E_OK;
1162 case SECPKG_ATTR_NEGOTIATION_INFO:
1164 SecPkgContext_NegotiationInfoW *info = (SecPkgContext_NegotiationInfoW *)buf;
1165 if (!(info->PackageInfo = build_package_info( &ntlm_package_info ))) return SEC_E_INSUFFICIENT_MEMORY;
1166 info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE;
1167 return SEC_E_OK;
1169 case SECPKG_ATTR_SESSION_KEY:
1171 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1172 SecPkgContext_SessionKey *key = (SecPkgContext_SessionKey *)buf;
1173 unsigned char *session_key;
1175 if (!(session_key = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(ctx->session_key) )))
1176 return SEC_E_INSUFFICIENT_MEMORY;
1177 memcpy( session_key, ctx->session_key, sizeof(ctx->session_key) );
1178 key->SessionKey = session_key;
1179 key->SessionKeyLength = sizeof(ctx->session_key);
1180 return SEC_E_OK;
1182 case SECPKG_ATTR_KEY_INFO:
1184 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1185 SecPkgContext_KeyInfoW *info = (SecPkgContext_KeyInfoW *)buf;
1186 SEC_WCHAR *signature_alg;
1187 ULONG signature_size, signature_algid;
1189 if (ctx->flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1191 signature_alg = (SEC_WCHAR *)L"HMAC-MD5";
1192 signature_size = sizeof(L"HMAC-MD5");
1193 signature_algid = 0xffffff76;
1195 else
1197 signature_alg = (SEC_WCHAR *)L"RSADSI RC4-CRC32";
1198 signature_size = sizeof(L"RSADSI RC4-CRC32");
1199 signature_algid = 0xffffff7c;
1202 if (!(info->sSignatureAlgorithmName = RtlAllocateHeap( GetProcessHeap(), 0, signature_size )))
1203 return SEC_E_INSUFFICIENT_MEMORY;
1204 wcscpy( info->sSignatureAlgorithmName, signature_alg );
1206 if (!(info->sEncryptAlgorithmName = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(L"RSADSI RC4") )))
1208 RtlFreeHeap( GetProcessHeap(), 0, info->sSignatureAlgorithmName );
1209 return SEC_E_INSUFFICIENT_MEMORY;
1211 wcscpy( info->sEncryptAlgorithmName, L"RSADSI RC4" );
1213 info->KeySize = sizeof(ctx->session_key) * 8;
1214 info->SignatureAlgorithm = signature_algid;
1215 info->EncryptAlgorithm = CALG_RC4;
1216 return SEC_E_OK;
1218 #undef X
1219 default:
1220 FIXME( "unknown attribute %lu\n", attr );
1221 break;
1224 return SEC_E_UNSUPPORTED_FUNCTION;
1227 static SECPKG_FUNCTION_TABLE ntlm_table =
1229 ntlm_LsaApInitializePackage,
1230 NULL, /* LsaLogonUser */
1231 NULL, /* CallPackage */
1232 NULL, /* LogonTerminated */
1233 NULL, /* CallPackageUntrusted */
1234 NULL, /* CallPackagePassthrough */
1235 NULL, /* LogonUserEx */
1236 NULL, /* LogonUserEx2 */
1237 ntlm_SpInitialize,
1238 NULL, /* SpShutdown */
1239 ntlm_SpGetInfo,
1240 NULL, /* AcceptCredentials */
1241 ntlm_SpAcquireCredentialsHandle,
1242 NULL, /* SpQueryCredentialsAttributes */
1243 ntlm_SpFreeCredentialsHandle,
1244 NULL, /* SaveCredentials */
1245 NULL, /* GetCredentials */
1246 NULL, /* DeleteCredentials */
1247 ntlm_SpInitLsaModeContext,
1248 ntlm_SpAcceptLsaModeContext,
1249 ntlm_SpDeleteContext,
1250 NULL, /* ApplyControlToken */
1251 NULL, /* GetUserInfo */
1252 NULL, /* GetExtendedInformation */
1253 ntlm_SpQueryContextAttributes,
1254 NULL, /* SpAddCredentials */
1255 NULL, /* SetExtendedInformation */
1256 NULL, /* SetContextAttributes */
1257 NULL, /* SetCredentialsAttributes */
1258 NULL, /* ChangeAccountPassword */
1259 NULL, /* QueryMetaData */
1260 NULL, /* ExchangeMetaData */
1261 NULL, /* GetCredUIContext */
1262 NULL, /* UpdateCredentials */
1263 NULL, /* ValidateTargetInfo */
1264 NULL, /* PostLogonUser */
1267 NTSTATUS NTAPI SpLsaModeInitialize( ULONG lsa_version, ULONG *package_version, SECPKG_FUNCTION_TABLE **table,
1268 ULONG *table_count )
1270 TRACE( "%#lx, %p, %p, %p\n", lsa_version, package_version, table, table_count );
1272 *package_version = SECPKG_INTERFACE_VERSION;
1273 *table = &ntlm_table;
1274 *table_count = 1;
1275 return STATUS_SUCCESS;
1278 static NTSTATUS NTAPI ntlm_SpInstanceInit( ULONG version, SECPKG_DLL_FUNCTIONS *dll_functions, void **user_functions )
1280 TRACE( "%#lx, %p, %p\n", version, dll_functions, user_functions );
1281 return STATUS_SUCCESS;
1284 struct hmac_md5_ctx
1286 struct md5_ctx ctx;
1287 char outer_padding[64];
1290 static void hmac_md5_init( struct hmac_md5_ctx *ctx, const char *key, unsigned int key_len )
1292 char inner_padding[64], tmp_key[16];
1293 unsigned int i;
1295 if (key_len > 64)
1297 struct md5_ctx tmp_ctx;
1299 MD5Init( &tmp_ctx );
1300 MD5Update( &tmp_ctx, key, key_len );
1301 MD5Final( &tmp_ctx );
1302 memcpy( tmp_key, tmp_ctx.digest, 16 );
1304 key = tmp_key;
1305 key_len = 16;
1308 memset( inner_padding, 0, 64 );
1309 memset( ctx->outer_padding, 0, 64 );
1310 memcpy( inner_padding, key, key_len );
1311 memcpy( ctx->outer_padding, key, key_len );
1313 for (i = 0; i < 64; i++)
1315 inner_padding[i] ^= 0x36;
1316 ctx->outer_padding[i] ^= 0x5c;
1319 MD5Init( &ctx->ctx );
1320 MD5Update( &ctx->ctx, inner_padding, 64 );
1323 static void hmac_md5_update( struct hmac_md5_ctx *ctx, const char *buf, unsigned int len )
1325 MD5Update( &ctx->ctx, buf, len );
1328 static void hmac_md5_final( struct hmac_md5_ctx *ctx, char *digest )
1330 struct md5_ctx outer_ctx;
1331 char inner_digest[16];
1333 MD5Final( &ctx->ctx );
1334 memcpy( inner_digest, ctx->ctx.digest, 16 );
1336 MD5Init( &outer_ctx );
1337 MD5Update( &outer_ctx, ctx->outer_padding, 64 );
1338 MD5Update( &outer_ctx, inner_digest, 16 );
1339 MD5Final( &outer_ctx );
1341 memcpy( digest, outer_ctx.digest, 16 );
1344 static SECURITY_STATUS create_signature( struct ntlm_ctx *ctx, unsigned int flags, SecBufferDesc *msg, int idx,
1345 enum sign_direction dir, BOOL encrypt )
1347 unsigned int i, sign_version = 1;
1348 char *sig = msg->pBuffers[idx].pvBuffer;
1350 if (flags & FLAG_NEGOTIATE_NTLM2 && flags & FLAG_NEGOTIATE_SIGN)
1352 char digest[16], seq_no[4];
1353 struct hmac_md5_ctx hmac_md5;
1355 if (dir == SIGN_SEND)
1357 seq_no[0] = (ctx->crypt.ntlm2.send_seq_no >> 0) & 0xff;
1358 seq_no[1] = (ctx->crypt.ntlm2.send_seq_no >> 8) & 0xff;
1359 seq_no[2] = (ctx->crypt.ntlm2.send_seq_no >> 16) & 0xff;
1360 seq_no[3] = (ctx->crypt.ntlm2.send_seq_no >> 24) & 0xff;
1361 ctx->crypt.ntlm2.send_seq_no++;
1363 hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.send_sign_key, 16 );
1365 else
1367 seq_no[0] = (ctx->crypt.ntlm2.recv_seq_no >> 0) & 0xff;
1368 seq_no[1] = (ctx->crypt.ntlm2.recv_seq_no >> 8) & 0xff;
1369 seq_no[2] = (ctx->crypt.ntlm2.recv_seq_no >> 16) & 0xff;
1370 seq_no[3] = (ctx->crypt.ntlm2.recv_seq_no >> 24) & 0xff;
1371 ctx->crypt.ntlm2.recv_seq_no++;
1373 hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.recv_sign_key, 16 );
1376 hmac_md5_update( &hmac_md5, seq_no, 4 );
1377 for (i = 0; i < msg->cBuffers; ++i)
1379 if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
1380 hmac_md5_update( &hmac_md5, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
1382 hmac_md5_final( &hmac_md5, digest );
1384 if (encrypt && flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1386 if (dir == SIGN_SEND)
1387 arc4_process( &ctx->crypt.ntlm2.send_arc4info, digest, 8 );
1388 else
1389 arc4_process( &ctx->crypt.ntlm2.recv_arc4info, digest, 8 );
1392 sig[0] = (sign_version >> 0) & 0xff;
1393 sig[1] = (sign_version >> 8) & 0xff;
1394 sig[2] = (sign_version >> 16) & 0xff;
1395 sig[3] = (sign_version >> 24) & 0xff;
1396 memcpy( sig + 4, digest, 8 );
1397 memcpy( sig + 12, seq_no, 4 );
1399 msg->pBuffers[idx].cbBuffer = 16;
1400 return SEC_E_OK;
1403 if (flags & FLAG_NEGOTIATE_SIGN)
1405 unsigned int crc = 0;
1407 for (i = 0; i < msg->cBuffers; ++i)
1409 if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
1410 crc = RtlComputeCrc32( crc, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
1413 sig[0] = (sign_version >> 0) & 0xff;
1414 sig[1] = (sign_version >> 8) & 0xff;
1415 sig[2] = (sign_version >> 16) & 0xff;
1416 sig[3] = (sign_version >> 24) & 0xff;
1417 memset( sig + 4, 0, 4 );
1418 sig[8] = (crc >> 0) & 0xff;
1419 sig[9] = (crc >> 8) & 0xff;
1420 sig[10] = (crc >> 16) & 0xff;
1421 sig[11] = (crc >> 24) & 0xff;
1422 sig[12] = (ctx->crypt.ntlm.seq_no >> 0) & 0xff;
1423 sig[13] = (ctx->crypt.ntlm.seq_no >> 8) & 0xff;
1424 sig[14] = (ctx->crypt.ntlm.seq_no >> 16) & 0xff;
1425 sig[15] = (ctx->crypt.ntlm.seq_no >> 24) & 0xff;
1426 ctx->crypt.ntlm.seq_no++;
1428 if (encrypt) arc4_process( &ctx->crypt.ntlm.arc4info, sig + 4, 12 );
1429 return SEC_E_OK;
1432 if (flags & FLAG_NEGOTIATE_ALWAYS_SIGN || !flags)
1434 /* create dummy signature */
1435 memset( msg->pBuffers[idx].pvBuffer, 0, 16 );
1436 memset( msg->pBuffers[idx].pvBuffer, 1, 1 );
1437 msg->pBuffers[idx].cbBuffer = 16;
1438 return SEC_E_OK;
1441 return SEC_E_UNSUPPORTED_FUNCTION;
1444 static NTSTATUS NTAPI ntlm_SpMakeSignature( LSA_SEC_HANDLE handle, ULONG qop, SecBufferDesc *msg, ULONG msg_seq_no )
1446 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1447 int idx;
1449 TRACE( "%#Ix, %#lx, %p, %lu\n", handle, qop, msg, msg_seq_no );
1450 if (qop) FIXME( "ignoring quality of protection %#lx\n", qop );
1451 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1453 if (!handle) return SEC_E_INVALID_HANDLE;
1454 if (!msg || !msg->pBuffers || msg->cBuffers < 2 || (idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1)
1455 return SEC_E_INVALID_TOKEN;
1456 if (msg->pBuffers[idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1458 return create_signature( ctx, ctx->flags, msg, idx, SIGN_SEND, TRUE );
1461 static NTSTATUS verify_signature( struct ntlm_ctx *ctx, unsigned int flags, SecBufferDesc *msg, int idx )
1463 NTSTATUS status;
1464 unsigned int i;
1465 SecBufferDesc desc;
1466 SecBuffer *buf;
1467 char sig[16];
1469 if (!(buf = malloc( msg->cBuffers * sizeof(*buf) ))) return SEC_E_INSUFFICIENT_MEMORY;
1470 desc.ulVersion = SECBUFFER_VERSION;
1471 desc.cBuffers = msg->cBuffers;
1472 desc.pBuffers = buf;
1474 for (i = 0; i < msg->cBuffers; i++)
1476 if (msg->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1478 buf[i].BufferType = SECBUFFER_TOKEN;
1479 buf[i].cbBuffer = 16;
1480 buf[i].pvBuffer = sig;
1482 else
1484 buf[i].BufferType = msg->pBuffers[i].BufferType;
1485 buf[i].cbBuffer = msg->pBuffers[i].cbBuffer;
1486 buf[i].pvBuffer = msg->pBuffers[i].pvBuffer;
1490 if ((status = create_signature( ctx, flags, &desc, idx, SIGN_RECV, TRUE )) == SEC_E_OK)
1492 if (memcmp( (char *)buf[idx].pvBuffer + 8, (char *)msg->pBuffers[idx].pvBuffer + 8, 8 ))
1493 status = SEC_E_MESSAGE_ALTERED;
1496 free( buf );
1497 return status;
1500 static NTSTATUS NTAPI ntlm_SpVerifySignature( LSA_SEC_HANDLE handle, SecBufferDesc *msg, ULONG msg_seq_no, ULONG *qop )
1502 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1503 int idx;
1505 TRACE( "%#Ix, %p, %lu, %p\n", handle, msg, msg_seq_no, qop );
1506 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1508 if (!handle) return SEC_E_INVALID_HANDLE;
1509 if (!msg || !msg->pBuffers || msg->cBuffers < 2 || (idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1)
1510 return SEC_E_INVALID_TOKEN;
1511 if (msg->pBuffers[idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1513 return verify_signature( ctx, ctx->flags, msg, idx );
1516 static NTSTATUS NTAPI ntlm_SpSealMessage( LSA_SEC_HANDLE handle, ULONG qop, SecBufferDesc *msg, ULONG msg_seq_no )
1518 int token_idx, data_idx;
1519 struct ntlm_ctx *ctx;
1521 TRACE( "%#Ix, %#lx, %p %lu\n", handle, qop, msg, msg_seq_no );
1522 if (qop) FIXME( "ignoring quality of protection %#lx\n", qop );
1523 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1525 if (!handle) return SEC_E_INVALID_HANDLE;
1527 if (!msg || !msg->pBuffers || msg->cBuffers < 2 ||
1528 (token_idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1 ||
1529 (data_idx = get_buffer_index( msg, SECBUFFER_DATA )) == -1) return SEC_E_INVALID_TOKEN;
1531 if (msg->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1533 ctx = (struct ntlm_ctx *)handle;
1534 if (ctx->flags & FLAG_NEGOTIATE_NTLM2 && ctx->flags & FLAG_NEGOTIATE_SEAL)
1536 create_signature( ctx, ctx->flags, msg, token_idx, SIGN_SEND, FALSE );
1538 arc4_process( &ctx->crypt.ntlm2.send_arc4info, msg->pBuffers[data_idx].pvBuffer,
1539 msg->pBuffers[data_idx].cbBuffer );
1540 if (ctx->flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1541 arc4_process( &ctx->crypt.ntlm2.send_arc4info, (char *)msg->pBuffers[token_idx].pvBuffer + 4, 8 );
1543 else
1545 char *sig = msg->pBuffers[token_idx].pvBuffer;
1547 create_signature( ctx, ctx->flags | FLAG_NEGOTIATE_SIGN, msg, token_idx, SIGN_SEND, FALSE );
1549 arc4_process( &ctx->crypt.ntlm.arc4info, msg->pBuffers[data_idx].pvBuffer, msg->pBuffers[data_idx].cbBuffer );
1550 arc4_process( &ctx->crypt.ntlm.arc4info, sig + 4, 12 );
1552 if (ctx->flags & FLAG_NEGOTIATE_ALWAYS_SIGN || !ctx->flags) memset( sig + 4, 0, 4 );
1555 return SEC_E_OK;
1558 static NTSTATUS NTAPI ntlm_SpUnsealMessage( LSA_SEC_HANDLE handle, SecBufferDesc *msg, ULONG msg_seq_no, ULONG *qop )
1560 int token_idx, data_idx;
1561 struct ntlm_ctx *ctx;
1563 TRACE( "%#Ix, %p, %lu, %p\n", handle, msg, msg_seq_no, qop );
1564 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1566 if (!handle) return SEC_E_INVALID_HANDLE;
1568 if (!msg || !msg->pBuffers || msg->cBuffers < 2 ||
1569 (token_idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1 ||
1570 (data_idx = get_buffer_index( msg, SECBUFFER_DATA )) == -1) return SEC_E_INVALID_TOKEN;
1572 if (msg->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1574 ctx = (struct ntlm_ctx *)handle;
1575 if (ctx->flags & FLAG_NEGOTIATE_NTLM2 && ctx->flags & FLAG_NEGOTIATE_SEAL)
1576 arc4_process( &ctx->crypt.ntlm2.recv_arc4info, msg->pBuffers[data_idx].pvBuffer,
1577 msg->pBuffers[data_idx].cbBuffer );
1578 else
1579 arc4_process( &ctx->crypt.ntlm.arc4info, msg->pBuffers[data_idx].pvBuffer,
1580 msg->pBuffers[data_idx].cbBuffer);
1582 /* make sure we use a session key for the signature check, SealMessage always does that,
1583 even in the dummy case */
1584 return verify_signature( ctx, ctx->flags | FLAG_NEGOTIATE_SIGN, msg, token_idx );
1587 static SECPKG_USER_FUNCTION_TABLE ntlm_user_table =
1589 ntlm_SpInstanceInit,
1590 NULL, /* SpInitUserModeContext */
1591 ntlm_SpMakeSignature,
1592 ntlm_SpVerifySignature,
1593 ntlm_SpSealMessage,
1594 ntlm_SpUnsealMessage,
1595 NULL, /* SpGetContextToken */
1596 NULL, /* SpQueryContextAttributes */
1597 NULL, /* SpCompleteAuthToken */
1598 NULL, /* SpDeleteContext */
1599 NULL, /* SpFormatCredentialsFn */
1600 NULL, /* SpMarshallSupplementalCreds */
1601 NULL, /* SpExportSecurityContext */
1602 NULL /* SpImportSecurityContext */
1605 NTSTATUS NTAPI SpUserModeInitialize( ULONG lsa_version, ULONG *package_version, SECPKG_USER_FUNCTION_TABLE **table,
1606 ULONG *table_count )
1608 TRACE( "%#lx, %p, %p, %p\n", lsa_version, package_version, table, table_count );
1610 *package_version = SECPKG_INTERFACE_VERSION;
1611 *table = &ntlm_user_table;
1612 *table_count = 1;
1613 return STATUS_SUCCESS;
1616 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved )
1618 switch (reason)
1620 case DLL_PROCESS_ATTACH:
1621 if (__wine_init_unix_call())
1622 return FALSE;
1623 DisableThreadLibraryCalls( hinst );
1624 break;
1626 return TRUE;