xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_read.c (revision 55f0a249fd3511728b02627190771a4ce4ddf20e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
26 #include <smbsrv/smb_kproto.h>
27 #include <smbsrv/smb_fsops.h>
28 
29 /*
30  * The maximum number of bytes to return from SMB Core
31  * SmbRead or SmbLockAndRead.
32  */
33 #define	SMB_CORE_READ_MAX	4432
34 
35 /*
36  * The limit in bytes for SmbReadX.
37  */
38 #define	SMB_READX_MAX		0x10000
39 
40 int smb_common_read(smb_request_t *, smb_rw_param_t *);
41 
42 /*
43  * Read bytes from a file or named pipe (SMB Core).
44  *
45  * The requested count specifies the number of bytes desired.  Offset
46  * is limited to 32 bits, so this client request is inappropriate for
47  * files with 64 bit offsets.
48  *
49  * On return, count is the number of bytes actually being returned, which
50  * may be less than the count requested only if a read specifies bytes
51  * beyond the current file size.  In this case only the bytes that exist
52  * are returned.  A read completely beyond the end of file results in a
53  * response of length zero.  This is the only circumstance when a zero
54  * length response is generated.  A count returned which is less than the
55  * count requested is the end of file indicator.
56  */
57 smb_sdrc_t
58 smb_pre_read(smb_request_t *sr)
59 {
60 	smb_rw_param_t *param;
61 	uint32_t off_low;
62 	uint16_t count;
63 	uint16_t remcnt;
64 	int rc;
65 
66 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
67 	sr->arg.rw = param;
68 
69 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
70 	    &count, &off_low, &remcnt);
71 
72 	param->rw_offset = (uint64_t)off_low;
73 	param->rw_count = (uint32_t)count;
74 	param->rw_mincnt = 0;
75 
76 	DTRACE_SMB_START(op__Read, smb_request_t *, sr); /* arg.rw */
77 
78 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
79 }
80 
81 void
82 smb_post_read(smb_request_t *sr)
83 {
84 	DTRACE_SMB_DONE(op__Read, smb_request_t *, sr); /* arg.rw */
85 
86 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
87 }
88 
89 smb_sdrc_t
90 smb_com_read(smb_request_t *sr)
91 {
92 	smb_rw_param_t *param = sr->arg.rw;
93 	uint16_t count;
94 	int rc;
95 
96 	smbsr_lookup_file(sr);
97 	if (sr->fid_ofile == NULL) {
98 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
99 		return (SDRC_ERROR);
100 	}
101 
102 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
103 
104 	if (param->rw_count > SMB_CORE_READ_MAX)
105 		param->rw_count = SMB_CORE_READ_MAX;
106 
107 	if ((rc = smb_common_read(sr, param)) != 0) {
108 		smbsr_errno(sr, rc);
109 		return (SDRC_ERROR);
110 	}
111 
112 	count = (uint16_t)param->rw_count;
113 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
114 	    5, count, VAR_BCC, 0x01, count, &sr->raw_data);
115 
116 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
117 }
118 
119 /*
120  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
121  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
122  * attempt to use it on non-disk shares.
123  *
124  * The requested count specifies the number of bytes desired.  Offset
125  * specifies the offset in the file of the first byte to be locked then
126  * read. Note that offset is limited to 32 bits, so this client request
127  * is inappropriate for files with 64 bit offsets.
128  *
129  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
130  * immediately an error should be returned to the client.  If an error
131  * occurs on the lock, the bytes should not be read.
132  *
133  * On return, count is the number of bytes actually being returned, which
134  * may be less than the count requested only if a read specifies bytes
135  * beyond the current file size.  In this case only the bytes that exist
136  * are returned.  A read completely beyond the end of file results in a
137  * response of length zero.  This is the only circumstance when a zero
138  * length response is generated.  A count returned which is less than the
139  * count requested is the end of file indicator.
140  */
141 smb_sdrc_t
142 smb_pre_lock_and_read(smb_request_t *sr)
143 {
144 	smb_rw_param_t *param;
145 	uint32_t off_low;
146 	uint16_t count;
147 	uint16_t remcnt;
148 	int rc;
149 
150 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
151 	sr->arg.rw = param;
152 
153 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
154 	    &count, &off_low, &remcnt);
155 
156 	param->rw_offset = (uint64_t)off_low;
157 	param->rw_count = (uint32_t)count;
158 	param->rw_mincnt = 0;
159 
160 	DTRACE_SMB_START(op__LockAndRead, smb_request_t *, sr); /* arg.rw */
161 
162 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
163 }
164 
165 void
166 smb_post_lock_and_read(smb_request_t *sr)
167 {
168 	DTRACE_SMB_DONE(op__LockAndRead, smb_request_t *, sr); /* arg.rw */
169 
170 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
171 }
172 
173 smb_sdrc_t
174 smb_com_lock_and_read(smb_request_t *sr)
175 {
176 	smb_rw_param_t *param = sr->arg.rw;
177 	DWORD status;
178 	uint32_t lk_pid;
179 	uint16_t count;
180 	int rc;
181 
182 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
183 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
184 		return (SDRC_ERROR);
185 	}
186 
187 	smbsr_lookup_file(sr);
188 	if (sr->fid_ofile == NULL) {
189 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
190 		return (SDRC_ERROR);
191 	}
192 
193 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
194 
195 	/* Note: SMB1 locking uses 16-bit PIDs. */
196 	lk_pid = sr->smb_pid & 0xFFFF;
197 
198 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
199 	    lk_pid, SMB_LOCK_TYPE_READWRITE, 0);
200 
201 	if (status != NT_STATUS_SUCCESS) {
202 		smb_lock_range_error(sr, status);
203 		return (SDRC_ERROR);
204 	}
205 
206 	if (param->rw_count > SMB_CORE_READ_MAX)
207 		param->rw_count = SMB_CORE_READ_MAX;
208 
209 	if ((rc = smb_common_read(sr, param)) != 0) {
210 		smbsr_errno(sr, rc);
211 		return (SDRC_ERROR);
212 	}
213 
214 	count = (uint16_t)param->rw_count;
215 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
216 	    5, count, VAR_BCC, 0x1, count, &sr->raw_data);
217 
218 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
219 }
220 
221 /*
222  * The SMB_COM_READ_RAW protocol was a negotiated option introduced in
223  * SMB Core Plus to maximize performance when reading a large block
224  * of data from a server.  It's obsolete and no longer supported.
225  *
226  * We keep a handler for it so the dtrace provider can see if
227  * the client tried to use this command.
228  */
229 smb_sdrc_t
230 smb_pre_read_raw(smb_request_t *sr)
231 {
232 	DTRACE_SMB_START(op__ReadRaw, smb_request_t *, sr);
233 	return (SDRC_SUCCESS);
234 }
235 
236 void
237 smb_post_read_raw(smb_request_t *sr)
238 {
239 	DTRACE_SMB_DONE(op__ReadRaw, smb_request_t *, sr);
240 }
241 
242 smb_sdrc_t
243 smb_com_read_raw(smb_request_t *sr)
244 {
245 	smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS,
246 	    ERROR_NOT_SUPPORTED);
247 	return (SDRC_ERROR);
248 }
249 
250 /*
251  * Read bytes from a file (SMB Core).  This request was extended in
252  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
253  * 12 and including additional offset information.
254  *
255  * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
256  * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
257  * than the negotiated buffer size.  If maxcnt_high is 0xFF, it must
258  * be ignored.  Otherwise, maxcnt_high represents the upper 16 bits
259  * of rw_count.
260  */
261 smb_sdrc_t
262 smb_pre_read_andx(smb_request_t *sr)
263 {
264 	smb_rw_param_t *param;
265 	uint32_t off_low;
266 	uint32_t off_high;
267 	uint32_t maxcnt_high;
268 	uint16_t maxcnt_low;
269 	uint16_t mincnt;
270 	uint16_t remcnt;
271 	int rc;
272 
273 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
274 	sr->arg.rw = param;
275 
276 	if (sr->smb_wct == 12) {
277 		rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
278 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
279 		    &remcnt, &off_high);
280 
281 		param->rw_offset = ((uint64_t)off_high << 32) |
282 		    (uint64_t)off_low;
283 
284 		param->rw_count = (uint32_t)maxcnt_low;
285 
286 		if ((sr->session->capabilities & CAP_LARGE_READX) &&
287 		    (maxcnt_high < 0xFF))
288 			param->rw_count |= maxcnt_high << 16;
289 	} else {
290 		rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
291 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
292 		    &remcnt);
293 
294 		param->rw_offset = (uint64_t)off_low;
295 		param->rw_count = (uint32_t)maxcnt_low;
296 	}
297 
298 	param->rw_mincnt = 0;
299 
300 	DTRACE_SMB_START(op__ReadX, smb_request_t *, sr); /* arg.rw */
301 
302 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
303 }
304 
305 void
306 smb_post_read_andx(smb_request_t *sr)
307 {
308 	DTRACE_SMB_DONE(op__ReadX, smb_request_t *, sr); /* arg.rw */
309 
310 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
311 }
312 
313 smb_sdrc_t
314 smb_com_read_andx(smb_request_t *sr)
315 {
316 	smb_rw_param_t *param = sr->arg.rw;
317 	uint16_t datalen_high;
318 	uint16_t datalen_low;
319 	uint16_t data_offset;
320 	uint16_t offset2;
321 	int rc;
322 
323 	smbsr_lookup_file(sr);
324 	if (sr->fid_ofile == NULL) {
325 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
326 		return (SDRC_ERROR);
327 	}
328 
329 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
330 
331 	if (param->rw_count >= SMB_READX_MAX)
332 		param->rw_count = 0;
333 
334 	if ((rc = smb_common_read(sr, param)) != 0) {
335 		smbsr_errno(sr, rc);
336 		return (SDRC_ERROR);
337 	}
338 
339 	datalen_low = param->rw_count & 0xFFFF;
340 	datalen_high = (param->rw_count >> 16) & 0xFF;
341 
342 	/*
343 	 * If this is a secondary command, the data offset
344 	 * includes the previous wct + sizeof(wct).
345 	 */
346 	data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
347 
348 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
349 		data_offset += 60;
350 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
351 
352 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
353 		    12,			/* wct */
354 		    param->rw_andx,	/* secondary andx command */
355 		    offset2,		/* offset to next command */
356 		    0,			/* set to 0 for named pipes */
357 		    datalen_low,	/* data byte count */
358 		    data_offset,	/* offset from start to data */
359 		    datalen_high,	/* data byte count */
360 		    VAR_BCC,		/* BCC marker */
361 		    0x00,		/* padding */
362 		    &sr->raw_data);
363 	} else {
364 		data_offset += 59;
365 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
366 
367 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
368 		    12,			/* wct */
369 		    param->rw_andx,	/* secondary andx command */
370 		    offset2,		/* offset to next command */
371 		    -1,			/* must be -1 for regular files */
372 		    datalen_low,	/* data byte count */
373 		    data_offset,	/* offset from start to data */
374 		    datalen_high,	/* data byte count */
375 		    VAR_BCC,		/* BCC marker */
376 		    &sr->raw_data);
377 	}
378 
379 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
380 }
381 
382 /*
383  * Common function for reading files or IPC/MSRPC named pipes.  All
384  * protocol read functions should lookup the fid before calling this
385  * function.  We can't move the fid lookup here because lock-and-read
386  * requires the fid to do locking before attempting the read.
387  *
388  * Reading from a file does not break oplocks because any need for
389  * breaking before read is handled in open.
390  *
391  * Returns errno values.
392  */
393 int
394 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
395 {
396 	smb_ofile_t *ofile = sr->fid_ofile;
397 	smb_node_t *node;
398 	smb_vdb_t *vdb = &param->rw_vdb;
399 	struct mbuf *top;
400 	int rc;
401 
402 	vdb->vdb_tag = 0;
403 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
404 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
405 	vdb->vdb_uio.uio_resid = param->rw_count;
406 	vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
407 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
408 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
409 
410 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
411 	case STYPE_DISKTREE:
412 		node = ofile->f_node;
413 
414 		if (!smb_node_is_dir(node)) {
415 			rc = smb_lock_range_access(sr, node, param->rw_offset,
416 			    param->rw_count, B_FALSE);
417 			if (rc != NT_STATUS_SUCCESS) {
418 				rc = ERANGE;
419 				break;
420 			}
421 		}
422 
423 		if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
424 		    !(sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)) {
425 			/*
426 			 * SMB_FLAGS2_READ_IF_EXECUTE: permit execute-only
427 			 * reads.
428 			 *
429 			 * Reject request if the file has been opened
430 			 * execute-only and SMB_FLAGS2_READ_IF_EXECUTE is not
431 			 * set.
432 			 */
433 			rc = EACCES;
434 			break;
435 		}
436 
437 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
438 		top = smb_mbuf_allocate(&vdb->vdb_uio);
439 
440 		rc = smb_fsop_read(sr, sr->user_cr, node, ofile,
441 		    &vdb->vdb_uio);
442 
443 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
444 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
445 		MBC_ATTACH_MBUF(&sr->raw_data, top);
446 		break;
447 
448 	case STYPE_IPC:
449 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
450 		top = smb_mbuf_allocate(&vdb->vdb_uio);
451 
452 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
453 
454 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
455 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
456 		MBC_ATTACH_MBUF(&sr->raw_data, top);
457 		break;
458 
459 	default:
460 		rc = EACCES;
461 		break;
462 	}
463 
464 	param->rw_count -= vdb->vdb_uio.uio_resid;
465 
466 	if (rc != 0)
467 		return (rc);
468 
469 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
470 		/*
471 		 * mincnt is only used by read-raw and is typically
472 		 * zero.  If mincnt is greater than zero and the
473 		 * number of bytes read is less than mincnt, tell
474 		 * the client that we read nothing.
475 		 */
476 		param->rw_count = 0;
477 	}
478 
479 	param->rw_offset += param->rw_count;
480 	mutex_enter(&sr->fid_ofile->f_mutex);
481 	ofile->f_seek_pos = param->rw_offset;
482 	mutex_exit(&sr->fid_ofile->f_mutex);
483 	return (rc);
484 }
485