xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_read.c (revision 03100a6332bd4edc7a53091fcf7c9a7131bcdaa7)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/syslog.h>
29 #include <smbsrv/smb_incl.h>
30 #include <smbsrv/smb_fsops.h>
31 
32 
33 typedef struct smb_read_param {
34 	uint64_t r_offset;
35 	uint16_t r_count;
36 	uint16_t r_mincnt;
37 } smb_read_param_t;
38 
39 
40 int smb_common_read(struct smb_request *sr, smb_read_param_t *param);
41 
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 int
59 smb_com_read(struct smb_request *sr)
60 {
61 	smb_read_param_t param;
62 	uint32_t off_low;
63 	uint16_t remcnt;
64 	int rc;
65 
66 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
67 	    &param.r_count, &off_low, &remcnt);
68 	if (rc != 0) {
69 		smbsr_decode_error(sr);
70 		/* NOTREACHED */
71 	}
72 
73 	param.r_offset = (uint64_t)off_low;
74 	param.r_mincnt = 0;
75 
76 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
77 	if (sr->fid_ofile == NULL) {
78 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
79 		    ERRDOS, ERRbadfid);
80 		/* NOTREACHED */
81 	}
82 
83 	if ((rc = smb_common_read(sr, &param)) != 0) {
84 		smbsr_raise_errno(sr, rc);
85 		/* NOTREACHED */
86 	}
87 
88 	smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
89 	    5, param.r_count, VAR_BCC, 0x01, param.r_count, &sr->raw_data);
90 
91 	return (SDRC_NORMAL_REPLY);
92 }
93 
94 /*
95  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
96  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
97  * attempt to use it on non-disk shares.
98  *
99  * The requested count specifies the number of bytes desired.  Offset
100  * specifies the offset in the file of the first byte to be locked then
101  * read. Note that offset is limited to 32 bits, so this client request
102  * is inappropriate for files with 64 bit offsets.
103  *
104  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
105  * immediately an error should be returned to the client.  If an error
106  * occurs on the lock, the bytes should not be read.
107  *
108  * On return, count is the number of bytes actually being returned, which
109  * may be less than the count requested only if a read specifies bytes
110  * beyond the current file size.  In this case only the bytes that exist
111  * are returned.  A read completely beyond the end of file results in a
112  * response of length zero.  This is the only circumstance when a zero
113  * length response is generated.  A count returned which is less than the
114  * count requested is the end of file indicator.
115  */
116 int
117 smb_com_lock_and_read(struct smb_request *sr)
118 {
119 	smb_read_param_t param;
120 	uint16_t remcnt;
121 	uint32_t off_low;
122 	DWORD result;
123 	int rc;
124 
125 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
126 		smbsr_raise_error(sr, ERRDOS, ERRnoaccess);
127 		/* NOTREACHED */
128 	}
129 
130 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
131 	    &param.r_count, &off_low, &remcnt);
132 	if (rc != 0) {
133 		smbsr_decode_error(sr);
134 		/* NOTREACHED */
135 	}
136 
137 	param.r_offset = (uint64_t)off_low;
138 	param.r_mincnt = 0;
139 
140 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
141 	if (sr->fid_ofile == NULL) {
142 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
143 		    ERRDOS, ERRbadfid);
144 		/* NOTREACHED */
145 	}
146 
147 	result = smb_lock_range(sr, sr->fid_ofile, param.r_offset,
148 	    (uint64_t)param.r_count, UINT_MAX, SMB_LOCK_TYPE_READWRITE);
149 	if (result != NT_STATUS_SUCCESS) {
150 		smb_lock_range_raise_error(sr, result);
151 	}
152 
153 	if ((rc = smb_common_read(sr, &param)) != 0) {
154 		smbsr_raise_errno(sr, rc);
155 		/* NOTREACHED */
156 	}
157 
158 	smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
159 	    5, param.r_count, VAR_BCC, 0x1, param.r_count, &sr->raw_data);
160 
161 	return (SDRC_NORMAL_REPLY);
162 }
163 
164 /*
165  * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
166  * SMB Core Plus to maximize performance when reading a large block
167  * of data from a server.  This request was extended in LM 0.12 to
168  * support 64-bit offsets; the server can indicate support by setting
169  * CAP_LARGE_FILES in the negotiated capabilities.
170  *
171  * The client must guarantee that there is (and will be) no other request
172  * to the server for the duration of the SMB_COM_READ_RAW, since the
173  * server response has no header or trailer. To help ensure that there
174  * are no interruptions, we block all I/O for the session during read raw.
175  *
176  * If this is the first SMB request received since we sent an oplock break
177  * to this client, we don't know if it's safe to send the raw data because
178  * the requests may have crossed on the wire and the client may have
179  * interpreted the oplock break as part of the raw data. To avoid problems,
180  * we send a zero length session packet, which will force the client to
181  * retry the read.
182  *
183  * Read errors are handled by sending a zero length response.
184  */
185 int
186 smb_com_read_raw(struct smb_request *sr)
187 {
188 	smb_read_param_t	param;
189 	smb_node_t		*node;
190 	uint32_t		off_low;
191 	uint32_t		off_high;
192 	uint32_t		timeout;
193 	int			rc;
194 
195 	switch (sr->session->s_state) {
196 	case SMB_SESSION_STATE_NEGOTIATED:
197 		if (sr->smb_wct == 8) {
198 			rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
199 			    &off_low, &param.r_count, &param.r_mincnt,
200 			    &timeout);
201 			param.r_offset = (uint64_t)off_low;
202 		} else {
203 			rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
204 			    &off_low, &param.r_count, &param.r_mincnt, &timeout,
205 			    &off_high);
206 			param.r_offset = ((uint64_t)off_high << 32) | off_low;
207 		}
208 
209 		if (rc != 0) {
210 			smbsr_decode_error(sr);
211 			/* NOTREACHED */
212 		}
213 
214 		sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
215 		    sr->smb_fid);
216 		if (sr->fid_ofile == NULL) {
217 			smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
218 			    ERRDOS, ERRbadfid);
219 			/* NOTREACHED */
220 		}
221 
222 		rc = smb_common_read(sr, &param);
223 		/*
224 		 * XXX Do we need to handle errors here?  What if we have an
225 		 * access error (either permissions or range lock violations?
226 		 */
227 		if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
228 			node = sr->fid_ofile->f_node;
229 			if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
230 				rc = EAGAIN;
231 			}
232 		}
233 
234 		if (rc != 0) {
235 			(void) smb_session_send(sr->session, 0, NULL);
236 			m_freem(sr->raw_data.chain);
237 			sr->raw_data.chain = 0;
238 		} else {
239 			(void) smb_session_send(sr->session, 0, &sr->raw_data);
240 		}
241 		return (SDRC_NO_REPLY);
242 
243 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
244 		(void) smb_session_send(sr->session, 0, NULL);
245 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
246 		return (SDRC_NO_REPLY);
247 
248 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
249 		ASSERT(0);
250 		return (SDRC_DROP_VC);
251 
252 	case SMB_SESSION_STATE_TERMINATED:
253 		ASSERT(0);
254 		return (SDRC_NO_REPLY);
255 
256 	case SMB_SESSION_STATE_DISCONNECTED:
257 		return (SDRC_NO_REPLY);
258 
259 	case SMB_SESSION_STATE_CONNECTED:
260 	case SMB_SESSION_STATE_ESTABLISHED:
261 	default:
262 		ASSERT(0);
263 		return (SDRC_DROP_VC);
264 	}
265 }
266 
267 /*
268  * Read bytes from a file (SMB Core).  This request was extended in
269  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
270  * 12 and including additional offset information.
271  */
272 int
273 smb_com_read_andx(struct smb_request *sr)
274 {
275 	smb_read_param_t param;
276 	uint32_t off_low;
277 	uint32_t off_high;
278 	uint16_t remcnt;
279 	uint16_t offset2;
280 	uint8_t secondary;
281 	int rc;
282 
283 	if (sr->smb_wct == 12) {
284 		rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &secondary,
285 		    &sr->smb_fid, &off_low, &param.r_count, &remcnt, &off_high);
286 
287 		param.r_offset = ((uint64_t)off_high << 32) | off_low;
288 	} else {
289 		rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &secondary,
290 		    &sr->smb_fid, &off_low, &param.r_count, &remcnt);
291 
292 		param.r_offset = (uint64_t)off_low;
293 	}
294 
295 	if (rc != 0) {
296 		smbsr_decode_error(sr);
297 		/* NOTREACHED */
298 	}
299 
300 	param.r_mincnt = 0;
301 
302 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
303 	if (sr->fid_ofile == NULL) {
304 		smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE,
305 		    ERRDOS, ERRbadfid);
306 		/* NOTREACHED */
307 	}
308 
309 	if ((rc = smb_common_read(sr, &param)) != 0) {
310 		smbsr_raise_errno(sr, rc);
311 		/* NOTREACHED */
312 	}
313 
314 	/*
315 	 * Ensure that the next response offset is zero
316 	 * if there is no secondary command.
317 	 */
318 	offset2 = (secondary == 0xFF) ? 0 : param.r_count + 59;
319 
320 	/*
321 	 * The STYPE_IPC response format is different.
322 	 * The unknown value (2) may be to indicate that it
323 	 * is a follow-up to an earlier RPC transaction.
324 	 */
325 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
326 		smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC",
327 		    12,			/* wct */
328 		    secondary,		/* Secondary andx command */
329 		    offset2,		/* offset to next */
330 		    0,			/* must be 0 */
331 		    param.r_count,	/* data byte count */
332 		    60,			/* Offset from start to data */
333 		    VAR_BCC,		/* BCC marker */
334 		    0x02,		/* unknown */
335 		    &sr->raw_data);
336 	} else {
337 		smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC",
338 		    12,			/* wct */
339 		    secondary,		/* Secondary andx command */
340 		    offset2,		/* offset to next */
341 		    -1,			/* must be -1 */
342 		    param.r_count,	/* data byte count */
343 		    59,			/* Offset from start to data */
344 		    VAR_BCC,		/* BCC marker */
345 		    &sr->raw_data);
346 	}
347 
348 	return (SDRC_NORMAL_REPLY);
349 }
350 
351 /*
352  * Common function for reading files or IPC/MSRPC named pipes.  All
353  * protocol read functions should lookup the fid before calling this
354  * function.  We can't move the fid lookup here because lock-and-read
355  * requires the fid to do locking before attempting the read.
356  *
357  * Returns errno values.
358  */
359 int
360 smb_common_read(struct smb_request *sr, smb_read_param_t *param)
361 {
362 	smb_ofile_t *ofile = sr->fid_ofile;
363 	smb_node_t *node;
364 	struct vardata_block *vdb;
365 	struct mbuf *top;
366 	int rc;
367 
368 	vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
369 	vdb->tag = 0;
370 	vdb->uio.uio_iov = &vdb->iovec[0];
371 	vdb->uio.uio_iovcnt = MAX_IOVEC;
372 	vdb->uio.uio_resid = param->r_count;
373 	vdb->uio.uio_loffset = (offset_t)param->r_offset;
374 	vdb->uio.uio_segflg = UIO_SYSSPACE;
375 
376 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
377 	case STYPE_DISKTREE:
378 		node = ofile->f_node;
379 
380 		if (node->attr.sa_vattr.va_type != VDIR) {
381 			rc = smb_lock_range_access(sr, node, param->r_offset,
382 			    param->r_count, FILE_READ_DATA);
383 			if (rc != NT_STATUS_SUCCESS) {
384 				rc = ERANGE;
385 				break;
386 			}
387 		}
388 
389 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
390 
391 		sr->raw_data.max_bytes = vdb->uio.uio_resid;
392 		top = smb_mbuf_allocate(&vdb->uio);
393 
394 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio,
395 		    &node->attr);
396 
397 		sr->raw_data.max_bytes -= vdb->uio.uio_resid;
398 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
399 		MBC_ATTACH_MBUF(&sr->raw_data, top);
400 		break;
401 
402 	case STYPE_IPC:
403 		rc = smb_rpc_read(sr, &vdb->uio);
404 		break;
405 
406 	default:
407 		rc = EACCES;
408 		break;
409 	}
410 
411 	param->r_count -= vdb->uio.uio_resid;
412 	kmem_free(vdb, sizeof (struct vardata_block));
413 
414 	if (rc != 0)
415 		return (rc);
416 
417 	if (param->r_mincnt != 0 && param->r_count < param->r_mincnt) {
418 		/*
419 		 * mincnt is only used by read-raw and is typically
420 		 * zero.  If mincnt is greater than zero and the
421 		 * number of bytes read is less than mincnt, tell
422 		 * the client that we read nothing.
423 		 */
424 		param->r_count = 0;
425 	}
426 
427 	param->r_offset += param->r_count;
428 	mutex_enter(&sr->fid_ofile->f_mutex);
429 	ofile->f_seek_pos = param->r_offset;
430 	mutex_exit(&sr->fid_ofile->f_mutex);
431 	return (rc);
432 }
433 
434 /*
435  * The Read Block Multiplexed protocol is used to maximize performance
436  * when reading a large block of data from server to client while still
437  * allowing other operations to take place between the client and server
438  * in parallel.
439  *
440  * The mpx sub protocol is not supported because we support only
441  * connection oriented transports and NT supports SMB_COM_READ_MPX
442  * only over connectionless transports.
443  */
444 /*ARGSUSED*/
445 int
446 smb_com_read_mpx(struct smb_request *sr)
447 {
448 	return (SDRC_UNIMPLEMENTED);
449 }
450 
451 /*ARGSUSED*/
452 int
453 smb_com_read_mpx_secondary(struct smb_request *sr)
454 {
455 	return (SDRC_UNIMPLEMENTED);
456 }
457