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