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
|
||||
DLLWRAP
|
||||
MINGWAR
|
||||
SECURITYLIB
|
||||
COREFOUNDATIONLIB
|
||||
IOKITLIB
|
||||
LDEXECFLAGS
|
||||
|
@ -8093,6 +8094,8 @@ fi
|
|||
LDSHARED="\$(CC) -dynamiclib"
|
||||
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) \$@"
|
||||
SECURITYLIB="-framework Security -framework CoreFoundation"
|
||||
|
||||
COREFOUNDATIONLIB="-framework CoreFoundation"
|
||||
|
||||
IOKITLIB="-framework IOKit -framework CoreFoundation"
|
||||
|
@ -22414,6 +22417,7 @@ LDD!$LDD$ac_delim
|
|||
DLLTOOL!$DLLTOOL$ac_delim
|
||||
DLLWRAP!$DLLWRAP$ac_delim
|
||||
MINGWAR!$MINGWAR$ac_delim
|
||||
SECURITYLIB!$SECURITYLIB$ac_delim
|
||||
COREFOUNDATIONLIB!$COREFOUNDATIONLIB$ac_delim
|
||||
IOKITLIB!$IOKITLIB$ac_delim
|
||||
LDEXECFLAGS!$LDEXECFLAGS$ac_delim
|
||||
|
@ -22462,7 +22466,7 @@ LIBOBJS!$LIBOBJS$ac_delim
|
|||
LTLIBOBJS!$LTLIBOBJS$ac_delim
|
||||
_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
|
||||
elif $ac_last_try; then
|
||||
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
|
||||
|
|
|
@ -388,6 +388,7 @@ case $host_os in
|
|||
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) \$@"
|
||||
dnl declare needed frameworks
|
||||
AC_SUBST(SECURITYLIB,"-framework Security -framework CoreFoundation")
|
||||
AC_SUBST(COREFOUNDATIONLIB,"-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"])
|
||||
|
|
|
@ -6,6 +6,7 @@ VPATH = @srcdir@
|
|||
MODULE = advapi32.dll
|
||||
IMPORTLIB = libadvapi32.$(IMPLIBEXT)
|
||||
IMPORTS = kernel32 ntdll
|
||||
EXTRALIBS = @SECURITYLIB@
|
||||
|
||||
C_SRCS = \
|
||||
advapi.c \
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
|
@ -26,6 +27,12 @@
|
|||
#include "wincred.h"
|
||||
#include "winternl.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <Security/SecKeychain.h>
|
||||
# include <Security/SecKeychainItem.h>
|
||||
# include <Security/SecKeychainSearch.h>
|
||||
#endif
|
||||
|
||||
#include "crypt.h"
|
||||
|
||||
#include "wine/unicode.h"
|
||||
|
@ -232,6 +239,200 @@ static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential,
|
|||
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,
|
||||
const BYTE key_data[KEY_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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
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,
|
||||
LPWSTR target_name,
|
||||
DWORD target_name_len, BYTE key_data[KEY_SIZE],
|
||||
PCREDENTIALW *credentials, char *buffer,
|
||||
PCREDENTIALW *credentials, char **buffer,
|
||||
DWORD *len, DWORD *count)
|
||||
{
|
||||
DWORD i;
|
||||
|
@ -460,21 +771,135 @@ static DWORD registry_enumerate_credentials(HKEY hkeyMgr, LPCWSTR filter,
|
|||
if (buffer)
|
||||
{
|
||||
*len = sizeof(CREDENTIALW);
|
||||
credentials[*count] = (PCREDENTIALW)buffer;
|
||||
credentials[*count] = (PCREDENTIALW)*buffer;
|
||||
}
|
||||
else
|
||||
*len += sizeof(CREDENTIALW);
|
||||
ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL,
|
||||
key_data, buffer ? buffer + sizeof(CREDENTIALW) : NULL,
|
||||
key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL,
|
||||
len);
|
||||
RegCloseKey(hkeyCred);
|
||||
if (ret != ERROR_SUCCESS) break;
|
||||
if (buffer) buffer += *len;
|
||||
if (buffer) *buffer += *len;
|
||||
(*count)++;
|
||||
}
|
||||
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)
|
||||
{
|
||||
char *buffer = (char *)CredentialA + sizeof(CREDENTIALA);
|
||||
|
@ -683,6 +1108,15 @@ BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags)
|
|||
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);
|
||||
if (ret != ERROR_SUCCESS)
|
||||
{
|
||||
|
@ -823,6 +1257,10 @@ BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
|
|||
len = 0;
|
||||
ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, target_name_len,
|
||||
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)
|
||||
ret = ERROR_NOT_FOUND;
|
||||
if (ret != ERROR_SUCCESS)
|
||||
|
@ -844,8 +1282,13 @@ BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count,
|
|||
*Count = 0;
|
||||
ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name,
|
||||
target_name_len, key_data,
|
||||
*Credentials, buffer, &len,
|
||||
*Credentials, &buffer, &len,
|
||||
Count);
|
||||
#ifdef __APPLE__
|
||||
if (ret == ERROR_SUCCESS)
|
||||
ret = mac_enumerate_credentials(Filter, *Credentials,
|
||||
buffer, &len, Count);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ret = ERROR_OUTOFMEMORY;
|
||||
|
@ -953,6 +1396,78 @@ BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW
|
|||
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);
|
||||
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);
|
||||
if (ret != ERROR_SUCCESS)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue