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 * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 #include <smbsrv/smb_kproto.h> 27 #include <smbsrv/smb_fsops.h> 28 29 /* 30 * The maximum number of bytes to return from SMB Core 31 * SmbRead or SmbLockAndRead. 32 */ 33 #define SMB_CORE_READ_MAX 4432 34 35 /* 36 * The limit in bytes for SmbReadX. 37 */ 38 #define SMB_READX_MAX 0x10000 39 40 int smb_common_read(smb_request_t *, smb_rw_param_t *); 41 42 /* 43 * Read bytes from a file or named pipe (SMB Core). 44 * 45 * The requested count specifies the number of bytes desired. Offset 46 * is limited to 32 bits, so this client request is inappropriate for 47 * files with 64 bit offsets. 48 * 49 * On return, count is the number of bytes actually being returned, which 50 * may be less than the count requested only if a read specifies bytes 51 * beyond the current file size. In this case only the bytes that exist 52 * are returned. A read completely beyond the end of file results in a 53 * response of length zero. This is the only circumstance when a zero 54 * length response is generated. A count returned which is less than the 55 * count requested is the end of file indicator. 56 */ 57 smb_sdrc_t 58 smb_pre_read(smb_request_t *sr) 59 { 60 smb_rw_param_t *param; 61 uint32_t off_low; 62 uint16_t count; 63 uint16_t remcnt; 64 int rc; 65 66 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 67 sr->arg.rw = param; 68 69 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 70 &count, &off_low, &remcnt); 71 72 param->rw_offset = (uint64_t)off_low; 73 param->rw_count = (uint32_t)count; 74 param->rw_mincnt = 0; 75 76 DTRACE_SMB_START(op__Read, smb_request_t *, sr); /* arg.rw */ 77 78 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 79 } 80 81 void 82 smb_post_read(smb_request_t *sr) 83 { 84 DTRACE_SMB_DONE(op__Read, smb_request_t *, sr); /* arg.rw */ 85 86 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 87 } 88 89 smb_sdrc_t 90 smb_com_read(smb_request_t *sr) 91 { 92 smb_rw_param_t *param = sr->arg.rw; 93 uint16_t count; 94 int rc; 95 96 smbsr_lookup_file(sr); 97 if (sr->fid_ofile == NULL) { 98 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 99 return (SDRC_ERROR); 100 } 101 102 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 103 104 if (param->rw_count > SMB_CORE_READ_MAX) 105 param->rw_count = SMB_CORE_READ_MAX; 106 107 if ((rc = smb_common_read(sr, param)) != 0) { 108 smbsr_errno(sr, rc); 109 return (SDRC_ERROR); 110 } 111 112 count = (uint16_t)param->rw_count; 113 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 114 5, count, VAR_BCC, 0x01, count, &sr->raw_data); 115 116 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 117 } 118 119 /* 120 * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/ 121 * SmbLockAndWrite sub-dialect is only valid on disk files: reject any 122 * attempt to use it on non-disk shares. 123 * 124 * The requested count specifies the number of bytes desired. Offset 125 * specifies the offset in the file of the first byte to be locked then 126 * read. Note that offset is limited to 32 bits, so this client request 127 * is inappropriate for files with 64 bit offsets. 128 * 129 * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted 130 * immediately an error should be returned to the client. If an error 131 * occurs on the lock, the bytes should not be read. 132 * 133 * On return, count is the number of bytes actually being returned, which 134 * may be less than the count requested only if a read specifies bytes 135 * beyond the current file size. In this case only the bytes that exist 136 * are returned. A read completely beyond the end of file results in a 137 * response of length zero. This is the only circumstance when a zero 138 * length response is generated. A count returned which is less than the 139 * count requested is the end of file indicator. 140 */ 141 smb_sdrc_t 142 smb_pre_lock_and_read(smb_request_t *sr) 143 { 144 smb_rw_param_t *param; 145 uint32_t off_low; 146 uint16_t count; 147 uint16_t remcnt; 148 int rc; 149 150 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 151 sr->arg.rw = param; 152 153 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 154 &count, &off_low, &remcnt); 155 156 param->rw_offset = (uint64_t)off_low; 157 param->rw_count = (uint32_t)count; 158 param->rw_mincnt = 0; 159 160 DTRACE_SMB_START(op__LockAndRead, smb_request_t *, sr); /* arg.rw */ 161 162 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 163 } 164 165 void 166 smb_post_lock_and_read(smb_request_t *sr) 167 { 168 DTRACE_SMB_DONE(op__LockAndRead, smb_request_t *, sr); /* arg.rw */ 169 170 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 171 } 172 173 smb_sdrc_t 174 smb_com_lock_and_read(smb_request_t *sr) 175 { 176 smb_rw_param_t *param = sr->arg.rw; 177 DWORD status; 178 uint32_t lk_pid; 179 uint16_t count; 180 int rc; 181 182 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 183 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 184 return (SDRC_ERROR); 185 } 186 187 smbsr_lookup_file(sr); 188 if (sr->fid_ofile == NULL) { 189 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 190 return (SDRC_ERROR); 191 } 192 193 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 194 195 /* Note: SMB1 locking uses 16-bit PIDs. */ 196 lk_pid = sr->smb_pid & 0xFFFF; 197 198 status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count, 199 lk_pid, SMB_LOCK_TYPE_READWRITE, 0); 200 201 if (status != NT_STATUS_SUCCESS) { 202 smb_lock_range_error(sr, status); 203 return (SDRC_ERROR); 204 } 205 206 if (param->rw_count > SMB_CORE_READ_MAX) 207 param->rw_count = SMB_CORE_READ_MAX; 208 209 if ((rc = smb_common_read(sr, param)) != 0) { 210 smbsr_errno(sr, rc); 211 return (SDRC_ERROR); 212 } 213 214 count = (uint16_t)param->rw_count; 215 rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 216 5, count, VAR_BCC, 0x1, count, &sr->raw_data); 217 218 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 219 } 220 221 /* 222 * The SMB_COM_READ_RAW protocol was a negotiated option introduced in 223 * SMB Core Plus to maximize performance when reading a large block 224 * of data from a server. It's obsolete and no longer supported. 225 * 226 * We keep a handler for it so the dtrace provider can see if 227 * the client tried to use this command. 228 */ 229 smb_sdrc_t 230 smb_pre_read_raw(smb_request_t *sr) 231 { 232 DTRACE_SMB_START(op__ReadRaw, smb_request_t *, sr); 233 return (SDRC_SUCCESS); 234 } 235 236 void 237 smb_post_read_raw(smb_request_t *sr) 238 { 239 DTRACE_SMB_DONE(op__ReadRaw, smb_request_t *, sr); 240 } 241 242 smb_sdrc_t 243 smb_com_read_raw(smb_request_t *sr) 244 { 245 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS, 246 ERROR_NOT_SUPPORTED); 247 return (SDRC_ERROR); 248 } 249 250 /* 251 * Read bytes from a file (SMB Core). This request was extended in 252 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 253 * 12 and including additional offset information. 254 * 255 * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4: 256 * If wct is 12 and CAP_LARGE_READX is set, the count may be larger 257 * than the negotiated buffer size. If maxcnt_high is 0xFF, it must 258 * be ignored. Otherwise, maxcnt_high represents the upper 16 bits 259 * of rw_count. 260 */ 261 smb_sdrc_t 262 smb_pre_read_andx(smb_request_t *sr) 263 { 264 smb_rw_param_t *param; 265 uint32_t off_low; 266 uint32_t off_high; 267 uint32_t maxcnt_high; 268 uint16_t maxcnt_low; 269 uint16_t mincnt; 270 uint16_t remcnt; 271 int rc; 272 273 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 274 sr->arg.rw = param; 275 276 if (sr->smb_wct == 12) { 277 rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", ¶m->rw_andx, 278 &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high, 279 &remcnt, &off_high); 280 281 param->rw_offset = ((uint64_t)off_high << 32) | 282 (uint64_t)off_low; 283 284 param->rw_count = (uint32_t)maxcnt_low; 285 286 if ((sr->session->capabilities & CAP_LARGE_READX) && 287 (maxcnt_high < 0xFF)) 288 param->rw_count |= maxcnt_high << 16; 289 } else { 290 rc = smbsr_decode_vwv(sr, "b3.wlwwlw", ¶m->rw_andx, 291 &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high, 292 &remcnt); 293 294 param->rw_offset = (uint64_t)off_low; 295 param->rw_count = (uint32_t)maxcnt_low; 296 } 297 298 param->rw_mincnt = 0; 299 300 DTRACE_SMB_START(op__ReadX, smb_request_t *, sr); /* arg.rw */ 301 302 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 303 } 304 305 void 306 smb_post_read_andx(smb_request_t *sr) 307 { 308 DTRACE_SMB_DONE(op__ReadX, smb_request_t *, sr); /* arg.rw */ 309 310 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 311 } 312 313 smb_sdrc_t 314 smb_com_read_andx(smb_request_t *sr) 315 { 316 smb_rw_param_t *param = sr->arg.rw; 317 uint16_t datalen_high; 318 uint16_t datalen_low; 319 uint16_t data_offset; 320 uint16_t offset2; 321 int rc; 322 323 smbsr_lookup_file(sr); 324 if (sr->fid_ofile == NULL) { 325 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 326 return (SDRC_ERROR); 327 } 328 329 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 330 331 if (param->rw_count >= SMB_READX_MAX) 332 param->rw_count = 0; 333 334 if ((rc = smb_common_read(sr, param)) != 0) { 335 smbsr_errno(sr, rc); 336 return (SDRC_ERROR); 337 } 338 339 datalen_low = param->rw_count & 0xFFFF; 340 datalen_high = (param->rw_count >> 16) & 0xFF; 341 342 /* 343 * If this is a secondary command, the data offset 344 * includes the previous wct + sizeof(wct). 345 */ 346 data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1; 347 348 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 349 data_offset += 60; 350 offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60; 351 352 rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC", 353 12, /* wct */ 354 param->rw_andx, /* secondary andx command */ 355 offset2, /* offset to next command */ 356 0, /* set to 0 for named pipes */ 357 datalen_low, /* data byte count */ 358 data_offset, /* offset from start to data */ 359 datalen_high, /* data byte count */ 360 VAR_BCC, /* BCC marker */ 361 0x00, /* padding */ 362 &sr->raw_data); 363 } else { 364 data_offset += 59; 365 offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59; 366 367 rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC", 368 12, /* wct */ 369 param->rw_andx, /* secondary andx command */ 370 offset2, /* offset to next command */ 371 -1, /* must be -1 for regular files */ 372 datalen_low, /* data byte count */ 373 data_offset, /* offset from start to data */ 374 datalen_high, /* data byte count */ 375 VAR_BCC, /* BCC marker */ 376 &sr->raw_data); 377 } 378 379 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 380 } 381 382 /* 383 * Common function for reading files or IPC/MSRPC named pipes. All 384 * protocol read functions should lookup the fid before calling this 385 * function. We can't move the fid lookup here because lock-and-read 386 * requires the fid to do locking before attempting the read. 387 * 388 * Reading from a file does not break oplocks because any need for 389 * breaking before read is handled in open. 390 * 391 * Returns errno values. 392 */ 393 int 394 smb_common_read(smb_request_t *sr, smb_rw_param_t *param) 395 { 396 smb_ofile_t *ofile = sr->fid_ofile; 397 smb_node_t *node; 398 smb_vdb_t *vdb = ¶m->rw_vdb; 399 struct mbuf *top; 400 int rc; 401 402 vdb->vdb_tag = 0; 403 vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0]; 404 vdb->vdb_uio.uio_iovcnt = MAX_IOVEC; 405 vdb->vdb_uio.uio_resid = param->rw_count; 406 vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset; 407 vdb->vdb_uio.uio_segflg = UIO_SYSSPACE; 408 vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 409 410 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 411 case STYPE_DISKTREE: 412 node = ofile->f_node; 413 414 if (!smb_node_is_dir(node)) { 415 rc = smb_lock_range_access(sr, node, param->rw_offset, 416 param->rw_count, B_FALSE); 417 if (rc != NT_STATUS_SUCCESS) { 418 rc = ERANGE; 419 break; 420 } 421 } 422 423 if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) && 424 !(sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)) { 425 /* 426 * SMB_FLAGS2_READ_IF_EXECUTE: permit execute-only 427 * reads. 428 * 429 * Reject request if the file has been opened 430 * execute-only and SMB_FLAGS2_READ_IF_EXECUTE is not 431 * set. 432 */ 433 rc = EACCES; 434 break; 435 } 436 437 sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid; 438 top = smb_mbuf_allocate(&vdb->vdb_uio); 439 440 rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio); 441 442 sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid; 443 smb_mbuf_trim(top, sr->raw_data.max_bytes); 444 MBC_ATTACH_MBUF(&sr->raw_data, top); 445 break; 446 447 case STYPE_IPC: 448 sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid; 449 top = smb_mbuf_allocate(&vdb->vdb_uio); 450 451 rc = smb_opipe_read(sr, &vdb->vdb_uio); 452 453 sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid; 454 smb_mbuf_trim(top, sr->raw_data.max_bytes); 455 MBC_ATTACH_MBUF(&sr->raw_data, top); 456 break; 457 458 default: 459 rc = EACCES; 460 break; 461 } 462 463 param->rw_count -= vdb->vdb_uio.uio_resid; 464 465 if (rc != 0) 466 return (rc); 467 468 if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) { 469 /* 470 * mincnt is only used by read-raw and is typically 471 * zero. If mincnt is greater than zero and the 472 * number of bytes read is less than mincnt, tell 473 * the client that we read nothing. 474 */ 475 param->rw_count = 0; 476 } 477 478 param->rw_offset += param->rw_count; 479 mutex_enter(&sr->fid_ofile->f_mutex); 480 ofile->f_seek_pos = param->rw_offset; 481 mutex_exit(&sr->fid_ofile->f_mutex); 482 return (rc); 483 } 484