1/* 2 * Copyright (c) 2000-2001, Boris Popov 3 * All rights reserved. 4 * 5 * Portions Copyright (C) 2001 - 2014 Apple Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Boris Popov. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35#include <sys/param.h> 36#include <sys/stat.h> 37#include <sys/errno.h> 38#include <sys/mount.h> 39 40#include <stdio.h> 41#include <string.h> 42#include <pwd.h> 43#include <grp.h> 44#include <unistd.h> 45#include <ctype.h> 46#include <stdlib.h> 47#include <err.h> 48#include <sysexits.h> 49#include <smbclient/smbclient.h> 50#include <smbclient/smbclient_internal.h> 51#include <smbclient/ntstatus.h> 52 53#include "SetNetworkAccountSID.h" 54 55#include <mntopts.h> 56 57static void usage(void); 58 59static struct mntopt mopts[] = { 60 MOPT_STDOPTS, 61 { "streams", 0, SMBFS_MNT_STREAMS_ON, 1 }, 62 { "notification", 1, SMBFS_MNT_NOTIFY_OFF, 1 }, 63 { "soft", 0, SMBFS_MNT_SOFT, 1 }, 64 { "timemachine", 0, SMBFS_MNT_TIME_MACHINE, 1 }, 65 { NULL, 0, 0, 0 } 66}; 67 68 69static unsigned xtoi(unsigned u) 70{ 71 if (isdigit(u)) 72 return (u - '0'); 73 else if (islower(u)) 74 return (10 + u - 'a'); 75 else if (isupper(u)) 76 return (10 + u - 'A'); 77 return (16); 78} 79 80/* Removes the "%" escape sequences from a URL component. 81 * See IETF RFC 2396. 82 * 83 * Someday we should convert this to use CFURLCreateStringByReplacingPercentEscapesUsingEncoding 84 */ 85static char * unpercent(char * component) 86{ 87 unsigned char c, *s; 88 unsigned hi, lo; 89 90 if (component) 91 for (s = (unsigned char *)component; (c = (unsigned char)*s); s++) { 92 if (c != '%') 93 continue; 94 if ((hi = xtoi(s[1])) > 15 || (lo = xtoi(s[2])) > 15) 95 continue; /* ignore invalid escapes */ 96 s[0] = hi*16 + lo; 97 /* 98 * This was strcpy(s + 1, s + 3); 99 * But nowadays leftward overlapping copies are 100 * officially undefined in C. Ours seems to 101 * work or not depending upon alignment. 102 */ 103 memmove(s+1, s+3, (strlen((char *)(s+3))) + 1); 104 } 105 return (component); 106} 107 108int main(int argc, char *argv[]) 109{ 110 SMBHANDLE serverConnection = NULL; 111 uint64_t options = kSMBOptionSessionOnly; 112 uint64_t mntOptions = 0; 113 int altflags = SMBFS_MNT_STREAMS_ON; 114 mode_t fileMode = 0, dirMode = 0; 115 int mntflags = 0; 116 NTSTATUS status; 117 char mountPoint[MAXPATHLEN]; 118 struct stat st; 119 char *next; 120 int opt; 121 const char * url = NULL; 122 int version = SMBFrameworkVersion(); 123 124 while ((opt = getopt(argc, argv, "Nvhsd:f:o:")) != -1) { 125 switch (opt) { 126 case 'd': 127 errno = 0; 128 dirMode = strtol(optarg, &next, 8); 129 if (errno || *next != 0) 130 errx(EX_DATAERR, "invalid value for directory mode"); 131 break; 132 case 'f': 133 errno = 0; 134 fileMode = strtol(optarg, &next, 8); 135 if (errno || *next != 0) 136 errx(EX_DATAERR, "invalid value for file mode"); 137 break; 138 case 'N': 139 options |= kSMBOptionNoPrompt; 140 break; 141 case 'o': { 142 mntoptparse_t mp = getmntopts(optarg, mopts, &mntflags, &altflags); 143 if (mp == NULL) 144 err(1, NULL); 145 freemntopts(mp); 146 break; 147 } 148 case 's': 149 options |= kSMBOptionForceNewSession; 150 mntOptions |= kSMBMntForceNewSession; 151 break; 152 case 'v': 153 errx(EX_OK, "version %d.%d.%d", 154 version / 100000, (version % 10000) / 1000, (version % 1000) / 100); 155 break; 156 case '?': 157 case 'h': 158 default: 159 usage(); 160 break; 161 } 162 } 163 if (optind >= argc) 164 usage(); 165 166 argc -= optind; 167 /* At this point we should only have a url and a mount point */ 168 if (argc != 2) 169 usage(); 170 url = argv[optind]; 171 optind++; 172 realpath(unpercent(argv[optind]), mountPoint); 173 174 if (stat(mountPoint, &st) == -1) 175 err(EX_OSERR, "could not find mount point %s", mountPoint); 176 177 if (!S_ISDIR(st.st_mode)) { 178 errno = ENOTDIR; 179 err(EX_OSERR, "can't mount on %s", mountPoint); 180 } 181 182 if (mntflags & MNT_AUTOMOUNTED) { 183 /* Automount volume, don't look in the user home directory */ 184 options |= kSMBOptionNoUserPreferences; 185 } 186 187 if ((altflags & SMBFS_MNT_STREAMS_ON) != SMBFS_MNT_STREAMS_ON) { 188 /* They told us to turn of named streams */ 189 mntOptions |= kSMBMntOptionNoStreams; 190 } 191 if ((altflags & SMBFS_MNT_NOTIFY_OFF) == SMBFS_MNT_NOTIFY_OFF) { 192 /* They told us to turn off remote notifications */ 193 mntOptions |= kSMBMntOptionNoNotifcations; 194 } 195 if ((altflags & SMBFS_MNT_SOFT) == SMBFS_MNT_SOFT) { 196 /* Make this a soft mount */ 197 mntOptions |= kSMBMntOptionSoftMount; 198 } 199 if ((altflags & SMBFS_MNT_TIME_MACHINE) == SMBFS_MNT_TIME_MACHINE) { 200 /* Make this a tm mount */ 201 mntOptions |= kSMBReservedTMMount; 202 } 203 204 status = SMBOpenServerEx(url, &serverConnection, options); 205 if (NT_SUCCESS(status)) { 206 status = SMBMountShareEx(serverConnection, NULL, mountPoint, mntflags, 207 mntOptions, fileMode, dirMode, setNetworkAccountSID, NULL); 208 } 209 /* 210 * SMBOpenServerEx now sets errno, so err will work correctly. We change 211 * the string based on the NTSTATUS Error. 212 */ 213 if (!NT_SUCCESS(status)) { 214 switch (status) { 215 case STATUS_NO_SUCH_DEVICE: 216 err(EX_UNAVAILABLE, "failed to intitialize the smb library"); 217 break; 218 case STATUS_LOGON_FAILURE: 219 err(EX_NOPERM, "server rejected the connection"); 220 break; 221 case STATUS_CONNECTION_REFUSED: 222 err(EX_NOHOST, "server connection failed"); 223 break; 224 case STATUS_INVALID_HANDLE: 225 case STATUS_NO_MEMORY: 226 err(EX_UNAVAILABLE, "internal error"); 227 break; 228 case STATUS_UNSUCCESSFUL: 229 err(EX_USAGE, "mount error: %s", mountPoint); 230 break; 231 case STATUS_INVALID_PARAMETER: 232 err(EX_USAGE, "URL parsing failed, please correct the URL and try again"); 233 break; 234 case STATUS_BAD_NETWORK_NAME: 235 err(EX_NOHOST, "share connection failed"); 236 break; 237 default: 238 err(EX_OSERR, "unknown status %d", status); 239 break; 240 } 241 } 242 243 /* We are done clean up anything left around */ 244 if (serverConnection) 245 SMBReleaseServer(serverConnection); 246 return 0; 247} 248 249static void 250usage(void) 251{ 252 fprintf(stderr, "%s\n", 253 "usage: mount_smbfs [-N] [-o options] [-d mode] [-f mode] [-h] [-s] [-v]\n" 254 " //" 255 "[domain;][user[:password]@]server[/share]" 256 " path"); 257 258 exit (EX_USAGE); 259} 260