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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Trans2 Set File/Path Information Levels: 28 * 29 * SMB_INFO_STANDARD 30 * SMB_INFO_SET_EAS 31 * SMB_SET_FILE_BASIC_INFO 32 * SMB_SET_FILE_DISPOSITION_INFO 33 * SMB_SET_FILE_END_OF_FILE_INFO 34 * SMB_SET_FILE_ALLOCATION_INFO 35 * 36 * Handled Passthrough levels: 37 * SMB_FILE_BASIC_INFORMATION 38 * SMB_FILE_RENAME_INFORMATION 39 * SMB_FILE_LINK_INFORMATION 40 * SMB_FILE_DISPOSITION_INFORMATION 41 * SMB_FILE_END_OF_FILE_INFORMATION 42 * SMB_FILE_ALLOCATION_INFORMATION 43 * 44 * Internal levels representing non trans2 requests 45 * SMB_SET_INFORMATION 46 * SMB_SET_INFORMATION2 47 */ 48 49 /* 50 * Setting timestamps: 51 * The behaviour when the time field is set to -1 is not documented 52 * but is generally treated like 0, meaning that that server file 53 * system assigned value need not be changed. 54 * 55 * Setting attributes - FILE_ATTRIBUTE_NORMAL: 56 * SMB_SET_INFORMATION - 57 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 58 * do NOT change the file's attributes. 59 * SMB_SET_BASIC_INFO - 60 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 61 * clear (0) the file's attributes. 62 * - if the specified attributes are 0 do NOT change the file's 63 * attributes. 64 */ 65 66 #include <smbsrv/smb_kproto.h> 67 #include <smbsrv/smb_fsops.h> 68 69 typedef struct smb_setinfo { 70 uint16_t si_infolev; 71 smb_xa_t *si_xa; 72 smb_node_t *si_node; 73 } smb_setinfo_t; 74 75 /* 76 * These functions all return 0 (success) or -1 (error). 77 * They set error details in the sr when appropriate. 78 */ 79 static int smb_set_by_fid(smb_request_t *, smb_xa_t *, uint16_t); 80 static int smb_set_by_path(smb_request_t *, smb_xa_t *, uint16_t); 81 static int smb_set_fileinfo(smb_request_t *, smb_setinfo_t *); 82 static int smb_set_information(smb_request_t *, smb_setinfo_t *); 83 static int smb_set_information2(smb_request_t *, smb_setinfo_t *); 84 static int smb_set_standard_info(smb_request_t *, smb_setinfo_t *); 85 static int smb_set_basic_info(smb_request_t *, smb_setinfo_t *); 86 static int smb_set_disposition_info(smb_request_t *, smb_setinfo_t *); 87 static int smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *); 88 static int smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *); 89 static int smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *); 90 91 /* 92 * smb_com_trans2_set_file_information 93 */ 94 smb_sdrc_t 95 smb_com_trans2_set_file_information(smb_request_t *sr, smb_xa_t *xa) 96 { 97 uint16_t infolev; 98 99 if (smb_mbc_decodef(&xa->req_param_mb, "ww", 100 &sr->smb_fid, &infolev) != 0) 101 return (SDRC_ERROR); 102 103 if (smb_set_by_fid(sr, xa, infolev) != 0) 104 return (SDRC_ERROR); 105 106 return (SDRC_SUCCESS); 107 } 108 109 /* 110 * smb_com_trans2_set_path_information 111 */ 112 smb_sdrc_t 113 smb_com_trans2_set_path_information(smb_request_t *sr, smb_xa_t *xa) 114 { 115 uint16_t infolev; 116 smb_fqi_t *fqi = &sr->arg.dirop.fqi; 117 118 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 119 smbsr_error(sr, NT_STATUS_INVALID_DEVICE_REQUEST, 120 ERRDOS, ERROR_INVALID_FUNCTION); 121 return (SDRC_ERROR); 122 } 123 124 if (smb_mbc_decodef(&xa->req_param_mb, "%w4.u", 125 sr, &infolev, &fqi->fq_path.pn_path) != 0) 126 return (SDRC_ERROR); 127 128 if (smb_set_by_path(sr, xa, infolev) != 0) 129 return (SDRC_ERROR); 130 131 return (SDRC_SUCCESS); 132 } 133 134 /* 135 * smb_com_set_information (aka setattr) 136 */ 137 smb_sdrc_t 138 smb_pre_set_information(smb_request_t *sr) 139 { 140 DTRACE_SMB_1(op__SetInformation__start, smb_request_t *, sr); 141 return (SDRC_SUCCESS); 142 } 143 144 void 145 smb_post_set_information(smb_request_t *sr) 146 { 147 DTRACE_SMB_1(op__SetInformation__done, smb_request_t *, sr); 148 } 149 150 smb_sdrc_t 151 smb_com_set_information(smb_request_t *sr) 152 { 153 uint16_t infolev = SMB_SET_INFORMATION; 154 smb_fqi_t *fqi = &sr->arg.dirop.fqi; 155 156 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) { 157 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 158 ERRDOS, ERROR_ACCESS_DENIED); 159 return (SDRC_ERROR); 160 } 161 162 if (smbsr_decode_data(sr, "%S", sr, &fqi->fq_path.pn_path) != 0) 163 return (SDRC_ERROR); 164 165 if (smb_set_by_path(sr, NULL, infolev) != 0) 166 return (SDRC_ERROR); 167 168 if (smbsr_encode_empty_result(sr) != 0) 169 return (SDRC_ERROR); 170 171 return (SDRC_SUCCESS); 172 } 173 174 /* 175 * smb_com_set_information2 (aka setattre) 176 */ 177 smb_sdrc_t 178 smb_pre_set_information2(smb_request_t *sr) 179 { 180 DTRACE_SMB_1(op__SetInformation2__start, smb_request_t *, sr); 181 return (SDRC_SUCCESS); 182 } 183 184 void 185 smb_post_set_information2(smb_request_t *sr) 186 { 187 DTRACE_SMB_1(op__SetInformation2__done, smb_request_t *, sr); 188 } 189 190 smb_sdrc_t 191 smb_com_set_information2(smb_request_t *sr) 192 { 193 uint16_t infolev = SMB_SET_INFORMATION2; 194 195 if (smbsr_decode_vwv(sr, "w", &sr->smb_fid) != 0) 196 return (SDRC_ERROR); 197 198 if (smb_set_by_fid(sr, NULL, infolev) != 0) 199 return (SDRC_ERROR); 200 201 if (smbsr_encode_empty_result(sr) != 0) 202 return (SDRC_ERROR); 203 204 return (SDRC_SUCCESS); 205 } 206 207 /* 208 * smb_set_by_fid 209 * 210 * Common code for setting file information by open file id. 211 * Use the id to identify the node object and invoke smb_set_fileinfo 212 * for that node. 213 * 214 * Setting attributes on a named pipe by id is handled by simply 215 * returning success. 216 */ 217 static int 218 smb_set_by_fid(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) 219 { 220 int rc; 221 smb_setinfo_t sinfo; 222 223 if (SMB_TREE_IS_READONLY(sr)) { 224 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 225 ERRDOS, ERROR_ACCESS_DENIED); 226 return (-1); 227 } 228 229 if (STYPE_ISIPC(sr->tid_tree->t_res_type)) 230 return (0); 231 232 smbsr_lookup_file(sr); 233 if (sr->fid_ofile == NULL) { 234 smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 235 return (-1); 236 } 237 238 if (!SMB_FTYPE_IS_DISK(sr->fid_ofile->f_ftype)) { 239 smbsr_release_file(sr); 240 return (0); 241 } 242 243 sr->user_cr = smb_ofile_getcred(sr->fid_ofile); 244 245 sinfo.si_xa = xa; 246 sinfo.si_infolev = infolev; 247 sinfo.si_node = sr->fid_ofile->f_node; 248 rc = smb_set_fileinfo(sr, &sinfo); 249 250 smbsr_release_file(sr); 251 return (rc); 252 } 253 254 /* 255 * smb_set_by_path 256 * 257 * Common code for setting file information by file name. 258 * Use the file name to identify the node object and invoke 259 * smb_set_fileinfo for that node. 260 * 261 * Path should be set in sr->arg.dirop.fqi.fq_path prior to 262 * calling smb_set_by_path. 263 * 264 * Setting attributes on a named pipe by name is an error and 265 * is handled in the calling functions so that they can return 266 * the appropriate error status code (which differs by caller). 267 */ 268 static int 269 smb_set_by_path(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev) 270 { 271 int rc; 272 smb_setinfo_t sinfo; 273 smb_node_t *node, *dnode; 274 char *name; 275 smb_pathname_t *pn; 276 277 if (SMB_TREE_IS_READONLY(sr)) { 278 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 279 ERRDOS, ERROR_ACCESS_DENIED); 280 return (-1); 281 } 282 283 pn = &sr->arg.dirop.fqi.fq_path; 284 smb_pathname_init(sr, pn, pn->pn_path); 285 if (!smb_pathname_validate(sr, pn)) 286 return (-1); 287 288 name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 289 rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path, 290 sr->tid_tree->t_snode, sr->tid_tree->t_snode, &dnode, name); 291 if (rc == 0) { 292 rc = smb_fsop_lookup_name(sr, sr->user_cr, SMB_FOLLOW_LINKS, 293 sr->tid_tree->t_snode, dnode, name, &node); 294 smb_node_release(dnode); 295 } 296 kmem_free(name, MAXNAMELEN); 297 298 if (rc != 0) { 299 if (rc == ENOENT) { 300 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND, 301 ERRDOS, ERROR_FILE_NOT_FOUND); 302 } else { 303 smbsr_errno(sr, rc); 304 } 305 return (-1); 306 } 307 308 sinfo.si_xa = xa; 309 sinfo.si_infolev = infolev; 310 sinfo.si_node = node; 311 rc = smb_set_fileinfo(sr, &sinfo); 312 313 smb_node_release(node); 314 return (rc); 315 } 316 317 /* 318 * smb_set_fileinfo 319 * 320 * For compatibility with windows servers, SMB_FILE_LINK_INFORMATION 321 * is handled by returning NT_STATUS_NOT_SUPPORTED. 322 */ 323 static int 324 smb_set_fileinfo(smb_request_t *sr, smb_setinfo_t *sinfo) 325 { 326 switch (sinfo->si_infolev) { 327 case SMB_SET_INFORMATION: 328 return (smb_set_information(sr, sinfo)); 329 330 case SMB_SET_INFORMATION2: 331 return (smb_set_information2(sr, sinfo)); 332 333 case SMB_INFO_STANDARD: 334 return (smb_set_standard_info(sr, sinfo)); 335 336 case SMB_INFO_SET_EAS: 337 /* EAs not supported */ 338 return (0); 339 340 case SMB_SET_FILE_BASIC_INFO: 341 case SMB_FILE_BASIC_INFORMATION: 342 return (smb_set_basic_info(sr, sinfo)); 343 344 case SMB_SET_FILE_DISPOSITION_INFO: 345 case SMB_FILE_DISPOSITION_INFORMATION: 346 return (smb_set_disposition_info(sr, sinfo)); 347 348 case SMB_SET_FILE_END_OF_FILE_INFO: 349 case SMB_FILE_END_OF_FILE_INFORMATION: 350 return (smb_set_eof_info(sr, sinfo)); 351 352 case SMB_SET_FILE_ALLOCATION_INFO: 353 case SMB_FILE_ALLOCATION_INFORMATION: 354 return (smb_set_alloc_info(sr, sinfo)); 355 356 case SMB_FILE_RENAME_INFORMATION: 357 return (smb_set_rename_info(sr, sinfo)); 358 359 case SMB_FILE_LINK_INFORMATION: 360 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, 361 ERRDOS, ERROR_NOT_SUPPORTED); 362 return (-1); 363 default: 364 break; 365 } 366 367 smbsr_error(sr, NT_STATUS_INVALID_INFO_CLASS, 368 ERRDOS, ERROR_INVALID_PARAMETER); 369 return (-1); 370 } 371 372 /* 373 * smb_set_information 374 * 375 * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the 376 * target is not a directory. 377 * 378 * For compatibility with Windows Servers, if the specified 379 * attributes have ONLY FILE_ATTRIBUTE_NORMAL set do NOT change 380 * the file's attributes. 381 */ 382 static int 383 smb_set_information(smb_request_t *sr, smb_setinfo_t *sinfo) 384 { 385 int rc; 386 uint16_t attributes; 387 smb_node_t *node = sinfo->si_node; 388 smb_attr_t attr; 389 uint32_t mtime; 390 391 if (smbsr_decode_vwv(sr, "wl10.", &attributes, &mtime) != 0) 392 return (-1); 393 394 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) && 395 (!smb_node_is_dir(node))) { 396 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 397 ERRDOS, ERROR_INVALID_PARAMETER); 398 return (-1); 399 } 400 401 bzero(&attr, sizeof (smb_attr_t)); 402 if (attributes != FILE_ATTRIBUTE_NORMAL) { 403 attr.sa_dosattr = attributes; 404 attr.sa_mask |= SMB_AT_DOSATTR; 405 } 406 407 if (mtime != 0 && mtime != UINT_MAX) { 408 attr.sa_vattr.va_mtime.tv_sec = 409 smb_time_local_to_gmt(sr, mtime); 410 attr.sa_mask |= SMB_AT_MTIME; 411 } 412 413 rc = smb_node_setattr(sr, node, sr->user_cr, NULL, &attr); 414 if (rc != 0) { 415 smbsr_errno(sr, rc); 416 return (-1); 417 } 418 419 return (0); 420 } 421 422 /* 423 * smb_set_information2 424 */ 425 static int 426 smb_set_information2(smb_request_t *sr, smb_setinfo_t *sinfo) 427 { 428 int rc; 429 uint32_t crtime, atime, mtime; 430 smb_attr_t attr; 431 432 if (smbsr_decode_vwv(sr, "yyy", &crtime, &atime, &mtime) != 0) 433 return (-1); 434 435 bzero(&attr, sizeof (smb_attr_t)); 436 if (mtime != 0 && mtime != UINT_MAX) { 437 attr.sa_vattr.va_mtime.tv_sec = 438 smb_time_local_to_gmt(sr, mtime); 439 attr.sa_mask |= SMB_AT_MTIME; 440 } 441 442 if (crtime != 0 && crtime != UINT_MAX) { 443 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime); 444 attr.sa_mask |= SMB_AT_CRTIME; 445 } 446 447 if (atime != 0 && atime != UINT_MAX) { 448 attr.sa_vattr.va_atime.tv_sec = 449 smb_time_local_to_gmt(sr, atime); 450 attr.sa_mask |= SMB_AT_ATIME; 451 } 452 453 rc = smb_node_setattr(sr, sinfo->si_node, sr->user_cr, 454 sr->fid_ofile, &attr); 455 if (rc != 0) { 456 smbsr_errno(sr, rc); 457 return (-1); 458 } 459 460 return (0); 461 } 462 463 /* 464 * smb_set_standard_info 465 * 466 * Sets standard file/path information. 467 */ 468 static int 469 smb_set_standard_info(smb_request_t *sr, smb_setinfo_t *sinfo) 470 { 471 smb_attr_t attr; 472 uint32_t crtime, atime, mtime; 473 smb_node_t *node = sinfo->si_node; 474 int rc; 475 476 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "yyy", 477 &crtime, &atime, &mtime) != 0) { 478 return (-1); 479 } 480 481 bzero(&attr, sizeof (smb_attr_t)); 482 if (mtime != 0 && mtime != (uint32_t)-1) { 483 attr.sa_vattr.va_mtime.tv_sec = 484 smb_time_local_to_gmt(sr, mtime); 485 attr.sa_mask |= SMB_AT_MTIME; 486 } 487 488 if (crtime != 0 && crtime != (uint32_t)-1) { 489 attr.sa_crtime.tv_sec = smb_time_local_to_gmt(sr, crtime); 490 attr.sa_mask |= SMB_AT_CRTIME; 491 } 492 493 if (atime != 0 && atime != (uint32_t)-1) { 494 attr.sa_vattr.va_atime.tv_sec = 495 smb_time_local_to_gmt(sr, atime); 496 attr.sa_mask |= SMB_AT_ATIME; 497 } 498 499 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 500 if (rc != 0) { 501 smbsr_errno(sr, rc); 502 return (-1); 503 } 504 505 return (0); 506 } 507 508 /* 509 * smb_set_basic_info 510 * 511 * Sets basic file/path information. 512 * 513 * It is not valid to set FILE_ATTRIBUTE_DIRECTORY if the 514 * target is not a directory. 515 * 516 * For compatibility with windows servers: 517 * - if the specified attributes have ONLY FILE_ATTRIBUTE_NORMAL set 518 * clear (0) the file's attributes. 519 * - if the specified attributes are 0 do NOT change the file's attributes. 520 */ 521 static int 522 smb_set_basic_info(smb_request_t *sr, smb_setinfo_t *sinfo) 523 { 524 int rc; 525 uint64_t crtime, atime, mtime, ctime; 526 uint16_t attributes; 527 smb_attr_t attr; 528 smb_node_t *node = sinfo->si_node; 529 530 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "qqqqw", 531 &crtime, &atime, &mtime, &ctime, &attributes) != 0) { 532 return (-1); 533 } 534 535 if ((attributes & FILE_ATTRIBUTE_DIRECTORY) && 536 (!smb_node_is_dir(node))) { 537 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 538 ERRDOS, ERROR_INVALID_PARAMETER); 539 return (-1); 540 } 541 542 bzero(&attr, sizeof (smb_attr_t)); 543 if (ctime != 0 && ctime != (uint64_t)-1) { 544 smb_time_nt_to_unix(ctime, &attr.sa_vattr.va_ctime); 545 attr.sa_mask |= SMB_AT_CTIME; 546 } 547 548 if (crtime != 0 && crtime != (uint64_t)-1) { 549 smb_time_nt_to_unix(crtime, &attr.sa_crtime); 550 attr.sa_mask |= SMB_AT_CRTIME; 551 } 552 553 if (mtime != 0 && mtime != (uint64_t)-1) { 554 smb_time_nt_to_unix(mtime, &attr.sa_vattr.va_mtime); 555 attr.sa_mask |= SMB_AT_MTIME; 556 } 557 558 if (atime != 0 && atime != (uint64_t)-1) { 559 smb_time_nt_to_unix(atime, &attr.sa_vattr.va_atime); 560 attr.sa_mask |= SMB_AT_ATIME; 561 } 562 563 if (attributes != 0) { 564 attr.sa_dosattr = attributes; 565 attr.sa_mask |= SMB_AT_DOSATTR; 566 } 567 568 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 569 if (rc != 0) { 570 smbsr_errno(sr, rc); 571 return (-1); 572 } 573 574 return (0); 575 } 576 577 /* 578 * smb_set_eof_info 579 */ 580 static int 581 smb_set_eof_info(smb_request_t *sr, smb_setinfo_t *sinfo) 582 { 583 int rc; 584 smb_attr_t attr; 585 uint64_t eof; 586 smb_node_t *node = sinfo->si_node; 587 588 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &eof) != 0) 589 return (-1); 590 591 if (smb_node_is_dir(node)) { 592 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 593 ERRDOS, ERROR_INVALID_PARAMETER); 594 return (-1); 595 } 596 597 /* If opened by path, break exclusive oplock */ 598 if (sr->fid_ofile == NULL) 599 (void) smb_oplock_break(sr, node, 600 SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE); 601 602 bzero(&attr, sizeof (smb_attr_t)); 603 attr.sa_mask = SMB_AT_SIZE; 604 attr.sa_vattr.va_size = (u_offset_t)eof; 605 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 606 if (rc != 0) { 607 smbsr_errno(sr, rc); 608 return (-1); 609 } 610 611 smb_oplock_break_levelII(node); 612 return (0); 613 } 614 615 /* 616 * smb_set_alloc_info 617 */ 618 static int 619 smb_set_alloc_info(smb_request_t *sr, smb_setinfo_t *sinfo) 620 { 621 int rc; 622 smb_attr_t attr; 623 uint64_t allocsz; 624 smb_node_t *node = sinfo->si_node; 625 626 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "q", &allocsz) != 0) 627 return (-1); 628 629 if (smb_node_is_dir(node)) { 630 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 631 ERRDOS, ERROR_INVALID_PARAMETER); 632 return (-1); 633 } 634 635 /* If opened by path, break exclusive oplock */ 636 if (sr->fid_ofile == NULL) 637 (void) smb_oplock_break(sr, node, 638 SMB_OPLOCK_BREAK_EXCLUSIVE | SMB_OPLOCK_BREAK_TO_NONE); 639 640 bzero(&attr, sizeof (smb_attr_t)); 641 attr.sa_mask = SMB_AT_ALLOCSZ; 642 attr.sa_allocsz = (u_offset_t)allocsz; 643 rc = smb_node_setattr(sr, node, sr->user_cr, sr->fid_ofile, &attr); 644 if (rc != 0) { 645 smbsr_errno(sr, rc); 646 return (-1); 647 } 648 649 smb_oplock_break_levelII(node); 650 return (0); 651 } 652 653 /* 654 * smb_set_disposition_info 655 * 656 * Set/Clear DELETE_ON_CLOSE flag for an open file. 657 * File should have been opened with DELETE access otherwise 658 * the operation is not permitted. 659 * 660 * NOTE: The node should be marked delete-on-close upon the receipt 661 * of the Trans2SetFileInfo(SetDispositionInfo) if mark_delete is set. 662 * It is different than both SmbNtCreateAndX and SmbNtTransact, which 663 * set delete-on-close on the ofile and defer setting the flag on the 664 * node until the file is closed. 665 * 666 * Observation of Windows 2000 indicates the following: 667 * 668 * 1) If a file is not opened with delete-on-close create options and 669 * the delete-on-close is set via Trans2SetFileInfo(SetDispositionInfo) 670 * using that open file handle, any subsequent open requests will fail 671 * with DELETE_PENDING. 672 * 673 * 2) If a file is opened with delete-on-close create options and the 674 * client attempts to unset delete-on-close via Trans2SetFileInfo 675 * (SetDispositionInfo) prior to the file close, any subsequent open 676 * requests will still fail with DELETE_PENDING after the file is closed. 677 * 678 * 3) If a file is opened with delete-on-close create options and that 679 * file handle (not the last open handle and the only file handle 680 * with delete-on-close set) is closed. Any subsequent open requests 681 * will fail with DELETE_PENDING. Unsetting delete-on-close via 682 * Trans2SetFileInfo(SetDispositionInfo) at this time will unset the 683 * node delete-on-close flag, which will result in the file not being 684 * removed even after the last file handle is closed. 685 */ 686 static int 687 smb_set_disposition_info(smb_request_t *sr, smb_setinfo_t *sinfo) 688 { 689 unsigned char mark_delete; 690 uint32_t flags = 0; 691 int doserr; 692 uint32_t status; 693 694 if (smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "b", &mark_delete) != 0) 695 return (-1); 696 697 if ((sr->fid_ofile == NULL) || 698 !(smb_ofile_granted_access(sr->fid_ofile) & DELETE)) { 699 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 700 ERRDOS, ERROR_ACCESS_DENIED); 701 return (-1); 702 } 703 704 if (mark_delete) { 705 if (SMB_TREE_SUPPORTS_CATIA(sr)) 706 flags |= SMB_CATIA; 707 708 status = smb_node_set_delete_on_close(sinfo->si_node, 709 sr->user_cr, flags); 710 if (status != NT_STATUS_SUCCESS) { 711 switch (status) { 712 case NT_STATUS_CANNOT_DELETE: 713 doserr = ERROR_ACCESS_DENIED; 714 break; 715 case NT_STATUS_DIRECTORY_NOT_EMPTY: 716 doserr = ERROR_DIR_NOT_EMPTY; 717 break; 718 default: 719 doserr = ERROR_GEN_FAILURE; 720 break; 721 } 722 smbsr_error(sr, status, ERRDOS, doserr); 723 return (-1); 724 } 725 } else { 726 smb_node_reset_delete_on_close(sinfo->si_node); 727 } 728 return (0); 729 } 730 731 /* 732 * smb_set_rename_info 733 * 734 * Explicitly specified parameter validation rules: 735 * - If rootdir is not NULL respond with NT_STATUS_INVALID_PARAMETER. 736 * - If the filename contains a separator character respond with 737 * NT_STATUS_INVALID_PARAMETER. 738 * 739 * Oplock break: 740 * Some Windows servers break BATCH oplocks prior to the rename. 741 * W2K3 does not. We behave as W2K3; we do not send an oplock break. 742 */ 743 static int 744 smb_set_rename_info(smb_request_t *sr, smb_setinfo_t *sinfo) 745 { 746 int rc; 747 uint32_t flags, rootdir, namelen; 748 char *fname; 749 750 rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "lll", 751 &flags, &rootdir, &namelen); 752 if (rc == 0) { 753 rc = smb_mbc_decodef(&sinfo->si_xa->req_data_mb, "%#U", 754 sr, namelen, &fname); 755 } 756 if (rc != 0) 757 return (-1); 758 759 if ((rootdir != 0) || (namelen == 0) || (namelen >= MAXNAMELEN)) { 760 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 761 ERRDOS, ERROR_INVALID_PARAMETER); 762 return (-1); 763 } 764 765 if (strchr(fname, '\\') != NULL) { 766 smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, 767 ERRDOS, ERROR_NOT_SUPPORTED); 768 return (-1); 769 } 770 771 rc = smb_trans2_rename(sr, sinfo->si_node, fname, flags); 772 773 return ((rc == 0) ? 0 : -1); 774 } 775