1/* 2 * Copyright (c) 2007-2011 Apple 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 <unistd.h> 25#include <mntopts.h> 26#include <syslog.h> 27 28#include <sys/mount.h> 29 30#include <CoreFoundation/CoreFoundation.h> 31#include <NetFS/NetFS.h> 32#include <NetFS/NetFSPrivate.h> 33/* 34 * XXX - <NetAuth/NetAuth.h> include <NetAuth/NAKeys.h>, which redefines 35 * some of our #defines if _NETFS_H_ isn't defined. 36 * 37 * To prevent that from happening, we include it *after* including NetFS.h, 38 * which defines _NETFS_H_. 39 */ 40#include <NetAuth/NetAuth.h> 41 42#define ALT_SOFT 0x00000001 43 44static const struct mntopt mopts_std[] = { 45 MOPT_STDOPTS, 46 MOPT_UPDATE, 47 MOPT_RELOAD, 48 { "soft", 0, ALT_SOFT, 1 }, 49 { NULL, 0, 0, 0 } 50}; 51 52static void usage(void); 53 54static int do_mount_direct(CFURLRef server_URL, CFStringRef mountdir, 55 CFDictionaryRef open_options, CFDictionaryRef mount_options, 56 CFDictionaryRef *mount_infop); 57 58int 59main(int argc, char **argv) 60{ 61 int c; 62 int usenetauth = 0; 63 mntoptparse_t mp; 64 int flags, altflags; 65 CFURLRef URL; 66 CFStringRef mountdir_CFString; 67 CFMutableDictionaryRef open_options, mount_options; 68 CFDictionaryRef mount_info; 69 int res; 70 71 flags = altflags = 0; 72 getmnt_silent = 1; 73 while ((c = getopt(argc, argv, "no:rw")) != -1) { 74 switch (c) { 75 76 case 'n': 77 usenetauth = 1; 78 break; 79 80 case 'o': 81 /* 82 * OK, parse these options, and update the flags. 83 */ 84 mp = getmntopts(optarg, mopts_std, &flags, &altflags); 85 freemntopts(mp); 86 break; 87 88 case 'r': 89 flags |= MNT_RDONLY; 90 break; 91 92 case 'w': 93 flags &= ~MNT_RDONLY; 94 break; 95 96 case '?': 97 default: 98 usage(); 99 break; 100 } 101 } 102 argc -= optind; 103 argv += optind; 104 105 if (argc != 2) 106 usage(); 107 108 /* 109 * Nothing can stop the Duke of... 110 */ 111 URL = CFURLCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)argv[0], 112 strlen(argv[0]), kCFStringEncodingUTF8, NULL); 113 if (URL == NULL) 114 exit(ENOMEM); 115 116 mountdir_CFString = CFStringCreateWithCString(kCFAllocatorDefault, 117 argv[1], kCFStringEncodingUTF8); 118 if (mountdir_CFString == NULL) 119 exit(ENOMEM); 120 121 open_options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 122 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 123 if (open_options == NULL) 124 exit(ENOMEM); 125 /* 126 * It's OK to use an existing session. 127 */ 128 CFDictionaryAddValue(open_options, kNetFSForceNewSessionKey, 129 kCFBooleanFalse); 130 /* 131 * And it's OK to mount something from ourselves. 132 */ 133 CFDictionaryAddValue(open_options, kNetFSAllowLoopbackKey, 134 kCFBooleanTrue); 135 /* 136 * This could be mounting a home directory, so we don't want 137 * the mount to look at user preferences in the home directory. 138 */ 139 CFDictionaryAddValue(open_options, kNetFSNoUserPreferencesKey, 140 kCFBooleanTrue); 141 /* 142 * We don't want any UI popped up for the mount. 143 */ 144 CFDictionaryAddValue(open_options, kUIOptionKey, kUIOptionNoUI); 145 146 mount_options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, 147 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 148 if (mount_options == NULL) 149 exit(ENOMEM); 150 /* 151 * It's OK to use an existing session. 152 */ 153 CFDictionaryAddValue(mount_options, kNetFSForceNewSessionKey, 154 kCFBooleanFalse); 155 /* 156 * We want the URL mounted exactly where we specify. 157 */ 158 CFDictionaryAddValue(mount_options, kNetFSMountAtMountDirKey, 159 kCFBooleanTrue); 160 /* 161 * This could be mounting a home directory, so we don't want 162 * the mount to look at user preferences in the home directory. 163 */ 164 CFDictionaryAddValue(mount_options, kNetFSNoUserPreferencesKey, 165 kCFBooleanTrue); 166 /* 167 * We want to allow the URL to specify a directory underneath 168 * a share point for file systems that support the notion of 169 * shares. 170 */ 171 CFDictionaryAddValue(mount_options, kNetFSAllowSubMountsKey, 172 kCFBooleanTrue); 173 /* 174 * Add the mount flags. 175 */ 176 CFDictionaryAddValue(mount_options, kNetFSMountFlagsKey, 177 CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, 178 &flags)); 179 /* 180 * Add the soft mount flag. 181 */ 182 CFDictionaryAddValue(mount_options, kNetFSSoftMountKey, 183 (altflags & ALT_SOFT) ? kCFBooleanTrue : kCFBooleanFalse); 184 /* 185 * We don't want any UI popped up for the mount. 186 */ 187 CFDictionaryAddValue(mount_options, kUIOptionKey, kUIOptionNoUI); 188 189 if (usenetauth) 190 res = NAConnectToServerSync(URL, mountdir_CFString, 191 open_options, mount_options, &mount_info); 192 else 193 res = do_mount_direct(URL, mountdir_CFString, open_options, 194 mount_options, &mount_info); 195 /* 196 * 0 means "no error", EEXIST means "that's already mounted, and 197 * mountinfo says where it's mounted". In those cases, a 198 * directory of mount information was returned; release it. 199 */ 200 if (res == 0 || res == EEXIST) 201 CFRelease(mount_info); 202 CFRelease(mount_options); 203 CFRelease(open_options); 204 CFRelease(mountdir_CFString); 205 CFRelease(URL); 206 if (res != 0) { 207 /* 208 * Report any failure status that doesn't fit in the 209 * 8 bits of a UN*X exit status, and map it to EIO 210 * by default and EAUTH for ENETFS errors. 211 */ 212 if ((res & 0xFFFFFF00) != 0) { 213 syslog(LOG_ERR, 214 "mount_url: Mount of %s on %s gives status %d", 215 argv[0], argv[1], res); 216 switch (res) { 217 218 case ENETFSACCOUNTRESTRICTED: 219 case ENETFSPWDNEEDSCHANGE: 220 case ENETFSPWDPOLICY: 221 res = EAUTH; 222 break; 223 224 default: 225 res = EIO; 226 break; 227 } 228 } 229 } 230 231 return res; 232} 233 234static void 235usage(void) 236{ 237 fprintf(stderr, "Usage: mount_url [-n] [-rw] [-o options] url node\n"); 238 exit(1); 239} 240 241static int 242do_mount_direct(CFURLRef server_URL, CFStringRef mountdir, 243 CFDictionaryRef open_options, CFDictionaryRef mount_options, 244 CFDictionaryRef *mount_infop) 245{ 246 int ret; 247 void *session_ref; 248 249 *mount_infop = NULL; 250 ret = netfs_CreateSessionRef(server_URL, &session_ref); 251 if (ret != 0) 252 return ret; 253 ret = netfs_OpenSession(server_URL, session_ref, open_options, NULL); 254 if (ret != 0) { 255 netfs_CloseSession(session_ref); 256 return ret; 257 } 258 ret = netfs_Mount(session_ref, server_URL, mountdir, mount_options, 259 mount_infop); 260 netfs_CloseSession(session_ref); 261 return ret; 262} 263