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:
Rob Shearman 2008-01-25 14:05:38 +00:00 committed by Alexandre Julliard
parent 506ba701bb
commit 8a2125f932
1 changed files with 144 additions and 53 deletions

View File

@ -24,11 +24,13 @@
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "wincred.h"
#include "rpc.h"
#include "sspi.h"
#include "lm.h"
#include "secur32_priv.h"
#include "hmac_md5.h"
#include "wine/unicode.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
@ -93,6 +95,42 @@ static SECURITY_STATUS SEC_ENTRY ntlm_QueryCredentialsAttributesW(
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
*/
@ -129,10 +167,6 @@ static SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(
break;
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));
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("Domain name is %s\n", debugstr_wn(auth_data->Domain, auth_data->DomainLength));
/* Get username and domain from pAuthData */
unixcp_size = WideCharToMultiByte(CP_UNIXCP, WC_NO_BEST_FIT_CHARS,
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';
ntlm_cred->username_arg = ntlm_GetUsernameArg(auth_data->User, auth_data->UserLength);
ntlm_cred->domain_arg = ntlm_GetDomainArg(auth_data->Domain, auth_data->DomainLength);
if(auth_data->PasswordLength != 0)
{
@ -362,6 +380,46 @@ static int ntlm_GetDataBufferIndex(PSecBufferDesc pMessage)
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
*/
@ -380,6 +438,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
int buffer_len, bin_len, max_len = NTLM_MAX_BUF;
int token_idx;
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,
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 */
if (pszTargetName)
{
TRACE("According to a MS whitepaper pszTargetName is ignored.\n");
}
if(TargetDataRep == SECURITY_NETWORK_DREP){
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 credentials_argv[] = "--use-cached-creds";
SEC_CHAR *client_argv[5];
int pwlen = 0;
TRACE("First time in ISC()\n");
@ -442,30 +498,62 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
{
LPWKSTA_USER_INFO_1 ui = NULL;
NET_API_STATUS status;
int unixcp_size;
static const char username_arg[] = "--username=";
PCREDENTIALW cred;
status = NetWkstaUserGetInfo(NULL, 1, (LPBYTE *)&ui);
if (status != NERR_Success || ui == NULL)
if (ntlm_GetCachedCredential(pszTargetName, &cred))
{
ret = SEC_E_NO_CREDENTIALS;
goto isc_end;
LPWSTR p;
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,
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");
TRACE("using cached credentials\n");
client_argv[2] = username;
client_argv[3] = credentials_argv;
client_argv[4] = NULL;
client_argv[2] = username;
client_argv[3] = credentials_argv;
client_argv[4] = NULL;
}
}
else
{
@ -487,19 +575,20 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
}
/* Generate the dummy session key = MD4(MD4(password))*/
if(ntlm_cred->password)
if(password || ntlm_cred->password)
{
SEC_WCHAR *unicode_password;
int passwd_lenW;
TRACE("Converting password to unicode.\n");
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);
unicode_password = HeapAlloc(GetProcessHeap(), 0,
passwd_lenW * sizeof(SEC_WCHAR));
MultiByteToWideChar(CP_ACP, 0, (LPCSTR)ntlm_cred->password,
ntlm_cred->pwlen, unicode_password, passwd_lenW);
MultiByteToWideChar(CP_ACP, 0, password ? (LPCSTR)password : (LPCSTR)ntlm_cred->password,
password ? pwlen : ntlm_cred->pwlen, unicode_password, passwd_lenW);
SECUR32_CreateNTLMv1SessionKey((PBYTE)unicode_password,
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
* password if this failed. */
if(ntlm_cred->password == NULL)
if(!password && !ntlm_cred->password)
{
lstrcpynA(buffer, "OK", max_len-1);
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
{
lstrcpynA(buffer, "PW ", max_len-1);
if((ret = encodeBase64((unsigned char*)ntlm_cred->password,
ntlm_cred->pwlen, buffer+3,
if((ret = encodeBase64(password ? (unsigned char *)password : (unsigned char *)ntlm_cred->password,
password ? pwlen : ntlm_cred->pwlen, buffer+3,
max_len-3, &buffer_len)) != SEC_E_OK)
{
cleanup_helper(helper);
@ -836,6 +925,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(
isc_end:
HeapFree(GetProcessHeap(), 0, username);
HeapFree(GetProcessHeap(), 0, domain);
HeapFree(GetProcessHeap(), 0, password);
HeapFree(GetProcessHeap(), 0, want_flags);
HeapFree(GetProcessHeap(), 0, buffer);
HeapFree(GetProcessHeap(), 0, bin);