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