1/*
2 * Copyright (c) 2006 - 2010 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 <sys/param.h>
25#include <sys/mount.h>
26#include <asl.h>
27
28#include <NetFS/NetFSPlugin.h>
29#include <NetFS/NetFSUtil.h>
30#include <NetFS/NetFSPrivate.h>
31#include <NetFS/NetFSUtilPrivate.h>
32
33#include <smbclient/smbclient.h>
34#include <smbclient/smbclient_netfs.h>
35#include <smbclient/smbclient_internal.h>
36
37#include "smb_netfs.h"
38#include "netshareenum.h"
39#include "SetNetworkAccountSID.h"
40
41/*
42 * SMB_GetTraceMessageScheme
43 *
44 * See whether we were passed a scheme to use when logging failures.  If so, we
45 * log them with NetFSLogToMessageTracer. The scheme string needs to be freed
46 * by the calling process.
47 */
48static char *SMB_GetTraceMessageScheme(CFDictionaryRef options)
49{
50	CFStringRef schemeRef;
51
52	if (!options) {
53		return NULL;
54	}
55	schemeRef = CFDictionaryGetValue(options, kNetFSTraceMessageSchemeKey);
56	if (!schemeRef) {
57		return NULL;
58	}
59	return NetFSCFStringtoCString(schemeRef);
60}
61
62/*
63 * SMB_CreateSessionRef
64 *
65 * Load the smbfs kext if need, initialize anything needed by the library  and
66 * create a session reference structure, the first element must have our schema
67 * as a CFStringRef.
68 */
69static netfsError SMB_CreateSessionRef(void **outConnection)
70{
71	int error = SMBNetFsCreateSessionRef((SMBHANDLE *)outConnection);
72
73	if (*outConnection == NULL) {
74		SMBLogInfo("%s: creating smb handle failed, syserr = %s",
75					 ASL_LEVEL_ERR, __FUNCTION__, strerror(error));
76	}
77	return error;
78}
79
80/*
81 * SMB_CancelSession
82 */
83static netfsError SMB_Cancel(void *inConnection)
84{
85	return SMBNetFsCancel(inConnection);
86}
87
88/*
89 * SMB_CloseSession
90 */
91static netfsError SMB_CloseSession(void *inConnection)
92{
93	return SMBNetFsCloseSession(inConnection);
94}
95
96/*
97 * SMB_ParseURL
98 */
99static netfsError SMB_ParseURL(CFURLRef url, CFDictionaryRef *urlParms)
100{
101	return SMBNetFsParseURL(url, urlParms);
102}
103
104/*
105 * SMB_CreateURL
106 */
107static netfsError SMB_CreateURL(CFDictionaryRef urlParms, CFURLRef *url)
108{
109	return SMBNetFsCreateURL(urlParms, url);
110}
111
112/*
113 * SMB_OpenSession
114 */
115static netfsError SMB_OpenSession(CFURLRef url, void *inConnection,
116								  CFDictionaryRef openOptions,
117								  CFDictionaryRef *sessionInfo)
118{
119	int error = 0;
120	char *tmscheme = SMB_GetTraceMessageScheme(openOptions);
121
122	if ((inConnection == NULL) || (url == NULL))  {
123		error = EINVAL;
124		NetFSLogToMessageTracer(tmscheme, "checking parameters in SMB_OpenSession", error);
125		goto done;
126	}
127	SMBNetFsLockSession(inConnection);
128	error = SMBNetFsOpenSession(url, inConnection, openOptions, sessionInfo);
129	if (error) {
130		SMBLogInfo("%s: - error = %d!", ASL_LEVEL_DEBUG, __FUNCTION__, error);
131		/* Tracing handled in smb_open_session */
132	}
133	SMBNetFsUnlockSession(inConnection);
134done:
135	if (tmscheme) {
136		free(tmscheme);
137	}
138	return error;
139}
140
141/*
142 * SMB_GetServerInfo
143 */
144static netfsError SMB_GetServerInfo(CFURLRef url, void *inConnection,
145									CFDictionaryRef openOptions,
146									CFDictionaryRef *serverParms)
147{
148	int error;
149
150	if ((inConnection == NULL) || (url == NULL)) {
151		return EINVAL;
152	}
153	SMBNetFsLockSession(inConnection);
154	error = SMBNetFsGetServerInfo(url, inConnection, openOptions, serverParms);
155	if (error) {
156		SMBLogInfo("%s: - error = %d!", ASL_LEVEL_DEBUG, __FUNCTION__, error);
157	}
158	SMBNetFsUnlockSession(inConnection);
159	return error;
160}
161
162/*
163 * SMB_EnumerateShares
164 */
165static netfsError SMB_EnumerateShares(void *inConnection,
166									  CFDictionaryRef enumerateOptions,
167									  CFDictionaryRef *sharePoints )
168{
169#pragma unused(enumerateOptions)
170	int error;
171
172	if (inConnection == NULL) {
173		return EINVAL;
174	}
175	SMBNetFsLockSession(inConnection);
176	/*
177	 * Make sure we have a tree connect to IPC$.This is safe because all
178	 * the NetAuth routines that care about the share name will reset it.
179	 */
180	error = SMBNetFsTreeConnectForEnumerateShares(inConnection);
181	if (!error) {
182		error = smb_netshareenum(inConnection, sharePoints, TRUE);
183	}
184	if (error) {
185		SMBLogInfo("%s: - error = %d!", ASL_LEVEL_DEBUG, __FUNCTION__, error);
186	}
187	SMBNetFsUnlockSession(inConnection);
188	return error;
189}
190
191/*
192 * SMB_Mount
193 */
194static netfsError SMB_Mount(void *inConnection, CFURLRef url, CFStringRef mPoint,
195					 CFDictionaryRef mOptions, CFDictionaryRef *mInfo)
196{
197	int error;
198	char *tmscheme = SMB_GetTraceMessageScheme(mOptions);
199
200	if ((inConnection == NULL) || (mPoint == NULL) || (url == NULL)) {
201		error = EINVAL;
202		NetFSLogToMessageTracer(tmscheme, "checking parameters in SMB_Mount", error);
203		goto done;
204	}
205	SMBNetFsLockSession(inConnection);
206	error =  SMBNetFsMount(inConnection,url, mPoint, mOptions, mInfo, setNetworkAccountSID, NULL);
207	if (error) {
208		SMBLogInfo("%s: - error = %d!", ASL_LEVEL_DEBUG, __FUNCTION__, error);
209		/* Tracing handled in smb_mount */
210	}
211	SMBNetFsUnlockSession(inConnection);
212done:
213	if (tmscheme) {
214		free(tmscheme);
215	}
216	return error;
217}
218
219/*
220 * SMB_GetMountInfo
221 */
222static netfsError SMB_GetMountInfo(CFStringRef in_Mountpath, CFDictionaryRef *out_MountInfo)
223{
224	return SMBNetFsGetMountInfo(in_Mountpath, out_MountInfo);
225}
226
227
228
229
230/* CIFS NetFS factory ID: 92D4EFEF-F5AA-11D5-A1EE-003065A0E6DE */
231#define kCIFSNetFSInterfaceFactoryID (CFUUIDGetConstantUUIDWithBytes(NULL, 0x92, 0xd4, 0xef, 0xef, 0xf5, 0xaa, 0x11, 0xd5, 0xa1, 0xee, 0x00, 0x30, 0x65, 0xa0, 0xe6, 0xde))
232
233/*
234 *  NetFS Type implementation:
235 */
236static NetFSMountInterface_V1 gCIFSNetFSMountInterfaceFTbl = {
237    NULL,				/* IUNKNOWN_C_GUTS: _reserved */
238    NetFSQueryInterface,		/* IUNKNOWN_C_GUTS: QueryInterface */
239    NetFSInterface_AddRef,		/* IUNKNOWN_C_GUTS: AddRef */
240    NetFSInterface_Release,		/* IUNKNOWN_C_GUTS: Release */
241    SMB_CreateSessionRef,		/* CreateSessionRef */
242    SMB_GetServerInfo,			/* GetServerInfo */
243    SMB_ParseURL,			/* ParseURL */
244    SMB_CreateURL,			/* CreateURL */
245    SMB_OpenSession,			/* OpenSession */
246    SMB_EnumerateShares,		/* EnumerateShares */
247    SMB_Mount,				/* Mount */
248    SMB_Cancel,				/* Cancel */
249    SMB_CloseSession,			/* CloseSession */
250    SMB_GetMountInfo,			/* GetMountInfo */
251};
252
253void * CIFSNetFSInterfaceFactory(CFAllocatorRef allocator, CFUUIDRef typeID);
254
255void *CIFSNetFSInterfaceFactory(CFAllocatorRef allocator, CFUUIDRef typeID)
256{
257#pragma unused(allocator)
258	if (CFEqual(typeID, kNetFSTypeID)) {
259		return NetFS_CreateInterface(kCIFSNetFSInterfaceFactoryID, &gCIFSNetFSMountInterfaceFTbl);
260    } else {
261		return NULL;
262	}
263}
264
265