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
24 #define WIN32_NO_STATUS
37 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ntlm
);
42 static ULONG ntlm_package_id
;
43 static LSA_DISPATCH_TABLE lsa_dispatch
;
45 static unixlib_handle_t ntlm_handle
;
47 static NTSTATUS
ntlm_check_version(void)
49 return __wine_unix_call( ntlm_handle
, unix_check_version
, NULL
);
52 static void ntlm_cleanup( struct ntlm_ctx
*ctx
)
54 __wine_unix_call( ntlm_handle
, unix_cleanup
, ctx
);
57 static NTSTATUS
ntlm_chat( struct ntlm_ctx
*ctx
, char *buf
, unsigned int buflen
, unsigned int *retlen
)
59 struct chat_params params
= { ctx
, buf
, buflen
, retlen
};
61 return __wine_unix_call( ntlm_handle
, unix_chat
, ¶ms
);
64 static NTSTATUS
ntlm_fork( struct ntlm_ctx
*ctx
, char **argv
)
66 struct fork_params params
= { ctx
, argv
};
68 return __wine_unix_call( ntlm_handle
, unix_fork
, ¶ms
);
72 ( SECPKG_FLAG_INTEGRITY \
73 | SECPKG_FLAG_PRIVACY \
74 | SECPKG_FLAG_TOKEN_ONLY \
75 | SECPKG_FLAG_CONNECTION \
76 | SECPKG_FLAG_MULTI_REQUIRED \
77 | SECPKG_FLAG_IMPERSONATION \
78 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
79 | SECPKG_FLAG_NEGOTIABLE \
81 | SECPKG_FLAG_RESTRICTED_TOKENS )
83 #define NTLM_MAX_BUF 1904
85 static const SecPkgInfoW ntlm_package_info
=
92 (SEC_WCHAR
*)L
"NTLM Security Package"
95 static inline const char *debugstr_as( const STRING
*str
)
97 if (!str
) return "<null>";
98 return debugstr_an( str
->Buffer
, str
->Length
);
101 static inline const char *debugstr_us( const UNICODE_STRING
*str
)
103 if (!str
) return "<null>";
104 return debugstr_wn( str
->Buffer
, str
->Length
/ sizeof(WCHAR
) );
107 static NTSTATUS NTAPI
ntlm_LsaApInitializePackage( ULONG package_id
, LSA_DISPATCH_TABLE
*dispatch
,
108 LSA_STRING
*database
, LSA_STRING
*confidentiality
,
109 LSA_STRING
**package_name
)
114 TRACE( "%#lx, %p, %s, %s, %p\n", package_id
, dispatch
, debugstr_as(database
), debugstr_as(confidentiality
),
117 if (ntlm_check_version())
119 ERR( "no NTLM support, expect problems\n" );
120 return STATUS_UNSUCCESSFUL
;
123 if (!(str
= dispatch
->AllocateLsaHeap( sizeof(*str
) + sizeof("NTLM" )))) return STATUS_NO_MEMORY
;
124 ptr
= (char *)(str
+ 1);
125 memcpy( ptr
, "NTLM", sizeof("NTLM") );
126 RtlInitString( str
, ptr
);
128 ntlm_package_id
= package_id
;
129 lsa_dispatch
= *dispatch
;
132 return STATUS_SUCCESS
;
135 static NTSTATUS NTAPI
ntlm_SpInitialize( ULONG_PTR package_id
, SECPKG_PARAMETERS
*params
,
136 LSA_SECPKG_FUNCTION_TABLE
*lsa_function_table
)
138 TRACE( "%#Ix, %p, %p\n", package_id
, params
, lsa_function_table
);
140 if (ntlm_check_version())
142 ERR( "no NTLM support, expect problems\n" );
143 return STATUS_UNSUCCESSFUL
;
145 return STATUS_SUCCESS
;
148 static NTSTATUS NTAPI
ntlm_SpGetInfo( SecPkgInfoW
*info
)
150 TRACE( "%p\n", info
);
151 *info
= ntlm_package_info
;
152 return STATUS_SUCCESS
;
155 static char *get_username_arg( const WCHAR
*user
, int user_len
)
157 static const char arg
[] = "--username=";
158 int len
= sizeof(arg
);
161 len
+= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, user
, user_len
, NULL
, 0, NULL
, NULL
);
162 if (!(ret
= malloc( len
))) return NULL
;
163 memcpy( ret
, arg
, sizeof(arg
) - 1 );
164 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, user
, user_len
, ret
+ sizeof(arg
) - 1,
165 len
- sizeof(arg
) + 1, NULL
, NULL
);
170 static char *get_domain_arg( const WCHAR
*domain
, int domain_len
)
172 static const char arg
[] = "--domain=";
173 int len
= sizeof(arg
);
176 len
+= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, domain
, domain_len
, NULL
, 0, NULL
, NULL
);
177 if (!(ret
= malloc( len
))) return NULL
;
178 memcpy( ret
, arg
, sizeof(arg
) - 1 );
179 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, domain
, domain_len
, ret
+ sizeof(arg
) - 1,
180 len
- sizeof(arg
) + 1, NULL
, NULL
);
185 #define WINE_NO_CACHED_CREDENTIALS 0x10000000
186 static NTSTATUS NTAPI
ntlm_SpAcquireCredentialsHandle( UNICODE_STRING
*principal
, ULONG cred_use
, LUID
*logon_id
,
187 void *auth_data
, void *get_key_fn
, void *get_key_arg
,
188 LSA_SEC_HANDLE
*handle
, TimeStamp
*expiry
)
190 SECURITY_STATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
191 struct ntlm_cred
*cred
= NULL
;
192 WCHAR
*domain
= NULL
, *user
= NULL
, *password
= NULL
;
193 SEC_WINNT_AUTH_IDENTITY_W
*id
= NULL
;
195 TRACE( "%s, %#lx, %p, %p, %p, %p, %p, %p\n", debugstr_us(principal
), cred_use
, logon_id
, auth_data
,
196 get_key_fn
, get_key_arg
, cred
, expiry
);
198 switch (cred_use
& ~SECPKG_CRED_RESERVED
)
200 case SECPKG_CRED_INBOUND
:
201 if (!(cred
= malloc( sizeof(*cred
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
202 cred
->mode
= MODE_SERVER
;
203 cred
->username_arg
= NULL
;
204 cred
->domain_arg
= NULL
;
205 cred
->password
= NULL
;
206 cred
->password_len
= 0;
207 cred
->no_cached_credentials
= 0;
209 *handle
= (LSA_SEC_HANDLE
)cred
;
213 case SECPKG_CRED_OUTBOUND
:
214 if (!(cred
= malloc( sizeof(*cred
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
216 cred
->mode
= MODE_CLIENT
;
217 cred
->username_arg
= NULL
;
218 cred
->domain_arg
= NULL
;
219 cred
->password
= NULL
;
220 cred
->password_len
= 0;
221 cred
->no_cached_credentials
= (cred_use
& WINE_NO_CACHED_CREDENTIALS
);
223 if ((id
= auth_data
))
225 int domain_len
= 0, user_len
= 0, password_len
= 0;
226 if (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
)
228 if (id
->DomainLength
)
230 domain_len
= MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Domain
, id
->DomainLength
, NULL
, 0 );
231 if (!(domain
= malloc( sizeof(WCHAR
) * domain_len
))) goto done
;
232 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Domain
, id
->DomainLength
, domain
, domain_len
);
236 user_len
= MultiByteToWideChar( CP_ACP
, 0, (char *)id
->User
, id
->UserLength
, NULL
, 0 );
237 if (!(user
= malloc( sizeof(WCHAR
) * user_len
))) goto done
;
238 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->User
, id
->UserLength
, user
, user_len
);
240 if (id
->PasswordLength
)
242 password_len
= MultiByteToWideChar( CP_ACP
, 0,(char *)id
->Password
, id
->PasswordLength
, NULL
, 0 );
243 if (!(password
= malloc( sizeof(WCHAR
) * password_len
))) goto done
;
244 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Password
, id
->PasswordLength
, password
, password_len
);
250 domain_len
= id
->DomainLength
;
252 user_len
= id
->UserLength
;
253 password
= id
->Password
;
254 password_len
= id
->PasswordLength
;
257 TRACE( "username is %s\n", debugstr_wn(user
, user_len
) );
258 TRACE( "domain name is %s\n", debugstr_wn(domain
, domain_len
) );
260 cred
->username_arg
= get_username_arg( user
, user_len
);
261 cred
->domain_arg
= get_domain_arg( domain
, domain_len
);
264 cred
->password_len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, password
, password_len
,
265 NULL
, 0, NULL
, NULL
);
266 if (!(cred
->password
= malloc( cred
->password_len
))) goto done
;
267 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, password
, password_len
, cred
->password
,
268 cred
->password_len
, NULL
, NULL
);
272 *handle
= (LSA_SEC_HANDLE
)cred
;
276 case SECPKG_CRED_BOTH
:
277 FIXME( "SECPKG_CRED_BOTH not supported\n" );
278 status
= SEC_E_UNSUPPORTED_FUNCTION
;
282 status
= SEC_E_UNKNOWN_CREDENTIALS
;
287 if (id
&& (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
))
293 if (status
!= SEC_E_OK
) free( cred
);
297 static NTSTATUS NTAPI
ntlm_SpFreeCredentialsHandle( LSA_SEC_HANDLE handle
)
299 struct ntlm_cred
*cred
= (struct ntlm_cred
*)handle
;
301 TRACE( "%#Ix\n", handle
);
303 if (!cred
) return SEC_E_OK
;
305 cred
->mode
= MODE_INVALID
;
306 if (cred
->password
) memset( cred
->password
, 0, cred
->password_len
);
307 free( cred
->password
);
308 free( cred
->username_arg
);
309 free( cred
->domain_arg
);
314 static BOOL
get_cached_credential( const UNICODE_STRING
*target
, CREDENTIALW
**cred
)
316 const WCHAR
*ptr
, *host
;
321 if (!target
) return FALSE
;
323 len
= target
->Length
/ sizeof(WCHAR
);
324 if ((host
= wmemchr( target
->Buffer
, '/', len
)))
327 len
-= host
- target
->Buffer
;
328 if (!(ptr
= wmemchr( host
, ':', len
))) ptr
= wmemchr( host
, '/', len
);
329 if (!ptr
) ptr
= host
+ len
;
333 host
= target
->Buffer
;
337 if (!(hostonly
= malloc( (ptr
- host
+ 1) * sizeof(WCHAR
) ))) return FALSE
;
338 memcpy( hostonly
, host
, (ptr
- host
) * sizeof(WCHAR
) );
339 hostonly
[ptr
- host
] = 0;
341 ret
= CredReadW( hostonly
, CRED_TYPE_DOMAIN_PASSWORD
, 0, cred
);
346 static UINT
encode_base64( const char *bin
, unsigned int len
, char *base64
)
348 static const char base64enc
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
353 /* first 6 bits, all from bin[0] */
354 base64
[n
++] = base64enc
[(bin
[0] & 0xfc) >> 2];
355 x
= (bin
[0] & 3) << 4;
357 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
360 base64
[n
++] = base64enc
[x
];
365 base64
[n
++] = base64enc
[x
| ((bin
[1] & 0xf0) >> 4)];
366 x
= (bin
[1] & 0x0f) << 2;
368 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
371 base64
[n
++] = base64enc
[x
];
375 base64
[n
++] = base64enc
[x
| ((bin
[2] & 0xc0) >> 6)];
377 /* last 6 bits, all from bin[2] */
378 base64
[n
++] = base64enc
[bin
[2] & 0x3f];
386 static inline char decode_char( char c
)
388 if (c
>= 'A' && c
<= 'Z') return c
- 'A';
389 if (c
>= 'a' && c
<= 'z') return c
- 'a' + 26;
390 if (c
>= '0' && c
<= '9') return c
- '0' + 52;
391 if (c
== '+') return 62;
392 if (c
== '/') return 63;
396 static unsigned int decode_base64( const char *base64
, unsigned int len
, char *buf
)
400 const char *p
= base64
;
404 if ((c0
= decode_char( p
[0] )) > 63) return 0;
405 if ((c1
= decode_char( p
[1] )) > 63) return 0;
406 if ((c2
= decode_char( p
[2] )) > 63) return 0;
407 if ((c3
= decode_char( p
[3] )) > 63) return 0;
410 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
411 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
412 buf
[i
+ 2] = (c2
<< 6) | c3
;
420 if ((c0
= decode_char( p
[0] )) > 63) return 0;
421 if ((c1
= decode_char( p
[1] )) > 63) return 0;
422 if (buf
) buf
[i
] = (c0
<< 2) | (c1
>> 4);
425 else if (p
[3] == '=')
427 if ((c0
= decode_char( p
[0] )) > 63) return 0;
428 if ((c1
= decode_char( p
[1] )) > 63) return 0;
429 if ((c2
= decode_char( p
[2] )) > 63) return 0;
432 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
433 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
439 if ((c0
= decode_char( p
[0] )) > 63) return 0;
440 if ((c1
= decode_char( p
[1] )) > 63) return 0;
441 if ((c2
= decode_char( p
[2] )) > 63) return 0;
442 if ((c3
= decode_char( p
[3] )) > 63) return 0;
445 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
446 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
447 buf
[i
+ 2] = (c2
<< 6) | c3
;
458 unsigned char in
[64];
459 unsigned char digest
[16];
462 void WINAPI
MD4Init( struct md4_ctx
* );
463 void WINAPI
MD4Update( struct md4_ctx
*, const char *, unsigned int );
464 void WINAPI
MD4Final( struct md4_ctx
* );
466 static void create_ntlm1_session_key( const char *secret
, unsigned int len
, char *session_key
)
472 MD4Update( &ctx
, secret
, len
);
474 memcpy( hash
, ctx
.digest
, 16 );
477 MD4Update( &ctx
, hash
, 16 );
479 memcpy( session_key
, ctx
.digest
, 16 );
486 unsigned char in
[64];
487 unsigned char digest
[16];
490 void WINAPI
MD5Init( struct md5_ctx
* );
491 void WINAPI
MD5Update( struct md5_ctx
*, const char *, unsigned int );
492 void WINAPI
MD5Final( struct md5_ctx
* );
494 static void calc_ntlm2_subkey( const char *session_key
, const char *magic
, char *subkey
)
499 MD5Update( &ctx
, session_key
, 16 );
500 MD5Update( &ctx
, magic
, strlen(magic
) + 1 );
502 memcpy( subkey
, ctx
.digest
, 16 );
505 static const char client_to_server_sign_constant
[] = "session key to client-to-server signing key magic constant";
506 static const char client_to_server_seal_constant
[] = "session key to client-to-server sealing key magic constant";
507 static const char server_to_client_sign_constant
[] = "session key to server-to-client signing key magic constant";
508 static const char server_to_client_seal_constant
[] = "session key to server-to-client sealing key magic constant";
510 static void create_ntlm2_subkeys( struct ntlm_ctx
*ctx
)
512 if (ctx
->mode
== MODE_CLIENT
)
514 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_sign_constant
, ctx
->crypt
.ntlm2
.send_sign_key
);
515 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_seal_constant
, ctx
->crypt
.ntlm2
.send_seal_key
);
516 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_sign_constant
, ctx
->crypt
.ntlm2
.recv_sign_key
);
517 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_seal_constant
, ctx
->crypt
.ntlm2
.recv_seal_key
);
521 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_sign_constant
, ctx
->crypt
.ntlm2
.send_sign_key
);
522 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_seal_constant
, ctx
->crypt
.ntlm2
.send_seal_key
);
523 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_sign_constant
, ctx
->crypt
.ntlm2
.recv_sign_key
);
524 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_seal_constant
, ctx
->crypt
.ntlm2
.recv_seal_key
);
529 * The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack,
530 * which in turn is based on public domain code by Wei Dai
532 static void arc4_init( struct arc4_info
*info
, const char *key
, unsigned int len
)
534 unsigned int key_idx
= 0, state_idx
= 0, i
, a
;
536 info
->x
= info
->y
= 0;
537 for (i
= 0; i
< 256; i
++) info
->state
[i
] = i
;
539 for (i
= 0; i
< 256; i
++)
542 state_idx
+= key
[key_idx
] + a
;
544 info
->state
[i
] = info
->state
[state_idx
];
545 info
->state
[state_idx
] = a
;
546 if (++key_idx
>= len
) key_idx
= 0;
550 static void arc4_process( struct arc4_info
*info
, char *buf
, unsigned int len
)
552 char *state
= info
->state
;
553 unsigned int x
= info
->x
, y
= info
->y
, a
, b
;
563 *buf
++ ^= state
[(a
+ b
) & 0xff];
570 static int get_buffer_index( SecBufferDesc
*desc
, ULONG type
)
573 for (idx
= 0; idx
< desc
->cBuffers
; idx
++)
575 if (desc
->pBuffers
[idx
].BufferType
== type
) return idx
;
580 static NTSTATUS NTAPI
ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle
, LSA_SEC_HANDLE ctx_handle
,
581 UNICODE_STRING
*target
, ULONG ctx_req
, ULONG data_rep
,
582 SecBufferDesc
*input
, LSA_SEC_HANDLE
*new_ctx_handle
,
583 SecBufferDesc
*output
, ULONG
*ctx_attr
, TimeStamp
*expiry
,
584 BOOLEAN
*mapped_ctx
, SecBuffer
*ctx_data
)
586 NTSTATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
587 struct ntlm_ctx
*ctx
= NULL
;
588 char *buf
, *bin
, *want_flags
= NULL
, *username
= NULL
, *domain
= NULL
, *password
= NULL
;
589 unsigned int len
, bin_len
;
592 TRACE( "%#Ix, %#Ix, %s, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle
, ctx_handle
, debugstr_us(target
),
593 ctx_req
, data_rep
, input
, new_ctx_handle
, output
, ctx_attr
, expiry
, mapped_ctx
, ctx_data
);
595 /* when communicating with the client there can be the following reply packets:
596 * YR <base64 blob> should be sent to the server
597 * PW should be sent back to helper with base64 encoded password
598 * AF <base64 blob> client is done, blob should be sent to server with KK prefixed
599 * GF <string list> a string list of negotiated flags
600 * GK <base64 blob> base64 encoded session key
601 * BH <char reason> something broke
603 * The squid cache size is 2010 chars and that's what ntlm_auth uses */
605 if (!(buf
= malloc( NTLM_MAX_BUF
))) return SEC_E_INSUFFICIENT_MEMORY
;
606 if (!(bin
= malloc( NTLM_MAX_BUF
))) goto done
;
608 if (!ctx_handle
&& !input
)
611 int password_len
= 0;
612 struct ntlm_cred
*cred
= (struct ntlm_cred
*)cred_handle
;
614 if (!cred
|| cred
->mode
!= MODE_CLIENT
)
616 status
= SEC_E_INVALID_HANDLE
;
620 argv
[0] = (char *)"ntlm_auth";
621 argv
[1] = (char *)"--helper-protocol=ntlmssp-client-1";
622 if (!cred
->username_arg
&& !cred
->domain_arg
)
624 WKSTA_USER_INFO_1
*ui
= NULL
;
628 if (get_cached_credential( target
, &cached
))
631 if ((p
= wcschr( cached
->UserName
, '\\' )))
633 if (!(domain
= get_domain_arg( cached
->UserName
, p
- cached
->UserName
))) goto done
;
638 if (!(domain
= get_domain_arg( NULL
, 0 ))) goto done
;
639 p
= cached
->UserName
;
641 if (!(username
= get_username_arg( p
, -1 ))) goto done
;
643 if (cached
->CredentialBlobSize
)
645 password_len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, (WCHAR
*)cached
->CredentialBlob
,
646 cached
->CredentialBlobSize
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
647 if (!(password
= malloc( password_len
))) goto done
;
648 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, (WCHAR
*)cached
->CredentialBlob
,
649 cached
->CredentialBlobSize
/ sizeof(WCHAR
), password
, password_len
, NULL
, NULL
);
659 ret
= NetWkstaUserGetInfo( NULL
, 1, (BYTE
**)&ui
);
660 if (ret
!= NERR_Success
|| !ui
|| cred
->no_cached_credentials
)
662 status
= SEC_E_NO_CREDENTIALS
;
665 if (!(username
= get_username_arg( ui
->wkui1_username
, -1 ))) goto done
;
666 NetApiBufferFree( ui
);
667 TRACE("using cached credentials\n");
670 argv
[3] = (char *)"--use-cached-creds";
676 argv
[2] = cred
->username_arg
;
677 argv
[3] = cred
->domain_arg
;
681 if (!(ctx
= calloc( 1, sizeof(*ctx
) ))) goto done
;
683 if ((status
= ntlm_fork( ctx
, argv
)) != SEC_E_OK
) goto done
;
684 status
= SEC_E_INSUFFICIENT_MEMORY
;
686 ctx
->mode
= MODE_CLIENT
;
687 memset( ctx
->session_key
, 0, sizeof(ctx
->session_key
) );
689 /* generate the dummy session key = MD4(MD4(password))*/
690 if (password
|| cred
->password
)
693 len
= MultiByteToWideChar( CP_ACP
, 0, password
? password
: cred
->password
,
694 password
? password_len
: cred
->password_len
, NULL
, 0 );
695 if (!(passwordW
= malloc( len
* sizeof(WCHAR
) ))) goto done
;
696 MultiByteToWideChar( CP_ACP
, 0, password
? password
: cred
->password
,
697 password
? password_len
: cred
->password_len
, passwordW
, len
);
699 create_ntlm1_session_key( (const char *)passwordW
, len
* sizeof(WCHAR
), ctx
->session_key
);
703 /* allocate space for a maximum string of
704 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL NTLMSSP_FEATURE_SESSION_KEY"
706 if (!(want_flags
= malloc( 73 ))) goto done
;
707 strcpy( want_flags
, "SF" );
708 if (ctx_req
& ISC_REQ_CONFIDENTIALITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SEAL" );
709 if ((ctx_req
& ISC_REQ_INTEGRITY
) || (ctx_req
& ISC_REQ_REPLAY_DETECT
) ||
710 (ctx_req
& ISC_REQ_SEQUENCE_DETECT
)) strcat( want_flags
, " NTLMSSP_FEATURE_SIGN" );
712 if (ctx_req
& ISC_REQ_CONNECTION
) ctx
->attrs
|= ISC_RET_CONNECTION
;
713 if (ctx_req
& ISC_REQ_EXTENDED_ERROR
) ctx
->attrs
|= ISC_RET_EXTENDED_ERROR
;
714 if (ctx_req
& ISC_REQ_MUTUAL_AUTH
) ctx
->attrs
|= ISC_RET_MUTUAL_AUTH
;
715 if (ctx_req
& ISC_REQ_USE_DCE_STYLE
) ctx
->attrs
|= ISC_RET_USED_DCE_STYLE
;
716 if (ctx_req
& ISC_REQ_DELEGATE
) ctx
->attrs
|= ISC_RET_DELEGATE
;
717 if (ctx_req
& ISC_REQ_STREAM
) FIXME( "ISC_REQ_STREAM\n" );
719 /* use cached credentials if no password was given, fall back to an empty password on failure */
720 if (!password
&& !cred
->password
)
723 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
725 /* if the helper replied with "PW" using cached credentials failed */
726 if (!strncmp( buf
, "PW", 2 ))
728 TRACE( "using cached credentials failed\n" );
729 strcpy( buf
, "PW AA==" );
731 else strcpy( buf
, "OK" ); /* just do a noop on the next run */
735 strcpy( buf
, "PW " );
736 encode_base64( password
? password
: cred
->password
, password
? password_len
: cred
->password_len
, buf
+ 3 );
739 TRACE( "sending to ntlm_auth: %s\n", debugstr_a(buf
) );
740 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
741 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf
) );
743 if (strlen( want_flags
) > 2)
745 TRACE( "want flags are %s\n", debugstr_a(want_flags
) );
746 strcpy( buf
, want_flags
);
747 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
748 if (!strncmp( buf
, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
752 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
753 TRACE( "ntlm_auth returned %s\n", buf
);
754 if (strncmp( buf
, "YR ", 3 ))
756 status
= SEC_E_INTERNAL_ERROR
;
759 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
761 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
762 status
= SEC_I_CONTINUE_NEEDED
;
764 else /* !ctx_handle && !input */
766 if (!input
|| ((idx
= get_buffer_index( input
, SECBUFFER_TOKEN
)) == -1))
768 status
= SEC_E_INVALID_TOKEN
;
772 ctx
= (struct ntlm_ctx
*)ctx_handle
;
773 if (!ctx
|| ctx
->mode
!= MODE_CLIENT
)
775 status
= SEC_E_INVALID_HANDLE
;
779 if (!input
->pBuffers
[idx
].pvBuffer
|| input
->pBuffers
[idx
].cbBuffer
> NTLM_MAX_BUF
)
781 status
= SEC_E_INVALID_TOKEN
;
784 bin_len
= input
->pBuffers
[idx
].cbBuffer
;
785 memcpy( bin
, input
->pBuffers
[idx
].pvBuffer
, bin_len
);
787 strcpy( buf
, "TT " );
788 encode_base64( bin
, bin_len
, buf
+ 3 );
789 TRACE( "server sent: %s\n", debugstr_a(buf
) );
791 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
))) goto done
;
792 TRACE( "ntlm_auth returned: %s\n", debugstr_a(buf
) );
794 if (strncmp( buf
, "KK ", 3 ) && strncmp( buf
, "AF ", 3 ))
796 status
= SEC_E_INVALID_TOKEN
;
799 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
801 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
805 if (!output
|| ((idx
= get_buffer_index( output
, SECBUFFER_TOKEN
)) == -1))
807 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
808 status
= SEC_E_BUFFER_TOO_SMALL
;
812 if (ctx_req
& ISC_REQ_ALLOCATE_MEMORY
)
814 /* freed with secur32.FreeContextBuffer */
815 if (!(output
->pBuffers
[idx
].pvBuffer
= RtlAllocateHeap( GetProcessHeap(), 0, bin_len
)))
817 status
= SEC_E_INSUFFICIENT_MEMORY
;
820 output
->pBuffers
[idx
].cbBuffer
= bin_len
;
822 else if (output
->pBuffers
[idx
].cbBuffer
< bin_len
)
824 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
825 status
= SEC_E_BUFFER_TOO_SMALL
;
829 if (!output
->pBuffers
[idx
].pvBuffer
)
831 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
832 status
= SEC_E_INTERNAL_ERROR
;
836 output
->pBuffers
[idx
].cbBuffer
= bin_len
;
837 memcpy( output
->pBuffers
[idx
].pvBuffer
, bin
, bin_len
);
838 if (status
== SEC_E_OK
)
841 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
842 if (len
< 3) ctx
->flags
= 0;
843 else sscanf( buf
+ 3, "%x", &ctx
->flags
);
846 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
848 if (!strncmp( buf
, "BH", 2 )) TRACE( "no key negotiated\n" );
849 else if (!strncmp( buf
, "GK ", 3 ))
851 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
852 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
853 memcpy( ctx
->session_key
, bin
, bin_len
);
856 arc4_init( &ctx
->crypt
.ntlm
.arc4info
, ctx
->session_key
, 16 );
857 ctx
->crypt
.ntlm
.seq_no
= 0;
858 create_ntlm2_subkeys( ctx
);
859 arc4_init( &ctx
->crypt
.ntlm2
.send_arc4info
, ctx
->crypt
.ntlm2
.send_seal_key
, 16 );
860 arc4_init( &ctx
->crypt
.ntlm2
.recv_arc4info
, ctx
->crypt
.ntlm2
.recv_seal_key
, 16 );
861 ctx
->crypt
.ntlm2
.send_seq_no
= 0;
862 ctx
->crypt
.ntlm2
.recv_seq_no
= 0;
866 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
)
878 TRACE( "returning %#lx\n", status
);
882 static NTSTATUS NTAPI
ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle
, LSA_SEC_HANDLE ctx_handle
,
883 SecBufferDesc
*input
, ULONG ctx_req
, ULONG data_rep
,
884 LSA_SEC_HANDLE
*new_ctx_handle
, SecBufferDesc
*output
,
885 ULONG
*ctx_attr
, TimeStamp
*expiry
, BOOLEAN
*mapped_ctx
,
886 SecBuffer
*ctx_data
)
888 NTSTATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
889 struct ntlm_ctx
*ctx
= NULL
;
890 char *buf
, *bin
, *want_flags
= NULL
;
891 unsigned int len
, bin_len
;
893 TRACE( "%#Ix, %#Ix, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle
, ctx_handle
, ctx_req
, data_rep
, input
,
894 new_ctx_handle
, output
, ctx_attr
, expiry
, mapped_ctx
, ctx_data
);
895 if (ctx_req
) FIXME( "ignoring flags %#lx\n", ctx_req
);
897 if (!(buf
= malloc( NTLM_MAX_BUF
))) return SEC_E_INSUFFICIENT_MEMORY
;
898 if (!(bin
= malloc( NTLM_MAX_BUF
))) goto done
;
902 struct ntlm_cred
*cred
= (struct ntlm_cred
*)cred_handle
;
905 if (!cred
|| cred
->mode
!= MODE_SERVER
)
907 status
= SEC_E_INVALID_HANDLE
;
911 if (!input
|| input
->cBuffers
< 1)
913 status
= SEC_E_INCOMPLETE_MESSAGE
;
917 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
919 status
= SEC_E_INVALID_TOKEN
;
922 else bin_len
= input
->pBuffers
[0].cbBuffer
;
924 if (!(ctx
= calloc( 1, sizeof(*ctx
) ))) goto done
;
926 argv
[0] = (char *)"ntlm_auth";
927 argv
[1] = (char *)"--helper-protocol=squid-2.5-ntlmssp";
929 if ((status
= ntlm_fork( ctx
, argv
)) != SEC_E_OK
) goto done
;
930 ctx
->mode
= MODE_SERVER
;
932 if (!(want_flags
= malloc( 73 )))
934 status
= SEC_E_INSUFFICIENT_MEMORY
;
937 strcpy( want_flags
, "SF" );
938 if (ctx_req
& ASC_REQ_CONFIDENTIALITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SEAL" );
939 if (ctx_req
& ASC_REQ_CONNECTION
)
941 strcat( want_flags
, " NTLMSSP_FEATURE_SESSION_KEY" );
942 ctx
->attrs
|= ASC_RET_CONNECTION
;
944 if (ctx_req
& ASC_REQ_INTEGRITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SIGN" );
945 if (ctx_req
& ASC_REQ_ALLOCATE_MEMORY
) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
946 if (ctx_req
& ASC_REQ_EXTENDED_ERROR
) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
947 if (ctx_req
& ASC_REQ_MUTUAL_AUTH
) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
948 if (ctx_req
& ASC_REQ_REPLAY_DETECT
) FIXME( "ASC_REQ_REPLAY_DETECT\n" );
949 if (ctx_req
& ASC_REQ_SEQUENCE_DETECT
) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
950 if (ctx_req
& ASC_REQ_STREAM
) FIXME( "ASC_REQ_STREAM\n" );
952 if (strlen( want_flags
) > 3)
954 TRACE( "want flags are %s\n", debugstr_a(want_flags
) );
955 strcpy( buf
, want_flags
);
956 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
957 if (!strncmp( buf
, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
960 memcpy( bin
, input
->pBuffers
[0].pvBuffer
, bin_len
);
961 strcpy( buf
, "YR " );
962 encode_base64( bin
, bin_len
, buf
+ 3 );
964 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
965 TRACE( "ntlm_auth returned %s\n", buf
);
966 if (strncmp( buf
, "TT ", 3))
968 status
= SEC_E_INTERNAL_ERROR
;
971 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
973 if (!output
|| output
->cBuffers
< 1)
975 status
= SEC_E_INSUFFICIENT_MEMORY
;
978 output
->pBuffers
[0].cbBuffer
= bin_len
;
979 output
->pBuffers
[0].BufferType
= SECBUFFER_DATA
;
980 memcpy( output
->pBuffers
[0].pvBuffer
, bin
, bin_len
);
982 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
983 status
= SEC_I_CONTINUE_NEEDED
;
987 if (!input
|| input
->cBuffers
< 1)
989 status
= SEC_E_INCOMPLETE_MESSAGE
;
993 ctx
= (struct ntlm_ctx
*)ctx_handle
;
994 if (!ctx
|| ctx
->mode
!= MODE_SERVER
)
996 status
= SEC_E_INVALID_HANDLE
;
1000 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
1002 status
= SEC_E_INVALID_TOKEN
;
1005 else bin_len
= input
->pBuffers
[0].cbBuffer
;
1006 memcpy( bin
, input
->pBuffers
[0].pvBuffer
, bin_len
);
1008 strcpy( buf
, "KK " );
1009 encode_base64( bin
, bin_len
, buf
+ 3 );
1011 TRACE( "client sent %s\n", debugstr_a(buf
) );
1012 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1013 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf
) );
1015 /* At this point, we get a NA if the user didn't authenticate, but a BH if ntlm_auth could not
1016 * connect to winbindd. Apart from running Wine as root, there is no way to fix this for now,
1017 * so just handle this as a failed login. */
1018 if (strncmp( buf
, "AF ", 3 ))
1020 if (!strncmp( buf
, "NA ", 3 ))
1022 status
= SEC_E_LOGON_DENIED
;
1027 const char err_v3
[] = "BH NT_STATUS_ACCESS_DENIED";
1028 const char err_v4
[] = "BH NT_STATUS_UNSUCCESSFUL";
1030 if ((len
>= strlen(err_v3
) && !strncmp( buf
, err_v3
, strlen(err_v3
) )) ||
1031 (len
>= strlen(err_v4
) && !strncmp( buf
, err_v4
, strlen(err_v4
) )))
1033 TRACE( "connection to winbindd failed\n" );
1034 status
= SEC_E_LOGON_DENIED
;
1036 else status
= SEC_E_INTERNAL_ERROR
;
1040 output
->pBuffers
[0].cbBuffer
= 0;
1042 strcpy( buf
, "GF" );
1043 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1044 if (len
< 3) ctx
->flags
= 0;
1045 else sscanf( buf
+ 3, "%x", &ctx
->flags
);
1047 strcpy( buf
, "GK" );
1048 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1050 if (!strncmp( buf
, "BH", 2 )) TRACE( "no key negotiated\n" );
1051 else if (!strncmp( buf
, "GK ", 3 ))
1053 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
1054 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
1055 memcpy( ctx
->session_key
, bin
, bin_len
);
1058 if (len
< 3) memset( ctx
->session_key
, 0 , 16 );
1061 if (!strncmp( buf
, "BH ", 3 ))
1063 TRACE( "helper sent %s\n", debugstr_a(buf
+ 3) );
1064 /*FIXME: generate dummy session key = MD4(MD4(password))*/
1065 memset( ctx
->session_key
, 0 , 16 );
1067 else if (!strncmp( buf
, "GK ", 3 ))
1069 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
1070 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
1071 memcpy( ctx
->session_key
, bin
, 16 );
1074 arc4_init( &ctx
->crypt
.ntlm
.arc4info
, ctx
->session_key
, 16 );
1075 ctx
->crypt
.ntlm
.seq_no
= 0;
1077 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
1082 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
)
1084 ntlm_cleanup( ctx
);
1091 TRACE( "returning %#lx\n", status
);
1095 static NTSTATUS NTAPI
ntlm_SpDeleteContext( LSA_SEC_HANDLE handle
)
1097 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1099 TRACE( "%#Ix\n", handle
);
1101 if (!ctx
) return SEC_E_INVALID_HANDLE
;
1102 ntlm_cleanup( ctx
);
1107 static SecPkgInfoW
*build_package_info( const SecPkgInfoW
*info
)
1110 DWORD size_name
= (wcslen(info
->Name
) + 1) * sizeof(WCHAR
);
1111 DWORD size_comment
= (wcslen(info
->Comment
) + 1) * sizeof(WCHAR
);
1113 if (!(ret
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*ret
) + size_name
+ size_comment
))) return NULL
;
1114 ret
->fCapabilities
= info
->fCapabilities
;
1115 ret
->wVersion
= info
->wVersion
;
1116 ret
->wRPCID
= info
->wRPCID
;
1117 ret
->cbMaxToken
= info
->cbMaxToken
;
1118 ret
->Name
= (SEC_WCHAR
*)(ret
+ 1);
1119 memcpy( ret
->Name
, info
->Name
, size_name
);
1120 ret
->Comment
= (SEC_WCHAR
*)((char *)ret
->Name
+ size_name
);
1121 memcpy( ret
->Comment
, info
->Comment
, size_comment
);
1125 static NTSTATUS NTAPI
ntlm_SpQueryContextAttributes( LSA_SEC_HANDLE handle
, ULONG attr
, void *buf
)
1127 TRACE( "%#Ix, %lu, %p\n", handle
, attr
, buf
);
1129 if (!handle
) return SEC_E_INVALID_HANDLE
;
1133 #define X(x) case (x) : FIXME(#x" stub\n"); break
1134 X(SECPKG_ATTR_ACCESS_TOKEN
);
1135 X(SECPKG_ATTR_AUTHORITY
);
1136 X(SECPKG_ATTR_DCE_INFO
);
1137 X(SECPKG_ATTR_KEY_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
;
1152 if (ctx
->flags
& FLAG_NEGOTIATE_SIGN
) flags
->Flags
|= ISC_RET_INTEGRITY
;
1153 if (ctx
->flags
& FLAG_NEGOTIATE_SEAL
) flags
->Flags
|= ISC_RET_CONFIDENTIALITY
;
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;
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
;
1174 FIXME( "unknown attribute %lu\n", attr
);
1178 return SEC_E_UNSUPPORTED_FUNCTION
;
1181 static SECPKG_FUNCTION_TABLE ntlm_table
=
1183 ntlm_LsaApInitializePackage
,
1184 NULL
, /* LsaLogonUser */
1185 NULL
, /* CallPackage */
1186 NULL
, /* LogonTerminated */
1187 NULL
, /* CallPackageUntrusted */
1188 NULL
, /* CallPackagePassthrough */
1189 NULL
, /* LogonUserEx */
1190 NULL
, /* LogonUserEx2 */
1192 NULL
, /* SpShutdown */
1194 NULL
, /* AcceptCredentials */
1195 ntlm_SpAcquireCredentialsHandle
,
1196 NULL
, /* SpQueryCredentialsAttributes */
1197 ntlm_SpFreeCredentialsHandle
,
1198 NULL
, /* SaveCredentials */
1199 NULL
, /* GetCredentials */
1200 NULL
, /* DeleteCredentials */
1201 ntlm_SpInitLsaModeContext
,
1202 ntlm_SpAcceptLsaModeContext
,
1203 ntlm_SpDeleteContext
,
1204 NULL
, /* ApplyControlToken */
1205 NULL
, /* GetUserInfo */
1206 NULL
, /* GetExtendedInformation */
1207 ntlm_SpQueryContextAttributes
,
1208 NULL
, /* SpAddCredentials */
1209 NULL
, /* SetExtendedInformation */
1210 NULL
, /* SetContextAttributes */
1211 NULL
, /* SetCredentialsAttributes */
1212 NULL
, /* ChangeAccountPassword */
1213 NULL
, /* QueryMetaData */
1214 NULL
, /* ExchangeMetaData */
1215 NULL
, /* GetCredUIContext */
1216 NULL
, /* UpdateCredentials */
1217 NULL
, /* ValidateTargetInfo */
1218 NULL
, /* PostLogonUser */
1221 NTSTATUS NTAPI
SpLsaModeInitialize( ULONG lsa_version
, ULONG
*package_version
, SECPKG_FUNCTION_TABLE
**table
,
1222 ULONG
*table_count
)
1224 TRACE( "%#lx, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
1226 *package_version
= SECPKG_INTERFACE_VERSION
;
1227 *table
= &ntlm_table
;
1229 return STATUS_SUCCESS
;
1232 static NTSTATUS NTAPI
ntlm_SpInstanceInit( ULONG version
, SECPKG_DLL_FUNCTIONS
*dll_functions
, void **user_functions
)
1234 TRACE( "%#lx, %p, %p\n", version
, dll_functions
, user_functions
);
1235 return STATUS_SUCCESS
;
1241 char outer_padding
[64];
1244 static void hmac_md5_init( struct hmac_md5_ctx
*ctx
, const char *key
, unsigned int key_len
)
1246 char inner_padding
[64], tmp_key
[16];
1251 struct md5_ctx tmp_ctx
;
1253 MD5Init( &tmp_ctx
);
1254 MD5Update( &tmp_ctx
, key
, key_len
);
1255 MD5Final( &tmp_ctx
);
1256 memcpy( tmp_key
, tmp_ctx
.digest
, 16 );
1262 memset( inner_padding
, 0, 64 );
1263 memset( ctx
->outer_padding
, 0, 64 );
1264 memcpy( inner_padding
, key
, key_len
);
1265 memcpy( ctx
->outer_padding
, key
, key_len
);
1267 for (i
= 0; i
< 64; i
++)
1269 inner_padding
[i
] ^= 0x36;
1270 ctx
->outer_padding
[i
] ^= 0x5c;
1273 MD5Init( &ctx
->ctx
);
1274 MD5Update( &ctx
->ctx
, inner_padding
, 64 );
1277 static void hmac_md5_update( struct hmac_md5_ctx
*ctx
, const char *buf
, unsigned int len
)
1279 MD5Update( &ctx
->ctx
, buf
, len
);
1282 static void hmac_md5_final( struct hmac_md5_ctx
*ctx
, char *digest
)
1284 struct md5_ctx outer_ctx
;
1285 char inner_digest
[16];
1287 MD5Final( &ctx
->ctx
);
1288 memcpy( inner_digest
, ctx
->ctx
.digest
, 16 );
1290 MD5Init( &outer_ctx
);
1291 MD5Update( &outer_ctx
, ctx
->outer_padding
, 64 );
1292 MD5Update( &outer_ctx
, inner_digest
, 16 );
1293 MD5Final( &outer_ctx
);
1295 memcpy( digest
, outer_ctx
.digest
, 16 );
1298 static SECURITY_STATUS
create_signature( struct ntlm_ctx
*ctx
, unsigned int flags
, SecBufferDesc
*msg
, int idx
,
1299 enum sign_direction dir
, BOOL encrypt
)
1301 unsigned int i
, sign_version
= 1;
1302 char *sig
= msg
->pBuffers
[idx
].pvBuffer
;
1304 if (flags
& FLAG_NEGOTIATE_NTLM2
&& flags
& FLAG_NEGOTIATE_SIGN
)
1306 char digest
[16], seq_no
[4];
1307 struct hmac_md5_ctx hmac_md5
;
1309 if (dir
== SIGN_SEND
)
1311 seq_no
[0] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 0) & 0xff;
1312 seq_no
[1] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 8) & 0xff;
1313 seq_no
[2] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 16) & 0xff;
1314 seq_no
[3] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 24) & 0xff;
1315 ctx
->crypt
.ntlm2
.send_seq_no
++;
1317 hmac_md5_init( &hmac_md5
, ctx
->crypt
.ntlm2
.send_sign_key
, 16 );
1321 seq_no
[0] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 0) & 0xff;
1322 seq_no
[1] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 8) & 0xff;
1323 seq_no
[2] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 16) & 0xff;
1324 seq_no
[3] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 24) & 0xff;
1325 ctx
->crypt
.ntlm2
.recv_seq_no
++;
1327 hmac_md5_init( &hmac_md5
, ctx
->crypt
.ntlm2
.recv_sign_key
, 16 );
1330 hmac_md5_update( &hmac_md5
, seq_no
, 4 );
1331 for (i
= 0; i
< msg
->cBuffers
; ++i
)
1333 if (msg
->pBuffers
[i
].BufferType
& SECBUFFER_DATA
)
1334 hmac_md5_update( &hmac_md5
, msg
->pBuffers
[i
].pvBuffer
, msg
->pBuffers
[i
].cbBuffer
);
1336 hmac_md5_final( &hmac_md5
, digest
);
1338 if (encrypt
&& flags
& FLAG_NEGOTIATE_KEY_EXCHANGE
)
1340 if (dir
== SIGN_SEND
)
1341 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, digest
, 8 );
1343 arc4_process( &ctx
->crypt
.ntlm2
.recv_arc4info
, digest
, 8 );
1346 sig
[0] = (sign_version
>> 0) & 0xff;
1347 sig
[1] = (sign_version
>> 8) & 0xff;
1348 sig
[2] = (sign_version
>> 16) & 0xff;
1349 sig
[3] = (sign_version
>> 24) & 0xff;
1350 memcpy( sig
+ 4, digest
, 8 );
1351 memcpy( sig
+ 12, seq_no
, 4 );
1353 msg
->pBuffers
[idx
].cbBuffer
= 16;
1357 if (flags
& FLAG_NEGOTIATE_SIGN
)
1359 unsigned int crc
= 0;
1361 for (i
= 0; i
< msg
->cBuffers
; ++i
)
1363 if (msg
->pBuffers
[i
].BufferType
& SECBUFFER_DATA
)
1364 crc
= RtlComputeCrc32( crc
, msg
->pBuffers
[i
].pvBuffer
, msg
->pBuffers
[i
].cbBuffer
);
1367 sig
[0] = (sign_version
>> 0) & 0xff;
1368 sig
[1] = (sign_version
>> 8) & 0xff;
1369 sig
[2] = (sign_version
>> 16) & 0xff;
1370 sig
[3] = (sign_version
>> 24) & 0xff;
1371 memset( sig
+ 4, 0, 4 );
1372 sig
[8] = (crc
>> 0) & 0xff;
1373 sig
[9] = (crc
>> 8) & 0xff;
1374 sig
[10] = (crc
>> 16) & 0xff;
1375 sig
[11] = (crc
>> 24) & 0xff;
1376 sig
[12] = (ctx
->crypt
.ntlm
.seq_no
>> 0) & 0xff;
1377 sig
[13] = (ctx
->crypt
.ntlm
.seq_no
>> 8) & 0xff;
1378 sig
[14] = (ctx
->crypt
.ntlm
.seq_no
>> 16) & 0xff;
1379 sig
[15] = (ctx
->crypt
.ntlm
.seq_no
>> 24) & 0xff;
1380 ctx
->crypt
.ntlm
.seq_no
++;
1382 if (encrypt
) arc4_process( &ctx
->crypt
.ntlm
.arc4info
, sig
+ 4, 12 );
1386 if (flags
& FLAG_NEGOTIATE_ALWAYS_SIGN
|| !flags
)
1388 /* create dummy signature */
1389 memset( msg
->pBuffers
[idx
].pvBuffer
, 0, 16 );
1390 memset( msg
->pBuffers
[idx
].pvBuffer
, 1, 1 );
1391 msg
->pBuffers
[idx
].cbBuffer
= 16;
1395 return SEC_E_UNSUPPORTED_FUNCTION
;
1398 static NTSTATUS NTAPI
ntlm_SpMakeSignature( LSA_SEC_HANDLE handle
, ULONG qop
, SecBufferDesc
*msg
, ULONG msg_seq_no
)
1400 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1403 TRACE( "%#Ix, %#lx, %p, %lu\n", handle
, qop
, msg
, msg_seq_no
);
1404 if (qop
) FIXME( "ignoring quality of protection %#lx\n", qop
);
1405 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1407 if (!handle
) return SEC_E_INVALID_HANDLE
;
1408 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 || (idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1)
1409 return SEC_E_INVALID_TOKEN
;
1410 if (msg
->pBuffers
[idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1412 return create_signature( ctx
, ctx
->flags
, msg
, idx
, SIGN_SEND
, TRUE
);
1415 static NTSTATUS
verify_signature( struct ntlm_ctx
*ctx
, unsigned int flags
, SecBufferDesc
*msg
, int idx
)
1423 if (!(buf
= malloc( msg
->cBuffers
* sizeof(*buf
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
1424 desc
.ulVersion
= SECBUFFER_VERSION
;
1425 desc
.cBuffers
= msg
->cBuffers
;
1426 desc
.pBuffers
= buf
;
1428 for (i
= 0; i
< msg
->cBuffers
; i
++)
1430 if (msg
->pBuffers
[i
].BufferType
== SECBUFFER_TOKEN
)
1432 buf
[i
].BufferType
= SECBUFFER_TOKEN
;
1433 buf
[i
].cbBuffer
= 16;
1434 buf
[i
].pvBuffer
= sig
;
1438 buf
[i
].BufferType
= msg
->pBuffers
[i
].BufferType
;
1439 buf
[i
].cbBuffer
= msg
->pBuffers
[i
].cbBuffer
;
1440 buf
[i
].pvBuffer
= msg
->pBuffers
[i
].pvBuffer
;
1444 if ((status
= create_signature( ctx
, flags
, &desc
, idx
, SIGN_RECV
, TRUE
)) == SEC_E_OK
)
1446 if (memcmp( (char *)buf
[idx
].pvBuffer
+ 8, (char *)msg
->pBuffers
[idx
].pvBuffer
+ 8, 8 ))
1447 status
= SEC_E_MESSAGE_ALTERED
;
1454 static NTSTATUS NTAPI
ntlm_SpVerifySignature( LSA_SEC_HANDLE handle
, SecBufferDesc
*msg
, ULONG msg_seq_no
, ULONG
*qop
)
1456 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1459 TRACE( "%#Ix, %p, %lu, %p\n", handle
, msg
, msg_seq_no
, qop
);
1460 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1462 if (!handle
) return SEC_E_INVALID_HANDLE
;
1463 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 || (idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1)
1464 return SEC_E_INVALID_TOKEN
;
1465 if (msg
->pBuffers
[idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1467 return verify_signature( ctx
, ctx
->flags
, msg
, idx
);
1470 static NTSTATUS NTAPI
ntlm_SpSealMessage( LSA_SEC_HANDLE handle
, ULONG qop
, SecBufferDesc
*msg
, ULONG msg_seq_no
)
1472 int token_idx
, data_idx
;
1473 struct ntlm_ctx
*ctx
;
1475 TRACE( "%#Ix, %#lx, %p %lu\n", handle
, qop
, msg
, msg_seq_no
);
1476 if (qop
) FIXME( "ignoring quality of protection %#lx\n", qop
);
1477 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1479 if (!handle
) return SEC_E_INVALID_HANDLE
;
1481 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 ||
1482 (token_idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1 ||
1483 (data_idx
= get_buffer_index( msg
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1485 if (msg
->pBuffers
[token_idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1487 ctx
= (struct ntlm_ctx
*)handle
;
1488 if (ctx
->flags
& FLAG_NEGOTIATE_NTLM2
&& ctx
->flags
& FLAG_NEGOTIATE_SEAL
)
1490 create_signature( ctx
, ctx
->flags
, msg
, token_idx
, SIGN_SEND
, FALSE
);
1492 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1493 msg
->pBuffers
[data_idx
].cbBuffer
);
1494 if (ctx
->flags
& FLAG_NEGOTIATE_KEY_EXCHANGE
)
1495 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, (char *)msg
->pBuffers
[token_idx
].pvBuffer
+ 4, 8 );
1499 char *sig
= msg
->pBuffers
[token_idx
].pvBuffer
;
1501 create_signature( ctx
, ctx
->flags
| FLAG_NEGOTIATE_SIGN
, msg
, token_idx
, SIGN_SEND
, FALSE
);
1503 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
, msg
->pBuffers
[data_idx
].cbBuffer
);
1504 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, sig
+ 4, 12 );
1506 if (ctx
->flags
& FLAG_NEGOTIATE_ALWAYS_SIGN
|| !ctx
->flags
) memset( sig
+ 4, 0, 4 );
1512 static NTSTATUS NTAPI
ntlm_SpUnsealMessage( LSA_SEC_HANDLE handle
, SecBufferDesc
*msg
, ULONG msg_seq_no
, ULONG
*qop
)
1514 int token_idx
, data_idx
;
1515 struct ntlm_ctx
*ctx
;
1517 TRACE( "%#Ix, %p, %lu, %p\n", handle
, msg
, msg_seq_no
, qop
);
1518 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1520 if (!handle
) return SEC_E_INVALID_HANDLE
;
1522 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 ||
1523 (token_idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1 ||
1524 (data_idx
= get_buffer_index( msg
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1526 if (msg
->pBuffers
[token_idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1528 ctx
= (struct ntlm_ctx
*)handle
;
1529 if (ctx
->flags
& FLAG_NEGOTIATE_NTLM2
&& ctx
->flags
& FLAG_NEGOTIATE_SEAL
)
1530 arc4_process( &ctx
->crypt
.ntlm2
.recv_arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1531 msg
->pBuffers
[data_idx
].cbBuffer
);
1533 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1534 msg
->pBuffers
[data_idx
].cbBuffer
);
1536 /* make sure we use a session key for the signature check, SealMessage always does that,
1537 even in the dummy case */
1538 return verify_signature( ctx
, ctx
->flags
| FLAG_NEGOTIATE_SIGN
, msg
, token_idx
);
1541 static SECPKG_USER_FUNCTION_TABLE ntlm_user_table
=
1543 ntlm_SpInstanceInit
,
1544 NULL
, /* SpInitUserModeContext */
1545 ntlm_SpMakeSignature
,
1546 ntlm_SpVerifySignature
,
1548 ntlm_SpUnsealMessage
,
1549 NULL
, /* SpGetContextToken */
1550 NULL
, /* SpQueryContextAttributes */
1551 NULL
, /* SpCompleteAuthToken */
1552 NULL
, /* SpDeleteContext */
1553 NULL
, /* SpFormatCredentialsFn */
1554 NULL
, /* SpMarshallSupplementalCreds */
1555 NULL
, /* SpExportSecurityContext */
1556 NULL
/* SpImportSecurityContext */
1559 NTSTATUS NTAPI
SpUserModeInitialize( ULONG lsa_version
, ULONG
*package_version
, SECPKG_USER_FUNCTION_TABLE
**table
,
1560 ULONG
*table_count
)
1562 TRACE( "%#lx, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
1564 *package_version
= SECPKG_INTERFACE_VERSION
;
1565 *table
= &ntlm_user_table
;
1567 return STATUS_SUCCESS
;
1570 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, void *reserved
)
1574 case DLL_PROCESS_ATTACH
:
1575 if (NtQueryVirtualMemory( GetCurrentProcess(), hinst
, MemoryWineUnixFuncs
,
1576 &ntlm_handle
, sizeof(ntlm_handle
), NULL
))
1578 DisableThreadLibraryCalls( hinst
);