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 2007 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 typedef struct smb_read_param { 34 uint64_t r_offset; 35 uint16_t r_count; 36 uint16_t r_mincnt; 37 } smb_read_param_t; 38 39 40 int smb_common_read(struct smb_request *sr, smb_read_param_t *param); 41 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 int 59 smb_com_read(struct smb_request *sr) 60 { 61 smb_read_param_t param; 62 uint32_t off_low; 63 uint16_t remcnt; 64 int rc; 65 66 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 67 ¶m.r_count, &off_low, &remcnt); 68 if (rc != 0) { 69 smbsr_decode_error(sr); 70 /* NOTREACHED */ 71 } 72 73 param.r_offset = (uint64_t)off_low; 74 param.r_mincnt = 0; 75 76 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 77 if (sr->fid_ofile == NULL) { 78 smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE, 79 ERRDOS, ERRbadfid); 80 /* NOTREACHED */ 81 } 82 83 if ((rc = smb_common_read(sr, ¶m)) != 0) { 84 smbsr_raise_errno(sr, rc); 85 /* NOTREACHED */ 86 } 87 88 smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 89 5, param.r_count, VAR_BCC, 0x01, param.r_count, &sr->raw_data); 90 91 return (SDRC_NORMAL_REPLY); 92 } 93 94 /* 95 * Lock and read bytes from a file (SMB Core Plus). The SmbLockAndRead/ 96 * SmbLockAndWrite sub-dialect is only valid on disk files: reject any 97 * attempt to use it on non-disk shares. 98 * 99 * The requested count specifies the number of bytes desired. Offset 100 * specifies the offset in the file of the first byte to be locked then 101 * read. Note that offset is limited to 32 bits, so this client request 102 * is inappropriate for files with 64 bit offsets. 103 * 104 * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted 105 * immediately an error should be returned to the client. If an error 106 * occurs on the lock, the bytes should not be read. 107 * 108 * On return, count is the number of bytes actually being returned, which 109 * may be less than the count requested only if a read specifies bytes 110 * beyond the current file size. In this case only the bytes that exist 111 * are returned. A read completely beyond the end of file results in a 112 * response of length zero. This is the only circumstance when a zero 113 * length response is generated. A count returned which is less than the 114 * count requested is the end of file indicator. 115 */ 116 int 117 smb_com_lock_and_read(struct smb_request *sr) 118 { 119 smb_read_param_t param; 120 uint16_t remcnt; 121 uint32_t off_low; 122 DWORD result; 123 int rc; 124 125 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 126 smbsr_raise_error(sr, ERRDOS, ERRnoaccess); 127 /* NOTREACHED */ 128 } 129 130 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, 131 ¶m.r_count, &off_low, &remcnt); 132 if (rc != 0) { 133 smbsr_decode_error(sr); 134 /* NOTREACHED */ 135 } 136 137 param.r_offset = (uint64_t)off_low; 138 param.r_mincnt = 0; 139 140 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 141 if (sr->fid_ofile == NULL) { 142 smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE, 143 ERRDOS, ERRbadfid); 144 /* NOTREACHED */ 145 } 146 147 result = smb_lock_range(sr, sr->fid_ofile, param.r_offset, 148 (uint64_t)param.r_count, 0xffffffff, SMB_LOCK_TYPE_READWRITE); 149 if (result != NT_STATUS_SUCCESS) { 150 smb_lock_range_raise_error(sr, result); 151 } 152 153 if ((rc = smb_common_read(sr, ¶m)) != 0) { 154 smbsr_raise_errno(sr, rc); 155 /* NOTREACHED */ 156 } 157 158 smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC", 159 5, param.r_count, VAR_BCC, 0x1, param.r_count, &sr->raw_data); 160 161 return (SDRC_NORMAL_REPLY); 162 } 163 164 /* 165 * The SMB_COM_READ_RAW protocol is a negotiated option introduced in 166 * SMB Core Plus to maximize performance when reading a large block 167 * of data from a server. This request was extended in LM 0.12 to 168 * support 64-bit offsets; the server can indicate support by setting 169 * CAP_LARGE_FILES in the negotiated capabilities. 170 * 171 * The client must guarantee that there is (and will be) no other request 172 * to the server for the duration of the SMB_COM_READ_RAW, since the 173 * server response has no header or trailer. To help ensure that there 174 * are no interruptions, we block all I/O for the session during read raw. 175 * 176 * If this is the first SMB request received since we sent an oplock break 177 * to this client, we don't know if it's safe to send the raw data because 178 * the requests may have crossed on the wire and the client may have 179 * interpreted the oplock break as part of the raw data. To avoid problems, 180 * we send a zero length session packet, which will force the client to 181 * retry the read. 182 * 183 * Read errors are handled by sending a zero length response. 184 */ 185 int 186 smb_com_read_raw(struct smb_request *sr) 187 { 188 smb_read_param_t param; 189 smb_node_t *node; 190 uint32_t off_low; 191 uint32_t off_high; 192 uint32_t timeout; 193 int rc; 194 195 switch (sr->session->s_state) { 196 case SMB_SESSION_STATE_NEGOTIATED: 197 if (sr->smb_wct == 8) { 198 rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid, 199 &off_low, ¶m.r_count, ¶m.r_mincnt, 200 &timeout); 201 param.r_offset = (uint64_t)off_low; 202 } else { 203 rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid, 204 &off_low, ¶m.r_count, ¶m.r_mincnt, &timeout, 205 &off_high); 206 param.r_offset = ((uint64_t)off_high << 32) | off_low; 207 } 208 209 if (rc != 0) { 210 smbsr_decode_error(sr); 211 /* NOTREACHED */ 212 } 213 214 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, 215 sr->smb_fid); 216 if (sr->fid_ofile == NULL) { 217 smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE, 218 ERRDOS, ERRbadfid); 219 /* NOTREACHED */ 220 } 221 222 rc = smb_common_read(sr, ¶m); 223 /* 224 * XXX Do we need to handle errors here? What if we have an 225 * access error (either permissions or range lock violations? 226 */ 227 if (STYPE_ISDSK(sr->tid_tree->t_res_type)) { 228 node = sr->fid_ofile->f_node; 229 if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) { 230 rc = EAGAIN; 231 } 232 } 233 234 if (rc != 0) { 235 (void) smb_session_send(sr->session, 0, NULL); 236 m_freem(sr->raw_data.chain); 237 sr->raw_data.chain = 0; 238 } else { 239 (void) smb_session_send(sr->session, 0, &sr->raw_data); 240 } 241 return (SDRC_NO_REPLY); 242 243 case SMB_SESSION_STATE_OPLOCK_BREAKING: 244 (void) smb_session_send(sr->session, 0, NULL); 245 sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED; 246 return (SDRC_NO_REPLY); 247 248 case SMB_SESSION_STATE_WRITE_RAW_ACTIVE: 249 ASSERT(0); 250 return (SDRC_DROP_VC); 251 252 case SMB_SESSION_STATE_TERMINATED: 253 ASSERT(0); 254 return (SDRC_NO_REPLY); 255 256 case SMB_SESSION_STATE_DISCONNECTED: 257 return (SDRC_NO_REPLY); 258 259 case SMB_SESSION_STATE_CONNECTED: 260 case SMB_SESSION_STATE_ESTABLISHED: 261 default: 262 ASSERT(0); 263 return (SDRC_DROP_VC); 264 } 265 } 266 267 /* 268 * Read bytes from a file (SMB Core). This request was extended in 269 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 270 * 12 and including additional offset information. 271 */ 272 int 273 smb_com_read_andx(struct smb_request *sr) 274 { 275 smb_read_param_t param; 276 uint32_t off_low; 277 uint32_t off_high; 278 uint16_t remcnt; 279 uint16_t offset2; 280 uint8_t secondary; 281 int rc; 282 283 if (sr->smb_wct == 12) { 284 rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &secondary, 285 &sr->smb_fid, &off_low, ¶m.r_count, &remcnt, &off_high); 286 287 param.r_offset = ((uint64_t)off_high << 32) | off_low; 288 } else { 289 rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &secondary, 290 &sr->smb_fid, &off_low, ¶m.r_count, &remcnt); 291 292 param.r_offset = (uint64_t)off_low; 293 } 294 295 if (rc != 0) { 296 smbsr_decode_error(sr); 297 /* NOTREACHED */ 298 } 299 300 param.r_mincnt = 0; 301 302 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 303 if (sr->fid_ofile == NULL) { 304 smbsr_raise_cifs_error(sr, NT_STATUS_INVALID_HANDLE, 305 ERRDOS, ERRbadfid); 306 /* NOTREACHED */ 307 } 308 309 if ((rc = smb_common_read(sr, ¶m)) != 0) { 310 smbsr_raise_errno(sr, rc); 311 /* NOTREACHED */ 312 } 313 314 /* 315 * Ensure that the next response offset is zero 316 * if there is no secondary command. 317 */ 318 offset2 = (secondary == 0xFF) ? 0 : param.r_count + 59; 319 320 /* 321 * The STYPE_IPC response format is different. 322 * The unknown value (2) may be to indicate that it 323 * is a follow-up to an earlier RPC transaction. 324 */ 325 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 326 smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC", 327 12, /* wct */ 328 secondary, /* Secondary andx command */ 329 offset2, /* offset to next */ 330 0, /* must be 0 */ 331 param.r_count, /* data byte count */ 332 60, /* Offset from start to data */ 333 VAR_BCC, /* BCC marker */ 334 0x02, /* unknown */ 335 &sr->raw_data); 336 } else { 337 smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC", 338 12, /* wct */ 339 secondary, /* Secondary andx command */ 340 offset2, /* offset to next */ 341 -1, /* must be -1 */ 342 param.r_count, /* data byte count */ 343 59, /* Offset from start to data */ 344 VAR_BCC, /* BCC marker */ 345 &sr->raw_data); 346 } 347 348 return (SDRC_NORMAL_REPLY); 349 } 350 351 /* 352 * Common function for reading files or IPC/MSRPC named pipes. All 353 * protocol read functions should lookup the fid before calling this 354 * function. We can't move the fid lookup here because lock-and-read 355 * requires the fid to do locking before attempting the read. 356 * 357 * Returns errno values. 358 */ 359 int 360 smb_common_read(struct smb_request *sr, smb_read_param_t *param) 361 { 362 smb_ofile_t *ofile = sr->fid_ofile; 363 smb_node_t *node; 364 struct vardata_block *vdb; 365 struct mbuf *top; 366 int rc; 367 368 vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP); 369 vdb->tag = 0; 370 vdb->uio.uio_iov = &vdb->iovec[0]; 371 vdb->uio.uio_iovcnt = MAX_IOVEC; 372 vdb->uio.uio_resid = param->r_count; 373 vdb->uio.uio_offset = param->r_offset; 374 vdb->uio.uio_segflg = UIO_SYSSPACE; 375 376 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 377 case STYPE_DISKTREE: 378 node = ofile->f_node; 379 380 if (node->attr.sa_vattr.va_type != VDIR) { 381 rc = smb_lock_range_access(sr, node, param->r_offset, 382 param->r_count, FILE_READ_DATA); 383 if (rc != NT_STATUS_SUCCESS) { 384 rc = ERANGE; 385 break; 386 } 387 } 388 389 (void) smb_sync_fsattr(sr, sr->user_cr, node); 390 391 sr->raw_data.max_bytes = vdb->uio.uio_resid; 392 top = smb_mbuf_allocate(&vdb->uio); 393 394 rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio, 395 &node->attr); 396 397 sr->raw_data.max_bytes -= vdb->uio.uio_resid; 398 smb_mbuf_trim(top, sr->raw_data.max_bytes); 399 MBC_ATTACH_MBUF(&sr->raw_data, top); 400 break; 401 402 case STYPE_IPC: 403 rc = smb_rpc_read(sr, &vdb->uio); 404 break; 405 406 default: 407 rc = EACCES; 408 break; 409 } 410 411 param->r_count -= vdb->uio.uio_resid; 412 kmem_free(vdb, sizeof (struct vardata_block)); 413 414 if (rc != 0) 415 return (rc); 416 417 if (param->r_mincnt != 0 && param->r_count < param->r_mincnt) { 418 /* 419 * mincnt is only used by read-raw and is typically 420 * zero. If mincnt is greater than zero and the 421 * number of bytes read is less than mincnt, tell 422 * the client that we read nothing. 423 */ 424 param->r_count = 0; 425 } 426 427 param->r_offset += param->r_count; 428 mutex_enter(&sr->fid_ofile->f_mutex); 429 ofile->f_seek_pos = param->r_offset; 430 mutex_exit(&sr->fid_ofile->f_mutex); 431 return (rc); 432 } 433 434 /* 435 * The Read Block Multiplexed protocol is used to maximize performance 436 * when reading a large block of data from server to client while still 437 * allowing other operations to take place between the client and server 438 * in parallel. 439 * 440 * The mpx sub protocol is not supported because we support only 441 * connection oriented transports and NT supports SMB_COM_READ_MPX 442 * only over connectionless transports. 443 */ 444 /*ARGSUSED*/ 445 int 446 smb_com_read_mpx(struct smb_request *sr) 447 { 448 return (SDRC_UNIMPLEMENTED); 449 } 450 451 /*ARGSUSED*/ 452 int 453 smb_com_read_mpx_secondary(struct smb_request *sr) 454 { 455 return (SDRC_UNIMPLEMENTED); 456 } 457