Author: dchapyshev Date: Tue Aug 5 09:45:40 2008 New Revision: 35127
URL: http://svn.reactos.org/svn/reactos?rev=35127&view=rev Log: - Add cred.c from Wine
Added: trunk/reactos/dll/win32/advapi32/sec/cred.c (with props) Modified: trunk/reactos/dll/win32/advapi32/advapi32.def trunk/reactos/dll/win32/advapi32/advapi32.rbuild trunk/reactos/dll/win32/advapi32/crypt/crypt.h
Modified: trunk/reactos/dll/win32/advapi32/advapi32.def URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/advapi32... ============================================================================== --- trunk/reactos/dll/win32/advapi32/advapi32.def [iso-8859-1] (original) +++ trunk/reactos/dll/win32/advapi32/advapi32.def [iso-8859-1] Tue Aug 5 09:45:40 2008 @@ -112,12 +112,12 @@ CreateServiceW@52 ;CreateTraceInstanceId@8 CreateWellKnownSid@16 -;CredDeleteA@12 -;CredDeleteW@12 -;CredEnumerateA@16 -;CredEnumerateW@16 -;CredFree@4 -;CredGetSessionTypes@8 +CredDeleteA@12 +CredDeleteW@12 +CredEnumerateA@16 +CredEnumerateW@16 +CredFree@4 +CredGetSessionTypes@8 ;CredGetTargetInfoA@12 ;CredGetTargetInfoW@12 ;CredIsMarshaledCredentialA@4 @@ -125,18 +125,18 @@ ;CredMarshalCredentialA@12 ;CredMarshalCredentialW@12 ;CredProfileLoaded -;CredReadA +CredReadA ;CredReadDomainCredentialsA ;CredReadDomainCredentialsW -;CredReadW +CredReadW ;CredRenameA ;CredRenameW ;CredUnmarshalCredentialA ;CredUnmarshalCredentialW -;CredWriteA +CredWriteA ;CredWriteDomainCredentialsA ;CredWriteDomainCredentialsW -;CredWriteW +CredWriteW ;CredpConvertCredential ;CredpConvertTargetInfo ;CredpDecodeCredential
Modified: trunk/reactos/dll/win32/advapi32/advapi32.rbuild URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/advapi32... ============================================================================== --- trunk/reactos/dll/win32/advapi32/advapi32.rbuild [iso-8859-1] (original) +++ trunk/reactos/dll/win32/advapi32/advapi32.rbuild [iso-8859-1] Tue Aug 5 09:45:40 2008 @@ -41,6 +41,7 @@ <directory name="sec"> <file>ac.c</file> <file>audit.c</file> + <file>cred.c</file> <file>lsa.c</file> <file>misc.c</file> <file>sec.c</file>
Modified: trunk/reactos/dll/win32/advapi32/crypt/crypt.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/crypt/cr... ============================================================================== --- trunk/reactos/dll/win32/advapi32/crypt/crypt.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/advapi32/crypt/crypt.h [iso-8859-1] Tue Aug 5 09:45:40 2008 @@ -113,6 +113,7 @@ VOID WINAPI MD4Final(MD4_CTX *ctx); void arc4_init(arc4_info *a4i, const BYTE *key, unsigned int keyLen); void arc4_ProcessString(arc4_info *a4i, BYTE *inoutString, unsigned int length); +NTSTATUS WINAPI SystemFunction032(struct ustring *data, struct ustring *key);
#endif /* __WINE_CRYPT_H_ */
Added: trunk/reactos/dll/win32/advapi32/sec/cred.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/advapi32/sec/cred... ============================================================================== --- trunk/reactos/dll/win32/advapi32/sec/cred.c (added) +++ trunk/reactos/dll/win32/advapi32/sec/cred.c [iso-8859-1] Tue Aug 5 09:45:40 2008 @@ -1,0 +1,1705 @@ +/* + * Credential Management APIs + * + * Copyright 2007 Robert Shearman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <time.h> + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wincred.h" +#include "winternl.h" + +#ifdef __APPLE__ +# include <Security/SecKeychain.h> +# include <Security/SecKeychainItem.h> +# include <Security/SecKeychainSearch.h> +#endif + +#include "../crypt/crypt.h" + +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(cred); + +/* the size of the ARC4 key used to encrypt the password data */ +#define KEY_SIZE 8 + +static const WCHAR wszCredentialManagerKey[] = {'S','o','f','t','w','a','r','e','\','W','i','n','e','\', + 'C','r','e','d','e','n','t','i','a','l',' ','M','a','n','a','g','e','r',0}; +static const WCHAR wszEncryptionKeyValue[] = {'E','n','c','r','y','p','t','i','o','n','K','e','y',0}; + +static const WCHAR wszFlagsValue[] = {'F','l','a','g','s',0}; +static const WCHAR wszTypeValue[] = {'T','y','p','e',0}; +static const WCHAR wszCommentValue[] = {'C','o','m','m','e','n','t',0}; +static const WCHAR wszLastWrittenValue[] = {'L','a','s','t','W','r','i','t','t','e','n',0}; +static const WCHAR wszPersistValue[] = {'P','e','r','s','i','s','t',0}; +static const WCHAR wszTargetAliasValue[] = {'T','a','r','g','e','t','A','l','i','a','s',0}; +static const WCHAR wszUserNameValue[] = {'U','s','e','r','N','a','m','e',0}; +static const WCHAR wszPasswordValue[] = {'P','a','s','s','w','o','r','d',0}; + +static DWORD read_credential_blob(HKEY hkey, const BYTE key_data[KEY_SIZE], + LPBYTE credential_blob, + DWORD *credential_blob_size) +{ + DWORD ret; + DWORD type; + + *credential_blob_size = 0; + ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, NULL, credential_blob_size); + if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_BINARY) + return ERROR_REGISTRY_CORRUPT; + if (credential_blob) + { + struct ustring data; + struct ustring key; + + ret = RegQueryValueExW(hkey, wszPasswordValue, 0, &type, (LPVOID)credential_blob, + credential_blob_size); + if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_BINARY) + return ERROR_REGISTRY_CORRUPT; + + key.Length = key.MaximumLength = KEY_SIZE; + key.Buffer = (unsigned char *)key_data; + + data.Length = data.MaximumLength = *credential_blob_size; + data.Buffer = credential_blob; + SystemFunction032(&data, &key); + } + return ERROR_SUCCESS; +} + +static DWORD registry_read_credential(HKEY hkey, PCREDENTIALW credential, + const BYTE key_data[KEY_SIZE], + char *buffer, DWORD *len) +{ + DWORD type; + DWORD ret; + DWORD count; + + ret = RegQueryValueExW(hkey, NULL, 0, &type, NULL, &count); + if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_SZ) + return ERROR_REGISTRY_CORRUPT; + *len += count; + if (credential) + { + credential->TargetName = (LPWSTR)buffer; + ret = RegQueryValueExW(hkey, NULL, 0, &type, (LPVOID)credential->TargetName, + &count); + if (ret != ERROR_SUCCESS || type != REG_SZ) return ret; + buffer += count; + } + + ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, NULL, &count); + if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS) + return ret; + else if (type != REG_SZ) + return ERROR_REGISTRY_CORRUPT; + *len += count; + if (credential) + { + credential->Comment = (LPWSTR)buffer; + ret = RegQueryValueExW(hkey, wszCommentValue, 0, &type, (LPVOID)credential->Comment, + &count); + if (ret == ERROR_FILE_NOT_FOUND) + credential->Comment = NULL; + else if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_SZ) + return ERROR_REGISTRY_CORRUPT; + else + buffer += count; + } + + ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, NULL, &count); + if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS) + return ret; + else if (type != REG_SZ) + return ERROR_REGISTRY_CORRUPT; + *len += count; + if (credential) + { + credential->TargetAlias = (LPWSTR)buffer; + ret = RegQueryValueExW(hkey, wszTargetAliasValue, 0, &type, (LPVOID)credential->TargetAlias, + &count); + if (ret == ERROR_FILE_NOT_FOUND) + credential->TargetAlias = NULL; + else if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_SZ) + return ERROR_REGISTRY_CORRUPT; + else + buffer += count; + } + + ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, NULL, &count); + if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS) + return ret; + else if (type != REG_SZ) + return ERROR_REGISTRY_CORRUPT; + *len += count; + if (credential) + { + credential->UserName = (LPWSTR)buffer; + ret = RegQueryValueExW(hkey, wszUserNameValue, 0, &type, (LPVOID)credential->UserName, + &count); + if (ret == ERROR_FILE_NOT_FOUND) + { + credential->UserName = NULL; + ret = ERROR_SUCCESS; + } + else if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_SZ) + return ERROR_REGISTRY_CORRUPT; + else + buffer += count; + } + + ret = read_credential_blob(hkey, key_data, NULL, &count); + if (ret != ERROR_FILE_NOT_FOUND && ret != ERROR_SUCCESS) + return ret; + *len += count; + if (credential) + { + credential->CredentialBlob = (LPBYTE)buffer; + ret = read_credential_blob(hkey, key_data, credential->CredentialBlob, &count); + if (ret == ERROR_FILE_NOT_FOUND) + { + credential->CredentialBlob = NULL; + ret = ERROR_SUCCESS; + } + else if (ret != ERROR_SUCCESS) + return ret; + credential->CredentialBlobSize = count; + buffer += count; + } + + /* FIXME: Attributes */ + if (credential) + { + credential->AttributeCount = 0; + credential->Attributes = NULL; + } + + if (!credential) return ERROR_SUCCESS; + + count = sizeof(credential->Flags); + ret = RegQueryValueExW(hkey, wszFlagsValue, NULL, &type, (LPVOID)&credential->Flags, + &count); + if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_DWORD) + return ERROR_REGISTRY_CORRUPT; + count = sizeof(credential->Type); + ret = RegQueryValueExW(hkey, wszTypeValue, NULL, &type, (LPVOID)&credential->Type, + &count); + if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_DWORD) + return ERROR_REGISTRY_CORRUPT; + + count = sizeof(credential->LastWritten); + ret = RegQueryValueExW(hkey, wszLastWrittenValue, NULL, &type, (LPVOID)&credential->LastWritten, + &count); + if (ret != ERROR_SUCCESS) + return ret; + else if (type != REG_BINARY) + return ERROR_REGISTRY_CORRUPT; + count = sizeof(credential->Persist); + ret = RegQueryValueExW(hkey, wszPersistValue, NULL, &type, (LPVOID)&credential->Persist, + &count); + if (ret == ERROR_SUCCESS && type != REG_DWORD) + return ERROR_REGISTRY_CORRUPT; + 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; + BOOL user_name_present = FALSE; + 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; + } + + for (i = 0; i < attr_list->count; i++) + if (attr_list->attr[i].tag == kSecAccountItemAttr && attr_list->attr[i].data) + { + user_name_present = TRUE; + break; + } + if (!user_name_present) + { + WARN("no kSecAccountItemAttr for item\n"); + 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) +{ + LPBYTE encrypted_credential_blob; + struct ustring data; + struct ustring key; + DWORD ret; + + key.Length = key.MaximumLength = KEY_SIZE; + key.Buffer = (unsigned char *)key_data; + + encrypted_credential_blob = HeapAlloc(GetProcessHeap(), 0, credential_blob_size); + if (!encrypted_credential_blob) return ERROR_OUTOFMEMORY; + + memcpy(encrypted_credential_blob, credential_blob, credential_blob_size); + data.Length = data.MaximumLength = credential_blob_size; + data.Buffer = encrypted_credential_blob; + SystemFunction032(&data, &key); + + ret = RegSetValueExW(hkey, wszPasswordValue, 0, REG_BINARY, (LPVOID)encrypted_credential_blob, credential_blob_size); + HeapFree(GetProcessHeap(), 0, encrypted_credential_blob); + + return ret; +} + +static DWORD registry_write_credential(HKEY hkey, const CREDENTIALW *credential, + const BYTE key_data[KEY_SIZE], BOOL preserve_blob) +{ + DWORD ret; + FILETIME LastWritten; + + GetSystemTimeAsFileTime(&LastWritten); + + ret = RegSetValueExW(hkey, wszFlagsValue, 0, REG_DWORD, (LPVOID)&credential->Flags, + sizeof(credential->Flags)); + if (ret != ERROR_SUCCESS) return ret; + ret = RegSetValueExW(hkey, wszTypeValue, 0, REG_DWORD, (LPVOID)&credential->Type, + sizeof(credential->Type)); + if (ret != ERROR_SUCCESS) return ret; + ret = RegSetValueExW(hkey, NULL, 0, REG_SZ, (LPVOID)credential->TargetName, + sizeof(WCHAR)*(strlenW(credential->TargetName)+1)); + if (ret != ERROR_SUCCESS) return ret; + if (credential->Comment) + { + ret = RegSetValueExW(hkey, wszCommentValue, 0, REG_SZ, (LPVOID)credential->Comment, + sizeof(WCHAR)*(strlenW(credential->Comment)+1)); + if (ret != ERROR_SUCCESS) return ret; + } + ret = RegSetValueExW(hkey, wszLastWrittenValue, 0, REG_BINARY, (LPVOID)&LastWritten, + sizeof(LastWritten)); + if (ret != ERROR_SUCCESS) return ret; + ret = RegSetValueExW(hkey, wszPersistValue, 0, REG_DWORD, (LPVOID)&credential->Persist, + sizeof(credential->Persist)); + if (ret != ERROR_SUCCESS) return ret; + /* FIXME: Attributes */ + if (credential->TargetAlias) + { + ret = RegSetValueExW(hkey, wszTargetAliasValue, 0, REG_SZ, (LPVOID)credential->TargetAlias, + sizeof(WCHAR)*(strlenW(credential->TargetAlias)+1)); + if (ret != ERROR_SUCCESS) return ret; + } + if (credential->UserName) + { + ret = RegSetValueExW(hkey, wszUserNameValue, 0, REG_SZ, (LPVOID)credential->UserName, + sizeof(WCHAR)*(strlenW(credential->UserName)+1)); + if (ret != ERROR_SUCCESS) return ret; + } + if (!preserve_blob) + { + ret = write_credential_blob(hkey, credential->TargetName, credential->Type, + key_data, credential->CredentialBlob, + credential->CredentialBlobSize); + } + 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, + NULL, REG_OPTION_NON_VOLATILE, + KEY_READ | (open_for_write ? KEY_WRITE : 0), NULL, hkey, NULL); +} + +static DWORD get_cred_mgr_encryption_key(HKEY hkeyMgr, BYTE key_data[KEY_SIZE]) +{ + static const BYTE my_key_data[KEY_SIZE] = { 0 }; + DWORD type; + DWORD count; + FILETIME ft; + ULONG seed; + ULONG value; + DWORD ret; + + memcpy(key_data, my_key_data, KEY_SIZE); + + count = KEY_SIZE; + ret = RegQueryValueExW(hkeyMgr, wszEncryptionKeyValue, NULL, &type, (LPVOID)key_data, + &count); + if (ret == ERROR_SUCCESS) + { + if (type != REG_BINARY) + return ERROR_REGISTRY_CORRUPT; + else + return ERROR_SUCCESS; + } + if (ret != ERROR_FILE_NOT_FOUND) + return ret; + + GetSystemTimeAsFileTime(&ft); + seed = ft.dwLowDateTime; + value = RtlUniform(&seed); + *(DWORD *)key_data = value; + seed = ft.dwHighDateTime; + value = RtlUniform(&seed); + *(DWORD *)(key_data + 4) = value; + + ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY, + (LPVOID)key_data, KEY_SIZE); + if (ret == ERROR_ACCESS_DENIED) + { + ret = open_cred_mgr_key(&hkeyMgr, TRUE); + if (ret == ERROR_SUCCESS) + { + ret = RegSetValueExW(hkeyMgr, wszEncryptionKeyValue, 0, REG_BINARY, + (LPVOID)key_data, KEY_SIZE); + RegCloseKey(hkeyMgr); + } + } + return ret; +} + +static LPWSTR get_key_name_for_target(LPCWSTR target_name, DWORD type) +{ + static const WCHAR wszGenericPrefix[] = {'G','e','n','e','r','i','c',':',' ',0}; + static const WCHAR wszDomPasswdPrefix[] = {'D','o','m','P','a','s','s','w','d',':',' ',0}; + INT len; + LPCWSTR prefix = NULL; + LPWSTR key_name, p; + + len = strlenW(target_name); + if (type == CRED_TYPE_GENERIC) + { + prefix = wszGenericPrefix; + len += sizeof(wszGenericPrefix)/sizeof(wszGenericPrefix[0]); + } + else + { + prefix = wszDomPasswdPrefix; + len += sizeof(wszDomPasswdPrefix)/sizeof(wszDomPasswdPrefix[0]); + } + + key_name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!key_name) return NULL; + + strcpyW(key_name, prefix); + strcatW(key_name, target_name); + + for (p = key_name; *p; p++) + if (*p == '\') *p = '_'; + + return key_name; +} + +static BOOL credential_matches_filter(HKEY hkeyCred, LPCWSTR filter) +{ + LPWSTR target_name; + DWORD ret; + DWORD type; + DWORD count; + LPCWSTR p; + + if (!filter) return TRUE; + + ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, NULL, &count); + if (ret != ERROR_SUCCESS) + return FALSE; + else if (type != REG_SZ) + return FALSE; + + target_name = HeapAlloc(GetProcessHeap(), 0, count); + if (!target_name) + return FALSE; + ret = RegQueryValueExW(hkeyCred, NULL, 0, &type, (LPVOID)target_name, &count); + if (ret != ERROR_SUCCESS || type != REG_SZ) + { + HeapFree(GetProcessHeap(), 0, target_name); + return FALSE; + } + + TRACE("comparing filter %s to target name %s\n", debugstr_w(filter), + debugstr_w(target_name)); + + p = strchrW(filter, '*'); + ret = CompareStringW(GetThreadLocale(), 0, filter, + (p && !p[1] ? p - filter : -1), target_name, + (p && !p[1] ? p - filter : -1)) == CSTR_EQUAL; + + HeapFree(GetProcessHeap(), 0, target_name); + return ret; +} + +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, + DWORD *len, DWORD *count) +{ + DWORD i; + DWORD ret; + for (i = 0;; i++) + { + HKEY hkeyCred; + ret = RegEnumKeyW(hkeyMgr, i, target_name, target_name_len+1); + if (ret == ERROR_NO_MORE_ITEMS) + { + ret = ERROR_SUCCESS; + break; + } + else if (ret != ERROR_SUCCESS) + { + ret = ERROR_SUCCESS; + continue; + } + TRACE("target_name = %s\n", debugstr_w(target_name)); + ret = RegOpenKeyExW(hkeyMgr, target_name, 0, KEY_QUERY_VALUE, &hkeyCred); + if (ret != ERROR_SUCCESS) + { + ret = ERROR_SUCCESS; + continue; + } + if (!credential_matches_filter(hkeyCred, filter)) + { + RegCloseKey(hkeyCred); + continue; + } + if (buffer) + { + *len = sizeof(CREDENTIALW); + credentials[*count] = (PCREDENTIALW)*buffer; + } + else + *len += sizeof(CREDENTIALW); + ret = registry_read_credential(hkeyCred, buffer ? credentials[*count] : NULL, + key_data, buffer ? *buffer + sizeof(CREDENTIALW) : NULL, + len); + RegCloseKey(hkeyCred); + if (ret != ERROR_SUCCESS) break; + 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); + INT string_len; + + *len += sizeof(CREDENTIALA); + if (!CredentialA) + { + if (CredentialW->TargetName) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, NULL, 0, NULL, NULL); + if (CredentialW->Comment) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, NULL, 0, NULL, NULL); + *len += CredentialW->CredentialBlobSize; + if (CredentialW->TargetAlias) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, NULL, 0, NULL, NULL); + if (CredentialW->UserName) *len += WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, NULL, 0, NULL, NULL); + + return; + } + + CredentialA->Flags = CredentialW->Flags; + CredentialA->Type = CredentialW->Type; + if (CredentialW->TargetName) + { + CredentialA->TargetName = buffer; + string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetName, -1, CredentialA->TargetName, -1, NULL, NULL); + buffer += string_len; + *len += string_len; + } + else + CredentialA->TargetName = NULL; + if (CredentialW->Comment) + { + CredentialA->Comment = buffer; + string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->Comment, -1, CredentialA->Comment, -1, NULL, NULL); + buffer += string_len; + *len += string_len; + } + else + CredentialA->Comment = NULL; + CredentialA->LastWritten = CredentialW->LastWritten; + CredentialA->CredentialBlobSize = CredentialW->CredentialBlobSize; + if (CredentialW->CredentialBlobSize) + { + CredentialA->CredentialBlob =(LPBYTE)buffer; + memcpy(CredentialA->CredentialBlob, CredentialW->CredentialBlob, + CredentialW->CredentialBlobSize); + buffer += CredentialW->CredentialBlobSize; + *len += CredentialW->CredentialBlobSize; + } + else + CredentialA->CredentialBlob = NULL; + CredentialA->Persist = CredentialW->Persist; + CredentialA->AttributeCount = 0; + CredentialA->Attributes = NULL; /* FIXME */ + if (CredentialW->TargetAlias) + { + CredentialA->TargetAlias = buffer; + string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->TargetAlias, -1, CredentialA->TargetAlias, -1, NULL, NULL); + buffer += string_len; + *len += string_len; + } + else + CredentialA->TargetAlias = NULL; + if (CredentialW->UserName) + { + CredentialA->UserName = buffer; + string_len = WideCharToMultiByte(CP_ACP, 0, CredentialW->UserName, -1, CredentialA->UserName, -1, NULL, NULL); + buffer += string_len; + *len += string_len; + } + else + CredentialA->UserName = NULL; +} + +static void convert_PCREDENTIALA_to_PCREDENTIALW(const CREDENTIALA *CredentialA, PCREDENTIALW CredentialW, DWORD *len) +{ + char *buffer = (char *)CredentialW + sizeof(CREDENTIALW); + INT string_len; + + *len += sizeof(CREDENTIALW); + if (!CredentialW) + { + if (CredentialA->TargetName) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, NULL, 0); + if (CredentialA->Comment) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, NULL, 0); + *len += CredentialA->CredentialBlobSize; + if (CredentialA->TargetAlias) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, NULL, 0); + if (CredentialA->UserName) *len += sizeof(WCHAR) * MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, NULL, 0); + + return; + } + + CredentialW->Flags = CredentialA->Flags; + CredentialW->Type = CredentialA->Type; + if (CredentialA->TargetName) + { + CredentialW->TargetName = (LPWSTR)buffer; + string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetName, -1, CredentialW->TargetName, -1); + buffer += sizeof(WCHAR) * string_len; + *len += sizeof(WCHAR) * string_len; + } + else + CredentialW->TargetName = NULL; + if (CredentialA->Comment) + { + CredentialW->Comment = (LPWSTR)buffer; + string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->Comment, -1, CredentialW->Comment, -1); + buffer += sizeof(WCHAR) * string_len; + *len += sizeof(WCHAR) * string_len; + } + else + CredentialW->Comment = NULL; + CredentialW->LastWritten = CredentialA->LastWritten; + CredentialW->CredentialBlobSize = CredentialA->CredentialBlobSize; + if (CredentialA->CredentialBlobSize) + { + CredentialW->CredentialBlob =(LPBYTE)buffer; + memcpy(CredentialW->CredentialBlob, CredentialA->CredentialBlob, + CredentialA->CredentialBlobSize); + buffer += CredentialA->CredentialBlobSize; + *len += CredentialA->CredentialBlobSize; + } + else + CredentialW->CredentialBlob = NULL; + CredentialW->Persist = CredentialA->Persist; + CredentialW->AttributeCount = 0; + CredentialW->Attributes = NULL; /* FIXME */ + if (CredentialA->TargetAlias) + { + CredentialW->TargetAlias = (LPWSTR)buffer; + string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->TargetAlias, -1, CredentialW->TargetAlias, -1); + buffer += sizeof(WCHAR) * string_len; + *len += sizeof(WCHAR) * string_len; + } + else + CredentialW->TargetAlias = NULL; + if (CredentialA->UserName) + { + CredentialW->UserName = (LPWSTR)buffer; + string_len = MultiByteToWideChar(CP_ACP, 0, CredentialA->UserName, -1, CredentialW->UserName, -1); + buffer += sizeof(WCHAR) * string_len; + *len += sizeof(WCHAR) * string_len; + } + else + CredentialW->UserName = NULL; +} + +/****************************************************************************** + * CredDeleteA [ADVAPI32.@] + */ +BOOL WINAPI CredDeleteA(LPCSTR TargetName, DWORD Type, DWORD Flags) +{ + LPWSTR TargetNameW; + DWORD len; + BOOL ret; + + TRACE("(%s, %d, 0x%x)\n", debugstr_a(TargetName), Type, Flags); + + if (!TargetName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0); + TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!TargetNameW) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len); + + ret = CredDeleteW(TargetNameW, Type, Flags); + + HeapFree(GetProcessHeap(), 0, TargetNameW); + + return ret; +} + +/****************************************************************************** + * CredDeleteW [ADVAPI32.@] + */ +BOOL WINAPI CredDeleteW(LPCWSTR TargetName, DWORD Type, DWORD Flags) +{ + HKEY hkeyMgr; + DWORD ret; + LPWSTR key_name; + + TRACE("(%s, %d, 0x%x)\n", debugstr_w(TargetName), Type, Flags); + + if (!TargetName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD) + { + FIXME("unhandled type %d\n", Type); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (Flags) + { + FIXME("unhandled flags 0x%x\n", Flags); + SetLastError(ERROR_INVALID_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) + { + WARN("couldn't open/create manager key, error %d\n", ret); + SetLastError(ERROR_NO_SUCH_LOGON_SESSION); + return FALSE; + } + + key_name = get_key_name_for_target(TargetName, Type); + ret = RegDeleteKeyW(hkeyMgr, key_name); + HeapFree(GetProcessHeap(), 0, key_name); + RegCloseKey(hkeyMgr); + if (ret != ERROR_SUCCESS) + { + SetLastError(ERROR_NOT_FOUND); + return FALSE; + } + + return TRUE; +} + +/****************************************************************************** + * CredEnumerateA [ADVAPI32.@] + */ +BOOL WINAPI CredEnumerateA(LPCSTR Filter, DWORD Flags, DWORD *Count, + PCREDENTIALA **Credentials) +{ + LPWSTR FilterW; + PCREDENTIALW *CredentialsW; + DWORD i; + DWORD len; + char *buffer; + + TRACE("(%s, 0x%x, %p, %p)\n", debugstr_a(Filter), Flags, Count, Credentials); + + if (Filter) + { + len = MultiByteToWideChar(CP_ACP, 0, Filter, -1, NULL, 0); + FilterW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!FilterW) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + MultiByteToWideChar(CP_ACP, 0, Filter, -1, FilterW, len); + } + else + FilterW = NULL; + + if (!CredEnumerateW(FilterW, Flags, Count, &CredentialsW)) + { + HeapFree(GetProcessHeap(), 0, FilterW); + return FALSE; + } + HeapFree(GetProcessHeap(), 0, FilterW); + + len = *Count * sizeof(PCREDENTIALA); + for (i = 0; i < *Count; i++) + convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], NULL, &len); + + *Credentials = HeapAlloc(GetProcessHeap(), 0, len); + if (!*Credentials) + { + CredFree(CredentialsW); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + buffer = (char *)&(*Credentials)[*Count]; + for (i = 0; i < *Count; i++) + { + len = 0; + (*Credentials)[i] = (PCREDENTIALA)buffer; + convert_PCREDENTIALW_to_PCREDENTIALA(CredentialsW[i], (*Credentials)[i], &len); + buffer += len; + } + + CredFree(CredentialsW); + + return TRUE; +} + +/****************************************************************************** + * CredEnumerateW [ADVAPI32.@] + */ +BOOL WINAPI CredEnumerateW(LPCWSTR Filter, DWORD Flags, DWORD *Count, + PCREDENTIALW **Credentials) +{ + HKEY hkeyMgr; + DWORD ret; + LPWSTR target_name; + DWORD target_name_len; + DWORD len; + char *buffer; + BYTE key_data[KEY_SIZE]; + + TRACE("(%s, 0x%x, %p, %p)\n", debugstr_w(Filter), Flags, Count, Credentials); + + if (Flags) + { + SetLastError(ERROR_INVALID_FLAGS); + return FALSE; + } + + ret = open_cred_mgr_key(&hkeyMgr, FALSE); + if (ret != ERROR_SUCCESS) + { + WARN("couldn't open/create manager key, error %d\n", ret); + SetLastError(ERROR_NO_SUCH_LOGON_SESSION); + return FALSE; + } + + ret = get_cred_mgr_encryption_key(hkeyMgr, key_data); + if (ret != ERROR_SUCCESS) + { + RegCloseKey(hkeyMgr); + SetLastError(ret); + return FALSE; + } + + ret = RegQueryInfoKeyW(hkeyMgr, NULL, NULL, NULL, NULL, &target_name_len, NULL, NULL, NULL, NULL, NULL, NULL); + if (ret != ERROR_SUCCESS) + { + RegCloseKey(hkeyMgr); + SetLastError(ret); + return FALSE; + } + + target_name = HeapAlloc(GetProcessHeap(), 0, (target_name_len+1)*sizeof(WCHAR)); + if (!target_name) + { + RegCloseKey(hkeyMgr); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + *Count = 0; + 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) + { + HeapFree(GetProcessHeap(), 0, target_name); + RegCloseKey(hkeyMgr); + SetLastError(ret); + return FALSE; + } + len += *Count * sizeof(PCREDENTIALW); + + if (ret == ERROR_SUCCESS) + { + buffer = HeapAlloc(GetProcessHeap(), 0, len); + *Credentials = (PCREDENTIALW *)buffer; + if (buffer) + { + buffer += *Count * sizeof(PCREDENTIALW); + *Count = 0; + ret = registry_enumerate_credentials(hkeyMgr, Filter, target_name, + target_name_len, key_data, + *Credentials, &buffer, &len, + Count); +#ifdef __APPLE__ + if (ret == ERROR_SUCCESS) + ret = mac_enumerate_credentials(Filter, *Credentials, + buffer, &len, Count); +#endif + } + else + ret = ERROR_OUTOFMEMORY; + } + + HeapFree(GetProcessHeap(), 0, target_name); + RegCloseKey(hkeyMgr); + + if (ret != ERROR_SUCCESS) + { + SetLastError(ret); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** + * CredFree [ADVAPI32.@] + */ +VOID WINAPI CredFree(PVOID Buffer) +{ + HeapFree(GetProcessHeap(), 0, Buffer); +} + +/****************************************************************************** + * CredReadA [ADVAPI32.@] + */ +BOOL WINAPI CredReadA(LPCSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALA *Credential) +{ + LPWSTR TargetNameW; + PCREDENTIALW CredentialW; + DWORD len; + + TRACE("(%s, %d, 0x%x, %p)\n", debugstr_a(TargetName), Type, Flags, Credential); + + if (!TargetName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + len = MultiByteToWideChar(CP_ACP, 0, TargetName, -1, NULL, 0); + TargetNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (!TargetNameW) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + MultiByteToWideChar(CP_ACP, 0, TargetName, -1, TargetNameW, len); + + if (!CredReadW(TargetNameW, Type, Flags, &CredentialW)) + { + HeapFree(GetProcessHeap(), 0, TargetNameW); + return FALSE; + } + HeapFree(GetProcessHeap(), 0, TargetNameW); + + len = 0; + convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, NULL, &len); + *Credential = HeapAlloc(GetProcessHeap(), 0, len); + if (!*Credential) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + len = 0; + convert_PCREDENTIALW_to_PCREDENTIALA(CredentialW, *Credential, &len); + + CredFree(CredentialW); + + return TRUE; +} + +/****************************************************************************** + * CredReadW [ADVAPI32.@] + */ +BOOL WINAPI CredReadW(LPCWSTR TargetName, DWORD Type, DWORD Flags, PCREDENTIALW *Credential) +{ + HKEY hkeyMgr; + HKEY hkeyCred; + DWORD ret; + LPWSTR key_name; + DWORD len; + BYTE key_data[KEY_SIZE]; + + TRACE("(%s, %d, 0x%x, %p)\n", debugstr_w(TargetName), Type, Flags, Credential); + + if (!TargetName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (Type != CRED_TYPE_GENERIC && Type != CRED_TYPE_DOMAIN_PASSWORD) + { + FIXME("unhandled type %d\n", Type); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (Flags) + { + FIXME("unhandled flags 0x%x\n", Flags); + SetLastError(ERROR_INVALID_FLAGS); + 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) + { + WARN("couldn't open/create manager key, error %d\n", ret); + SetLastError(ERROR_NO_SUCH_LOGON_SESSION); + return FALSE; + } + + ret = get_cred_mgr_encryption_key(hkeyMgr, key_data); + if (ret != ERROR_SUCCESS) + { + RegCloseKey(hkeyMgr); + SetLastError(ret); + return FALSE; + } + + key_name = get_key_name_for_target(TargetName, Type); + ret = RegOpenKeyExW(hkeyMgr, key_name, 0, KEY_QUERY_VALUE, &hkeyCred); + HeapFree(GetProcessHeap(), 0, key_name); + if (ret != ERROR_SUCCESS) + { + TRACE("credentials for target name %s not found\n", debugstr_w(TargetName)); + SetLastError(ERROR_NOT_FOUND); + return FALSE; + } + + len = sizeof(**Credential); + ret = registry_read_credential(hkeyCred, NULL, key_data, NULL, &len); + if (ret == ERROR_SUCCESS) + { + *Credential = HeapAlloc(GetProcessHeap(), 0, len); + if (*Credential) + { + len = sizeof(**Credential); + ret = registry_read_credential(hkeyCred, *Credential, key_data, + (char *)(*Credential + 1), &len); + } + else + ret = ERROR_OUTOFMEMORY; + } + + RegCloseKey(hkeyCred); + RegCloseKey(hkeyMgr); + + if (ret != ERROR_SUCCESS) + { + SetLastError(ret); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** + * CredWriteA [ADVAPI32.@] + */ +BOOL WINAPI CredWriteA(PCREDENTIALA Credential, DWORD Flags) +{ + BOOL ret; + DWORD len; + PCREDENTIALW CredentialW; + + TRACE("(%p, 0x%x)\n", Credential, Flags); + + if (!Credential || !Credential->TargetName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + len = 0; + convert_PCREDENTIALA_to_PCREDENTIALW(Credential, NULL, &len); + CredentialW = HeapAlloc(GetProcessHeap(), 0, len); + if (!CredentialW) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + len = 0; + convert_PCREDENTIALA_to_PCREDENTIALW(Credential, CredentialW, &len); + + ret = CredWriteW(CredentialW, Flags); + + HeapFree(GetProcessHeap(), 0, CredentialW); + + return ret; +} + +/****************************************************************************** + * CredWriteW [ADVAPI32.@] + */ +BOOL WINAPI CredWriteW(PCREDENTIALW Credential, DWORD Flags) +{ + HKEY hkeyMgr; + HKEY hkeyCred; + DWORD ret; + LPWSTR key_name; + BYTE key_data[KEY_SIZE]; + + TRACE("(%p, 0x%x)\n", Credential, Flags); + + if (!Credential || !Credential->TargetName) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (Flags & ~CRED_PRESERVE_CREDENTIAL_BLOB) + { + FIXME("unhandled flags 0x%x\n", Flags); + SetLastError(ERROR_INVALID_FLAGS); + return FALSE; + } + + if (Credential->Type != CRED_TYPE_GENERIC && Credential->Type != CRED_TYPE_DOMAIN_PASSWORD) + { + FIXME("unhandled type %d\n", Credential->Type); + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + TRACE("Credential->TargetName = %s\n", debugstr_w(Credential->TargetName)); + TRACE("Credential->UserName = %s\n", debugstr_w(Credential->UserName)); + + if (Credential->Type == CRED_TYPE_DOMAIN_PASSWORD) + { + if (!Credential->UserName || + (!strchrW(Credential->UserName, '\') && !strchrW(Credential->UserName, '@'))) + { + ERR("bad username %s\n", debugstr_w(Credential->UserName)); + SetLastError(ERROR_BAD_USERNAME); + return FALSE; + } + } + +#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) + { + WARN("couldn't open/create manager key, error %d\n", ret); + SetLastError(ERROR_NO_SUCH_LOGON_SESSION); + return FALSE; + } + + ret = get_cred_mgr_encryption_key(hkeyMgr, key_data); + if (ret != ERROR_SUCCESS) + { + RegCloseKey(hkeyMgr); + SetLastError(ret); + return FALSE; + } + + key_name = get_key_name_for_target(Credential->TargetName, Credential->Type); + ret = RegCreateKeyExW(hkeyMgr, key_name, 0, NULL, + Credential->Persist == CRED_PERSIST_SESSION ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE, + KEY_READ|KEY_WRITE, NULL, &hkeyCred, NULL); + HeapFree(GetProcessHeap(), 0, key_name); + if (ret != ERROR_SUCCESS) + { + TRACE("credentials for target name %s not found\n", + debugstr_w(Credential->TargetName)); + SetLastError(ERROR_NOT_FOUND); + return FALSE; + } + + ret = registry_write_credential(hkeyCred, Credential, key_data, + Flags & CRED_PRESERVE_CREDENTIAL_BLOB); + + RegCloseKey(hkeyCred); + RegCloseKey(hkeyMgr); + + if (ret != ERROR_SUCCESS) + { + SetLastError(ret); + return FALSE; + } + return TRUE; +} + +/****************************************************************************** + * CredGetSessionTypes [ADVAPI32.@] + */ +BOOL WINAPI CredGetSessionTypes(DWORD persistCount, LPDWORD persists) +{ + TRACE("(%u, %p)\n", persistCount, persists); + + memset(persists, CRED_PERSIST_NONE, persistCount*sizeof(*persists)); + if (CRED_TYPE_GENERIC < persistCount) + { + persists[CRED_TYPE_GENERIC] = CRED_PERSIST_ENTERPRISE; + + if (CRED_TYPE_DOMAIN_PASSWORD < persistCount) + { + persists[CRED_TYPE_DOMAIN_PASSWORD] = CRED_PERSIST_ENTERPRISE; + } + } + return TRUE; +}
Propchange: trunk/reactos/dll/win32/advapi32/sec/cred.c ------------------------------------------------------------------------------ svn:eol-style = native