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