#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCSchemaDefinitions.h>
#include <CoreServices/CoreServices.h>
#include <CoreServices/CoreServicesPriv.h>
#include <netdb.h>
#include <syslog.h>
#include "webdavlib.h"
#define STREAM_EVENT_BUFSIZE 4096
#define WEBDAVLIB_MAX_AGAIN_COUNT 10
#define WEBAVLIB_USER_AGENT_STRING "WebDAVLib/1.1"
#define CFReleaseNull(obj) do { if(obj != NULL) { CFRelease(obj); obj = NULL; } } while (0)
enum CheckAuthCallbackStatus {CheckAuthInprogress = 0, CheckAuthCallbackDone = 1, CheckAuthCallbackStreamError = 2};
struct callback_ctx {
CFMutableDataRef theData; CFHTTPMessageRef response; CFMutableDictionaryRef sslPropDict; CFHTTPAuthenticationRef serverAuth;
uint32_t againCount;
boolean_t triedServerCredentials; boolean_t triedProxyServerCredentials;
CFStringRef proxyRealm;
boolean_t httpProxyEnabled; CFStringRef httpProxyServer; int httpProxyPort;
boolean_t httpsProxyEnabled; CFStringRef httpsProxyServer; int httpsProxyPort;
CFDictionaryRef proxyDict; SCDynamicStoreRef proxyStore; CFHTTPAuthenticationRef proxyAuth; CFIndex statusCode; CFStreamError streamError; enum CheckAuthCallbackStatus status;
};
static enum WEBDAVLIBAuthStatus finalStatusFromStatusCode(struct callback_ctx *ctx, int *error);
static int handleStreamError(struct callback_ctx *ctx, boolean_t *tryAgain);
static int handleSSLErrors(struct callback_ctx *ctx, boolean_t *tryAgain);
static enum WEBDAVLIBAuthStatus sendOptionsRequest(CFURLRef a_url, struct callback_ctx *ctx, int *result);
static enum WEBDAVLIBAuthStatus sendOptionsRequestAuthenticated(CFURLRef a_url, struct callback_ctx *ctx, CFDictionaryRef creds, int *result);
static void applyCredentialsToRequest(struct callback_ctx *ctx, CFDictionaryRef creds, CFHTTPMessageRef request);
static void checkServerAuth_handleStreamEvent(CFReadStreamRef stream, CFStreamEventType type, void *clientCallBackInfo);
static int updateNetworkProxies(struct callback_ctx *ctx);
static void releaseContextItems(struct callback_ctx *ctx);
static void initContext(struct callback_ctx *ctx);
static SCDynamicStoreRef gProxyStore;
enum
{
kHttpDefaultPort = 80, kHttpsDefaultPort = 443 };
enum WEBDAVLIBAuthStatus
queryForProxy(CFURLRef a_url, CFMutableDictionaryRef proxyInfo, int *error)
{
enum WEBDAVLIBAuthStatus finalStatus;
int result;
struct callback_ctx ctx;
CFStringRef cf_port;
initContext(&ctx);
finalStatus = sendOptionsRequest(a_url, &ctx, &result);
*error = result;
switch (finalStatus) {
case WEBDAVLIB_Success:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_Success", __FUNCTION__);
break;
case WEBDAVLIB_ProxyAuth:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_ProxyAuth", __FUNCTION__);
if(ctx.httpProxyEnabled == TRUE) {
CFDictionarySetValue(proxyInfo, kWebDAVLibProxySchemeKey, CFSTR("http"));
CFDictionarySetValue(proxyInfo, kWebDAVLibProxyServerNameKey, ctx.httpProxyServer);
if (ctx.proxyRealm != NULL)
CFDictionarySetValue(proxyInfo, kWebDAVLibProxyRealmKey, ctx.proxyRealm);
cf_port = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), ctx.httpProxyPort);
if (cf_port != NULL) {
CFDictionarySetValue(proxyInfo, kWebDAVLibProxyPortKey, cf_port);
CFRelease(cf_port);
}
}
else {
CFDictionarySetValue(proxyInfo, kWebDAVLibProxySchemeKey, CFSTR("https"));
CFDictionarySetValue(proxyInfo, kWebDAVLibProxyServerNameKey, ctx.httpsProxyServer);
if (ctx.proxyRealm != NULL)
CFDictionarySetValue(proxyInfo, kWebDAVLibProxyRealmKey, ctx.proxyRealm);
cf_port = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), ctx.httpsProxyPort);
if (cf_port != NULL) {
CFDictionarySetValue(proxyInfo, kWebDAVLibProxyPortKey, cf_port);
CFRelease(cf_port);
}
}
break;
case WEBDAVLIB_ServerAuth:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_ServerAuth", __FUNCTION__);
break;
case WEBDAVLIB_UnexpectedStatus:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_UnexpectedStatus, errno: %d", __FUNCTION__, result);
break;
case WEBDAVLIB_IOError:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_IOError, errno: %d", __FUNCTION__, result);
break;
}
releaseContextItems(&ctx);
return (finalStatus);
}
enum WEBDAVLIBAuthStatus
connectToServer(CFURLRef a_url, CFDictionaryRef creds, int *error)
{
enum WEBDAVLIBAuthStatus finalStatus;
int result;
struct callback_ctx ctx;
CFStringRef cf_port;
initContext(&ctx);
finalStatus = sendOptionsRequestAuthenticated(a_url, &ctx, creds, &result);
*error = result;
switch (finalStatus) {
case WEBDAVLIB_Success:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_Success", __FUNCTION__);
break;
case WEBDAVLIB_ProxyAuth:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_ProxyAuth", __FUNCTION__);
break;
case WEBDAVLIB_ServerAuth:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_ServerAuth", __FUNCTION__);
break;
case WEBDAVLIB_UnexpectedStatus:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_UnexpectedStatus, errno %d", __FUNCTION__, result);
break;
case WEBDAVLIB_IOError:
syslog(LOG_DEBUG, "%s: Returning WEBDAVLIB_IOError, errno %d", __FUNCTION__, result);
break;
}
releaseContextItems(&ctx);
return (finalStatus);
}
static enum WEBDAVLIBAuthStatus
sendOptionsRequest(CFURLRef a_url, struct callback_ctx *ctx, int *err)
{
CFHTTPMessageRef message;
CFReadStreamRef rdStream;
boolean_t done, tryAgain;
enum WEBDAVLIBAuthStatus finalStatus;
*err = 0;
ctx->status = CheckAuthInprogress;
ctx->theData = CFDataCreateMutable(NULL, 0);
ctx->sslPropDict = NULL;
CFStreamClientContext context = {0, ctx, NULL, NULL, NULL};
updateNetworkProxies(ctx);
done = FALSE;
while (done == FALSE) {
message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("OPTIONS"), a_url, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("User-Agent"), CFSTR(WEBAVLIB_USER_AGENT_STRING));
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Accept"), CFSTR("*/*"));
rdStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, message);
CFRelease(message);
message = NULL;
ctx->status = CheckAuthInprogress;
CFReadStreamSetProperty(rdStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);
if (ctx->proxyDict != NULL)
CFReadStreamSetProperty(rdStream, kCFStreamPropertyHTTPProxy, ctx->proxyDict);
if (ctx->sslPropDict != NULL)
CFReadStreamSetProperty(rdStream, kCFStreamPropertySSLSettings, ctx->sslPropDict);
CFReadStreamSetClient(rdStream,
kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred,
checkServerAuth_handleStreamEvent,
&context);
CFReadStreamScheduleWithRunLoop(rdStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFReadStreamOpen(rdStream);
while (ctx->status == CheckAuthInprogress) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 20, TRUE);
}
if (ctx->status == CheckAuthCallbackDone) {
finalStatus = finalStatusFromStatusCode(ctx, err);
if (finalStatus == WEBDAVLIB_ProxyAuth) {
ctx->proxyAuth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, ctx->response);
ctx->proxyRealm = CFHTTPAuthenticationCopyRealm(ctx->proxyAuth);
}
done = TRUE;
}
else if (ctx->status = CheckAuthCallbackStreamError) {
*err = handleStreamError(ctx, &tryAgain);
if ((tryAgain == FALSE) || (++ctx->againCount > WEBDAVLIB_MAX_AGAIN_COUNT)) {
finalStatus = WEBDAVLIB_IOError;
done = TRUE;
}
}
CFReadStreamSetClient(rdStream, kCFStreamEventNone, NULL, NULL);
CFReadStreamUnscheduleFromRunLoop(rdStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFReadStreamClose(rdStream);
CFRelease(rdStream);
rdStream = NULL;
CFRelease(ctx->theData);
ctx->theData = CFDataCreateMutable(NULL, 0);
}
return (finalStatus);
}
static enum WEBDAVLIBAuthStatus
sendOptionsRequestAuthenticated(CFURLRef a_url, struct callback_ctx *ctx, CFDictionaryRef creds, int *err)
{
CFHTTPMessageRef message;
CFReadStreamRef rdStream;
boolean_t done, tryAgain;
enum WEBDAVLIBAuthStatus finalStatus;
*err = 0;
ctx->status = CheckAuthInprogress;
ctx->theData = CFDataCreateMutable(NULL, 0);
ctx->sslPropDict = NULL;
CFStreamClientContext context = {0, ctx, NULL, NULL, NULL};
updateNetworkProxies(ctx);
done = FALSE;
while (done == FALSE) {
message = CFHTTPMessageCreateRequest(kCFAllocatorDefault, CFSTR("OPTIONS"), a_url, kCFHTTPVersion1_1);
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("User-Agent"), CFSTR(WEBAVLIB_USER_AGENT_STRING));
CFHTTPMessageSetHeaderFieldValue(message, CFSTR("Accept"), CFSTR("*/*"));
applyCredentialsToRequest(ctx, creds, message);
rdStream = CFReadStreamCreateForHTTPRequest(kCFAllocatorDefault, message);
CFRelease(message);
message = NULL;
ctx->status = CheckAuthInprogress;
CFReadStreamSetProperty(rdStream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue);
if (ctx->proxyDict != NULL)
CFReadStreamSetProperty(rdStream, kCFStreamPropertyHTTPProxy, ctx->proxyDict);
if (ctx->sslPropDict != NULL)
CFReadStreamSetProperty(rdStream, kCFStreamPropertySSLSettings, ctx->sslPropDict);
CFReadStreamSetClient(rdStream,
kCFStreamEventHasBytesAvailable | kCFStreamEventEndEncountered | kCFStreamEventErrorOccurred,
checkServerAuth_handleStreamEvent,
&context);
CFReadStreamScheduleWithRunLoop(rdStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFReadStreamOpen(rdStream);
while (ctx->status == CheckAuthInprogress) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 20, TRUE);
}
if (ctx->status == CheckAuthCallbackDone) {
finalStatus = finalStatusFromStatusCode(ctx, err);
if (finalStatus == WEBDAVLIB_ServerAuth) {
if (ctx->serverAuth == NULL) {
ctx->serverAuth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, ctx->response);
if (ctx->serverAuth != NULL) {
if (CFHTTPAuthenticationIsValid(ctx->serverAuth, NULL) == FALSE) {
syslog(LOG_DEBUG, "%s: Server CFHTTPAuthenticationIsValid is FALSE", __FUNCTION__);
*err = EIO;
done = TRUE;
continue;
}
if (CFHTTPAuthenticationRequiresUserNameAndPassword(ctx->serverAuth) == TRUE) {
if (CFDictionaryContainsKey(creds, kWebDAVLibUserNameKey) == FALSE) {
syslog(LOG_DEBUG, "%s: No server credentials in dictionary", __FUNCTION__);
done = TRUE;
}
}
}
else {
syslog(LOG_DEBUG, "%s: Initial Server CFHTTPAuthenticationCreateFromResponse returned NULL", __FUNCTION__);
done = TRUE;
*err = EIO;
}
}
else {
if (CFHTTPAuthenticationIsValid(ctx->serverAuth, NULL) == FALSE) {
CFRelease(ctx->serverAuth);
ctx->serverAuth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, ctx->response);
if (ctx->serverAuth != NULL) {
if (CFHTTPAuthenticationIsValid(ctx->serverAuth, NULL) == FALSE) {
syslog(LOG_DEBUG, "%s: Server CFHTTPAuthenticationIsValid is FALSE", __FUNCTION__);
*err = EIO;
done = TRUE;
continue;
}
if (CFHTTPAuthenticationRequiresUserNameAndPassword(ctx->serverAuth) == TRUE) {
if (CFDictionaryContainsKey(creds, kWebDAVLibUserNameKey) == FALSE) {
syslog(LOG_DEBUG, "%s: No server credentials in dictionary", __FUNCTION__);
done = TRUE;
}
if (ctx->triedServerCredentials == TRUE) {
syslog(LOG_DEBUG, "%s: Server credentials were not accepted", __FUNCTION__);
done = TRUE;
}
}
}
else {
syslog(LOG_DEBUG, "%s: Server CFHTTPAuthenticationCreateFromResponse returned NULL", __FUNCTION__);
*err = EIO;
done = TRUE;
}
}
}
}
else if (finalStatus == WEBDAVLIB_ProxyAuth) {
if (ctx->proxyAuth == NULL) {
if (CFDictionaryContainsKey(creds, kWebDAVLibProxyUserNameKey) == FALSE) {
syslog(LOG_DEBUG, "%s: No proxy server credentials in dictionary", __FUNCTION__);
done = TRUE;
continue;
}
ctx->proxyAuth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, ctx->response);
if (ctx->proxyAuth != NULL) {
if (CFHTTPAuthenticationIsValid(ctx->proxyAuth, NULL) == FALSE) {
syslog(LOG_DEBUG, "%s: Proxy CFHTTPAuthenticationIsValid is FALSE", __FUNCTION__);
*err = EIO;
done = TRUE;
continue;
}
if (CFHTTPAuthenticationRequiresUserNameAndPassword(ctx->proxyAuth) == TRUE) {
if (CFDictionaryContainsKey(creds, kWebDAVLibProxyUserNameKey) == FALSE) {
syslog(LOG_DEBUG, "%s: No proxy server credentials in dictionary", __FUNCTION__);
done = TRUE;
}
}
}
else {
syslog(LOG_DEBUG, "%s: Server CFHTTPAuthenticationCreateFromResponse returned NULL", __FUNCTION__);
*err = EIO;
done = TRUE;
}
}
else {
if (CFHTTPAuthenticationIsValid(ctx->proxyAuth, NULL) == FALSE) {
CFRelease(ctx->proxyAuth);
ctx->proxyAuth = CFHTTPAuthenticationCreateFromResponse(kCFAllocatorDefault, ctx->response);
if (ctx->proxyAuth != NULL) {
if (CFHTTPAuthenticationIsValid(ctx->proxyAuth, NULL) == FALSE) {
syslog(LOG_DEBUG, "%s: Proxy server CFHTTPAuthenticationIsValid is FALSE", __FUNCTION__);
*err = EIO;
done = TRUE;
continue;
}
if (CFHTTPAuthenticationRequiresUserNameAndPassword(ctx->proxyAuth) == TRUE) {
if (CFDictionaryContainsKey(creds, kWebDAVLibProxyUserNameKey) == FALSE) {
syslog(LOG_DEBUG, "%s: No proxy server creds in dictionary", __FUNCTION__);
done = TRUE;
}
if (ctx->triedProxyServerCredentials == TRUE) {
syslog(LOG_DEBUG, "%s: Proxy server credentials were not accepted", __FUNCTION__);
done = TRUE;
}
}
}
else {
syslog(LOG_DEBUG, "%s: Proxy server CFHTTPAuthenticationCreateFromResponse returned NULL", __FUNCTION__);
*err = EIO;
done = TRUE;
}
}
}
}
else {
done = TRUE;
}
}
else if (ctx->status = CheckAuthCallbackStreamError) {
*err = handleStreamError(ctx, &tryAgain);
if ((tryAgain == FALSE) || (++ctx->againCount > WEBDAVLIB_MAX_AGAIN_COUNT)) {
finalStatus = WEBDAVLIB_IOError;
done = TRUE;
}
}
CFReadStreamSetClient(rdStream, kCFStreamEventNone, NULL, NULL);
CFReadStreamUnscheduleFromRunLoop(rdStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
CFReadStreamClose(rdStream);
CFRelease(rdStream);
rdStream = NULL;
CFRelease(ctx->theData);
ctx->theData = CFDataCreateMutable(NULL, 0);
}
return (finalStatus);
}
static void applyCredentialsToRequest(struct callback_ctx *ctx, CFDictionaryRef creds, CFHTTPMessageRef request)
{
CFStringRef user, password;
if (ctx->serverAuth != NULL) {
user = CFDictionaryGetValue(creds, kWebDAVLibUserNameKey);
password = CFDictionaryGetValue(creds, kWebDAVLibPasswordKey);
CFHTTPMessageApplyCredentials(request, ctx->serverAuth, user, password, NULL);
ctx->triedServerCredentials = TRUE;
}
if (ctx->proxyAuth != NULL) {
user = CFDictionaryGetValue(creds, kWebDAVLibProxyUserNameKey);
password = CFDictionaryGetValue(creds, kWebDAVLibProxyPasswordKey);
CFHTTPMessageApplyCredentials(request, ctx->proxyAuth, user, password, NULL);
ctx->triedProxyServerCredentials = TRUE;
}
}
static enum WEBDAVLIBAuthStatus
finalStatusFromStatusCode(struct callback_ctx *ctx, int *error)
{
enum WEBDAVLIBAuthStatus finalStatus;
*error = 0;
switch (ctx->statusCode / 100) {
case 2: finalStatus = WEBDAVLIB_Success;
break;
case 4:
if (ctx->statusCode == 401) {
finalStatus = WEBDAVLIB_ServerAuth;
*error = EAUTH;
}
else if (ctx->statusCode == 407) {
finalStatus = WEBDAVLIB_ProxyAuth;
*error = EAUTH;
}
else {
syslog(LOG_ERR, "%s: unexpected http status code %d\n", __FUNCTION__, ctx->statusCode);
*error = EIO;
finalStatus = WEBDAVLIB_UnexpectedStatus;
}
break;
case 1: case 3: case 5: default:
syslog(LOG_ERR, "%s: unexpected http status code %d\n", __FUNCTION__, ctx->statusCode);
finalStatus = WEBDAVLIB_UnexpectedStatus;
*error = EIO;
break;
}
return (finalStatus);
}
static int
handleStreamError(struct callback_ctx *ctx, boolean_t *tryAgain)
{
int result = EIO;
*tryAgain = FALSE;
if (ctx->streamError.domain == kCFStreamErrorDomainSSL) {
result = handleSSLErrors(ctx, tryAgain);
}
else if (ctx->streamError.domain == kCFStreamErrorDomainPOSIX) {
result = ctx->streamError.error;
if (result == EPIPE) {
syslog(LOG_DEBUG, "%s: retrying stream error domain: posix error: EPIPE\n", __FUNCTION__);
*tryAgain = TRUE;
}
else
syslog(LOG_ERR, "%s: stream error domain: posix error: %d\n", __FUNCTION__, ctx->streamError.error);
}
else if (ctx->streamError.domain == kCFStreamErrorDomainHTTP) {
if (ctx->streamError.error == kCFStreamErrorHTTPConnectionLost) {
syslog(LOG_DEBUG, "%s: retrying, stream error domain: http error: kCFStreamErrorHTTPConnectionLost", __FUNCTION__);
*tryAgain = TRUE;
result = ECONNRESET;
}
else {
syslog(LOG_ERR, "%s: stream error domain: http error: %d", __FUNCTION__, ctx->streamError.error);
result = EIO;
}
}
else if (ctx->streamError.domain == kCFStreamErrorDomainNetDB) {
switch (ctx->streamError.error) {
case EAI_NODATA:
syslog(LOG_DEBUG, "%s: retrying, stream error domain: netdb error: EAI_NODATA", __FUNCTION__);
*tryAgain = TRUE;
result = EADDRNOTAVAIL;
break;
default:
syslog(LOG_ERR, "%s: stream error domain: netdb error: %d\n", __FUNCTION__, ctx->streamError.error);
result = EIO;
break;
}
}
else {
syslog(LOG_ERR, "%s: stream error domain: %ld error: %d\n", __FUNCTION__, ctx->streamError.domain, ctx->streamError.error);
result = EIO;
}
return (result);
}
static int
handleSSLErrors(struct callback_ctx *ctx, boolean_t *tryAgain)
{
SInt32 error;
int result;
result = EIO;
*tryAgain = TRUE;
error = ctx->streamError.error;
syslog(LOG_DEBUG, "%s: stream error domain: ssl error: %d", __FUNCTION__, ctx->streamError.error);
if (ctx->sslPropDict == NULL)
ctx->sslPropDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (ctx->sslPropDict == NULL) {
syslog(LOG_ERR, "%s: no memory for sslPropDictionary", __FUNCTION__);
return ENOMEM;
}
if ( (CFDictionaryGetValue(ctx->sslPropDict, kCFStreamSSLLevel) == NULL) &&
(((error <= errSSLProtocol) && (error > errSSLXCertChainInvalid)) ||
((error <= errSSLCrypto) && (error > errSSLUnknownRootCert)) ||
((error <= errSSLClosedNoNotify) && (error > errSSLPeerBadCert)) ||
(error == errSSLIllegalParam) ||
((error <= errSSLPeerAccessDenied) && (error > errSSLLast))) )
{
CFDictionarySetValue(ctx->sslPropDict, kCFStreamSSLLevel, kCFStreamSocketSecurityLevelSSLv3);
return (result);
}
switch ( ctx->streamError.error )
{
case errSSLCertExpired:
case errSSLCertNotYetValid:
if ( (CFDictionaryGetValue(ctx->sslPropDict, kCFStreamSSLAllowsExpiredCertificates) == NULL) )
{
CFDictionarySetValue(ctx->sslPropDict, kCFStreamSSLAllowsExpiredCertificates, kCFBooleanTrue);
CFDictionarySetValue(ctx->sslPropDict, kCFStreamSSLAllowsExpiredRoots, kCFBooleanTrue);
}
break;
case errSSLBadCert:
case errSSLXCertChainInvalid:
case errSSLHostNameMismatch:
if ( (CFDictionaryGetValue(ctx->sslPropDict, kCFStreamSSLValidatesCertificateChain) == NULL) )
{
CFDictionarySetValue(ctx->sslPropDict, kCFStreamSSLValidatesCertificateChain, kCFBooleanFalse);
}
break;
case errSSLUnknownRootCert:
case errSSLNoRootCert:
if ( (CFDictionaryGetValue(ctx->sslPropDict, kCFStreamSSLAllowsAnyRoot) == NULL) )
{
CFDictionarySetValue(ctx->sslPropDict, kCFStreamSSLAllowsAnyRoot, kCFBooleanTrue);
}
break;
default:
syslog(LOG_ERR, "%s: stream error domain: ssl error: %d", __FUNCTION__, ctx->streamError.error);
*tryAgain = TRUE;
break;
}
return (result);
}
static void checkServerAuth_handleStreamEvent(CFReadStreamRef stream, CFStreamEventType type, void *clientCallBackInfo)
{
struct callback_ctx *ctx;
CFTypeRef theResponsePropertyRef;
CFIndex bytesRead;
CFStreamError streamError;
UInt8 buffer[STREAM_EVENT_BUFSIZE];
ctx = (struct callback_ctx *)clientCallBackInfo;
switch (type) {
case kCFStreamEventHasBytesAvailable:
bytesRead = CFReadStreamRead(stream, buffer, STREAM_EVENT_BUFSIZE);
if (bytesRead > 0) {
CFDataAppendBytes(ctx->theData, buffer, bytesRead);
}
break;
case kCFStreamEventEndEncountered:
theResponsePropertyRef = CFReadStreamCopyProperty(stream, kCFStreamPropertyHTTPResponseHeader);
ctx->response = *((CFHTTPMessageRef*)((void*)&theResponsePropertyRef));
ctx->statusCode = CFHTTPMessageGetResponseStatusCode(ctx->response);
ctx->status = CheckAuthCallbackDone;
syslog(LOG_DEBUG, "%s: StreamEventEndEncountered, status code %d\n", __FUNCTION__, ctx->statusCode);
break;
case kCFStreamEventErrorOccurred:
streamError = CFReadStreamGetError(stream);
syslog(LOG_DEBUG,"%s: EventHasErrorOccurred: domain %ld, error %d",
__FUNCTION__, streamError.domain, streamError.error);
ctx->streamError = streamError;
ctx->status = CheckAuthCallbackStreamError;
break;
default:
syslog(LOG_DEBUG, "%s: Received unexpected stream event %d\n", __FUNCTION__, type);
break;
}
}
static int updateNetworkProxies(struct callback_ctx *ctx)
{
CFNumberRef cf_enabled;
CFNumberRef cf_port;
int enabled;
int err;
if (ctx->proxyStore == NULL) {
ctx->proxyStore = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("WebDAVFSPlugin"), NULL, NULL);
if (ctx->proxyStore == NULL)
return ENOMEM;
}
if (ctx->proxyRealm != NULL) {
CFRelease(ctx->proxyRealm);
ctx->proxyRealm = NULL;
}
ctx->httpProxyEnabled = FALSE;
ctx->httpsProxyEnabled = FALSE;
if (ctx->httpProxyServer != NULL)
{
CFRelease(ctx->httpProxyServer);
ctx->httpProxyServer = NULL;
}
if (ctx->httpsProxyServer != NULL)
{
CFRelease(ctx->httpsProxyServer);
ctx->httpsProxyServer = NULL;
}
if (ctx->proxyDict != NULL)
{
CFRelease(ctx->proxyDict);
ctx->proxyDict = NULL;
}
ctx->httpProxyEnabled = FALSE;
ctx->httpsProxyEnabled = FALSE;
ctx->proxyDict = SCDynamicStoreCopyProxies(gProxyStore);
if (ctx->proxyDict != NULL) {
cf_enabled = CFDictionaryGetValue(ctx->proxyDict, kSCPropNetProxiesHTTPEnable);
if ( (cf_enabled != NULL) && CFNumberGetValue(cf_enabled, kCFNumberIntType, &enabled) && enabled )
{
ctx->httpProxyServer = CFDictionaryGetValue(ctx->proxyDict, kSCPropNetProxiesHTTPProxy);
if ( ctx->httpProxyServer != NULL )
{
CFRetain(ctx->httpProxyServer);
cf_port = CFDictionaryGetValue(ctx->proxyDict, kSCPropNetProxiesHTTPPort);
if ( (cf_port != NULL) && CFNumberGetValue(cf_port, kCFNumberIntType, &ctx->httpProxyPort) )
{
if ( ctx->httpProxyPort == 0 )
{
ctx->httpProxyPort = kHttpDefaultPort;
}
ctx->httpProxyEnabled = TRUE;
}
}
}
cf_enabled = CFDictionaryGetValue(ctx->proxyDict, kSCPropNetProxiesHTTPSEnable);
if ( (cf_enabled != NULL) && CFNumberGetValue(cf_enabled, kCFNumberIntType, &enabled) && enabled )
{
ctx->httpsProxyServer = CFDictionaryGetValue(ctx->proxyDict, kSCPropNetProxiesHTTPSProxy);
if ( ctx->httpsProxyServer != NULL )
{
CFRetain(ctx->httpsProxyServer);
cf_port = CFDictionaryGetValue(ctx->proxyDict, kSCPropNetProxiesHTTPSPort);
if ( (cf_port != NULL) && CFNumberGetValue(cf_port, kCFNumberIntType, &ctx->httpsProxyPort) )
{
if ( ctx->httpsProxyPort == 0 )
{
ctx->httpsProxyPort = kHttpsDefaultPort;
}
ctx->httpsProxyEnabled = TRUE;
}
}
}
}
}
static void initContext(struct callback_ctx *ctx)
{
ctx->theData = NULL;
ctx->response = NULL;
ctx->sslPropDict = NULL;
ctx->serverAuth = NULL;
ctx->againCount = 0;
ctx->triedServerCredentials = FALSE;
ctx->triedProxyServerCredentials = FALSE;
ctx->proxyRealm = NULL;
ctx->httpProxyEnabled = FALSE;
ctx->httpProxyServer = NULL;
ctx->httpsProxyEnabled = FALSE;
ctx->httpsProxyServer = NULL;
ctx->proxyDict = NULL;
ctx->proxyStore = NULL;
ctx->proxyAuth = NULL;
}
static void releaseContextItems(struct callback_ctx *ctx)
{
CFReleaseNull(ctx->theData);
CFReleaseNull(ctx->response);
CFReleaseNull(ctx->sslPropDict);
CFReleaseNull(ctx->serverAuth);
CFReleaseNull(ctx->proxyRealm);
CFReleaseNull(ctx->httpProxyServer);
CFReleaseNull(ctx->httpsProxyServer);
CFReleaseNull(ctx->proxyDict);
CFReleaseNull (ctx->proxyStore);
CFReleaseNull(ctx->proxyAuth);
}