Print this page
NEX-13644 File access audit logging
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-5665 SMB2 oplock leases
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-2831 panic in smb_make_link
NEX-2442 regression with smbtorture test raw.sfileinfo.rename
NEX-1920 SMB rename from Win2k8 fails
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)


   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 #include <sys/synch.h>
  27 #include <smbsrv/smb_kproto.h>
  28 #include <smbsrv/smb_fsops.h>
  29 #include <sys/nbmlock.h>
  30 
  31 /*
  32  * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
  33  */
  34 #define SMB_RENAME_FLAG_OVERWRITE       0x001
  35 
  36 static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
  37 static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
  38 static int smb_rename_lookup_src(smb_request_t *);

  39 static void smb_rename_release_src(smb_request_t *);
  40 static uint32_t smb_rename_errno2status(int);
  41 
  42 /*
  43  * smb_setinfo_rename
  44  *
  45  * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
  46  * and Trans2_Set_PathInfo and SMB2 set_info, FileRenameInformation.
  47  * If the new filename (dst_fqi) already exists it may be overwritten
  48  * if flags == 1.
  49  *
  50  * The passed path is a full path relative to the share root.
  51  *
  52  * Returns NT status codes.
  53  *
  54  * Similar to smb_setinfo_link(), below.
  55  */
  56 uint32_t
  57 smb_setinfo_rename(smb_request_t *sr, smb_node_t *node, char *path, int flags)
  58 {


  82  *
  83  * Common code for renaming a file.
  84  *
  85  * If the source and destination are identical, we go through all
  86  * the checks but we don't actually do the rename.  If the source
  87  * and destination files differ only in case, we do a case-sensitive
  88  * rename.  Otherwise, we do a full case-insensitive rename.
  89  *
  90  * Returns NT status values.
  91  *
  92  * Similar to smb_make_link(), below.
  93  */
  94 uint32_t
  95 smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
  96 {
  97         smb_node_t *src_fnode, *src_dnode, *dst_dnode;
  98         smb_node_t *dst_fnode = 0;
  99         smb_node_t *tnode;
 100         char *new_name, *path;
 101         DWORD status;
 102         int rc, count;





 103 
 104         tnode = sr->tid_tree->t_snode;
 105         path = dst_fqi->fq_path.pn_path;
 106 
 107         /* Check if attempting to rename a stream - not yet supported */
 108         rc = smb_rename_check_stream(src_fqi, dst_fqi);
 109         if (rc != 0)
 110                 return (smb_rename_errno2status(rc));
 111 
 112         /*
 113          * The source node may already have been provided,
 114          * i.e. when called by SMB1/SMB2 smb_setinfo_rename.
 115          * Not provided by smb_com_rename, smb_com_nt_rename.


 116          */
 117         if (src_fqi->fq_fnode) {
 118                 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
 119                 smb_node_ref(src_fqi->fq_fnode);
 120                 smb_node_ref(src_fqi->fq_dnode);


 121         } else {
 122                 /* lookup and validate src node */
 123                 rc = smb_rename_lookup_src(sr);
 124                 if (rc != 0)
 125                         return (smb_rename_errno2status(rc));

 126         }
 127 
 128         src_fnode = src_fqi->fq_fnode;
 129         src_dnode = src_fqi->fq_dnode;
 130 







 131         /*






 132          * Find the destination dnode and last component.
 133          * May already be provided, i.e. when called via
 134          * SMB1 trans2 setinfo.
 135          */
 136         if (dst_fqi->fq_dnode) {
 137                 /* called via smb_set_rename_info */
 138                 smb_node_ref(dst_fqi->fq_dnode);
 139         } else {
 140                 /* called via smb2_setf_rename, smb_com_rename, etc. */
 141                 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 142                     &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
 143                 if (rc != 0) {
 144                         smb_rename_release_src(sr);
 145                         return (smb_rename_errno2status(rc));
 146                 }
 147         }
 148 
 149         dst_dnode = dst_fqi->fq_dnode;
 150         new_name = dst_fqi->fq_last_comp;
 151 


 217 
 218         if ((rc != 0) && (rc != ENOENT)) {
 219                 smb_rename_release_src(sr);
 220                 smb_node_release(dst_fqi->fq_dnode);
 221                 return (smb_rename_errno2status(rc));
 222         }
 223 
 224         if (dst_fqi->fq_fnode) {
 225                 /*
 226                  * Destination already exists.  Do delete checks.
 227                  */
 228                 dst_fnode = dst_fqi->fq_fnode;
 229 
 230                 if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
 231                         smb_rename_release_src(sr);
 232                         smb_node_release(dst_fnode);
 233                         smb_node_release(dst_dnode);
 234                         return (NT_STATUS_OBJECT_NAME_COLLISION);
 235                 }
 236 
 237                 (void) smb_oplock_break(sr, dst_fnode,
 238                     SMB_OPLOCK_BREAK_TO_NONE | SMB_OPLOCK_BREAK_BATCH);











 239 
 240                 /*
 241                  * Wait (a little) for the oplock break to be
 242                  * responded to by clients closing handles.
 243                  * Hold node->n_lock as reader to keep new
 244                  * ofiles from showing up after we check.
 245                  */
 246                 smb_node_rdlock(dst_fnode);
 247                 for (count = 0; count <= 12; count++) {
 248                         status = smb_node_delete_check(dst_fnode);
 249                         if (status != NT_STATUS_SHARING_VIOLATION)
 250                                 break;
 251                         smb_node_unlock(dst_fnode);
 252                         delay(MSEC_TO_TICK(100));
 253                         smb_node_rdlock(dst_fnode);
 254                 }
 255                 if (status != NT_STATUS_SUCCESS) {
 256                         smb_node_unlock(dst_fnode);
 257                         smb_rename_release_src(sr);
 258                         smb_node_release(dst_fnode);
 259                         smb_node_release(dst_dnode);
 260                         return (NT_STATUS_ACCESS_DENIED);
 261                 }
 262 
 263                 /*
 264                  * Note, the combination of these two:
 265                  *      smb_node_rdlock(node);
 266                  *      nbl_start_crit(node->vp, RW_READER);
 267                  * is equivalent to this call:
 268                  *      smb_node_start_crit(node, RW_READER)
 269                  *
 270                  * Cleanup after this point should use:
 271                  *      smb_node_end_crit(dst_fnode)
 272                  */
 273                 nbl_start_crit(dst_fnode->vp, RW_READER);
 274 
 275                 /*
 276                  * This checks nbl_share_conflict, nbl_lock_conflict
 277                  */
 278                 status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE);
 279                 if (status != NT_STATUS_SUCCESS) {
 280                         smb_node_end_crit(dst_fnode);
 281                         smb_rename_release_src(sr);
 282                         smb_node_release(dst_fnode);
 283                         smb_node_release(dst_dnode);
 284                         return (NT_STATUS_ACCESS_DENIED);
 285                 }
 286 
 287                 new_name = dst_fnode->od_name;

 288         }
 289 















 290         rc = smb_fsop_rename(sr, sr->user_cr,
 291             src_dnode, src_fnode->od_name,
 292             dst_dnode, new_name);
 293 














 294         if (rc == 0) {
 295                 /*
 296                  * Note that renames in the same directory are normally
 297                  * delivered in {old,new} pairs, and clients expect them
 298                  * in that order, if both events are delivered.
 299                  */
 300                 int a_src, a_dst; /* action codes */
 301                 if (src_dnode == dst_dnode) {
 302                         a_src = FILE_ACTION_RENAMED_OLD_NAME;
 303                         a_dst = FILE_ACTION_RENAMED_NEW_NAME;
 304                 } else {
 305                         a_src = FILE_ACTION_REMOVED;
 306                         a_dst = FILE_ACTION_ADDED;
 307                 }
 308                 smb_node_notify_change(src_dnode, a_src, src_fnode->od_name);
 309                 smb_node_notify_change(dst_dnode, a_dst, new_name);
 310         }
 311 
 312         smb_rename_release_src(sr);
 313 


 417  * Similar to smb_common_rename() above.
 418  */
 419 uint32_t
 420 smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
 421 {
 422         smb_node_t *tnode;
 423         char *path;
 424         int rc;
 425 
 426         tnode = sr->tid_tree->t_snode;
 427         path = dst_fqi->fq_path.pn_path;
 428 
 429         /* Cannnot create link on named stream */
 430         if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
 431             smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
 432                 return (NT_STATUS_INVALID_PARAMETER);
 433         }
 434 
 435         /* The source node may already have been provided */
 436         if (src_fqi->fq_fnode) {
 437                 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
 438                 smb_node_ref(src_fqi->fq_fnode);
 439                 smb_node_ref(src_fqi->fq_dnode);

 440         } else {
 441                 /* lookup and validate src node */
 442                 rc = smb_rename_lookup_src(sr);
 443                 if (rc != 0)
 444                         return (smb_rename_errno2status(rc));

 445         }
 446 
 447         /* Not valid to create hardlink for directory */
 448         if (smb_node_is_dir(src_fqi->fq_fnode)) {
 449                 smb_rename_release_src(sr);

 450                 return (NT_STATUS_FILE_IS_A_DIRECTORY);
 451         }
 452 
 453         /*







 454          * Find the destination dnode and last component.
 455          * May already be provided, i.e. when called via
 456          * SMB1 trans2 setinfo.
 457          */
 458         if (dst_fqi->fq_dnode) {
 459                 smb_node_ref(dst_fqi->fq_dnode);
 460         } else {
 461                 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 462                     &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
 463                 if (rc != 0) {
 464                         smb_rename_release_src(sr);
 465                         return (smb_rename_errno2status(rc));
 466                 }
 467         }
 468 
 469         /* If CI name match in same directory, we're done */
 470         if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
 471             (smb_strcasecmp(src_fqi->fq_fnode->od_name,
 472             dst_fqi->fq_last_comp, 0) == 0)) {
 473                 smb_rename_release_src(sr);


 493                 smb_node_release(dst_fqi->fq_dnode);
 494                 return (smb_rename_errno2status(rc));
 495         }
 496 
 497         rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
 498             dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
 499 
 500         if (rc == 0) {
 501                 smb_node_notify_change(dst_fqi->fq_dnode,
 502                     FILE_ACTION_ADDED, dst_fqi->fq_last_comp);
 503         }
 504 
 505         smb_rename_release_src(sr);
 506         smb_node_release(dst_fqi->fq_dnode);
 507         return (smb_rename_errno2status(rc));
 508 }
 509 
 510 /*
 511  * smb_rename_lookup_src
 512  *
 513  * Lookup the src node, checking for sharing violations and
 514  * breaking any existing BATCH oplock.
 515  * Populate sr->arg.dirop.fqi
 516  *
 517  * Upon success, the dnode and fnode will have holds and the
 518  * fnode will be in a critical section. These should be
 519  * released using smb_rename_release_src().
 520  *
 521  * Returns errno values.
 522  */
 523 static int
 524 smb_rename_lookup_src(smb_request_t *sr)
 525 {
 526         smb_node_t *src_node, *tnode;
 527         DWORD status;
 528         int rc;
 529         int count;
 530         char *path;

 531 
 532         smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
 533 
 534         if (smb_is_stream_name(src_fqi->fq_path.pn_path))
 535                 return (EINVAL);
 536 
 537         /* Lookup the source node */
 538         tnode = sr->tid_tree->t_snode;
 539         path = src_fqi->fq_path.pn_path;
 540         rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 541             &src_fqi->fq_dnode, src_fqi->fq_last_comp);
 542         if (rc != 0)
 543                 return (rc);

 544 
 545         rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
 546             src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
 547         if (rc != 0) {
 548                 smb_node_release(src_fqi->fq_dnode);
 549                 return (rc);
 550         }
 551         src_node = src_fqi->fq_fnode;
 552 
 553         rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr);
 554         if (rc != 0) {
 555                 smb_node_release(src_fqi->fq_fnode);
 556                 smb_node_release(src_fqi->fq_dnode);
 557                 return (rc);
 558         }
 559 





















 560         /*
 561          * Break BATCH oplock before ofile checks. If a client
 562          * has a file open, this will force a flush or close,
 563          * which may affect the outcome of any share checking.



 564          */
 565         (void) smb_oplock_break(sr, src_node,
 566             SMB_OPLOCK_BREAK_TO_LEVEL_II | SMB_OPLOCK_BREAK_BATCH);
 567 










 568         /*
 569          * Wait (a little) for the oplock break to be
 570          * responded to by clients closing handles.
 571          * Hold node->n_lock as reader to keep new
 572          * ofiles from showing up after we check.
 573          */






















 574         smb_node_rdlock(src_node);
 575         for (count = 0; count <= 12; count++) {
 576                 status = smb_node_rename_check(src_node);
 577                 if (status != NT_STATUS_SHARING_VIOLATION)
 578                         break;
 579                 smb_node_unlock(src_node);
 580                 delay(MSEC_TO_TICK(100));
 581                 smb_node_rdlock(src_node);
 582         }
 583         if (status != NT_STATUS_SUCCESS) {
 584                 smb_node_unlock(src_node);
 585                 smb_node_release(src_fqi->fq_fnode);
 586                 smb_node_release(src_fqi->fq_dnode);
 587                 return (EPIPE); /* = ERRbadshare */
 588         }
 589 






 590         /*
 591          * Note, the combination of these two:
 592          *      smb_node_rdlock(node);
 593          *      nbl_start_crit(node->vp, RW_READER);
 594          * is equivalent to this call:
 595          *      smb_node_start_crit(node, RW_READER)
 596          *
 597          * Cleanup after this point should use:
 598          *      smb_node_end_crit(src_node)
 599          */
 600         nbl_start_crit(src_node->vp, RW_READER);
 601 
 602         /*
 603          * This checks nbl_share_conflict, nbl_lock_conflict
 604          */
 605         status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME);
 606         if (status != NT_STATUS_SUCCESS) {
 607                 smb_node_end_crit(src_node);
 608                 smb_node_release(src_fqi->fq_fnode);
 609                 smb_node_release(src_fqi->fq_dnode);
 610                 if (status == NT_STATUS_SHARING_VIOLATION)
 611                         return (EPIPE); /* = ERRbadshare */
 612                 return (EACCES);
 613         }
 614 
 615         /* NB: Caller expects holds on src_fqi fnode, dnode */
 616         return (0);
 617 }
 618 
 619 /*
 620  * smb_rename_release_src
 621  */
 622 static void
 623 smb_rename_release_src(smb_request_t *sr)
 624 {
 625         smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
 626 
 627         smb_node_end_crit(src_fqi->fq_fnode);
 628         smb_node_release(src_fqi->fq_fnode);
 629         smb_node_release(src_fqi->fq_dnode);
 630 }
 631 
 632 
 633 static int
 634 smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
 635 {
 636         smb_attr_t attr;




   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 2018 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 #include <sys/synch.h>
  27 #include <smbsrv/smb2_kproto.h>
  28 #include <smbsrv/smb_fsops.h>
  29 #include <sys/nbmlock.h>
  30 
  31 /*
  32  * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag
  33  */
  34 #define SMB_RENAME_FLAG_OVERWRITE       0x001
  35 
  36 static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *);
  37 static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t);
  38 static int smb_rename_lookup_src(smb_request_t *);
  39 static uint32_t smb_rename_check_src(smb_request_t *, smb_fqi_t *);
  40 static void smb_rename_release_src(smb_request_t *);
  41 static uint32_t smb_rename_errno2status(int);
  42 
  43 /*
  44  * smb_setinfo_rename
  45  *
  46  * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo
  47  * and Trans2_Set_PathInfo and SMB2 set_info, FileRenameInformation.
  48  * If the new filename (dst_fqi) already exists it may be overwritten
  49  * if flags == 1.
  50  *
  51  * The passed path is a full path relative to the share root.
  52  *
  53  * Returns NT status codes.
  54  *
  55  * Similar to smb_setinfo_link(), below.
  56  */
  57 uint32_t
  58 smb_setinfo_rename(smb_request_t *sr, smb_node_t *node, char *path, int flags)
  59 {


  83  *
  84  * Common code for renaming a file.
  85  *
  86  * If the source and destination are identical, we go through all
  87  * the checks but we don't actually do the rename.  If the source
  88  * and destination files differ only in case, we do a case-sensitive
  89  * rename.  Otherwise, we do a full case-insensitive rename.
  90  *
  91  * Returns NT status values.
  92  *
  93  * Similar to smb_make_link(), below.
  94  */
  95 uint32_t
  96 smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
  97 {
  98         smb_node_t *src_fnode, *src_dnode, *dst_dnode;
  99         smb_node_t *dst_fnode = 0;
 100         smb_node_t *tnode;
 101         char *new_name, *path;
 102         DWORD status;
 103         int rc;
 104         boolean_t have_src = B_FALSE;
 105         boolean_t dst_exists = B_FALSE;
 106         boolean_t do_audit;
 107         char *srcpath = NULL;
 108         char *dstpath = NULL;
 109 
 110         tnode = sr->tid_tree->t_snode;
 111         path = dst_fqi->fq_path.pn_path;
 112 
 113         /* Check if attempting to rename a stream - not yet supported */
 114         rc = smb_rename_check_stream(src_fqi, dst_fqi);
 115         if (rc != 0)
 116                 return (smb_rename_errno2status(rc));
 117 
 118         /*
 119          * The source node may already have been provided,
 120          * i.e. when called by SMB1/SMB2 smb_setinfo_rename
 121          * with an ofile.  When we have an ofile, open has
 122          * already checked for sharing violations.  For
 123          * path-based operations, do sharing check here.
 124          */
 125         if (src_fqi->fq_fnode) {


 126                 smb_node_ref(src_fqi->fq_dnode);
 127                 smb_node_ref(src_fqi->fq_fnode);
 128                 have_src = B_TRUE;
 129         } else {
 130                 /* lookup and validate src node */
 131                 rc = smb_rename_lookup_src(sr);
 132                 if (rc != 0)
 133                         return (smb_rename_errno2status(rc));
 134                 /* Holding refs on dnode, fnode */
 135         }

 136         src_fnode = src_fqi->fq_fnode;
 137         src_dnode = src_fqi->fq_dnode;
 138 
 139         /* Break oplocks, and check share modes. */
 140         status = smb_rename_check_src(sr, src_fqi);
 141         if (status != NT_STATUS_SUCCESS) {
 142                 smb_node_release(src_fqi->fq_fnode);
 143                 smb_node_release(src_fqi->fq_dnode);
 144                 return (status);
 145         }
 146         /*
 147          * NB: src_fnode is now "in crit" (critical section)
 148          * as if we did smb_node_start_crit(..., RW_READER);
 149          * Call smb_rename_release_src(sr) on errors.
 150          */
 151 
 152         /*
 153          * Find the destination dnode and last component.
 154          * May already be provided, i.e. when called via
 155          * SMB1 trans2 setinfo.
 156          */
 157         if (dst_fqi->fq_dnode) {
 158                 /* called via smb_set_rename_info */
 159                 smb_node_ref(dst_fqi->fq_dnode);
 160         } else {
 161                 /* called via smb2_setf_rename, smb_com_rename, etc. */
 162                 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 163                     &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
 164                 if (rc != 0) {
 165                         smb_rename_release_src(sr);
 166                         return (smb_rename_errno2status(rc));
 167                 }
 168         }
 169 
 170         dst_dnode = dst_fqi->fq_dnode;
 171         new_name = dst_fqi->fq_last_comp;
 172 


 238 
 239         if ((rc != 0) && (rc != ENOENT)) {
 240                 smb_rename_release_src(sr);
 241                 smb_node_release(dst_fqi->fq_dnode);
 242                 return (smb_rename_errno2status(rc));
 243         }
 244 
 245         if (dst_fqi->fq_fnode) {
 246                 /*
 247                  * Destination already exists.  Do delete checks.
 248                  */
 249                 dst_fnode = dst_fqi->fq_fnode;
 250 
 251                 if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) {
 252                         smb_rename_release_src(sr);
 253                         smb_node_release(dst_fnode);
 254                         smb_node_release(dst_dnode);
 255                         return (NT_STATUS_OBJECT_NAME_COLLISION);
 256                 }
 257 
 258                 status = smb_oplock_break_DELETE(dst_fnode, NULL);
 259                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 260                         if (sr->session->dialect >= SMB_VERS_2_BASE)
 261                                 (void) smb2sr_go_async(sr);
 262                         (void) smb_oplock_wait_break(dst_fnode, 0);
 263                         status = 0;
 264                 }
 265                 if (status != 0) {
 266                         smb_rename_release_src(sr);
 267                         smb_node_release(dst_fnode);
 268                         smb_node_release(dst_dnode);
 269                         return (status);
 270                 }
 271 






 272                 smb_node_rdlock(dst_fnode);

 273                 status = smb_node_delete_check(dst_fnode);






 274                 if (status != NT_STATUS_SUCCESS) {
 275                         smb_node_unlock(dst_fnode);
 276                         smb_rename_release_src(sr);
 277                         smb_node_release(dst_fnode);
 278                         smb_node_release(dst_dnode);
 279                         return (NT_STATUS_ACCESS_DENIED);
 280                 }
 281 
 282                 /*
 283                  * Note, the combination of these two:
 284                  *      smb_node_rdlock(node);
 285                  *      nbl_start_crit(node->vp, RW_READER);
 286                  * is equivalent to this call:
 287                  *      smb_node_start_crit(node, RW_READER)
 288                  *
 289                  * Cleanup after this point should use:
 290                  *      smb_node_end_crit(dst_fnode)
 291                  */
 292                 nbl_start_crit(dst_fnode->vp, RW_READER);
 293 
 294                 /*
 295                  * This checks nbl_share_conflict, nbl_lock_conflict
 296                  */
 297                 status = smb_nbl_conflict(dst_fnode, 0, UINT64_MAX, NBL_REMOVE);
 298                 if (status != NT_STATUS_SUCCESS) {
 299                         smb_node_end_crit(dst_fnode);
 300                         smb_rename_release_src(sr);
 301                         smb_node_release(dst_fnode);
 302                         smb_node_release(dst_dnode);
 303                         return (NT_STATUS_ACCESS_DENIED);
 304                 }
 305 
 306                 new_name = dst_fnode->od_name;
 307                 dst_exists = B_TRUE;
 308         }
 309 
 310         do_audit = smb_audit_rename_init(sr);
 311         /* save paths for later auditing */
 312         if (do_audit) {
 313                 if (!have_src) {
 314                         srcpath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
 315                         smb_node_getpath_nofail(src_fnode, smb_audit_rootvp(sr),
 316                             srcpath, SMB_MAXPATHLEN);
 317                 }
 318                 if (dst_exists) {
 319                         dstpath = kmem_alloc(SMB_MAXPATHLEN, KM_SLEEP);
 320                         smb_node_getpath_nofail(dst_fnode, smb_audit_rootvp(sr),
 321                             dstpath, SMB_MAXPATHLEN);
 322                 }
 323         }
 324 
 325         rc = smb_fsop_rename(sr, sr->user_cr,
 326             src_dnode, src_fnode->od_name,
 327             dst_dnode, new_name);
 328 
 329         if (do_audit) {
 330                 smb_audit_rename_fini(sr,
 331                     srcpath,
 332                     dst_dnode,
 333                     dstpath,
 334                     rc == 0,
 335                     smb_node_is_dir(src_fnode));
 336 
 337                 if (srcpath != NULL)
 338                         kmem_free(srcpath, SMB_MAXPATHLEN);
 339                 if (dstpath != NULL)
 340                         kmem_free(dstpath, SMB_MAXPATHLEN);
 341         }
 342 
 343         if (rc == 0) {
 344                 /*
 345                  * Note that renames in the same directory are normally
 346                  * delivered in {old,new} pairs, and clients expect them
 347                  * in that order, if both events are delivered.
 348                  */
 349                 int a_src, a_dst; /* action codes */
 350                 if (src_dnode == dst_dnode) {
 351                         a_src = FILE_ACTION_RENAMED_OLD_NAME;
 352                         a_dst = FILE_ACTION_RENAMED_NEW_NAME;
 353                 } else {
 354                         a_src = FILE_ACTION_REMOVED;
 355                         a_dst = FILE_ACTION_ADDED;
 356                 }
 357                 smb_node_notify_change(src_dnode, a_src, src_fnode->od_name);
 358                 smb_node_notify_change(dst_dnode, a_dst, new_name);
 359         }
 360 
 361         smb_rename_release_src(sr);
 362 


 466  * Similar to smb_common_rename() above.
 467  */
 468 uint32_t
 469 smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi)
 470 {
 471         smb_node_t *tnode;
 472         char *path;
 473         int rc;
 474 
 475         tnode = sr->tid_tree->t_snode;
 476         path = dst_fqi->fq_path.pn_path;
 477 
 478         /* Cannnot create link on named stream */
 479         if (smb_is_stream_name(src_fqi->fq_path.pn_path) ||
 480             smb_is_stream_name(dst_fqi->fq_path.pn_path)) {
 481                 return (NT_STATUS_INVALID_PARAMETER);
 482         }
 483 
 484         /* The source node may already have been provided */
 485         if (src_fqi->fq_fnode) {


 486                 smb_node_ref(src_fqi->fq_dnode);
 487                 smb_node_ref(src_fqi->fq_fnode);
 488         } else {
 489                 /* lookup and validate src node */
 490                 rc = smb_rename_lookup_src(sr);
 491                 if (rc != 0)
 492                         return (smb_rename_errno2status(rc));
 493                 /* Holding refs on dnode, fnode */
 494         }
 495 
 496         /* Not valid to create hardlink for directory */
 497         if (smb_node_is_dir(src_fqi->fq_fnode)) {
 498                 smb_node_release(src_fqi->fq_dnode);
 499                 smb_node_release(src_fqi->fq_fnode);
 500                 return (NT_STATUS_FILE_IS_A_DIRECTORY);
 501         }
 502 
 503         /*
 504          * Unlike in rename, we will not unlink the src,
 505          * so skip the smb_rename_check_src() call, and
 506          * just "start crit" instead.
 507          */
 508         smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
 509 
 510         /*
 511          * Find the destination dnode and last component.
 512          * May already be provided, i.e. when called via
 513          * SMB1 trans2 setinfo.
 514          */
 515         if (dst_fqi->fq_dnode) {
 516                 smb_node_ref(dst_fqi->fq_dnode);
 517         } else {
 518                 rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 519                     &dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
 520                 if (rc != 0) {
 521                         smb_rename_release_src(sr);
 522                         return (smb_rename_errno2status(rc));
 523                 }
 524         }
 525 
 526         /* If CI name match in same directory, we're done */
 527         if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) &&
 528             (smb_strcasecmp(src_fqi->fq_fnode->od_name,
 529             dst_fqi->fq_last_comp, 0) == 0)) {
 530                 smb_rename_release_src(sr);


 550                 smb_node_release(dst_fqi->fq_dnode);
 551                 return (smb_rename_errno2status(rc));
 552         }
 553 
 554         rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode,
 555             dst_fqi->fq_dnode, dst_fqi->fq_last_comp);
 556 
 557         if (rc == 0) {
 558                 smb_node_notify_change(dst_fqi->fq_dnode,
 559                     FILE_ACTION_ADDED, dst_fqi->fq_last_comp);
 560         }
 561 
 562         smb_rename_release_src(sr);
 563         smb_node_release(dst_fqi->fq_dnode);
 564         return (smb_rename_errno2status(rc));
 565 }
 566 
 567 /*
 568  * smb_rename_lookup_src
 569  *
 570  * Lookup the src node for a path-based link or rename.


 571  *
 572  * On success, fills in sr->arg.dirop.fqi, and returns with
 573  * holds on the source dnode and fnode.

 574  *
 575  * Returns errno values.
 576  */
 577 static int
 578 smb_rename_lookup_src(smb_request_t *sr)
 579 {
 580         smb_node_t *tnode;



 581         char *path;
 582         int rc;
 583 
 584         smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
 585 
 586         if (smb_is_stream_name(src_fqi->fq_path.pn_path))
 587                 return (EINVAL);
 588 
 589         /* Lookup the source node */
 590         tnode = sr->tid_tree->t_snode;
 591         path = src_fqi->fq_path.pn_path;
 592         rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode,
 593             &src_fqi->fq_dnode, src_fqi->fq_last_comp);
 594         if (rc != 0)
 595                 return (rc);
 596         /* hold fq_dnode */
 597 
 598         rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode,
 599             src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode);
 600         if (rc != 0) {
 601                 smb_node_release(src_fqi->fq_dnode);
 602                 return (rc);
 603         }
 604         /* hold fq_dnode, fq_fnode */
 605 
 606         rc = smb_rename_check_attr(sr, src_fqi->fq_fnode, src_fqi->fq_sattr);
 607         if (rc != 0) {
 608                 smb_node_release(src_fqi->fq_fnode);
 609                 smb_node_release(src_fqi->fq_dnode);
 610                 return (rc);
 611         }
 612 
 613         return (0);
 614 }
 615 
 616 /*
 617  * smb_rename_check_src
 618  *
 619  * Check for sharing violations on the file we'll unlink, and
 620  * break oplocks for the rename operation.  Note that we've
 621  * already done oplock breaks associated with opening a handle
 622  * on the file to rename.
 623  *
 624  * On success, returns with fnode in a critical section,
 625  * as if smb_node_start_crit were called with the node.
 626  * Caller should release using smb_rename_release_src().
 627  */
 628 static uint32_t
 629 smb_rename_check_src(smb_request_t *sr, smb_fqi_t *src_fqi)
 630 {
 631         smb_node_t *src_node = src_fqi->fq_fnode;
 632         uint32_t status;
 633 
 634         /*
 635          * Break BATCH oplock before ofile checks. If a client
 636          * has a file open, this will force a flush or close,
 637          * which may affect the outcome of any share checking.
 638          *
 639          * This operation may have either a handle or path for
 640          * the source node (that will be unlinked via rename).
 641          */


 642 
 643         if (sr->fid_ofile != NULL) {
 644                 status = smb_oplock_break_SETINFO(src_node, sr->fid_ofile,
 645                     FileRenameInformation);
 646                 if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 647                         if (sr->session->dialect >= SMB_VERS_2_BASE)
 648                                 (void) smb2sr_go_async(sr);
 649                         (void) smb_oplock_wait_break(src_node, 0);
 650                         status = 0;
 651                 }
 652 
 653                 /*
 654                  * Sharing violations were checked at open time.
 655                  * Just "start crit" to be consistent with the
 656                  * state returned for path-based rename.

 657                  */
 658                 smb_node_start_crit(src_fqi->fq_fnode, RW_READER);
 659                 return (NT_STATUS_SUCCESS);
 660         }
 661 
 662         /*
 663          * This code path operates without a real open, so
 664          * break oplocks now as if we opened for delete.
 665          * Note: SMB2 does only ofile-based rename.
 666          *
 667          * Todo:  Use an "internal open" for path-based
 668          * rename and delete, then delete this code.
 669          */
 670         ASSERT(sr->session->dialect < SMB_VERS_2_BASE);
 671         status = smb_oplock_break_DELETE(src_node, NULL);
 672         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 673                 (void) smb_oplock_wait_break(src_node, 0);
 674         }
 675 
 676         /*
 677          * Path-based access to the src file (no ofile)
 678          * so check for sharing violations here.
 679          */
 680         smb_node_rdlock(src_node);

 681         status = smb_node_rename_check(src_node);






 682         if (status != NT_STATUS_SUCCESS) {
 683                 smb_node_unlock(src_node);
 684                 return (status);


 685         }
 686 
 687         status = smb_oplock_break_SETINFO(src_node, NULL,
 688             FileRenameInformation);
 689         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 690                 (void) smb_oplock_wait_break(src_node, 0);
 691         }
 692 
 693         /*
 694          * Note, the combination of these two:
 695          *      smb_node_rdlock(node);
 696          *      nbl_start_crit(node->vp, RW_READER);
 697          * is equivalent to this call:
 698          *      smb_node_start_crit(node, RW_READER)
 699          *
 700          * Cleanup after this point should use:
 701          *      smb_node_end_crit(src_node)
 702          */
 703         nbl_start_crit(src_node->vp, RW_READER);
 704 
 705         /*
 706          * This checks nbl_share_conflict, nbl_lock_conflict
 707          */
 708         status = smb_nbl_conflict(src_node, 0, UINT64_MAX, NBL_RENAME);
 709         if (status != NT_STATUS_SUCCESS) {
 710                 smb_node_end_crit(src_node);





 711         }
 712 
 713         /* NB: Caller expects to be "in crit" on fnode. */
 714         return (status);
 715 }
 716 
 717 /*
 718  * smb_rename_release_src
 719  */
 720 static void
 721 smb_rename_release_src(smb_request_t *sr)
 722 {
 723         smb_fqi_t *src_fqi = &sr->arg.dirop.fqi;
 724 
 725         smb_node_end_crit(src_fqi->fq_fnode);
 726         smb_node_release(src_fqi->fq_fnode);
 727         smb_node_release(src_fqi->fq_dnode);
 728 }
 729 
 730 
 731 static int
 732 smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr)
 733 {
 734         smb_attr_t attr;