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 ¶m->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 ¶m->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, ¶m->rw_count, ¶m->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, ¶m->rw_count, ¶m->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", ¶m->rw_andx, 332 &sr->smb_fid, &off_low, ¶m->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", ¶m->rw_andx, 338 &sr->smb_fid, &off_low, ¶m->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 = ¶m->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