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