#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <sys/dirent.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
#include <syslog.h>
#include <CoreServices/CoreServices.h>
#include <NetFS/NetFSPlugin.h>
#include <NetFS/NetFSUtil.h>
#include <NetFS/NetFSPrivate.h>
#include "webdavlib.h"
#define WebDAVMediaType ((VolumeType)('http'))
#define WEBDAVURLSCHEME "http"
#define UNIQUEDIGITS 5
#define MOUNT_COMMAND "/sbin/mount"
#define WEBDAV_MOUNT_TYPE "webdav"
#define HTTP_PREFIX "http://"
#define HTTPS_PREFIX "https://"
#define XXY(...) syslog(LOG_ERR, __VA_ARGS__)
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
#pragma pack(2)
#endif
static CFURLRef copyStripUserPassFromCFURL(CFURLRef in_url);
struct webdav_ctx {
pthread_mutex_t mutex;
CFStringRef ct_user;
CFStringRef ct_pass;
CFStringRef ct_proxy_user;
CFStringRef ct_proxy_pass;
CFURLRef ct_url;
};
struct runloopInfo {
CFHTTPMessageRef message;
CFStringRef user;
CFStringRef pass;
int status;
};
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
#pragma pack()
#endif
#define IDISK_SERVER_NAME "idisk.mac.com"
#define CFReleaseNull(obj) do { if(obj != NULL) { CFRelease(obj); obj = NULL; } } while (0)
void percent_decode_in_place(char *uri)
{
char *s;
s = uri;
while (*uri)
{
if (*uri == '%' && uri[1] && isxdigit(uri[1]) && isxdigit(uri[2]))
{
int c;
char buf[] = "xx";
buf[0] = uri[1];
buf[1] = uri[2];
sscanf(buf, "%x", &c);
uri += 3;
*s++ = c;
}
else
{
*s++ = *uri++;
}
}
*s = '\0';
}
static int
GetMountURI(const char *arguri, char dst_buf[], size_t mntfrom_size)
{
int hasScheme;
int hasTrailingSlash;
int isHTTPS;
int result;
size_t argURILength;
result = 0;
argURILength = strlen(arguri);
if (argURILength + 1 >= mntfrom_size)
return EINVAL;
isHTTPS = (strncasecmp(arguri, HTTPS_PREFIX, strlen(HTTPS_PREFIX)) == 0);
hasScheme = ((strncasecmp(arguri, HTTP_PREFIX, strlen(HTTP_PREFIX)) == 0) || isHTTPS);
hasTrailingSlash = arguri[argURILength - 1] == '/';
if ( !hasScheme )
{
(void)strlcpy(dst_buf, HTTP_PREFIX, mntfrom_size);
}
else
{
dst_buf[0] = '\0';
}
if ( strlcat(dst_buf, arguri, mntfrom_size) >= mntfrom_size )
{
result = EINVAL;
}
else if ( !hasTrailingSlash )
{
if ( strlcat(dst_buf, "/", mntfrom_size) >= mntfrom_size )
result = EINVAL;
}
return ( result );
}
static int
FindActiveMountPointFromURL(const char* url, char* mountpoint, size_t mountpoint_len)
{
struct statfs *buffer;
int i, count, error;
unsigned int mntfromnameLength;
uid_t processUID;
char mntfromname[MNAMELEN];
error = EBUSY;
processUID = getuid();
if ( GetMountURI(url, mntfromname, sizeof(mntfromname)) != 0 ) {
syslog(LOG_ERR, "%s: url: %s is too long!", __FUNCTION__, url);
return EINVAL;
}
mntfromnameLength = strlen(mntfromname);
count = getmntinfo(&buffer, MNT_NOWAIT);
for (i = 0; i < count; i++)
{
if ( (buffer[i].f_owner == processUID) &&
(strcmp("webdav", buffer[i].f_fstypename) == 0) &&
(strlen(buffer[i].f_mntfromname) == mntfromnameLength) &&
(strncasecmp(buffer[i].f_mntfromname, mntfromname, mntfromnameLength) == 0) )
{
strlcpy(mountpoint, buffer[i].f_mntonname, mountpoint_len);
error = 0;
break;
}
}
return (error);
}
#define CFENVFORMATSTRING "__CF_USER_TEXT_ENCODING=0x%X:0:0"
static int
AttemptMount(const char *urlPtr, const char *mountPointPtr, u_int32_t options, int fd, const char *volumename, int hostisidisk)
{
pid_t pid, terminated_pid;
int result;
union wait status;
char options_str[MAXNAMLEN + 21];
pid = fork();
if (pid == 0) {
uid_t effective_uid;
uid_t real_uid;
char CFUserTextEncodingEnvSetting[sizeof(CFENVFORMATSTRING) + 20];
char *env[] = {CFUserTextEncodingEnvSetting, "", (char *) 0 };
real_uid = getuid();
effective_uid = geteuid();
if ( (real_uid == 0) && (effective_uid != 0) ) {
setuid(real_uid);
setuid(effective_uid);
}
snprintf(CFUserTextEncodingEnvSetting, sizeof(CFUserTextEncodingEnvSetting), CFENVFORMATSTRING, getuid());
*options_str = '\0';
if (fd != -1) {
sprintf(options_str, "-a%d", fd);
}
#if 0
if (options & kSuppressAllUI) {
if (*options_str != '\0') {
strcat(options_str, ",");
}
strcat(options_str, "-S");
}
#endif
if (volumename != NULL && *volumename != '\0') {
if (*options_str != '\0') {
strcat(options_str, ",");
}
strcat(options_str, "-v");
strcat(options_str, volumename);
}
if (hostisidisk) {
if (*options_str != '\0') {
strcat(options_str, ",");
}
strcat(options_str, "-s");
}
if (*options_str == '\0') {
result = execle(MOUNT_COMMAND, MOUNT_COMMAND ,
"-t", WEBDAV_MOUNT_TYPE,
"-o", (options & MNT_AUTOMOUNTED) ? "automounted" : "noautomounted",
"-o", (options & MNT_DONTBROWSE) ? "nobrowse" : "browse",
"-o", (options & MNT_RDONLY) ? "rdonly" : "nordonly",
urlPtr, mountPointPtr, NULL, env);
} else {
result = execle(MOUNT_COMMAND, MOUNT_COMMAND ,
"-t", WEBDAV_MOUNT_TYPE,
"-o", (options & MNT_AUTOMOUNTED) ? "automounted" : "noautomounted",
"-o", (options & MNT_DONTBROWSE) ? "nobrowse" : "browse",
"-o", (options & MNT_RDONLY) ? "rdonly" : "nordonly",
"-o", options_str,
urlPtr, mountPointPtr, NULL, env);
}
exit(result ? result : ECHILD);
}
if (pid == -1) {
result = -1;
goto Return;
}
while ( (terminated_pid = wait4(pid, (int *)&status, 0, NULL)) < 0 ) {
if ( errno != EINTR ) {
break;
}
}
if ((terminated_pid == pid) && (WIFEXITED(status))) {
result = WEXITSTATUS(status);
} else {
result = -1;
}
Return:
if (fd != -1)
(void)close(fd);
return result;
}
static int curl_is_idisk(const char* url)
{
char* colon = NULL;
uint idisk_len = sizeof(IDISK_SERVER_NAME) - 1;
if (url == NULL)
return FALSE;
colon = strchr(url, ':');
if ( (colon == NULL) || (strlen(colon) < idisk_len) )
return FALSE;
colon += 3;
return 0 == strncasecmp(colon, IDISK_SERVER_NAME, idisk_len);
}
#define WEBDAV_TEMPLATE "/tmp/webdav.XXXXXX"
static int
WebDAVMountURL(const char *url,
const char *username,
const char *password,
const char *proxy_username,
const char *proxy_password,
char *mountpoint,
size_t mountpoint_len,
u_int32_t options)
{
int fd = -1;
int error;
int hostisidisk = FALSE;
#if DEBUG_TRACE
syslog(LOG_DEBUG,
"WebDAV_MountURLWithAuthentication: Mounting '%s'...\n",
url);
#endif
hostisidisk = curl_is_idisk(url);
if ((username != NULL) || (proxy_username != NULL)) {
char template[sizeof(WEBDAV_TEMPLATE)+1];
strcpy(template, WEBDAV_TEMPLATE);
if ((fd = mkstemp(template)) != -1) {
size_t len;
uint32_t be_len;
unlink(template);
if (username != NULL) {
len = strlen(username);
be_len = htonl(len);
if (write(fd, &be_len, sizeof be_len) > 0) {
if (write(fd, username, len) > 0) {
be_len = htonl(strlen(password));
if (write(fd, &be_len, sizeof be_len) > 0)
write(fd, password, strlen(password));
}
}
}
else {
be_len = 0;
write(fd, &be_len, sizeof be_len);
write(fd, &be_len, sizeof be_len);
}
if (proxy_username != NULL) {
len = strlen(proxy_username);
be_len = htonl(len);
if (write(fd, &be_len, sizeof be_len) > 0) {
if (write(fd, proxy_username, len) > 0) {
be_len = htonl(strlen(proxy_password));
if (write(fd, &be_len, sizeof be_len) > 0)
write(fd, proxy_password, strlen(proxy_password));
}
}
}
else {
be_len = 0;
write(fd, &be_len, sizeof be_len);
write(fd, &be_len, sizeof be_len);
}
(void)fsync(fd);
}
}
#if DEBUG_TRACE
syslog(LOG_DEBUG,
"WebDAV_MountURLWithAuthentication: AttemptMount('%s', '%s')...\n",
url, mountpoint);
#endif
if (error = AttemptMount(url, mountpoint, options, fd, NULL, hostisidisk)) {
#if DEBUG_TRACE
syslog(LOG_DEBUG,
"WebDAV_MountURLWithAuthentication: AttemptMount returned %d\n",
error, mountpoint);
#endif
if (error == EBUSY) {
if (!FindActiveMountPointFromURL(url, mountpoint, mountpoint_len)) {
error = EEXIST;
}
}
goto error;
};
return(0);
error:
return(error);
}
static SInt32
GetHostAndPort(CFURLRef in_URL, CFStringRef *out_Host,
CFStringRef *out_Port)
{
SInt32 error = 0;
CFStringRef host = NULL;
CFStringRef port = NULL;
CFMutableStringRef hostM = NULL;
SInt32 altPort;
CFRange foundColon;
if (out_Host != NULL)
*out_Host = NULL;
if (out_Port != NULL)
*out_Port = NULL;
host = CFURLCopyHostName(in_URL);
if (host == NULL) {
error = EINVAL;
goto exit;
}
hostM = CFStringCreateMutableCopy(NULL, 0, host);
CFRelease(host);
if (hostM == NULL) {
error = ENOMEM;
goto exit;
}
foundColon = CFStringFind(hostM, CFSTR(":"), 0);
if (foundColon.location != kCFNotFound) {
CFStringInsert(hostM, 0, CFSTR("["));
CFStringAppend(hostM, CFSTR("]"));
}
altPort = CFURLGetPortNumber (in_URL);
if (altPort != -1) {
port = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"),
altPort);
if (port == NULL) {
error = ENOMEM;
goto exit;
}
}
if (out_Port == NULL && port != NULL) {
CFStringAppend(hostM, CFSTR(":"));
CFStringAppend(hostM, port);
}
if (out_Host != NULL)
*out_Host = hostM;
if (out_Port != NULL && port != NULL)
*out_Port = port;
exit:
if (error) {
if (hostM != NULL)
CFRelease(hostM);
if (port != NULL)
CFRelease(port);
}
return error;
}
netfsError WebDAV_CreateSessionRef(void **out_SessionRef)
{
struct webdav_ctx *session_ref = NULL;
if (out_SessionRef == NULL)
return EINVAL;
session_ref = (struct webdav_ctx *)malloc(sizeof(struct webdav_ctx));
if (session_ref == NULL)
return ENOMEM;
memset(session_ref, '\0', sizeof(struct webdav_ctx));
if (pthread_mutex_init(&session_ref->mutex, NULL) == -1) {
syslog(LOG_ERR, "%s: pthread_mutex_init failed!", __FUNCTION__);
free(session_ref);
return EINVAL;
}
*out_SessionRef = session_ref;
return 0;
}
netfsError WebDAV_GetServerInfo(CFURLRef in_URL,
void *in_SessionRef,
CFDictionaryRef in_GetInfoOptions,
CFDictionaryRef *out_ServerParms)
{
#pragma unused(in_SessionRef, in_GetInfoOptions)
CFMutableDictionaryRef mutableDict = NULL;
CFStringRef serverName = NULL;
CFMutableDictionaryRef proxyInfo;
CFStringRef cf_str;
CFURLRef a_url;
enum WEBDAVLIBAuthStatus authStat;
int error;
if ( in_URL == NULL || out_ServerParms == NULL )
return EINVAL;
mutableDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (mutableDict == NULL) {
return ENOMEM;
}
serverName = CFURLCopyHostName(in_URL);
CFDictionarySetValue (mutableDict, kNetFSSupportsChangePasswordKey, kCFBooleanFalse);
if(serverName != NULL) {
CFDictionarySetValue(mutableDict, kNetFSServerDisplayNameKey, serverName);
CFRelease(serverName);
}
CFDictionarySetValue (mutableDict, kNetFSSupportsKerberosKey, kCFBooleanFalse);
CFDictionarySetValue (mutableDict, kNetFSSupportsGuestKey, kCFBooleanTrue);
CFDictionarySetValue (mutableDict, kNetFSGuestOnlyKey, kCFBooleanFalse);
proxyInfo = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (proxyInfo == NULL) {
CFRelease(mutableDict);
return ENOMEM;
}
a_url = copyStripUserPassFromCFURL(in_URL);
authStat = queryForProxy(a_url, proxyInfo, &error);
CFReleaseNull(a_url);
if (authStat == WEBDAVLIB_ProxyAuth) {
syslog(LOG_DEBUG, "%s: Proxy server found", __FUNCTION__);
cf_str = (CFStringRef) CFDictionaryGetValue(proxyInfo, kWebDAVLibProxyServerNameKey);
if (cf_str != NULL) {
CFDictionarySetValue(mutableDict, kNetFSProxyServerNameKey, cf_str);
}
else {
syslog(LOG_ERR, "%s: Missing kNetFSProxyServerNameKey", __FUNCTION__);
}
cf_str = (CFStringRef) CFDictionaryGetValue(proxyInfo, kWebDAVLibProxyRealmKey);
if (cf_str != NULL) {
CFDictionarySetValue(mutableDict, kNetFSProxyServerRealmKey, cf_str);
}
else {
syslog(LOG_ERR, "%s: Missing kNetFSProxyServerRealmKey", __FUNCTION__);
}
}
CFReleaseNull(proxyInfo);
if ((authStat == WEBDAVLIB_UnexpectedStatus) || (authStat == WEBDAVLIB_IOError)) {
CFRelease(mutableDict);
}
else {
*out_ServerParms = mutableDict;
error = 0;
}
return error;
}
netfsError WebDAV_ParseURL(CFURLRef in_URL, CFDictionaryRef *out_URLParms)
{
CFMutableDictionaryRef mutableDict = NULL;
CFStringRef scheme = NULL;
CFStringRef host = NULL;
CFStringRef port = NULL;
CFStringRef path = NULL;
CFStringRef user = NULL;
CFStringRef pass = NULL;
netfsError error = 0;
if (in_URL == NULL || out_URLParms == NULL)
return EINVAL;
*out_URLParms = NULL;
if (!CFURLCanBeDecomposed(in_URL)) {
error = EINVAL;
goto exit;
}
mutableDict = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (mutableDict == NULL) {
error = ENOMEM;
goto exit;
}
scheme = CFURLCopyScheme(in_URL);
if (scheme == NULL) {
error = ENOMEM;
goto exit;
}
CFDictionarySetValue(mutableDict, kNetFSSchemeKey, scheme);
CFRelease(scheme);
user = CFURLCopyUserName(in_URL);
if (user != NULL) {
CFDictionarySetValue(mutableDict, kNetFSUserNameKey, user);
CFRelease(user);
pass = CFURLCopyPassword(in_URL);
if (pass != NULL) {
CFDictionarySetValue(mutableDict, kNetFSPasswordKey, pass);
CFRelease(pass);
}
}
error = GetHostAndPort(in_URL, &host, &port);
if (error != 0)
goto exit;
CFDictionarySetValue(mutableDict, kNetFSHostKey, host);
CFRelease(host);
if (port != NULL) {
CFDictionarySetValue(mutableDict, kNetFSAlternatePortKey, port);
CFRelease(port);
}
path = CFURLCopyPath(in_URL);
if (path != NULL) {
CFDictionarySetValue(mutableDict, kNetFSPathKey, path);
CFRelease(path);
}
*out_URLParms = mutableDict;
exit:
if (error) {
if (mutableDict != NULL)
CFRelease (mutableDict);
}
return error;
}
netfsError WebDAV_CreateURL(CFDictionaryRef in_URLParms, CFURLRef *out_URL)
{
SInt32 error = 0;
CFMutableStringRef urlStringM = NULL;
CFURLRef myURL = NULL;
CFStringRef scheme;
CFStringRef host;
CFStringRef port;
CFStringRef path;
CFStringRef user;
CFStringRef pass;
if (in_URLParms == NULL || out_URL == NULL)
return EINVAL;
*out_URL = NULL;
scheme = (CFStringRef) CFDictionaryGetValue(in_URLParms,
kNetFSSchemeKey);
if (scheme == NULL) {
error = EINVAL;
goto exit;
}
urlStringM = CFStringCreateMutableCopy(NULL, 0, scheme);
if (urlStringM == NULL) {
error = ENOMEM;
goto exit;
}
CFStringAppend(urlStringM, CFSTR("://"));
user = (CFStringRef) CFDictionaryGetValue(in_URLParms, kNetFSUserNameKey);
if (user != NULL) {
user = CFURLCreateStringByAddingPercentEscapes(NULL, user,
NULL, CFSTR("@:/?"),
kCFStringEncodingUTF8);
CFStringAppend(urlStringM, user);
CFRelease(user);
pass = (CFStringRef) CFDictionaryGetValue(in_URLParms, kNetFSPasswordKey);
if (pass != NULL) {
pass = CFURLCreateStringByAddingPercentEscapes(NULL, pass,
NULL, CFSTR("@:/?"),
kCFStringEncodingUTF8);
CFStringAppend(urlStringM, CFSTR(":"));
CFStringAppend(urlStringM, pass);
CFRelease(pass);
}
CFStringAppend(urlStringM, CFSTR("@"));
}
host = (CFStringRef) CFDictionaryGetValue(in_URLParms, kNetFSHostKey);
if (host == NULL) {
error = EINVAL;
goto exit;
}
host = CFURLCreateStringByAddingPercentEscapes(NULL, host,
CFSTR("[]"), CFSTR("/@:,?=;&+$"), kCFStringEncodingUTF8);
CFStringAppend(urlStringM, host);
CFRelease(host);
port = (CFStringRef) CFDictionaryGetValue(in_URLParms,
kNetFSAlternatePortKey);
if (port != NULL) {
port = CFURLCreateStringByAddingPercentEscapes(NULL, port,
NULL, NULL, kCFStringEncodingUTF8);
CFStringAppend(urlStringM, CFSTR(":"));
CFStringAppend(urlStringM, port);
CFRelease(port);
}
path = (CFStringRef) CFDictionaryGetValue(in_URLParms, kNetFSPathKey);
if (path != NULL) {
path = CFURLCreateStringByAddingPercentEscapes(NULL, path,
NULL, CFSTR("?"), kCFStringEncodingUTF8);
CFStringAppend(urlStringM, path);
CFRelease(path);
}
else {
syslog(LOG_ERR, "%s: path is NULL!", __FUNCTION__);
error = EINVAL;
goto exit;
}
myURL = CFURLCreateWithString(NULL, urlStringM, NULL);
CFRelease(urlStringM);
urlStringM = NULL;
if (myURL == NULL) {
error = ENOMEM;
goto exit;
}
*out_URL = myURL;
exit:
if (urlStringM != NULL)
CFRelease(urlStringM);
return error;
}
static CFURLRef copyStripUserPassFromCFURL(CFURLRef in_url)
{
CFURLRef newurl = NULL;
CFMutableDictionaryRef mutableDict = NULL;
if (in_url == NULL)
return NULL;
if (WebDAV_ParseURL(in_url, (CFDictionaryRef *)&mutableDict) != 0) {
syslog(LOG_ERR, "%s: WebDAV_ParseURL failed", __FUNCTION__);
return NULL;
}
CFDictionaryRemoveValue(mutableDict, kNetFSUserNameKey);
CFDictionaryRemoveValue(mutableDict, kNetFSPasswordKey);
if(WebDAV_CreateURL(mutableDict, &newurl) != 0) {
syslog(LOG_ERR, "%s: WebDAV_CreateURL failed", __FUNCTION__);
return NULL;
}
CFRelease(mutableDict);
return newurl;
}
netfsError WebDAV_OpenSession(CFURLRef in_URL,
void *in_SessionRef,
CFDictionaryRef in_OpenOptions,
CFDictionaryRef *out_SessionInfo)
{
int error = 0;
struct webdav_ctx* ctx = in_SessionRef;
int UseGuest = FALSE;
CFMutableDictionaryRef mutableDict = NULL;
boolean_t checkAuth, checkProxyServerOnly;
enum WEBDAVLIBAuthStatus authStat;
CFDictionaryRef proxyCredsDict;
CFMutableDictionaryRef serverCredsDict;
CFURLRef a_url;
if (in_SessionRef == NULL) {
syslog(LOG_ERR, "%s: in_SessionRef is NULL!", __FUNCTION__);
return EINVAL;
}
if (out_SessionInfo != NULL) {
*out_SessionInfo = NULL;
}
if (in_OpenOptions != NULL) {
CFBooleanRef booleanRef = NULL;
booleanRef = (CFBooleanRef)CFDictionaryGetValue(in_OpenOptions, kNetFSUseGuestKey);
if (booleanRef != NULL)
UseGuest = CFBooleanGetValue(booleanRef);
}
proxyCredsDict = (CFDictionaryRef) CFDictionaryGetValue(in_OpenOptions, kNetFSProxyServerCredentialsKey);
if (proxyCredsDict == NULL) {
if (in_URL != NULL) {
if (ctx->ct_url != NULL)
CFRelease(ctx->ct_url);
ctx->ct_url = CFURLCopyAbsoluteURL(in_URL);
if (ctx->ct_url != NULL) {
ctx->ct_user = CFURLCopyUserName(ctx->ct_url);
ctx->ct_pass = CFURLCopyPassword(ctx->ct_url);
}
}
if (out_SessionInfo != NULL) {
mutableDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (mutableDict == NULL) {
syslog(LOG_ERR, "%s: mutableDict is NULL!", __FUNCTION__);
return ENOMEM;
}
if (ctx->ct_user != NULL) {
CFDictionarySetValue(mutableDict, kNetFSMountedByUserKey, ctx->ct_user);
}
else if (UseGuest) {
CFDictionarySetValue(mutableDict, kNetFSMountedByGuestKey, kCFBooleanTrue);
}
else
syslog(LOG_ERR, "%s: not set to guest and user is NULL!", __FUNCTION__);
}
}
serverCredsDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (serverCredsDict == NULL) {
syslog(LOG_ERR, "%s: No mem for serverCredsDictionary", __FUNCTION__);
error = ENOMEM;
goto out;
}
checkAuth = FALSE;
checkProxyServerOnly = FALSE;
if (proxyCredsDict != NULL ) {
syslog(LOG_DEBUG, "%s: authenticating with proxy server", __FUNCTION__);
CFReleaseNull(ctx->ct_proxy_user);
CFReleaseNull(ctx->ct_proxy_pass);
ctx->ct_proxy_user = CFDictionaryGetValue(proxyCredsDict, kNetFSUserNameKey);
ctx->ct_proxy_pass = CFDictionaryGetValue(proxyCredsDict, kNetFSPasswordKey);
if (ctx->ct_proxy_user != NULL)
CFRetain(ctx->ct_proxy_user);
if (ctx->ct_proxy_pass != NULL)
CFRetain(ctx->ct_proxy_pass);
if (ctx->ct_proxy_user == NULL || ctx->ct_proxy_pass == NULL) {
syslog(LOG_ERR, "%s: missing proxy credentials", __FUNCTION__);
}
else {
CFDictionarySetValue(serverCredsDict, kWebDAVLibProxyUserNameKey, ctx->ct_proxy_user);
CFDictionarySetValue(serverCredsDict, kWebDAVLibProxyPasswordKey, ctx->ct_proxy_pass);
checkProxyServerOnly = TRUE;
checkAuth = TRUE;
}
}
else if (UseGuest == FALSE) {
syslog(LOG_DEBUG, "%s: authenticating with destination server", __FUNCTION__);
if (ctx->ct_user == NULL || ctx->ct_pass == NULL) {
syslog(LOG_ERR, "%s: missing server credentials", __FUNCTION__);
}
else {
CFDictionarySetValue(serverCredsDict, kWebDAVLibUserNameKey, ctx->ct_user);
CFDictionarySetValue(serverCredsDict, kWebDAVLibPasswordKey, ctx->ct_pass);
if (ctx->ct_proxy_user != NULL && ctx->ct_proxy_pass != NULL) {
CFDictionarySetValue(serverCredsDict, kWebDAVLibProxyUserNameKey, ctx->ct_proxy_user);
CFDictionarySetValue(serverCredsDict, kWebDAVLibProxyPasswordKey, ctx->ct_proxy_pass);
}
checkAuth = TRUE;
}
}
else
syslog(LOG_DEBUG, "%s: guest authentication", __FUNCTION__);
if (checkAuth == TRUE) {
a_url = copyStripUserPassFromCFURL(in_URL);
authStat = connectToServer(a_url, serverCredsDict, &error);
CFReleaseNull(a_url);
switch (authStat) {
case WEBDAVLIB_Success:
error = 0;
break;
case WEBDAVLIB_ProxyAuth:
if (checkProxyServerOnly != TRUE) {
syslog(LOG_ERR, "%s: Unexpected 407 status when checking server", __FUNCTION__);
}
break;
case WEBDAVLIB_ServerAuth:
if (checkProxyServerOnly == TRUE) {
syslog(LOG_DEBUG, "%s: Success, we got through the proxy server", __FUNCTION__);
error = 0;
}
break;
default:
syslog(LOG_DEBUG, "%s: connectToServer returned %d, error %d", __FUNCTION__, authStat, error);
break;
}
}
CFReleaseNull(serverCredsDict);
out:
if (mutableDict != NULL) {
if (error == 0) {
*out_SessionInfo = mutableDict;
}
else
CFRelease(mutableDict);
}
return error;
}
netfsError WebDAV_EnumerateShares(void *in_SessionRef,
CFDictionaryRef in_EnumerateOptions,
CFDictionaryRef *out_Sharepoints)
{
#pragma unused(in_SessionRef, in_EnumerateOptions, out_Sharepoints)
return ENOTSUP;
}
netfsError WebDAV_Mount(void *in_SessionRef,
CFURLRef in_URL,
CFStringRef in_Mountpoint,
CFDictionaryRef in_MountOptions,
CFDictionaryRef *out_MountInfo)
{
struct webdav_ctx* ctx = in_SessionRef;
char mountpoint[MAXPATHLEN];
char* url = NULL;
char* username = NULL;
char* password = NULL;
char* proxy_username = NULL;
char* proxy_password = NULL;
CFURLRef tmpurl = NULL;
CFNumberRef numRef = NULL;
CFStringRef cfpassword = NULL;
CFDataRef dataref = NULL;
CFMutableDictionaryRef mutableDict = NULL;
u_int32_t mntflags;
int error = 0;
*out_MountInfo = NULL;
if (in_SessionRef == NULL || in_URL == NULL || in_Mountpoint == NULL) {
syslog(LOG_ERR, "%s: invalid arguments!", __FUNCTION__);
return EINVAL;
}
tmpurl = copyStripUserPassFromCFURL(in_URL);
if (tmpurl == NULL) {
syslog(LOG_ERR, "%s: copyStripUserPassFromCFURL failed!", __FUNCTION__);
return EIO;
}
url = NetFSCFStringtoCString(CFURLGetString(tmpurl));
CFRelease(tmpurl);
if (url == NULL) {
syslog(LOG_ERR, "%s: NetFSCFStringtoCString failed!", __FUNCTION__);
return ENOMEM;
}
if (CFStringGetCString(in_Mountpoint, mountpoint, sizeof(mountpoint), kCFStringEncodingUTF8) == false) {
syslog(LOG_ERR, "%s: CFStringGetCString failed!", __FUNCTION__);
error = EINVAL;
goto out;
}
if (ctx->ct_user != NULL) {
username = NetFSCFStringtoCString(ctx->ct_user);
if (username == NULL) {
error = ENOMEM;
goto out;
}
if (in_MountOptions) {
dataref = (CFDataRef)CFDictionaryGetValue(in_MountOptions, kNetFSPasswordKey);
if (dataref != NULL) {
cfpassword = CFStringCreateFromExternalRepresentation(NULL, dataref, kCFStringEncodingUTF8);
}
}
if (cfpassword == NULL && ctx->ct_pass != NULL) {
cfpassword = CFStringCreateCopy(NULL, ctx->ct_pass);
}
if (cfpassword != NULL) {
password = NetFSCFStringtoCString(cfpassword);
if (password == NULL) {
error = ENOMEM;
goto out;
}
}
}
if (ctx->ct_proxy_user != NULL) {
proxy_username = NetFSCFStringtoCString(ctx->ct_proxy_user);
if (ctx->ct_proxy_pass != NULL)
proxy_password = NetFSCFStringtoCString(ctx->ct_proxy_pass);
if (proxy_username == NULL || proxy_password == NULL) {
syslog(LOG_ERR, "%s: No mem for proxy credentials", __FUNCTION__);
if (proxy_username != NULL)
free(proxy_username);
if (proxy_password != NULL)
free(proxy_password);
proxy_username = NULL;
proxy_password = NULL;
}
}
mutableDict = CFDictionaryCreateMutable(NULL, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (mutableDict == NULL) {
error = EIO;
goto out;
}
mntflags = 0;
if (in_MountOptions) {
numRef = (CFNumberRef)CFDictionaryGetValue(in_MountOptions, kNetFSMountFlagsKey);
if (numRef)
(void)CFNumberGetValue(numRef, kCFNumberSInt32Type, &mntflags);
}
error = WebDAVMountURL(url, username, password, proxy_username, proxy_password, mountpoint, sizeof(mountpoint), mntflags);
#if DEBUG_TRACE
if (error)
syslog(LOG_ERR, "%s: MountURLWithAuthentication exited with error: %d", __FUNCTION__, error);
#endif
if (error == 0 || error == EEXIST) {
if (error == EEXIST) {
CFStringRef mountPath = NULL;
mountPath = CFStringCreateWithCString(NULL, mountpoint, kCFStringEncodingUTF8);
if (mountPath == NULL) {
syslog(LOG_ERR, "%s: CFStringCreateWithCString failed!", __FUNCTION__);
error = ENOMEM;
goto out;
}
CFDictionarySetValue(mutableDict, kNetFSMountPathKey, mountPath);
CFRelease(mountPath);
}
else {
CFDictionarySetValue(mutableDict, kNetFSMountPathKey, in_Mountpoint);
}
if (ctx->ct_user != NULL) {
CFDictionarySetValue(mutableDict, kNetFSMountedByUserKey, ctx->ct_user);
}
*out_MountInfo = mutableDict;
}
out:
if (url)
free(url);
if (username)
free(username);
if (password)
free(password);
if (proxy_username)
free(proxy_username);
if (proxy_password)
free(proxy_password);
if (cfpassword) {
CFRelease(cfpassword);
cfpassword = NULL;
}
return error;
}
netfsError WebDAV_Cancel(void *in_SessionRef)
{
#pragma unused(in_SessionRef)
return 0;
}
netfsError WebDAV_CloseSession(void *in_SessionRef)
{
struct webdav_ctx* ctx = in_SessionRef;
if (in_SessionRef == NULL) {
syslog(LOG_ERR, "%s: in_SessionRef is NULL", __FUNCTION__);
return EINVAL;
}
WebDAV_Cancel(in_SessionRef);
pthread_mutex_destroy(&ctx->mutex);
CFReleaseNull(ctx->ct_user);
CFReleaseNull(ctx->ct_pass);
CFReleaseNull(ctx->ct_proxy_user);
CFReleaseNull(ctx->ct_proxy_pass);
CFReleaseNull(ctx->ct_url);
free(in_SessionRef);
return 0;
}
netfsError WebDAV_GetMountInfo(CFStringRef in_mountpoint, CFDictionaryRef *out_MountInfo)
{
CFStringRef urlString = NULL;
CFMutableDictionaryRef mutableDict = NULL;
char *mountpath = NULL;
struct statfs statbuf;
int error = 0;
*out_MountInfo = NULL;
mutableDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (mutableDict == NULL)
return ENOMEM;
mountpath = NetFSCFStringtoCString(in_mountpoint);
if (mountpath == NULL) {
CFRelease(mutableDict);
return ENOMEM;
}
if (statfs(mountpath, &statbuf) == -1) {
error = errno;
CFRelease(mutableDict);
free(mountpath);
return error;
}
free(mountpath);
urlString = CFStringCreateWithCString(NULL, statbuf.f_mntfromname, kCFStringEncodingUTF8);
if (urlString == NULL) {
CFRelease(mutableDict);
return ENOMEM;
}
CFDictionarySetValue(mutableDict, kNetFSMountedURLKey, urlString);
*out_MountInfo = mutableDict;
CFRelease(urlString);
return 0;
}
static NetFSMountInterface_V1 gWebDAVNetFSInterfaceFTbl = {
NULL,
NetFSQueryInterface,
NetFSInterface_AddRef,
NetFSInterface_Release,
WebDAV_CreateSessionRef,
WebDAV_GetServerInfo,
WebDAV_ParseURL,
WebDAV_CreateURL,
WebDAV_OpenSession,
WebDAV_EnumerateShares,
WebDAV_Mount,
WebDAV_Cancel,
WebDAV_CloseSession,
WebDAV_GetMountInfo,
};
#define kWebDAVURLMounterFactoryID CFUUIDGetConstantUUIDWithBytes(NULL, 0xf1, 0x82, 0x1b, 0xfb, 0xf6, 0x59, 0x11, 0xd5, 0xab, 0x4b, 0x00, 0x30, 0x65, 0xa0, 0xe6, 0xde)
void *
WebDAVURLMounterFactory(__unused CFAllocatorRef allocator, CFUUIDRef typeID)
{
if (CFEqual(typeID, kNetFSTypeID)) {
NetFSInterface *result = NetFS_CreateInterface(kWebDAVURLMounterFactoryID, &gWebDAVNetFSInterfaceFTbl);
return result;
} else {
return NULL;
}
}