secur32: Try to retrive credentials by using the credential manager to retrieve credentials saved for the target server in InitializeContextHandleW, if possible.
This commit is contained in:
parent
506ba701bb
commit
8a2125f932
|
@ -24,11 +24,13 @@
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
#include "winnls.h"
|
#include "winnls.h"
|
||||||
|
#include "wincred.h"
|
||||||
#include "rpc.h"
|
#include "rpc.h"
|
||||||
#include "sspi.h"
|
#include "sspi.h"
|
||||||
#include "lm.h"
|
#include "lm.h"
|
||||||
#include "secur32_priv.h"
|
#include "secur32_priv.h"
|
||||||
#include "hmac_md5.h"
|
#include "hmac_md5.h"
|
||||||
|
#include "wine/unicode.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
|
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
|
||||||
|
@ -93,6 +95,42 @@ static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *ntlm_GetUsernameArg(LPCWSTR userW, INT userW_length)
|
||||||
|
{
|
||||||
|
static const char username_arg[] = "--username=";
|
||||||
|
char *user;
|
||||||
|
int unixcp_size;
|
||||||
|
|
||||||
|
unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
|
||||||
|
userW, userW_length, NULL, 0, NULL, NULL) + sizeof(username_arg);
|
||||||
|
user = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
|
||||||
|
if (!user) return NULL;
|
||||||
|
memcpy(user, username_arg, sizeof(username_arg) - 1);
|
||||||
|
WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, userW, userW_length,
|
||||||
|
user + sizeof(username_arg) - 1,
|
||||||
|
unixcp_size - sizeof(username_arg) + 1, NULL, NULL);
|
||||||
|
user[unixcp_size - 1] = '\0';
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *ntlm_GetDomainArg(LPCWSTR domainW, INT domainW_length)
|
||||||
|
{
|
||||||
|
static const char domain_arg[] = "--domain=";
|
||||||
|
char *domain;
|
||||||
|
int unixcp_size;
|
||||||
|
|
||||||
|
unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
|
||||||
|
domainW, domainW_length, NULL, 0, NULL, NULL) + sizeof(domain_arg);
|
||||||
|
domain = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
|
||||||
|
if (!domain) return NULL;
|
||||||
|
memcpy(domain, domain_arg, sizeof(domain_arg) - 1);
|
||||||
|
WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, domainW,
|
||||||
|
domainW_length, domain + sizeof(domain_arg) - 1,
|
||||||
|
unixcp_size - sizeof(domain) + 1, NULL, NULL);
|
||||||
|
domain[unixcp_size - 1] = '\0';
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* AcquireCredentialsHandleW
|
* AcquireCredentialsHandleW
|
||||||
*/
|
*/
|
||||||
|
@ -129,10 +167,6 @@ static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
|
||||||
break;
|
break;
|
||||||
case SECPKG_CRED_OUTBOUND:
|
case SECPKG_CRED_OUTBOUND:
|
||||||
{
|
{
|
||||||
static const char username_arg[] = "--username=";
|
|
||||||
static const char domain_arg[] = "--domain=";
|
|
||||||
int unixcp_size;
|
|
||||||
|
|
||||||
ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred));
|
ntlm_cred = HeapAlloc(GetProcessHeap(), 0, sizeof(*ntlm_cred));
|
||||||
if (!ntlm_cred)
|
if (!ntlm_cred)
|
||||||
{
|
{
|
||||||
|
@ -153,24 +187,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
|
||||||
TRACE("Username is %s\n", debugstr_wn(auth_data->User, auth_data->UserLength));
|
TRACE("Username is %s\n", debugstr_wn(auth_data->User, auth_data->UserLength));
|
||||||
TRACE("Domain name is %s\n", debugstr_wn(auth_data->Domain, auth_data->DomainLength));
|
TRACE("Domain name is %s\n", debugstr_wn(auth_data->Domain, auth_data->DomainLength));
|
||||||
|
|
||||||
/* Get username and domain from pAuthData */
|
ntlm_cred->username_arg = ntlm_GetUsernameArg(auth_data->User, auth_data->UserLength);
|
||||||
unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
|
ntlm_cred->domain_arg = ntlm_GetDomainArg(auth_data->Domain, auth_data->DomainLength);
|
||||||
auth_data->User, auth_data->UserLength, NULL, 0, NULL, NULL) + sizeof(username_arg);
|
|
||||||
ntlm_cred->username_arg = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
|
|
||||||
memcpy(ntlm_cred->username_arg, username_arg, sizeof(username_arg) - 1);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, auth_data->User, auth_data->UserLength,
|
|
||||||
ntlm_cred->username_arg + sizeof(username_arg) - 1,
|
|
||||||
unixcp_size - sizeof(username_arg) + 1, NULL, NULL);
|
|
||||||
ntlm_cred->username_arg[unixcp_size - 1] = '\0';
|
|
||||||
|
|
||||||
unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
|
|
||||||
auth_data->Domain, auth_data->DomainLength, NULL, 0, NULL, NULL) + sizeof(domain_arg);
|
|
||||||
ntlm_cred->domain_arg = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
|
|
||||||
memcpy(ntlm_cred->domain_arg, domain_arg, sizeof(domain_arg) - 1);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, auth_data->Domain,
|
|
||||||
auth_data->DomainLength, ntlm_cred->domain_arg + sizeof(domain_arg) - 1,
|
|
||||||
unixcp_size - sizeof(domain) + 1, NULL, NULL);
|
|
||||||
ntlm_cred->domain_arg[unixcp_size - 1] = '\0';
|
|
||||||
|
|
||||||
if(auth_data->PasswordLength != 0)
|
if(auth_data->PasswordLength != 0)
|
||||||
{
|
{
|
||||||
|
@ -362,6 +380,46 @@ static int ntlm_GetDataBufferIndex(PSecBufferDesc pMessage)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BOOL ntlm_GetCachedCredential(const SEC_WCHAR *pszTargetName, PCREDENTIALW *cred)
|
||||||
|
{
|
||||||
|
LPCWSTR p;
|
||||||
|
LPCWSTR pszHost;
|
||||||
|
LPWSTR pszHostOnly;
|
||||||
|
BOOL ret;
|
||||||
|
|
||||||
|
if (!pszTargetName)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* try to get the start of the hostname from service principal name (SPN) */
|
||||||
|
pszHost = strchrW(pszTargetName, '/');
|
||||||
|
if (pszHost)
|
||||||
|
{
|
||||||
|
/* skip slash character */
|
||||||
|
pszHost++;
|
||||||
|
|
||||||
|
/* find end of host by detecting start of instance port or start of referrer */
|
||||||
|
p = strchrW(pszHost, ':');
|
||||||
|
if (!p)
|
||||||
|
p = strchrW(pszHost, '/');
|
||||||
|
if (!p)
|
||||||
|
p = pszHost + strlenW(pszHost);
|
||||||
|
}
|
||||||
|
else /* otherwise not an SPN, just a host */
|
||||||
|
p = pszHost + strlenW(pszHost);
|
||||||
|
|
||||||
|
pszHostOnly = HeapAlloc(GetProcessHeap(), 0, (p - pszHost + 1) * sizeof(WCHAR));
|
||||||
|
if (!pszHostOnly)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
memcpy(pszHostOnly, pszHost, (p - pszHost) * sizeof(WCHAR));
|
||||||
|
pszHostOnly[p - pszHost] = '\0';
|
||||||
|
|
||||||
|
ret = CredReadW(pszHostOnly, CRED_TYPE_DOMAIN_PASSWORD, 0, cred);
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, pszHostOnly);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* InitializeSecurityContextW
|
* InitializeSecurityContextW
|
||||||
*/
|
*/
|
||||||
|
@ -380,6 +438,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
|
int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
|
||||||
int token_idx;
|
int token_idx;
|
||||||
SEC_CHAR *username = NULL;
|
SEC_CHAR *username = NULL;
|
||||||
|
SEC_CHAR *domain = NULL;
|
||||||
|
SEC_CHAR *password = NULL;
|
||||||
|
|
||||||
TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
|
TRACE("%p %p %s %d %d %d %p %d %p %p %p %p\n", phCredential, phContext,
|
||||||
debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
|
debugstr_w(pszTargetName), fContextReq, Reserved1, TargetDataRep, pInput,
|
||||||
|
@ -399,11 +459,6 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
*/
|
*/
|
||||||
/* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
|
/* The squid cache size is 2010 chars, and that's what ntlm_auth uses */
|
||||||
|
|
||||||
if (pszTargetName)
|
|
||||||
{
|
|
||||||
TRACE("According to a MS whitepaper pszTargetName is ignored.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(TargetDataRep == SECURITY_NETWORK_DREP){
|
if(TargetDataRep == SECURITY_NETWORK_DREP){
|
||||||
TRACE("Setting SECURITY_NETWORK_DREP\n");
|
TRACE("Setting SECURITY_NETWORK_DREP\n");
|
||||||
}
|
}
|
||||||
|
@ -416,6 +471,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
static char helper_protocol[] = "--helper-protocol=ntlmssp-client-1";
|
static char helper_protocol[] = "--helper-protocol=ntlmssp-client-1";
|
||||||
static CHAR credentials_argv[] = "--use-cached-creds";
|
static CHAR credentials_argv[] = "--use-cached-creds";
|
||||||
SEC_CHAR *client_argv[5];
|
SEC_CHAR *client_argv[5];
|
||||||
|
int pwlen = 0;
|
||||||
|
|
||||||
TRACE("First time in ISC()\n");
|
TRACE("First time in ISC()\n");
|
||||||
|
|
||||||
|
@ -442,30 +498,62 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
{
|
{
|
||||||
LPWKSTA_USER_INFO_1 ui = NULL;
|
LPWKSTA_USER_INFO_1 ui = NULL;
|
||||||
NET_API_STATUS status;
|
NET_API_STATUS status;
|
||||||
int unixcp_size;
|
PCREDENTIALW cred;
|
||||||
static const char username_arg[] = "--username=";
|
|
||||||
|
|
||||||
status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui);
|
if (ntlm_GetCachedCredential(pszTargetName, &cred))
|
||||||
if (status != NERR_Success || ui == NULL)
|
|
||||||
{
|
{
|
||||||
ret = SEC_E_NO_CREDENTIALS;
|
LPWSTR p;
|
||||||
goto isc_end;
|
p = strchrW(cred->UserName, '\\');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
domain = ntlm_GetDomainArg(cred->UserName, p - cred->UserName);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
domain = ntlm_GetDomainArg(NULL, 0);
|
||||||
|
p = cred->UserName;
|
||||||
|
}
|
||||||
|
|
||||||
|
username = ntlm_GetUsernameArg(p, -1);
|
||||||
|
|
||||||
|
if(cred->CredentialBlobSize != 0)
|
||||||
|
{
|
||||||
|
pwlen = WideCharToMultiByte(CP_UNIXCP,
|
||||||
|
WC_NO_BEST_FIT_CHARS, (LPWSTR)cred->CredentialBlob,
|
||||||
|
cred->CredentialBlobSize / sizeof(WCHAR), NULL, 0,
|
||||||
|
NULL, NULL);
|
||||||
|
|
||||||
|
password = HeapAlloc(GetProcessHeap(), 0, pwlen);
|
||||||
|
|
||||||
|
WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
|
||||||
|
(LPWSTR)cred->CredentialBlob,
|
||||||
|
cred->CredentialBlobSize / sizeof(WCHAR),
|
||||||
|
password, pwlen, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CredFree(cred);
|
||||||
|
|
||||||
|
client_argv[2] = username;
|
||||||
|
client_argv[3] = domain;
|
||||||
|
client_argv[4] = NULL;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui);
|
||||||
|
if (status != NERR_Success || ui == NULL)
|
||||||
|
{
|
||||||
|
ret = SEC_E_NO_CREDENTIALS;
|
||||||
|
goto isc_end;
|
||||||
|
}
|
||||||
|
username = ntlm_GetUsernameArg(ui->wkui1_username, -1);
|
||||||
|
|
||||||
unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
|
TRACE("using cached credentials\n");
|
||||||
ui->wkui1_username, -1, NULL, 0, NULL, NULL) + sizeof(username_arg);
|
|
||||||
username = HeapAlloc(GetProcessHeap(), 0, unixcp_size);
|
|
||||||
memcpy(username, username_arg, sizeof(username_arg) - 1);
|
|
||||||
WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS, ui->wkui1_username, -1,
|
|
||||||
username + sizeof(username_arg) - 1,
|
|
||||||
unixcp_size - sizeof(username_arg) + 1, NULL, NULL);
|
|
||||||
username[unixcp_size - 1] = '\0';
|
|
||||||
|
|
||||||
TRACE("using cached credentials\n");
|
client_argv[2] = username;
|
||||||
|
client_argv[3] = credentials_argv;
|
||||||
client_argv[2] = username;
|
client_argv[4] = NULL;
|
||||||
client_argv[3] = credentials_argv;
|
}
|
||||||
client_argv[4] = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -487,19 +575,20 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generate the dummy session key = MD4(MD4(password))*/
|
/* Generate the dummy session key = MD4(MD4(password))*/
|
||||||
if(ntlm_cred->password)
|
if(password || ntlm_cred->password)
|
||||||
{
|
{
|
||||||
SEC_WCHAR *unicode_password;
|
SEC_WCHAR *unicode_password;
|
||||||
int passwd_lenW;
|
int passwd_lenW;
|
||||||
|
|
||||||
TRACE("Converting password to unicode.\n");
|
TRACE("Converting password to unicode.\n");
|
||||||
passwd_lenW = MultiByteToWideChar(CP_ACP, 0,
|
passwd_lenW = MultiByteToWideChar(CP_ACP, 0,
|
||||||
(LPCSTR)ntlm_cred->password, ntlm_cred->pwlen,
|
password ? (LPCSTR)password : (LPCSTR)ntlm_cred->password,
|
||||||
|
password ? pwlen : ntlm_cred->pwlen,
|
||||||
NULL, 0);
|
NULL, 0);
|
||||||
unicode_password = HeapAlloc(GetProcessHeap(), 0,
|
unicode_password = HeapAlloc(GetProcessHeap(), 0,
|
||||||
passwd_lenW * sizeof(SEC_WCHAR));
|
passwd_lenW * sizeof(SEC_WCHAR));
|
||||||
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)ntlm_cred->password,
|
MultiByteToWideChar(CP_ACP, 0, password ? (LPCSTR)password : (LPCSTR)ntlm_cred->password,
|
||||||
ntlm_cred->pwlen, unicode_password, passwd_lenW);
|
password ? pwlen : ntlm_cred->pwlen, unicode_password, passwd_lenW);
|
||||||
|
|
||||||
SECUR32_CreateNTLMv1SessionKey((PBYTE)unicode_password,
|
SECUR32_CreateNTLMv1SessionKey((PBYTE)unicode_password,
|
||||||
passwd_lenW * sizeof(SEC_WCHAR), helper->session_key);
|
passwd_lenW * sizeof(SEC_WCHAR), helper->session_key);
|
||||||
|
@ -560,7 +649,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
|
|
||||||
/* If no password is given, try to use cached credentials. Fall back to an empty
|
/* If no password is given, try to use cached credentials. Fall back to an empty
|
||||||
* password if this failed. */
|
* password if this failed. */
|
||||||
if(ntlm_cred->password == NULL)
|
if(!password && !ntlm_cred->password)
|
||||||
{
|
{
|
||||||
lstrcpynA(buffer, "OK", max_len-1);
|
lstrcpynA(buffer, "OK", max_len-1);
|
||||||
if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
|
if((ret = run_helper(helper, buffer, max_len, &buffer_len)) != SEC_E_OK)
|
||||||
|
@ -581,8 +670,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lstrcpynA(buffer, "PW ", max_len-1);
|
lstrcpynA(buffer, "PW ", max_len-1);
|
||||||
if((ret = encodeBase64((unsigned char*)ntlm_cred->password,
|
if((ret = encodeBase64(password ? (unsigned char *)password : (unsigned char *)ntlm_cred->password,
|
||||||
ntlm_cred->pwlen, buffer+3,
|
password ? pwlen : ntlm_cred->pwlen, buffer+3,
|
||||||
max_len-3, &buffer_len)) != SEC_E_OK)
|
max_len-3, &buffer_len)) != SEC_E_OK)
|
||||||
{
|
{
|
||||||
cleanup_helper(helper);
|
cleanup_helper(helper);
|
||||||
|
@ -836,6 +925,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
|
||||||
|
|
||||||
isc_end:
|
isc_end:
|
||||||
HeapFree(GetProcessHeap(), 0, username);
|
HeapFree(GetProcessHeap(), 0, username);
|
||||||
|
HeapFree(GetProcessHeap(), 0, domain);
|
||||||
|
HeapFree(GetProcessHeap(), 0, password);
|
||||||
HeapFree(GetProcessHeap(), 0, want_flags);
|
HeapFree(GetProcessHeap(), 0, want_flags);
|
||||||
HeapFree(GetProcessHeap(), 0, buffer);
|
HeapFree(GetProcessHeap(), 0, buffer);
|
||||||
HeapFree(GetProcessHeap(), 0, bin);
|
HeapFree(GetProcessHeap(), 0, bin);
|
||||||
|
|
Loading…
Reference in New Issue