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 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2016 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 #include <sys/sdt.h> 28 #include <smbsrv/smb_kproto.h> 29 #include <smbsrv/smb_fsops.h> 30 #include <smbsrv/netbios.h> 31 32 33 static int smb_write_truncate(smb_request_t *, smb_rw_param_t *); 34 35 36 /* 37 * Write count bytes at the specified offset in a file. The offset is 38 * limited to 32-bits. If the count is zero, the file is truncated to 39 * the length specified by the offset. 40 * 41 * The response count indicates the actual number of bytes written, which 42 * will equal the requested count on success. If request and response 43 * counts differ but there is no error, the client will assume that the 44 * server encountered a resource issue. 45 */ 46 smb_sdrc_t 47 smb_pre_write(smb_request_t *sr) 48 { 49 smb_rw_param_t *param; 50 uint32_t off; 51 uint16_t count; 52 int rc; 53 54 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 55 sr->arg.rw = param; 56 param->rw_magic = SMB_RW_MAGIC; 57 58 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, &count, &off); 59 60 param->rw_count = (uint32_t)count; 61 param->rw_offset = (uint64_t)off; 62 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 63 64 DTRACE_SMB_2(op__Write__start, smb_request_t *, sr, 65 smb_rw_param_t *, param); 66 67 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 68 } 69 70 void 71 smb_post_write(smb_request_t *sr) 72 { 73 DTRACE_SMB_2(op__Write__done, smb_request_t *, sr, 74 smb_rw_param_t *, sr->arg.rw); 75 76 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 77 } 78 79 smb_sdrc_t 80 smb_com_write(smb_request_t *sr) 81 { 82 smb_rw_param_t *param = sr->arg.rw; 83 int rc; 84 85 smbsr_lookup_file(sr); 86 if (sr->fid_ofile == NULL) { 87 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 88 return (SDRC_ERROR); 89 } 90 91 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 92 93 if (param->rw_count == 0) { 94 rc = smb_write_truncate(sr, param); 95 } else { 96 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 97 98 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 99 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 100 ERRDOS, ERROR_INVALID_PARAMETER); 101 return (SDRC_ERROR); 102 } 103 104 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 105 106 rc = smb_common_write(sr, param); 107 } 108 109 if (rc != 0) { 110 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 111 smbsr_errno(sr, rc); 112 return (SDRC_ERROR); 113 } 114 115 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 116 (uint16_t)param->rw_count, 0); 117 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 118 } 119 120 /* 121 * Write count bytes to a file and then close the file. This function 122 * can only be used to write to 32-bit offsets and the client must set 123 * WordCount (6 or 12) correctly in order to locate the data to be 124 * written. If an error occurs on the write, the file should still be 125 * closed. If Count is 0, the file is truncated (or extended) to offset. 126 * 127 * If the last_write time is non-zero, last_write should be used to set 128 * the mtime. Otherwise the file system stamps the mtime. Failure to 129 * set mtime should not result in an error response. 130 */ 131 smb_sdrc_t 132 smb_pre_write_and_close(smb_request_t *sr) 133 { 134 smb_rw_param_t *param; 135 uint32_t off; 136 uint16_t count; 137 int rc; 138 139 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 140 sr->arg.rw = param; 141 param->rw_magic = SMB_RW_MAGIC; 142 143 if (sr->smb_wct == 12) { 144 rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 145 &count, &off, ¶m->rw_last_write); 146 } else { 147 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 148 &count, &off, ¶m->rw_last_write); 149 } 150 151 param->rw_count = (uint32_t)count; 152 param->rw_offset = (uint64_t)off; 153 154 DTRACE_SMB_2(op__WriteAndClose__start, smb_request_t *, sr, 155 smb_rw_param_t *, param); 156 157 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 158 } 159 160 void 161 smb_post_write_and_close(smb_request_t *sr) 162 { 163 DTRACE_SMB_2(op__WriteAndClose__done, smb_request_t *, sr, 164 smb_rw_param_t *, sr->arg.rw); 165 166 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 167 } 168 169 smb_sdrc_t 170 smb_com_write_and_close(smb_request_t *sr) 171 { 172 smb_rw_param_t *param = sr->arg.rw; 173 uint16_t count; 174 int rc = 0; 175 176 smbsr_lookup_file(sr); 177 if (sr->fid_ofile == NULL) { 178 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 179 return (SDRC_ERROR); 180 } 181 182 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 183 184 if (param->rw_count == 0) { 185 rc = smb_write_truncate(sr, param); 186 } else { 187 /* 188 * There may be a bug here: should this be "3.#B"? 189 */ 190 rc = smbsr_decode_data(sr, ".#B", param->rw_count, 191 ¶m->rw_vdb); 192 193 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 194 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 195 ERRDOS, ERROR_INVALID_PARAMETER); 196 return (SDRC_ERROR); 197 } 198 199 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 200 201 rc = smb_common_write(sr, param); 202 } 203 204 if (rc != 0) { 205 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 206 smbsr_errno(sr, rc); 207 return (SDRC_ERROR); 208 } 209 210 smb_ofile_close(sr->fid_ofile, param->rw_last_write); 211 212 count = (uint16_t)param->rw_count; 213 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, count, 0); 214 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 215 } 216 217 /* 218 * Write count bytes to a file at the specified offset and then unlock 219 * them. Write behind is safe because the client should have the range 220 * locked and this request is allowed to extend the file - note that 221 * offset is limited to 32-bits. 222 * 223 * Spec advice: it is an error for count to be zero. For compatibility, 224 * we take no action and return success. 225 * 226 * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 227 * files. Reject any attempt to use it on other shares. 228 * 229 * The response count indicates the actual number of bytes written, which 230 * will equal the requested count on success. If request and response 231 * counts differ but there is no error, the client will assume that the 232 * server encountered a resource issue. 233 */ 234 smb_sdrc_t 235 smb_pre_write_and_unlock(smb_request_t *sr) 236 { 237 smb_rw_param_t *param; 238 uint32_t off; 239 uint16_t count; 240 uint16_t remcnt; 241 int rc; 242 243 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 244 sr->arg.rw = param; 245 param->rw_magic = SMB_RW_MAGIC; 246 247 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, &count, &off, &remcnt); 248 249 param->rw_count = (uint32_t)count; 250 param->rw_offset = (uint64_t)off; 251 252 DTRACE_SMB_2(op__WriteAndUnlock__start, smb_request_t *, sr, 253 smb_rw_param_t *, param); 254 255 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 256 } 257 258 void 259 smb_post_write_and_unlock(smb_request_t *sr) 260 { 261 DTRACE_SMB_2(op__WriteAndUnlock__done, smb_request_t *, sr, 262 smb_rw_param_t *, sr->arg.rw); 263 264 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 265 } 266 267 smb_sdrc_t 268 smb_com_write_and_unlock(smb_request_t *sr) 269 { 270 smb_rw_param_t *param = sr->arg.rw; 271 uint32_t lk_pid; 272 uint32_t status; 273 int rc = 0; 274 275 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 276 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 277 return (SDRC_ERROR); 278 } 279 280 smbsr_lookup_file(sr); 281 if (sr->fid_ofile == NULL) { 282 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 283 return (SDRC_ERROR); 284 } 285 286 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 287 288 if (param->rw_count == 0) { 289 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 0, 0); 290 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 291 } 292 293 294 rc = smbsr_decode_data(sr, "D", ¶m->rw_vdb); 295 296 if ((rc != 0) || (param->rw_count != param->rw_vdb.vdb_len)) { 297 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 298 ERRDOS, ERROR_INVALID_PARAMETER); 299 return (SDRC_ERROR); 300 } 301 302 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 303 304 if ((rc = smb_common_write(sr, param)) != 0) { 305 if (sr->smb_error.status != NT_STATUS_FILE_LOCK_CONFLICT) 306 smbsr_errno(sr, rc); 307 return (SDRC_ERROR); 308 } 309 310 311 /* Note: SMB1 locking uses 16-bit PIDs. */ 312 lk_pid = sr->smb_pid & 0xFFFF; 313 314 status = smb_unlock_range(sr, param->rw_offset, 315 (uint64_t)param->rw_count, lk_pid); 316 if (status != NT_STATUS_SUCCESS) { 317 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 318 ERRDOS, ERROR_NOT_LOCKED); 319 return (SDRC_ERROR); 320 } 321 322 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, 323 (uint16_t)param->rw_count, 0); 324 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 325 } 326 327 /* 328 * Write bytes to a file (SMB Core). This request was extended in 329 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 330 * 14, instead of 12, and including additional offset information. 331 * 332 * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 333 * to truncate a file. A zero length merely transfers zero bytes. 334 * 335 * If bit 0 of WriteMode is set, Fid must refer to a disk file and 336 * the data must be on stable storage before responding. 337 * 338 * MS-SMB 3.3.5.8 update to LM 0.12 4.2.5: 339 * If CAP_LARGE_WRITEX is set, the byte count may be larger than the 340 * negotiated buffer size and the server is expected to write the 341 * number of bytes specified. 342 */ 343 smb_sdrc_t 344 smb_pre_write_andx(smb_request_t *sr) 345 { 346 smb_rw_param_t *param; 347 uint32_t off_low; 348 uint32_t off_high; 349 uint16_t datalen_low; 350 uint16_t datalen_high; 351 uint16_t remcnt; 352 int rc; 353 354 param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP); 355 sr->arg.rw = param; 356 param->rw_magic = SMB_RW_MAGIC; 357 358 if (sr->smb_wct == 14) { 359 rc = smbsr_decode_vwv(sr, "4.wl4.wwwwwl", &sr->smb_fid, 360 &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 361 &datalen_low, ¶m->rw_dsoff, &off_high); 362 363 if (param->rw_dsoff >= 63) 364 param->rw_dsoff -= 63; 365 param->rw_offset = ((uint64_t)off_high << 32) | off_low; 366 } else if (sr->smb_wct == 12) { 367 rc = smbsr_decode_vwv(sr, "4.wl4.wwwww", &sr->smb_fid, 368 &off_low, ¶m->rw_mode, &remcnt, &datalen_high, 369 &datalen_low, ¶m->rw_dsoff); 370 371 if (param->rw_dsoff >= 59) 372 param->rw_dsoff -= 59; 373 param->rw_offset = (uint64_t)off_low; 374 /* off_high not present */ 375 } else { 376 rc = -1; 377 } 378 379 param->rw_count = (uint32_t)datalen_low; 380 381 /* 382 * Work-around a Win7 bug, where it fails to set the 383 * CAP_LARGE_WRITEX flag during session setup. Assume 384 * a large write if the data remaining is >= 64k. 385 */ 386 if ((sr->session->capabilities & CAP_LARGE_WRITEX) != 0 || 387 (sr->smb_data.max_bytes > (sr->smb_data.chain_offset + 0xFFFF))) 388 param->rw_count |= ((uint32_t)datalen_high << 16); 389 390 DTRACE_SMB_2(op__WriteX__start, smb_request_t *, sr, 391 smb_rw_param_t *, param); 392 393 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 394 } 395 396 void 397 smb_post_write_andx(smb_request_t *sr) 398 { 399 DTRACE_SMB_2(op__WriteX__done, smb_request_t *, sr, 400 smb_rw_param_t *, sr->arg.rw); 401 402 kmem_free(sr->arg.rw, sizeof (smb_rw_param_t)); 403 } 404 405 smb_sdrc_t 406 smb_com_write_andx(smb_request_t *sr) 407 { 408 smb_rw_param_t *param = sr->arg.rw; 409 uint16_t count_high; 410 uint16_t count_low; 411 int rc; 412 413 ASSERT(param); 414 ASSERT(param->rw_magic == SMB_RW_MAGIC); 415 416 smbsr_lookup_file(sr); 417 if (sr->fid_ofile == NULL) { 418 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 419 return (SDRC_ERROR); 420 } 421 422 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 423 424 if (SMB_WRMODE_IS_STABLE(param->rw_mode) && 425 STYPE_ISIPC(sr->tid_tree->t_res_type)) { 426 smbsr_error(sr, 0, ERRSRV, ERRaccess); 427 return (SDRC_ERROR); 428 } 429 430 rc = smbsr_decode_data(sr, "#.#B", param->rw_dsoff, param->rw_count, 431 ¶m->rw_vdb); 432 433 if ((rc != 0) || (param->rw_vdb.vdb_len != param->rw_count)) { 434 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 435 ERRDOS, ERROR_INVALID_PARAMETER); 436 return (SDRC_ERROR); 437 } 438 439 param->rw_vdb.vdb_uio.uio_loffset = (offset_t)param->rw_offset; 440 441 if (param->rw_count != 0) { 442 if ((rc = smb_common_write(sr, param)) != 0) { 443 if (sr->smb_error.status != 444 NT_STATUS_FILE_LOCK_CONFLICT) 445 smbsr_errno(sr, rc); 446 return (SDRC_ERROR); 447 } 448 } 449 450 count_low = param->rw_count & 0xFFFF; 451 count_high = (param->rw_count >> 16) & 0xFF; 452 453 rc = smbsr_encode_result(sr, 6, 0, "bb1.wwwwww", 454 6, sr->andx_com, 15, count_low, 0, count_high, 0, 0); 455 456 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 457 } 458 459 /* 460 * Common function for writing files or IPC/MSRPC named pipes. 461 * 462 * Returns errno values. 463 */ 464 int 465 smb_common_write(smb_request_t *sr, smb_rw_param_t *param) 466 { 467 smb_ofile_t *ofile = sr->fid_ofile; 468 smb_node_t *node; 469 int stability = 0; 470 uint32_t lcount; 471 int rc = 0; 472 473 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 474 case STYPE_DISKTREE: 475 case STYPE_PRINTQ: 476 node = ofile->f_node; 477 478 if (!smb_node_is_dir(node)) { 479 rc = smb_lock_range_access(sr, node, param->rw_offset, 480 param->rw_count, B_TRUE); 481 if (rc != NT_STATUS_SUCCESS) { 482 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 483 ERRDOS, ERROR_LOCK_VIOLATION); 484 return (EACCES); 485 } 486 } 487 488 if (SMB_WRMODE_IS_STABLE(param->rw_mode) || 489 (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 490 stability = FSYNC; 491 } 492 493 rc = smb_fsop_write(sr, sr->user_cr, node, 494 ¶m->rw_vdb.vdb_uio, &lcount, stability); 495 496 if (rc) 497 return (rc); 498 499 /* 500 * Used to have code here to set mtime. 501 * We have just done a write, so we know 502 * the file system will update mtime. 503 * No need to do it again here. 504 * 505 * However, keep track of the fact that 506 * we have written data via this handle. 507 */ 508 ofile->f_written = B_TRUE; 509 510 if (!smb_node_is_dir(node)) 511 smb_oplock_break_levelII(node); 512 513 param->rw_count = lcount; 514 break; 515 516 case STYPE_IPC: 517 param->rw_count = param->rw_vdb.vdb_uio.uio_resid; 518 519 if ((rc = smb_opipe_write(sr, ¶m->rw_vdb.vdb_uio)) != 0) 520 param->rw_count = 0; 521 break; 522 523 default: 524 rc = EACCES; 525 break; 526 } 527 528 if (rc != 0) 529 return (rc); 530 531 mutex_enter(&ofile->f_mutex); 532 ofile->f_seek_pos = param->rw_offset + param->rw_count; 533 mutex_exit(&ofile->f_mutex); 534 return (rc); 535 } 536 537 /* 538 * Truncate a disk file to the specified offset. 539 * Typically, w_count will be zero here. 540 * 541 * Note that smb_write_andx cannot be used to reduce the file size so, 542 * if this is required, smb_write is called with a count of zero and 543 * the appropriate file length in offset. The file should be resized 544 * to the length specified by the offset. 545 * 546 * Returns errno values. 547 */ 548 static int 549 smb_write_truncate(smb_request_t *sr, smb_rw_param_t *param) 550 { 551 smb_ofile_t *ofile = sr->fid_ofile; 552 smb_node_t *node = ofile->f_node; 553 smb_attr_t attr; 554 uint32_t status; 555 int rc; 556 557 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) 558 return (0); 559 560 mutex_enter(&node->n_mutex); 561 if (!smb_node_is_dir(node)) { 562 status = smb_lock_range_access(sr, node, param->rw_offset, 563 param->rw_count, B_TRUE); 564 if (status != NT_STATUS_SUCCESS) { 565 mutex_exit(&node->n_mutex); 566 smbsr_error(sr, NT_STATUS_FILE_LOCK_CONFLICT, 567 ERRDOS, ERROR_LOCK_VIOLATION); 568 return (EACCES); 569 } 570 } 571 mutex_exit(&node->n_mutex); 572 573 bzero(&attr, sizeof (smb_attr_t)); 574 attr.sa_mask = SMB_AT_SIZE; 575 attr.sa_vattr.va_size = param->rw_offset; 576 rc = smb_node_setattr(sr, node, sr->user_cr, ofile, &attr); 577 if (rc != 0) 578 return (rc); 579 580 mutex_enter(&ofile->f_mutex); 581 ofile->f_seek_pos = param->rw_offset + param->rw_count; 582 mutex_exit(&ofile->f_mutex); 583 return (0); 584 } 585