xref: /titanic_41/usr/src/uts/common/fs/smbsrv/smb_read.c (revision bbb1277b6ec1b0daad4e3ed1a2b891d3e2ece2eb)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <smbsrv/smb_kproto.h>
27 #include <smbsrv/smb_fsops.h>
28 
29 
30 /*
31  * The maximum number of bytes to return from SMB Core
32  * SmbRead or SmbLockAndRead.
33  */
34 #define	SMB_CORE_READ_MAX	4432
35 
36 /*
37  * The limit in bytes for SmbReadX.
38  */
39 #define	SMB_READX_MAX		0x10000
40 
41 int smb_common_read(smb_request_t *, smb_rw_param_t *);
42 
43 /*
44  * Read bytes from a file or named pipe (SMB Core).
45  *
46  * The requested count specifies the number of bytes desired.  Offset
47  * is limited to 32 bits, so this client request is inappropriate for
48  * files with 64 bit offsets.
49  *
50  * On return, count is the number of bytes actually being returned, which
51  * may be less than the count requested only if a read specifies bytes
52  * beyond the current file size.  In this case only the bytes that exist
53  * are returned.  A read completely beyond the end of file results in a
54  * response of length zero.  This is the only circumstance when a zero
55  * length response is generated.  A count returned which is less than the
56  * count requested is the end of file indicator.
57  */
58 smb_sdrc_t
59 smb_pre_read(smb_request_t *sr)
60 {
61 	smb_rw_param_t *param;
62 	uint32_t off_low;
63 	uint16_t count;
64 	uint16_t remcnt;
65 	int rc;
66 
67 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
68 	sr->arg.rw = param;
69 
70 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
71 	    &count, &off_low, &remcnt);
72 
73 	param->rw_offset = (uint64_t)off_low;
74 	param->rw_count = (uint32_t)count;
75 	param->rw_mincnt = 0;
76 
77 	DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
78 	    smb_rw_param_t *, param);
79 
80 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
81 }
82 
83 void
84 smb_post_read(smb_request_t *sr)
85 {
86 	DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
87 	    smb_rw_param_t *, sr->arg.rw);
88 
89 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
90 }
91 
92 smb_sdrc_t
93 smb_com_read(smb_request_t *sr)
94 {
95 	smb_rw_param_t *param = sr->arg.rw;
96 	uint16_t count;
97 	int rc;
98 
99 	smbsr_lookup_file(sr);
100 	if (sr->fid_ofile == NULL) {
101 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
102 		return (SDRC_ERROR);
103 	}
104 
105 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
106 
107 	if (param->rw_count > SMB_CORE_READ_MAX)
108 		param->rw_count = SMB_CORE_READ_MAX;
109 
110 	if ((rc = smb_common_read(sr, param)) != 0) {
111 		smbsr_errno(sr, rc);
112 		return (SDRC_ERROR);
113 	}
114 
115 	count = (uint16_t)param->rw_count;
116 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
117 	    5, count, VAR_BCC, 0x01, count, &sr->raw_data);
118 
119 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
120 }
121 
122 /*
123  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
124  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
125  * attempt to use it on non-disk shares.
126  *
127  * The requested count specifies the number of bytes desired.  Offset
128  * specifies the offset in the file of the first byte to be locked then
129  * read. Note that offset is limited to 32 bits, so this client request
130  * is inappropriate for files with 64 bit offsets.
131  *
132  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
133  * immediately an error should be returned to the client.  If an error
134  * occurs on the lock, the bytes should not be read.
135  *
136  * On return, count is the number of bytes actually being returned, which
137  * may be less than the count requested only if a read specifies bytes
138  * beyond the current file size.  In this case only the bytes that exist
139  * are returned.  A read completely beyond the end of file results in a
140  * response of length zero.  This is the only circumstance when a zero
141  * length response is generated.  A count returned which is less than the
142  * count requested is the end of file indicator.
143  */
144 smb_sdrc_t
145 smb_pre_lock_and_read(smb_request_t *sr)
146 {
147 	smb_rw_param_t *param;
148 	uint32_t off_low;
149 	uint16_t count;
150 	uint16_t remcnt;
151 	int rc;
152 
153 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
154 	sr->arg.rw = param;
155 
156 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
157 	    &count, &off_low, &remcnt);
158 
159 	param->rw_offset = (uint64_t)off_low;
160 	param->rw_count = (uint32_t)count;
161 	param->rw_mincnt = 0;
162 
163 	DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
164 	    smb_rw_param_t *, param);
165 
166 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
167 }
168 
169 void
170 smb_post_lock_and_read(smb_request_t *sr)
171 {
172 	DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
173 	    smb_rw_param_t *, sr->arg.rw);
174 
175 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
176 }
177 
178 smb_sdrc_t
179 smb_com_lock_and_read(smb_request_t *sr)
180 {
181 	smb_rw_param_t *param = sr->arg.rw;
182 	DWORD status;
183 	uint16_t count;
184 	int rc;
185 
186 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
187 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
188 		return (SDRC_ERROR);
189 	}
190 
191 	smbsr_lookup_file(sr);
192 	if (sr->fid_ofile == NULL) {
193 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
194 		return (SDRC_ERROR);
195 	}
196 
197 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
198 
199 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
200 	    0, SMB_LOCK_TYPE_READWRITE);
201 
202 	if (status != NT_STATUS_SUCCESS) {
203 		smb_lock_range_error(sr, status);
204 		return (SDRC_ERROR);
205 	}
206 
207 	if (param->rw_count > SMB_CORE_READ_MAX)
208 		param->rw_count = SMB_CORE_READ_MAX;
209 
210 	if ((rc = smb_common_read(sr, param)) != 0) {
211 		smbsr_errno(sr, rc);
212 		return (SDRC_ERROR);
213 	}
214 
215 	count = (uint16_t)param->rw_count;
216 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
217 	    5, count, VAR_BCC, 0x1, count, &sr->raw_data);
218 
219 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
220 }
221 
222 /*
223  * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
224  * SMB Core Plus to maximize performance when reading a large block
225  * of data from a server.  This request was extended in LM 0.12 to
226  * support 64-bit offsets; the server can indicate support by setting
227  * CAP_LARGE_FILES in the negotiated capabilities.
228  *
229  * The client must guarantee that there is (and will be) no other request
230  * to the server for the duration of the SMB_COM_READ_RAW, since the
231  * server response has no header or trailer. To help ensure that there
232  * are no interruptions, we block all I/O for the session during read raw.
233  *
234  * If this is the first SMB request received since we sent an oplock break
235  * to this client, we don't know if it's safe to send the raw data because
236  * the requests may have crossed on the wire and the client may have
237  * interpreted the oplock break as part of the raw data. To avoid problems,
238  * we send a zero length session packet, which will force the client to
239  * retry the read.
240  *
241  * Do not return errors from SmbReadRaw.
242  * Read errors are handled by sending a zero length response.
243  */
244 smb_sdrc_t
245 smb_pre_read_raw(smb_request_t *sr)
246 {
247 	smb_rw_param_t *param;
248 	uint32_t off_low;
249 	uint32_t off_high;
250 	uint32_t timeout;
251 	uint16_t count;
252 	int rc;
253 
254 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
255 	sr->arg.rw = param;
256 
257 	if (sr->smb_wct == 8) {
258 		rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
259 		    &off_low, &count, &param->rw_mincnt, &timeout);
260 		if (rc == 0) {
261 			param->rw_offset = (uint64_t)off_low;
262 			param->rw_count = (uint32_t)count;
263 		}
264 	} else {
265 		rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
266 		    &off_low, &count, &param->rw_mincnt, &timeout, &off_high);
267 		if (rc == 0) {
268 			param->rw_offset = ((uint64_t)off_high << 32) | off_low;
269 			param->rw_count = (uint32_t)count;
270 		}
271 	}
272 
273 	DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr,
274 	    smb_rw_param_t *, param);
275 
276 	smb_rwx_rwenter(&sr->session->s_lock, RW_WRITER);
277 	return (SDRC_SUCCESS);
278 }
279 
280 void
281 smb_post_read_raw(smb_request_t *sr)
282 {
283 	mbuf_chain_t	*mbc;
284 
285 	if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) {
286 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
287 
288 		while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) !=
289 		    NULL) {
290 			SMB_MBC_VALID(mbc);
291 			list_remove(&sr->session->s_oplock_brkreqs, mbc);
292 			(void) smb_session_send(sr->session, 0, mbc);
293 			smb_mbc_free(mbc);
294 		}
295 	}
296 
297 	DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr,
298 	    smb_rw_param_t *, sr->arg.rw);
299 
300 	smb_rwx_rwexit(&sr->session->s_lock);
301 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
302 }
303 
304 smb_sdrc_t
305 smb_com_read_raw(smb_request_t *sr)
306 {
307 	smb_rw_param_t *param = sr->arg.rw;
308 
309 	switch (sr->session->s_state) {
310 	case SMB_SESSION_STATE_NEGOTIATED:
311 		sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE;
312 		break;
313 
314 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
315 		(void) smb_session_send(sr->session, 0, NULL);
316 		return (SDRC_NO_REPLY);
317 
318 	case SMB_SESSION_STATE_TERMINATED:
319 	case SMB_SESSION_STATE_DISCONNECTED:
320 		return (SDRC_NO_REPLY);
321 
322 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
323 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
324 		return (SDRC_DROP_VC);
325 
326 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
327 	case SMB_SESSION_STATE_CONNECTED:
328 	case SMB_SESSION_STATE_ESTABLISHED:
329 	default:
330 		return (SDRC_DROP_VC);
331 	}
332 
333 	smbsr_lookup_file(sr);
334 	if (sr->fid_ofile == NULL) {
335 		(void) smb_session_send(sr->session, 0, NULL);
336 		return (SDRC_NO_REPLY);
337 	}
338 
339 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
340 
341 	if (param->rw_mincnt > param->rw_count)
342 		param->rw_mincnt = 0;
343 
344 	if (smb_common_read(sr, param) != 0) {
345 		(void) smb_session_send(sr->session, 0, NULL);
346 		m_freem(sr->raw_data.chain);
347 		sr->raw_data.chain = NULL;
348 	} else {
349 		(void) smb_session_send(sr->session, 0, &sr->raw_data);
350 	}
351 
352 	return (SDRC_NO_REPLY);
353 }
354 
355 /*
356  * Read bytes from a file (SMB Core).  This request was extended in
357  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
358  * 12 and including additional offset information.
359  *
360  * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
361  * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
362  * than the negotiated buffer size.  If maxcnt_high is 0xFF, it must
363  * be ignored.  Otherwise, maxcnt_high represents the upper 16 bits
364  * of rw_count.
365  */
366 smb_sdrc_t
367 smb_pre_read_andx(smb_request_t *sr)
368 {
369 	smb_rw_param_t *param;
370 	uint32_t off_low;
371 	uint32_t off_high;
372 	uint32_t maxcnt_high;
373 	uint16_t maxcnt_low;
374 	uint16_t mincnt;
375 	uint16_t remcnt;
376 	int rc;
377 
378 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
379 	sr->arg.rw = param;
380 
381 	if (sr->smb_wct == 12) {
382 		rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
383 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
384 		    &remcnt, &off_high);
385 
386 		param->rw_offset = ((uint64_t)off_high << 32) |
387 		    (uint64_t)off_low;
388 
389 		param->rw_count = (uint32_t)maxcnt_low;
390 
391 		if ((sr->session->capabilities & CAP_LARGE_READX) &&
392 		    (maxcnt_high < 0xFF))
393 			param->rw_count |= maxcnt_high << 16;
394 	} else {
395 		rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
396 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
397 		    &remcnt);
398 
399 		param->rw_offset = (uint64_t)off_low;
400 		param->rw_count = (uint32_t)maxcnt_low;
401 	}
402 
403 	param->rw_mincnt = 0;
404 
405 	DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
406 	    smb_rw_param_t *, param);
407 
408 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
409 }
410 
411 void
412 smb_post_read_andx(smb_request_t *sr)
413 {
414 	DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
415 	    smb_rw_param_t *, sr->arg.rw);
416 
417 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
418 }
419 
420 smb_sdrc_t
421 smb_com_read_andx(smb_request_t *sr)
422 {
423 	smb_rw_param_t *param = sr->arg.rw;
424 	uint16_t datalen_high;
425 	uint16_t datalen_low;
426 	uint16_t data_offset;
427 	uint16_t offset2;
428 	int rc;
429 
430 	smbsr_lookup_file(sr);
431 	if (sr->fid_ofile == NULL) {
432 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
433 		return (SDRC_ERROR);
434 	}
435 
436 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
437 
438 	if (param->rw_count >= SMB_READX_MAX)
439 		param->rw_count = 0;
440 
441 	if ((rc = smb_common_read(sr, param)) != 0) {
442 		smbsr_errno(sr, rc);
443 		return (SDRC_ERROR);
444 	}
445 
446 	datalen_low = param->rw_count & 0xFFFF;
447 	datalen_high = (param->rw_count >> 16) & 0xFF;
448 
449 	/*
450 	 * If this is a secondary command, the data offset
451 	 * includes the previous wct + sizeof(wct).
452 	 */
453 	data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
454 
455 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
456 		data_offset += 60;
457 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
458 
459 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
460 		    12,			/* wct */
461 		    param->rw_andx,	/* secondary andx command */
462 		    offset2,		/* offset to next command */
463 		    0,			/* set to 0 for named pipes */
464 		    datalen_low,	/* data byte count */
465 		    data_offset,	/* offset from start to data */
466 		    datalen_high,	/* data byte count */
467 		    VAR_BCC,		/* BCC marker */
468 		    0x00,		/* padding */
469 		    &sr->raw_data);
470 	} else {
471 		data_offset += 59;
472 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
473 
474 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
475 		    12,			/* wct */
476 		    param->rw_andx,	/* secondary andx command */
477 		    offset2,		/* offset to next command */
478 		    -1,			/* must be -1 for regular files */
479 		    datalen_low,	/* data byte count */
480 		    data_offset,	/* offset from start to data */
481 		    datalen_high,	/* data byte count */
482 		    VAR_BCC,		/* BCC marker */
483 		    &sr->raw_data);
484 	}
485 
486 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
487 }
488 
489 /*
490  * Common function for reading files or IPC/MSRPC named pipes.  All
491  * protocol read functions should lookup the fid before calling this
492  * function.  We can't move the fid lookup here because lock-and-read
493  * requires the fid to do locking before attempting the read.
494  *
495  * Returns errno values.
496  */
497 int
498 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
499 {
500 	smb_ofile_t *ofile = sr->fid_ofile;
501 	smb_node_t *node;
502 	smb_vdb_t *vdb = &param->rw_vdb;
503 	struct mbuf *top;
504 	int rc;
505 
506 	vdb->vdb_tag = 0;
507 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
508 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
509 	vdb->vdb_uio.uio_resid = param->rw_count;
510 	vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
511 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
512 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
513 
514 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
515 	case STYPE_DISKTREE:
516 		node = ofile->f_node;
517 
518 		if (!smb_node_is_dir(node)) {
519 			rc = smb_lock_range_access(sr, node, param->rw_offset,
520 			    param->rw_count, B_FALSE);
521 			if (rc != NT_STATUS_SUCCESS) {
522 				rc = ERANGE;
523 				break;
524 			}
525 		}
526 
527 		if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
528 		    !(sr->smb_flg2 & SMB_FLAGS2_PAGING_IO)) {
529 			/*
530 			 * SMB_FLAGS2_PAGING_IO: permit execute-only reads.
531 			 *
532 			 * Reject request if the file has been opened
533 			 * execute-only and SMB_FLAGS2_PAGING_IO is not set.
534 			 */
535 			rc = EACCES;
536 			break;
537 		}
538 
539 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
540 		top = smb_mbuf_allocate(&vdb->vdb_uio);
541 
542 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio);
543 
544 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
545 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
546 		MBC_ATTACH_MBUF(&sr->raw_data, top);
547 		break;
548 
549 	case STYPE_IPC:
550 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
551 		break;
552 
553 	default:
554 		rc = EACCES;
555 		break;
556 	}
557 
558 	param->rw_count -= vdb->vdb_uio.uio_resid;
559 
560 	if (rc != 0)
561 		return (rc);
562 
563 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
564 		/*
565 		 * mincnt is only used by read-raw and is typically
566 		 * zero.  If mincnt is greater than zero and the
567 		 * number of bytes read is less than mincnt, tell
568 		 * the client that we read nothing.
569 		 */
570 		param->rw_count = 0;
571 	}
572 
573 	param->rw_offset += param->rw_count;
574 	mutex_enter(&sr->fid_ofile->f_mutex);
575 	ofile->f_seek_pos = param->rw_offset;
576 	mutex_exit(&sr->fid_ofile->f_mutex);
577 	return (rc);
578 }
579