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
38 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(ntlm
);
43 static ULONG ntlm_package_id
;
44 static LSA_DISPATCH_TABLE lsa_dispatch
;
46 static NTSTATUS
ntlm_check_version(void)
48 return WINE_UNIX_CALL( unix_check_version
, NULL
);
51 static void ntlm_cleanup( struct ntlm_ctx
*ctx
)
53 WINE_UNIX_CALL( unix_cleanup
, ctx
);
56 static NTSTATUS
ntlm_chat( struct ntlm_ctx
*ctx
, char *buf
, unsigned int buflen
, unsigned int *retlen
)
58 struct chat_params params
= { ctx
, buf
, buflen
, retlen
};
60 return WINE_UNIX_CALL( unix_chat
, ¶ms
);
63 static NTSTATUS
ntlm_fork( struct ntlm_ctx
*ctx
, char **argv
)
65 struct fork_params params
= { ctx
, argv
};
67 return WINE_UNIX_CALL( unix_fork
, ¶ms
);
71 ( SECPKG_FLAG_INTEGRITY \
72 | SECPKG_FLAG_PRIVACY \
73 | SECPKG_FLAG_TOKEN_ONLY \
74 | SECPKG_FLAG_CONNECTION \
75 | SECPKG_FLAG_MULTI_REQUIRED \
76 | SECPKG_FLAG_IMPERSONATION \
77 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
78 | SECPKG_FLAG_NEGOTIABLE \
80 | SECPKG_FLAG_RESTRICTED_TOKENS )
82 #define NTLM_MAX_BUF 1904
84 static const SecPkgInfoW ntlm_package_info
=
91 (SEC_WCHAR
*)L
"NTLM Security Package"
94 static inline const char *debugstr_as( const STRING
*str
)
96 if (!str
) return "<null>";
97 return debugstr_an( str
->Buffer
, str
->Length
);
100 static inline const char *debugstr_us( const UNICODE_STRING
*str
)
102 if (!str
) return "<null>";
103 return debugstr_wn( str
->Buffer
, str
->Length
/ sizeof(WCHAR
) );
106 static NTSTATUS NTAPI
ntlm_LsaApInitializePackage( ULONG package_id
, LSA_DISPATCH_TABLE
*dispatch
,
107 LSA_STRING
*database
, LSA_STRING
*confidentiality
,
108 LSA_STRING
**package_name
)
113 TRACE( "%#lx, %p, %s, %s, %p\n", package_id
, dispatch
, debugstr_as(database
), debugstr_as(confidentiality
),
116 if (ntlm_check_version())
118 ERR( "no NTLM support, expect problems\n" );
119 return STATUS_UNSUCCESSFUL
;
122 if (!(str
= dispatch
->AllocateLsaHeap( sizeof(*str
) + sizeof("NTLM" )))) return STATUS_NO_MEMORY
;
123 ptr
= (char *)(str
+ 1);
124 memcpy( ptr
, "NTLM", sizeof("NTLM") );
125 RtlInitString( str
, ptr
);
127 ntlm_package_id
= package_id
;
128 lsa_dispatch
= *dispatch
;
131 return STATUS_SUCCESS
;
134 static NTSTATUS NTAPI
ntlm_SpInitialize( ULONG_PTR package_id
, SECPKG_PARAMETERS
*params
,
135 LSA_SECPKG_FUNCTION_TABLE
*lsa_function_table
)
137 TRACE( "%#Ix, %p, %p\n", package_id
, params
, lsa_function_table
);
139 if (ntlm_check_version())
141 ERR( "no NTLM support, expect problems\n" );
142 return STATUS_UNSUCCESSFUL
;
144 return STATUS_SUCCESS
;
147 static NTSTATUS NTAPI
ntlm_SpGetInfo( SecPkgInfoW
*info
)
149 TRACE( "%p\n", info
);
150 *info
= ntlm_package_info
;
151 return STATUS_SUCCESS
;
154 static char *get_username_arg( const WCHAR
*user
, int user_len
)
156 static const char arg
[] = "--username=";
157 int len
= sizeof(arg
);
160 len
+= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, user
, user_len
, NULL
, 0, NULL
, NULL
);
161 if (!(ret
= malloc( len
))) return NULL
;
162 memcpy( ret
, arg
, sizeof(arg
) - 1 );
163 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, user
, user_len
, ret
+ sizeof(arg
) - 1,
164 len
- sizeof(arg
) + 1, NULL
, NULL
);
169 static char *get_domain_arg( const WCHAR
*domain
, int domain_len
)
171 static const char arg
[] = "--domain=";
172 int len
= sizeof(arg
);
175 len
+= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, domain
, domain_len
, NULL
, 0, NULL
, NULL
);
176 if (!(ret
= malloc( len
))) return NULL
;
177 memcpy( ret
, arg
, sizeof(arg
) - 1 );
178 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, domain
, domain_len
, ret
+ sizeof(arg
) - 1,
179 len
- sizeof(arg
) + 1, NULL
, NULL
);
184 #define WINE_NO_CACHED_CREDENTIALS 0x10000000
185 static NTSTATUS NTAPI
ntlm_SpAcquireCredentialsHandle( UNICODE_STRING
*principal
, ULONG cred_use
, LUID
*logon_id
,
186 void *auth_data
, void *get_key_fn
, void *get_key_arg
,
187 LSA_SEC_HANDLE
*handle
, TimeStamp
*expiry
)
189 SECURITY_STATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
190 struct ntlm_cred
*cred
= NULL
;
191 WCHAR
*domain
= NULL
, *user
= NULL
, *password
= NULL
;
192 SEC_WINNT_AUTH_IDENTITY_W
*id
= NULL
;
194 TRACE( "%s, %#lx, %p, %p, %p, %p, %p, %p\n", debugstr_us(principal
), cred_use
, logon_id
, auth_data
,
195 get_key_fn
, get_key_arg
, cred
, expiry
);
197 switch (cred_use
& ~SECPKG_CRED_RESERVED
)
199 case SECPKG_CRED_INBOUND
:
200 if (!(cred
= malloc( sizeof(*cred
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
201 cred
->mode
= MODE_SERVER
;
202 cred
->username_arg
= NULL
;
203 cred
->domain_arg
= NULL
;
204 cred
->password
= NULL
;
205 cred
->password_len
= 0;
206 cred
->no_cached_credentials
= 0;
208 *handle
= (LSA_SEC_HANDLE
)cred
;
212 case SECPKG_CRED_OUTBOUND
:
213 if (!(cred
= malloc( sizeof(*cred
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
215 cred
->mode
= MODE_CLIENT
;
216 cred
->username_arg
= NULL
;
217 cred
->domain_arg
= NULL
;
218 cred
->password
= NULL
;
219 cred
->password_len
= 0;
220 cred
->no_cached_credentials
= (cred_use
& WINE_NO_CACHED_CREDENTIALS
);
222 if ((id
= auth_data
))
224 int domain_len
= 0, user_len
= 0, password_len
= 0;
225 if (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
)
227 if (id
->DomainLength
)
229 domain_len
= MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Domain
, id
->DomainLength
, NULL
, 0 );
230 if (!(domain
= malloc( sizeof(WCHAR
) * domain_len
))) goto done
;
231 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Domain
, id
->DomainLength
, domain
, domain_len
);
235 user_len
= MultiByteToWideChar( CP_ACP
, 0, (char *)id
->User
, id
->UserLength
, NULL
, 0 );
236 if (!(user
= malloc( sizeof(WCHAR
) * user_len
))) goto done
;
237 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->User
, id
->UserLength
, user
, user_len
);
239 if (id
->PasswordLength
)
241 password_len
= MultiByteToWideChar( CP_ACP
, 0,(char *)id
->Password
, id
->PasswordLength
, NULL
, 0 );
242 if (!(password
= malloc( sizeof(WCHAR
) * password_len
))) goto done
;
243 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Password
, id
->PasswordLength
, password
, password_len
);
249 domain_len
= id
->DomainLength
;
251 user_len
= id
->UserLength
;
252 password
= id
->Password
;
253 password_len
= id
->PasswordLength
;
256 TRACE( "username is %s\n", debugstr_wn(user
, user_len
) );
257 TRACE( "domain name is %s\n", debugstr_wn(domain
, domain_len
) );
259 cred
->username_arg
= get_username_arg( user
, user_len
);
260 cred
->domain_arg
= get_domain_arg( domain
, domain_len
);
263 cred
->password_len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, password
, password_len
,
264 NULL
, 0, NULL
, NULL
);
265 if (!(cred
->password
= malloc( cred
->password_len
))) goto done
;
266 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, password
, password_len
, cred
->password
,
267 cred
->password_len
, NULL
, NULL
);
271 *handle
= (LSA_SEC_HANDLE
)cred
;
275 case SECPKG_CRED_BOTH
:
276 FIXME( "SECPKG_CRED_BOTH not supported\n" );
277 status
= SEC_E_UNSUPPORTED_FUNCTION
;
281 status
= SEC_E_UNKNOWN_CREDENTIALS
;
286 if (id
&& (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
))
292 if (status
!= SEC_E_OK
) free( cred
);
296 static NTSTATUS NTAPI
ntlm_SpFreeCredentialsHandle( LSA_SEC_HANDLE handle
)
298 struct ntlm_cred
*cred
= (struct ntlm_cred
*)handle
;
300 TRACE( "%#Ix\n", handle
);
302 if (!cred
) return SEC_E_OK
;
304 cred
->mode
= MODE_INVALID
;
305 if (cred
->password
) memset( cred
->password
, 0, cred
->password_len
);
306 free( cred
->password
);
307 free( cred
->username_arg
);
308 free( cred
->domain_arg
);
313 static BOOL
get_cached_credential( const UNICODE_STRING
*target
, CREDENTIALW
**cred
)
315 const WCHAR
*ptr
, *host
;
320 if (!target
) return FALSE
;
322 len
= target
->Length
/ sizeof(WCHAR
);
323 if ((host
= wmemchr( target
->Buffer
, '/', len
)))
326 len
-= host
- target
->Buffer
;
327 if (!(ptr
= wmemchr( host
, ':', len
))) ptr
= wmemchr( host
, '/', len
);
328 if (!ptr
) ptr
= host
+ len
;
332 host
= target
->Buffer
;
336 if (!(hostonly
= malloc( (ptr
- host
+ 1) * sizeof(WCHAR
) ))) return FALSE
;
337 memcpy( hostonly
, host
, (ptr
- host
) * sizeof(WCHAR
) );
338 hostonly
[ptr
- host
] = 0;
340 ret
= CredReadW( hostonly
, CRED_TYPE_DOMAIN_PASSWORD
, 0, cred
);
345 static UINT
encode_base64( const char *bin
, unsigned int len
, char *base64
)
347 static const char base64enc
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
352 /* first 6 bits, all from bin[0] */
353 base64
[n
++] = base64enc
[(bin
[0] & 0xfc) >> 2];
354 x
= (bin
[0] & 3) << 4;
356 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
359 base64
[n
++] = base64enc
[x
];
364 base64
[n
++] = base64enc
[x
| ((bin
[1] & 0xf0) >> 4)];
365 x
= (bin
[1] & 0x0f) << 2;
367 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
370 base64
[n
++] = base64enc
[x
];
374 base64
[n
++] = base64enc
[x
| ((bin
[2] & 0xc0) >> 6)];
376 /* last 6 bits, all from bin[2] */
377 base64
[n
++] = base64enc
[bin
[2] & 0x3f];
385 static inline char decode_char( char c
)
387 if (c
>= 'A' && c
<= 'Z') return c
- 'A';
388 if (c
>= 'a' && c
<= 'z') return c
- 'a' + 26;
389 if (c
>= '0' && c
<= '9') return c
- '0' + 52;
390 if (c
== '+') return 62;
391 if (c
== '/') return 63;
395 static unsigned int decode_base64( const char *base64
, unsigned int len
, char *buf
)
399 const char *p
= base64
;
403 if ((c0
= decode_char( p
[0] )) > 63) return 0;
404 if ((c1
= decode_char( p
[1] )) > 63) return 0;
405 if ((c2
= decode_char( p
[2] )) > 63) return 0;
406 if ((c3
= decode_char( p
[3] )) > 63) return 0;
409 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
410 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
411 buf
[i
+ 2] = (c2
<< 6) | c3
;
419 if ((c0
= decode_char( p
[0] )) > 63) return 0;
420 if ((c1
= decode_char( p
[1] )) > 63) return 0;
421 if (buf
) buf
[i
] = (c0
<< 2) | (c1
>> 4);
424 else if (p
[3] == '=')
426 if ((c0
= decode_char( p
[0] )) > 63) return 0;
427 if ((c1
= decode_char( p
[1] )) > 63) return 0;
428 if ((c2
= decode_char( p
[2] )) > 63) return 0;
431 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
432 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
438 if ((c0
= decode_char( p
[0] )) > 63) return 0;
439 if ((c1
= decode_char( p
[1] )) > 63) return 0;
440 if ((c2
= decode_char( p
[2] )) > 63) return 0;
441 if ((c3
= decode_char( p
[3] )) > 63) return 0;
444 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
445 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
446 buf
[i
+ 2] = (c2
<< 6) | c3
;
457 unsigned char in
[64];
458 unsigned char digest
[16];
461 void WINAPI
MD4Init( struct md4_ctx
* );
462 void WINAPI
MD4Update( struct md4_ctx
*, const char *, unsigned int );
463 void WINAPI
MD4Final( struct md4_ctx
* );
465 static void create_ntlm1_session_key( const char *secret
, unsigned int len
, char *session_key
)
471 MD4Update( &ctx
, secret
, len
);
473 memcpy( hash
, ctx
.digest
, 16 );
476 MD4Update( &ctx
, hash
, 16 );
478 memcpy( session_key
, ctx
.digest
, 16 );
485 unsigned char in
[64];
486 unsigned char digest
[16];
489 void WINAPI
MD5Init( struct md5_ctx
* );
490 void WINAPI
MD5Update( struct md5_ctx
*, const char *, unsigned int );
491 void WINAPI
MD5Final( struct md5_ctx
* );
493 static void calc_ntlm2_subkey( const char *session_key
, const char *magic
, char *subkey
)
498 MD5Update( &ctx
, session_key
, 16 );
499 MD5Update( &ctx
, magic
, strlen(magic
) + 1 );
501 memcpy( subkey
, ctx
.digest
, 16 );
504 static const char client_to_server_sign_constant
[] = "session key to client-to-server signing key magic constant";
505 static const char client_to_server_seal_constant
[] = "session key to client-to-server sealing key magic constant";
506 static const char server_to_client_sign_constant
[] = "session key to server-to-client signing key magic constant";
507 static const char server_to_client_seal_constant
[] = "session key to server-to-client sealing key magic constant";
509 static void create_ntlm2_subkeys( struct ntlm_ctx
*ctx
)
511 if (ctx
->mode
== MODE_CLIENT
)
513 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_sign_constant
, ctx
->crypt
.ntlm2
.send_sign_key
);
514 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_seal_constant
, ctx
->crypt
.ntlm2
.send_seal_key
);
515 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_sign_constant
, ctx
->crypt
.ntlm2
.recv_sign_key
);
516 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_seal_constant
, ctx
->crypt
.ntlm2
.recv_seal_key
);
520 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_sign_constant
, ctx
->crypt
.ntlm2
.send_sign_key
);
521 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_seal_constant
, ctx
->crypt
.ntlm2
.send_seal_key
);
522 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_sign_constant
, ctx
->crypt
.ntlm2
.recv_sign_key
);
523 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_seal_constant
, ctx
->crypt
.ntlm2
.recv_seal_key
);
528 * The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack,
529 * which in turn is based on public domain code by Wei Dai
531 static void arc4_init( struct arc4_info
*info
, const char *key
, unsigned int len
)
533 unsigned int key_idx
= 0, state_idx
= 0, i
, a
;
535 info
->x
= info
->y
= 0;
536 for (i
= 0; i
< 256; i
++) info
->state
[i
] = i
;
538 for (i
= 0; i
< 256; i
++)
541 state_idx
+= key
[key_idx
] + a
;
543 info
->state
[i
] = info
->state
[state_idx
];
544 info
->state
[state_idx
] = a
;
545 if (++key_idx
>= len
) key_idx
= 0;
549 static void arc4_process( struct arc4_info
*info
, char *buf
, unsigned int len
)
551 char *state
= info
->state
;
552 unsigned int x
= info
->x
, y
= info
->y
, a
, b
;
562 *buf
++ ^= state
[(a
+ b
) & 0xff];
569 static int get_buffer_index( SecBufferDesc
*desc
, ULONG type
)
572 for (idx
= 0; idx
< desc
->cBuffers
; idx
++)
574 if (desc
->pBuffers
[idx
].BufferType
== type
) return idx
;
579 static NTSTATUS NTAPI
ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle
, LSA_SEC_HANDLE ctx_handle
,
580 UNICODE_STRING
*target
, ULONG ctx_req
, ULONG data_rep
,
581 SecBufferDesc
*input
, LSA_SEC_HANDLE
*new_ctx_handle
,
582 SecBufferDesc
*output
, ULONG
*ctx_attr
, TimeStamp
*expiry
,
583 BOOLEAN
*mapped_ctx
, SecBuffer
*ctx_data
)
585 NTSTATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
586 struct ntlm_ctx
*ctx
= NULL
;
587 char *buf
, *bin
, *want_flags
= NULL
, *username
= NULL
, *domain
= NULL
, *password
= NULL
;
588 unsigned int len
, bin_len
;
591 TRACE( "%#Ix, %#Ix, %s, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle
, ctx_handle
, debugstr_us(target
),
592 ctx_req
, data_rep
, input
, new_ctx_handle
, output
, ctx_attr
, expiry
, mapped_ctx
, ctx_data
);
594 /* when communicating with the client there can be the following reply packets:
595 * YR <base64 blob> should be sent to the server
596 * PW should be sent back to helper with base64 encoded password
597 * AF <base64 blob> client is done, blob should be sent to server with KK prefixed
598 * GF <string list> a string list of negotiated flags
599 * GK <base64 blob> base64 encoded session key
600 * BH <char reason> something broke
602 * The squid cache size is 2010 chars and that's what ntlm_auth uses */
604 if (!(buf
= malloc( NTLM_MAX_BUF
))) return SEC_E_INSUFFICIENT_MEMORY
;
605 if (!(bin
= malloc( NTLM_MAX_BUF
))) goto done
;
607 if (!ctx_handle
&& !input
)
610 int password_len
= 0;
611 struct ntlm_cred
*cred
= (struct ntlm_cred
*)cred_handle
;
613 if (!cred
|| cred
->mode
!= MODE_CLIENT
)
615 status
= SEC_E_INVALID_HANDLE
;
619 argv
[0] = (char *)"ntlm_auth";
620 argv
[1] = (char *)"--helper-protocol=ntlmssp-client-1";
621 if (!cred
->username_arg
&& !cred
->domain_arg
)
623 WKSTA_USER_INFO_1
*ui
= NULL
;
627 if (get_cached_credential( target
, &cached
))
630 if ((p
= wcschr( cached
->UserName
, '\\' )))
632 if (!(domain
= get_domain_arg( cached
->UserName
, p
- cached
->UserName
))) goto done
;
637 if (!(domain
= get_domain_arg( NULL
, 0 ))) goto done
;
638 p
= cached
->UserName
;
640 if (!(username
= get_username_arg( p
, -1 ))) goto done
;
642 if (cached
->CredentialBlobSize
)
644 password_len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, (WCHAR
*)cached
->CredentialBlob
,
645 cached
->CredentialBlobSize
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
646 if (!(password
= malloc( password_len
))) goto done
;
647 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, (WCHAR
*)cached
->CredentialBlob
,
648 cached
->CredentialBlobSize
/ sizeof(WCHAR
), password
, password_len
, NULL
, NULL
);
658 ret
= NetWkstaUserGetInfo( NULL
, 1, (BYTE
**)&ui
);
659 if (ret
!= NERR_Success
|| !ui
|| cred
->no_cached_credentials
)
661 status
= SEC_E_NO_CREDENTIALS
;
664 if (!(username
= get_username_arg( ui
->wkui1_username
, -1 ))) goto done
;
665 NetApiBufferFree( ui
);
666 TRACE("using cached credentials\n");
669 argv
[3] = (char *)"--use-cached-creds";
675 argv
[2] = cred
->username_arg
;
676 argv
[3] = cred
->domain_arg
;
680 if (!(ctx
= calloc( 1, sizeof(*ctx
) ))) goto done
;
682 if ((status
= ntlm_fork( ctx
, argv
)) != SEC_E_OK
) goto done
;
683 status
= SEC_E_INSUFFICIENT_MEMORY
;
685 ctx
->mode
= MODE_CLIENT
;
686 memset( ctx
->session_key
, 0, sizeof(ctx
->session_key
) );
688 /* generate the dummy session key = MD4(MD4(password))*/
689 if (password
|| cred
->password
)
692 len
= MultiByteToWideChar( CP_ACP
, 0, password
? password
: cred
->password
,
693 password
? password_len
: cred
->password_len
, NULL
, 0 );
694 if (!(passwordW
= malloc( len
* sizeof(WCHAR
) ))) goto done
;
695 MultiByteToWideChar( CP_ACP
, 0, password
? password
: cred
->password
,
696 password
? password_len
: cred
->password_len
, passwordW
, len
);
698 create_ntlm1_session_key( (const char *)passwordW
, len
* sizeof(WCHAR
), ctx
->session_key
);
702 /* allocate space for a maximum string of
703 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL NTLMSSP_FEATURE_SESSION_KEY"
705 if (!(want_flags
= malloc( 73 ))) goto done
;
706 strcpy( want_flags
, "SF" );
707 if (ctx_req
& ISC_REQ_CONFIDENTIALITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SEAL" );
708 if ((ctx_req
& ISC_REQ_INTEGRITY
) || (ctx_req
& ISC_REQ_REPLAY_DETECT
) ||
709 (ctx_req
& ISC_REQ_SEQUENCE_DETECT
)) strcat( want_flags
, " NTLMSSP_FEATURE_SIGN" );
711 if (ctx_req
& ISC_REQ_CONNECTION
) ctx
->attrs
|= ISC_RET_CONNECTION
;
712 if (ctx_req
& ISC_REQ_EXTENDED_ERROR
) ctx
->attrs
|= ISC_RET_EXTENDED_ERROR
;
713 if (ctx_req
& ISC_REQ_MUTUAL_AUTH
) ctx
->attrs
|= ISC_RET_MUTUAL_AUTH
;
714 if (ctx_req
& ISC_REQ_USE_DCE_STYLE
) ctx
->attrs
|= ISC_RET_USED_DCE_STYLE
;
715 if (ctx_req
& ISC_REQ_DELEGATE
) ctx
->attrs
|= ISC_RET_DELEGATE
;
716 if (ctx_req
& ISC_REQ_STREAM
) FIXME( "ISC_REQ_STREAM\n" );
718 /* use cached credentials if no password was given, fall back to an empty password on failure */
719 if (!password
&& !cred
->password
)
722 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
724 /* if the helper replied with "PW" using cached credentials failed */
725 if (!strncmp( buf
, "PW", 2 ))
727 TRACE( "using cached credentials failed\n" );
728 strcpy( buf
, "PW AA==" );
730 else strcpy( buf
, "OK" ); /* just do a noop on the next run */
734 strcpy( buf
, "PW " );
735 encode_base64( password
? password
: cred
->password
, password
? password_len
: cred
->password_len
, buf
+ 3 );
738 TRACE( "sending to ntlm_auth: %s\n", debugstr_a(buf
) );
739 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
740 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf
) );
742 if (strlen( want_flags
) > 2)
744 TRACE( "want flags are %s\n", debugstr_a(want_flags
) );
745 strcpy( buf
, want_flags
);
746 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
747 if (!strncmp( buf
, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
751 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
752 TRACE( "ntlm_auth returned %s\n", buf
);
753 if (strncmp( buf
, "YR ", 3 ))
755 status
= SEC_E_INTERNAL_ERROR
;
758 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
760 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
761 status
= SEC_I_CONTINUE_NEEDED
;
763 else /* !ctx_handle && !input */
765 if (!input
|| ((idx
= get_buffer_index( input
, SECBUFFER_TOKEN
)) == -1))
767 status
= SEC_E_INVALID_TOKEN
;
771 ctx
= (struct ntlm_ctx
*)ctx_handle
;
772 if (!ctx
|| ctx
->mode
!= MODE_CLIENT
)
774 status
= SEC_E_INVALID_HANDLE
;
778 if (!input
->pBuffers
[idx
].pvBuffer
|| input
->pBuffers
[idx
].cbBuffer
> NTLM_MAX_BUF
)
780 status
= SEC_E_INVALID_TOKEN
;
783 bin_len
= input
->pBuffers
[idx
].cbBuffer
;
784 memcpy( bin
, input
->pBuffers
[idx
].pvBuffer
, bin_len
);
786 strcpy( buf
, "TT " );
787 encode_base64( bin
, bin_len
, buf
+ 3 );
788 TRACE( "server sent: %s\n", debugstr_a(buf
) );
790 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
))) goto done
;
791 TRACE( "ntlm_auth returned: %s\n", debugstr_a(buf
) );
793 if (strncmp( buf
, "KK ", 3 ) && strncmp( buf
, "AF ", 3 ))
795 status
= SEC_E_INVALID_TOKEN
;
798 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
800 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
804 if (!output
|| ((idx
= get_buffer_index( output
, SECBUFFER_TOKEN
)) == -1))
806 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
807 status
= SEC_E_BUFFER_TOO_SMALL
;
811 if (ctx_req
& ISC_REQ_ALLOCATE_MEMORY
)
813 /* freed with secur32.FreeContextBuffer */
814 if (!(output
->pBuffers
[idx
].pvBuffer
= RtlAllocateHeap( GetProcessHeap(), 0, bin_len
)))
816 status
= SEC_E_INSUFFICIENT_MEMORY
;
819 output
->pBuffers
[idx
].cbBuffer
= bin_len
;
821 else if (output
->pBuffers
[idx
].cbBuffer
< bin_len
)
823 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
824 status
= SEC_E_BUFFER_TOO_SMALL
;
828 if (!output
->pBuffers
[idx
].pvBuffer
)
830 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
831 status
= SEC_E_INTERNAL_ERROR
;
835 output
->pBuffers
[idx
].cbBuffer
= bin_len
;
836 memcpy( output
->pBuffers
[idx
].pvBuffer
, bin
, bin_len
);
837 if (status
== SEC_E_OK
)
840 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
841 if (len
< 3) ctx
->flags
= 0;
842 else sscanf( buf
+ 3, "%x", &ctx
->flags
);
845 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
847 if (!strncmp( buf
, "BH", 2 )) TRACE( "no key negotiated\n" );
848 else if (!strncmp( buf
, "GK ", 3 ))
850 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
851 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
852 memcpy( ctx
->session_key
, bin
, bin_len
);
855 arc4_init( &ctx
->crypt
.ntlm
.arc4info
, ctx
->session_key
, 16 );
856 ctx
->crypt
.ntlm
.seq_no
= 0;
857 create_ntlm2_subkeys( ctx
);
858 arc4_init( &ctx
->crypt
.ntlm2
.send_arc4info
, ctx
->crypt
.ntlm2
.send_seal_key
, 16 );
859 arc4_init( &ctx
->crypt
.ntlm2
.recv_arc4info
, ctx
->crypt
.ntlm2
.recv_seal_key
, 16 );
860 ctx
->crypt
.ntlm2
.send_seq_no
= 0;
861 ctx
->crypt
.ntlm2
.recv_seq_no
= 0;
865 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
&& !ctx_handle
&& !input
)
877 TRACE( "returning %#lx\n", status
);
881 static NTSTATUS NTAPI
ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle
, LSA_SEC_HANDLE ctx_handle
,
882 SecBufferDesc
*input
, ULONG ctx_req
, ULONG data_rep
,
883 LSA_SEC_HANDLE
*new_ctx_handle
, SecBufferDesc
*output
,
884 ULONG
*ctx_attr
, TimeStamp
*expiry
, BOOLEAN
*mapped_ctx
,
885 SecBuffer
*ctx_data
)
887 NTSTATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
888 struct ntlm_ctx
*ctx
= NULL
;
889 char *buf
, *bin
, *want_flags
= NULL
;
890 unsigned int len
, bin_len
;
892 TRACE( "%#Ix, %#Ix, %#lx, %lu, %p, %p, %p, %p, %p, %p, %p\n", cred_handle
, ctx_handle
, ctx_req
, data_rep
, input
,
893 new_ctx_handle
, output
, ctx_attr
, expiry
, mapped_ctx
, ctx_data
);
894 if (ctx_req
) FIXME( "ignoring flags %#lx\n", ctx_req
);
896 if (!(buf
= malloc( NTLM_MAX_BUF
))) return SEC_E_INSUFFICIENT_MEMORY
;
897 if (!(bin
= malloc( NTLM_MAX_BUF
))) goto done
;
901 struct ntlm_cred
*cred
= (struct ntlm_cred
*)cred_handle
;
904 if (!cred
|| cred
->mode
!= MODE_SERVER
)
906 status
= SEC_E_INVALID_HANDLE
;
910 if (!input
|| input
->cBuffers
< 1)
912 status
= SEC_E_INCOMPLETE_MESSAGE
;
916 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
918 status
= SEC_E_INVALID_TOKEN
;
921 else bin_len
= input
->pBuffers
[0].cbBuffer
;
923 if (!(ctx
= calloc( 1, sizeof(*ctx
) ))) goto done
;
925 argv
[0] = (char *)"ntlm_auth";
926 argv
[1] = (char *)"--helper-protocol=squid-2.5-ntlmssp";
928 if ((status
= ntlm_fork( ctx
, argv
)) != SEC_E_OK
) goto done
;
929 ctx
->mode
= MODE_SERVER
;
931 if (!(want_flags
= malloc( 73 )))
933 status
= SEC_E_INSUFFICIENT_MEMORY
;
936 strcpy( want_flags
, "SF" );
937 if (ctx_req
& ASC_REQ_CONFIDENTIALITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SEAL" );
938 if (ctx_req
& ASC_REQ_CONNECTION
)
940 strcat( want_flags
, " NTLMSSP_FEATURE_SESSION_KEY" );
941 ctx
->attrs
|= ASC_RET_CONNECTION
;
943 if (ctx_req
& ASC_REQ_INTEGRITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SIGN" );
944 if (ctx_req
& ASC_REQ_ALLOCATE_MEMORY
) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
945 if (ctx_req
& ASC_REQ_EXTENDED_ERROR
) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
946 if (ctx_req
& ASC_REQ_MUTUAL_AUTH
) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
947 if (ctx_req
& ASC_REQ_REPLAY_DETECT
) FIXME( "ASC_REQ_REPLAY_DETECT\n" );
948 if (ctx_req
& ASC_REQ_SEQUENCE_DETECT
) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
949 if (ctx_req
& ASC_REQ_STREAM
) FIXME( "ASC_REQ_STREAM\n" );
951 if (strlen( want_flags
) > 3)
953 TRACE( "want flags are %s\n", debugstr_a(want_flags
) );
954 strcpy( buf
, want_flags
);
955 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
956 if (!strncmp( buf
, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
959 memcpy( bin
, input
->pBuffers
[0].pvBuffer
, bin_len
);
960 strcpy( buf
, "YR " );
961 encode_base64( bin
, bin_len
, buf
+ 3 );
963 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
964 TRACE( "ntlm_auth returned %s\n", buf
);
965 if (strncmp( buf
, "TT ", 3))
967 status
= SEC_E_INTERNAL_ERROR
;
970 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
972 if (!output
|| output
->cBuffers
< 1)
974 status
= SEC_E_INSUFFICIENT_MEMORY
;
977 output
->pBuffers
[0].cbBuffer
= bin_len
;
978 output
->pBuffers
[0].BufferType
= SECBUFFER_DATA
;
979 memcpy( output
->pBuffers
[0].pvBuffer
, bin
, bin_len
);
981 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
982 status
= SEC_I_CONTINUE_NEEDED
;
986 if (!input
|| input
->cBuffers
< 1)
988 status
= SEC_E_INCOMPLETE_MESSAGE
;
992 ctx
= (struct ntlm_ctx
*)ctx_handle
;
993 if (!ctx
|| ctx
->mode
!= MODE_SERVER
)
995 status
= SEC_E_INVALID_HANDLE
;
999 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
1001 status
= SEC_E_INVALID_TOKEN
;
1004 else bin_len
= input
->pBuffers
[0].cbBuffer
;
1005 memcpy( bin
, input
->pBuffers
[0].pvBuffer
, bin_len
);
1007 strcpy( buf
, "KK " );
1008 encode_base64( bin
, bin_len
, buf
+ 3 );
1010 TRACE( "client sent %s\n", debugstr_a(buf
) );
1011 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1012 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf
) );
1014 /* At this point, we get a NA if the user didn't authenticate, but a BH if ntlm_auth could not
1015 * connect to winbindd. Apart from running Wine as root, there is no way to fix this for now,
1016 * so just handle this as a failed login. */
1017 if (strncmp( buf
, "AF ", 3 ))
1019 if (!strncmp( buf
, "NA ", 3 ))
1021 status
= SEC_E_LOGON_DENIED
;
1026 const char err_v3
[] = "BH NT_STATUS_ACCESS_DENIED";
1027 const char err_v4
[] = "BH NT_STATUS_UNSUCCESSFUL";
1029 if ((len
>= strlen(err_v3
) && !strncmp( buf
, err_v3
, strlen(err_v3
) )) ||
1030 (len
>= strlen(err_v4
) && !strncmp( buf
, err_v4
, strlen(err_v4
) )))
1032 TRACE( "connection to winbindd failed\n" );
1033 status
= SEC_E_LOGON_DENIED
;
1035 else status
= SEC_E_INTERNAL_ERROR
;
1039 output
->pBuffers
[0].cbBuffer
= 0;
1041 strcpy( buf
, "GF" );
1042 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1043 if (len
< 3) ctx
->flags
= 0;
1044 else sscanf( buf
+ 3, "%x", &ctx
->flags
);
1046 strcpy( buf
, "GK" );
1047 if ((status
= ntlm_chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1049 if (!strncmp( buf
, "BH", 2 )) TRACE( "no key negotiated\n" );
1050 else if (!strncmp( buf
, "GK ", 3 ))
1052 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
1053 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
1054 memcpy( ctx
->session_key
, bin
, bin_len
);
1057 if (len
< 3) memset( ctx
->session_key
, 0 , 16 );
1060 if (!strncmp( buf
, "BH ", 3 ))
1062 TRACE( "helper sent %s\n", debugstr_a(buf
+ 3) );
1063 /*FIXME: generate dummy session key = MD4(MD4(password))*/
1064 memset( ctx
->session_key
, 0 , 16 );
1066 else if (!strncmp( buf
, "GK ", 3 ))
1068 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
1069 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
1070 memcpy( ctx
->session_key
, bin
, 16 );
1073 arc4_init( &ctx
->crypt
.ntlm
.arc4info
, ctx
->session_key
, 16 );
1074 ctx
->crypt
.ntlm
.seq_no
= 0;
1076 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
1081 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
&& !ctx_handle
)
1083 ntlm_cleanup( ctx
);
1090 TRACE( "returning %#lx\n", status
);
1094 static NTSTATUS NTAPI
ntlm_SpDeleteContext( LSA_SEC_HANDLE handle
)
1096 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1098 TRACE( "%#Ix\n", handle
);
1100 if (!ctx
) return SEC_E_INVALID_HANDLE
;
1101 ntlm_cleanup( ctx
);
1106 static SecPkgInfoW
*build_package_info( const SecPkgInfoW
*info
)
1109 DWORD size_name
= (wcslen(info
->Name
) + 1) * sizeof(WCHAR
);
1110 DWORD size_comment
= (wcslen(info
->Comment
) + 1) * sizeof(WCHAR
);
1112 if (!(ret
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*ret
) + size_name
+ size_comment
))) return NULL
;
1113 ret
->fCapabilities
= info
->fCapabilities
;
1114 ret
->wVersion
= info
->wVersion
;
1115 ret
->wRPCID
= info
->wRPCID
;
1116 ret
->cbMaxToken
= info
->cbMaxToken
;
1117 ret
->Name
= (SEC_WCHAR
*)(ret
+ 1);
1118 memcpy( ret
->Name
, info
->Name
, size_name
);
1119 ret
->Comment
= (SEC_WCHAR
*)((char *)ret
->Name
+ size_name
);
1120 memcpy( ret
->Comment
, info
->Comment
, size_comment
);
1124 static NTSTATUS NTAPI
ntlm_SpQueryContextAttributes( LSA_SEC_HANDLE handle
, ULONG attr
, void *buf
)
1126 TRACE( "%#Ix, %lu, %p\n", handle
, attr
, buf
);
1128 if (!handle
) return SEC_E_INVALID_HANDLE
;
1132 #define X(x) case (x) : FIXME(#x" stub\n"); break
1133 X(SECPKG_ATTR_ACCESS_TOKEN
);
1134 X(SECPKG_ATTR_AUTHORITY
);
1135 X(SECPKG_ATTR_DCE_INFO
);
1136 X(SECPKG_ATTR_LIFESPAN
);
1137 X(SECPKG_ATTR_NAMES
);
1138 X(SECPKG_ATTR_NATIVE_NAMES
);
1139 X(SECPKG_ATTR_PACKAGE_INFO
);
1140 X(SECPKG_ATTR_PASSWORD_EXPIRY
);
1141 X(SECPKG_ATTR_SESSION_KEY
);
1142 X(SECPKG_ATTR_STREAM_SIZES
);
1143 X(SECPKG_ATTR_TARGET_INFORMATION
);
1144 case SECPKG_ATTR_FLAGS
:
1146 SecPkgContext_Flags
*flags
= (SecPkgContext_Flags
*)buf
;
1147 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1150 if (ctx
->flags
& FLAG_NEGOTIATE_SIGN
) flags
->Flags
|= ISC_RET_INTEGRITY
;
1151 if (ctx
->flags
& FLAG_NEGOTIATE_SEAL
) flags
->Flags
|= ISC_RET_CONFIDENTIALITY
;
1154 case SECPKG_ATTR_SIZES
:
1156 SecPkgContext_Sizes
*sizes
= (SecPkgContext_Sizes
*)buf
;
1157 sizes
->cbMaxToken
= NTLM_MAX_BUF
;
1158 sizes
->cbMaxSignature
= 16;
1159 sizes
->cbBlockSize
= 0;
1160 sizes
->cbSecurityTrailer
= 16;
1163 case SECPKG_ATTR_NEGOTIATION_INFO
:
1165 SecPkgContext_NegotiationInfoW
*info
= (SecPkgContext_NegotiationInfoW
*)buf
;
1166 if (!(info
->PackageInfo
= build_package_info( &ntlm_package_info
))) return SEC_E_INSUFFICIENT_MEMORY
;
1167 info
->NegotiationState
= SECPKG_NEGOTIATION_COMPLETE
;
1170 case SECPKG_ATTR_KEY_INFO
:
1172 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1173 SecPkgContext_KeyInfoW
*info
= (SecPkgContext_KeyInfoW
*)buf
;
1174 SEC_WCHAR
*signature_alg
;
1175 ULONG signature_size
, signature_algid
;
1177 if (ctx
->flags
& FLAG_NEGOTIATE_KEY_EXCHANGE
)
1179 signature_alg
= (SEC_WCHAR
*)L
"HMAC-MD5";
1180 signature_size
= sizeof(L
"HMAC-MD5");
1181 signature_algid
= 0xffffff76;
1185 signature_alg
= (SEC_WCHAR
*)L
"RSADSI RC4-CRC32";
1186 signature_size
= sizeof(L
"RSADSI RC4-CRC32");
1187 signature_algid
= 0xffffff7c;
1190 if (!(info
->sSignatureAlgorithmName
= RtlAllocateHeap( GetProcessHeap(), 0, signature_size
)))
1191 return SEC_E_INSUFFICIENT_MEMORY
;
1192 wcscpy( info
->sSignatureAlgorithmName
, signature_alg
);
1194 if (!(info
->sEncryptAlgorithmName
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(L
"RSADSI RC4") )))
1196 RtlFreeHeap( GetProcessHeap(), 0, info
->sSignatureAlgorithmName
);
1197 return SEC_E_INSUFFICIENT_MEMORY
;
1199 wcscpy( info
->sEncryptAlgorithmName
, L
"RSADSI RC4" );
1201 info
->KeySize
= sizeof(ctx
->session_key
) * 8;
1202 info
->SignatureAlgorithm
= signature_algid
;
1203 info
->EncryptAlgorithm
= CALG_RC4
;
1208 FIXME( "unknown attribute %lu\n", attr
);
1212 return SEC_E_UNSUPPORTED_FUNCTION
;
1215 static SECPKG_FUNCTION_TABLE ntlm_table
=
1217 ntlm_LsaApInitializePackage
,
1218 NULL
, /* LsaLogonUser */
1219 NULL
, /* CallPackage */
1220 NULL
, /* LogonTerminated */
1221 NULL
, /* CallPackageUntrusted */
1222 NULL
, /* CallPackagePassthrough */
1223 NULL
, /* LogonUserEx */
1224 NULL
, /* LogonUserEx2 */
1226 NULL
, /* SpShutdown */
1228 NULL
, /* AcceptCredentials */
1229 ntlm_SpAcquireCredentialsHandle
,
1230 NULL
, /* SpQueryCredentialsAttributes */
1231 ntlm_SpFreeCredentialsHandle
,
1232 NULL
, /* SaveCredentials */
1233 NULL
, /* GetCredentials */
1234 NULL
, /* DeleteCredentials */
1235 ntlm_SpInitLsaModeContext
,
1236 ntlm_SpAcceptLsaModeContext
,
1237 ntlm_SpDeleteContext
,
1238 NULL
, /* ApplyControlToken */
1239 NULL
, /* GetUserInfo */
1240 NULL
, /* GetExtendedInformation */
1241 ntlm_SpQueryContextAttributes
,
1242 NULL
, /* SpAddCredentials */
1243 NULL
, /* SetExtendedInformation */
1244 NULL
, /* SetContextAttributes */
1245 NULL
, /* SetCredentialsAttributes */
1246 NULL
, /* ChangeAccountPassword */
1247 NULL
, /* QueryMetaData */
1248 NULL
, /* ExchangeMetaData */
1249 NULL
, /* GetCredUIContext */
1250 NULL
, /* UpdateCredentials */
1251 NULL
, /* ValidateTargetInfo */
1252 NULL
, /* PostLogonUser */
1255 NTSTATUS NTAPI
SpLsaModeInitialize( ULONG lsa_version
, ULONG
*package_version
, SECPKG_FUNCTION_TABLE
**table
,
1256 ULONG
*table_count
)
1258 TRACE( "%#lx, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
1260 *package_version
= SECPKG_INTERFACE_VERSION
;
1261 *table
= &ntlm_table
;
1263 return STATUS_SUCCESS
;
1266 static NTSTATUS NTAPI
ntlm_SpInstanceInit( ULONG version
, SECPKG_DLL_FUNCTIONS
*dll_functions
, void **user_functions
)
1268 TRACE( "%#lx, %p, %p\n", version
, dll_functions
, user_functions
);
1269 return STATUS_SUCCESS
;
1275 char outer_padding
[64];
1278 static void hmac_md5_init( struct hmac_md5_ctx
*ctx
, const char *key
, unsigned int key_len
)
1280 char inner_padding
[64], tmp_key
[16];
1285 struct md5_ctx tmp_ctx
;
1287 MD5Init( &tmp_ctx
);
1288 MD5Update( &tmp_ctx
, key
, key_len
);
1289 MD5Final( &tmp_ctx
);
1290 memcpy( tmp_key
, tmp_ctx
.digest
, 16 );
1296 memset( inner_padding
, 0, 64 );
1297 memset( ctx
->outer_padding
, 0, 64 );
1298 memcpy( inner_padding
, key
, key_len
);
1299 memcpy( ctx
->outer_padding
, key
, key_len
);
1301 for (i
= 0; i
< 64; i
++)
1303 inner_padding
[i
] ^= 0x36;
1304 ctx
->outer_padding
[i
] ^= 0x5c;
1307 MD5Init( &ctx
->ctx
);
1308 MD5Update( &ctx
->ctx
, inner_padding
, 64 );
1311 static void hmac_md5_update( struct hmac_md5_ctx
*ctx
, const char *buf
, unsigned int len
)
1313 MD5Update( &ctx
->ctx
, buf
, len
);
1316 static void hmac_md5_final( struct hmac_md5_ctx
*ctx
, char *digest
)
1318 struct md5_ctx outer_ctx
;
1319 char inner_digest
[16];
1321 MD5Final( &ctx
->ctx
);
1322 memcpy( inner_digest
, ctx
->ctx
.digest
, 16 );
1324 MD5Init( &outer_ctx
);
1325 MD5Update( &outer_ctx
, ctx
->outer_padding
, 64 );
1326 MD5Update( &outer_ctx
, inner_digest
, 16 );
1327 MD5Final( &outer_ctx
);
1329 memcpy( digest
, outer_ctx
.digest
, 16 );
1332 static SECURITY_STATUS
create_signature( struct ntlm_ctx
*ctx
, unsigned int flags
, SecBufferDesc
*msg
, int idx
,
1333 enum sign_direction dir
, BOOL encrypt
)
1335 unsigned int i
, sign_version
= 1;
1336 char *sig
= msg
->pBuffers
[idx
].pvBuffer
;
1338 if (flags
& FLAG_NEGOTIATE_NTLM2
&& flags
& FLAG_NEGOTIATE_SIGN
)
1340 char digest
[16], seq_no
[4];
1341 struct hmac_md5_ctx hmac_md5
;
1343 if (dir
== SIGN_SEND
)
1345 seq_no
[0] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 0) & 0xff;
1346 seq_no
[1] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 8) & 0xff;
1347 seq_no
[2] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 16) & 0xff;
1348 seq_no
[3] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 24) & 0xff;
1349 ctx
->crypt
.ntlm2
.send_seq_no
++;
1351 hmac_md5_init( &hmac_md5
, ctx
->crypt
.ntlm2
.send_sign_key
, 16 );
1355 seq_no
[0] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 0) & 0xff;
1356 seq_no
[1] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 8) & 0xff;
1357 seq_no
[2] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 16) & 0xff;
1358 seq_no
[3] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 24) & 0xff;
1359 ctx
->crypt
.ntlm2
.recv_seq_no
++;
1361 hmac_md5_init( &hmac_md5
, ctx
->crypt
.ntlm2
.recv_sign_key
, 16 );
1364 hmac_md5_update( &hmac_md5
, seq_no
, 4 );
1365 for (i
= 0; i
< msg
->cBuffers
; ++i
)
1367 if (msg
->pBuffers
[i
].BufferType
& SECBUFFER_DATA
)
1368 hmac_md5_update( &hmac_md5
, msg
->pBuffers
[i
].pvBuffer
, msg
->pBuffers
[i
].cbBuffer
);
1370 hmac_md5_final( &hmac_md5
, digest
);
1372 if (encrypt
&& flags
& FLAG_NEGOTIATE_KEY_EXCHANGE
)
1374 if (dir
== SIGN_SEND
)
1375 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, digest
, 8 );
1377 arc4_process( &ctx
->crypt
.ntlm2
.recv_arc4info
, digest
, 8 );
1380 sig
[0] = (sign_version
>> 0) & 0xff;
1381 sig
[1] = (sign_version
>> 8) & 0xff;
1382 sig
[2] = (sign_version
>> 16) & 0xff;
1383 sig
[3] = (sign_version
>> 24) & 0xff;
1384 memcpy( sig
+ 4, digest
, 8 );
1385 memcpy( sig
+ 12, seq_no
, 4 );
1387 msg
->pBuffers
[idx
].cbBuffer
= 16;
1391 if (flags
& FLAG_NEGOTIATE_SIGN
)
1393 unsigned int crc
= 0;
1395 for (i
= 0; i
< msg
->cBuffers
; ++i
)
1397 if (msg
->pBuffers
[i
].BufferType
& SECBUFFER_DATA
)
1398 crc
= RtlComputeCrc32( crc
, msg
->pBuffers
[i
].pvBuffer
, msg
->pBuffers
[i
].cbBuffer
);
1401 sig
[0] = (sign_version
>> 0) & 0xff;
1402 sig
[1] = (sign_version
>> 8) & 0xff;
1403 sig
[2] = (sign_version
>> 16) & 0xff;
1404 sig
[3] = (sign_version
>> 24) & 0xff;
1405 memset( sig
+ 4, 0, 4 );
1406 sig
[8] = (crc
>> 0) & 0xff;
1407 sig
[9] = (crc
>> 8) & 0xff;
1408 sig
[10] = (crc
>> 16) & 0xff;
1409 sig
[11] = (crc
>> 24) & 0xff;
1410 sig
[12] = (ctx
->crypt
.ntlm
.seq_no
>> 0) & 0xff;
1411 sig
[13] = (ctx
->crypt
.ntlm
.seq_no
>> 8) & 0xff;
1412 sig
[14] = (ctx
->crypt
.ntlm
.seq_no
>> 16) & 0xff;
1413 sig
[15] = (ctx
->crypt
.ntlm
.seq_no
>> 24) & 0xff;
1414 ctx
->crypt
.ntlm
.seq_no
++;
1416 if (encrypt
) arc4_process( &ctx
->crypt
.ntlm
.arc4info
, sig
+ 4, 12 );
1420 if (flags
& FLAG_NEGOTIATE_ALWAYS_SIGN
|| !flags
)
1422 /* create dummy signature */
1423 memset( msg
->pBuffers
[idx
].pvBuffer
, 0, 16 );
1424 memset( msg
->pBuffers
[idx
].pvBuffer
, 1, 1 );
1425 msg
->pBuffers
[idx
].cbBuffer
= 16;
1429 return SEC_E_UNSUPPORTED_FUNCTION
;
1432 static NTSTATUS NTAPI
ntlm_SpMakeSignature( LSA_SEC_HANDLE handle
, ULONG qop
, SecBufferDesc
*msg
, ULONG msg_seq_no
)
1434 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1437 TRACE( "%#Ix, %#lx, %p, %lu\n", handle
, qop
, msg
, msg_seq_no
);
1438 if (qop
) FIXME( "ignoring quality of protection %#lx\n", qop
);
1439 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1441 if (!handle
) return SEC_E_INVALID_HANDLE
;
1442 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 || (idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1)
1443 return SEC_E_INVALID_TOKEN
;
1444 if (msg
->pBuffers
[idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1446 return create_signature( ctx
, ctx
->flags
, msg
, idx
, SIGN_SEND
, TRUE
);
1449 static NTSTATUS
verify_signature( struct ntlm_ctx
*ctx
, unsigned int flags
, SecBufferDesc
*msg
, int idx
)
1457 if (!(buf
= malloc( msg
->cBuffers
* sizeof(*buf
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
1458 desc
.ulVersion
= SECBUFFER_VERSION
;
1459 desc
.cBuffers
= msg
->cBuffers
;
1460 desc
.pBuffers
= buf
;
1462 for (i
= 0; i
< msg
->cBuffers
; i
++)
1464 if (msg
->pBuffers
[i
].BufferType
== SECBUFFER_TOKEN
)
1466 buf
[i
].BufferType
= SECBUFFER_TOKEN
;
1467 buf
[i
].cbBuffer
= 16;
1468 buf
[i
].pvBuffer
= sig
;
1472 buf
[i
].BufferType
= msg
->pBuffers
[i
].BufferType
;
1473 buf
[i
].cbBuffer
= msg
->pBuffers
[i
].cbBuffer
;
1474 buf
[i
].pvBuffer
= msg
->pBuffers
[i
].pvBuffer
;
1478 if ((status
= create_signature( ctx
, flags
, &desc
, idx
, SIGN_RECV
, TRUE
)) == SEC_E_OK
)
1480 if (memcmp( (char *)buf
[idx
].pvBuffer
+ 8, (char *)msg
->pBuffers
[idx
].pvBuffer
+ 8, 8 ))
1481 status
= SEC_E_MESSAGE_ALTERED
;
1488 static NTSTATUS NTAPI
ntlm_SpVerifySignature( LSA_SEC_HANDLE handle
, SecBufferDesc
*msg
, ULONG msg_seq_no
, ULONG
*qop
)
1490 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1493 TRACE( "%#Ix, %p, %lu, %p\n", handle
, msg
, msg_seq_no
, qop
);
1494 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1496 if (!handle
) return SEC_E_INVALID_HANDLE
;
1497 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 || (idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1)
1498 return SEC_E_INVALID_TOKEN
;
1499 if (msg
->pBuffers
[idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1501 return verify_signature( ctx
, ctx
->flags
, msg
, idx
);
1504 static NTSTATUS NTAPI
ntlm_SpSealMessage( LSA_SEC_HANDLE handle
, ULONG qop
, SecBufferDesc
*msg
, ULONG msg_seq_no
)
1506 int token_idx
, data_idx
;
1507 struct ntlm_ctx
*ctx
;
1509 TRACE( "%#Ix, %#lx, %p %lu\n", handle
, qop
, msg
, msg_seq_no
);
1510 if (qop
) FIXME( "ignoring quality of protection %#lx\n", qop
);
1511 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1513 if (!handle
) return SEC_E_INVALID_HANDLE
;
1515 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 ||
1516 (token_idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1 ||
1517 (data_idx
= get_buffer_index( msg
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1519 if (msg
->pBuffers
[token_idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1521 ctx
= (struct ntlm_ctx
*)handle
;
1522 if (ctx
->flags
& FLAG_NEGOTIATE_NTLM2
&& ctx
->flags
& FLAG_NEGOTIATE_SEAL
)
1524 create_signature( ctx
, ctx
->flags
, msg
, token_idx
, SIGN_SEND
, FALSE
);
1526 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1527 msg
->pBuffers
[data_idx
].cbBuffer
);
1528 if (ctx
->flags
& FLAG_NEGOTIATE_KEY_EXCHANGE
)
1529 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, (char *)msg
->pBuffers
[token_idx
].pvBuffer
+ 4, 8 );
1533 char *sig
= msg
->pBuffers
[token_idx
].pvBuffer
;
1535 create_signature( ctx
, ctx
->flags
| FLAG_NEGOTIATE_SIGN
, msg
, token_idx
, SIGN_SEND
, FALSE
);
1537 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
, msg
->pBuffers
[data_idx
].cbBuffer
);
1538 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, sig
+ 4, 12 );
1540 if (ctx
->flags
& FLAG_NEGOTIATE_ALWAYS_SIGN
|| !ctx
->flags
) memset( sig
+ 4, 0, 4 );
1546 static NTSTATUS NTAPI
ntlm_SpUnsealMessage( LSA_SEC_HANDLE handle
, SecBufferDesc
*msg
, ULONG msg_seq_no
, ULONG
*qop
)
1548 int token_idx
, data_idx
;
1549 struct ntlm_ctx
*ctx
;
1551 TRACE( "%#Ix, %p, %lu, %p\n", handle
, msg
, msg_seq_no
, qop
);
1552 if (msg_seq_no
) FIXME( "ignoring message sequence number %lu\n", msg_seq_no
);
1554 if (!handle
) return SEC_E_INVALID_HANDLE
;
1556 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 ||
1557 (token_idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1 ||
1558 (data_idx
= get_buffer_index( msg
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1560 if (msg
->pBuffers
[token_idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1562 ctx
= (struct ntlm_ctx
*)handle
;
1563 if (ctx
->flags
& FLAG_NEGOTIATE_NTLM2
&& ctx
->flags
& FLAG_NEGOTIATE_SEAL
)
1564 arc4_process( &ctx
->crypt
.ntlm2
.recv_arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1565 msg
->pBuffers
[data_idx
].cbBuffer
);
1567 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1568 msg
->pBuffers
[data_idx
].cbBuffer
);
1570 /* make sure we use a session key for the signature check, SealMessage always does that,
1571 even in the dummy case */
1572 return verify_signature( ctx
, ctx
->flags
| FLAG_NEGOTIATE_SIGN
, msg
, token_idx
);
1575 static SECPKG_USER_FUNCTION_TABLE ntlm_user_table
=
1577 ntlm_SpInstanceInit
,
1578 NULL
, /* SpInitUserModeContext */
1579 ntlm_SpMakeSignature
,
1580 ntlm_SpVerifySignature
,
1582 ntlm_SpUnsealMessage
,
1583 NULL
, /* SpGetContextToken */
1584 NULL
, /* SpQueryContextAttributes */
1585 NULL
, /* SpCompleteAuthToken */
1586 NULL
, /* SpDeleteContext */
1587 NULL
, /* SpFormatCredentialsFn */
1588 NULL
, /* SpMarshallSupplementalCreds */
1589 NULL
, /* SpExportSecurityContext */
1590 NULL
/* SpImportSecurityContext */
1593 NTSTATUS NTAPI
SpUserModeInitialize( ULONG lsa_version
, ULONG
*package_version
, SECPKG_USER_FUNCTION_TABLE
**table
,
1594 ULONG
*table_count
)
1596 TRACE( "%#lx, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
1598 *package_version
= SECPKG_INTERFACE_VERSION
;
1599 *table
= &ntlm_user_table
;
1601 return STATUS_SUCCESS
;
1604 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, void *reserved
)
1608 case DLL_PROCESS_ATTACH
:
1609 if (__wine_init_unix_call())
1611 DisableThreadLibraryCalls( hinst
);