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