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