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