user32/tests: Link directly to imm32.
[wine.git] / dlls / msv1_0 / main.c
blob8785754cd51d7761ebe20e53be7f79a98349bd32
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 unixlib_handle_t ntlm_handle;
48 static NTSTATUS ntlm_check_version(void)
50 return __wine_unix_call( ntlm_handle, unix_check_version, NULL );
53 static void ntlm_cleanup( struct ntlm_ctx *ctx )
55 __wine_unix_call( ntlm_handle, unix_cleanup, ctx );
58 static NTSTATUS ntlm_chat( struct ntlm_ctx *ctx, char *buf, unsigned int buflen, unsigned int *retlen )
60 struct chat_params params = { ctx, buf, buflen, retlen };
62 return __wine_unix_call( ntlm_handle, unix_chat, &params );
65 static NTSTATUS ntlm_fork( struct ntlm_ctx *ctx, char **argv )
67 struct fork_params params = { ctx, argv };
69 return __wine_unix_call( ntlm_handle, unix_fork, &params );
72 #define NTLM_CAPS \
73 ( SECPKG_FLAG_INTEGRITY \
74 | SECPKG_FLAG_PRIVACY \
75 | SECPKG_FLAG_TOKEN_ONLY \
76 | SECPKG_FLAG_CONNECTION \
77 | SECPKG_FLAG_MULTI_REQUIRED \
78 | SECPKG_FLAG_IMPERSONATION \
79 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
80 | SECPKG_FLAG_NEGOTIABLE \
81 | SECPKG_FLAG_LOGON \
82 | SECPKG_FLAG_RESTRICTED_TOKENS )
84 #define NTLM_MAX_BUF 1904
86 static const SecPkgInfoW ntlm_package_info =
88 NTLM_CAPS,
90 RPC_C_AUTHN_WINNT,
91 NTLM_MAX_BUF,
92 (SEC_WCHAR *)L"NTLM",
93 (SEC_WCHAR *)L"NTLM Security Package"
96 static inline const char *debugstr_as( const STRING *str )
98 if (!str) return "<null>";
99 return debugstr_an( str->Buffer, str->Length );
102 static inline const char *debugstr_us( const UNICODE_STRING *str )
104 if (!str) return "<null>";
105 return debugstr_wn( str->Buffer, str->Length / sizeof(WCHAR) );
108 static NTSTATUS NTAPI ntlm_LsaApInitializePackage( ULONG package_id, LSA_DISPATCH_TABLE *dispatch,
109 LSA_STRING *database, LSA_STRING *confidentiality,
110 LSA_STRING **package_name )
112 LSA_STRING *str;
113 char *ptr;
115 TRACE( "%#lx, %p, %s, %s, %p\n", package_id, dispatch, debugstr_as(database), debugstr_as(confidentiality),
116 package_name );
118 if (ntlm_check_version())
120 ERR( "no NTLM support, expect problems\n" );
121 return STATUS_UNSUCCESSFUL;
124 if (!(str = dispatch->AllocateLsaHeap( sizeof(*str) + sizeof("NTLM" )))) return STATUS_NO_MEMORY;
125 ptr = (char *)(str + 1);
126 memcpy( ptr, "NTLM", sizeof("NTLM") );
127 RtlInitString( str, ptr );
129 ntlm_package_id = package_id;
130 lsa_dispatch = *dispatch;
132 *package_name = str;
133 return STATUS_SUCCESS;
136 static NTSTATUS NTAPI ntlm_SpInitialize( ULONG_PTR package_id, SECPKG_PARAMETERS *params,
137 LSA_SECPKG_FUNCTION_TABLE *lsa_function_table )
139 TRACE( "%#Ix, %p, %p\n", package_id, params, lsa_function_table );
141 if (ntlm_check_version())
143 ERR( "no NTLM support, expect problems\n" );
144 return STATUS_UNSUCCESSFUL;
146 return STATUS_SUCCESS;
149 static NTSTATUS NTAPI ntlm_SpGetInfo( SecPkgInfoW *info )
151 TRACE( "%p\n", info );
152 *info = ntlm_package_info;
153 return STATUS_SUCCESS;
156 static char *get_username_arg( const WCHAR *user, int user_len )
158 static const char arg[] = "--username=";
159 int len = sizeof(arg);
160 char *ret;
162 len += WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, user, user_len, NULL, 0, NULL, NULL );
163 if (!(ret = malloc( len ))) return NULL;
164 memcpy( ret, arg, sizeof(arg) - 1 );
165 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, user, user_len, ret + sizeof(arg) - 1,
166 len - sizeof(arg) + 1, NULL, NULL );
167 ret[len - 1] = 0;
168 return ret;
171 static char *get_domain_arg( const WCHAR *domain, int domain_len )
173 static const char arg[] = "--domain=";
174 int len = sizeof(arg);
175 char *ret;
177 len += WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain, domain_len, NULL, 0, NULL, NULL );
178 if (!(ret = malloc( len ))) return NULL;
179 memcpy( ret, arg, sizeof(arg) - 1 );
180 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domain, domain_len, ret + sizeof(arg) - 1,
181 len - sizeof(arg) + 1, NULL, NULL );
182 ret[len - 1] = 0;
183 return ret;
186 #define WINE_NO_CACHED_CREDENTIALS 0x10000000
187 static NTSTATUS NTAPI ntlm_SpAcquireCredentialsHandle( UNICODE_STRING *principal, ULONG cred_use, LUID *logon_id,
188 void *auth_data, void *get_key_fn, void *get_key_arg,
189 LSA_SEC_HANDLE *handle, TimeStamp *expiry )
191 SECURITY_STATUS status = SEC_E_INSUFFICIENT_MEMORY;
192 struct ntlm_cred *cred = NULL;
193 WCHAR *domain = NULL, *user = NULL, *password = NULL;
194 SEC_WINNT_AUTH_IDENTITY_W *id = NULL;
196 TRACE( "%s, %#lx, %p, %p, %p, %p, %p, %p\n", debugstr_us(principal), cred_use, logon_id, auth_data,
197 get_key_fn, get_key_arg, cred, expiry );
199 switch (cred_use & ~SECPKG_CRED_RESERVED)
201 case SECPKG_CRED_INBOUND:
202 if (!(cred = malloc( sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY;
203 cred->mode = MODE_SERVER;
204 cred->username_arg = NULL;
205 cred->domain_arg = NULL;
206 cred->password = NULL;
207 cred->password_len = 0;
208 cred->no_cached_credentials = 0;
210 *handle = (LSA_SEC_HANDLE)cred;
211 status = SEC_E_OK;
212 break;
214 case SECPKG_CRED_OUTBOUND:
215 if (!(cred = malloc( sizeof(*cred) ))) return SEC_E_INSUFFICIENT_MEMORY;
217 cred->mode = MODE_CLIENT;
218 cred->username_arg = NULL;
219 cred->domain_arg = NULL;
220 cred->password = NULL;
221 cred->password_len = 0;
222 cred->no_cached_credentials = (cred_use & WINE_NO_CACHED_CREDENTIALS);
224 if ((id = auth_data))
226 int domain_len = 0, user_len = 0, password_len = 0;
227 if (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI)
229 if (id->DomainLength)
231 domain_len = MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, NULL, 0 );
232 if (!(domain = malloc( sizeof(WCHAR) * domain_len ))) goto done;
233 MultiByteToWideChar( CP_ACP, 0, (char *)id->Domain, id->DomainLength, domain, domain_len );
235 if (id->UserLength)
237 user_len = MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, NULL, 0 );
238 if (!(user = malloc( sizeof(WCHAR) * user_len ))) goto done;
239 MultiByteToWideChar( CP_ACP, 0, (char *)id->User, id->UserLength, user, user_len );
241 if (id->PasswordLength)
243 password_len = MultiByteToWideChar( CP_ACP, 0,(char *)id->Password, id->PasswordLength, NULL, 0 );
244 if (!(password = malloc( sizeof(WCHAR) * password_len ))) goto done;
245 MultiByteToWideChar( CP_ACP, 0, (char *)id->Password, id->PasswordLength, password, password_len );
248 else
250 domain = id->Domain;
251 domain_len = id->DomainLength;
252 user = id->User;
253 user_len = id->UserLength;
254 password = id->Password;
255 password_len = id->PasswordLength;
258 TRACE( "username is %s\n", debugstr_wn(user, user_len) );
259 TRACE( "domain name is %s\n", debugstr_wn(domain, domain_len) );
261 cred->username_arg = get_username_arg( user, user_len );
262 cred->domain_arg = get_domain_arg( domain, domain_len );
263 if (password_len)
265 cred->password_len = WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len,
266 NULL, 0, NULL, NULL );
267 if (!(cred->password = malloc( cred->password_len ))) goto done;
268 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, password, password_len, cred->password,
269 cred->password_len, NULL, NULL );
273 *handle = (LSA_SEC_HANDLE)cred;
274 status = SEC_E_OK;
275 break;
277 case SECPKG_CRED_BOTH:
278 FIXME( "SECPKG_CRED_BOTH not supported\n" );
279 status = SEC_E_UNSUPPORTED_FUNCTION;
280 break;
282 default:
283 status = SEC_E_UNKNOWN_CREDENTIALS;
284 break;
287 done:
288 if (id && (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI))
290 free( domain );
291 free( user );
292 free( password );
294 if (status != SEC_E_OK) free( cred );
295 return status;
298 static NTSTATUS NTAPI ntlm_SpFreeCredentialsHandle( LSA_SEC_HANDLE handle )
300 struct ntlm_cred *cred = (struct ntlm_cred *)handle;
302 TRACE( "%#Ix\n", handle );
304 if (!cred) return SEC_E_OK;
306 cred->mode = MODE_INVALID;
307 if (cred->password) memset( cred->password, 0, cred->password_len );
308 free( cred->password );
309 free( cred->username_arg );
310 free( cred->domain_arg );
311 free( cred );
312 return SEC_E_OK;
315 static BOOL get_cached_credential( const UNICODE_STRING *target, CREDENTIALW **cred )
317 const WCHAR *ptr, *host;
318 WCHAR *hostonly;
319 size_t len;
320 BOOL ret;
322 if (!target) return FALSE;
324 len = target->Length / sizeof(WCHAR);
325 if ((host = wmemchr( target->Buffer, '/', len )))
327 host++;
328 len -= host - target->Buffer;
329 if (!(ptr = wmemchr( host, ':', len ))) ptr = wmemchr( host, '/', len );
330 if (!ptr) ptr = host + len;
332 else
334 host = target->Buffer;
335 ptr = host + len;
338 if (!(hostonly = malloc( (ptr - host + 1) * sizeof(WCHAR) ))) return FALSE;
339 memcpy( hostonly, host, (ptr - host) * sizeof(WCHAR) );
340 hostonly[ptr - host] = 0;
342 ret = CredReadW( hostonly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred );
343 free( hostonly );
344 return ret;
347 static UINT encode_base64( const char *bin, unsigned int len, char *base64 )
349 static const char base64enc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
350 UINT n = 0, x;
352 while (len > 0)
354 /* first 6 bits, all from bin[0] */
355 base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
356 x = (bin[0] & 3) << 4;
358 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
359 if (len == 1)
361 base64[n++] = base64enc[x];
362 base64[n++] = '=';
363 base64[n++] = '=';
364 break;
366 base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
367 x = (bin[1] & 0x0f) << 2;
369 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
370 if (len == 2)
372 base64[n++] = base64enc[x];
373 base64[n++] = '=';
374 break;
376 base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
378 /* last 6 bits, all from bin[2] */
379 base64[n++] = base64enc[bin[2] & 0x3f];
380 bin += 3;
381 len -= 3;
383 base64[n] = 0;
384 return n;
387 static inline char decode_char( char c )
389 if (c >= 'A' && c <= 'Z') return c - 'A';
390 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
391 if (c >= '0' && c <= '9') return c - '0' + 52;
392 if (c == '+') return 62;
393 if (c == '/') return 63;
394 return 64;
397 static unsigned int decode_base64( const char *base64, unsigned int len, char *buf )
399 unsigned int i = 0;
400 char c0, c1, c2, c3;
401 const char *p = base64;
403 while (len > 4)
405 if ((c0 = decode_char( p[0] )) > 63) return 0;
406 if ((c1 = decode_char( p[1] )) > 63) return 0;
407 if ((c2 = decode_char( p[2] )) > 63) return 0;
408 if ((c3 = decode_char( p[3] )) > 63) return 0;
409 if (buf)
411 buf[i + 0] = (c0 << 2) | (c1 >> 4);
412 buf[i + 1] = (c1 << 4) | (c2 >> 2);
413 buf[i + 2] = (c2 << 6) | c3;
415 len -= 4;
416 i += 3;
417 p += 4;
419 if (p[2] == '=')
421 if ((c0 = decode_char( p[0] )) > 63) return 0;
422 if ((c1 = decode_char( p[1] )) > 63) return 0;
423 if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
424 i++;
426 else if (p[3] == '=')
428 if ((c0 = decode_char( p[0] )) > 63) return 0;
429 if ((c1 = decode_char( p[1] )) > 63) return 0;
430 if ((c2 = decode_char( p[2] )) > 63) return 0;
431 if (buf)
433 buf[i + 0] = (c0 << 2) | (c1 >> 4);
434 buf[i + 1] = (c1 << 4) | (c2 >> 2);
436 i += 2;
438 else
440 if ((c0 = decode_char( p[0] )) > 63) return 0;
441 if ((c1 = decode_char( p[1] )) > 63) return 0;
442 if ((c2 = decode_char( p[2] )) > 63) return 0;
443 if ((c3 = decode_char( p[3] )) > 63) return 0;
444 if (buf)
446 buf[i + 0] = (c0 << 2) | (c1 >> 4);
447 buf[i + 1] = (c1 << 4) | (c2 >> 2);
448 buf[i + 2] = (c2 << 6) | c3;
450 i += 3;
452 return i;
455 struct md4_ctx
457 unsigned int buf[4];
458 unsigned int i[2];
459 unsigned char in[64];
460 unsigned char digest[16];
463 void WINAPI MD4Init( struct md4_ctx * );
464 void WINAPI MD4Update( struct md4_ctx *, const char *, unsigned int );
465 void WINAPI MD4Final( struct md4_ctx * );
467 static void create_ntlm1_session_key( const char *secret, unsigned int len, char *session_key )
469 struct md4_ctx ctx;
470 char hash[16];
472 MD4Init( &ctx );
473 MD4Update( &ctx, secret, len );
474 MD4Final( &ctx );
475 memcpy( hash, ctx.digest, 16 );
477 MD4Init( &ctx );
478 MD4Update( &ctx, hash, 16 );
479 MD4Final( &ctx );
480 memcpy( session_key, ctx.digest, 16 );
483 struct md5_ctx
485 unsigned int i[2];
486 unsigned int buf[4];
487 unsigned char in[64];
488 unsigned char digest[16];
491 void WINAPI MD5Init( struct md5_ctx * );
492 void WINAPI MD5Update( struct md5_ctx *, const char *, unsigned int );
493 void WINAPI MD5Final( struct md5_ctx * );
495 static void calc_ntlm2_subkey( const char *session_key, const char *magic, char *subkey )
497 struct md5_ctx ctx;
499 MD5Init( &ctx );
500 MD5Update( &ctx, session_key, 16 );
501 MD5Update( &ctx, magic, strlen(magic) + 1 );
502 MD5Final( &ctx );
503 memcpy( subkey, ctx.digest, 16 );
506 static const char client_to_server_sign_constant[] = "session key to client-to-server signing key magic constant";
507 static const char client_to_server_seal_constant[] = "session key to client-to-server sealing key magic constant";
508 static const char server_to_client_sign_constant[] = "session key to server-to-client signing key magic constant";
509 static const char server_to_client_seal_constant[] = "session key to server-to-client sealing key magic constant";
511 static void create_ntlm2_subkeys( struct ntlm_ctx *ctx )
513 if (ctx->mode == MODE_CLIENT)
515 calc_ntlm2_subkey( ctx->session_key, client_to_server_sign_constant, ctx->crypt.ntlm2.send_sign_key );
516 calc_ntlm2_subkey( ctx->session_key, client_to_server_seal_constant, ctx->crypt.ntlm2.send_seal_key );
517 calc_ntlm2_subkey( ctx->session_key, server_to_client_sign_constant, ctx->crypt.ntlm2.recv_sign_key );
518 calc_ntlm2_subkey( ctx->session_key, server_to_client_seal_constant, ctx->crypt.ntlm2.recv_seal_key );
520 else
522 calc_ntlm2_subkey( ctx->session_key, server_to_client_sign_constant, ctx->crypt.ntlm2.send_sign_key );
523 calc_ntlm2_subkey( ctx->session_key, server_to_client_seal_constant, ctx->crypt.ntlm2.send_seal_key );
524 calc_ntlm2_subkey( ctx->session_key, client_to_server_sign_constant, ctx->crypt.ntlm2.recv_sign_key );
525 calc_ntlm2_subkey( ctx->session_key, client_to_server_seal_constant, ctx->crypt.ntlm2.recv_seal_key );
530 * The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack,
531 * which in turn is based on public domain code by Wei Dai
533 static void arc4_init( struct arc4_info *info, const char *key, unsigned int len )
535 unsigned int key_idx = 0, state_idx = 0, i, a;
537 info->x = info->y = 0;
538 for (i = 0; i < 256; i++) info->state[i] = i;
540 for (i = 0; i < 256; i++)
542 a = info->state[i];
543 state_idx += key[key_idx] + a;
544 state_idx &= 0xff;
545 info->state[i] = info->state[state_idx];
546 info->state[state_idx] = a;
547 if (++key_idx >= len) key_idx = 0;
551 static void arc4_process( struct arc4_info *info, char *buf, unsigned int len )
553 char *state = info->state;
554 unsigned int x = info->x, y = info->y, a, b;
556 while (len--)
558 x = (x + 1) & 0xff;
559 a = state[x];
560 y = (y + a) & 0xff;
561 b = state[y];
562 state[x] = b;
563 state[y] = a;
564 *buf++ ^= state[(a + b) & 0xff];
567 info->x = x;
568 info->y = y;
571 static int get_buffer_index( SecBufferDesc *desc, ULONG type )
573 int idx;
574 for (idx = 0; idx < desc->cBuffers; idx++)
576 if (desc->pBuffers[idx].BufferType == type) return idx;
578 return -1;
581 static NTSTATUS NTAPI ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA_SEC_HANDLE ctx_handle,
582 UNICODE_STRING *target, ULONG ctx_req, ULONG data_rep,
583 SecBufferDesc *input, LSA_SEC_HANDLE *new_ctx_handle,
584 SecBufferDesc *output, ULONG *ctx_attr, TimeStamp *expiry,
585 BOOLEAN *mapped_ctx, SecBuffer *ctx_data )
587 NTSTATUS status = SEC_E_INSUFFICIENT_MEMORY;
588 struct ntlm_ctx *ctx = NULL;
589 char *buf, *bin, *want_flags = NULL, *username = NULL, *domain = NULL, *password = NULL;
590 unsigned int len, bin_len;
591 int idx;
593 TRACE( "%#Ix, %#Ix, %s, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle, ctx_handle, debugstr_us(target),
594 ctx_req, data_rep, input, new_ctx_handle, output, ctx_attr, expiry, mapped_ctx, ctx_data );
596 /* when communicating with the client there can be the following reply packets:
597 * YR <base64 blob> should be sent to the server
598 * PW should be sent back to helper with base64 encoded password
599 * AF <base64 blob> client is done, blob should be sent to server with KK prefixed
600 * GF <string list> a string list of negotiated flags
601 * GK <base64 blob> base64 encoded session key
602 * BH <char reason> something broke
604 * The squid cache size is 2010 chars and that's what ntlm_auth uses */
606 if (!(buf = malloc( NTLM_MAX_BUF ))) return SEC_E_INSUFFICIENT_MEMORY;
607 if (!(bin = malloc( NTLM_MAX_BUF ))) goto done;
609 if (!ctx_handle && !input)
611 char *argv[5];
612 int password_len = 0;
613 struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
615 if (!cred || cred->mode != MODE_CLIENT)
617 status = SEC_E_INVALID_HANDLE;
618 goto done;
621 argv[0] = (char *)"ntlm_auth";
622 argv[1] = (char *)"--helper-protocol=ntlmssp-client-1";
623 if (!cred->username_arg && !cred->domain_arg)
625 WKSTA_USER_INFO_1 *ui = NULL;
626 NET_API_STATUS ret;
627 CREDENTIALW *cached;
629 if (get_cached_credential( target, &cached ))
631 WCHAR *p;
632 if ((p = wcschr( cached->UserName, '\\' )))
634 if (!(domain = get_domain_arg( cached->UserName, p - cached->UserName ))) goto done;
635 p++;
637 else
639 if (!(domain = get_domain_arg( NULL, 0 ))) goto done;
640 p = cached->UserName;
642 if (!(username = get_username_arg( p, -1 ))) goto done;
644 if (cached->CredentialBlobSize)
646 password_len = WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, (WCHAR *)cached->CredentialBlob,
647 cached->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL );
648 if (!(password = malloc( password_len ))) goto done;
649 WideCharToMultiByte( CP_UNIXCP, WC_NO_BEST_FIT_CHARS, (WCHAR *)cached->CredentialBlob,
650 cached->CredentialBlobSize / sizeof(WCHAR), password, password_len, NULL, NULL );
652 CredFree( cached );
654 argv[2] = username;
655 argv[3] = domain;
656 argv[4] = NULL;
658 else
660 ret = NetWkstaUserGetInfo( NULL, 1, (BYTE **)&ui );
661 if (ret != NERR_Success || !ui || cred->no_cached_credentials)
663 status = SEC_E_NO_CREDENTIALS;
664 goto done;
666 if (!(username = get_username_arg( ui->wkui1_username, -1 ))) goto done;
667 NetApiBufferFree( ui );
668 TRACE("using cached credentials\n");
670 argv[2] = username;
671 argv[3] = (char *)"--use-cached-creds";
672 argv[4] = NULL;
675 else
677 argv[2] = cred->username_arg;
678 argv[3] = cred->domain_arg;
679 argv[4] = NULL;
682 if (!(ctx = calloc( 1, sizeof(*ctx) ))) goto done;
684 if ((status = ntlm_fork( ctx, argv )) != SEC_E_OK) goto done;
685 status = SEC_E_INSUFFICIENT_MEMORY;
687 ctx->mode = MODE_CLIENT;
688 memset( ctx->session_key, 0, sizeof(ctx->session_key) );
690 /* generate the dummy session key = MD4(MD4(password))*/
691 if (password || cred->password)
693 WCHAR *passwordW;
694 len = MultiByteToWideChar( CP_ACP, 0, password ? password : cred->password,
695 password ? password_len : cred->password_len, NULL, 0 );
696 if (!(passwordW = malloc( len * sizeof(WCHAR) ))) goto done;
697 MultiByteToWideChar( CP_ACP, 0, password ? password : cred->password,
698 password ? password_len : cred->password_len, passwordW, len );
700 create_ntlm1_session_key( (const char *)passwordW, len * sizeof(WCHAR), ctx->session_key );
701 free( passwordW );
704 /* allocate space for a maximum string of
705 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL NTLMSSP_FEATURE_SESSION_KEY"
707 if (!(want_flags = malloc( 73 ))) goto done;
708 strcpy( want_flags, "SF" );
709 if (ctx_req & ISC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
710 if ((ctx_req & ISC_REQ_INTEGRITY) || (ctx_req & ISC_REQ_REPLAY_DETECT) ||
711 (ctx_req & ISC_REQ_SEQUENCE_DETECT)) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
713 if (ctx_req & ISC_REQ_CONNECTION) ctx->attrs |= ISC_RET_CONNECTION;
714 if (ctx_req & ISC_REQ_EXTENDED_ERROR) ctx->attrs |= ISC_RET_EXTENDED_ERROR;
715 if (ctx_req & ISC_REQ_MUTUAL_AUTH) ctx->attrs |= ISC_RET_MUTUAL_AUTH;
716 if (ctx_req & ISC_REQ_USE_DCE_STYLE) ctx->attrs |= ISC_RET_USED_DCE_STYLE;
717 if (ctx_req & ISC_REQ_DELEGATE) ctx->attrs |= ISC_RET_DELEGATE;
718 if (ctx_req & ISC_REQ_STREAM) FIXME( "ISC_REQ_STREAM\n" );
720 /* use cached credentials if no password was given, fall back to an empty password on failure */
721 if (!password && !cred->password)
723 strcpy( buf, "OK" );
724 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
726 /* if the helper replied with "PW" using cached credentials failed */
727 if (!strncmp( buf, "PW", 2 ))
729 TRACE( "using cached credentials failed\n" );
730 strcpy( buf, "PW AA==" );
732 else strcpy( buf, "OK" ); /* just do a noop on the next run */
734 else
736 strcpy( buf, "PW " );
737 encode_base64( password ? password : cred->password, password ? password_len : cred->password_len, buf + 3 );
740 TRACE( "sending to ntlm_auth: %s\n", debugstr_a(buf) );
741 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
742 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf) );
744 if (strlen( want_flags ) > 2)
746 TRACE( "want flags are %s\n", debugstr_a(want_flags) );
747 strcpy( buf, want_flags );
748 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
749 if (!strncmp( buf, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
752 strcpy( buf, "YR" );
753 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
754 TRACE( "ntlm_auth returned %s\n", buf );
755 if (strncmp( buf, "YR ", 3 ))
757 status = SEC_E_INTERNAL_ERROR;
758 goto done;
760 bin_len = decode_base64( buf + 3, len - 3, bin );
762 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
763 status = SEC_I_CONTINUE_NEEDED;
765 else /* !ctx_handle && !input */
767 if (!input || ((idx = get_buffer_index( input, SECBUFFER_TOKEN )) == -1))
769 status = SEC_E_INVALID_TOKEN;
770 goto done;
773 ctx = (struct ntlm_ctx *)ctx_handle;
774 if (!ctx || ctx->mode != MODE_CLIENT)
776 status = SEC_E_INVALID_HANDLE;
777 goto done;
780 if (!input->pBuffers[idx].pvBuffer || input->pBuffers[idx].cbBuffer > NTLM_MAX_BUF)
782 status = SEC_E_INVALID_TOKEN;
783 goto done;
785 bin_len = input->pBuffers[idx].cbBuffer;
786 memcpy( bin, input->pBuffers[idx].pvBuffer, bin_len );
788 strcpy( buf, "TT " );
789 encode_base64( bin, bin_len, buf + 3 );
790 TRACE( "server sent: %s\n", debugstr_a(buf) );
792 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len ))) goto done;
793 TRACE( "ntlm_auth returned: %s\n", debugstr_a(buf) );
795 if (strncmp( buf, "KK ", 3 ) && strncmp( buf, "AF ", 3 ))
797 status = SEC_E_INVALID_TOKEN;
798 goto done;
800 bin_len = decode_base64( buf + 3, len - 3, bin );
802 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
803 status = SEC_E_OK;
806 if (!output || ((idx = get_buffer_index( output, SECBUFFER_TOKEN )) == -1))
808 if (!ctx_handle && !input) *new_ctx_handle = 0;
809 status = SEC_E_BUFFER_TOO_SMALL;
810 goto done;
813 if (ctx_req & ISC_REQ_ALLOCATE_MEMORY)
815 /* freed with secur32.FreeContextBuffer */
816 if (!(output->pBuffers[idx].pvBuffer = RtlAllocateHeap( GetProcessHeap(), 0, bin_len )))
818 status = SEC_E_INSUFFICIENT_MEMORY;
819 goto done;
821 output->pBuffers[idx].cbBuffer = bin_len;
823 else if (output->pBuffers[idx].cbBuffer < bin_len)
825 if (!ctx_handle && !input) *new_ctx_handle = 0;
826 status = SEC_E_BUFFER_TOO_SMALL;
827 goto done;
830 if (!output->pBuffers[idx].pvBuffer)
832 if (!ctx_handle && !input) *new_ctx_handle = 0;
833 status = SEC_E_INTERNAL_ERROR;
834 goto done;
837 output->pBuffers[idx].cbBuffer = bin_len;
838 memcpy( output->pBuffers[idx].pvBuffer, bin, bin_len );
839 if (status == SEC_E_OK)
841 strcpy( buf, "GF" );
842 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
843 if (len < 3) ctx->flags = 0;
844 else sscanf( buf + 3, "%x", &ctx->flags );
846 strcpy( buf, "GK" );
847 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
849 if (!strncmp( buf, "BH", 2 )) TRACE( "no key negotiated\n" );
850 else if (!strncmp( buf, "GK ", 3 ))
852 bin_len = decode_base64( buf + 3, len - 3, bin );
853 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
854 memcpy( ctx->session_key, bin, bin_len );
857 arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
858 ctx->crypt.ntlm.seq_no = 0;
859 create_ntlm2_subkeys( ctx );
860 arc4_init( &ctx->crypt.ntlm2.send_arc4info, ctx->crypt.ntlm2.send_seal_key, 16 );
861 arc4_init( &ctx->crypt.ntlm2.recv_arc4info, ctx->crypt.ntlm2.recv_seal_key, 16 );
862 ctx->crypt.ntlm2.send_seq_no = 0;
863 ctx->crypt.ntlm2.recv_seq_no = 0;
866 done:
867 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
869 ntlm_cleanup( ctx );
870 free( ctx );
872 free( username );
873 free( domain );
874 free( password );
875 free( buf );
876 free( bin );
877 free( want_flags );
879 TRACE( "returning %#lx\n", status );
880 return status;
883 static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA_SEC_HANDLE ctx_handle,
884 SecBufferDesc *input, ULONG ctx_req, ULONG data_rep,
885 LSA_SEC_HANDLE *new_ctx_handle, SecBufferDesc *output,
886 ULONG *ctx_attr, TimeStamp *expiry, BOOLEAN *mapped_ctx,
887 SecBuffer *ctx_data )
889 NTSTATUS status = SEC_E_INSUFFICIENT_MEMORY;
890 struct ntlm_ctx *ctx = NULL;
891 char *buf, *bin, *want_flags = NULL;
892 unsigned int len, bin_len;
894 TRACE( "%#Ix, %#Ix, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle, ctx_handle, ctx_req, data_rep, input,
895 new_ctx_handle, output, ctx_attr, expiry, mapped_ctx, ctx_data );
896 if (ctx_req) FIXME( "ignoring flags %#lx\n", ctx_req );
898 if (!(buf = malloc( NTLM_MAX_BUF ))) return SEC_E_INSUFFICIENT_MEMORY;
899 if (!(bin = malloc( NTLM_MAX_BUF ))) goto done;
901 if (!ctx_handle)
903 struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
904 char *argv[3];
906 if (!cred || cred->mode != MODE_SERVER)
908 status = SEC_E_INVALID_HANDLE;
909 goto done;
912 if (!input || input->cBuffers < 1)
914 status = SEC_E_INCOMPLETE_MESSAGE;
915 goto done;
918 if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
920 status = SEC_E_INVALID_TOKEN;
921 goto done;
923 else bin_len = input->pBuffers[0].cbBuffer;
925 if (!(ctx = calloc( 1, sizeof(*ctx) ))) goto done;
927 argv[0] = (char *)"ntlm_auth";
928 argv[1] = (char *)"--helper-protocol=squid-2.5-ntlmssp";
929 argv[2] = NULL;
930 if ((status = ntlm_fork( ctx, argv )) != SEC_E_OK) goto done;
931 ctx->mode = MODE_SERVER;
933 if (!(want_flags = malloc( 73 )))
935 status = SEC_E_INSUFFICIENT_MEMORY;
936 goto done;
938 strcpy( want_flags, "SF" );
939 if (ctx_req & ASC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
940 if (ctx_req & ASC_REQ_CONNECTION)
942 strcat( want_flags, " NTLMSSP_FEATURE_SESSION_KEY" );
943 ctx->attrs |= ASC_RET_CONNECTION;
945 if (ctx_req & ASC_REQ_INTEGRITY) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
946 if (ctx_req & ASC_REQ_ALLOCATE_MEMORY) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
947 if (ctx_req & ASC_REQ_EXTENDED_ERROR) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
948 if (ctx_req & ASC_REQ_MUTUAL_AUTH) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
949 if (ctx_req & ASC_REQ_REPLAY_DETECT) FIXME( "ASC_REQ_REPLAY_DETECT\n" );
950 if (ctx_req & ASC_REQ_SEQUENCE_DETECT) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
951 if (ctx_req & ASC_REQ_STREAM) FIXME( "ASC_REQ_STREAM\n" );
953 if (strlen( want_flags ) > 3)
955 TRACE( "want flags are %s\n", debugstr_a(want_flags) );
956 strcpy( buf, want_flags );
957 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
958 if (!strncmp( buf, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
961 memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
962 strcpy( buf, "YR " );
963 encode_base64( bin, bin_len, buf + 3 );
965 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
966 TRACE( "ntlm_auth returned %s\n", buf );
967 if (strncmp( buf, "TT ", 3))
969 status = SEC_E_INTERNAL_ERROR;
970 goto done;
972 bin_len = decode_base64( buf + 3, len - 3, bin );
974 if (!output || output->cBuffers < 1)
976 status = SEC_E_INSUFFICIENT_MEMORY;
977 goto done;
979 output->pBuffers[0].cbBuffer = bin_len;
980 output->pBuffers[0].BufferType = SECBUFFER_DATA;
981 memcpy( output->pBuffers[0].pvBuffer, bin, bin_len );
983 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
984 status = SEC_I_CONTINUE_NEEDED;
986 else
988 if (!input || input->cBuffers < 1)
990 status = SEC_E_INCOMPLETE_MESSAGE;
991 goto done;
994 ctx = (struct ntlm_ctx *)ctx_handle;
995 if (!ctx || ctx->mode != MODE_SERVER)
997 status = SEC_E_INVALID_HANDLE;
998 goto done;
1001 if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
1003 status = SEC_E_INVALID_TOKEN;
1004 goto done;
1006 else bin_len = input->pBuffers[0].cbBuffer;
1007 memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
1009 strcpy( buf, "KK " );
1010 encode_base64( bin, bin_len, buf + 3 );
1012 TRACE( "client sent %s\n", debugstr_a(buf) );
1013 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1014 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf) );
1016 /* At this point, we get a NA if the user didn't authenticate, but a BH if ntlm_auth could not
1017 * connect to winbindd. Apart from running Wine as root, there is no way to fix this for now,
1018 * so just handle this as a failed login. */
1019 if (strncmp( buf, "AF ", 3 ))
1021 if (!strncmp( buf, "NA ", 3 ))
1023 status = SEC_E_LOGON_DENIED;
1024 goto done;
1026 else
1028 const char err_v3[] = "BH NT_STATUS_ACCESS_DENIED";
1029 const char err_v4[] = "BH NT_STATUS_UNSUCCESSFUL";
1031 if ((len >= strlen(err_v3) && !strncmp( buf, err_v3, strlen(err_v3) )) ||
1032 (len >= strlen(err_v4) && !strncmp( buf, err_v4, strlen(err_v4) )))
1034 TRACE( "connection to winbindd failed\n" );
1035 status = SEC_E_LOGON_DENIED;
1037 else status = SEC_E_INTERNAL_ERROR;
1038 goto done;
1041 output->pBuffers[0].cbBuffer = 0;
1043 strcpy( buf, "GF" );
1044 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1045 if (len < 3) ctx->flags = 0;
1046 else sscanf( buf + 3, "%x", &ctx->flags );
1048 strcpy( buf, "GK" );
1049 if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
1051 if (!strncmp( buf, "BH", 2 )) TRACE( "no key negotiated\n" );
1052 else if (!strncmp( buf, "GK ", 3 ))
1054 bin_len = decode_base64( buf + 3, len - 3, bin );
1055 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
1056 memcpy( ctx->session_key, bin, bin_len );
1059 if (len < 3) memset( ctx->session_key, 0 , 16 );
1060 else
1062 if (!strncmp( buf, "BH ", 3 ))
1064 TRACE( "helper sent %s\n", debugstr_a(buf + 3) );
1065 /*FIXME: generate dummy session key = MD4(MD4(password))*/
1066 memset( ctx->session_key, 0 , 16 );
1068 else if (!strncmp( buf, "GK ", 3 ))
1070 bin_len = decode_base64( buf + 3, len - 3, bin );
1071 TRACE( "session key is %s\n", debugstr_a(buf + 3) );
1072 memcpy( ctx->session_key, bin, 16 );
1075 arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
1076 ctx->crypt.ntlm.seq_no = 0;
1078 *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
1079 status = SEC_E_OK;
1082 done:
1083 if (status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
1085 ntlm_cleanup( ctx );
1086 free( ctx );
1088 free( buf );
1089 free( bin );
1090 free( want_flags );
1092 TRACE( "returning %#lx\n", status );
1093 return status;
1096 static NTSTATUS NTAPI ntlm_SpDeleteContext( LSA_SEC_HANDLE handle )
1098 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1100 TRACE( "%#Ix\n", handle );
1102 if (!ctx) return SEC_E_INVALID_HANDLE;
1103 ntlm_cleanup( ctx );
1104 free( ctx );
1105 return SEC_E_OK;
1108 static SecPkgInfoW *build_package_info( const SecPkgInfoW *info )
1110 SecPkgInfoW *ret;
1111 DWORD size_name = (wcslen(info->Name) + 1) * sizeof(WCHAR);
1112 DWORD size_comment = (wcslen(info->Comment) + 1) * sizeof(WCHAR);
1114 if (!(ret = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*ret) + size_name + size_comment ))) return NULL;
1115 ret->fCapabilities = info->fCapabilities;
1116 ret->wVersion = info->wVersion;
1117 ret->wRPCID = info->wRPCID;
1118 ret->cbMaxToken = info->cbMaxToken;
1119 ret->Name = (SEC_WCHAR *)(ret + 1);
1120 memcpy( ret->Name, info->Name, size_name );
1121 ret->Comment = (SEC_WCHAR *)((char *)ret->Name + size_name);
1122 memcpy( ret->Comment, info->Comment, size_comment );
1123 return ret;
1126 static NTSTATUS NTAPI ntlm_SpQueryContextAttributes( LSA_SEC_HANDLE handle, ULONG attr, void *buf )
1128 TRACE( "%#Ix, %lu, %p\n", handle, attr, buf );
1130 if (!handle) return SEC_E_INVALID_HANDLE;
1132 switch (attr)
1134 #define X(x) case (x) : FIXME(#x" stub\n"); break
1135 X(SECPKG_ATTR_ACCESS_TOKEN);
1136 X(SECPKG_ATTR_AUTHORITY);
1137 X(SECPKG_ATTR_DCE_INFO);
1138 X(SECPKG_ATTR_LIFESPAN);
1139 X(SECPKG_ATTR_NAMES);
1140 X(SECPKG_ATTR_NATIVE_NAMES);
1141 X(SECPKG_ATTR_PACKAGE_INFO);
1142 X(SECPKG_ATTR_PASSWORD_EXPIRY);
1143 X(SECPKG_ATTR_SESSION_KEY);
1144 X(SECPKG_ATTR_STREAM_SIZES);
1145 X(SECPKG_ATTR_TARGET_INFORMATION);
1146 case SECPKG_ATTR_FLAGS:
1148 SecPkgContext_Flags *flags = (SecPkgContext_Flags *)buf;
1149 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1151 flags->Flags = 0;
1152 if (ctx->flags & FLAG_NEGOTIATE_SIGN) flags->Flags |= ISC_RET_INTEGRITY;
1153 if (ctx->flags & FLAG_NEGOTIATE_SEAL) flags->Flags |= ISC_RET_CONFIDENTIALITY;
1154 return SEC_E_OK;
1156 case SECPKG_ATTR_SIZES:
1158 SecPkgContext_Sizes *sizes = (SecPkgContext_Sizes *)buf;
1159 sizes->cbMaxToken = NTLM_MAX_BUF;
1160 sizes->cbMaxSignature = 16;
1161 sizes->cbBlockSize = 0;
1162 sizes->cbSecurityTrailer = 16;
1163 return SEC_E_OK;
1165 case SECPKG_ATTR_NEGOTIATION_INFO:
1167 SecPkgContext_NegotiationInfoW *info = (SecPkgContext_NegotiationInfoW *)buf;
1168 if (!(info->PackageInfo = build_package_info( &ntlm_package_info ))) return SEC_E_INSUFFICIENT_MEMORY;
1169 info->NegotiationState = SECPKG_NEGOTIATION_COMPLETE;
1170 return SEC_E_OK;
1172 case SECPKG_ATTR_KEY_INFO:
1174 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1175 SecPkgContext_KeyInfoW *info = (SecPkgContext_KeyInfoW *)buf;
1176 SEC_WCHAR *signature_alg;
1177 ULONG signature_size, signature_algid;
1179 if (ctx->flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1181 signature_alg = (SEC_WCHAR *)L"HMAC-MD5";
1182 signature_size = sizeof(L"HMAC-MD5");
1183 signature_algid = 0xffffff76;
1185 else
1187 signature_alg = (SEC_WCHAR *)L"RSADSI RC4-CRC32";
1188 signature_size = sizeof(L"RSADSI RC4-CRC32");
1189 signature_algid = 0xffffff7c;
1192 if (!(info->sSignatureAlgorithmName = RtlAllocateHeap( GetProcessHeap(), 0, signature_size )))
1193 return SEC_E_INSUFFICIENT_MEMORY;
1194 wcscpy( info->sSignatureAlgorithmName, signature_alg );
1196 if (!(info->sEncryptAlgorithmName = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(L"RSADSI RC4") )))
1198 RtlFreeHeap( GetProcessHeap(), 0, info->sSignatureAlgorithmName );
1199 return SEC_E_INSUFFICIENT_MEMORY;
1201 wcscpy( info->sEncryptAlgorithmName, L"RSADSI RC4" );
1203 info->KeySize = sizeof(ctx->session_key) * 8;
1204 info->SignatureAlgorithm = signature_algid;
1205 info->EncryptAlgorithm = CALG_RC4;
1206 return SEC_E_OK;
1208 #undef X
1209 default:
1210 FIXME( "unknown attribute %lu\n", attr );
1211 break;
1214 return SEC_E_UNSUPPORTED_FUNCTION;
1217 static SECPKG_FUNCTION_TABLE ntlm_table =
1219 ntlm_LsaApInitializePackage,
1220 NULL, /* LsaLogonUser */
1221 NULL, /* CallPackage */
1222 NULL, /* LogonTerminated */
1223 NULL, /* CallPackageUntrusted */
1224 NULL, /* CallPackagePassthrough */
1225 NULL, /* LogonUserEx */
1226 NULL, /* LogonUserEx2 */
1227 ntlm_SpInitialize,
1228 NULL, /* SpShutdown */
1229 ntlm_SpGetInfo,
1230 NULL, /* AcceptCredentials */
1231 ntlm_SpAcquireCredentialsHandle,
1232 NULL, /* SpQueryCredentialsAttributes */
1233 ntlm_SpFreeCredentialsHandle,
1234 NULL, /* SaveCredentials */
1235 NULL, /* GetCredentials */
1236 NULL, /* DeleteCredentials */
1237 ntlm_SpInitLsaModeContext,
1238 ntlm_SpAcceptLsaModeContext,
1239 ntlm_SpDeleteContext,
1240 NULL, /* ApplyControlToken */
1241 NULL, /* GetUserInfo */
1242 NULL, /* GetExtendedInformation */
1243 ntlm_SpQueryContextAttributes,
1244 NULL, /* SpAddCredentials */
1245 NULL, /* SetExtendedInformation */
1246 NULL, /* SetContextAttributes */
1247 NULL, /* SetCredentialsAttributes */
1248 NULL, /* ChangeAccountPassword */
1249 NULL, /* QueryMetaData */
1250 NULL, /* ExchangeMetaData */
1251 NULL, /* GetCredUIContext */
1252 NULL, /* UpdateCredentials */
1253 NULL, /* ValidateTargetInfo */
1254 NULL, /* PostLogonUser */
1257 NTSTATUS NTAPI SpLsaModeInitialize( ULONG lsa_version, ULONG *package_version, SECPKG_FUNCTION_TABLE **table,
1258 ULONG *table_count )
1260 TRACE( "%#lx, %p, %p, %p\n", lsa_version, package_version, table, table_count );
1262 *package_version = SECPKG_INTERFACE_VERSION;
1263 *table = &ntlm_table;
1264 *table_count = 1;
1265 return STATUS_SUCCESS;
1268 static NTSTATUS NTAPI ntlm_SpInstanceInit( ULONG version, SECPKG_DLL_FUNCTIONS *dll_functions, void **user_functions )
1270 TRACE( "%#lx, %p, %p\n", version, dll_functions, user_functions );
1271 return STATUS_SUCCESS;
1274 struct hmac_md5_ctx
1276 struct md5_ctx ctx;
1277 char outer_padding[64];
1280 static void hmac_md5_init( struct hmac_md5_ctx *ctx, const char *key, unsigned int key_len )
1282 char inner_padding[64], tmp_key[16];
1283 unsigned int i;
1285 if (key_len > 64)
1287 struct md5_ctx tmp_ctx;
1289 MD5Init( &tmp_ctx );
1290 MD5Update( &tmp_ctx, key, key_len );
1291 MD5Final( &tmp_ctx );
1292 memcpy( tmp_key, tmp_ctx.digest, 16 );
1294 key = tmp_key;
1295 key_len = 16;
1298 memset( inner_padding, 0, 64 );
1299 memset( ctx->outer_padding, 0, 64 );
1300 memcpy( inner_padding, key, key_len );
1301 memcpy( ctx->outer_padding, key, key_len );
1303 for (i = 0; i < 64; i++)
1305 inner_padding[i] ^= 0x36;
1306 ctx->outer_padding[i] ^= 0x5c;
1309 MD5Init( &ctx->ctx );
1310 MD5Update( &ctx->ctx, inner_padding, 64 );
1313 static void hmac_md5_update( struct hmac_md5_ctx *ctx, const char *buf, unsigned int len )
1315 MD5Update( &ctx->ctx, buf, len );
1318 static void hmac_md5_final( struct hmac_md5_ctx *ctx, char *digest )
1320 struct md5_ctx outer_ctx;
1321 char inner_digest[16];
1323 MD5Final( &ctx->ctx );
1324 memcpy( inner_digest, ctx->ctx.digest, 16 );
1326 MD5Init( &outer_ctx );
1327 MD5Update( &outer_ctx, ctx->outer_padding, 64 );
1328 MD5Update( &outer_ctx, inner_digest, 16 );
1329 MD5Final( &outer_ctx );
1331 memcpy( digest, outer_ctx.digest, 16 );
1334 static SECURITY_STATUS create_signature( struct ntlm_ctx *ctx, unsigned int flags, SecBufferDesc *msg, int idx,
1335 enum sign_direction dir, BOOL encrypt )
1337 unsigned int i, sign_version = 1;
1338 char *sig = msg->pBuffers[idx].pvBuffer;
1340 if (flags & FLAG_NEGOTIATE_NTLM2 && flags & FLAG_NEGOTIATE_SIGN)
1342 char digest[16], seq_no[4];
1343 struct hmac_md5_ctx hmac_md5;
1345 if (dir == SIGN_SEND)
1347 seq_no[0] = (ctx->crypt.ntlm2.send_seq_no >> 0) & 0xff;
1348 seq_no[1] = (ctx->crypt.ntlm2.send_seq_no >> 8) & 0xff;
1349 seq_no[2] = (ctx->crypt.ntlm2.send_seq_no >> 16) & 0xff;
1350 seq_no[3] = (ctx->crypt.ntlm2.send_seq_no >> 24) & 0xff;
1351 ctx->crypt.ntlm2.send_seq_no++;
1353 hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.send_sign_key, 16 );
1355 else
1357 seq_no[0] = (ctx->crypt.ntlm2.recv_seq_no >> 0) & 0xff;
1358 seq_no[1] = (ctx->crypt.ntlm2.recv_seq_no >> 8) & 0xff;
1359 seq_no[2] = (ctx->crypt.ntlm2.recv_seq_no >> 16) & 0xff;
1360 seq_no[3] = (ctx->crypt.ntlm2.recv_seq_no >> 24) & 0xff;
1361 ctx->crypt.ntlm2.recv_seq_no++;
1363 hmac_md5_init( &hmac_md5, ctx->crypt.ntlm2.recv_sign_key, 16 );
1366 hmac_md5_update( &hmac_md5, seq_no, 4 );
1367 for (i = 0; i < msg->cBuffers; ++i)
1369 if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
1370 hmac_md5_update( &hmac_md5, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
1372 hmac_md5_final( &hmac_md5, digest );
1374 if (encrypt && flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1376 if (dir == SIGN_SEND)
1377 arc4_process( &ctx->crypt.ntlm2.send_arc4info, digest, 8 );
1378 else
1379 arc4_process( &ctx->crypt.ntlm2.recv_arc4info, digest, 8 );
1382 sig[0] = (sign_version >> 0) & 0xff;
1383 sig[1] = (sign_version >> 8) & 0xff;
1384 sig[2] = (sign_version >> 16) & 0xff;
1385 sig[3] = (sign_version >> 24) & 0xff;
1386 memcpy( sig + 4, digest, 8 );
1387 memcpy( sig + 12, seq_no, 4 );
1389 msg->pBuffers[idx].cbBuffer = 16;
1390 return SEC_E_OK;
1393 if (flags & FLAG_NEGOTIATE_SIGN)
1395 unsigned int crc = 0;
1397 for (i = 0; i < msg->cBuffers; ++i)
1399 if (msg->pBuffers[i].BufferType & SECBUFFER_DATA)
1400 crc = RtlComputeCrc32( crc, msg->pBuffers[i].pvBuffer, msg->pBuffers[i].cbBuffer );
1403 sig[0] = (sign_version >> 0) & 0xff;
1404 sig[1] = (sign_version >> 8) & 0xff;
1405 sig[2] = (sign_version >> 16) & 0xff;
1406 sig[3] = (sign_version >> 24) & 0xff;
1407 memset( sig + 4, 0, 4 );
1408 sig[8] = (crc >> 0) & 0xff;
1409 sig[9] = (crc >> 8) & 0xff;
1410 sig[10] = (crc >> 16) & 0xff;
1411 sig[11] = (crc >> 24) & 0xff;
1412 sig[12] = (ctx->crypt.ntlm.seq_no >> 0) & 0xff;
1413 sig[13] = (ctx->crypt.ntlm.seq_no >> 8) & 0xff;
1414 sig[14] = (ctx->crypt.ntlm.seq_no >> 16) & 0xff;
1415 sig[15] = (ctx->crypt.ntlm.seq_no >> 24) & 0xff;
1416 ctx->crypt.ntlm.seq_no++;
1418 if (encrypt) arc4_process( &ctx->crypt.ntlm.arc4info, sig + 4, 12 );
1419 return SEC_E_OK;
1422 if (flags & FLAG_NEGOTIATE_ALWAYS_SIGN || !flags)
1424 /* create dummy signature */
1425 memset( msg->pBuffers[idx].pvBuffer, 0, 16 );
1426 memset( msg->pBuffers[idx].pvBuffer, 1, 1 );
1427 msg->pBuffers[idx].cbBuffer = 16;
1428 return SEC_E_OK;
1431 return SEC_E_UNSUPPORTED_FUNCTION;
1434 static NTSTATUS NTAPI ntlm_SpMakeSignature( LSA_SEC_HANDLE handle, ULONG qop, SecBufferDesc *msg, ULONG msg_seq_no )
1436 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1437 int idx;
1439 TRACE( "%#Ix, %#lx, %p, %lu\n", handle, qop, msg, msg_seq_no );
1440 if (qop) FIXME( "ignoring quality of protection %#lx\n", qop );
1441 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1443 if (!handle) return SEC_E_INVALID_HANDLE;
1444 if (!msg || !msg->pBuffers || msg->cBuffers < 2 || (idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1)
1445 return SEC_E_INVALID_TOKEN;
1446 if (msg->pBuffers[idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1448 return create_signature( ctx, ctx->flags, msg, idx, SIGN_SEND, TRUE );
1451 static NTSTATUS verify_signature( struct ntlm_ctx *ctx, unsigned int flags, SecBufferDesc *msg, int idx )
1453 NTSTATUS status;
1454 unsigned int i;
1455 SecBufferDesc desc;
1456 SecBuffer *buf;
1457 char sig[16];
1459 if (!(buf = malloc( msg->cBuffers * sizeof(*buf) ))) return SEC_E_INSUFFICIENT_MEMORY;
1460 desc.ulVersion = SECBUFFER_VERSION;
1461 desc.cBuffers = msg->cBuffers;
1462 desc.pBuffers = buf;
1464 for (i = 0; i < msg->cBuffers; i++)
1466 if (msg->pBuffers[i].BufferType == SECBUFFER_TOKEN)
1468 buf[i].BufferType = SECBUFFER_TOKEN;
1469 buf[i].cbBuffer = 16;
1470 buf[i].pvBuffer = sig;
1472 else
1474 buf[i].BufferType = msg->pBuffers[i].BufferType;
1475 buf[i].cbBuffer = msg->pBuffers[i].cbBuffer;
1476 buf[i].pvBuffer = msg->pBuffers[i].pvBuffer;
1480 if ((status = create_signature( ctx, flags, &desc, idx, SIGN_RECV, TRUE )) == SEC_E_OK)
1482 if (memcmp( (char *)buf[idx].pvBuffer + 8, (char *)msg->pBuffers[idx].pvBuffer + 8, 8 ))
1483 status = SEC_E_MESSAGE_ALTERED;
1486 free( buf );
1487 return status;
1490 static NTSTATUS NTAPI ntlm_SpVerifySignature( LSA_SEC_HANDLE handle, SecBufferDesc *msg, ULONG msg_seq_no, ULONG *qop )
1492 struct ntlm_ctx *ctx = (struct ntlm_ctx *)handle;
1493 int idx;
1495 TRACE( "%#Ix, %p, %lu, %p\n", handle, msg, msg_seq_no, qop );
1496 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1498 if (!handle) return SEC_E_INVALID_HANDLE;
1499 if (!msg || !msg->pBuffers || msg->cBuffers < 2 || (idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1)
1500 return SEC_E_INVALID_TOKEN;
1501 if (msg->pBuffers[idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1503 return verify_signature( ctx, ctx->flags, msg, idx );
1506 static NTSTATUS NTAPI ntlm_SpSealMessage( LSA_SEC_HANDLE handle, ULONG qop, SecBufferDesc *msg, ULONG msg_seq_no )
1508 int token_idx, data_idx;
1509 struct ntlm_ctx *ctx;
1511 TRACE( "%#Ix, %#lx, %p %lu\n", handle, qop, msg, msg_seq_no );
1512 if (qop) FIXME( "ignoring quality of protection %#lx\n", qop );
1513 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1515 if (!handle) return SEC_E_INVALID_HANDLE;
1517 if (!msg || !msg->pBuffers || msg->cBuffers < 2 ||
1518 (token_idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1 ||
1519 (data_idx = get_buffer_index( msg, SECBUFFER_DATA )) == -1) return SEC_E_INVALID_TOKEN;
1521 if (msg->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1523 ctx = (struct ntlm_ctx *)handle;
1524 if (ctx->flags & FLAG_NEGOTIATE_NTLM2 && ctx->flags & FLAG_NEGOTIATE_SEAL)
1526 create_signature( ctx, ctx->flags, msg, token_idx, SIGN_SEND, FALSE );
1528 arc4_process( &ctx->crypt.ntlm2.send_arc4info, msg->pBuffers[data_idx].pvBuffer,
1529 msg->pBuffers[data_idx].cbBuffer );
1530 if (ctx->flags & FLAG_NEGOTIATE_KEY_EXCHANGE)
1531 arc4_process( &ctx->crypt.ntlm2.send_arc4info, (char *)msg->pBuffers[token_idx].pvBuffer + 4, 8 );
1533 else
1535 char *sig = msg->pBuffers[token_idx].pvBuffer;
1537 create_signature( ctx, ctx->flags | FLAG_NEGOTIATE_SIGN, msg, token_idx, SIGN_SEND, FALSE );
1539 arc4_process( &ctx->crypt.ntlm.arc4info, msg->pBuffers[data_idx].pvBuffer, msg->pBuffers[data_idx].cbBuffer );
1540 arc4_process( &ctx->crypt.ntlm.arc4info, sig + 4, 12 );
1542 if (ctx->flags & FLAG_NEGOTIATE_ALWAYS_SIGN || !ctx->flags) memset( sig + 4, 0, 4 );
1545 return SEC_E_OK;
1548 static NTSTATUS NTAPI ntlm_SpUnsealMessage( LSA_SEC_HANDLE handle, SecBufferDesc *msg, ULONG msg_seq_no, ULONG *qop )
1550 int token_idx, data_idx;
1551 struct ntlm_ctx *ctx;
1553 TRACE( "%#Ix, %p, %lu, %p\n", handle, msg, msg_seq_no, qop );
1554 if (msg_seq_no) FIXME( "ignoring message sequence number %lu\n", msg_seq_no );
1556 if (!handle) return SEC_E_INVALID_HANDLE;
1558 if (!msg || !msg->pBuffers || msg->cBuffers < 2 ||
1559 (token_idx = get_buffer_index( msg, SECBUFFER_TOKEN )) == -1 ||
1560 (data_idx = get_buffer_index( msg, SECBUFFER_DATA )) == -1) return SEC_E_INVALID_TOKEN;
1562 if (msg->pBuffers[token_idx].cbBuffer < 16) return SEC_E_BUFFER_TOO_SMALL;
1564 ctx = (struct ntlm_ctx *)handle;
1565 if (ctx->flags & FLAG_NEGOTIATE_NTLM2 && ctx->flags & FLAG_NEGOTIATE_SEAL)
1566 arc4_process( &ctx->crypt.ntlm2.recv_arc4info, msg->pBuffers[data_idx].pvBuffer,
1567 msg->pBuffers[data_idx].cbBuffer );
1568 else
1569 arc4_process( &ctx->crypt.ntlm.arc4info, msg->pBuffers[data_idx].pvBuffer,
1570 msg->pBuffers[data_idx].cbBuffer);
1572 /* make sure we use a session key for the signature check, SealMessage always does that,
1573 even in the dummy case */
1574 return verify_signature( ctx, ctx->flags | FLAG_NEGOTIATE_SIGN, msg, token_idx );
1577 static SECPKG_USER_FUNCTION_TABLE ntlm_user_table =
1579 ntlm_SpInstanceInit,
1580 NULL, /* SpInitUserModeContext */
1581 ntlm_SpMakeSignature,
1582 ntlm_SpVerifySignature,
1583 ntlm_SpSealMessage,
1584 ntlm_SpUnsealMessage,
1585 NULL, /* SpGetContextToken */
1586 NULL, /* SpQueryContextAttributes */
1587 NULL, /* SpCompleteAuthToken */
1588 NULL, /* SpDeleteContext */
1589 NULL, /* SpFormatCredentialsFn */
1590 NULL, /* SpMarshallSupplementalCreds */
1591 NULL, /* SpExportSecurityContext */
1592 NULL /* SpImportSecurityContext */
1595 NTSTATUS NTAPI SpUserModeInitialize( ULONG lsa_version, ULONG *package_version, SECPKG_USER_FUNCTION_TABLE **table,
1596 ULONG *table_count )
1598 TRACE( "%#lx, %p, %p, %p\n", lsa_version, package_version, table, table_count );
1600 *package_version = SECPKG_INTERFACE_VERSION;
1601 *table = &ntlm_user_table;
1602 *table_count = 1;
1603 return STATUS_SUCCESS;
1606 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, void *reserved )
1608 switch (reason)
1610 case DLL_PROCESS_ATTACH:
1611 if (NtQueryVirtualMemory( GetCurrentProcess(), hinst, MemoryWineUnixFuncs,
1612 &ntlm_handle, sizeof(ntlm_handle), NULL ))
1613 return FALSE;
1614 DisableThreadLibraryCalls( hinst );
1615 break;
1617 return TRUE;