1/* 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <sys/types.h> 25#include <sys/errno.h> 26#include <sys/wait.h> 27#include <sys/time.h> 28#include <sys/resource.h> 29#include <stdio.h> 30#include <stdlib.h> 31#include <unistd.h> 32#include <signal.h> 33#include <strings.h> 34 35#define PRIVATE_WEBDAVFS_AGENT_COMMAND "/System/Library/Extensions/webdav_fs.kext/Contents/Resources/webdavfs_agent" 36#define WEBDAVFS_AGENT_PATH "PATH=/System/Library/Extensions/webdav_fs.kext/Contents/Resources" 37#define CFENVFORMATSTRING "__CF_USER_TEXT_ENCODING=0x%X:0:0" 38 39/*****************************************************************************/ 40 41static void usage(void) 42{ 43 (void)fprintf(stderr, 44 "usage: mount_webdav [-i] [-s] [-S] [-o options] [-v <volume name>]\n"); 45 (void)fprintf(stderr, 46 "\t<WebDAV_URL> node\n"); 47} 48 49/*****************************************************************************/ 50 51/* called when child normally terminates the parent */ 52static void parentexit(int x) 53{ 54#pragma unused(x) 55 exit(EXIT_SUCCESS); 56} 57 58/*****************************************************************************/ 59 60int main(int argc, char *argv[]) 61{ 62 int pid, terminated_pid, cnt; 63 union wait status; 64 char **argv_child; 65 int error; 66 67 if (argc < 2) { 68 usage(); 69 error = EINVAL; 70 goto error_exit; 71 } 72 73 error = 0; 74 75 /* 76 * Create an argument vector to pass to execve. 77 * The only difference is argv[0] is set to "webdavfs_agent", 78 * which allows the 'ps' command to display the correct command name 79 * in the listing. 80 */ 81 for (cnt = 0; argv[cnt]; cnt++) 82 ; 83 84 // allocate new arg vector, adding an extra element for the list terminator 85 argv_child = alloca((cnt + 1) * sizeof(char *)); 86 if (argv_child == NULL) { 87 error = ENOMEM; 88 goto error_exit; 89 } 90 91 /* this is the command name of the new process */ 92 argv_child[0] = "webdavfs_agent"; 93 argv_child[cnt] = (char *)0; 94 /* copy over the remaining argv strings */ 95 bcopy(argv + 1, argv_child + 1, (cnt - 1) * sizeof(char *)); 96 97 /* make sure SIGTERM is not masked (<rdar://problem/6019476>) */ 98 sigset_t mask; 99 sigemptyset(&mask); 100 sigaddset(&mask, SIGTERM); 101 sigprocmask(SIG_UNBLOCK, &mask, NULL); 102 103 /* if terminated by our child, we will exit with EXIT_SUCCESS */ 104 signal(SIGTERM, parentexit); 105 106 pid = fork(); 107 108 if (pid < 0) { 109 error = errno; 110 goto error_exit; 111 } 112 113 if (pid == 0) 114 { 115 char CFUserTextEncodingEnvSetting[sizeof(CFENVFORMATSTRING) + 20]; 116 /* 117 * Add WEBDAVFS_AGENT_PATH to the environment so that libsecurity knows where 118 * to look for webdavfs_agent when adding it to the keychain. 119 */ 120 char *env[] = {CFUserTextEncodingEnvSetting, WEBDAVFS_AGENT_PATH, "", (char *) 0 }; 121 122 /* 123 * Create a new environment with a definition of __CF_USER_TEXT_ENCODING to work 124 * around CF's interest in the user's home directory (which could be networked, 125 * causing recursive references through automount). Make sure we include the uid 126 * since CF will check for this when deciding if to look in the home directory. 127 */ 128 snprintf(CFUserTextEncodingEnvSetting, sizeof(CFUserTextEncodingEnvSetting), CFENVFORMATSTRING, getuid()); 129 130 /* child executes the webdavfs agent */ 131 execve(PRIVATE_WEBDAVFS_AGENT_COMMAND, argv_child, env); 132 133 /* We can only get here if the exec failed */ 134 error = errno; 135 goto error_exit; 136 } 137 138 /* Wait for child's signal or for child's completion */ 139 while ( (terminated_pid = wait4(pid, (int *)&status, 0, NULL)) < 0 ) 140 { 141 /* retry if EINTR, else break out with error */ 142 if ( errno != EINTR ) 143 { 144 break; 145 } 146 } 147 148 /* we'll get here only if the child completed before killing us */ 149 if ( (terminated_pid == pid) && WIFEXITED(status) ) 150 { 151 error = WEXITSTATUS(status); 152 } 153 else 154 { 155 error = ECHILD; 156 } 157 158error_exit: 159 160 /* Return the set of error codes things expect mounts to return */ 161 162 switch (error) 163 { 164 /* The server directory could not be mounted by mount_webdav because the node path is invalid. */ 165 case ENOENT: 166 break; 167 168 /* Could not connect to the server because the name or password is not correct */ 169 case EAUTH: 170 break; 171 172 /* Could not connect to the server because the name or password is not correct and the user canceled */ 173 case ECANCELED: 174 break; 175 176 /* You are already connected to this server volume */ 177 case EBUSY: 178 break; 179 180 /* You cannot connect to this server because it cannot be found on the network. Try again later or try a different URL. */ 181 case ENODEV: 182 break; 183 184 /* ap everything else to a generic unexpected error */ 185 default: 186 error = EINVAL; 187 break; 188 } 189 190 exit(error); 191} 192