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 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
, ¶ms
);
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
, ¶ms
);
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 \
82 | SECPKG_FLAG_RESTRICTED_TOKENS )
84 #define NTLM_MAX_BUF 1904
86 static const SecPkgInfoW ntlm_package_info
=
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
)
115 TRACE( "%#lx, %p, %s, %s, %p\n", package_id
, dispatch
, debugstr_as(database
), debugstr_as(confidentiality
),
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
;
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
);
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
);
171 static char *get_domain_arg( const WCHAR
*domain
, int domain_len
)
173 static const char arg
[] = "--domain=";
174 int len
= sizeof(arg
);
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
);
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
;
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
);
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
);
251 domain_len
= id
->DomainLength
;
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
);
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
;
277 case SECPKG_CRED_BOTH
:
278 FIXME( "SECPKG_CRED_BOTH not supported\n" );
279 status
= SEC_E_UNSUPPORTED_FUNCTION
;
283 status
= SEC_E_UNKNOWN_CREDENTIALS
;
288 if (id
&& (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
))
294 if (status
!= SEC_E_OK
) free( cred
);
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
);
315 static BOOL
get_cached_credential( const UNICODE_STRING
*target
, CREDENTIALW
**cred
)
317 const WCHAR
*ptr
, *host
;
322 if (!target
) return FALSE
;
324 len
= target
->Length
/ sizeof(WCHAR
);
325 if ((host
= wmemchr( target
->Buffer
, '/', len
)))
328 len
-= host
- target
->Buffer
;
329 if (!(ptr
= wmemchr( host
, ':', len
))) ptr
= wmemchr( host
, '/', len
);
330 if (!ptr
) ptr
= host
+ len
;
334 host
= target
->Buffer
;
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
);
347 static UINT
encode_base64( const char *bin
, unsigned int len
, char *base64
)
349 static const char base64enc
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
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] */
361 base64
[n
++] = base64enc
[x
];
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] */
372 base64
[n
++] = base64enc
[x
];
376 base64
[n
++] = base64enc
[x
| ((bin
[2] & 0xc0) >> 6)];
378 /* last 6 bits, all from bin[2] */
379 base64
[n
++] = base64enc
[bin
[2] & 0x3f];
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;
397 static unsigned int decode_base64( const char *base64
, unsigned int len
, char *buf
)
401 const char *p
= base64
;
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;
411 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
412 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
413 buf
[i
+ 2] = (c2
<< 6) | c3
;
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);
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;
433 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
434 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
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;
446 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
447 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
448 buf
[i
+ 2] = (c2
<< 6) | c3
;
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
)
473 MD4Update( &ctx
, secret
, len
);
475 memcpy( hash
, ctx
.digest
, 16 );
478 MD4Update( &ctx
, hash
, 16 );
480 memcpy( session_key
, ctx
.digest
, 16 );
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
)
500 MD5Update( &ctx
, session_key
, 16 );
501 MD5Update( &ctx
, magic
, strlen(magic
) + 1 );
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
);
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
++)
543 state_idx
+= key
[key_idx
] + a
;
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
;
564 *buf
++ ^= state
[(a
+ b
) & 0xff];
571 static int get_buffer_index( SecBufferDesc
*desc
, ULONG type
)
574 for (idx
= 0; idx
< desc
->cBuffers
; idx
++)
576 if (desc
->pBuffers
[idx
].BufferType
== type
) return idx
;
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
;
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
)
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
;
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
;
629 if (get_cached_credential( target
, &cached
))
632 if ((p
= wcschr( cached
->UserName
, '\\' )))
634 if (!(domain
= get_domain_arg( cached
->UserName
, p
- cached
->UserName
))) goto done
;
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
);
660 ret
= NetWkstaUserGetInfo( NULL
, 1, (BYTE
**)&ui
);
661 if (ret
!= NERR_Success
|| !ui
|| cred
->no_cached_credentials
)
663 status
= SEC_E_NO_CREDENTIALS
;
666 if (!(username
= get_username_arg( ui
->wkui1_username
, -1 ))) goto done
;
667 NetApiBufferFree( ui
);
668 TRACE("using cached credentials\n");
671 argv
[3] = (char *)"--use-cached-creds";
677 argv
[2] = cred
->username_arg
;
678 argv
[3] = cred
->domain_arg
;
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
)
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
);
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
)
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 */
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" );
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
;
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
;
773 ctx
= (struct ntlm_ctx
*)ctx_handle
;
774 if (!ctx
|| ctx
->mode
!= MODE_CLIENT
)
776 status
= SEC_E_INVALID_HANDLE
;
780 if (!input
->pBuffers
[idx
].pvBuffer
|| input
->pBuffers
[idx
].cbBuffer
> NTLM_MAX_BUF
)
782 status
= SEC_E_INVALID_TOKEN
;
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
;
800 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
802 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
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
;
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
;
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
;
830 if (!output
->pBuffers
[idx
].pvBuffer
)
832 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
833 status
= SEC_E_INTERNAL_ERROR
;
837 output
->pBuffers
[idx
].cbBuffer
= bin_len
;
838 memcpy( output
->pBuffers
[idx
].pvBuffer
, bin
, bin_len
);
839 if (status
== SEC_E_OK
)
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
);
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;
867 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
)
879 TRACE( "returning %#lx\n", 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
;
903 struct ntlm_cred
*cred
= (struct ntlm_cred
*)cred_handle
;
906 if (!cred
|| cred
->mode
!= MODE_SERVER
)
908 status
= SEC_E_INVALID_HANDLE
;
912 if (!input
|| input
->cBuffers
< 1)
914 status
= SEC_E_INCOMPLETE_MESSAGE
;
918 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
920 status
= SEC_E_INVALID_TOKEN
;
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";
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
;
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
;
972 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
974 if (!output
|| output
->cBuffers
< 1)
976 status
= SEC_E_INSUFFICIENT_MEMORY
;
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
;
988 if (!input
|| input
->cBuffers
< 1)
990 status
= SEC_E_INCOMPLETE_MESSAGE
;
994 ctx
= (struct ntlm_ctx
*)ctx_handle
;
995 if (!ctx
|| ctx
->mode
!= MODE_SERVER
)
997 status
= SEC_E_INVALID_HANDLE
;
1001 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
1003 status
= SEC_E_INVALID_TOKEN
;
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
;
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
;
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 );
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
;
1083 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
)
1085 ntlm_cleanup( ctx
);
1092 TRACE( "returning %#lx\n", 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
);
1108 static SecPkgInfoW
*build_package_info( const SecPkgInfoW
*info
)
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
);
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
;
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
;
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
;
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;
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
;
1210 FIXME( "unknown attribute %lu\n", attr
);
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 */
1228 NULL
, /* SpShutdown */
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
;
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
;
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];
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 );
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 );
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 );
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;
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 );
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;
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
;
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
)
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
;
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
;
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
;
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 );
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 );
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
);
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
,
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
;
1603 return STATUS_SUCCESS
;
1606 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, void *reserved
)
1610 case DLL_PROCESS_ATTACH
:
1611 if (NtQueryVirtualMemory( GetCurrentProcess(), hinst
, MemoryWineUnixFuncs
,
1612 &ntlm_handle
, sizeof(ntlm_handle
), NULL
))
1614 DisableThreadLibraryCalls( hinst
);