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