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