webdav_authcache.c [plain text]
#include "webdavd.h"
#include <sys/types.h>
#include <Security/SecKey.h>
#include <Security/SecKeychain.h>
#include <Security/SecKeychainItem.h>
#include <Security/SecKeychainSearch.h>
#include <pthread.h>
#include "webdav_authcache.h"
#include "webdav_network.h"
struct authcache_entry
{
uid_t uid;
CFHTTPAuthenticationRef auth;
CFStringRef username;
CFStringRef password;
CFStringRef domain;
u_int32_t authflags;
u_int32_t generation;
};
enum
{
kAuthNone = 0x00000000,
kCredentialsFromMount = 0x00000001,
kCredentialsFromKeychain = 0x00000002,
kCredentialsFromUI = 0x00000004,
kAuthHasCredentials = (kCredentialsFromMount | kCredentialsFromKeychain | kCredentialsFromUI),
kNoMountCredentials = 0x00000008,
kNoKeychainCredentials = 0x00000010,
kCredentialsValid = 0x00000020,
kAddCredentialsToKeychain = 0x00000040
};
static pthread_mutex_t authcache_lock;
static u_int32_t authcache_generation = 1;
static struct authcache_entry *authcache_server_entry = NULL;
static struct authcache_entry *authcache_proxy_entry = NULL;
static CFStringRef mount_username = NULL;
static CFStringRef mount_password = NULL;
static CFStringRef mount_domain = NULL;
enum AuthCache_State
{
UNDEFINED_GUEST = 0,
TRY_MOUNT_CRED = 1,
TRY_KEYCHAIN_CRED = 2,
TRY_UI_CRED = 3,
AUTHENTICATED_USER = 4,
GUEST_USER = 5
};
static enum AuthCache_State authcache_state = UNDEFINED_GUEST;
enum {MAX_AUTHENTICATED_USER_RETRIES = 4};
static
OSStatus KeychainItemCopyAccountPassword(
SecKeychainItemRef itemRef,
CFStringRef *username,
CFStringRef *password,
CFStringRef *domain);
static
char *CopyCFStringToCString(CFStringRef theString);
static
void ReleaseCredentials(struct authcache_entry *entry_ptr);
static
void LoginFailedWarning(void)
{
SInt32 error;
CFURLRef localizationPath;
CFURLRef iconPath;
CFOptionFlags responseFlags;
CFMutableDictionaryRef dictionary;
CFUserNotificationRef userNotification;
dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
require(dictionary != NULL, CFDictionaryCreateMutable);
localizationPath = CFURLCreateWithFileSystemPath(NULL, CFSTR(WEBDAV_LOCALIZATION_BUNDLE),
kCFURLPOSIXPathStyle, TRUE);
require(localizationPath != NULL, CFURLCreateWithFileSystemPath_localization);
CFDictionaryAddValue(dictionary, kCFUserNotificationLocalizationURLKey, localizationPath);
iconPath = CFURLCreateWithFileSystemPath(NULL, CFSTR(WEBDAV_SERVER_ICON_PATH),
kCFURLPOSIXPathStyle, TRUE);
require(iconPath != NULL, CFURLCreateWithFileSystemPath_Icon);
CFDictionaryAddValue(dictionary, kCFUserNotificationIconURLKey, iconPath);
CFDictionaryAddValue(dictionary, kCFUserNotificationAlertHeaderKey, CFSTR("WEBDAV_LOGIN_FAILED_HEADER_KEY"));
CFDictionaryAddValue(dictionary, kCFUserNotificationAlertMessageKey, CFSTR("WEBDAV_LOGIN_FAILED_MSG_KEY"));
CFDictionaryAddValue(dictionary, kCFUserNotificationDefaultButtonTitleKey, CFSTR("WEBDAV_LOGIN_FAILED_OK_KEY"));
userNotification = CFUserNotificationCreate(NULL, WEBDAV_AUTHENTICATION_TIMEOUT,
kCFUserNotificationStopAlertLevel, &error, dictionary);
require(userNotification != NULL, CFUserNotificationCreate);
CFUserNotificationReceiveResponse(userNotification, WEBDAV_AUTHENTICATION_TIMEOUT,
&responseFlags);
CFRelease(userNotification);
CFUserNotificationCreate:
CFRelease(iconPath);
CFURLCreateWithFileSystemPath_Icon:
CFRelease(localizationPath);
CFURLCreateWithFileSystemPath_localization:
CFRelease(dictionary);
CFDictionaryCreateMutable:
return;
}
static
int CopyCredentialsFromUserNotification(
CFHTTPAuthenticationRef auth,
CFHTTPMessageRef request,
int badlogin,
int isProxy,
CFStringRef *username,
CFStringRef *password,
CFStringRef *domain,
int *addtokeychain,
int *secureAuth)
{
int result;
CFStringRef method;
int useDomain;
int index;
CFTypeRef a[3];
CFArrayRef array;
SInt32 error;
CFOptionFlags responseFlags;
CFURLRef url;
CFStringRef urlString;
CFStringRef realmString;
CFMutableDictionaryRef dictionary;
CFURLRef localizationPath;
CFURLRef iconPath;
CFUserNotificationRef userNotification;
result = ENOMEM;
*secureAuth = FALSE;
if ( badlogin )
{
LoginFailedWarning();
}
if ( gSecureConnection )
{
*secureAuth = TRUE;
}
else
{
method = CFHTTPAuthenticationCopyMethod(auth);
if ( method != NULL )
{
*secureAuth = !CFEqual(method, CFSTR("Basic"));
CFRelease(method);
}
else
{
*secureAuth = FALSE;
}
}
if ( isProxy )
{
int httpProxyEnabled;
char *httpProxyServer;
int httpProxyPort;
int httpsProxyEnabled;
char *httpsProxyServer;
int httpsProxyPort;
url = NULL;
result = network_get_proxy_settings(&httpProxyEnabled, &httpProxyServer, &httpProxyPort,
&httpsProxyEnabled, &httpsProxyServer, &httpsProxyPort);
require_noerr_quiet(result, network_get_proxy_settings);
if ( gSecureConnection )
{
urlString = CFStringCreateWithCString(kCFAllocatorDefault, httpsProxyServer, kCFStringEncodingUTF8);
}
else
{
urlString = CFStringCreateWithCString(kCFAllocatorDefault, httpProxyServer, kCFStringEncodingUTF8);
}
free(httpProxyServer);
free(httpsProxyServer);
require(urlString != NULL, CFStringCreateWithCString);
}
else
{
url = CFHTTPMessageCopyRequestURL(request);
require(url != NULL, CFHTTPMessageCopyRequestURL);
urlString = CFURLGetString(url);
require(urlString != NULL, CFURLGetString);
require_action_quiet(!gSecureServerAuth || (*secureAuth), SecureServerAuthRequired, result = EACCES);
}
realmString = CFHTTPAuthenticationCopyRealm(auth);
useDomain = CFHTTPAuthenticationRequiresAccountDomain(auth);
dictionary = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
require(dictionary != NULL, CFDictionaryCreateMutable);
localizationPath = CFURLCreateWithFileSystemPath(NULL, CFSTR(WEBDAV_LOCALIZATION_BUNDLE),
kCFURLPOSIXPathStyle, TRUE);
require(localizationPath != NULL, CFURLCreateWithFileSystemPath_localization);
CFDictionaryAddValue(dictionary, kCFUserNotificationLocalizationURLKey, localizationPath);
iconPath = CFURLCreateWithFileSystemPath(NULL, CFSTR(WEBDAV_SERVER_ICON_PATH),
kCFURLPOSIXPathStyle, TRUE);
require(iconPath != NULL, CFURLCreateWithFileSystemPath_Icon);
CFDictionaryAddValue(dictionary, kCFUserNotificationIconURLKey, iconPath);
CFDictionaryAddValue(dictionary, kCFUserNotificationAlertHeaderKey, CFSTR("WEBDAV_AUTH_HEADER_KEY"));
CFDictionaryAddValue(dictionary, CFSTR("AlertMessageWithParameters"),
useDomain ? CFSTR("WEBDAV_AUTH_DOMAIN_MSG_WITH_PARAMETERS_KEY") : CFSTR("WEBDAV_AUTH_MSG_WITH_PARAMETERS_KEY"));
a[0] = urlString;
a[1] = (realmString != NULL) ? realmString : CFSTR("");
a[2] = *secureAuth ? CFSTR("WEBDAV_AUTH_MSG_SECURE_PARAMETER_KEY") : CFSTR("WEBDAV_AUTH_MSG_INSECURE_PARAMETER_KEY");
array = CFArrayCreate(NULL, a, 3, &kCFTypeArrayCallBacks);
require(array != NULL, CFArrayCreate_AlertMessageParameter);
CFDictionaryAddValue(dictionary, CFSTR("AlertMessageParameter"), array);
CFRelease(array);
index = 0;
if ( useDomain )
{
a[index++] = CFSTR("WEBDAV_AUTH_DOMAIN_KEY");
}
a[index++] = CFSTR("WEBDAV_AUTH_USERNAME_KEY");
a[index++] = CFSTR("WEBDAV_AUTH_PASSWORD_KEY");
array = CFArrayCreate(NULL, a, index, &kCFTypeArrayCallBacks);
require(array != NULL, CFArrayCreate_TextFieldTitles);
CFDictionaryAddValue(dictionary, kCFUserNotificationTextFieldTitlesKey, array);
CFRelease(array);
index = 0;
if ( useDomain )
{
a[index++] = (*domain != NULL) ? *domain : CFSTR("");
}
a[index++] = (*username != NULL) ? *username : CFSTR("");
a[index++] = (*password != NULL) ? *password : CFSTR("");
array = CFArrayCreate(NULL, a, index, &kCFTypeArrayCallBacks);
*username = NULL;
*password = NULL;
*domain = NULL;
require(array != NULL, CFArrayCreate_TextFieldValues);
CFDictionaryAddValue(dictionary, kCFUserNotificationTextFieldValuesKey, array);
CFRelease(array);
CFDictionaryAddValue(dictionary, kCFUserNotificationCheckBoxTitlesKey, CFSTR("WEBDAV_AUTH_KEYCHAIN_KEY"));
CFDictionaryAddValue(dictionary, kCFUserNotificationDefaultButtonTitleKey, CFSTR("WEBDAV_AUTH_OK_KEY"));
CFDictionaryAddValue(dictionary, kCFUserNotificationAlternateButtonTitleKey, CFSTR("WEBDAV_AUTH_CANCEL_KEY"));
userNotification = CFUserNotificationCreate(NULL, WEBDAV_AUTHENTICATION_TIMEOUT,
kCFUserNotificationPlainAlertLevel | CFUserNotificationSecureTextField(useDomain ? 2 : 1), &error, dictionary);
require(userNotification != NULL, CFUserNotificationCreate);
if ( CFUserNotificationReceiveResponse(userNotification, WEBDAV_AUTHENTICATION_TIMEOUT, &responseFlags) == 0)
{
if ( (responseFlags & 3) == kCFUserNotificationDefaultResponse)
{
index = 0;
if ( useDomain )
{
*domain = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, index++);
if (*domain != NULL)
CFRetain(*domain);
}
*username = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, index++);
if (*username != NULL)
CFRetain(*username);
*password = CFUserNotificationGetResponseValue(userNotification, kCFUserNotificationTextFieldValuesKey, index++);
if (*password != NULL)
CFRetain(*password);
if ( (useDomain && *domain == NULL) ||
(*username == NULL) ||
(*password == NULL) )
{
if (*domain != NULL)
CFRelease (*domain);
if (*username != NULL)
CFRelease (*username);
if (*password != NULL)
CFRelease (*password);
syslog(LOG_ERR, "Unable to get one or more credential fields from UserNotification");
}
else
{
*addtokeychain = ((responseFlags & CFUserNotificationCheckBoxChecked(0)) != 0);
result = 0;
}
}
else if ( (responseFlags & 3) == kCFUserNotificationAlternateResponse)
{
result = ECANCELED;
syslog(LOG_DEBUG, "User auth notification cancelled by user");
}
else
{
result = EACCES;
syslog(LOG_DEBUG, "User auth notification timed out");
}
}
else
{
result = EACCES;
syslog(LOG_DEBUG, "User auth notification timed out");
}
CFRelease(userNotification);
CFUserNotificationCreate:
CFArrayCreate_TextFieldValues:
CFArrayCreate_TextFieldTitles:
CFArrayCreate_AlertMessageParameter:
CFRelease(iconPath);
CFURLCreateWithFileSystemPath_Icon:
CFRelease(localizationPath);
CFURLCreateWithFileSystemPath_localization:
CFRelease(dictionary);
CFDictionaryCreateMutable:
if ( realmString != NULL )
{
CFRelease(realmString);
}
SecureServerAuthRequired:
CFURLGetString:
if ( url != NULL )
{
CFRelease(url);
}
CFStringCreateWithCString:
CFHTTPMessageCopyRequestURL:
network_get_proxy_settings:
return ( result );
}
static
void RemoveAuthentication(struct authcache_entry *entry_ptr)
{
if ( entry_ptr != authcache_proxy_entry )
{
authcache_server_entry = NULL;
}
else
{
authcache_proxy_entry = NULL;
}
++authcache_generation;
if ( authcache_generation == 0 )
{
++authcache_generation;
}
if ( entry_ptr->auth != NULL )
{
CFRelease(entry_ptr->auth);
entry_ptr->auth = NULL;
}
ReleaseCredentials(entry_ptr);
free(entry_ptr);
}
static
void ReleaseCredentials(
struct authcache_entry *entry_ptr)
{
if (entry_ptr->username != NULL)
{
CFRelease(entry_ptr->username);
entry_ptr->username = NULL;
}
if (entry_ptr->password != NULL)
{
CFRelease(entry_ptr->password);
entry_ptr->password = NULL;
}
if (entry_ptr->domain != NULL)
{
CFRelease(entry_ptr->domain);
entry_ptr->domain = NULL;
}
}
static
void SetCredentials(
struct authcache_entry *entry_ptr,
CFStringRef new_username,
CFStringRef new_password,
CFStringRef new_domain)
{
entry_ptr->username = new_username;
entry_ptr->password = new_password;
entry_ptr->domain = new_domain;
}
static
char *CopyCFStringToCString(CFStringRef theString)
{
char *cstring;
CFIndex usedBufLen;
CFIndex converted;
CFRange range;
range = CFRangeMake(0, CFStringGetLength(theString));
converted = CFStringGetBytes(theString, range, kCFStringEncodingUTF8, 0, false, NULL, 0, &usedBufLen);
cstring = malloc(usedBufLen + 1);
if ( cstring != NULL )
{
converted = CFStringGetBytes(theString, range, kCFStringEncodingUTF8, 0, false, (UInt8 *)cstring, usedBufLen, &usedBufLen);
cstring[usedBufLen] = '\0';
}
return ( cstring );
}
static
OSStatus KeychainItemCopyAccountPassword(
SecKeychainItemRef itemRef,
CFStringRef *username,
CFStringRef *password,
CFStringRef *domain)
{
OSStatus result;
SecKeychainAttribute attr;
SecKeychainAttributeList attrList;
UInt32 length;
void *outData;
attr.tag = kSecAccountItemAttr;
attr.length = 0;
attr.data = NULL;
attrList.count = 1;
attrList.attr = &attr;
result = SecKeychainItemCopyContent(itemRef, NULL, &attrList, &length, &outData);
if ( result == noErr )
{
*username = CFStringCreateWithBytes(kCFAllocatorDefault, attr.data, attr.length, kCFStringEncodingUTF8, false);
*password = CFStringCreateWithBytes(kCFAllocatorDefault, outData, length, kCFStringEncodingUTF8, false);
*domain = NULL;
(void) SecKeychainItemFreeContent(&attrList, outData);
}
return ( result );
}
static
int CopyMountCredentials(
CFHTTPAuthenticationRef auth,
CFStringRef *username,
CFStringRef *password,
CFStringRef *domain,
int *secureAuth)
{
int result;
CFStringRef method;
if ( gSecureConnection )
{
*secureAuth = TRUE;
}
else
{
method = CFHTTPAuthenticationCopyMethod(auth);
if ( method != NULL )
{
*secureAuth = !CFEqual(method, CFSTR("Basic"));
CFRelease(method);
}
else
{
*secureAuth = FALSE;
}
}
require_action_quiet(!gSecureServerAuth || (*secureAuth), SecureServerAuthRequired, result = EACCES);
if ( mount_username != NULL )
{
CFRetain(mount_username);
*username = mount_username;
if ( mount_password != NULL )
{
CFRetain(mount_password);
}
*password = mount_password;
if ( mount_domain != NULL )
{
CFRetain(mount_domain);
}
*domain = mount_domain;
result = 0;
}
else
{
result = 1;
}
SecureServerAuthRequired:
return ( result );
}
static
char *CopyComponentPathToCString(CFURLRef url)
{
char *result;
CFRange range;
CFIndex bufferLength;
UInt8 *buffer;
result = NULL;
buffer = NULL;
bufferLength = CFURLGetBytes(url, NULL, 0);
require(bufferLength != 0, CFURLGetBytes_length);
buffer = malloc(bufferLength);
require(buffer != NULL, malloc_buffer);
require(CFURLGetBytes(url, buffer, bufferLength) == bufferLength, CFURLGetBytes);
range = CFURLGetByteRangeForComponent(url, kCFURLComponentPath, NULL);
require(range.location != kCFNotFound, CFURLGetByteRangeForComponent);
result = malloc(range.length + 1);
require(result != NULL, malloc_result);
strncpy(result, (char *)&buffer[range.location], range.length);
result[range.length] = '\0';
malloc_result:
CFURLGetByteRangeForComponent:
CFURLGetBytes:
free (buffer);
malloc_buffer:
CFURLGetBytes_length:
return ( result );
}
static
int CopyCredentialsFromKeychain(
CFHTTPAuthenticationRef auth,
CFHTTPMessageRef request,
CFStringRef *username,
CFStringRef *password,
CFStringRef *domain,
int isProxy,
int *secureAuth)
{
OSStatus result;
CFURLRef messageURL;
CFStringRef theString;
SecProtocolType protocol;
SecAuthenticationType authenticationType;
SecKeychainItemRef itemRef;
int portNumber;
char *serverName;
char *realmStr;
char *path;
result = 0;
serverName = NULL;
realmStr = NULL;
path = NULL;
messageURL = CFHTTPMessageCopyRequestURL(request);
require_action(messageURL != NULL, CFHTTPMessageCopyRequestURL, result = 1);
theString = CFURLCopyScheme(messageURL);
if ( CFEqual(theString, CFSTR("http")) )
{
if ( isProxy )
{
protocol = kSecProtocolTypeHTTPProxy;
}
else
{
protocol = kSecProtocolTypeHTTP;
}
}
else if ( CFEqual(theString, CFSTR("https")) )
{
if ( isProxy )
{
protocol = kSecProtocolTypeHTTPSProxy;
}
else
{
protocol = kSecProtocolTypeHTTPS;
}
}
else
{
protocol = 0;
}
CFRelease(theString);
require_action(protocol != 0, unknown_protocol, result = 1);
theString = CFHTTPAuthenticationCopyMethod(auth);
if ( CFEqual(theString, CFSTR("Basic")) )
{
authenticationType = kSecAuthenticationTypeHTTPBasic;
}
else if ( CFEqual(theString, CFSTR("Digest")) )
{
authenticationType = kSecAuthenticationTypeHTTPDigest;
}
else if ( CFEqual(theString, CFSTR("NTLM")) )
{
authenticationType = kSecAuthenticationTypeNTLM;
}
else
{
authenticationType = kSecAuthenticationTypeDefault;
}
CFRelease(theString);
*secureAuth = (protocol == kSecProtocolTypeHTTPSProxy) ||
(protocol == kSecProtocolTypeHTTPS) ||
(authenticationType != kSecAuthenticationTypeHTTPBasic);
if ( isProxy )
{
int httpProxyEnabled;
char *httpProxyServer;
int httpProxyPort;
int httpsProxyEnabled;
char *httpsProxyServer;
int httpsProxyPort;
result = network_get_proxy_settings(&httpProxyEnabled, &httpProxyServer, &httpProxyPort,
&httpsProxyEnabled, &httpsProxyServer, &httpsProxyPort);
require_noerr_quiet(result, network_get_proxy_settings);
if ( protocol == kSecProtocolTypeHTTPProxy )
{
free(httpsProxyServer);
serverName = httpProxyServer;
portNumber = httpProxyPort;
}
else
{
free(httpProxyServer);
serverName = httpsProxyServer;
portNumber = httpsProxyPort;
}
result = SecKeychainFindInternetPassword(NULL,
strlen(serverName), serverName,
0, NULL,
0, NULL,
0, NULL,
portNumber,
protocol,
0,
0, NULL,
&itemRef);
}
else
{
require_action_quiet(!gSecureServerAuth || (*secureAuth), SecureServerAuthRequired, result = EACCES);
path = CopyComponentPathToCString(gBaseURL);
theString = CFURLCopyHostName(messageURL);
require(theString != NULL, CFURLCopyHostName);
serverName = CopyCFStringToCString(theString);
CFRelease(theString);
require(serverName != NULL, CopyCFStringToCString);
theString = CFHTTPAuthenticationCopyRealm(auth);
if ( theString != NULL )
{
realmStr = CopyCFStringToCString(theString);
CFRelease(theString);
}
portNumber = CFURLGetPortNumber(messageURL);
if ( portNumber == -1 )
{
if ( protocol == kSecProtocolTypeHTTP )
{
portNumber = kHttpDefaultPort;
}
else if ( protocol == kSecProtocolTypeHTTPS )
{
portNumber = kHttpsDefaultPort;
}
}
result = SecKeychainFindInternetPassword(NULL,
strlen(serverName), serverName,
(realmStr != NULL) ? strlen(realmStr) : 0, realmStr,
0, NULL,
(path != NULL) ? strlen(path) : 0, path,
portNumber,
protocol,
authenticationType,
0, NULL,
&itemRef);
}
if ( result == noErr )
{
result = KeychainItemCopyAccountPassword(itemRef, username, password, domain);
CFRelease(itemRef);
}
network_get_proxy_settings:
CopyCFStringToCString:
CFURLCopyHostName:
SecureServerAuthRequired:
unknown_protocol:
CFHTTPMessageCopyRequestURL:
if ( serverName != NULL )
{
free(serverName);
}
if ( realmStr != NULL )
{
free(realmStr);
}
if ( path != NULL )
{
free(path);
}
if ( messageURL != NULL )
{
CFRelease(messageURL);
}
return ( result );
}
static
int SaveCredentialsToKeychain(
struct authcache_entry *entry_ptr,
CFHTTPMessageRef request,
int isProxy)
{
OSStatus result;
CFURLRef messageURL;
CFStringRef theString;
SecProtocolType protocol;
SecAuthenticationType authenticationType;
SecKeychainItemRef itemRef;
int portNumber;
char *serverName;
char *realmStr;
char *username;
char *password;
char *path;
serverName = NULL;
realmStr = NULL;
username = NULL;
password = NULL;
path = NULL;
messageURL = CFHTTPMessageCopyRequestURL(request);
require_action(messageURL != NULL, CFHTTPMessageCopyRequestURL, result = 1);
theString = CFHTTPAuthenticationCopyRealm(entry_ptr->auth);
if ( theString != NULL )
{
realmStr = CopyCFStringToCString(theString);
CFRelease(theString);
}
username = CopyCFStringToCString(entry_ptr->username);
require_action(username != NULL, CopyCFStringToCString, result = 1);
if ( (entry_ptr->domain != NULL) && (CFStringGetLength(entry_ptr->domain) != 0) )
{
char *domain;
char *temp;
domain = CopyCFStringToCString(entry_ptr->domain);
require_action(domain != NULL, CopyCFStringToCString, result = 1);
temp = malloc(strlen(domain) + strlen(username) + 2);
require_action(temp != NULL, malloc, result = 1);
strcpy(temp, domain);
free(domain);
strcat(temp, "\\");
strcat(temp, username);
free(username);
username = temp;
}
theString = CFURLCopyScheme(messageURL);
if ( CFEqual(theString, CFSTR("http")) )
{
if ( isProxy )
{
protocol = kSecProtocolTypeHTTPProxy;
}
else
{
protocol = kSecProtocolTypeHTTP;
}
}
else if ( CFEqual(theString, CFSTR("https")) )
{
if ( isProxy )
{
protocol = kSecProtocolTypeHTTPSProxy;
}
else
{
protocol = kSecProtocolTypeHTTPS;
}
}
else
{
protocol = 0;
}
CFRelease(theString);
require_action(protocol != 0, unknown_protocol, result = 1);
theString = CFHTTPAuthenticationCopyMethod(entry_ptr->auth);
if ( CFEqual(theString, CFSTR("Basic")) )
{
authenticationType = kSecAuthenticationTypeHTTPBasic;
}
else if ( CFEqual(theString, CFSTR("Digest")) )
{
authenticationType = kSecAuthenticationTypeHTTPDigest;
}
else if ( CFEqual(theString, CFSTR("NTLM")) )
{
authenticationType = kSecAuthenticationTypeNTLM;
}
else
{
authenticationType = kSecAuthenticationTypeDefault;
}
CFRelease(theString);
password = CopyCFStringToCString(entry_ptr->password);
require_action(username != NULL, CopyCFStringToCString, result = 1);
if ( isProxy )
{
int httpProxyEnabled;
char *httpProxyServer;
int httpProxyPort;
int httpsProxyEnabled;
char *httpsProxyServer;
int httpsProxyPort;
result = network_get_proxy_settings(&httpProxyEnabled, &httpProxyServer, &httpProxyPort,
&httpsProxyEnabled, &httpsProxyServer, &httpsProxyPort);
require_noerr_action_quiet(result, network_get_proxy_settings, result = 1);
if ( protocol == kSecProtocolTypeHTTPProxy )
{
free(httpsProxyServer);
serverName = httpProxyServer;
portNumber = httpProxyPort;
}
else
{
free(httpProxyServer);
serverName = httpsProxyServer;
portNumber = httpsProxyPort;
}
result = SecKeychainFindInternetPassword(NULL,
strlen(serverName), serverName,
0, NULL,
0, NULL,
0, NULL,
portNumber,
protocol,
0,
0, NULL,
&itemRef);
}
else
{
path = CopyComponentPathToCString(gBaseURL);
theString = CFURLCopyHostName(messageURL);
require_action(theString != NULL, CFURLCopyHostName, result = 1);
serverName = CopyCFStringToCString(theString);
CFRelease(theString);
portNumber = CFURLGetPortNumber(messageURL);
if ( portNumber == -1 )
{
if ( protocol == kSecProtocolTypeHTTP )
{
portNumber = kHttpDefaultPort;
}
else if ( protocol == kSecProtocolTypeHTTPS )
{
portNumber = kHttpsDefaultPort;
}
}
result = SecKeychainFindInternetPassword(NULL,
strlen(serverName), serverName,
(realmStr != NULL) ? strlen(realmStr) : 0, realmStr,
strlen(username), username,
(path != NULL) ? strlen(path) : 0, path,
portNumber,
protocol,
authenticationType,
0, NULL,
&itemRef);
}
if ( result == noErr )
{
SecKeychainAttribute attr;
SecKeychainAttributeList attrList;
attr.tag = kSecAccountItemAttr;
attr.length = strlen(username);
attr.data = username;
attrList.count = 1;
attrList.attr = &attr;
result = SecKeychainItemModifyContent(itemRef, &attrList, strlen(password), (void *)password);
CFRelease(itemRef);
require_noerr(result, SecKeychainItemModifyContent);
}
else
{
result = SecKeychainAddInternetPassword(NULL,
strlen(serverName), serverName,
(realmStr != NULL) ? strlen(realmStr) : 0, realmStr,
strlen(username), username,
(path != NULL) ? strlen(path) : 0, path,
portNumber,
protocol,
authenticationType,
strlen(password), password,
&itemRef);
require_noerr(result, SecKeychainAddInternetPassword);
CFRelease(itemRef);
}
entry_ptr->authflags &= ~kAuthHasCredentials;
entry_ptr->authflags |= kCredentialsFromKeychain;
SecKeychainAddInternetPassword:
SecKeychainItemModifyContent:
network_get_proxy_settings:
CopyCFStringToCString:
malloc:
CFURLCopyHostName:
unknown_protocol:
CFHTTPMessageCopyRequestURL:
if ( serverName != NULL )
{
free(serverName);
}
if ( realmStr != NULL )
{
free(realmStr);
}
if ( username != NULL )
{
free(username);
}
if ( password != NULL )
{
free(password);
}
if ( path != NULL )
{
free(path);
}
if ( messageURL != NULL )
{
CFRelease(messageURL);
}
return ( result );
}
static
int AddServerCredentials(CFHTTPMessageRef request)
{
int result;
CFStringRef username;
CFStringRef password;
CFStringRef domain;
int secureAuth;
username = password = domain = NULL;
result = EACCES;
if ( authcache_state == UNDEFINED_GUEST )
{
if ( CopyMountCredentials(authcache_server_entry->auth, &username, &password, &domain, &secureAuth) == 0 )
{
syslog(LOG_DEBUG, "AddServerCred:UNDEFINED_GUEST: -> TRY_MOUNT_CRED, req %p", request);
SetCredentials(authcache_server_entry, username, password, domain);
authcache_state = TRY_MOUNT_CRED;
++authcache_generation;
if ( authcache_generation == 0 )
{
++authcache_generation;
}
result = 0;
}
else
{
syslog(LOG_DEBUG, "AddServerCred:UNDEFINED_GUEST: no mount creds, req %p", request);
}
}
if ( (result != 0) && ( (authcache_state == UNDEFINED_GUEST) || (authcache_state == TRY_MOUNT_CRED)) )
{
if ( CopyCredentialsFromKeychain(authcache_server_entry->auth, request, &username, &password, &domain, FALSE, &secureAuth) == 0 )
{
syslog(LOG_DEBUG, "AddServerCred: state %d -> TRY_KEYCHAIN_CRED, req %p", authcache_state, request);
ReleaseCredentials(authcache_server_entry);
SetCredentials(authcache_server_entry, username, password, domain);
authcache_state = TRY_KEYCHAIN_CRED;
++authcache_generation;
if ( authcache_generation == 0 )
{
++authcache_generation;
}
result = 0;
}
else
{
syslog(LOG_DEBUG, "AddServerCred: state %d, no keychain creds, req %p", authcache_state, request);
}
}
if (result != 0)
{
int addtokeychain;
username = authcache_server_entry->username;
password = authcache_server_entry->password;
domain = authcache_server_entry->domain;
if (authcache_state != TRY_UI_CRED)
{
syslog(LOG_DEBUG, "AddServerCred: state %d -> TRY_UI_CRED, req %p", authcache_state, request);
}
else
{
syslog(LOG_DEBUG, "AddServerCred:TRY_UI_CRED: prompting user for creds, req %p", request);
}
result = CopyCredentialsFromUserNotification(authcache_server_entry->auth, request,
(authcache_state == TRY_UI_CRED), FALSE,
&username, &password, &domain, &addtokeychain, &secureAuth);
authcache_state = TRY_UI_CRED;
++authcache_generation;
if ( authcache_generation == 0 )
{
++authcache_generation;
}
if (result == 0)
{
syslog(LOG_DEBUG, "AddServerCred:TRY_UI_CRED: Got creds, retrying req %p", request);
ReleaseCredentials(authcache_server_entry);
SetCredentials(authcache_server_entry, username, password, domain);
if ( addtokeychain )
{
authcache_server_entry->authflags |= kAddCredentialsToKeychain;
}
}
else if (result == ECANCELED)
{
syslog(LOG_NOTICE, "Athentication cancelled by user action, mounting as guest user");
authcache_state = GUEST_USER;
++authcache_generation;
if ( authcache_generation == 0 )
{
++authcache_generation;
}
ReleaseCredentials(authcache_server_entry);
CFRelease(authcache_server_entry->auth);
free (authcache_server_entry);
authcache_server_entry = NULL;
result = EACCES;
}
else
{
syslog(LOG_DEBUG, "AddServerCred:TRY_UI_CRED: UI timed out, returning EACCES, req %p", request);
ReleaseCredentials(authcache_server_entry);
result = EACCES;
}
}
if ( (result == 0) && !(secureAuth) )
{
CFURLRef url;
CFStringRef urlString;
char *urlStr;
urlStr = NULL;
url = CFHTTPMessageCopyRequestURL(request);
if ( url != NULL )
{
urlString = CFURLGetString(url);
if ( urlString != NULL )
{
urlStr = CopyCFStringToCString(urlString);
}
else
{
urlStr = NULL;
}
CFRelease(url);
}
syslog(LOG_ERR | LOG_AUTHPRIV, "WebDAV FS authentication credentials are being sent insecurely to: %s", (urlStr ? urlStr : ""));
if ( urlStr != NULL )
{
free(urlStr);
}
}
return ( result );
}
static
int AddProxyCredentials(
struct authcache_entry *entry_ptr,
CFHTTPMessageRef request)
{
int result;
CFStringRef username;
CFStringRef password;
CFStringRef domain;
int secureAuth;
if ( CFHTTPAuthenticationRequiresUserNameAndPassword(entry_ptr->auth) )
{
username = password = domain = NULL;
result = EACCES;
if (entry_ptr->authflags & kCredentialsFromKeychain)
{
entry_ptr->authflags |= kNoKeychainCredentials;
}
if ( (entry_ptr->authflags & kNoKeychainCredentials) == 0 )
{
if ( CopyCredentialsFromKeychain(entry_ptr->auth, request, &username, &password, &domain, TRUE, &secureAuth) == 0 )
{
ReleaseCredentials(entry_ptr);
SetCredentials(entry_ptr, username, password, domain);
entry_ptr->authflags &= ~kAuthHasCredentials;
entry_ptr->authflags |= kCredentialsFromKeychain;
result = 0;
}
else
{
entry_ptr->authflags |= kNoKeychainCredentials;
result = EACCES;
}
}
if ( result != 0 )
{
int addtokeychain;
username = entry_ptr->username;
password = entry_ptr->password;
domain = entry_ptr->domain;
if ( CopyCredentialsFromUserNotification(entry_ptr->auth, request,
((entry_ptr->authflags & kCredentialsFromUI) != 0), TRUE,
&username, &password, &domain, &addtokeychain, &secureAuth) == 0 )
{
ReleaseCredentials(entry_ptr);
SetCredentials(entry_ptr, username, password, domain);
entry_ptr->authflags &= ~kAuthHasCredentials;
entry_ptr->authflags |= kCredentialsFromUI;
if ( addtokeychain )
{
entry_ptr->authflags |= kAddCredentialsToKeychain;
}
result = 0;
}
else
{
ReleaseCredentials(entry_ptr);
result = EACCES;
}
}
}
else
{
result = 0;
}
return ( result );
}
static
struct authcache_entry *CreateProxyAuthenticationFromResponse(
uid_t uid,
CFHTTPMessageRef request,
CFHTTPMessageRef response)
{
struct authcache_entry *entry_ptr;
int result;
entry_ptr = calloc(sizeof(struct authcache_entry), 1);
require(entry_ptr != NULL, calloc);
entry_ptr->uid = uid;
entry_ptr->auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response);
require(entry_ptr->auth != NULL, CFHTTPAuthenticationCreateFromResponse);
require(CFHTTPAuthenticationIsValid(entry_ptr->auth, NULL), CFHTTPAuthenticationIsValid);
result = AddProxyCredentials(entry_ptr, request);
require_noerr_quiet(result, AddProxyCredentials);
authcache_proxy_entry = entry_ptr;
++authcache_generation;
if ( authcache_generation == 0 )
{
++authcache_generation;
}
return ( entry_ptr );
AddProxyCredentials:
CFHTTPAuthenticationIsValid:
CFRelease(entry_ptr->auth);
CFHTTPAuthenticationCreateFromResponse:
free(entry_ptr);
calloc:
return ( NULL );
}
static int ApplyCredentialsToRequest(struct authcache_entry *entry_ptr, CFHTTPMessageRef request)
{
int result;
if ( entry_ptr->domain != NULL ) {
CFMutableDictionaryRef dict;
dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
require_action(dict != NULL, CFDictionaryCreateMutable, result = FALSE);
if ( entry_ptr->username != NULL ) {
CFDictionaryAddValue(dict, kCFHTTPAuthenticationUsername, entry_ptr->username);
}
if ( entry_ptr->password != NULL ) {
CFDictionaryAddValue(dict, kCFHTTPAuthenticationPassword, entry_ptr->password);
}
if ( entry_ptr->domain != NULL ) {
CFDictionaryAddValue(dict, kCFHTTPAuthenticationAccountDomain, entry_ptr->domain);
}
result = CFHTTPMessageApplyCredentialDictionary(request, entry_ptr->auth, dict, NULL);
CFRelease(dict);
}
else {
result = CFHTTPMessageApplyCredentials(request, entry_ptr->auth, entry_ptr->username, entry_ptr->password, NULL);
}
CFDictionaryCreateMutable:
return ( result );
}
static
int AddExistingAuthentications(
CFHTTPMessageRef request)
{
switch (authcache_state)
{
case UNDEFINED_GUEST:
if (authcache_server_entry != NULL)
{
if (CFHTTPAuthenticationIsValid(authcache_server_entry->auth, NULL))
{
syslog(LOG_DEBUG, "AddExistingAuth:UNDEFINED_GUEST: applying creds, req %p", request);
ApplyCredentialsToRequest(authcache_server_entry, request);
}
else
{
syslog(LOG_DEBUG, "AddExistingAuth:UNDEFINED_GUEST: auth obj not valid, req %p", request);
}
}
break;
case TRY_MOUNT_CRED:
case TRY_KEYCHAIN_CRED:
case TRY_UI_CRED:
case AUTHENTICATED_USER:
if (CFHTTPAuthenticationIsValid(authcache_server_entry->auth, NULL))
{
ApplyCredentialsToRequest(authcache_server_entry, request);
}
else
{
syslog(LOG_DEBUG, "AddExistingAuth: state %d, auth obj not valid, req %p", authcache_state, request);
}
break;
case GUEST_USER:
break;
}
if ( authcache_proxy_entry != NULL )
{
if ( !CFHTTPAuthenticationIsValid(authcache_proxy_entry->auth, NULL) || !ApplyCredentialsToRequest(authcache_proxy_entry, request) )
{
RemoveAuthentication(authcache_proxy_entry);
}
}
return ( 0 );
}
static
int DoServerAuthentication(
uid_t uid,
CFHTTPMessageRef request,
CFHTTPMessageRef response,
AuthRequestContext *ctx)
{
CFHTTPAuthenticationRef auth;
int result = 0;
switch (authcache_state) {
case UNDEFINED_GUEST:
if ( authcache_server_entry == NULL)
{
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: creating authcache_server_entry, req %p", request);
authcache_server_entry = calloc(sizeof(struct authcache_entry), 1);
require(authcache_server_entry != NULL, calloc_entry);
authcache_server_entry->uid = uid;
authcache_server_entry->auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response);
require(authcache_server_entry->auth != NULL, CFHTTPAuthenticationCreateFromResponse);
require(CFHTTPAuthenticationIsValid(authcache_server_entry->auth, NULL), CFHTTPAuthenticationIsValid);
++authcache_generation;
if ( authcache_generation == 0 )
++authcache_generation;
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: authcache_server_entry created, req %p", request);
}
else
{
if (ctx->generation != authcache_generation)
{
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: stale generation, req %p", request);
result = 0;
goto done;
}
if ( !CFHTTPAuthenticationAppliesToRequest(authcache_server_entry->auth, request) )
{
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: auth doesn't apply to req %p", request);
result = EACCES;
goto done;
}
if ( !CFHTTPAuthenticationIsValid(authcache_server_entry->auth, NULL) )
{
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: authcache_server_entry not valid, req %p", request);
auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response);
if (auth == NULL) {
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: failed to create auth obj from response, req %p", request);
result = EACCES;
goto done;
}
if ( !CFHTTPAuthenticationIsValid(auth, NULL) )
{
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: new auth obj not valid, req %p", request);
CFRelease(auth);
result = EACCES;
goto done;
}
CFRelease(authcache_server_entry->auth);
authcache_server_entry->auth = auth;
++authcache_generation;
if ( authcache_generation == 0 )
++authcache_generation;
}
}
if ( CFHTTPAuthenticationRequiresUserNameAndPassword(authcache_server_entry->auth) )
{
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: Adding Server Credentials, req %p", request);
result = AddServerCredentials(request);
}
else
{
syslog(LOG_DEBUG, "doServerAuth:UNDEFINED_GUEST: Crendentials not needed, req %p", request);
result = 0;
}
break;
case TRY_MOUNT_CRED:
case TRY_KEYCHAIN_CRED:
case TRY_UI_CRED:
if (ctx->generation != authcache_generation)
{
syslog(LOG_DEBUG, "webdav_fsagent:doServerAuth: state %d, stale generation, req %p", authcache_state, request);
result = 0;
goto done;
}
if ( !CFHTTPAuthenticationAppliesToRequest(authcache_server_entry->auth, request) )
{
syslog(LOG_DEBUG, "doServerAuth: state %d, auth doesn't apply to req %p", authcache_state, request);
result = EACCES;
goto done;
}
if ( !CFHTTPAuthenticationIsValid(authcache_server_entry->auth, NULL) )
{
syslog(LOG_DEBUG, "doServerAuth: state %d, auth not valid, req %p", authcache_state, request);
auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response);
if (auth == NULL) {
syslog(LOG_DEBUG, "doServerAuth: state %d, failed to create auth obj from response, req %p",
authcache_state, request);
result = EACCES;
goto done;
}
if ( !CFHTTPAuthenticationIsValid(auth, NULL) )
{
syslog(LOG_DEBUG, "doServerAuth: state %d, new auth obj not valid, req %p", authcache_state, request);
CFRelease(auth);
result = EACCES;
goto done;
}
CFRelease(authcache_server_entry->auth);
authcache_server_entry->auth = auth;
++authcache_generation;
if ( authcache_generation == 0 )
++authcache_generation;
}
result = AddServerCredentials(request);
break;
case AUTHENTICATED_USER:
if (ctx->generation != authcache_generation)
{
syslog(LOG_DEBUG, "doServerAuth:AUTHENTICATED_USER: stale generation, req %p", request);
result = 0;
goto done;
}
if ( !CFHTTPAuthenticationAppliesToRequest(authcache_server_entry->auth, request) )
{
syslog(LOG_DEBUG, "doServerAuth:AUTHENTICATED_USER: auth doesn't apply to req %p", request);
result = EACCES;
goto done;
}
if ( !CFHTTPAuthenticationIsValid(authcache_server_entry->auth, NULL) )
{
syslog(LOG_DEBUG, "doServerAuth:AUTHENTICATED_USER: authcache_server_entry not valid, req %p", request);
auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response);
if (auth == NULL) {
syslog(LOG_DEBUG, "doServerAuth:AUTHENTICATED_USER: failed to create auth obj from response, req %p", request);
result = EACCES;
goto done;
}
if ( !CFHTTPAuthenticationIsValid(auth, NULL) )
{
syslog(LOG_DEBUG, "webdavfs_agent:doServerAuth:AUTHENTICATED_USER: new auth obj not valid, req %p", request);
CFRelease(auth);
result = EACCES;
goto done;
}
CFRelease(authcache_server_entry->auth);
authcache_server_entry->auth = auth;
++authcache_generation;
if ( authcache_generation == 0 )
++authcache_generation;
}
if (ctx->count < MAX_AUTHENTICATED_USER_RETRIES)
{
ctx->count++;
result = 0;
}
else
{
syslog(LOG_DEBUG, "doServerAuth:AUTHENTICATED_USER: to many auth retries for req %p", request);
result = EACCES;
}
break;
case GUEST_USER:
syslog(LOG_DEBUG, "doServerAuth:GUEST: not authorized, req %p", request);
result = EACCES;
break;
}
done:
return (result);
CFHTTPAuthenticationIsValid:
CFRelease(authcache_server_entry->auth);
CFHTTPAuthenticationCreateFromResponse:
free (authcache_server_entry);
authcache_server_entry = NULL;
calloc_entry:
result = EACCES;
return (result);
}
static
int AddProxyAuthentication(
uid_t uid,
CFHTTPMessageRef request,
CFHTTPMessageRef response)
{
int result;
if ( authcache_proxy_entry != NULL )
{
authcache_proxy_entry->authflags &= ~kCredentialsValid;
if ( CFHTTPAuthenticationIsValid(authcache_proxy_entry->auth, NULL) )
{
result = 0;
}
else
{
CFRelease(authcache_proxy_entry->auth);
authcache_proxy_entry->auth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, response);
if ( authcache_proxy_entry->auth != NULL )
{
if ( CFHTTPAuthenticationIsValid(authcache_proxy_entry->auth, NULL) )
{
result = AddProxyCredentials(authcache_proxy_entry, request);
}
else
{
result = EACCES;
}
}
else
{
result = EACCES;
}
}
if ( result != 0 )
{
RemoveAuthentication(authcache_proxy_entry);
}
}
else
{
authcache_proxy_entry = CreateProxyAuthenticationFromResponse(uid, request, response);
if ( authcache_proxy_entry != NULL )
{
result = 0;
}
else
{
result = EACCES;
}
}
return ( result );
}
int authcache_apply(
uid_t uid,
CFHTTPMessageRef request,
UInt32 statusCode,
CFHTTPMessageRef response,
AuthRequestContext *ctx)
{
int result, result2;
result = pthread_mutex_lock(&authcache_lock);
require_noerr_action(result, pthread_mutex_lock, webdav_kill(-1));
switch (statusCode)
{
case 0:
result = 0;
break;
case 401:
if ( (gProcessUID == uid) || (0 == uid) )
{
result = DoServerAuthentication(uid, request, response, ctx);
}
else
{
result = EACCES;
}
break;
case 407:
if ( (gProcessUID == uid) || (0 == uid) )
{
result = AddProxyAuthentication(uid, request, response);
}
else
{
result = EACCES;
}
break;
default:
result = EACCES;
break;
}
if ( (result == 0) && ((gProcessUID == uid) || (0 == uid)) )
{
result = AddExistingAuthentications(request);
}
ctx->generation = authcache_generation;
result2 = pthread_mutex_unlock(&authcache_lock);
require_noerr_action(result2, pthread_mutex_unlock, result = result2; webdav_kill(-1));
pthread_mutex_unlock:
pthread_mutex_lock:
return ( result );
}
int authcache_valid(
uid_t uid,
CFHTTPMessageRef request,
AuthRequestContext *ctx)
{
int result, result2;
require_quiet(((gProcessUID == uid) || (0 == uid)), not_owner_uid);
result = pthread_mutex_lock(&authcache_lock);
require_noerr_action(result, pthread_mutex_lock, webdav_kill(-1));
if ( ctx->generation == authcache_generation )
{
switch (authcache_state)
{
case UNDEFINED_GUEST:
case AUTHENTICATED_USER:
case GUEST_USER:
break;
case TRY_MOUNT_CRED:
case TRY_KEYCHAIN_CRED:
case TRY_UI_CRED:
syslog(LOG_NOTICE, "mounting as authenticated user");
authcache_state = AUTHENTICATED_USER;
++authcache_generation;
if ( authcache_generation == 0 )
{
++authcache_generation;
}
if ( authcache_server_entry->authflags & kAddCredentialsToKeychain )
{
authcache_server_entry->authflags &= ~kAddCredentialsToKeychain;
result = SaveCredentialsToKeychain(authcache_server_entry, request, FALSE);
}
break;
}
if ( authcache_proxy_entry != NULL )
{
authcache_proxy_entry->authflags |= kCredentialsValid;
if ( authcache_proxy_entry->authflags & kAddCredentialsToKeychain )
{
authcache_proxy_entry->authflags &= ~kAddCredentialsToKeychain;
result = SaveCredentialsToKeychain(authcache_proxy_entry, request, TRUE);
}
}
}
result2 = pthread_mutex_unlock(&authcache_lock);
require_noerr_action(result2, pthread_mutex_unlock, result = result2; webdav_kill(-1));
pthread_mutex_unlock:
pthread_mutex_lock:
not_owner_uid:
return ( 0 );
}
int authcache_proxy_invalidate(void)
{
int result, result2;
result = pthread_mutex_lock(&authcache_lock);
require_noerr_action(result, pthread_mutex_lock, webdav_kill(-1));
if ( authcache_proxy_entry != NULL )
{
RemoveAuthentication(authcache_proxy_entry);
}
result2 = pthread_mutex_unlock(&authcache_lock);
require_noerr_action(result2, pthread_mutex_unlock, result = result2; webdav_kill(-1));
pthread_mutex_unlock:
pthread_mutex_lock:
return ( result );
}
int authcache_init(
char *username,
char *password,
char *domain)
{
int result;
pthread_mutexattr_t mutexattr;
result = pthread_mutexattr_init(&mutexattr);
require_noerr(result, pthread_mutexattr_init);
result = pthread_mutex_init(&authcache_lock, &mutexattr);
require_noerr(result, pthread_mutex_init);
authcache_generation = 1;
result = 0;
if ( username != NULL && password != NULL && username[0] != '\0')
{
mount_username = CFStringCreateWithCString(kCFAllocatorDefault, username, kCFStringEncodingUTF8);
require_action(mount_username != NULL, CFStringCreateWithCString, result = ENOMEM);
mount_password = CFStringCreateWithCString(kCFAllocatorDefault, password, kCFStringEncodingUTF8);
require_action(mount_password != NULL, CFStringCreateWithCString, result = ENOMEM);
}
if ( domain != NULL && domain[0] != '\0' )
{
mount_domain = CFStringCreateWithCString(kCFAllocatorDefault, domain, kCFStringEncodingUTF8);
require_action(mount_domain != NULL, CFStringCreateWithCString, result = ENOMEM);
}
CFStringCreateWithCString:
pthread_mutex_init:
pthread_mutexattr_init:
return ( result );
}