2 * Copyright 2005, 2006 Kai Blin
3 * Copyright 2021 Hans Leidekker for CodeWeavers
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define WIN32_NO_STATUS
37 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(ntlm
);
42 static HINSTANCE instance
;
43 static ULONG ntlm_package_id
;
44 static LSA_DISPATCH_TABLE lsa_dispatch
;
46 const struct ntlm_funcs
*ntlm_funcs
= NULL
;
49 ( SECPKG_FLAG_INTEGRITY \
50 | SECPKG_FLAG_PRIVACY \
51 | SECPKG_FLAG_TOKEN_ONLY \
52 | SECPKG_FLAG_CONNECTION \
53 | SECPKG_FLAG_MULTI_REQUIRED \
54 | SECPKG_FLAG_IMPERSONATION \
55 | SECPKG_FLAG_ACCEPT_WIN32_NAME \
56 | SECPKG_FLAG_NEGOTIABLE \
58 | SECPKG_FLAG_RESTRICTED_TOKENS )
60 #define NTLM_MAX_BUF 1904
62 static const SecPkgInfoW ntlm_package_info
=
69 (SEC_WCHAR
*)L
"NTLM Security Package"
72 static inline const char *debugstr_as( const STRING
*str
)
74 if (!str
) return "<null>";
75 return debugstr_an( str
->Buffer
, str
->Length
);
78 static inline const char *debugstr_us( const UNICODE_STRING
*str
)
80 if (!str
) return "<null>";
81 return debugstr_wn( str
->Buffer
, str
->Length
/ sizeof(WCHAR
) );
84 static NTSTATUS NTAPI
ntlm_LsaApInitializePackage( ULONG package_id
, LSA_DISPATCH_TABLE
*dispatch
,
85 LSA_STRING
*database
, LSA_STRING
*confidentiality
,
86 LSA_STRING
**package_name
)
91 TRACE( "%08x, %p, %s, %s, %p\n", package_id
, dispatch
, debugstr_as(database
), debugstr_as(confidentiality
),
94 if (!ntlm_funcs
&& __wine_init_unix_lib( instance
, DLL_PROCESS_ATTACH
, NULL
, &ntlm_funcs
))
96 ERR( "no NTLM support, expect problems\n" );
97 return STATUS_UNSUCCESSFUL
;
100 if (!(str
= dispatch
->AllocateLsaHeap( sizeof(*str
) + sizeof("NTLM" )))) return STATUS_NO_MEMORY
;
101 ptr
= (char *)(str
+ 1);
102 memcpy( ptr
, "NTLM", sizeof("NTLM") );
103 RtlInitString( str
, ptr
);
105 ntlm_package_id
= package_id
;
106 lsa_dispatch
= *dispatch
;
109 return STATUS_SUCCESS
;
112 static NTSTATUS NTAPI
ntlm_SpInitialize( ULONG_PTR package_id
, SECPKG_PARAMETERS
*params
,
113 LSA_SECPKG_FUNCTION_TABLE
*lsa_function_table
)
115 TRACE( "%lu, %p, %p\n", package_id
, params
, lsa_function_table
);
117 if (!ntlm_funcs
&& __wine_init_unix_lib( instance
, DLL_PROCESS_ATTACH
, NULL
, &ntlm_funcs
))
119 ERR( "no NTLM support, expect problems\n" );
120 return STATUS_UNSUCCESSFUL
;
122 return STATUS_SUCCESS
;
125 static NTSTATUS NTAPI
ntlm_SpGetInfo( SecPkgInfoW
*info
)
127 TRACE( "%p\n", info
);
128 *info
= ntlm_package_info
;
129 return STATUS_SUCCESS
;
132 static char *get_username_arg( const WCHAR
*user
, int user_len
)
134 static const char arg
[] = "--username=";
135 int len
= sizeof(arg
);
138 len
+= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, user
, user_len
, NULL
, 0, NULL
, NULL
);
139 if (!(ret
= malloc( len
))) return NULL
;
140 memcpy( ret
, arg
, sizeof(arg
) - 1 );
141 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, user
, user_len
, ret
+ sizeof(arg
) - 1,
142 len
- sizeof(arg
) + 1, NULL
, NULL
);
147 static char *get_domain_arg( const WCHAR
*domain
, int domain_len
)
149 static const char arg
[] = "--domain=";
150 int len
= sizeof(arg
);
153 len
+= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, domain
, domain_len
, NULL
, 0, NULL
, NULL
);
154 if (!(ret
= malloc( len
))) return NULL
;
155 memcpy( ret
, arg
, sizeof(arg
) - 1 );
156 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, domain
, domain_len
, ret
+ sizeof(arg
) - 1,
157 len
- sizeof(arg
) + 1, NULL
, NULL
);
162 #define WINE_NO_CACHED_CREDENTIALS 0x10000000
163 static NTSTATUS NTAPI
ntlm_SpAcquireCredentialsHandle( UNICODE_STRING
*principal
, ULONG cred_use
, LUID
*logon_id
,
164 void *auth_data
, void *get_key_fn
, void *get_key_arg
,
165 LSA_SEC_HANDLE
*handle
, TimeStamp
*expiry
)
167 SECURITY_STATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
168 struct ntlm_cred
*cred
= NULL
;
169 WCHAR
*domain
= NULL
, *user
= NULL
, *password
= NULL
;
170 SEC_WINNT_AUTH_IDENTITY_W
*id
= NULL
;
172 TRACE( "%s, 0x%08x, %p, %p, %p, %p, %p, %p\n", debugstr_us(principal
), cred_use
, logon_id
, auth_data
,
173 get_key_fn
, get_key_arg
, cred
, expiry
);
175 switch (cred_use
& ~SECPKG_CRED_RESERVED
)
177 case SECPKG_CRED_INBOUND
:
178 if (!(cred
= malloc( sizeof(*cred
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
179 cred
->mode
= MODE_SERVER
;
180 cred
->username_arg
= NULL
;
181 cred
->domain_arg
= NULL
;
182 cred
->password
= NULL
;
183 cred
->password_len
= 0;
184 cred
->no_cached_credentials
= 0;
186 *handle
= (LSA_SEC_HANDLE
)cred
;
190 case SECPKG_CRED_OUTBOUND
:
191 if (!(cred
= malloc( sizeof(*cred
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
193 cred
->mode
= MODE_CLIENT
;
194 cred
->username_arg
= NULL
;
195 cred
->domain_arg
= NULL
;
196 cred
->password
= NULL
;
197 cred
->password_len
= 0;
198 cred
->no_cached_credentials
= (cred_use
& WINE_NO_CACHED_CREDENTIALS
);
200 if ((id
= auth_data
))
202 int domain_len
= 0, user_len
= 0, password_len
= 0;
203 if (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
)
205 if (id
->DomainLength
)
207 domain_len
= MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Domain
, id
->DomainLength
, NULL
, 0 );
208 if (!(domain
= malloc( sizeof(WCHAR
) * domain_len
))) goto done
;
209 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Domain
, id
->DomainLength
, domain
, domain_len
);
213 user_len
= MultiByteToWideChar( CP_ACP
, 0, (char *)id
->User
, id
->UserLength
, NULL
, 0 );
214 if (!(user
= malloc( sizeof(WCHAR
) * user_len
))) goto done
;
215 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->User
, id
->UserLength
, user
, user_len
);
217 if (id
->PasswordLength
)
219 password_len
= MultiByteToWideChar( CP_ACP
, 0,(char *)id
->Password
, id
->PasswordLength
, NULL
, 0 );
220 if (!(password
= malloc( sizeof(WCHAR
) * password_len
))) goto done
;
221 MultiByteToWideChar( CP_ACP
, 0, (char *)id
->Password
, id
->PasswordLength
, password
, password_len
);
227 domain_len
= id
->DomainLength
;
229 user_len
= id
->UserLength
;
230 password
= id
->Password
;
231 password_len
= id
->PasswordLength
;
234 TRACE( "username is %s\n", debugstr_wn(user
, user_len
) );
235 TRACE( "domain name is %s\n", debugstr_wn(domain
, domain_len
) );
237 cred
->username_arg
= get_username_arg( user
, user_len
);
238 cred
->domain_arg
= get_domain_arg( domain
, domain_len
);
241 cred
->password_len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, password
, password_len
,
242 NULL
, 0, NULL
, NULL
);
243 if (!(cred
->password
= malloc( cred
->password_len
))) goto done
;
244 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, password
, password_len
, cred
->password
,
245 cred
->password_len
, NULL
, NULL
);
249 *handle
= (LSA_SEC_HANDLE
)cred
;
253 case SECPKG_CRED_BOTH
:
254 FIXME( "SECPKG_CRED_BOTH not supported\n" );
255 status
= SEC_E_UNSUPPORTED_FUNCTION
;
259 status
= SEC_E_UNKNOWN_CREDENTIALS
;
264 if (id
&& (id
->Flags
& SEC_WINNT_AUTH_IDENTITY_ANSI
))
270 if (status
!= SEC_E_OK
) free( cred
);
274 static NTSTATUS NTAPI
ntlm_SpFreeCredentialsHandle( LSA_SEC_HANDLE handle
)
276 struct ntlm_cred
*cred
= (struct ntlm_cred
*)handle
;
278 TRACE( "%lx\n", handle
);
280 if (!cred
) return SEC_E_OK
;
282 cred
->mode
= MODE_INVALID
;
283 if (cred
->password
) memset( cred
->password
, 0, cred
->password_len
);
284 free( cred
->password
);
285 free( cred
->username_arg
);
286 free( cred
->domain_arg
);
291 static BOOL
get_cached_credential( const UNICODE_STRING
*target
, CREDENTIALW
**cred
)
293 const WCHAR
*ptr
, *host
;
298 if (!target
) return FALSE
;
300 len
= target
->Length
/ sizeof(WCHAR
);
301 if ((host
= wmemchr( target
->Buffer
, '/', len
)))
304 len
-= host
- target
->Buffer
;
305 if (!(ptr
= wmemchr( host
, ':', len
))) ptr
= wmemchr( host
, '/', len
);
306 if (!ptr
) ptr
= host
+ len
;
310 host
= target
->Buffer
;
314 if (!(hostonly
= malloc( (ptr
- host
+ 1) * sizeof(WCHAR
) ))) return FALSE
;
315 memcpy( hostonly
, host
, (ptr
- host
) * sizeof(WCHAR
) );
316 hostonly
[ptr
- host
] = 0;
318 ret
= CredReadW( hostonly
, CRED_TYPE_DOMAIN_PASSWORD
, 0, cred
);
323 static UINT
encode_base64( const char *bin
, unsigned int len
, char *base64
)
325 static const char base64enc
[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
330 /* first 6 bits, all from bin[0] */
331 base64
[n
++] = base64enc
[(bin
[0] & 0xfc) >> 2];
332 x
= (bin
[0] & 3) << 4;
334 /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
337 base64
[n
++] = base64enc
[x
];
342 base64
[n
++] = base64enc
[x
| ((bin
[1] & 0xf0) >> 4)];
343 x
= (bin
[1] & 0x0f) << 2;
345 /* next 6 bits 4 from bin[1] and 2 from bin[2] */
348 base64
[n
++] = base64enc
[x
];
352 base64
[n
++] = base64enc
[x
| ((bin
[2] & 0xc0) >> 6)];
354 /* last 6 bits, all from bin[2] */
355 base64
[n
++] = base64enc
[bin
[2] & 0x3f];
363 static inline char decode_char( char c
)
365 if (c
>= 'A' && c
<= 'Z') return c
- 'A';
366 if (c
>= 'a' && c
<= 'z') return c
- 'a' + 26;
367 if (c
>= '0' && c
<= '9') return c
- '0' + 52;
368 if (c
== '+') return 62;
369 if (c
== '/') return 63;
373 static unsigned int decode_base64( const char *base64
, unsigned int len
, char *buf
)
377 const char *p
= base64
;
381 if ((c0
= decode_char( p
[0] )) > 63) return 0;
382 if ((c1
= decode_char( p
[1] )) > 63) return 0;
383 if ((c2
= decode_char( p
[2] )) > 63) return 0;
384 if ((c3
= decode_char( p
[3] )) > 63) return 0;
387 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
388 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
389 buf
[i
+ 2] = (c2
<< 6) | c3
;
397 if ((c0
= decode_char( p
[0] )) > 63) return 0;
398 if ((c1
= decode_char( p
[1] )) > 63) return 0;
399 if (buf
) buf
[i
] = (c0
<< 2) | (c1
>> 4);
402 else if (p
[3] == '=')
404 if ((c0
= decode_char( p
[0] )) > 63) return 0;
405 if ((c1
= decode_char( p
[1] )) > 63) return 0;
406 if ((c2
= decode_char( p
[2] )) > 63) return 0;
409 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
410 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
416 if ((c0
= decode_char( p
[0] )) > 63) return 0;
417 if ((c1
= decode_char( p
[1] )) > 63) return 0;
418 if ((c2
= decode_char( p
[2] )) > 63) return 0;
419 if ((c3
= decode_char( p
[3] )) > 63) return 0;
422 buf
[i
+ 0] = (c0
<< 2) | (c1
>> 4);
423 buf
[i
+ 1] = (c1
<< 4) | (c2
>> 2);
424 buf
[i
+ 2] = (c2
<< 6) | c3
;
435 unsigned char in
[64];
436 unsigned char digest
[16];
439 void WINAPI
MD4Init( struct md4_ctx
* );
440 void WINAPI
MD4Update( struct md4_ctx
*, const char *, unsigned int );
441 void WINAPI
MD4Final( struct md4_ctx
* );
443 static void create_ntlm1_session_key( const char *secret
, unsigned int len
, char *session_key
)
449 MD4Update( &ctx
, secret
, len
);
451 memcpy( hash
, ctx
.digest
, 16 );
454 MD4Update( &ctx
, hash
, 16 );
456 memcpy( session_key
, ctx
.digest
, 16 );
463 unsigned char in
[64];
464 unsigned char digest
[16];
467 void WINAPI
MD5Init( struct md5_ctx
* );
468 void WINAPI
MD5Update( struct md5_ctx
*, const char *, unsigned int );
469 void WINAPI
MD5Final( struct md5_ctx
* );
471 static void calc_ntlm2_subkey( const char *session_key
, const char *magic
, char *subkey
)
476 MD5Update( &ctx
, session_key
, 16 );
477 MD5Update( &ctx
, magic
, strlen(magic
) + 1 );
479 memcpy( subkey
, ctx
.digest
, 16 );
482 static const char client_to_server_sign_constant
[] = "session key to client-to-server signing key magic constant";
483 static const char client_to_server_seal_constant
[] = "session key to client-to-server sealing key magic constant";
484 static const char server_to_client_sign_constant
[] = "session key to server-to-client signing key magic constant";
485 static const char server_to_client_seal_constant
[] = "session key to server-to-client sealing key magic constant";
487 static void create_ntlm2_subkeys( struct ntlm_ctx
*ctx
)
489 if (ctx
->mode
== MODE_CLIENT
)
491 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_sign_constant
, ctx
->crypt
.ntlm2
.send_sign_key
);
492 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_seal_constant
, ctx
->crypt
.ntlm2
.send_seal_key
);
493 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_sign_constant
, ctx
->crypt
.ntlm2
.recv_sign_key
);
494 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_seal_constant
, ctx
->crypt
.ntlm2
.recv_seal_key
);
498 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_sign_constant
, ctx
->crypt
.ntlm2
.send_sign_key
);
499 calc_ntlm2_subkey( ctx
->session_key
, server_to_client_seal_constant
, ctx
->crypt
.ntlm2
.send_seal_key
);
500 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_sign_constant
, ctx
->crypt
.ntlm2
.recv_sign_key
);
501 calc_ntlm2_subkey( ctx
->session_key
, client_to_server_seal_constant
, ctx
->crypt
.ntlm2
.recv_seal_key
);
506 * The arc4 code is based on dlls/advapi32/crypt_arc4.c by Mike McCormack,
507 * which in turn is based on public domain code by Wei Dai
509 static void arc4_init( struct arc4_info
*info
, const char *key
, unsigned int len
)
511 unsigned int key_idx
= 0, state_idx
= 0, i
, a
;
513 info
->x
= info
->y
= 0;
514 for (i
= 0; i
< 256; i
++) info
->state
[i
] = i
;
516 for (i
= 0; i
< 256; i
++)
519 state_idx
+= key
[key_idx
] + a
;
521 info
->state
[i
] = info
->state
[state_idx
];
522 info
->state
[state_idx
] = a
;
523 if (++key_idx
>= len
) key_idx
= 0;
527 static void arc4_process( struct arc4_info
*info
, char *buf
, unsigned int len
)
529 char *state
= info
->state
;
530 unsigned int x
= info
->x
, y
= info
->y
, a
, b
;
540 *buf
++ ^= state
[(a
+ b
) & 0xff];
547 static int get_buffer_index( SecBufferDesc
*desc
, ULONG type
)
550 for (idx
= 0; idx
< desc
->cBuffers
; idx
++)
552 if (desc
->pBuffers
[idx
].BufferType
== type
) return idx
;
557 static NTSTATUS NTAPI
ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle
, LSA_SEC_HANDLE ctx_handle
,
558 UNICODE_STRING
*target
, ULONG ctx_req
, ULONG data_rep
,
559 SecBufferDesc
*input
, LSA_SEC_HANDLE
*new_ctx_handle
,
560 SecBufferDesc
*output
, ULONG
*ctx_attr
, TimeStamp
*expiry
,
561 BOOLEAN
*mapped_ctx
, SecBuffer
*ctx_data
)
563 NTSTATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
564 struct ntlm_ctx
*ctx
= NULL
;
565 char *buf
, *bin
, *want_flags
= NULL
, *username
= NULL
, *domain
= NULL
, *password
= NULL
;
566 unsigned int len
, bin_len
;
569 TRACE( "%lx, %lx, %s, 0x%08x, %u, %p, %p, %p, %p, %p, %p, %p\n", cred_handle
, ctx_handle
, debugstr_us(target
),
570 ctx_req
, data_rep
, input
, new_ctx_handle
, output
, ctx_attr
, expiry
, mapped_ctx
, ctx_data
);
572 /* when communicating with the client there can be the following reply packets:
573 * YR <base64 blob> should be sent to the server
574 * PW should be sent back to helper with base64 encoded password
575 * AF <base64 blob> client is done, blob should be sent to server with KK prefixed
576 * GF <string list> a string list of negotiated flags
577 * GK <base64 blob> base64 encoded session key
578 * BH <char reason> something broke
580 * The squid cache size is 2010 chars and that's what ntlm_auth uses */
582 if (!(buf
= malloc( NTLM_MAX_BUF
))) return SEC_E_INSUFFICIENT_MEMORY
;
583 if (!(bin
= malloc( NTLM_MAX_BUF
))) goto done
;
585 if (!ctx_handle
&& !input
)
588 int password_len
= 0;
589 struct ntlm_cred
*cred
= (struct ntlm_cred
*)cred_handle
;
591 if (!cred
|| cred
->mode
!= MODE_CLIENT
)
593 status
= SEC_E_INVALID_HANDLE
;
597 argv
[0] = (char *)"ntlm_auth";
598 argv
[1] = (char *)"--helper-protocol=ntlmssp-client-1";
599 if (!cred
->username_arg
&& !cred
->domain_arg
)
601 WKSTA_USER_INFO_1
*ui
= NULL
;
605 if (get_cached_credential( target
, &cached
))
608 if ((p
= wcschr( cached
->UserName
, '\\' )))
610 if (!(domain
= get_domain_arg( cached
->UserName
, p
- cached
->UserName
))) goto done
;
615 if (!(domain
= get_domain_arg( NULL
, 0 ))) goto done
;
616 p
= cached
->UserName
;
618 if (!(username
= get_username_arg( p
, -1 ))) goto done
;
620 if (cached
->CredentialBlobSize
)
622 password_len
= WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, (WCHAR
*)cached
->CredentialBlob
,
623 cached
->CredentialBlobSize
/ sizeof(WCHAR
), NULL
, 0, NULL
, NULL
);
624 if (!(password
= malloc( password_len
))) goto done
;
625 WideCharToMultiByte( CP_UNIXCP
, WC_NO_BEST_FIT_CHARS
, (WCHAR
*)cached
->CredentialBlob
,
626 cached
->CredentialBlobSize
/ sizeof(WCHAR
), password
, password_len
, NULL
, NULL
);
636 ret
= NetWkstaUserGetInfo( NULL
, 1, (BYTE
**)&ui
);
637 if (ret
!= NERR_Success
|| !ui
|| cred
->no_cached_credentials
)
639 status
= SEC_E_NO_CREDENTIALS
;
642 if (!(username
= get_username_arg( ui
->wkui1_username
, -1 ))) goto done
;
643 NetApiBufferFree( ui
);
644 TRACE("using cached credentials\n");
647 argv
[3] = (char *)"--use-cached-creds";
653 argv
[2] = cred
->username_arg
;
654 argv
[3] = cred
->domain_arg
;
658 if ((status
= ntlm_funcs
->fork( argv
, &ctx
)) != SEC_E_OK
) goto done
;
659 status
= SEC_E_INSUFFICIENT_MEMORY
;
661 ctx
->mode
= MODE_CLIENT
;
662 memset( ctx
->session_key
, 0, sizeof(ctx
->session_key
) );
664 /* generate the dummy session key = MD4(MD4(password))*/
665 if (password
|| cred
->password
)
668 len
= MultiByteToWideChar( CP_ACP
, 0, password
? password
: cred
->password
,
669 password
? password_len
: cred
->password_len
, NULL
, 0 );
670 if (!(passwordW
= malloc( len
* sizeof(WCHAR
) ))) goto done
;
671 MultiByteToWideChar( CP_ACP
, 0, password
? password
: cred
->password
,
672 password
? password_len
: cred
->password_len
, passwordW
, len
);
674 create_ntlm1_session_key( (const char *)passwordW
, len
* sizeof(WCHAR
), ctx
->session_key
);
678 /* allocate space for a maximum string of
679 * "SF NTLMSSP_FEATURE_SIGN NTLMSSP_FEATURE_SEAL NTLMSSP_FEATURE_SESSION_KEY"
681 if (!(want_flags
= malloc( 73 ))) goto done
;
682 strcpy( want_flags
, "SF" );
683 if (ctx_req
& ISC_REQ_CONFIDENTIALITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SEAL" );
684 if ((ctx_req
& ISC_REQ_INTEGRITY
) || (ctx_req
& ISC_REQ_REPLAY_DETECT
) ||
685 (ctx_req
& ISC_REQ_SEQUENCE_DETECT
)) strcat( want_flags
, " NTLMSSP_FEATURE_SIGN" );
687 if (ctx_req
& ISC_REQ_CONNECTION
) ctx
->attrs
|= ISC_RET_CONNECTION
;
688 if (ctx_req
& ISC_REQ_EXTENDED_ERROR
) ctx
->attrs
|= ISC_RET_EXTENDED_ERROR
;
689 if (ctx_req
& ISC_REQ_MUTUAL_AUTH
) ctx
->attrs
|= ISC_RET_MUTUAL_AUTH
;
690 if (ctx_req
& ISC_REQ_USE_DCE_STYLE
) ctx
->attrs
|= ISC_RET_USED_DCE_STYLE
;
691 if (ctx_req
& ISC_REQ_DELEGATE
) ctx
->attrs
|= ISC_RET_DELEGATE
;
692 if (ctx_req
& ISC_REQ_STREAM
) FIXME( "ISC_REQ_STREAM\n" );
694 /* use cached credentials if no password was given, fall back to an empty password on failure */
695 if (!password
&& !cred
->password
)
698 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
700 /* if the helper replied with "PW" using cached credentials failed */
701 if (!strncmp( buf
, "PW", 2 ))
703 TRACE( "using cached credentials failed\n" );
704 strcpy( buf
, "PW AA==" );
706 else strcpy( buf
, "OK" ); /* just do a noop on the next run */
710 strcpy( buf
, "PW " );
711 encode_base64( password
? password
: cred
->password
, password
? password_len
: cred
->password_len
, buf
+ 3 );
714 TRACE( "sending to ntlm_auth: %s\n", debugstr_a(buf
) );
715 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
716 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf
) );
718 if (strlen( want_flags
) > 2)
720 TRACE( "want flags are %s\n", debugstr_a(want_flags
) );
721 strcpy( buf
, want_flags
);
722 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
723 if (!strncmp( buf
, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
727 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
728 TRACE( "ntlm_auth returned %s\n", buf
);
729 if (strncmp( buf
, "YR ", 3 ))
731 status
= SEC_E_INTERNAL_ERROR
;
734 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
736 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
737 status
= SEC_I_CONTINUE_NEEDED
;
739 else /* !ctx_handle && !input */
741 if (!input
|| ((idx
= get_buffer_index( input
, SECBUFFER_TOKEN
)) == -1))
743 status
= SEC_E_INVALID_TOKEN
;
747 ctx
= (struct ntlm_ctx
*)ctx_handle
;
748 if (!ctx
|| ctx
->mode
!= MODE_CLIENT
)
750 status
= SEC_E_INVALID_HANDLE
;
754 if (!input
->pBuffers
[idx
].pvBuffer
|| input
->pBuffers
[idx
].cbBuffer
> NTLM_MAX_BUF
)
756 status
= SEC_E_INVALID_TOKEN
;
759 bin_len
= input
->pBuffers
[idx
].cbBuffer
;
760 memcpy( bin
, input
->pBuffers
[idx
].pvBuffer
, bin_len
);
762 strcpy( buf
, "TT " );
763 encode_base64( bin
, bin_len
, buf
+ 3 );
764 TRACE( "server sent: %s\n", debugstr_a(buf
) );
766 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
))) goto done
;
767 TRACE( "ntlm_auth returned: %s\n", debugstr_a(buf
) );
769 if (strncmp( buf
, "KK ", 3 ) && strncmp( buf
, "AF ", 3 ))
771 status
= SEC_E_INVALID_TOKEN
;
774 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
776 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
780 if (!output
|| ((idx
= get_buffer_index( output
, SECBUFFER_TOKEN
)) == -1))
782 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
783 status
= SEC_E_BUFFER_TOO_SMALL
;
787 if (ctx_req
& ISC_REQ_ALLOCATE_MEMORY
)
789 /* freed with secur32.FreeContextBuffer */
790 if (!(output
->pBuffers
[idx
].pvBuffer
= RtlAllocateHeap( GetProcessHeap(), 0, bin_len
)))
792 status
= SEC_E_INSUFFICIENT_MEMORY
;
795 output
->pBuffers
[idx
].cbBuffer
= bin_len
;
797 else if (output
->pBuffers
[idx
].cbBuffer
< bin_len
)
799 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
800 status
= SEC_E_BUFFER_TOO_SMALL
;
804 if (!output
->pBuffers
[idx
].pvBuffer
)
806 if (!ctx_handle
&& !input
) *new_ctx_handle
= 0;
807 status
= SEC_E_INTERNAL_ERROR
;
811 output
->pBuffers
[idx
].cbBuffer
= bin_len
;
812 memcpy( output
->pBuffers
[idx
].pvBuffer
, bin
, bin_len
);
813 if (status
== SEC_E_OK
)
816 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
817 if (len
< 3) ctx
->flags
= 0;
818 else sscanf( buf
+ 3, "%x", &ctx
->flags
);
821 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
823 if (!strncmp( buf
, "BH", 2 )) TRACE( "no key negotiated\n" );
824 else if (!strncmp( buf
, "GK ", 3 ))
826 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
827 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
828 memcpy( ctx
->session_key
, bin
, bin_len
);
831 arc4_init( &ctx
->crypt
.ntlm
.arc4info
, ctx
->session_key
, 16 );
832 ctx
->crypt
.ntlm
.seq_no
= 0;
833 create_ntlm2_subkeys( ctx
);
834 arc4_init( &ctx
->crypt
.ntlm2
.send_arc4info
, ctx
->crypt
.ntlm2
.send_seal_key
, 16 );
835 arc4_init( &ctx
->crypt
.ntlm2
.recv_arc4info
, ctx
->crypt
.ntlm2
.recv_seal_key
, 16 );
836 ctx
->crypt
.ntlm2
.send_seq_no
= 0;
837 ctx
->crypt
.ntlm2
.recv_seq_no
= 0;
841 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
) ntlm_funcs
->cleanup( ctx
);
849 TRACE( "returning %08x\n", status
);
853 static NTSTATUS NTAPI
ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle
, LSA_SEC_HANDLE ctx_handle
,
854 SecBufferDesc
*input
, ULONG ctx_req
, ULONG data_rep
,
855 LSA_SEC_HANDLE
*new_ctx_handle
, SecBufferDesc
*output
,
856 ULONG
*ctx_attr
, TimeStamp
*expiry
, BOOLEAN
*mapped_ctx
,
857 SecBuffer
*ctx_data
)
859 NTSTATUS status
= SEC_E_INSUFFICIENT_MEMORY
;
860 struct ntlm_ctx
*ctx
= NULL
;
861 char *buf
, *bin
, *want_flags
= NULL
;
862 unsigned int len
, bin_len
;
864 TRACE( "%lx, %lx, %08x, %u, %p, %p, %p, %p, %p, %p, %p\n", cred_handle
, ctx_handle
, ctx_req
, data_rep
, input
,
865 new_ctx_handle
, output
, ctx_attr
, expiry
, mapped_ctx
, ctx_data
);
866 if (ctx_req
) FIXME( "ignoring flags %08x\n", ctx_req
);
868 if (!(buf
= malloc( NTLM_MAX_BUF
))) return SEC_E_INSUFFICIENT_MEMORY
;
869 if (!(bin
= malloc( NTLM_MAX_BUF
))) goto done
;
873 struct ntlm_cred
*cred
= (struct ntlm_cred
*)cred_handle
;
876 if (!cred
|| cred
->mode
!= MODE_SERVER
)
878 status
= SEC_E_INVALID_HANDLE
;
882 if (!input
|| input
->cBuffers
< 1)
884 status
= SEC_E_INCOMPLETE_MESSAGE
;
888 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
890 status
= SEC_E_INVALID_TOKEN
;
893 else bin_len
= input
->pBuffers
[0].cbBuffer
;
895 argv
[0] = (char *)"ntlm_auth";
896 argv
[1] = (char *)"--helper-protocol=squid-2.5-ntlmssp";
898 if ((status
= ntlm_funcs
->fork( argv
, &ctx
)) != SEC_E_OK
) goto done
;
899 ctx
->mode
= MODE_SERVER
;
901 if (!(want_flags
= malloc( 73 )))
903 status
= SEC_E_INSUFFICIENT_MEMORY
;
906 strcpy( want_flags
, "SF" );
907 if (ctx_req
& ASC_REQ_CONFIDENTIALITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SEAL" );
908 if (ctx_req
& ASC_REQ_CONNECTION
)
910 strcat( want_flags
, " NTLMSSP_FEATURE_SESSION_KEY" );
911 ctx
->attrs
|= ASC_RET_CONNECTION
;
913 if (ctx_req
& ASC_REQ_INTEGRITY
) strcat( want_flags
, " NTLMSSP_FEATURE_SIGN" );
914 if (ctx_req
& ASC_REQ_ALLOCATE_MEMORY
) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
915 if (ctx_req
& ASC_REQ_EXTENDED_ERROR
) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
916 if (ctx_req
& ASC_REQ_MUTUAL_AUTH
) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
917 if (ctx_req
& ASC_REQ_REPLAY_DETECT
) FIXME( "ASC_REQ_REPLAY_DETECT\n" );
918 if (ctx_req
& ASC_REQ_SEQUENCE_DETECT
) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
919 if (ctx_req
& ASC_REQ_STREAM
) FIXME( "ASC_REQ_STREAM\n" );
921 if (strlen( want_flags
) > 3)
923 TRACE( "want flags are %s\n", debugstr_a(want_flags
) );
924 strcpy( buf
, want_flags
);
925 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
926 if (!strncmp( buf
, "BH", 2 )) ERR( "ntlm_auth doesn't understand new command set\n" );
929 memcpy( bin
, input
->pBuffers
[0].pvBuffer
, bin_len
);
930 strcpy( buf
, "YR " );
931 encode_base64( bin
, bin_len
, buf
+ 3 );
933 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
934 TRACE( "ntlm_auth returned %s\n", buf
);
935 if (strncmp( buf
, "TT ", 3))
937 status
= SEC_E_INTERNAL_ERROR
;
940 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
942 if (!output
|| output
->cBuffers
< 1)
944 status
= SEC_E_INSUFFICIENT_MEMORY
;
947 output
->pBuffers
[0].cbBuffer
= bin_len
;
948 output
->pBuffers
[0].BufferType
= SECBUFFER_DATA
;
949 memcpy( output
->pBuffers
[0].pvBuffer
, bin
, bin_len
);
951 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
952 status
= SEC_I_CONTINUE_NEEDED
;
956 if (!input
|| input
->cBuffers
< 1)
958 status
= SEC_E_INCOMPLETE_MESSAGE
;
962 ctx
= (struct ntlm_ctx
*)ctx_handle
;
963 if (!ctx
|| ctx
->mode
!= MODE_SERVER
)
965 status
= SEC_E_INVALID_HANDLE
;
969 if (input
->pBuffers
[0].cbBuffer
> NTLM_MAX_BUF
)
971 status
= SEC_E_INVALID_TOKEN
;
974 else bin_len
= input
->pBuffers
[0].cbBuffer
;
975 memcpy( bin
, input
->pBuffers
[0].pvBuffer
, bin_len
);
977 strcpy( buf
, "KK " );
978 encode_base64( bin
, bin_len
, buf
+ 3 );
980 TRACE( "client sent %s\n", debugstr_a(buf
) );
981 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
982 TRACE( "ntlm_auth returned %s\n", debugstr_a(buf
) );
984 /* At this point, we get a NA if the user didn't authenticate, but a BH if ntlm_auth could not
985 * connect to winbindd. Apart from running Wine as root, there is no way to fix this for now,
986 * so just handle this as a failed login. */
987 if (strncmp( buf
, "AF ", 3 ))
989 if (!strncmp( buf
, "NA ", 3 ))
991 status
= SEC_E_LOGON_DENIED
;
996 const char err_v3
[] = "BH NT_STATUS_ACCESS_DENIED";
997 const char err_v4
[] = "BH NT_STATUS_UNSUCCESSFUL";
999 if ((len
>= strlen(err_v3
) && !strncmp( buf
, err_v3
, strlen(err_v3
) )) ||
1000 (len
>= strlen(err_v4
) && !strncmp( buf
, err_v4
, strlen(err_v4
) )))
1002 TRACE( "connection to winbindd failed\n" );
1003 status
= SEC_E_LOGON_DENIED
;
1005 else status
= SEC_E_INTERNAL_ERROR
;
1009 output
->pBuffers
[0].cbBuffer
= 0;
1011 strcpy( buf
, "GF" );
1012 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1013 if (len
< 3) ctx
->flags
= 0;
1014 else sscanf( buf
+ 3, "%x", &ctx
->flags
);
1016 strcpy( buf
, "GK" );
1017 if ((status
= ntlm_funcs
->chat( ctx
, buf
, NTLM_MAX_BUF
, &len
)) != SEC_E_OK
) goto done
;
1019 if (!strncmp( buf
, "BH", 2 )) TRACE( "no key negotiated\n" );
1020 else if (!strncmp( buf
, "GK ", 3 ))
1022 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
1023 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
1024 memcpy( ctx
->session_key
, bin
, bin_len
);
1027 if (len
< 3) memset( ctx
->session_key
, 0 , 16 );
1030 if (!strncmp( buf
, "BH ", 3 ))
1032 TRACE( "helper sent %s\n", debugstr_a(buf
+ 3) );
1033 /*FIXME: generate dummy session key = MD4(MD4(password))*/
1034 memset( ctx
->session_key
, 0 , 16 );
1036 else if (!strncmp( buf
, "GK ", 3 ))
1038 bin_len
= decode_base64( buf
+ 3, len
- 3, bin
);
1039 TRACE( "session key is %s\n", debugstr_a(buf
+ 3) );
1040 memcpy( ctx
->session_key
, bin
, 16 );
1043 arc4_init( &ctx
->crypt
.ntlm
.arc4info
, ctx
->session_key
, 16 );
1044 ctx
->crypt
.ntlm
.seq_no
= 0;
1046 *new_ctx_handle
= (LSA_SEC_HANDLE
)ctx
;
1051 if (status
!= SEC_E_OK
&& status
!= SEC_I_CONTINUE_NEEDED
) ntlm_funcs
->cleanup( ctx
);
1056 TRACE( "returning %08x\n", status
);
1060 static NTSTATUS NTAPI
ntlm_SpDeleteContext( LSA_SEC_HANDLE handle
)
1062 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1064 TRACE( "%lx\n", handle
);
1066 if (!ctx
) return SEC_E_INVALID_HANDLE
;
1067 ntlm_funcs
->cleanup( ctx
);
1071 static SecPkgInfoW
*build_package_info( const SecPkgInfoW
*info
)
1074 DWORD size_name
= (wcslen(info
->Name
) + 1) * sizeof(WCHAR
);
1075 DWORD size_comment
= (wcslen(info
->Comment
) + 1) * sizeof(WCHAR
);
1077 if (!(ret
= RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*ret
) + size_name
+ size_comment
))) return NULL
;
1078 ret
->fCapabilities
= info
->fCapabilities
;
1079 ret
->wVersion
= info
->wVersion
;
1080 ret
->wRPCID
= info
->wRPCID
;
1081 ret
->cbMaxToken
= info
->cbMaxToken
;
1082 ret
->Name
= (SEC_WCHAR
*)(ret
+ 1);
1083 memcpy( ret
->Name
, info
->Name
, size_name
);
1084 ret
->Comment
= (SEC_WCHAR
*)((char *)ret
->Name
+ size_name
);
1085 memcpy( ret
->Comment
, info
->Comment
, size_comment
);
1089 static NTSTATUS NTAPI
ntlm_SpQueryContextAttributes( LSA_SEC_HANDLE handle
, ULONG attr
, void *buf
)
1091 TRACE( "%lx, %u, %p\n", handle
, attr
, buf
);
1093 if (!handle
) return SEC_E_INVALID_HANDLE
;
1097 #define X(x) case (x) : FIXME(#x" stub\n"); break
1098 X(SECPKG_ATTR_ACCESS_TOKEN
);
1099 X(SECPKG_ATTR_AUTHORITY
);
1100 X(SECPKG_ATTR_DCE_INFO
);
1101 X(SECPKG_ATTR_KEY_INFO
);
1102 X(SECPKG_ATTR_LIFESPAN
);
1103 X(SECPKG_ATTR_NAMES
);
1104 X(SECPKG_ATTR_NATIVE_NAMES
);
1105 X(SECPKG_ATTR_PACKAGE_INFO
);
1106 X(SECPKG_ATTR_PASSWORD_EXPIRY
);
1107 X(SECPKG_ATTR_SESSION_KEY
);
1108 X(SECPKG_ATTR_STREAM_SIZES
);
1109 X(SECPKG_ATTR_TARGET_INFORMATION
);
1110 case SECPKG_ATTR_FLAGS
:
1112 SecPkgContext_Flags
*flags
= (SecPkgContext_Flags
*)buf
;
1113 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1116 if (ctx
->flags
& FLAG_NEGOTIATE_SIGN
) flags
->Flags
|= ISC_RET_INTEGRITY
;
1117 if (ctx
->flags
& FLAG_NEGOTIATE_SEAL
) flags
->Flags
|= ISC_RET_CONFIDENTIALITY
;
1120 case SECPKG_ATTR_SIZES
:
1122 SecPkgContext_Sizes
*sizes
= (SecPkgContext_Sizes
*)buf
;
1123 sizes
->cbMaxToken
= NTLM_MAX_BUF
;
1124 sizes
->cbMaxSignature
= 16;
1125 sizes
->cbBlockSize
= 0;
1126 sizes
->cbSecurityTrailer
= 16;
1129 case SECPKG_ATTR_NEGOTIATION_INFO
:
1131 SecPkgContext_NegotiationInfoW
*info
= (SecPkgContext_NegotiationInfoW
*)buf
;
1132 if (!(info
->PackageInfo
= build_package_info( &ntlm_package_info
))) return SEC_E_INSUFFICIENT_MEMORY
;
1133 info
->NegotiationState
= SECPKG_NEGOTIATION_COMPLETE
;
1138 FIXME( "unknown attribute %u\n", attr
);
1142 return SEC_E_UNSUPPORTED_FUNCTION
;
1145 static SECPKG_FUNCTION_TABLE ntlm_table
=
1147 ntlm_LsaApInitializePackage
,
1148 NULL
, /* LsaLogonUser */
1149 NULL
, /* CallPackage */
1150 NULL
, /* LogonTerminated */
1151 NULL
, /* CallPackageUntrusted */
1152 NULL
, /* CallPackagePassthrough */
1153 NULL
, /* LogonUserEx */
1154 NULL
, /* LogonUserEx2 */
1156 NULL
, /* SpShutdown */
1158 NULL
, /* AcceptCredentials */
1159 ntlm_SpAcquireCredentialsHandle
,
1160 NULL
, /* SpQueryCredentialsAttributes */
1161 ntlm_SpFreeCredentialsHandle
,
1162 NULL
, /* SaveCredentials */
1163 NULL
, /* GetCredentials */
1164 NULL
, /* DeleteCredentials */
1165 ntlm_SpInitLsaModeContext
,
1166 ntlm_SpAcceptLsaModeContext
,
1167 ntlm_SpDeleteContext
,
1168 NULL
, /* ApplyControlToken */
1169 NULL
, /* GetUserInfo */
1170 NULL
, /* GetExtendedInformation */
1171 ntlm_SpQueryContextAttributes
,
1172 NULL
, /* SpAddCredentials */
1173 NULL
, /* SetExtendedInformation */
1174 NULL
, /* SetContextAttributes */
1175 NULL
, /* SetCredentialsAttributes */
1176 NULL
, /* ChangeAccountPassword */
1177 NULL
, /* QueryMetaData */
1178 NULL
, /* ExchangeMetaData */
1179 NULL
, /* GetCredUIContext */
1180 NULL
, /* UpdateCredentials */
1181 NULL
, /* ValidateTargetInfo */
1182 NULL
, /* PostLogonUser */
1185 NTSTATUS NTAPI
SpLsaModeInitialize( ULONG lsa_version
, ULONG
*package_version
, SECPKG_FUNCTION_TABLE
**table
,
1186 ULONG
*table_count
)
1188 TRACE( "%08x, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
1190 *package_version
= SECPKG_INTERFACE_VERSION
;
1191 *table
= &ntlm_table
;
1193 return STATUS_SUCCESS
;
1196 static NTSTATUS NTAPI
ntlm_SpInstanceInit( ULONG version
, SECPKG_DLL_FUNCTIONS
*dll_functions
, void **user_functions
)
1198 TRACE( "%08x, %p, %p\n", version
, dll_functions
, user_functions
);
1199 return STATUS_SUCCESS
;
1205 char outer_padding
[64];
1208 static void hmac_md5_init( struct hmac_md5_ctx
*ctx
, const char *key
, unsigned int key_len
)
1210 char inner_padding
[64], tmp_key
[16];
1215 struct md5_ctx tmp_ctx
;
1217 MD5Init( &tmp_ctx
);
1218 MD5Update( &tmp_ctx
, key
, key_len
);
1219 MD5Final( &tmp_ctx
);
1220 memcpy( tmp_key
, tmp_ctx
.digest
, 16 );
1226 memset( inner_padding
, 0, 64 );
1227 memset( ctx
->outer_padding
, 0, 64 );
1228 memcpy( inner_padding
, key
, key_len
);
1229 memcpy( ctx
->outer_padding
, key
, key_len
);
1231 for (i
= 0; i
< 64; i
++)
1233 inner_padding
[i
] ^= 0x36;
1234 ctx
->outer_padding
[i
] ^= 0x5c;
1237 MD5Init( &ctx
->ctx
);
1238 MD5Update( &ctx
->ctx
, inner_padding
, 64 );
1241 static void hmac_md5_update( struct hmac_md5_ctx
*ctx
, const char *buf
, unsigned int len
)
1243 MD5Update( &ctx
->ctx
, buf
, len
);
1246 static void hmac_md5_final( struct hmac_md5_ctx
*ctx
, char *digest
)
1248 struct md5_ctx outer_ctx
;
1249 char inner_digest
[16];
1251 MD5Final( &ctx
->ctx
);
1252 memcpy( inner_digest
, ctx
->ctx
.digest
, 16 );
1254 MD5Init( &outer_ctx
);
1255 MD5Update( &outer_ctx
, ctx
->outer_padding
, 64 );
1256 MD5Update( &outer_ctx
, inner_digest
, 16 );
1257 MD5Final( &outer_ctx
);
1259 memcpy( digest
, outer_ctx
.digest
, 16 );
1262 static SECURITY_STATUS
create_signature( struct ntlm_ctx
*ctx
, unsigned int flags
, SecBufferDesc
*msg
, int idx
,
1263 enum sign_direction dir
, BOOL encrypt
)
1265 unsigned int i
, sign_version
= 1;
1266 char *sig
= msg
->pBuffers
[idx
].pvBuffer
;
1268 if (flags
& FLAG_NEGOTIATE_NTLM2
&& flags
& FLAG_NEGOTIATE_SIGN
)
1270 char digest
[16], seq_no
[4];
1271 struct hmac_md5_ctx hmac_md5
;
1273 if (dir
== SIGN_SEND
)
1275 seq_no
[0] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 0) & 0xff;
1276 seq_no
[1] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 8) & 0xff;
1277 seq_no
[2] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 16) & 0xff;
1278 seq_no
[3] = (ctx
->crypt
.ntlm2
.send_seq_no
>> 24) & 0xff;
1279 ctx
->crypt
.ntlm2
.send_seq_no
++;
1281 hmac_md5_init( &hmac_md5
, ctx
->crypt
.ntlm2
.send_sign_key
, 16 );
1285 seq_no
[0] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 0) & 0xff;
1286 seq_no
[1] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 8) & 0xff;
1287 seq_no
[2] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 16) & 0xff;
1288 seq_no
[3] = (ctx
->crypt
.ntlm2
.recv_seq_no
>> 24) & 0xff;
1289 ctx
->crypt
.ntlm2
.recv_seq_no
++;
1291 hmac_md5_init( &hmac_md5
, ctx
->crypt
.ntlm2
.recv_sign_key
, 16 );
1294 hmac_md5_update( &hmac_md5
, seq_no
, 4 );
1295 for (i
= 0; i
< msg
->cBuffers
; ++i
)
1297 if (msg
->pBuffers
[i
].BufferType
& SECBUFFER_DATA
)
1298 hmac_md5_update( &hmac_md5
, msg
->pBuffers
[i
].pvBuffer
, msg
->pBuffers
[i
].cbBuffer
);
1300 hmac_md5_final( &hmac_md5
, digest
);
1302 if (encrypt
&& flags
& FLAG_NEGOTIATE_KEY_EXCHANGE
)
1304 if (dir
== SIGN_SEND
)
1305 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, digest
, 8 );
1307 arc4_process( &ctx
->crypt
.ntlm2
.recv_arc4info
, digest
, 8 );
1310 sig
[0] = (sign_version
>> 0) & 0xff;
1311 sig
[1] = (sign_version
>> 8) & 0xff;
1312 sig
[2] = (sign_version
>> 16) & 0xff;
1313 sig
[3] = (sign_version
>> 24) & 0xff;
1314 memcpy( sig
+ 4, digest
, 8 );
1315 memcpy( sig
+ 12, seq_no
, 4 );
1317 msg
->pBuffers
[idx
].cbBuffer
= 16;
1321 if (flags
& FLAG_NEGOTIATE_SIGN
)
1323 unsigned int crc
= 0;
1325 for (i
= 0; i
< msg
->cBuffers
; ++i
)
1327 if (msg
->pBuffers
[i
].BufferType
& SECBUFFER_DATA
)
1328 crc
= RtlComputeCrc32( crc
, msg
->pBuffers
[i
].pvBuffer
, msg
->pBuffers
[i
].cbBuffer
);
1331 sig
[0] = (sign_version
>> 0) & 0xff;
1332 sig
[1] = (sign_version
>> 8) & 0xff;
1333 sig
[2] = (sign_version
>> 16) & 0xff;
1334 sig
[3] = (sign_version
>> 24) & 0xff;
1335 memset( sig
+ 4, 0, 4 );
1336 sig
[8] = (crc
>> 0) & 0xff;
1337 sig
[9] = (crc
>> 8) & 0xff;
1338 sig
[10] = (crc
>> 16) & 0xff;
1339 sig
[11] = (crc
>> 24) & 0xff;
1340 sig
[12] = (ctx
->crypt
.ntlm
.seq_no
>> 0) & 0xff;
1341 sig
[13] = (ctx
->crypt
.ntlm
.seq_no
>> 8) & 0xff;
1342 sig
[14] = (ctx
->crypt
.ntlm
.seq_no
>> 16) & 0xff;
1343 sig
[15] = (ctx
->crypt
.ntlm
.seq_no
>> 24) & 0xff;
1344 ctx
->crypt
.ntlm
.seq_no
++;
1346 if (encrypt
) arc4_process( &ctx
->crypt
.ntlm
.arc4info
, sig
+ 4, 12 );
1350 if (flags
& FLAG_NEGOTIATE_ALWAYS_SIGN
|| !flags
)
1352 /* create dummy signature */
1353 memset( msg
->pBuffers
[idx
].pvBuffer
, 0, 16 );
1354 memset( msg
->pBuffers
[idx
].pvBuffer
, 1, 1 );
1355 msg
->pBuffers
[idx
].cbBuffer
= 16;
1359 return SEC_E_UNSUPPORTED_FUNCTION
;
1362 static NTSTATUS NTAPI
ntlm_SpMakeSignature( LSA_SEC_HANDLE handle
, ULONG qop
, SecBufferDesc
*msg
, ULONG msg_seq_no
)
1364 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1367 TRACE( "%lx, 0x%08x, %p, %u\n", handle
, qop
, msg
, msg_seq_no
);
1368 if (qop
) FIXME( "ignoring quality of protection %08x\n", qop
);
1369 if (msg_seq_no
) FIXME( "ignoring message sequence number %u\n", msg_seq_no
);
1371 if (!handle
) return SEC_E_INVALID_HANDLE
;
1372 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 || (idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1)
1373 return SEC_E_INVALID_TOKEN
;
1374 if (msg
->pBuffers
[idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1376 return create_signature( ctx
, ctx
->flags
, msg
, idx
, SIGN_SEND
, TRUE
);
1379 static NTSTATUS
verify_signature( struct ntlm_ctx
*ctx
, unsigned int flags
, SecBufferDesc
*msg
, int idx
)
1387 if (!(buf
= malloc( msg
->cBuffers
* sizeof(*buf
) ))) return SEC_E_INSUFFICIENT_MEMORY
;
1388 desc
.ulVersion
= SECBUFFER_VERSION
;
1389 desc
.cBuffers
= msg
->cBuffers
;
1390 desc
.pBuffers
= buf
;
1392 for (i
= 0; i
< msg
->cBuffers
; i
++)
1394 if (msg
->pBuffers
[i
].BufferType
== SECBUFFER_TOKEN
)
1396 buf
[i
].BufferType
= SECBUFFER_TOKEN
;
1397 buf
[i
].cbBuffer
= 16;
1398 buf
[i
].pvBuffer
= sig
;
1402 buf
[i
].BufferType
= msg
->pBuffers
[i
].BufferType
;
1403 buf
[i
].cbBuffer
= msg
->pBuffers
[i
].cbBuffer
;
1404 buf
[i
].pvBuffer
= msg
->pBuffers
[i
].pvBuffer
;
1408 if ((status
= create_signature( ctx
, flags
, &desc
, idx
, SIGN_RECV
, TRUE
)) == SEC_E_OK
)
1410 if (memcmp( (char *)buf
[idx
].pvBuffer
+ 8, (char *)msg
->pBuffers
[idx
].pvBuffer
+ 8, 8 ))
1411 status
= SEC_E_MESSAGE_ALTERED
;
1418 static NTSTATUS NTAPI
ntlm_SpVerifySignature( LSA_SEC_HANDLE handle
, SecBufferDesc
*msg
, ULONG msg_seq_no
, ULONG
*qop
)
1420 struct ntlm_ctx
*ctx
= (struct ntlm_ctx
*)handle
;
1423 TRACE( "%lx, %p, %u, %p\n", handle
, msg
, msg_seq_no
, qop
);
1424 if (msg_seq_no
) FIXME( "ignoring message sequence number %u\n", msg_seq_no
);
1426 if (!handle
) return SEC_E_INVALID_HANDLE
;
1427 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 || (idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1)
1428 return SEC_E_INVALID_TOKEN
;
1429 if (msg
->pBuffers
[idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1431 return verify_signature( ctx
, ctx
->flags
, msg
, idx
);
1434 static NTSTATUS NTAPI
ntlm_SpSealMessage( LSA_SEC_HANDLE handle
, ULONG qop
, SecBufferDesc
*msg
, ULONG msg_seq_no
)
1436 int token_idx
, data_idx
;
1437 struct ntlm_ctx
*ctx
;
1439 TRACE( "%lx, %08x, %p %u\n", handle
, qop
, msg
, msg_seq_no
);
1440 if (qop
) FIXME( "ignoring quality of protection %08x\n", qop
);
1441 if (msg_seq_no
) FIXME( "ignoring message sequence number %u\n", msg_seq_no
);
1443 if (!handle
) return SEC_E_INVALID_HANDLE
;
1445 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 ||
1446 (token_idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1 ||
1447 (data_idx
= get_buffer_index( msg
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1449 if (msg
->pBuffers
[token_idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1451 ctx
= (struct ntlm_ctx
*)handle
;
1452 if (ctx
->flags
& FLAG_NEGOTIATE_NTLM2
&& ctx
->flags
& FLAG_NEGOTIATE_SEAL
)
1454 create_signature( ctx
, ctx
->flags
, msg
, token_idx
, SIGN_SEND
, FALSE
);
1456 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1457 msg
->pBuffers
[data_idx
].cbBuffer
);
1458 if (ctx
->flags
& FLAG_NEGOTIATE_KEY_EXCHANGE
)
1459 arc4_process( &ctx
->crypt
.ntlm2
.send_arc4info
, (char *)msg
->pBuffers
[token_idx
].pvBuffer
+ 4, 8 );
1463 char *sig
= msg
->pBuffers
[token_idx
].pvBuffer
;
1465 create_signature( ctx
, ctx
->flags
| FLAG_NEGOTIATE_SIGN
, msg
, token_idx
, SIGN_SEND
, FALSE
);
1467 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
, msg
->pBuffers
[data_idx
].cbBuffer
);
1468 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, sig
+ 4, 12 );
1470 if (ctx
->flags
& FLAG_NEGOTIATE_ALWAYS_SIGN
|| !ctx
->flags
) memset( sig
+ 4, 0, 4 );
1476 static NTSTATUS NTAPI
ntlm_SpUnsealMessage( LSA_SEC_HANDLE handle
, SecBufferDesc
*msg
, ULONG msg_seq_no
, ULONG
*qop
)
1478 int token_idx
, data_idx
;
1479 struct ntlm_ctx
*ctx
;
1481 TRACE( "%lx, %p, %u, %p\n", handle
, msg
, msg_seq_no
, qop
);
1482 if (msg_seq_no
) FIXME( "ignoring message sequence number %u\n", msg_seq_no
);
1484 if (!handle
) return SEC_E_INVALID_HANDLE
;
1486 if (!msg
|| !msg
->pBuffers
|| msg
->cBuffers
< 2 ||
1487 (token_idx
= get_buffer_index( msg
, SECBUFFER_TOKEN
)) == -1 ||
1488 (data_idx
= get_buffer_index( msg
, SECBUFFER_DATA
)) == -1) return SEC_E_INVALID_TOKEN
;
1490 if (msg
->pBuffers
[token_idx
].cbBuffer
< 16) return SEC_E_BUFFER_TOO_SMALL
;
1492 ctx
= (struct ntlm_ctx
*)handle
;
1493 if (ctx
->flags
& FLAG_NEGOTIATE_NTLM2
&& ctx
->flags
& FLAG_NEGOTIATE_SEAL
)
1494 arc4_process( &ctx
->crypt
.ntlm2
.recv_arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1495 msg
->pBuffers
[data_idx
].cbBuffer
);
1497 arc4_process( &ctx
->crypt
.ntlm
.arc4info
, msg
->pBuffers
[data_idx
].pvBuffer
,
1498 msg
->pBuffers
[data_idx
].cbBuffer
);
1500 /* make sure we use a session key for the signature check, SealMessage always does that,
1501 even in the dummy case */
1502 return verify_signature( ctx
, ctx
->flags
| FLAG_NEGOTIATE_SIGN
, msg
, token_idx
);
1505 static SECPKG_USER_FUNCTION_TABLE ntlm_user_table
=
1507 ntlm_SpInstanceInit
,
1508 NULL
, /* SpInitUserModeContext */
1509 ntlm_SpMakeSignature
,
1510 ntlm_SpVerifySignature
,
1512 ntlm_SpUnsealMessage
,
1513 NULL
, /* SpGetContextToken */
1514 NULL
, /* SpQueryContextAttributes */
1515 NULL
, /* SpCompleteAuthToken */
1516 NULL
, /* SpDeleteContext */
1517 NULL
, /* SpFormatCredentialsFn */
1518 NULL
, /* SpMarshallSupplementalCreds */
1519 NULL
, /* SpExportSecurityContext */
1520 NULL
/* SpImportSecurityContext */
1523 NTSTATUS NTAPI
SpUserModeInitialize( ULONG lsa_version
, ULONG
*package_version
, SECPKG_USER_FUNCTION_TABLE
**table
,
1524 ULONG
*table_count
)
1526 TRACE( "%08x, %p, %p, %p\n", lsa_version
, package_version
, table
, table_count
);
1528 *package_version
= SECPKG_INTERFACE_VERSION
;
1529 *table
= &ntlm_user_table
;
1531 return STATUS_SUCCESS
;
1534 BOOL WINAPI
DllMain( HINSTANCE hinst
, DWORD reason
, void *reserved
)
1538 case DLL_PROCESS_ATTACH
:
1540 DisableThreadLibraryCalls( hinst
);
1542 case DLL_PROCESS_DETACH
: