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/sdt.h> 29 #include <smbsrv/smb_incl.h> 30 #include <smbsrv/smb_fsops.h> 31 #include <smbsrv/mbuf.h> 32 #include <smbsrv/netbios.h> 33 34 35 #define SMB_WRMODE_WRITE_THRU 0x0001 36 #define SMB_WRMODE_IS_STABLE(M) ((M) & SMB_WRMODE_WRITE_THRU) 37 38 39 typedef struct smb_write_param { 40 struct vardata_block w_vdb; 41 uint64_t w_offset; 42 uint16_t w_mode; 43 uint16_t w_count; 44 } smb_write_param_t; 45 46 47 static int smb_write_common(struct smb_request *, smb_write_param_t *); 48 static int smb_write_truncate(struct smb_request *, smb_write_param_t *); 49 int smb_set_file_size(struct smb_request *); 50 51 52 /* 53 * Write count bytes at the specified offset in a file. The offset is 54 * limited to 32-bits. If the count is zero, the file is truncated to 55 * the length specified by the offset. 56 * 57 * The response count indicates the actual number of bytes written, which 58 * will equal the requested count on success. If request and response 59 * counts differ but there is no error, the client will assume that the 60 * server encountered a resource issue. 61 */ 62 smb_sdrc_t 63 smb_com_write(struct smb_request *sr) 64 { 65 smb_write_param_t *param; 66 uint32_t off; 67 int rc; 68 69 param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 70 71 rc = smbsr_decode_vwv(sr, "wwl", &sr->smb_fid, ¶m->w_count, &off); 72 if (rc != 0) { 73 kmem_free(param, sizeof (smb_write_param_t)); 74 return (SDRC_ERROR_REPLY); 75 } 76 77 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 78 if (sr->fid_ofile == NULL) { 79 kmem_free(param, sizeof (smb_write_param_t)); 80 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 81 return (SDRC_ERROR_REPLY); 82 } 83 84 param->w_offset = (uint64_t)off; 85 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 86 87 if (param->w_count == 0) { 88 rc = smb_write_truncate(sr, param); 89 } else { 90 rc = smbsr_decode_data(sr, "D", ¶m->w_vdb); 91 92 if ((rc != 0) || (param->w_vdb.len != param->w_count)) { 93 kmem_free(param, sizeof (smb_write_param_t)); 94 return (SDRC_ERROR_REPLY); 95 } 96 97 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 98 99 rc = smb_write_common(sr, param); 100 } 101 102 if (rc != 0) { 103 kmem_free(param, sizeof (smb_write_param_t)); 104 smbsr_errno(sr, rc); 105 return (SDRC_ERROR_REPLY); 106 } 107 108 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0); 109 kmem_free(param, sizeof (smb_write_param_t)); 110 return ((rc == 0) ? SDRC_NORMAL_REPLY : SDRC_ERROR_REPLY); 111 } 112 113 /* 114 * Write count bytes to a file and then close the file. This function 115 * can only be used to write to 32-bit offsets and the client must set 116 * WordCount (6 or 12) correctly in order to locate the data to be 117 * written. If an error occurs on the write, the file should still be 118 * closed. If Count is 0, the file is truncated (or extended) to offset. 119 * 120 * If the last_write time is non-zero, last_write should be used to set 121 * the mtime. Otherwise the file system stamps the mtime. Failure to 122 * set mtime should not result in an error response. 123 */ 124 smb_sdrc_t 125 smb_com_write_and_close(struct smb_request *sr) 126 { 127 smb_write_param_t *param; 128 uint32_t last_write; 129 uint32_t off; 130 int rc = 0; 131 132 param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 133 134 if (sr->smb_wct == 12) { 135 rc = smbsr_decode_vwv(sr, "wwll12.", &sr->smb_fid, 136 ¶m->w_count, &off, &last_write); 137 } else { 138 rc = smbsr_decode_vwv(sr, "wwll", &sr->smb_fid, 139 ¶m->w_count, &off, &last_write); 140 } 141 142 if (rc != 0) { 143 kmem_free(param, sizeof (smb_write_param_t)); 144 return (SDRC_ERROR_REPLY); 145 } 146 147 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 148 if (sr->fid_ofile == NULL) { 149 kmem_free(param, sizeof (smb_write_param_t)); 150 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 151 return (SDRC_ERROR_REPLY); 152 } 153 154 param->w_offset = (uint64_t)off; 155 156 if (param->w_count == 0) { 157 rc = smb_write_truncate(sr, param); 158 } else { 159 /* 160 * There may be a bug here: should this be "3.#B"? 161 */ 162 rc = smbsr_decode_data(sr, ".#B", param->w_count, 163 ¶m->w_vdb); 164 165 if ((rc != 0) || (param->w_vdb.len != param->w_count)) { 166 kmem_free(param, sizeof (smb_write_param_t)); 167 return (SDRC_ERROR_REPLY); 168 } 169 170 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 171 172 rc = smb_write_common(sr, param); 173 } 174 175 if (rc != 0) { 176 kmem_free(param, sizeof (smb_write_param_t)); 177 smbsr_errno(sr, rc); 178 return (SDRC_ERROR_REPLY); 179 } 180 181 if ((rc = smb_common_close(sr, last_write)) != 0) { 182 kmem_free(param, sizeof (smb_write_param_t)); 183 smbsr_errno(sr, rc); 184 return (SDRC_ERROR_REPLY); 185 } 186 187 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0); 188 kmem_free(param, sizeof (smb_write_param_t)); 189 return ((rc == 0) ? SDRC_NORMAL_REPLY : SDRC_ERROR_REPLY); 190 } 191 192 /* 193 * Write count bytes to a file at the specified offset and then unlock 194 * them. Write behind is safe because the client should have the range 195 * locked and this request is allowed to extend the file - note that 196 * offest is limited to 32-bits. It is an error for count to be zero. 197 * 198 * The SmbLockAndRead/SmbWriteAndUnlock sub-dialect is only valid on disk 199 * files. Reject any attempt to use it on other shares. 200 * 201 * The response count indicates the actual number of bytes written, which 202 * will equal the requested count on success. If request and response 203 * counts differ but there is no error, the client will assume that the 204 * server encountered a resource issue. 205 */ 206 smb_sdrc_t 207 smb_com_write_and_unlock(struct smb_request *sr) 208 { 209 smb_write_param_t *param; 210 uint32_t off; 211 uint32_t result; 212 uint16_t remcnt; 213 int rc = 0; 214 215 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 216 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess); 217 return (SDRC_ERROR_REPLY); 218 } 219 220 param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 221 222 rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid, ¶m->w_count, &off, 223 &remcnt); 224 if (rc != 0) { 225 kmem_free(param, sizeof (smb_write_param_t)); 226 return (SDRC_ERROR_REPLY); 227 } 228 229 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 230 if (sr->fid_ofile == NULL) { 231 kmem_free(param, sizeof (smb_write_param_t)); 232 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 233 return (SDRC_ERROR_REPLY); 234 } 235 236 if (param->w_count == 0) { 237 kmem_free(param, sizeof (smb_write_param_t)); 238 return (SDRC_ERROR_REPLY); 239 } 240 241 rc = smbsr_decode_data(sr, "D", ¶m->w_vdb); 242 243 if ((rc != 0) || (param->w_count != param->w_vdb.len)) { 244 kmem_free(param, sizeof (smb_write_param_t)); 245 return (SDRC_ERROR_REPLY); 246 } 247 248 param->w_offset = (uint64_t)off; 249 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 250 251 if ((rc = smb_write_common(sr, param)) != 0) { 252 kmem_free(param, sizeof (smb_write_param_t)); 253 smbsr_errno(sr, rc); 254 return (SDRC_ERROR_REPLY); 255 } 256 257 result = smb_unlock_range(sr, sr->fid_ofile->f_node, param->w_offset, 258 (uint64_t)param->w_count); 259 if (result != NT_STATUS_SUCCESS) { 260 kmem_free(param, sizeof (smb_write_param_t)); 261 smbsr_error(sr, NT_STATUS_RANGE_NOT_LOCKED, 262 ERRDOS, ERRnotlocked); 263 return (SDRC_ERROR_REPLY); 264 } 265 266 rc = smbsr_encode_result(sr, 1, 0, "bww", 1, param->w_count, 0); 267 kmem_free(param, sizeof (smb_write_param_t)); 268 return ((rc == 0) ? SDRC_NORMAL_REPLY : SDRC_ERROR_REPLY); 269 } 270 271 /* 272 * Write bytes to a file (SMB Core). This request was extended in 273 * LM 0.12 to support 64-bit offsets, indicated by sending a wct of 274 * 14, instead of 12, and including additional offset information. 275 * 276 * A ByteCount of 0 does not truncate the file - use SMB_COM_WRITE 277 * to truncate a file. A zero length merely transfers zero bytes. 278 * 279 * If bit 0 of WriteMode is set, Fid must refer to a disk file and 280 * the data must be on stable storage before responding. 281 */ 282 smb_sdrc_t 283 smb_com_write_andx(struct smb_request *sr) 284 { 285 smb_write_param_t *param; 286 uint32_t off_low; 287 uint32_t off_high; 288 uint16_t data_offset; 289 uint16_t remcnt; 290 int rc = 0; 291 292 param = kmem_zalloc(sizeof (smb_write_param_t), KM_SLEEP); 293 294 if (sr->smb_wct == 14) { 295 rc = smbsr_decode_vwv(sr, "4.wl4.ww2.wwl", &sr->smb_fid, 296 &off_low, ¶m->w_mode, &remcnt, ¶m->w_count, 297 &data_offset, &off_high); 298 299 data_offset -= 63; 300 param->w_offset = ((uint64_t)off_high << 32) | off_low; 301 } else { 302 rc = smbsr_decode_vwv(sr, "4.wl4.ww2.ww", &sr->smb_fid, 303 &off_low, ¶m->w_mode, &remcnt, ¶m->w_count, 304 &data_offset); 305 306 param->w_offset = (uint64_t)off_low; 307 data_offset -= 59; 308 } 309 310 if (rc != 0) { 311 kmem_free(param, sizeof (smb_write_param_t)); 312 return (SDRC_ERROR_REPLY); 313 } 314 315 sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid); 316 if (sr->fid_ofile == NULL) { 317 kmem_free(param, sizeof (smb_write_param_t)); 318 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 319 return (SDRC_ERROR_REPLY); 320 } 321 322 if (SMB_WRMODE_IS_STABLE(param->w_mode) && 323 STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) { 324 kmem_free(param, sizeof (smb_write_param_t)); 325 smbsr_error(sr, 0, ERRSRV, ERRaccess); 326 return (SDRC_ERROR_REPLY); 327 } 328 329 rc = smbsr_decode_data(sr, "#.#B", data_offset, param->w_count, 330 ¶m->w_vdb); 331 if ((rc != 0) || (param->w_vdb.len != param->w_count)) { 332 kmem_free(param, sizeof (smb_write_param_t)); 333 return (SDRC_ERROR_REPLY); 334 } 335 336 param->w_vdb.uio.uio_loffset = (offset_t)param->w_offset; 337 338 if (param->w_count != 0) { 339 if ((rc = smb_write_common(sr, param)) != 0) { 340 kmem_free(param, sizeof (smb_write_param_t)); 341 smbsr_errno(sr, rc); 342 return (SDRC_ERROR_REPLY); 343 } 344 } 345 346 rc = smbsr_encode_result(sr, 6, 0, "bb1.ww6.w", 347 6, sr->andx_com, 15, param->w_count, 0); 348 349 kmem_free(param, sizeof (smb_write_param_t)); 350 return ((rc == 0) ? SDRC_NORMAL_REPLY : SDRC_ERROR_REPLY); 351 } 352 353 /* 354 * Common function for writing files or IPC/MSRPC named pipes. 355 * 356 * Returns errno values. 357 */ 358 static int 359 smb_write_common(struct smb_request *sr, smb_write_param_t *param) 360 { 361 struct smb_ofile *ofile = sr->fid_ofile; 362 smb_node_t *node; 363 uint32_t stability = FSSTAB_UNSTABLE; 364 uint32_t lcount; 365 int rc = 0; 366 367 switch (sr->tid_tree->t_res_type & STYPE_MASK) { 368 case STYPE_DISKTREE: 369 node = ofile->f_node; 370 371 if (node->attr.sa_vattr.va_type != VDIR) { 372 rc = smb_lock_range_access(sr, node, param->w_offset, 373 param->w_count, B_TRUE); 374 if (rc != NT_STATUS_SUCCESS) 375 return (EPERM); 376 } 377 378 if (SMB_WRMODE_IS_STABLE(param->w_mode) || 379 (node->flags & NODE_FLAGS_WRITE_THROUGH)) { 380 stability = FSSTAB_FILE_SYNC; 381 } 382 383 rc = smb_fsop_write(sr, sr->user_cr, node, 384 ¶m->w_vdb.uio, &lcount, &node->attr, &stability); 385 386 if (rc) 387 return (rc); 388 389 node->flags |= NODE_FLAGS_SYNCATIME; 390 391 if (node->flags & NODE_FLAGS_SET_SIZE) { 392 if ((param->w_offset + lcount) >= node->n_size) { 393 node->flags &= ~NODE_FLAGS_SET_SIZE; 394 node->n_size = param->w_offset + lcount; 395 } 396 } 397 398 param->w_count = (uint16_t)lcount; 399 break; 400 401 case STYPE_IPC: 402 param->w_count = (uint16_t)param->w_vdb.uio.uio_resid; 403 404 if ((rc = smb_rpc_write(sr, ¶m->w_vdb.uio)) != 0) 405 param->w_count = 0; 406 break; 407 408 default: 409 rc = EACCES; 410 break; 411 } 412 413 if (rc != 0) 414 return (rc); 415 416 mutex_enter(&ofile->f_mutex); 417 ofile->f_seek_pos = param->w_offset + param->w_count; 418 mutex_exit(&ofile->f_mutex); 419 return (rc); 420 } 421 422 /* 423 * Truncate a disk file to the specified offset. 424 * Typically, w_count will be zero here. 425 * 426 * Returns errno values. 427 */ 428 static int 429 smb_write_truncate(struct smb_request *sr, smb_write_param_t *param) 430 { 431 struct smb_ofile *ofile = sr->fid_ofile; 432 smb_node_t *node = ofile->f_node; 433 boolean_t append_only = B_FALSE; 434 uint32_t status; 435 int rc; 436 437 if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) 438 return (0); 439 440 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, FILE_WRITE_DATA); 441 if (status != NT_STATUS_SUCCESS) { 442 status = smb_ofile_access(sr->fid_ofile, sr->user_cr, 443 FILE_APPEND_DATA); 444 if (status != NT_STATUS_SUCCESS) 445 return (EACCES); 446 else 447 append_only = B_TRUE; 448 } 449 450 smb_rwx_xenter(&node->n_lock); 451 452 if (append_only && (param->w_offset < node->n_size)) { 453 smb_rwx_xexit(&node->n_lock); 454 return (EACCES); 455 } 456 457 if (node->attr.sa_vattr.va_type != VDIR) { 458 status = smb_lock_range_access(sr, node, param->w_offset, 459 param->w_count, B_TRUE); 460 if (status != NT_STATUS_SUCCESS) { 461 smb_rwx_xexit(&node->n_lock); 462 return (EACCES); 463 } 464 } 465 466 node->flags |= NODE_FLAGS_SET_SIZE; 467 node->n_size = param->w_offset; 468 469 smb_rwx_xexit(&node->n_lock); 470 471 if ((rc = smb_set_file_size(sr)) != 0) 472 return (rc); 473 474 mutex_enter(&ofile->f_mutex); 475 ofile->f_seek_pos = param->w_offset + param->w_count; 476 mutex_exit(&ofile->f_mutex); 477 return (0); 478 } 479 480 /* 481 * Set the file size using the value in the node. The file will only be 482 * updated if NODE_FLAGS_SET_SIZE is set. It is safe to pass a null node 483 * pointer, we just return success. 484 * 485 * The node attributes are refreshed here from the file system. So any 486 * attributes that are affected by file size changes, i.e. the mtime, 487 * will be current. 488 * 489 * Note that smb_write_andx cannot be used to reduce the file size so, 490 * if this is required, smb_write is called with a count of zero and 491 * the appropriate file length in offset. The file should be resized 492 * to the length specified by the offset. 493 * 494 * Returns 0 on success. Otherwise returns EACCES. 495 */ 496 int 497 smb_set_file_size(struct smb_request *sr) 498 { 499 struct smb_node *node; 500 smb_attr_t new_attr; 501 uint32_t dosattr; 502 503 if ((node = sr->fid_ofile->f_node) == 0) 504 return (0); 505 506 if ((node->flags & NODE_FLAGS_SET_SIZE) == 0) 507 return (0); 508 509 node->flags &= ~NODE_FLAGS_SET_SIZE; 510 511 dosattr = smb_node_get_dosattr(node); 512 513 if (dosattr & SMB_FA_READONLY) { 514 if (((node->flags & NODE_FLAGS_CREATED) == 0) || 515 (sr->session->s_kid != node->n_orig_session_id)) 516 return (EACCES); 517 } 518 519 bzero(&new_attr, sizeof (new_attr)); 520 new_attr.sa_vattr.va_size = node->n_size; 521 new_attr.sa_mask = SMB_AT_SIZE; 522 523 (void) smb_fsop_setattr(sr, sr->user_cr, node, &new_attr, 524 &node->attr); 525 526 return (0); 527 } 528 529 /* 530 * write_complete is sent acknowledge completion of raw write requests. 531 * We never send raw write commands to other servers so, if we receive a 532 * write_complete, we treat it as an error. 533 */ 534 smb_sdrc_t /*ARGSUSED*/ 535 smb_com_write_complete(struct smb_request *sr) 536 { 537 return (SDRC_ERROR_REPLY); 538 } 539 540 /* 541 * The Write Block Multiplexed protocol is used to maximize performance 542 * when writing a large block of data. 543 * 544 * The mpx sub protocol is not supported because we support only 545 * connection oriented transports and NT supports SMB_COM_READ_MPX 546 * only over connectionless transports. 547 */ 548 smb_sdrc_t /*ARGSUSED*/ 549 smb_com_write_mpx(struct smb_request *sr) 550 { 551 return (SDRC_UNIMPLEMENTED); 552 } 553 554 smb_sdrc_t /*ARGSUSED*/ 555 smb_com_write_mpx_secondary(struct smb_request *sr) 556 { 557 return (SDRC_UNIMPLEMENTED); 558 } 559