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