advapi32: Add support for using the Mac Keychain services as a backend for the credential functions instead of the registry.
This commit is contained in:
parent
c111c2d685
commit
312a1db3ec
|
@ -722,6 +722,7 @@ LDD
|
||||||
DLLTOOL
|
DLLTOOL
|
||||||
DLLWRAP
|
DLLWRAP
|
||||||
MINGWAR
|
MINGWAR
|
||||||
|
SECURITYLIB
|
||||||
COREFOUNDATIONLIB
|
COREFOUNDATIONLIB
|
||||||
IOKITLIB
|
IOKITLIB
|
||||||
LDEXECFLAGS
|
LDEXECFLAGS
|
||||||
|
@ -8093,7 +8094,9 @@ fi
|
||||||
LDSHARED="\$(CC) -dynamiclib"
|
LDSHARED="\$(CC) -dynamiclib"
|
||||||
STRIP="$STRIP -x"
|
STRIP="$STRIP -x"
|
||||||
LDRPATH_LOCAL="&& install_name_tool -change @executable_path/\`\$(RELPATH) \$(bindir) \$(libdir)\`/libwine.1.dylib @executable_path/\$(TOPOBJDIR)/libs/wine/libwine.1.dylib \$@ || \$(RM) \$@"
|
LDRPATH_LOCAL="&& install_name_tool -change @executable_path/\`\$(RELPATH) \$(bindir) \$(libdir)\`/libwine.1.dylib @executable_path/\$(TOPOBJDIR)/libs/wine/libwine.1.dylib \$@ || \$(RM) \$@"
|
||||||
COREFOUNDATIONLIB="-framework CoreFoundation"
|
SECURITYLIB="-framework Security -framework CoreFoundation"
|
||||||
|
|
||||||
|
COREFOUNDATIONLIB="-framework CoreFoundation"
|
||||||
|
|
||||||
IOKITLIB="-framework IOKit -framework CoreFoundation"
|
IOKITLIB="-framework IOKit -framework CoreFoundation"
|
||||||
|
|
||||||
|
@ -22414,6 +22417,7 @@ LDD!$LDD$ac_delim
|
||||||
DLLTOOL!$DLLTOOL$ac_delim
|
DLLTOOL!$DLLTOOL$ac_delim
|
||||||
DLLWRAP!$DLLWRAP$ac_delim
|
DLLWRAP!$DLLWRAP$ac_delim
|
||||||
MINGWAR!$MINGWAR$ac_delim
|
MINGWAR!$MINGWAR$ac_delim
|
||||||
|
SECURITYLIB!$SECURITYLIB$ac_delim
|
||||||
COREFOUNDATIONLIB!$COREFOUNDATIONLIB$ac_delim
|
COREFOUNDATIONLIB!$COREFOUNDATIONLIB$ac_delim
|
||||||
IOKITLIB!$IOKITLIB$ac_delim
|
IOKITLIB!$IOKITLIB$ac_delim
|
||||||
LDEXECFLAGS!$LDEXECFLAGS$ac_delim
|
LDEXECFLAGS!$LDEXECFLAGS$ac_delim
|
||||||
|
@ -22462,7 +22466,7 @@ LIBOBJS!$LIBOBJS$ac_delim
|
||||||
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
||||||
_ACEOF
|
_ACEOF
|
||||||
|
|
||||||
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 71; then
|
if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 72; then
|
||||||
break
|
break
|
||||||
elif $ac_last_try; then
|
elif $ac_last_try; then
|
||||||
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
||||||
|
|
|
@ -388,6 +388,7 @@ case $host_os in
|
||||||
STRIP="$STRIP -x"
|
STRIP="$STRIP -x"
|
||||||
LDRPATH_LOCAL="&& install_name_tool -change @executable_path/\`\$(RELPATH) \$(bindir) \$(libdir)\`/libwine.1.dylib @executable_path/\$(TOPOBJDIR)/libs/wine/libwine.1.dylib \$@ || \$(RM) \$@"
|
LDRPATH_LOCAL="&& install_name_tool -change @executable_path/\`\$(RELPATH) \$(bindir) \$(libdir)\`/libwine.1.dylib @executable_path/\$(TOPOBJDIR)/libs/wine/libwine.1.dylib \$@ || \$(RM) \$@"
|
||||||
dnl declare needed frameworks
|
dnl declare needed frameworks
|
||||||
|
AC_SUBST(SECURITYLIB,"-framework Security -framework CoreFoundation")
|
||||||
AC_SUBST(COREFOUNDATIONLIB,"-framework CoreFoundation")
|
AC_SUBST(COREFOUNDATIONLIB,"-framework CoreFoundation")
|
||||||
AC_SUBST(IOKITLIB,"-framework IOKit -framework CoreFoundation")
|
AC_SUBST(IOKITLIB,"-framework IOKit -framework CoreFoundation")
|
||||||
AC_SUBST(LDEXECFLAGS,["-image_base 0x7bf00000 -Wl,-segaddr,WINE_DOS,0x00000000,-segaddr,WINE_SHARED_HEAP,0x7f000000"])
|
AC_SUBST(LDEXECFLAGS,["-image_base 0x7bf00000 -Wl,-segaddr,WINE_DOS,0x00000000,-segaddr,WINE_SHARED_HEAP,0x7f000000"])
|
||||||
|
|
|
@ -6,6 +6,7 @@ VPATH = @srcdir@
|
||||||
MODULE = advapi32.dll
|
MODULE = advapi32.dll
|
||||||
IMPORTLIB = libadvapi32.$(IMPLIBEXT)
|
IMPORTLIB = libadvapi32.$(IMPLIBEXT)
|
||||||
IMPORTS = kernel32 ntdll
|
IMPORTS = kernel32 ntdll
|
||||||
|
EXTRALIBS = @SECURITYLIB@
|
||||||
|
|
||||||
C_SRCS = \
|
C_SRCS = \
|
||||||
advapi.c \
|
advapi.c \
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
#include "winbase.h"
|
#include "winbase.h"
|
||||||
|
@ -26,6 +27,12 @@
|
||||||
#include "wincred.h"
|
#include "wincred.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
# include <Security/SecKeychain.h>
|
||||||
|
# include <Security/SecKeychainItem.h>
|
||||||
|
# include <Security/SecKeychainSearch.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "crypt.h"
|
#include "crypt.h"
|
||||||
|
|
||||||
#include "wine/unicode.h"
|
#include "wine/unicode.h"
|
||||||
|
@ -232,6 +239,200 @@ static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static DWORD mac_read_credential_from_item(SecKeychainItemRef item, BOOL require_password,
|
||||||
|
PCREDENTIALW credential, char *buffer,
|
||||||
|
DWORD *len)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
UInt32 i;
|
||||||
|
UInt32 cred_blob_len;
|
||||||
|
void *cred_blob;
|
||||||
|
LPWSTR domain = NULL;
|
||||||
|
LPWSTR user = NULL;
|
||||||
|
SecKeychainAttributeInfo info;
|
||||||
|
SecKeychainAttributeList *attr_list;
|
||||||
|
UInt32 info_tags[] = { kSecServerItemAttr, kSecSecurityDomainItemAttr, kSecAccountItemAttr,
|
||||||
|
kSecCommentItemAttr, kSecCreationDateItemAttr };
|
||||||
|
info.count = sizeof(info_tags)/sizeof(info_tags[0]);
|
||||||
|
info.tag = info_tags;
|
||||||
|
info.format = NULL;
|
||||||
|
status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, &cred_blob);
|
||||||
|
if (status == errSecAuthFailed && !require_password)
|
||||||
|
{
|
||||||
|
cred_blob_len = 0;
|
||||||
|
cred_blob = NULL;
|
||||||
|
status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, &cred_blob_len, NULL);
|
||||||
|
}
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
|
||||||
|
return ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
credential->Flags = 0;
|
||||||
|
credential->Type = CRED_TYPE_DOMAIN_PASSWORD;
|
||||||
|
credential->TargetName = NULL;
|
||||||
|
credential->Comment = NULL;
|
||||||
|
memset(&credential->LastWritten, 0, sizeof(credential->LastWritten));
|
||||||
|
credential->CredentialBlobSize = 0;
|
||||||
|
credential->CredentialBlob = NULL;
|
||||||
|
credential->Persist = CRED_PERSIST_LOCAL_MACHINE;
|
||||||
|
credential->AttributeCount = 0;
|
||||||
|
credential->Attributes = NULL;
|
||||||
|
credential->TargetAlias = NULL;
|
||||||
|
credential->UserName = NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i < attr_list->count; i++)
|
||||||
|
{
|
||||||
|
switch (attr_list->attr[i].tag)
|
||||||
|
{
|
||||||
|
case kSecServerItemAttr:
|
||||||
|
TRACE("kSecServerItemAttr: %.*s\n", (int)attr_list->attr[i].length,
|
||||||
|
(char *)attr_list->attr[i].data);
|
||||||
|
if (!attr_list->attr[i].data) continue;
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
credential->TargetName = (LPWSTR)buffer;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
|
||||||
|
credential->TargetName[str_len] = '\0';
|
||||||
|
buffer += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
*len += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, NULL, 0);
|
||||||
|
*len += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kSecAccountItemAttr:
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
TRACE("kSecAccountItemAttr: %.*s\n", (int)attr_list->attr[i].length,
|
||||||
|
(char *)attr_list->attr[i].data);
|
||||||
|
if (!attr_list->attr[i].data) continue;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, NULL, 0);
|
||||||
|
user = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, user, str_len);
|
||||||
|
user[str_len] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kSecCommentItemAttr:
|
||||||
|
TRACE("kSecCommentItemAttr: %.*s\n", (int)attr_list->attr[i].length,
|
||||||
|
(char *)attr_list->attr[i].data);
|
||||||
|
if (!attr_list->attr[i].data) continue;
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
credential->Comment = (LPWSTR)buffer;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, (LPWSTR)buffer, 0xffff);
|
||||||
|
credential->Comment[str_len] = '\0';
|
||||||
|
buffer += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
*len += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, NULL, 0);
|
||||||
|
*len += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kSecSecurityDomainItemAttr:
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
TRACE("kSecSecurityDomainItemAttr: %.*s\n", (int)attr_list->attr[i].length,
|
||||||
|
(char *)attr_list->attr[i].data);
|
||||||
|
if (!attr_list->attr[i].data) continue;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, NULL, 0);
|
||||||
|
domain = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[i].data,
|
||||||
|
attr_list->attr[i].length, domain, str_len);
|
||||||
|
domain[str_len] = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kSecCreationDateItemAttr:
|
||||||
|
TRACE("kSecCreationDateItemAttr: %.*s\n", (int)attr_list->attr[i].length,
|
||||||
|
(char *)attr_list->attr[i].data);
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER win_time;
|
||||||
|
struct tm tm;
|
||||||
|
time_t time;
|
||||||
|
memset(&tm, 0, sizeof(tm));
|
||||||
|
strptime(attr_list->attr[i].data, "%Y%m%d%H%M%SZ", &tm);
|
||||||
|
time = mktime(&tm);
|
||||||
|
RtlSecondsSince1970ToTime(time, &win_time);
|
||||||
|
credential->LastWritten.dwLowDateTime = win_time.u.LowPart;
|
||||||
|
credential->LastWritten.dwHighDateTime = win_time.u.HighPart;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user)
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
if (buffer)
|
||||||
|
credential->UserName = (LPWSTR)buffer;
|
||||||
|
if (domain)
|
||||||
|
{
|
||||||
|
str_len = strlenW(domain);
|
||||||
|
*len += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
memcpy(credential->UserName, domain, str_len * sizeof(WCHAR));
|
||||||
|
/* FIXME: figure out when to use an '@' */
|
||||||
|
credential->UserName[str_len] = '\\';
|
||||||
|
buffer += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str_len = strlenW(user);
|
||||||
|
*len += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
memcpy(buffer, user, (str_len + 1) * sizeof(WCHAR));
|
||||||
|
buffer += (str_len + 1) * sizeof(WCHAR);
|
||||||
|
TRACE("UserName = %s\n", debugstr_w(credential->UserName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, user);
|
||||||
|
HeapFree(GetProcessHeap(), 0, domain);
|
||||||
|
|
||||||
|
if (cred_blob)
|
||||||
|
{
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
credential->CredentialBlob = (BYTE *)buffer;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
|
||||||
|
(LPWSTR)buffer, 0xffff);
|
||||||
|
credential->CredentialBlobSize = str_len * sizeof(WCHAR);
|
||||||
|
buffer += str_len * sizeof(WCHAR);
|
||||||
|
*len += str_len * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
INT str_len;
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, cred_blob, cred_blob_len,
|
||||||
|
NULL, 0);
|
||||||
|
*len += str_len * sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SecKeychainItemFreeAttributesAndData(attr_list, cred_blob);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
|
static DWORD write_credential_blob(HKEY hkey, LPCWSTR target_name, DWORD type,
|
||||||
const BYTE key_data[KEY_SIZE],
|
const BYTE key_data[KEY_SIZE],
|
||||||
const BYTE *credential_blob, DWORD credential_blob_size)
|
const BYTE *credential_blob, DWORD credential_blob_size)
|
||||||
|
@ -309,6 +510,116 @@ static DWORD registry_write_credential(HKEY hkey, const CREDENTIALW *credential,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static DWORD mac_write_credential(const CREDENTIALW *credential, BOOL preserve_blob)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
SecKeychainItemRef keychain_item;
|
||||||
|
char *username;
|
||||||
|
char *domain = NULL;
|
||||||
|
char *password;
|
||||||
|
char *servername;
|
||||||
|
UInt32 userlen;
|
||||||
|
UInt32 domainlen = 0;
|
||||||
|
UInt32 pwlen;
|
||||||
|
UInt32 serverlen;
|
||||||
|
LPCWSTR p;
|
||||||
|
SecKeychainAttribute attrs[1];
|
||||||
|
SecKeychainAttributeList attr_list;
|
||||||
|
|
||||||
|
if (credential->Flags)
|
||||||
|
FIXME("Flags 0x%x not written\n", credential->Flags);
|
||||||
|
if (credential->Type != CRED_TYPE_DOMAIN_PASSWORD)
|
||||||
|
FIXME("credential type of %d not supported\n", credential->Type);
|
||||||
|
if (credential->Persist != CRED_PERSIST_LOCAL_MACHINE)
|
||||||
|
FIXME("persist value of %d not supported\n", credential->Persist);
|
||||||
|
if (credential->AttributeCount)
|
||||||
|
FIXME("custom attributes not supported\n");
|
||||||
|
|
||||||
|
p = strchrW(credential->UserName, '\\');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
domainlen = WideCharToMultiByte(CP_UTF8, 0, credential->UserName,
|
||||||
|
p - credential->UserName, NULL, 0, NULL, NULL);
|
||||||
|
domain = HeapAlloc(GetProcessHeap(), 0, (domainlen + 1) * sizeof(*domain));
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, credential->UserName, p - credential->UserName,
|
||||||
|
domain, domainlen, NULL, NULL);
|
||||||
|
domain[domainlen] = '\0';
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p = credential->UserName;
|
||||||
|
userlen = WideCharToMultiByte(CP_UTF8, 0, p, -1, NULL, 0, NULL, NULL);
|
||||||
|
username = HeapAlloc(GetProcessHeap(), 0, userlen * sizeof(*username));
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, p, -1, username, userlen, NULL, NULL);
|
||||||
|
|
||||||
|
serverlen = WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, NULL, 0, NULL, NULL);
|
||||||
|
servername = HeapAlloc(GetProcessHeap(), 0, serverlen * sizeof(*servername));
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, credential->TargetName, -1, servername, serverlen, NULL, NULL);
|
||||||
|
pwlen = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
|
||||||
|
credential->CredentialBlobSize / sizeof(WCHAR), NULL, 0, NULL, NULL);
|
||||||
|
password = HeapAlloc(GetProcessHeap(), 0, pwlen * sizeof(*domain));
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)credential->CredentialBlob,
|
||||||
|
credential->CredentialBlobSize / sizeof(WCHAR), password, pwlen, NULL, NULL);
|
||||||
|
|
||||||
|
TRACE("adding server %s, domain %s, username %s using Keychain\n", servername, domain, username);
|
||||||
|
status = SecKeychainAddInternetPassword(NULL, strlen(servername), servername,
|
||||||
|
strlen(domain), domain, strlen(username),
|
||||||
|
username, 0, NULL, 0,
|
||||||
|
0 /* no protocol */,
|
||||||
|
kSecAuthenticationTypeDefault,
|
||||||
|
strlen(password), password, &keychain_item);
|
||||||
|
if (status != noErr)
|
||||||
|
ERR("SecKeychainAddInternetPassword returned %ld\n", status);
|
||||||
|
if (status == errSecDuplicateItem)
|
||||||
|
{
|
||||||
|
SecKeychainItemRef keychain_item;
|
||||||
|
|
||||||
|
status = SecKeychainFindInternetPassword(NULL, strlen(servername), servername,
|
||||||
|
strlen(domain), domain,
|
||||||
|
strlen(username), username,
|
||||||
|
0, NULL /* any path */, 0,
|
||||||
|
0 /* any protocol */,
|
||||||
|
0 /* any authentication type */,
|
||||||
|
0, NULL, &keychain_item);
|
||||||
|
if (status != noErr)
|
||||||
|
ERR("SecKeychainFindInternetPassword returned %ld\n", status);
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, domain);
|
||||||
|
HeapFree(GetProcessHeap(), 0, username);
|
||||||
|
HeapFree(GetProcessHeap(), 0, servername);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, password);
|
||||||
|
return ERROR_GEN_FAILURE;
|
||||||
|
}
|
||||||
|
if (credential->Comment)
|
||||||
|
{
|
||||||
|
attr_list.count = 1;
|
||||||
|
attr_list.attr = attrs;
|
||||||
|
attrs[0].tag = kSecCommentItemAttr;
|
||||||
|
attrs[0].length = WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, NULL, 0, NULL, NULL);
|
||||||
|
if (attrs[0].length) attrs[0].length--;
|
||||||
|
attrs[0].data = HeapAlloc(GetProcessHeap(), 0, attrs[0].length);
|
||||||
|
WideCharToMultiByte(CP_UTF8, 0, credential->Comment, -1, attrs[0].data, attrs[0].length, NULL, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
attr_list.count = 0;
|
||||||
|
attr_list.attr = NULL;
|
||||||
|
}
|
||||||
|
status = SecKeychainItemModifyAttributesAndData(keychain_item, &attr_list,
|
||||||
|
preserve_blob ? 0 : strlen(password),
|
||||||
|
preserve_blob ? NULL : password);
|
||||||
|
if (credential->Comment)
|
||||||
|
HeapFree(GetProcessHeap(), 0, attrs[0].data);
|
||||||
|
HeapFree(GetProcessHeap(), 0, password);
|
||||||
|
/* FIXME: set TargetAlias attribute */
|
||||||
|
CFRelease(keychain_item);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
|
static DWORD open_cred_mgr_key(HKEY *hkey, BOOL open_for_write)
|
||||||
{
|
{
|
||||||
return RegCreateKeyExW(HKEY_CURRENT_USER, wszCredentialManagerKey, 0,
|
return RegCreateKeyExW(HKEY_CURRENT_USER, wszCredentialManagerKey, 0,
|
||||||
|
@ -426,7 +737,7 @@ static BOOL credential_matches_filter(HKEY hkeyCred, LPCWSTR filter)
|
||||||
static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
|
static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
|
||||||
LPWSTR target_name,
|
LPWSTR target_name,
|
||||||
DWORD target_name_len, BYTE key_data[KEY_SIZE],
|
DWORD target_name_len, BYTE key_data[KEY_SIZE],
|
||||||
PCREDENTIALW *credentials, char *buffer,
|
PCREDENTIALW *credentials, char **buffer,
|
||||||
DWORD *len, DWORD *count)
|
DWORD *len, DWORD *count)
|
||||||
{
|
{
|
||||||
DWORD i;
|
DWORD i;
|
||||||
|
@ -460,21 +771,135 @@ static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
|
||||||
if (buffer)
|
if (buffer)
|
||||||
{
|
{
|
||||||
*len = sizeof(CREDENTIALW);
|
*len = sizeof(CREDENTIALW);
|
||||||
credentials[*count] = (PCREDENTIALW)buffer;
|
credentials[*count] = (PCREDENTIALW)*buffer;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
*len += sizeof(CREDENTIALW);
|
*len += sizeof(CREDENTIALW);
|
||||||
ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
|
ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
|
||||||
key_data, buffer ? buffer + sizeof(CREDENTIALW) : NULL,
|
key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL,
|
||||||
len);
|
len);
|
||||||
RegCloseKey(hkeyCred);
|
RegCloseKey(hkeyCred);
|
||||||
if (ret != ERROR_SUCCESS) break;
|
if (ret != ERROR_SUCCESS) break;
|
||||||
if (buffer) buffer += *len;
|
if (buffer) *buffer += *len;
|
||||||
(*count)++;
|
(*count)++;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
static DWORD mac_enumerate_credentials(LPCWSTR filter, PCREDENTIALW *credentials,
|
||||||
|
char *buffer, DWORD *len, DWORD *count)
|
||||||
|
{
|
||||||
|
SecKeychainSearchRef search;
|
||||||
|
SecKeychainItemRef item;
|
||||||
|
OSStatus status;
|
||||||
|
Boolean saved_user_interaction_allowed;
|
||||||
|
DWORD ret;
|
||||||
|
|
||||||
|
SecKeychainGetUserInteractionAllowed(&saved_user_interaction_allowed);
|
||||||
|
SecKeychainSetUserInteractionAllowed(false);
|
||||||
|
|
||||||
|
status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
|
||||||
|
if (status == noErr)
|
||||||
|
{
|
||||||
|
while (SecKeychainSearchCopyNext(search, &item) == noErr)
|
||||||
|
{
|
||||||
|
SecKeychainAttributeInfo info;
|
||||||
|
SecKeychainAttributeList *attr_list;
|
||||||
|
UInt32 info_tags[] = { kSecServerItemAttr };
|
||||||
|
info.count = sizeof(info_tags)/sizeof(info_tags[0]);
|
||||||
|
info.tag = info_tags;
|
||||||
|
info.format = NULL;
|
||||||
|
status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (buffer)
|
||||||
|
{
|
||||||
|
*len = sizeof(CREDENTIALW);
|
||||||
|
credentials[*count] = (PCREDENTIALW)buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*len += sizeof(CREDENTIALW);
|
||||||
|
if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr) continue;
|
||||||
|
TRACE("server item: %.*s\n", (int)attr_list->attr[0].length, (char *)attr_list->attr[0].data);
|
||||||
|
/* FIXME: filter based on attr_list->attr[0].data */
|
||||||
|
SecKeychainItemFreeAttributesAndData(attr_list, NULL);
|
||||||
|
ret = mac_read_credential_from_item(item, FALSE,
|
||||||
|
buffer ? credentials[*count] : NULL,
|
||||||
|
buffer ? buffer + sizeof(CREDENTIALW) : NULL,
|
||||||
|
len);
|
||||||
|
CFRelease(item);
|
||||||
|
if (ret == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
(*count)++;
|
||||||
|
if (buffer) buffer += *len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(search);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR("SecKeychainSearchCreateFromAttributes returned status %ld\n", status);
|
||||||
|
SecKeychainSetUserInteractionAllowed(saved_user_interaction_allowed);
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD mac_delete_credential(LPCWSTR TargetName)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
SecKeychainSearchRef search;
|
||||||
|
status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
|
||||||
|
if (status == noErr)
|
||||||
|
{
|
||||||
|
SecKeychainItemRef item;
|
||||||
|
while (SecKeychainSearchCopyNext(search, &item) == noErr)
|
||||||
|
{
|
||||||
|
SecKeychainAttributeInfo info;
|
||||||
|
SecKeychainAttributeList *attr_list;
|
||||||
|
UInt32 info_tags[] = { kSecServerItemAttr };
|
||||||
|
LPWSTR target_name;
|
||||||
|
INT str_len;
|
||||||
|
info.count = sizeof(info_tags)/sizeof(info_tags[0]);
|
||||||
|
info.tag = info_tags;
|
||||||
|
info.format = NULL;
|
||||||
|
status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr)
|
||||||
|
{
|
||||||
|
CFRelease(item);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
|
||||||
|
target_name = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
|
||||||
|
/* nul terminate */
|
||||||
|
target_name[str_len] = '\0';
|
||||||
|
if (strcmpiW(TargetName, target_name))
|
||||||
|
{
|
||||||
|
CFRelease(item);
|
||||||
|
HeapFree(GetProcessHeap(), 0, target_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, target_name);
|
||||||
|
SecKeychainItemFreeAttributesAndData(attr_list, NULL);
|
||||||
|
SecKeychainItemDelete(item);
|
||||||
|
CFRelease(item);
|
||||||
|
CFRelease(search);
|
||||||
|
|
||||||
|
return ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
CFRelease(search);
|
||||||
|
}
|
||||||
|
return ERROR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD *len)
|
static void convert_PCREDENTIALW_to_PCREDENTIALA(const CREDENTIALW *CredentialW, PCREDENTIALA CredentialA, DWORD *len)
|
||||||
{
|
{
|
||||||
char *buffer = (char *)CredentialA + sizeof(CREDENTIALA);
|
char *buffer = (char *)CredentialA + sizeof(CREDENTIALA);
|
||||||
|
@ -683,6 +1108,15 @@ BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (Type == CRED_TYPE_DOMAIN_PASSWORD)
|
||||||
|
{
|
||||||
|
ret = mac_delete_credential(TargetName);
|
||||||
|
if (ret == ERROR_SUCCESS)
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ret = open_cred_mgr_key(&hkeyMgr, TRUE);
|
ret = open_cred_mgr_key(&hkeyMgr, TRUE);
|
||||||
if (ret != ERROR_SUCCESS)
|
if (ret != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
@ -823,6 +1257,10 @@ BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
|
||||||
len = 0;
|
len = 0;
|
||||||
ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
|
ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
|
||||||
key_data, NULL, NULL, &len, Count);
|
key_data, NULL, NULL, &len, Count);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (ret == ERROR_SUCCESS)
|
||||||
|
ret = mac_enumerate_credentials(Filter, NULL, NULL, &len, Count);
|
||||||
|
#endif
|
||||||
if (ret == ERROR_SUCCESS && *Count == 0)
|
if (ret == ERROR_SUCCESS && *Count == 0)
|
||||||
ret = ERROR_NOT_FOUND;
|
ret = ERROR_NOT_FOUND;
|
||||||
if (ret != ERROR_SUCCESS)
|
if (ret != ERROR_SUCCESS)
|
||||||
|
@ -844,8 +1282,13 @@ BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
|
||||||
*Count = 0;
|
*Count = 0;
|
||||||
ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name,
|
ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name,
|
||||||
target_name_len, key_data,
|
target_name_len, key_data,
|
||||||
*Credentials, buffer, &len,
|
*Credentials, &buffer, &len,
|
||||||
Count);
|
Count);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (ret == ERROR_SUCCESS)
|
||||||
|
ret = mac_enumerate_credentials(Filter, *Credentials,
|
||||||
|
buffer, &len, Count);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ret = ERROR_OUTOFMEMORY;
|
ret = ERROR_OUTOFMEMORY;
|
||||||
|
@ -953,6 +1396,78 @@ BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (Type == CRED_TYPE_DOMAIN_PASSWORD)
|
||||||
|
{
|
||||||
|
OSStatus status;
|
||||||
|
SecKeychainSearchRef search;
|
||||||
|
status = SecKeychainSearchCreateFromAttributes(NULL, kSecInternetPasswordItemClass, NULL, &search);
|
||||||
|
if (status == noErr)
|
||||||
|
{
|
||||||
|
SecKeychainItemRef item;
|
||||||
|
while (SecKeychainSearchCopyNext(search, &item) == noErr)
|
||||||
|
{
|
||||||
|
SecKeychainAttributeInfo info;
|
||||||
|
SecKeychainAttributeList *attr_list;
|
||||||
|
UInt32 info_tags[] = { kSecServerItemAttr };
|
||||||
|
LPWSTR target_name;
|
||||||
|
INT str_len;
|
||||||
|
info.count = sizeof(info_tags)/sizeof(info_tags[0]);
|
||||||
|
info.tag = info_tags;
|
||||||
|
info.format = NULL;
|
||||||
|
status = SecKeychainItemCopyAttributesAndData(item, &info, NULL, &attr_list, NULL, NULL);
|
||||||
|
len = sizeof(**Credential);
|
||||||
|
if (status != noErr)
|
||||||
|
{
|
||||||
|
WARN("SecKeychainItemCopyAttributesAndData returned status %ld\n", status);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (attr_list->count != 1 || attr_list->attr[0].tag != kSecServerItemAttr)
|
||||||
|
{
|
||||||
|
CFRelease(item);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
str_len = MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, NULL, 0);
|
||||||
|
target_name = HeapAlloc(GetProcessHeap(), 0, (str_len + 1) * sizeof(WCHAR));
|
||||||
|
MultiByteToWideChar(CP_UTF8, 0, attr_list->attr[0].data, attr_list->attr[0].length, target_name, str_len);
|
||||||
|
/* nul terminate */
|
||||||
|
target_name[str_len] = '\0';
|
||||||
|
if (strcmpiW(TargetName, target_name))
|
||||||
|
{
|
||||||
|
CFRelease(item);
|
||||||
|
HeapFree(GetProcessHeap(), 0, target_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, target_name);
|
||||||
|
SecKeychainItemFreeAttributesAndData(attr_list, NULL);
|
||||||
|
ret = mac_read_credential_from_item(item, TRUE, NULL, NULL, &len);
|
||||||
|
if (ret == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
*Credential = HeapAlloc(GetProcessHeap(), 0, len);
|
||||||
|
if (*Credential)
|
||||||
|
{
|
||||||
|
len = sizeof(**Credential);
|
||||||
|
ret = mac_read_credential_from_item(item, TRUE, *Credential,
|
||||||
|
(char *)(*Credential + 1), &len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = ERROR_OUTOFMEMORY;
|
||||||
|
CFRelease(item);
|
||||||
|
CFRelease(search);
|
||||||
|
if (ret != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
SetLastError(ret);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
CFRelease(item);
|
||||||
|
}
|
||||||
|
CFRelease(search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ret = open_cred_mgr_key(&hkeyMgr, FALSE);
|
ret = open_cred_mgr_key(&hkeyMgr, FALSE);
|
||||||
if (ret != ERROR_SUCCESS)
|
if (ret != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
@ -1087,6 +1602,21 @@ BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
if (!Credential->AttributeCount &&
|
||||||
|
Credential->Type == CRED_TYPE_DOMAIN_PASSWORD &&
|
||||||
|
(Credential->Persist == CRED_PERSIST_LOCAL_MACHINE || Credential->Persist == CRED_PERSIST_ENTERPRISE))
|
||||||
|
{
|
||||||
|
ret = mac_write_credential(Credential, Flags & CRED_PRESERVE_CREDENTIAL_BLOB);
|
||||||
|
if (ret != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
SetLastError(ret);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ret = open_cred_mgr_key(&hkeyMgr, FALSE);
|
ret = open_cred_mgr_key(&hkeyMgr, FALSE);
|
||||||
if (ret != ERROR_SUCCESS)
|
if (ret != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue