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