1adee6784SGordon Ross /*
2adee6784SGordon Ross  * Copyright (c) 2011 - 2013 Apple Inc. All rights reserved.
3adee6784SGordon Ross  *
4adee6784SGordon Ross  * @APPLE_LICENSE_HEADER_START@
5adee6784SGordon Ross  *
6adee6784SGordon Ross  * This file contains Original Code and/or Modifications of Original Code
7adee6784SGordon Ross  * as defined in and that are subject to the Apple Public Source License
8adee6784SGordon Ross  * Version 2.0 (the 'License'). You may not use this file except in
9adee6784SGordon Ross  * compliance with the License. Please obtain a copy of the License at
10adee6784SGordon Ross  * http://www.opensource.apple.com/apsl/ and read it before using this
11adee6784SGordon Ross  * file.
12adee6784SGordon Ross  *
13adee6784SGordon Ross  * The Original Code and all software distributed under the License are
14adee6784SGordon Ross  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15adee6784SGordon Ross  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16adee6784SGordon Ross  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17adee6784SGordon Ross  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18adee6784SGordon Ross  * Please see the License for the specific language governing rights and
19adee6784SGordon Ross  * limitations under the License.
20adee6784SGordon Ross  *
21adee6784SGordon Ross  * @APPLE_LICENSE_HEADER_END@
22adee6784SGordon Ross  */
23adee6784SGordon Ross 
24adee6784SGordon Ross /*
25adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
26adee6784SGordon Ross  */
27adee6784SGordon Ross 
28adee6784SGordon Ross #include <sys/param.h>
29adee6784SGordon Ross #include <sys/systm.h>
30adee6784SGordon Ross #include <sys/kmem.h>
31adee6784SGordon Ross #include <sys/proc.h>
32adee6784SGordon Ross #include <sys/lock.h>
33adee6784SGordon Ross #include <sys/socket.h>
34adee6784SGordon Ross #include <sys/uio.h>
35adee6784SGordon Ross #include <sys/random.h>
36adee6784SGordon Ross #include <sys/note.h>
37adee6784SGordon Ross #include <sys/errno.h>
38adee6784SGordon Ross #include <sys/cmn_err.h>
39adee6784SGordon Ross 
40adee6784SGordon Ross #include <smb/ntaccess.h>
41adee6784SGordon Ross #include <smb/winioctl.h>
42adee6784SGordon Ross 
43adee6784SGordon Ross #include <netsmb/smb_osdep.h>
44adee6784SGordon Ross 
45adee6784SGordon Ross #include <netsmb/smb.h>
46adee6784SGordon Ross #include <netsmb/smb2.h>
47adee6784SGordon Ross #include <netsmb/smb_conn.h>
48adee6784SGordon Ross #include <netsmb/smb_subr.h>
49adee6784SGordon Ross #include <netsmb/smb_tran.h>
50adee6784SGordon Ross #include <netsmb/smb_rq.h>
51adee6784SGordon Ross #include <netsmb/smb2_rq.h>
52adee6784SGordon Ross 
53*686670eaSGordon Ross /*
54*686670eaSGordon Ross  * Supported dialects.  Keep sorted by number because of how the
55*686670eaSGordon Ross  * vc_maxver check below may truncate this list.
56*686670eaSGordon Ross  */
57*686670eaSGordon Ross #define	NDIALECTS	3
58*686670eaSGordon Ross static const uint16_t smb2_dialects[NDIALECTS] = {
59*686670eaSGordon Ross 	SMB2_DIALECT_0210,
60*686670eaSGordon Ross 	SMB2_DIALECT_0300,
61*686670eaSGordon Ross 	SMB2_DIALECT_0302,
62adee6784SGordon Ross };
63adee6784SGordon Ross 
64adee6784SGordon Ross /* Optional capabilities we advertise (none yet). */
65adee6784SGordon Ross uint32_t smb2_clnt_caps = 0;
66adee6784SGordon Ross 
67adee6784SGordon Ross /* How many credits to ask for during ssn. setup. */
68adee6784SGordon Ross uint16_t smb2_ss_req_credits = 64;
69adee6784SGordon Ross 
70adee6784SGordon Ross /*
71adee6784SGordon Ross  * Default timeout values, all in seconds.
72adee6784SGordon Ross  * Make these tunable (only via mdb for now).
73adee6784SGordon Ross  */
74adee6784SGordon Ross int smb2_timo_notice = 15;
75adee6784SGordon Ross int smb2_timo_default = 30;
76adee6784SGordon Ross int smb2_timo_logon = 45;
77adee6784SGordon Ross int smb2_timo_open = 45;
78adee6784SGordon Ross int smb2_timo_read = 45;
79adee6784SGordon Ross int smb2_timo_write = 60;
80adee6784SGordon Ross int smb2_timo_append = 90;
81adee6784SGordon Ross 
82adee6784SGordon Ross /*
83adee6784SGordon Ross  * This is a special handler for the odd SMB1-to-SMB2 negotiate
84adee6784SGordon Ross  * response, where an SMB1 request gets an SMB2 response.
85adee6784SGordon Ross  *
86adee6784SGordon Ross  * Unlike most parse functions here, this needs to parse both
87adee6784SGordon Ross  * the SMB2 header and the nego. response body.  Note that
88adee6784SGordon Ross  * the only "SMB2" dialect our SMB1 negotiate offered was
89adee6784SGordon Ross  * { SMB_DIALECT_SMB2_FF, "SMB 2.???"} so the only valid
90adee6784SGordon Ross  * SMB2 dialect we should get is: SMB2_DIALECT_02ff
91adee6784SGordon Ross  */
92adee6784SGordon Ross int
smb2_parse_smb1nego_resp(struct smb_rq * rqp)93adee6784SGordon Ross smb2_parse_smb1nego_resp(struct smb_rq *rqp)
94adee6784SGordon Ross {
95adee6784SGordon Ross 	struct smb_vc *vcp = rqp->sr_vc;
96adee6784SGordon Ross 	struct smb_sopt *sp = &vcp->vc_sopt;
97adee6784SGordon Ross 	struct mdchain *mdp;
98adee6784SGordon Ross 	uint16_t length = 0;
99adee6784SGordon Ross 	int error;
100adee6784SGordon Ross 
101adee6784SGordon Ross 	/* Get pointer to response data */
102adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
103adee6784SGordon Ross 
104adee6784SGordon Ross 	error = smb2_rq_parsehdr(rqp);
105adee6784SGordon Ross 	if (error != 0)
106adee6784SGordon Ross 		return (error);
107adee6784SGordon Ross 
108adee6784SGordon Ross 	/*
109adee6784SGordon Ross 	 * Parse SMB 2/3 Negotiate Response
110adee6784SGordon Ross 	 * We are already pointing to begining of Response data
111adee6784SGordon Ross 	 */
112adee6784SGordon Ross 
113adee6784SGordon Ross 	/* Check structure size is 65 */
114adee6784SGordon Ross 	md_get_uint16le(mdp, &length);
115adee6784SGordon Ross 	if (length != 65)
116adee6784SGordon Ross 		return (EBADRPC);
117adee6784SGordon Ross 
118adee6784SGordon Ross 	/* Get Security Mode */
119adee6784SGordon Ross 	md_get_uint16le(mdp, &sp->sv2_security_mode);
120adee6784SGordon Ross 
121adee6784SGordon Ross 	/* Get Dialect. */
122*686670eaSGordon Ross 	error = md_get_uint16le(mdp, &sp->sv_proto);
123adee6784SGordon Ross 	if (error != 0)
124adee6784SGordon Ross 		return (error);
125adee6784SGordon Ross 
126adee6784SGordon Ross 	/* What dialect did we get? */
127*686670eaSGordon Ross 	if (sp->sv_proto != SMB2_DIALECT_02ff) {
128*686670eaSGordon Ross 		SMBERROR("Unknown dialect 0x%x\n", sp->sv_proto);
129adee6784SGordon Ross 		return (EINVAL);
130adee6784SGordon Ross 	}
131adee6784SGordon Ross 	/* Set our (internal) SMB1 dialect also. */
132adee6784SGordon Ross 	sp->sv_proto = SMB_DIALECT_SMB2_FF;
133adee6784SGordon Ross 
134adee6784SGordon Ross 	/*
135adee6784SGordon Ross 	 * This request did not go through smb2_iod_addrq and
136adee6784SGordon Ross 	 * smb2_iod_process() so the SMB2 message ID state is
137adee6784SGordon Ross 	 * behind what we need it to be.  Fix that.
138adee6784SGordon Ross 	 */
139adee6784SGordon Ross 	vcp->vc2_next_message_id = 1;
140adee6784SGordon Ross 	vcp->vc2_limit_message_id = 2;
141adee6784SGordon Ross 
142adee6784SGordon Ross 	/*
143adee6784SGordon Ross 	 * Skip parsing the rest.  We'll get a normal
144adee6784SGordon Ross 	 * SMB2 negotiate next and do negotiate then.
145adee6784SGordon Ross 	 */
146adee6784SGordon Ross 	return (0);
147adee6784SGordon Ross }
148adee6784SGordon Ross 
149adee6784SGordon Ross int
smb2_smb_negotiate(struct smb_vc * vcp,struct smb_cred * scred)150adee6784SGordon Ross smb2_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred)
151adee6784SGordon Ross {
152adee6784SGordon Ross 	smb_sopt_t *sp = &vcp->vc_sopt;
153adee6784SGordon Ross 	smbioc_ssn_work_t *wk = &vcp->vc_work;
154adee6784SGordon Ross 	struct smb_rq *rqp = NULL;
155adee6784SGordon Ross 	struct mbchain *mbp = NULL;
156adee6784SGordon Ross 	struct mdchain *mdp = NULL;
157*686670eaSGordon Ross 	uint16_t *ndialects_p;
158adee6784SGordon Ross 	uint16_t ndialects = NDIALECTS;
159adee6784SGordon Ross 	boolean_t will_sign = B_FALSE;
160adee6784SGordon Ross 	uint16_t length = 0;
161adee6784SGordon Ross 	uint16_t security_mode;
162adee6784SGordon Ross 	uint16_t sec_buf_off;
163adee6784SGordon Ross 	uint16_t sec_buf_len;
164adee6784SGordon Ross 	int err, i;
165adee6784SGordon Ross 
166adee6784SGordon Ross 	/*
167adee6784SGordon Ross 	 * Compute security mode
168adee6784SGordon Ross 	 */
169adee6784SGordon Ross 	if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
170adee6784SGordon Ross 		security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
171adee6784SGordon Ross 	} else {
172adee6784SGordon Ross 		security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
173adee6784SGordon Ross 	}
174adee6784SGordon Ross 
175adee6784SGordon Ross 	err = smb_rq_alloc(VCTOCP(vcp), SMB2_NEGOTIATE, scred, &rqp);
176adee6784SGordon Ross 	if (err)
177adee6784SGordon Ross 		return (err);
178adee6784SGordon Ross 
179adee6784SGordon Ross 	/*
180adee6784SGordon Ross 	 * Build the SMB2 negotiate request.
181adee6784SGordon Ross 	 */
182adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
183adee6784SGordon Ross 	mb_put_uint16le(mbp, 36);		/* Struct Size */
184*686670eaSGordon Ross 	ndialects_p = mb_reserve(mbp, 2);	/* Dialect Count */
185adee6784SGordon Ross 	mb_put_uint16le(mbp, security_mode);
186adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);		/*  Reserved */
187adee6784SGordon Ross 	mb_put_uint32le(mbp, smb2_clnt_caps);
188adee6784SGordon Ross 	mb_put_mem(mbp, vcp->vc_cl_guid, 16, MB_MSYSTEM);
189adee6784SGordon Ross 	mb_put_uint64le(mbp, 0);		/* Start Time */
190adee6784SGordon Ross 	for (i = 0; i < ndialects; i++) {	/* Dialects */
191*686670eaSGordon Ross 		if (smb2_dialects[i] > vcp->vc_maxver)
192*686670eaSGordon Ross 			break;
193adee6784SGordon Ross 		mb_put_uint16le(mbp, smb2_dialects[i]);
194adee6784SGordon Ross 	}
195*686670eaSGordon Ross 	*ndialects_p = htoles(i);
196adee6784SGordon Ross 
197adee6784SGordon Ross 	/*
198adee6784SGordon Ross 	 * Do the OTW call.
199adee6784SGordon Ross 	 */
200adee6784SGordon Ross 	err = smb2_rq_internal(rqp, smb2_timo_default);
201adee6784SGordon Ross 	if (err) {
202adee6784SGordon Ross 		goto errout;
203adee6784SGordon Ross 	}
204adee6784SGordon Ross 	/* Should only get status success. */
205adee6784SGordon Ross 	if (rqp->sr_error != NT_STATUS_SUCCESS) {
206adee6784SGordon Ross 		err = ENOTSUP;
207adee6784SGordon Ross 		goto errout;
208adee6784SGordon Ross 	}
209adee6784SGordon Ross 
210adee6784SGordon Ross 	/*
211adee6784SGordon Ross 	 * Decode the negotiate response
212adee6784SGordon Ross 	 */
213adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
214adee6784SGordon Ross 
215adee6784SGordon Ross 	md_get_uint16le(mdp, &length);	/* Struct size */
216adee6784SGordon Ross 	if (length != 65) {
217adee6784SGordon Ross 		err = EBADRPC;
218adee6784SGordon Ross 		goto errout;
219adee6784SGordon Ross 	}
220adee6784SGordon Ross 
221adee6784SGordon Ross 	md_get_uint16le(mdp, &sp->sv2_security_mode);
222*686670eaSGordon Ross 	md_get_uint16le(mdp, &sp->sv_proto); /* dialect */
223adee6784SGordon Ross 	md_get_uint16le(mdp, NULL);	/* reserved */
224adee6784SGordon Ross 	md_get_mem(mdp, sp->sv2_guid, 16, MB_MSYSTEM);
225adee6784SGordon Ross 	md_get_uint32le(mdp, &sp->sv2_capabilities);
226adee6784SGordon Ross 	md_get_uint32le(mdp, &sp->sv2_maxtransact);
227adee6784SGordon Ross 	md_get_uint32le(mdp, &sp->sv2_maxread);
228adee6784SGordon Ross 	md_get_uint32le(mdp, &sp->sv2_maxwrite);
229adee6784SGordon Ross 	md_get_uint64le(mdp, NULL);	/* curr_time */
230adee6784SGordon Ross 	md_get_uint64le(mdp, NULL);	/* boot_time */
231adee6784SGordon Ross 
232adee6784SGordon Ross 	/* Get Security Blob offset and length */
233adee6784SGordon Ross 	md_get_uint16le(mdp, &sec_buf_off);
234adee6784SGordon Ross 	err = md_get_uint16le(mdp, &sec_buf_len);
235adee6784SGordon Ross 	if (err != 0)
236adee6784SGordon Ross 		goto errout;
237adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* reserved */
238adee6784SGordon Ross 
239adee6784SGordon Ross 	/*
240adee6784SGordon Ross 	 * Security buffer offset is from the beginning of SMB 2 Header
241adee6784SGordon Ross 	 * Calculate how much further we have to go to get to it.
242adee6784SGordon Ross 	 * Current offset is: SMB2_HDRLEN + 64
243adee6784SGordon Ross 	 */
244adee6784SGordon Ross 	if (sec_buf_len != 0) {
245adee6784SGordon Ross 		int skip = (int)sec_buf_off - (SMB2_HDRLEN + 64);
246adee6784SGordon Ross 		if (skip < 0) {
247adee6784SGordon Ross 			err = EBADRPC;
248adee6784SGordon Ross 			goto errout;
249adee6784SGordon Ross 		}
250adee6784SGordon Ross 		if (skip > 0) {
251adee6784SGordon Ross 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
252adee6784SGordon Ross 		}
253adee6784SGordon Ross 
254adee6784SGordon Ross 		/*
255adee6784SGordon Ross 		 * Copy the security blob out to user space.
256adee6784SGordon Ross 		 * Buffer addr,size in vc_auth_rbuf,rlen
257adee6784SGordon Ross 		 */
258adee6784SGordon Ross 		if (wk->wk_u_auth_rlen < sec_buf_len) {
259adee6784SGordon Ross 			SMBSDEBUG("vc_auth_rbuf too small");
260adee6784SGordon Ross 			/* Give caller required size. */
261adee6784SGordon Ross 			wk->wk_u_auth_rlen = sec_buf_len;
262adee6784SGordon Ross 			err = EMSGSIZE;
263adee6784SGordon Ross 			goto errout;
264adee6784SGordon Ross 		}
265adee6784SGordon Ross 		wk->wk_u_auth_rlen = sec_buf_len;
266adee6784SGordon Ross 		err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
267*686670eaSGordon Ross 		    sec_buf_len, MB_MUSER);
268adee6784SGordon Ross 		if (err) {
269adee6784SGordon Ross 			goto errout;
270adee6784SGordon Ross 		}
271adee6784SGordon Ross 	}
272adee6784SGordon Ross 
273adee6784SGordon Ross 	/*
274adee6784SGordon Ross 	 * Decoded everything.  Now decisions.
275adee6784SGordon Ross 	 */
276adee6784SGordon Ross 
277adee6784SGordon Ross 	/*
278adee6784SGordon Ross 	 * Turn on signing if either Server or client requires it,
279adee6784SGordon Ross 	 * except: anonymous sessions can't sign.
280adee6784SGordon Ross 	 */
281adee6784SGordon Ross 	if ((sp->sv2_security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) ||
282adee6784SGordon Ross 	    (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED))
283adee6784SGordon Ross 		will_sign = B_TRUE;
284adee6784SGordon Ross 	if (vcp->vc_vopt & SMBVOPT_ANONYMOUS)
285adee6784SGordon Ross 		will_sign = B_FALSE;
286adee6784SGordon Ross 	SMBSDEBUG("Security signatures: %d", (int)will_sign);
287adee6784SGordon Ross 	if (will_sign)
288adee6784SGordon Ross 		vcp->vc_flags |= SMBV_SIGNING;
289adee6784SGordon Ross 
290adee6784SGordon Ross 	/*
291adee6784SGordon Ross 	 * ToDo - too many places are looking at sv_caps, so for now
292adee6784SGordon Ross 	 * set the SMB1 capabilities too.  Later we should use the
293adee6784SGordon Ross 	 * sv2_capabilities for SMB 2+.
294adee6784SGordon Ross 	 */
295adee6784SGordon Ross 	sp->sv_caps =  (SMB_CAP_UNICODE |
296adee6784SGordon Ross 			SMB_CAP_LARGE_FILES |
297adee6784SGordon Ross 			SMB_CAP_STATUS32 |
298adee6784SGordon Ross 			SMB_CAP_LARGE_READX |
299adee6784SGordon Ross 			SMB_CAP_LARGE_WRITEX |
300adee6784SGordon Ross 			SMB_CAP_EXT_SECURITY);
301adee6784SGordon Ross 	if (sp->sv2_capabilities & SMB2_CAP_DFS)
302adee6784SGordon Ross 		sp->sv_caps |= SMB_CAP_DFS;
303adee6784SGordon Ross 
304adee6784SGordon Ross 	/*
305adee6784SGordon Ross 	 * A few sanity checks on what we received,
306adee6784SGordon Ross 	 * becuse we will send these in ssnsetup.
307adee6784SGordon Ross 	 *
308adee6784SGordon Ross 	 * Maximum outstanding requests (we care),
309adee6784SGordon Ross 	 * and Max. VCs (we only use one).  Also,
310adee6784SGordon Ross 	 * MaxBufferSize lower limit per spec.
311adee6784SGordon Ross 	 */
312adee6784SGordon Ross 	if (sp->sv2_maxread < 0x8000) {
313adee6784SGordon Ross 		SMBSDEBUG("maxread too small\n");
314adee6784SGordon Ross 		err = ENOTSUP;
315adee6784SGordon Ross 		goto errout;
316adee6784SGordon Ross 	}
317adee6784SGordon Ross 	if (sp->sv2_maxwrite < 0x8000) {
318adee6784SGordon Ross 		SMBSDEBUG("maxwrite too small\n");
319adee6784SGordon Ross 		err = ENOTSUP;
320adee6784SGordon Ross 		goto errout;
321adee6784SGordon Ross 	}
322adee6784SGordon Ross 	if (sp->sv2_maxtransact < 0x4000) {
323adee6784SGordon Ross 		SMBSDEBUG("maxtransact too small\n");
324adee6784SGordon Ross 		err = ENOTSUP;
325adee6784SGordon Ross 		goto errout;
326adee6784SGordon Ross 	}
327adee6784SGordon Ross 
328adee6784SGordon Ross 	/* Here too, fill SMB1 fields */
329adee6784SGordon Ross 	vcp->vc_rxmax = sp->sv2_maxread;
330adee6784SGordon Ross 	vcp->vc_wxmax = sp->sv2_maxwrite;
331adee6784SGordon Ross 	vcp->vc_txmax = sp->sv2_maxtransact;
332adee6784SGordon Ross 
333adee6784SGordon Ross 	smb_rq_done(rqp);
334adee6784SGordon Ross 	return (0);
335adee6784SGordon Ross 
336adee6784SGordon Ross errout:
337adee6784SGordon Ross 	smb_rq_done(rqp);
338adee6784SGordon Ross 	if (err == 0)
339adee6784SGordon Ross 		err = EBADRPC;
340adee6784SGordon Ross 	return (err);
341adee6784SGordon Ross }
342adee6784SGordon Ross 
343adee6784SGordon Ross int
smb2_smb_ssnsetup(struct smb_vc * vcp,struct smb_cred * scred)344adee6784SGordon Ross smb2_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred)
345adee6784SGordon Ross {
346adee6784SGordon Ross 	// smb_sopt_t *sv = &vcp->vc_sopt;
347adee6784SGordon Ross 	smbioc_ssn_work_t *wk = &vcp->vc_work;
348adee6784SGordon Ross 	struct smb_rq *rqp = NULL;
349adee6784SGordon Ross 	struct mbchain *mbp = NULL;
350adee6784SGordon Ross 	struct mdchain *mdp = NULL;
351adee6784SGordon Ross 	char *sb;
352adee6784SGordon Ross 	int err, ret;
353adee6784SGordon Ross 	uint16_t sblen;
354adee6784SGordon Ross 	uint16_t length = 0;
355adee6784SGordon Ross 	uint16_t session_flags;
356adee6784SGordon Ross 	uint16_t sec_buf_off;
357adee6784SGordon Ross 	uint16_t sec_buf_len;
358adee6784SGordon Ross 	uint8_t security_mode;
359adee6784SGordon Ross 
360adee6784SGordon Ross 	/*
361adee6784SGordon Ross 	 * Compute security mode
362adee6784SGordon Ross 	 */
363adee6784SGordon Ross 	if (vcp->vc_vopt & SMBVOPT_SIGNING_REQUIRED) {
364adee6784SGordon Ross 		security_mode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
365adee6784SGordon Ross 	} else {
366adee6784SGordon Ross 		security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
367adee6784SGordon Ross 	}
368adee6784SGordon Ross 
369adee6784SGordon Ross 	sb = wk->wk_u_auth_wbuf.lp_ptr;
370adee6784SGordon Ross 	sblen = (uint16_t)wk->wk_u_auth_wlen;
371adee6784SGordon Ross 
372adee6784SGordon Ross 	err = smb_rq_alloc(VCTOCP(vcp), SMB2_SESSION_SETUP, scred, &rqp);
373adee6784SGordon Ross 	if (err != 0) {
374adee6784SGordon Ross 		ret = err;
375adee6784SGordon Ross 		goto out;
376adee6784SGordon Ross 	}
377adee6784SGordon Ross 
378adee6784SGordon Ross 	/*
379adee6784SGordon Ross 	 * Always ask for some credits. The server usually will
380adee6784SGordon Ross 	 * only grant these credits once we've authenticated.
381adee6784SGordon Ross 	 */
382adee6784SGordon Ross 	rqp->sr2_creditsrequested = smb2_ss_req_credits;
383adee6784SGordon Ross 
384adee6784SGordon Ross 	/*
385adee6784SGordon Ross 	 * Build the SMB Session Setup request.
386adee6784SGordon Ross 	 */
387adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
388adee6784SGordon Ross 
389adee6784SGordon Ross 	mb_put_uint16le(mbp, 25);	/* Struct size */
390adee6784SGordon Ross 	mb_put_uint8(mbp, 0);		/* VcNumber */
391adee6784SGordon Ross 	mb_put_uint8(mbp, security_mode);
392adee6784SGordon Ross 	mb_put_uint32le(mbp, smb2_clnt_caps);	/* Capabilities */
393adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);	/* Channel - always 0 */
394adee6784SGordon Ross 
395adee6784SGordon Ross 	/*
396adee6784SGordon Ross 	 * Security buffer offset and length.  Normally would use
397adee6784SGordon Ross 	 * ptr = mb_reserve() and fill in later, but since only a
398adee6784SGordon Ross 	 * small amount of fixed-size stuff follows (12 bytes)
399adee6784SGordon Ross 	 * we can just compute the offset now.
400adee6784SGordon Ross 	 */
401adee6784SGordon Ross 	mb_put_uint16le(mbp, mbp->mb_count + 12);
402adee6784SGordon Ross 	mb_put_uint16le(mbp, sblen);
403adee6784SGordon Ross 	mb_put_uint64le(mbp, vcp->vc2_prev_session_id);
404adee6784SGordon Ross 	err = mb_put_mem(mbp, sb, sblen, MB_MUSER);
405adee6784SGordon Ross 	if (err != 0) {
406adee6784SGordon Ross 		ret = err;
407adee6784SGordon Ross 		goto out;
408adee6784SGordon Ross 	}
409adee6784SGordon Ross 
410adee6784SGordon Ross 	/*
411adee6784SGordon Ross 	 * Run the request.  The return value here should be the
412adee6784SGordon Ross 	 * return from this function, unless we fail decoding.
413adee6784SGordon Ross 	 * Note: NT_STATUS_MORE_PROCESSING_REQUIRED is OK, and
414adee6784SGordon Ross 	 * the caller expects EINPROGRESS for that case.
415adee6784SGordon Ross 	 */
416adee6784SGordon Ross 	ret = smb2_rq_internal(rqp, smb2_timo_logon);
417adee6784SGordon Ross 	if (ret != 0)
418adee6784SGordon Ross 		goto out;
419adee6784SGordon Ross 	switch (rqp->sr_error) {
420adee6784SGordon Ross 	case NT_STATUS_SUCCESS:
421adee6784SGordon Ross 		break;
422adee6784SGordon Ross 	case NT_STATUS_MORE_PROCESSING_REQUIRED:
423adee6784SGordon Ross 		/* Keep going, but return... */
424adee6784SGordon Ross 		ret = EINPROGRESS;
425adee6784SGordon Ross 		break;
426adee6784SGordon Ross 	default:
427adee6784SGordon Ross 		ret = EAUTH;
428adee6784SGordon Ross 		goto out;
429adee6784SGordon Ross 	}
430adee6784SGordon Ross 
431adee6784SGordon Ross 	/*
432adee6784SGordon Ross 	 * After the first Session Setup Response,
433adee6784SGordon Ross 	 * save the session ID.
434adee6784SGordon Ross 	 */
435adee6784SGordon Ross 	if (vcp->vc2_session_id == 0)
436adee6784SGordon Ross 		vcp->vc2_session_id = rqp->sr2_rspsessionid;
437adee6784SGordon Ross 
438adee6784SGordon Ross 	/*
439adee6784SGordon Ross 	 * Decode the session setup response
440adee6784SGordon Ross 	 */
441adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
442adee6784SGordon Ross 
443adee6784SGordon Ross 	md_get_uint16le(mdp, &length);	/* Struct size */
444adee6784SGordon Ross 	if (length != 9) {
445adee6784SGordon Ross 		ret = EBADRPC;
446adee6784SGordon Ross 		goto out;
447adee6784SGordon Ross 	}
448adee6784SGordon Ross 
449adee6784SGordon Ross 	md_get_uint16le(mdp, &session_flags);
450adee6784SGordon Ross 	md_get_uint16le(mdp, &sec_buf_off);
451adee6784SGordon Ross 	err = md_get_uint16le(mdp, &sec_buf_len);
452adee6784SGordon Ross 	if (err != 0) {
453adee6784SGordon Ross 		ret = err;
454adee6784SGordon Ross 		goto out;
455adee6784SGordon Ross 	}
456adee6784SGordon Ross 
457adee6784SGordon Ross 	/*
458adee6784SGordon Ross 	 * Security buffer offset is from the beginning of SMB 2 Header
459adee6784SGordon Ross 	 * Calculate how much further we have to go to get to it.
460adee6784SGordon Ross 	 * Current offset is: SMB2_HDRLEN + 8
461adee6784SGordon Ross 	 */
462adee6784SGordon Ross 	if (sec_buf_len != 0) {
463adee6784SGordon Ross 		int skip = (int)sec_buf_off - (SMB2_HDRLEN + 8);
464adee6784SGordon Ross 		if (skip < 0) {
465adee6784SGordon Ross 			ret = EBADRPC;
466adee6784SGordon Ross 			goto out;
467adee6784SGordon Ross 		}
468adee6784SGordon Ross 		if (skip > 0) {
469adee6784SGordon Ross 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
470adee6784SGordon Ross 		}
471adee6784SGordon Ross 
472adee6784SGordon Ross 		/*
473adee6784SGordon Ross 		 * Copy the security blob out to user space.
474adee6784SGordon Ross 		 * Buffer addr,size in vc_auth_rbuf,rlen
475adee6784SGordon Ross 		 */
476adee6784SGordon Ross 		if (wk->wk_u_auth_rlen < sec_buf_len) {
477adee6784SGordon Ross 			SMBSDEBUG("vc_auth_rbuf too small");
478adee6784SGordon Ross 			/* Give caller required size. */
479adee6784SGordon Ross 			wk->wk_u_auth_rlen = sec_buf_len;
480adee6784SGordon Ross 			ret = EMSGSIZE;
481adee6784SGordon Ross 			goto out;
482adee6784SGordon Ross 		}
483adee6784SGordon Ross 		wk->wk_u_auth_rlen = sec_buf_len;
484adee6784SGordon Ross 		err = md_get_mem(mdp, wk->wk_u_auth_rbuf.lp_ptr,
485*686670eaSGordon Ross 		    sec_buf_len, MB_MUSER);
486adee6784SGordon Ross 		if (err != 0) {
487adee6784SGordon Ross 			ret = err;
488adee6784SGordon Ross 			goto out;
489adee6784SGordon Ross 		}
490adee6784SGordon Ross 	}
491adee6784SGordon Ross 
492adee6784SGordon Ross out:
493adee6784SGordon Ross 	if (err != 0 && err != EINPROGRESS) {
494adee6784SGordon Ross 		/* Session ID no longer valid. */
495adee6784SGordon Ross 		vcp->vc2_session_id = 0;
496adee6784SGordon Ross 	}
497adee6784SGordon Ross 	if (rqp)
498adee6784SGordon Ross 		smb_rq_done(rqp);
499adee6784SGordon Ross 
500adee6784SGordon Ross 	return (ret);
501adee6784SGordon Ross }
502adee6784SGordon Ross 
503adee6784SGordon Ross int
smb2_smb_logoff(struct smb_vc * vcp,struct smb_cred * scred)504adee6784SGordon Ross smb2_smb_logoff(struct smb_vc *vcp, struct smb_cred *scred)
505adee6784SGordon Ross {
506adee6784SGordon Ross 	struct smb_rq *rqp;
507adee6784SGordon Ross 	struct mbchain *mbp;
508adee6784SGordon Ross 	int error;
509adee6784SGordon Ross 
510adee6784SGordon Ross 	if (vcp->vc2_session_id == 0)
511adee6784SGordon Ross 		return (0);
512adee6784SGordon Ross 
513adee6784SGordon Ross 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_LOGOFF, scred, &rqp);
514adee6784SGordon Ross 	if (error)
515adee6784SGordon Ross 		return (error);
516adee6784SGordon Ross 
517adee6784SGordon Ross 	/*
518adee6784SGordon Ross 	 * Fill in Logoff part
519adee6784SGordon Ross 	 */
520adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
521adee6784SGordon Ross 	mb_put_uint16le(mbp, 4);	/* Struct size */
522adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);	/* Reserved */
523adee6784SGordon Ross 
524adee6784SGordon Ross 	/*
525adee6784SGordon Ross 	 * Run this with a relatively short timeout. (5 sec.)
526adee6784SGordon Ross 	 * We don't really care about the result here.
527adee6784SGordon Ross 	 * Also, don't reconnect for this, of course!
528adee6784SGordon Ross 	 */
529adee6784SGordon Ross 	rqp->sr_flags |= SMBR_NORECONNECT;
530adee6784SGordon Ross 	error = smb2_rq_internal(rqp, 5);
531adee6784SGordon Ross 	smb_rq_done(rqp);
532adee6784SGordon Ross 	return (error);
533adee6784SGordon Ross }
534adee6784SGordon Ross 
535adee6784SGordon Ross int
smb2_smb_treeconnect(struct smb_share * ssp,struct smb_cred * scred)536adee6784SGordon Ross smb2_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred)
537adee6784SGordon Ross {
538adee6784SGordon Ross 	struct smb_vc *vcp;
539adee6784SGordon Ross 	struct smb_rq *rqp = NULL;
540adee6784SGordon Ross 	struct mbchain *mbp;
541adee6784SGordon Ross 	struct mdchain *mdp;
542adee6784SGordon Ross 	char *unc_name = NULL;
543adee6784SGordon Ross 	int error, unc_len;
544adee6784SGordon Ross 	uint16_t plen, *plenp;
545adee6784SGordon Ross 	uint16_t options = 0;
546adee6784SGordon Ross 	uint_t cnt0;
547adee6784SGordon Ross 	uint32_t net_stype;
548adee6784SGordon Ross 	uint16_t structure_size = 0;
549adee6784SGordon Ross 	uint8_t smb2stype;
550adee6784SGordon Ross 
551adee6784SGordon Ross 	vcp = SSTOVC(ssp);
552adee6784SGordon Ross 
553adee6784SGordon Ross 	/*
554adee6784SGordon Ross 	 * Make this a "VC-level" request, so it will have
555adee6784SGordon Ross 	 * rqp->sr_share == NULL, and smb_iod_sendrq()
556adee6784SGordon Ross 	 * will send it with TID = SMB_TID_UNKNOWN
557adee6784SGordon Ross 	 *
558adee6784SGordon Ross 	 * This also serves to bypass the wait for
559adee6784SGordon Ross 	 * share state changes, which this call is
560adee6784SGordon Ross 	 * trying to carry out.
561adee6784SGordon Ross 	 */
562adee6784SGordon Ross 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_CONNECT, scred, &rqp);
563adee6784SGordon Ross 	if (error)
564adee6784SGordon Ross 		return (error);
565adee6784SGordon Ross 
566adee6784SGordon Ross 	/*
567adee6784SGordon Ross 	 * Build the UNC name, i.e. "//server/share"
568adee6784SGordon Ross 	 * but with backslashes of course.
569adee6784SGordon Ross 	 * size math: three slashes, one null.
570adee6784SGordon Ross 	 */
571adee6784SGordon Ross 	unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name);
572adee6784SGordon Ross 	unc_name = kmem_alloc(unc_len, KM_SLEEP);
573adee6784SGordon Ross 	(void) snprintf(unc_name, unc_len, "\\\\%s\\%s",
574adee6784SGordon Ross 	    vcp->vc_srvname, ssp->ss_name);
575adee6784SGordon Ross 	SMBSDEBUG("unc_name: \"%s\"", unc_name);
576adee6784SGordon Ross 
577adee6784SGordon Ross 	/*
578adee6784SGordon Ross 	 * Build the request.
579adee6784SGordon Ross 	 */
580adee6784SGordon Ross 	mbp = &rqp->sr_rq;
581adee6784SGordon Ross 
582adee6784SGordon Ross 	mb_put_uint16le(mbp, 9);	/* Struct size */
583adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);	/* Reserved */
584adee6784SGordon Ross 	mb_put_uint16le(mbp, 72);	/* Path Offset */
585adee6784SGordon Ross 
586adee6784SGordon Ross 	/*
587adee6784SGordon Ross 	 * Fill in path length after we put the string, so we know
588adee6784SGordon Ross 	 * the length after conversion from UTF-8 to UCS-2.
589adee6784SGordon Ross 	 */
590adee6784SGordon Ross 	plenp = mb_reserve(mbp, 2);
591adee6784SGordon Ross 	cnt0 = mbp->mb_count;
592adee6784SGordon Ross 
593adee6784SGordon Ross 	/* UNC resource name (without the null) */
594adee6784SGordon Ross 	error = smb_put_dmem(mbp, vcp, unc_name, unc_len - 1,
595adee6784SGordon Ross 	    SMB_CS_NONE, NULL);
596adee6784SGordon Ross 	if (error)
597adee6784SGordon Ross 		goto out;
598adee6784SGordon Ross 
599adee6784SGordon Ross 	/* Now go back and fill in the path length. */
600adee6784SGordon Ross 	plen = (uint16_t)(mbp->mb_count - cnt0);
601adee6784SGordon Ross 	*plenp = htoles(plen);
602adee6784SGordon Ross 
603adee6784SGordon Ross 	/*
604adee6784SGordon Ross 	 * Run the request.
605adee6784SGordon Ross 	 *
606adee6784SGordon Ross 	 * Using NOINTR_RECV because we don't want to risk
607adee6784SGordon Ross 	 * missing a successful tree connect response,
608adee6784SGordon Ross 	 * which would "leak" Tree IDs.
609adee6784SGordon Ross 	 */
610adee6784SGordon Ross 	rqp->sr_flags |= SMBR_NOINTR_RECV;
611adee6784SGordon Ross 	error = smb2_rq_simple(rqp);
612adee6784SGordon Ross 	SMBSDEBUG("%d\n", error);
613adee6784SGordon Ross 	if (error) {
614adee6784SGordon Ross 		/*
615adee6784SGordon Ross 		 * If we get the server name wrong, i.e. due to
616adee6784SGordon Ross 		 * mis-configured name services, this will be
617adee6784SGordon Ross 		 * NT_STATUS_DUPLICATE_NAME.  Log this error.
618adee6784SGordon Ross 		 */
619adee6784SGordon Ross 		SMBERROR("(%s) failed, status=0x%x",
620adee6784SGordon Ross 		    unc_name, rqp->sr_error);
621adee6784SGordon Ross 		goto out;
622adee6784SGordon Ross 	}
623adee6784SGordon Ross 
624adee6784SGordon Ross 	/*
625adee6784SGordon Ross 	 * Parse the tree connect response
626adee6784SGordon Ross 	 */
627adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
628adee6784SGordon Ross 
629adee6784SGordon Ross 	/* Check structure size is 16 */
630adee6784SGordon Ross 	md_get_uint16le(mdp, &structure_size);
631adee6784SGordon Ross 	if (structure_size != 16) {
632adee6784SGordon Ross 		error = EBADRPC;
633adee6784SGordon Ross 		goto out;
634adee6784SGordon Ross 	}
635adee6784SGordon Ross 
636adee6784SGordon Ross 	md_get_uint8(mdp, &smb2stype);
637adee6784SGordon Ross 	md_get_uint8(mdp, NULL);	/* reserved */
638adee6784SGordon Ross 	md_get_uint32le(mdp, &ssp->ss2_share_flags);
639adee6784SGordon Ross 	md_get_uint32le(mdp, &ssp->ss2_share_caps);
640adee6784SGordon Ross 	error = md_get_uint32le(mdp, NULL);	/* maxAccessRights */
641adee6784SGordon Ross 	if (error)
642adee6784SGordon Ross 		goto out;
643adee6784SGordon Ross 
644adee6784SGordon Ross 	/*
645adee6784SGordon Ross 	 * Convert SMB2 share type to NetShareEnum share type
646adee6784SGordon Ross 	 */
647adee6784SGordon Ross 	switch (smb2stype) {
648adee6784SGordon Ross 	case SMB2_SHARE_TYPE_DISK:
649adee6784SGordon Ross 		net_stype = STYPE_DISKTREE;
650adee6784SGordon Ross 		break;
651adee6784SGordon Ross 	case SMB2_SHARE_TYPE_PIPE:
652adee6784SGordon Ross 		net_stype = STYPE_IPC;
653adee6784SGordon Ross 		break;
654adee6784SGordon Ross 	case SMB2_SHARE_TYPE_PRINT:
655adee6784SGordon Ross 		net_stype = STYPE_PRINTQ;
656adee6784SGordon Ross 		break;
657adee6784SGordon Ross 	default:
658adee6784SGordon Ross 		net_stype = STYPE_UNKNOWN;
659adee6784SGordon Ross 		break;
660adee6784SGordon Ross 	}
661adee6784SGordon Ross 	ssp->ss_type = net_stype;
662adee6784SGordon Ross 
663adee6784SGordon Ross 	/*
664adee6784SGordon Ross 	 * Map SMB 2/3 capabilities to SMB 1 options,
665adee6784SGordon Ross 	 * for common code that looks there.
666adee6784SGordon Ross 	 */
667adee6784SGordon Ross 	if (ssp->ss2_share_caps & SMB2_SHARE_CAP_DFS)
668adee6784SGordon Ross 		options |= SMB_SHARE_IS_IN_DFS;
669adee6784SGordon Ross 
670adee6784SGordon Ross 	/* Update share state */
671adee6784SGordon Ross 	SMB_SS_LOCK(ssp);
672adee6784SGordon Ross 	ssp->ss2_tree_id = rqp->sr2_rsptreeid;
673adee6784SGordon Ross 	ssp->ss_vcgenid = vcp->vc_genid;
674adee6784SGordon Ross 	ssp->ss_options = options;
675adee6784SGordon Ross 	ssp->ss_flags |= SMBS_CONNECTED;
676adee6784SGordon Ross 	SMB_SS_UNLOCK(ssp);
677adee6784SGordon Ross 
678adee6784SGordon Ross out:
679adee6784SGordon Ross 	if (unc_name)
680adee6784SGordon Ross 		kmem_free(unc_name, unc_len);
681adee6784SGordon Ross 	smb_rq_done(rqp);
682adee6784SGordon Ross 	return (error);
683adee6784SGordon Ross }
684adee6784SGordon Ross 
685adee6784SGordon Ross int
smb2_smb_treedisconnect(struct smb_share * ssp,struct smb_cred * scred)686adee6784SGordon Ross smb2_smb_treedisconnect(struct smb_share *ssp, struct smb_cred *scred)
687adee6784SGordon Ross {
688adee6784SGordon Ross 	struct smb_vc *vcp;
689adee6784SGordon Ross 	struct smb_rq *rqp;
690adee6784SGordon Ross 	struct mbchain *mbp;
691adee6784SGordon Ross 	int error;
692adee6784SGordon Ross 
693adee6784SGordon Ross 	if (ssp->ss2_tree_id == SMB2_TID_UNKNOWN)
694adee6784SGordon Ross 		return (0);
695adee6784SGordon Ross 
696adee6784SGordon Ross 	/*
697adee6784SGordon Ross 	 * Build this as a "VC-level" request, so it will
698adee6784SGordon Ross 	 * avoid testing the _GONE flag on the share,
699adee6784SGordon Ross 	 * which has already been set at this point.
700adee6784SGordon Ross 	 * Add the share pointer "by hand" below, so
701adee6784SGordon Ross 	 * smb_iod_sendrq will plug in the TID.
702adee6784SGordon Ross 	 */
703adee6784SGordon Ross 	vcp = SSTOVC(ssp);
704adee6784SGordon Ross 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_TREE_DISCONNECT, scred, &rqp);
705adee6784SGordon Ross 	if (error)
706adee6784SGordon Ross 		return (error);
707adee6784SGordon Ross 	rqp->sr_share = ssp; /* See "by hand" above. */
708adee6784SGordon Ross 
709adee6784SGordon Ross 	/*
710adee6784SGordon Ross 	 * Fill in SMB2 Tree Disconnect part
711adee6784SGordon Ross 	 */
712adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
713adee6784SGordon Ross 	mb_put_uint16le(mbp, 4);	/* Struct size */
714adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);	/* Reserved */
715adee6784SGordon Ross 
716adee6784SGordon Ross 	/*
717adee6784SGordon Ross 	 * Run this with a relatively short timeout. (5 sec.)
718adee6784SGordon Ross 	 * We don't really care about the result here, but we
719adee6784SGordon Ross 	 * do need to make sure we send this out, or we could
720adee6784SGordon Ross 	 * "leak" active tree IDs on interrupt or timeout.
721adee6784SGordon Ross 	 * The NOINTR_SEND flag makes this request immune to
722adee6784SGordon Ross 	 * interrupt or timeout until the send is done.
723adee6784SGordon Ross 	 * Also, don't reconnect for this, of course!
724adee6784SGordon Ross 	 */
725adee6784SGordon Ross 	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
726adee6784SGordon Ross 	error = smb2_rq_simple_timed(rqp, 5);
727adee6784SGordon Ross 
728adee6784SGordon Ross 	smb_rq_done(rqp);
729adee6784SGordon Ross 
730adee6784SGordon Ross 	/* Whether we get an error or not... */
731adee6784SGordon Ross 	ssp->ss2_tree_id = SMB2_TID_UNKNOWN;
732adee6784SGordon Ross 
733adee6784SGordon Ross 	return (error);
734adee6784SGordon Ross }
735adee6784SGordon Ross 
736adee6784SGordon Ross /*
737adee6784SGordon Ross  * Put the name, first skipping a leading slash.
738adee6784SGordon Ross  */
739adee6784SGordon Ross static int
put_name_skip_slash(struct mbchain * mbp,struct mbchain * name_mbp)740adee6784SGordon Ross put_name_skip_slash(struct mbchain *mbp, struct mbchain *name_mbp)
741adee6784SGordon Ross {
742adee6784SGordon Ross 	mblk_t *m;
743adee6784SGordon Ross 
744adee6784SGordon Ross 	if (name_mbp == NULL)
745adee6784SGordon Ross 		return (0);
746adee6784SGordon Ross 	m = name_mbp->mb_top;
747adee6784SGordon Ross 	if (m == NULL)
748adee6784SGordon Ross 		return (0);
749adee6784SGordon Ross 
750adee6784SGordon Ross 	/* Use a dup of the message to leave the passed one untouched. */
751adee6784SGordon Ross 	m = dupmsg(m);
752adee6784SGordon Ross 	if (m == NULL)
753adee6784SGordon Ross 		return (ENOSR);
754adee6784SGordon Ross 
755adee6784SGordon Ross 	if (MBLKL(m) >= 2 &&
756adee6784SGordon Ross 	    m->b_rptr[0] == '\\' &&
757adee6784SGordon Ross 	    m->b_rptr[1] == '\0')
758adee6784SGordon Ross 		m->b_rptr += 2;
759adee6784SGordon Ross 
760adee6784SGordon Ross 	return (mb_put_mbuf(mbp, m));
761adee6784SGordon Ross }
762adee6784SGordon Ross 
763adee6784SGordon Ross /*
764adee6784SGordon Ross  * Modern create/open of file or directory.
765adee6784SGordon Ross  *
766adee6784SGordon Ross  * The passed name is a full path relative to the share root.
767adee6784SGordon Ross  * Callers prepare paths with a leading slash (backslash)
768adee6784SGordon Ross  * because that's what SMB1 expected.  SMB2 does not allow the
769adee6784SGordon Ross  * leading slash here.  To make life simpler for callers skip a
770adee6784SGordon Ross  * leading slash here.  That allows callers use use common logic
771adee6784SGordon Ross  * for building paths without needing to know if the connection
772adee6784SGordon Ross  * is using SMB1 or SMB2 (just build paths with a leading slash).
773adee6784SGordon Ross  */
774adee6784SGordon Ross int
smb2_smb_ntcreate(struct smb_share * ssp,struct mbchain * name_mb,struct mbchain * cctx_in,struct mdchain * cctx_out,uint32_t cr_flags,uint32_t req_acc,uint32_t efa,uint32_t share_acc,uint32_t open_disp,uint32_t createopt,uint32_t impersonate,struct smb_cred * scrp,smb2fid_t * fidp,uint32_t * cr_act_p,struct smbfattr * fap)775adee6784SGordon Ross smb2_smb_ntcreate(
776adee6784SGordon Ross 	struct smb_share *ssp,
777adee6784SGordon Ross 	struct mbchain	*name_mb,
778adee6784SGordon Ross 	struct mbchain	*cctx_in,
779adee6784SGordon Ross 	struct mdchain	*cctx_out,
780adee6784SGordon Ross 	uint32_t cr_flags,	/* create flags */
781adee6784SGordon Ross 	uint32_t req_acc,	/* requested access */
782adee6784SGordon Ross 	uint32_t efa,		/* ext. file attrs (DOS attr +) */
783adee6784SGordon Ross 	uint32_t share_acc,
784adee6784SGordon Ross 	uint32_t open_disp,	/* open disposition */
785adee6784SGordon Ross 	uint32_t createopt,	/* NTCREATEX_OPTIONS_ */
786adee6784SGordon Ross 	uint32_t impersonate,	/* NTCREATEX_IMPERSONATION_... */
787adee6784SGordon Ross 	struct smb_cred *scrp,
788adee6784SGordon Ross 	smb2fid_t *fidp,	/* returned FID */
789adee6784SGordon Ross 	uint32_t *cr_act_p,	/* optional create action */
790adee6784SGordon Ross 	struct smbfattr *fap)	/* optional attributes */
791adee6784SGordon Ross {
792adee6784SGordon Ross 	struct smbfattr fa;
793adee6784SGordon Ross 	struct smb_rq *rqp;
794adee6784SGordon Ross 	struct mbchain *mbp;
795adee6784SGordon Ross 	struct mdchain *mdp;
796adee6784SGordon Ross 	uint16_t *name_offp;
797adee6784SGordon Ross 	uint16_t *name_lenp;
798adee6784SGordon Ross 	uint32_t *cctx_offp;
799adee6784SGordon Ross 	uint32_t *cctx_lenp;
800adee6784SGordon Ross 	uint32_t rcc_off, rcc_len;
801adee6784SGordon Ross 	smb2fid_t smb2_fid;
802adee6784SGordon Ross 	uint64_t llongint;
803adee6784SGordon Ross 	uint32_t longint, createact;
804adee6784SGordon Ross 	uint_t off, len;
805adee6784SGordon Ross 	int error;
806adee6784SGordon Ross 	uint16_t StructSize = 57;	// [MS-SMB2]
807adee6784SGordon Ross 
808adee6784SGordon Ross 	bzero(&fa, sizeof (fa));
809adee6784SGordon Ross 
810adee6784SGordon Ross 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_CREATE, scrp, &rqp);
811adee6784SGordon Ross 	if (error)
812adee6784SGordon Ross 		return (error);
813adee6784SGordon Ross 
814adee6784SGordon Ross 	/*
815adee6784SGordon Ross 	 * Todo: Assemble creat contexts (if needed)
816adee6784SGordon Ross 	 * into an mbchain.
817adee6784SGordon Ross 	 */
818adee6784SGordon Ross 
819adee6784SGordon Ross 	/*
820adee6784SGordon Ross 	 * Build the SMB 2/3 Create Request
821adee6784SGordon Ross 	 */
822adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
823adee6784SGordon Ross 	mb_put_uint16le(mbp, StructSize);
824adee6784SGordon Ross 	mb_put_uint8(mbp, 0);				/* Security flags */
825adee6784SGordon Ross 	mb_put_uint8(mbp, SMB2_OPLOCK_LEVEL_NONE);	/* Oplock level */
826*686670eaSGordon Ross 	mb_put_uint32le(mbp, impersonate);	/* Impersonation Level */
827adee6784SGordon Ross 	mb_put_uint64le(mbp, cr_flags);
828adee6784SGordon Ross 	mb_put_uint64le(mbp, 0);			/* Reserved */
829adee6784SGordon Ross 	mb_put_uint32le(mbp, req_acc);
830adee6784SGordon Ross 	mb_put_uint32le(mbp, efa);			/* File attributes */
831adee6784SGordon Ross 	mb_put_uint32le(mbp, share_acc);		/* Share access */
832adee6784SGordon Ross 	mb_put_uint32le(mbp, open_disp);		/* Create disposition */
833adee6784SGordon Ross 	mb_put_uint32le(mbp, createopt);		/* Create options */
834adee6784SGordon Ross 
835adee6784SGordon Ross 	name_offp = mb_reserve(mbp, 2);			/* Name offset */
836adee6784SGordon Ross 	name_lenp = mb_reserve(mbp, 2);			/* Name len */
837adee6784SGordon Ross 
838adee6784SGordon Ross 	cctx_offp = mb_reserve(mbp, 4);			/* Context offset */
839adee6784SGordon Ross 	cctx_lenp = mb_reserve(mbp, 4);			/* Context len */
840adee6784SGordon Ross 
841adee6784SGordon Ross 	/*
842adee6784SGordon Ross 	 * Put the file name, which is provided in an mbchain.
843adee6784SGordon Ross 	 * If there's a leading slash, skip it (see above).
844adee6784SGordon Ross 	 */
845adee6784SGordon Ross 	off = mbp->mb_count;
846adee6784SGordon Ross 	*name_offp = htoles((uint16_t)off);
847adee6784SGordon Ross 	error = put_name_skip_slash(mbp, name_mb);
848adee6784SGordon Ross 	if (error)
849adee6784SGordon Ross 		goto out;
850adee6784SGordon Ross 	len = mbp->mb_count - off;
851adee6784SGordon Ross 	*name_lenp = htoles((uint16_t)len);
852adee6784SGordon Ross 
853adee6784SGordon Ross 	/*
854adee6784SGordon Ross 	 * Now the create contexts (if provided)
855adee6784SGordon Ross 	 */
856adee6784SGordon Ross 	if (cctx_in != NULL) {
857adee6784SGordon Ross 		off = mbp->mb_count;
858adee6784SGordon Ross 		*cctx_offp = htolel((uint32_t)off);
859adee6784SGordon Ross 		mb_put_mbchain(mbp, cctx_in);
860adee6784SGordon Ross 		len = mbp->mb_count - off;
861adee6784SGordon Ross 		*cctx_lenp = htolel((uint32_t)len);
862adee6784SGordon Ross 	} else {
863adee6784SGordon Ross 		*cctx_offp = 0;
864adee6784SGordon Ross 		*cctx_lenp = 0;
865adee6784SGordon Ross 	}
866adee6784SGordon Ross 
867adee6784SGordon Ross 	/*
868adee6784SGordon Ross 	 * If we didn't put any variable-sized data, we'll have
869adee6784SGordon Ross 	 * put exactly 56 bytes of data, and we need to pad out
870adee6784SGordon Ross 	 * this request to the 57 bytes StructSize indicated.
871adee6784SGordon Ross 	 */
872adee6784SGordon Ross 	if (mbp->mb_count < (StructSize + SMB2_HDRLEN))
873adee6784SGordon Ross 		mb_put_uint8(mbp, 0);
874adee6784SGordon Ross 
875adee6784SGordon Ross 	/*
876adee6784SGordon Ross 	 * Don't want to risk missing a successful
877adee6784SGordon Ross 	 * open response, or we could "leak" FIDs.
878adee6784SGordon Ross 	 */
879adee6784SGordon Ross 	rqp->sr_flags |= SMBR_NOINTR_RECV;
880adee6784SGordon Ross 	error = smb2_rq_simple_timed(rqp, smb2_timo_open);
881adee6784SGordon Ross 	if (error)
882adee6784SGordon Ross 		goto out;
883adee6784SGordon Ross 
884adee6784SGordon Ross 	/*
885adee6784SGordon Ross 	 * Parse SMB 2/3 Create Response
886adee6784SGordon Ross 	 */
887adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
888adee6784SGordon Ross 
889adee6784SGordon Ross 	/* Check structure size is 89 */
890adee6784SGordon Ross 	error = md_get_uint16le(mdp, &StructSize);
891adee6784SGordon Ross 	if (StructSize != 89) {
892adee6784SGordon Ross 		error = EBADRPC;
893adee6784SGordon Ross 		goto out;
894adee6784SGordon Ross 	}
895adee6784SGordon Ross 
896adee6784SGordon Ross 	md_get_uint8(mdp, NULL);		/* oplock lvl granted */
897adee6784SGordon Ross 	md_get_uint8(mdp, NULL);		/* mbz */
898adee6784SGordon Ross 	md_get_uint32le(mdp, &createact);	/* create_action */
899adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);	/* creation time */
900adee6784SGordon Ross 	smb_time_NT2local(llongint, &fa.fa_createtime);
901adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);	/* access time */
902adee6784SGordon Ross 	smb_time_NT2local(llongint, &fa.fa_atime);
903adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);	/* write time */
904adee6784SGordon Ross 	smb_time_NT2local(llongint, &fa.fa_mtime);
905adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);	/* change time */
906adee6784SGordon Ross 	smb_time_NT2local(llongint, &fa.fa_ctime);
907adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);	/* allocation size */
908adee6784SGordon Ross 	fa.fa_allocsz = llongint;
909adee6784SGordon Ross 	md_get_uint64le(mdp, &llongint);	/* EOF position */
910adee6784SGordon Ross 	fa.fa_size = llongint;
911adee6784SGordon Ross 	md_get_uint32le(mdp, &longint);		/* attributes */
912adee6784SGordon Ross 	fa.fa_attr = longint;
913adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);		/* reserved */
914adee6784SGordon Ross 
915adee6784SGordon Ross 	/* Get SMB 2/3 File ID and create user fid to return */
916adee6784SGordon Ross 	md_get_uint64le(mdp, &smb2_fid.fid_persistent);
917adee6784SGordon Ross 	error = md_get_uint64le(mdp, &smb2_fid.fid_volatile);
918adee6784SGordon Ross 	if (error)
919adee6784SGordon Ross 		goto out;
920adee6784SGordon Ross 
921adee6784SGordon Ross 	/* Get Context Offset */
922adee6784SGordon Ross 	error = md_get_uint32le(mdp, &rcc_off);
923adee6784SGordon Ross 	if (error)
924adee6784SGordon Ross 		goto out;
925adee6784SGordon Ross 	/* Get Context Length */
926adee6784SGordon Ross 	error = md_get_uint32le(mdp, &rcc_len);
927adee6784SGordon Ross 	if (error)
928adee6784SGordon Ross 		goto out;
929adee6784SGordon Ross 
930adee6784SGordon Ross 	/*
931adee6784SGordon Ross 	 * If the caller wants the returned create contexts, parse.
932adee6784SGordon Ross 	 * Context offset is from the beginning of SMB 2/3 Header
933adee6784SGordon Ross 	 * Calculate how much further we have to go to get to it.
934adee6784SGordon Ross 	 * Current offset is: SMB2_HDRLEN + 88
935adee6784SGordon Ross 	 */
936adee6784SGordon Ross 	if (rcc_len != 0) {
937adee6784SGordon Ross 		int skip = (int)rcc_off - (SMB2_HDRLEN + 88);
938adee6784SGordon Ross 		if (skip < 0) {
939adee6784SGordon Ross 			error = EBADRPC;
940adee6784SGordon Ross 			goto out;
941adee6784SGordon Ross 		}
942adee6784SGordon Ross 		if (skip > 0) {
943adee6784SGordon Ross 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
944adee6784SGordon Ross 		}
945adee6784SGordon Ross 		if (cctx_out != NULL) {
946adee6784SGordon Ross 			mblk_t *m = NULL;
947adee6784SGordon Ross 			error = md_get_mbuf(mdp, rcc_len, &m);
948adee6784SGordon Ross 			if (error)
949adee6784SGordon Ross 				goto out;
950adee6784SGordon Ross 			md_initm(cctx_out, m);
951adee6784SGordon Ross 		}
952adee6784SGordon Ross 	}
953adee6784SGordon Ross 
954adee6784SGordon Ross out:
955adee6784SGordon Ross 	smb_rq_done(rqp);
956adee6784SGordon Ross 	if (error)
957adee6784SGordon Ross 		return (error);
958adee6784SGordon Ross 
959adee6784SGordon Ross 	*fidp = smb2_fid;
960adee6784SGordon Ross 	if (cr_act_p)
961adee6784SGordon Ross 		*cr_act_p = createact;
962adee6784SGordon Ross 	if (fap)
963adee6784SGordon Ross 		*fap = fa; /* struct copy */
964adee6784SGordon Ross 
965adee6784SGordon Ross 	return (0);
966adee6784SGordon Ross }
967adee6784SGordon Ross 
968adee6784SGordon Ross int
smb2_smb_close(struct smb_share * ssp,smb2fid_t * fid,struct smb_cred * scrp)969adee6784SGordon Ross smb2_smb_close(struct smb_share *ssp, smb2fid_t *fid, struct smb_cred *scrp)
970adee6784SGordon Ross {
971adee6784SGordon Ross 	struct smb_rq *rqp;
972adee6784SGordon Ross 	struct mbchain *mbp;
973adee6784SGordon Ross 	int error;
974adee6784SGordon Ross 
975adee6784SGordon Ross 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_CLOSE, scrp, &rqp);
976adee6784SGordon Ross 	if (error)
977adee6784SGordon Ross 		return (error);
978adee6784SGordon Ross 
979adee6784SGordon Ross 	/*
980adee6784SGordon Ross 	 * Build the SMB 2/3 Close Request
981adee6784SGordon Ross 	 */
982adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
983adee6784SGordon Ross 	mb_put_uint16le(mbp, 24);		/* Struct size */
984adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);		/* Flags */
985adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Reserved */
986adee6784SGordon Ross 
987adee6784SGordon Ross 	mb_put_uint64le(mbp, fid->fid_persistent);
988adee6784SGordon Ross 	mb_put_uint64le(mbp, fid->fid_volatile);
989adee6784SGordon Ross 
990adee6784SGordon Ross 	/* Make sure we send, but only if already connected */
991adee6784SGordon Ross 	rqp->sr_flags |= (SMBR_NOINTR_SEND | SMBR_NORECONNECT);
992adee6784SGordon Ross 	error = smb2_rq_simple(rqp);
993adee6784SGordon Ross 	smb_rq_done(rqp);
994adee6784SGordon Ross 	return (error);
995adee6784SGordon Ross }
996adee6784SGordon Ross 
997adee6784SGordon Ross int
smb2_smb_ioctl(struct smb_share * ssp,smb2fid_t * fid,struct mbchain * data_in,struct mdchain * data_out,uint32_t * data_out_sz,uint32_t ctl_code,struct smb_cred * scrp)998adee6784SGordon Ross smb2_smb_ioctl(
999adee6784SGordon Ross 	struct smb_share *ssp,
1000adee6784SGordon Ross 	smb2fid_t *fid,
1001adee6784SGordon Ross 	struct mbchain	*data_in,
1002adee6784SGordon Ross 	struct mdchain	*data_out,
1003adee6784SGordon Ross 	uint32_t *data_out_sz,	/* max / returned */
1004adee6784SGordon Ross 	uint32_t ctl_code,
1005adee6784SGordon Ross 	struct smb_cred *scrp)
1006adee6784SGordon Ross {
1007adee6784SGordon Ross 	struct smb_rq *rqp;
1008adee6784SGordon Ross 	struct mbchain *mbp;
1009adee6784SGordon Ross 	struct mdchain *mdp;
1010adee6784SGordon Ross 	uint32_t *data_in_offp;
1011adee6784SGordon Ross 	uint32_t *data_in_lenp;
1012adee6784SGordon Ross 	uint32_t data_out_off;
1013adee6784SGordon Ross 	uint32_t data_out_len;
1014adee6784SGordon Ross 	uint16_t length = 0;
1015adee6784SGordon Ross 	uint_t off, len;
1016adee6784SGordon Ross 	int error;
1017adee6784SGordon Ross 
1018adee6784SGordon Ross 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_IOCTL, scrp, &rqp);
1019adee6784SGordon Ross 	if (error)
1020adee6784SGordon Ross 		return (error);
1021adee6784SGordon Ross 
1022adee6784SGordon Ross 	/*
1023adee6784SGordon Ross 	 * Build the SMB 2 IOCTL Request
1024adee6784SGordon Ross 	 */
1025adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
1026adee6784SGordon Ross 	mb_put_uint16le(mbp, 57);		/* Struct size */
1027adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);		/* Reserved */
1028adee6784SGordon Ross 	mb_put_uint32le(mbp, ctl_code);
1029adee6784SGordon Ross 
1030adee6784SGordon Ross 	mb_put_uint64le(mbp, fid->fid_persistent);
1031adee6784SGordon Ross 	mb_put_uint64le(mbp, fid->fid_volatile);
1032adee6784SGordon Ross 
1033adee6784SGordon Ross 	data_in_offp = mb_reserve(mbp, 4);
1034adee6784SGordon Ross 	data_in_lenp = mb_reserve(mbp, 4);
1035adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Max input resp */
1036adee6784SGordon Ross 
1037adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Output offset */
1038adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Output count */
1039adee6784SGordon Ross 	mb_put_uint32le(mbp, *data_out_sz);
1040adee6784SGordon Ross 
1041adee6784SGordon Ross 	mb_put_uint32le(mbp, SMB2_IOCTL_IS_FSCTL); /* Flags */
1042adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Reserved2 */
1043adee6784SGordon Ross 
1044adee6784SGordon Ross 	/*
1045adee6784SGordon Ross 	 * Now data_in (if provided)
1046adee6784SGordon Ross 	 */
1047adee6784SGordon Ross 	if (data_in != NULL) {
1048adee6784SGordon Ross 		off = mbp->mb_count;
1049adee6784SGordon Ross 		*data_in_offp = htolel((uint32_t)off);
1050adee6784SGordon Ross 		mb_put_mbchain(mbp, data_in);
1051adee6784SGordon Ross 		len = mbp->mb_count - off;
1052adee6784SGordon Ross 		*data_in_lenp = htolel((uint32_t)len);
1053adee6784SGordon Ross 	} else {
1054adee6784SGordon Ross 		*data_in_offp = 0;
1055adee6784SGordon Ross 		*data_in_lenp = 0;
1056adee6784SGordon Ross 	}
1057adee6784SGordon Ross 
1058adee6784SGordon Ross 	/*
1059adee6784SGordon Ross 	 * Run the request
1060adee6784SGordon Ross 	 */
1061adee6784SGordon Ross 	error = smb2_rq_simple_timed(rqp, smb2_timo_default);
1062adee6784SGordon Ross 	if (error)
1063adee6784SGordon Ross 		goto out;
1064adee6784SGordon Ross 
1065adee6784SGordon Ross 	/*
1066adee6784SGordon Ross 	 * Parse SMB 2 Ioctl Response
1067adee6784SGordon Ross 	 */
1068adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
1069adee6784SGordon Ross 
1070adee6784SGordon Ross 	/* Check structure size is 49 */
1071adee6784SGordon Ross 	md_get_uint16le(mdp, &length);
1072adee6784SGordon Ross 	if (length != 49) {
1073adee6784SGordon Ross 		error = EBADRPC;
1074adee6784SGordon Ross 		goto out;
1075adee6784SGordon Ross 	}
1076adee6784SGordon Ross 	md_get_uint16le(mdp, NULL);	/* reserved */
1077adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* Get CtlCode */
1078adee6784SGordon Ross 	md_get_uint64le(mdp, NULL);	/* fid_persistent */
1079adee6784SGordon Ross 	md_get_uint64le(mdp, NULL);	/* fid_volatile */
1080adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* Get Input offset */
1081adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* Get Input count */
1082adee6784SGordon Ross 
1083adee6784SGordon Ross 	error = md_get_uint32le(mdp, &data_out_off);
1084adee6784SGordon Ross 	if (error)
1085adee6784SGordon Ross 		goto out;
1086adee6784SGordon Ross 	error = md_get_uint32le(mdp, &data_out_len);
1087adee6784SGordon Ross 	if (error)
1088adee6784SGordon Ross 		goto out;
1089adee6784SGordon Ross 
1090adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* Flags */
1091adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* reserved */
1092adee6784SGordon Ross 
1093adee6784SGordon Ross 	/*
1094adee6784SGordon Ross 	 * If the caller wants the ioctl output data, parse.
1095adee6784SGordon Ross 	 * Current offset is: SMB2_HDRLEN + 48
1096adee6784SGordon Ross 	 * Always return the received length.
1097adee6784SGordon Ross 	 */
1098adee6784SGordon Ross 	*data_out_sz = data_out_len;
1099adee6784SGordon Ross 	if (data_out_len != 0) {
1100adee6784SGordon Ross 		int skip = (int)data_out_off - (SMB2_HDRLEN + 48);
1101adee6784SGordon Ross 		if (skip < 0) {
1102adee6784SGordon Ross 			error = EBADRPC;
1103adee6784SGordon Ross 			goto out;
1104adee6784SGordon Ross 		}
1105adee6784SGordon Ross 		if (skip > 0) {
1106adee6784SGordon Ross 			md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1107adee6784SGordon Ross 		}
1108adee6784SGordon Ross 		if (data_out != NULL) {
1109adee6784SGordon Ross 			mblk_t *m = NULL;
1110adee6784SGordon Ross 			error = md_get_mbuf(mdp, data_out_len, &m);
1111adee6784SGordon Ross 			if (error)
1112adee6784SGordon Ross 				goto out;
1113adee6784SGordon Ross 			md_initm(data_out, m);
1114adee6784SGordon Ross 		}
1115adee6784SGordon Ross 	}
1116adee6784SGordon Ross 
1117adee6784SGordon Ross out:
1118adee6784SGordon Ross 	smb_rq_done(rqp);
1119adee6784SGordon Ross 
1120adee6784SGordon Ross 	return (error);
1121adee6784SGordon Ross }
1122adee6784SGordon Ross 
1123adee6784SGordon Ross int
smb2_smb_read(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1124adee6784SGordon Ross smb2_smb_read(smb_fh_t *fhp, uint32_t *lenp,
1125adee6784SGordon Ross 	uio_t *uiop, smb_cred_t *scred, int timo)
1126adee6784SGordon Ross {
1127adee6784SGordon Ross 	struct smb_share *ssp = FHTOSS(fhp);
1128adee6784SGordon Ross 	struct smb_rq *rqp;
1129adee6784SGordon Ross 	struct mbchain *mbp;
1130adee6784SGordon Ross 	struct mdchain *mdp;
1131adee6784SGordon Ross 	int error;
1132adee6784SGordon Ross 	uint64_t off64 = uiop->uio_loffset;
1133adee6784SGordon Ross 	uint32_t rlen;
1134adee6784SGordon Ross 	uint16_t length = 0;
1135adee6784SGordon Ross 	uint8_t data_offset;
1136adee6784SGordon Ross 
1137adee6784SGordon Ross 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_READ, scred, &rqp);
1138adee6784SGordon Ross 	if (error)
1139adee6784SGordon Ross 		return (error);
1140adee6784SGordon Ross 
1141adee6784SGordon Ross 	/*
1142adee6784SGordon Ross 	 * Build the SMB 2 Read Request
1143adee6784SGordon Ross 	 */
1144adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
1145adee6784SGordon Ross 	mb_put_uint16le(mbp, 49);		/* Struct size */
1146adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);		/* Padding and Reserved */
1147adee6784SGordon Ross 
1148adee6784SGordon Ross 	mb_put_uint32le(mbp, *lenp);		/* Length of read */
1149adee6784SGordon Ross 	mb_put_uint64le(mbp, off64);		/* Offset */
1150adee6784SGordon Ross 
1151adee6784SGordon Ross 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1152adee6784SGordon Ross 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1153adee6784SGordon Ross 
1154adee6784SGordon Ross 	mb_put_uint32le(mbp, 1);	/* MinCount */
1155adee6784SGordon Ross 					/* (only indicates blocking) */
1156adee6784SGordon Ross 
1157adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);	/* Channel */
1158adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);	/* Remaining */
1159adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);	/* Channel offset/len */
1160adee6784SGordon Ross 	mb_put_uint8(mbp, 0);		/* data "blob" (pad) */
1161adee6784SGordon Ross 
1162adee6784SGordon Ross 	if (timo == 0)
1163adee6784SGordon Ross 		timo = smb2_timo_read;
1164adee6784SGordon Ross 	error = smb2_rq_simple_timed(rqp, timo);
1165adee6784SGordon Ross 	if (error)
1166adee6784SGordon Ross 		goto out;
1167adee6784SGordon Ross 
1168adee6784SGordon Ross 	/*
1169adee6784SGordon Ross 	 * Parse SMB 2 Read Response
1170adee6784SGordon Ross 	 */
1171adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
1172adee6784SGordon Ross 
1173adee6784SGordon Ross 	/* Check structure size is 17 */
1174adee6784SGordon Ross 	md_get_uint16le(mdp, &length);
1175adee6784SGordon Ross 	if (length != 17) {
1176adee6784SGordon Ross 		error = EBADRPC;
1177adee6784SGordon Ross 		goto out;
1178adee6784SGordon Ross 	}
1179adee6784SGordon Ross 	md_get_uint8(mdp, &data_offset);
1180adee6784SGordon Ross 	md_get_uint8(mdp, NULL);		/* reserved */
1181adee6784SGordon Ross 
1182adee6784SGordon Ross 	/* Get Data Length read */
1183adee6784SGordon Ross 	error = md_get_uint32le(mdp, &rlen);
1184adee6784SGordon Ross 	if (error)
1185adee6784SGordon Ross 		goto out;
1186adee6784SGordon Ross 
1187adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* Data Remaining (always 0) */
1188adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);	/* Get Reserved2 (always 0) */
1189adee6784SGordon Ross 
1190adee6784SGordon Ross 	/*
1191adee6784SGordon Ross 	 * Data offset is from the beginning of SMB 2/3 Header
1192adee6784SGordon Ross 	 * Calculate how much further we have to go to get to it.
1193adee6784SGordon Ross 	 */
1194adee6784SGordon Ross 	if (data_offset < (SMB2_HDRLEN + 16)) {
1195adee6784SGordon Ross 		error = EBADRPC;
1196adee6784SGordon Ross 		goto out;
1197adee6784SGordon Ross 	}
1198adee6784SGordon Ross 	if (data_offset > (SMB2_HDRLEN + 16)) {
1199adee6784SGordon Ross 		int skip = data_offset - (SMB2_HDRLEN + 16);
1200adee6784SGordon Ross 		md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
1201adee6784SGordon Ross 	}
1202adee6784SGordon Ross 
1203adee6784SGordon Ross 	/*
1204adee6784SGordon Ross 	 * Get the data
1205adee6784SGordon Ross 	 */
1206adee6784SGordon Ross 	if (rlen == 0) {
1207adee6784SGordon Ross 		*lenp = rlen;
1208adee6784SGordon Ross 		goto out;
1209adee6784SGordon Ross 	}
1210adee6784SGordon Ross 	/* paranoid */
1211adee6784SGordon Ross 	if (rlen > *lenp) {
1212adee6784SGordon Ross 		SMBSDEBUG("bad server! rlen %d, len %d\n",
1213adee6784SGordon Ross 		    rlen, *lenp);
1214adee6784SGordon Ross 		rlen = *lenp;
1215adee6784SGordon Ross 	}
1216adee6784SGordon Ross 
1217adee6784SGordon Ross 	error = md_get_uio(mdp, uiop, rlen);
1218adee6784SGordon Ross 	if (error)
1219adee6784SGordon Ross 		goto out;
1220adee6784SGordon Ross 
1221adee6784SGordon Ross 	/* Success */
1222adee6784SGordon Ross 	*lenp = rlen;
1223adee6784SGordon Ross 
1224adee6784SGordon Ross out:
1225adee6784SGordon Ross 	smb_rq_done(rqp);
1226adee6784SGordon Ross 	return (error);
1227adee6784SGordon Ross }
1228adee6784SGordon Ross 
1229adee6784SGordon Ross int
smb2_smb_write(smb_fh_t * fhp,uint32_t * lenp,uio_t * uiop,smb_cred_t * scred,int timo)1230adee6784SGordon Ross smb2_smb_write(smb_fh_t *fhp, uint32_t *lenp,
1231adee6784SGordon Ross 	uio_t *uiop, smb_cred_t *scred, int timo)
1232adee6784SGordon Ross {
1233adee6784SGordon Ross 	struct smb_share *ssp = FHTOSS(fhp);
1234adee6784SGordon Ross 	struct smb_rq *rqp;
1235adee6784SGordon Ross 	struct mbchain *mbp;
1236adee6784SGordon Ross 	struct mdchain *mdp;
1237adee6784SGordon Ross 	int error;
1238adee6784SGordon Ross 	uint64_t off64 = uiop->uio_loffset;
1239adee6784SGordon Ross 	uint32_t rlen;
1240adee6784SGordon Ross 	uint16_t data_offset;
1241adee6784SGordon Ross 	uint16_t length = 0;
1242adee6784SGordon Ross 
1243adee6784SGordon Ross 	error = smb_rq_alloc(SSTOCP(ssp), SMB2_WRITE, scred, &rqp);
1244adee6784SGordon Ross 	if (error)
1245adee6784SGordon Ross 		return (error);
1246adee6784SGordon Ross 
1247adee6784SGordon Ross 	/*
1248adee6784SGordon Ross 	 * Build the SMB 2 Write Request
1249adee6784SGordon Ross 	 */
1250adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
1251adee6784SGordon Ross 	mb_put_uint16le(mbp, 49);		/* Struct size */
1252adee6784SGordon Ross 	data_offset = SMB2_HDRLEN + 48;
1253adee6784SGordon Ross 	mb_put_uint16le(mbp, data_offset);	/* Data Offset */
1254adee6784SGordon Ross 	mb_put_uint32le(mbp, *lenp);		/* Length of write */
1255adee6784SGordon Ross 	mb_put_uint64le(mbp, off64);		/* Offset */
1256adee6784SGordon Ross 
1257adee6784SGordon Ross 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_persistent);
1258adee6784SGordon Ross 	mb_put_uint64le(mbp, fhp->fh_fid2.fid_volatile);
1259adee6784SGordon Ross 
1260adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Channel */
1261adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Remaining */
1262adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Channel offset/len */
1263adee6784SGordon Ross 	mb_put_uint32le(mbp, 0);		/* Write flags */
1264adee6784SGordon Ross 
1265adee6784SGordon Ross 	error = mb_put_uio(mbp, uiop, *lenp);
1266adee6784SGordon Ross 	if (error)
1267adee6784SGordon Ross 		goto out;
1268adee6784SGordon Ross 
1269adee6784SGordon Ross 	if (timo == 0)
1270adee6784SGordon Ross 		timo = smb2_timo_write;
1271adee6784SGordon Ross 	error = smb2_rq_simple_timed(rqp, timo);
1272adee6784SGordon Ross 	if (error)
1273adee6784SGordon Ross 		goto out;
1274adee6784SGordon Ross 
1275adee6784SGordon Ross 	/*
1276adee6784SGordon Ross 	 * Parse SMB 2/3 Write Response
1277adee6784SGordon Ross 	 */
1278adee6784SGordon Ross 	smb_rq_getreply(rqp, &mdp);
1279adee6784SGordon Ross 
1280adee6784SGordon Ross 	/* Check structure size is 17 */
1281adee6784SGordon Ross 	md_get_uint16le(mdp, &length);
1282adee6784SGordon Ross 	if (length != 17) {
1283adee6784SGordon Ross 		error = EBADRPC;
1284adee6784SGordon Ross 		goto out;
1285adee6784SGordon Ross 	}
1286adee6784SGordon Ross 
1287adee6784SGordon Ross 	md_get_uint16le(mdp, NULL);    /* Get Reserved */
1288adee6784SGordon Ross 
1289adee6784SGordon Ross 	/* Get Data Length written */
1290adee6784SGordon Ross 	error = md_get_uint32le(mdp, &rlen);
1291adee6784SGordon Ross 	if (error)
1292adee6784SGordon Ross 		goto out;
1293adee6784SGordon Ross 
1294adee6784SGordon Ross 	/* Get Data Remaining (always 0) */
1295adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);
1296adee6784SGordon Ross 
1297adee6784SGordon Ross 	/* Get Reserved2 (always 0) */
1298adee6784SGordon Ross 	md_get_uint32le(mdp, NULL);
1299adee6784SGordon Ross 
1300adee6784SGordon Ross 	/* Success */
1301adee6784SGordon Ross 	*lenp = rlen;
1302adee6784SGordon Ross 
1303adee6784SGordon Ross out:
1304adee6784SGordon Ross 	smb_rq_done(rqp);
1305adee6784SGordon Ross 	return (error);
1306adee6784SGordon Ross }
1307adee6784SGordon Ross 
1308adee6784SGordon Ross /*
1309adee6784SGordon Ross  * Note: the IOD calls this, so this request must not wait for
1310adee6784SGordon Ross  * connection state changes, etc. (uses smb2_rq_internal)
1311adee6784SGordon Ross  */
1312adee6784SGordon Ross int
smb2_smb_echo(struct smb_vc * vcp,struct smb_cred * scred,int timo)1313adee6784SGordon Ross smb2_smb_echo(struct smb_vc *vcp, struct smb_cred *scred, int timo)
1314adee6784SGordon Ross {
1315adee6784SGordon Ross 	struct smb_rq *rqp;
1316adee6784SGordon Ross 	struct mbchain *mbp;
1317adee6784SGordon Ross 	int error;
1318adee6784SGordon Ross 
1319adee6784SGordon Ross 	error = smb_rq_alloc(VCTOCP(vcp), SMB2_ECHO, scred, &rqp);
1320adee6784SGordon Ross 	if (error)
1321adee6784SGordon Ross 		return (error);
1322adee6784SGordon Ross 
1323adee6784SGordon Ross 	/*
1324adee6784SGordon Ross 	 * Build the SMB 2 Echo Request
1325adee6784SGordon Ross 	 */
1326adee6784SGordon Ross 	smb_rq_getrequest(rqp, &mbp);
1327adee6784SGordon Ross 	mb_put_uint16le(mbp, 4);		/* Struct size */
1328adee6784SGordon Ross 	mb_put_uint16le(mbp, 0);		/* Reserved */
1329adee6784SGordon Ross 
1330adee6784SGordon Ross 	rqp->sr_flags |= SMBR_NORECONNECT;
1331adee6784SGordon Ross 	error = smb2_rq_internal(rqp, timo);
1332adee6784SGordon Ross 
1333adee6784SGordon Ross 	smb_rq_done(rqp);
1334adee6784SGordon Ross 	return (error);
1335adee6784SGordon Ross }
1336