Print this page
NEX-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-15578 SMB2 durable handle redesign
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@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-1643 dtrace provider for smbsrv
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-5586 SMB2 ofiles need real Persistent IDs
NEX-5313 SMB2 oplock break notification should use TID=0
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-5560 smb2 should use 64-bit server-global uids
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-1892 30 sec. delay responding to smb2_create
NEX-1734 SMB2 oplock break request missing a flag
SMB-122 smbd core dumps in smbd_dc_update / smb_log
SMB-117 Win7 fails to open security properties
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)
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_OPLOCK_BREAK
  18  */
  19 
  20 #include <smbsrv/smb2_kproto.h>
  21 






  22 /*
  23  * SMB2 Oplock Break Acknowledgement
  24  * [MS-SMB2 2.2.24]

  25  */
  26 smb_sdrc_t
  27 smb2_oplock_break_ack(smb_request_t *sr)
  28 {
  29         smb_node_t *node;
  30         smb2fid_t smb2fid;
  31         uint32_t status;
  32         uint16_t StructSize;
  33         uint8_t OplockLevel;
  34         uint8_t brk;
  35         int rc = 0;

  36 
  37         /*
  38          * Decode the SMB2 Oplock Break Ack.


  39          */
















  40         rc = smb_mbc_decodef(
  41             &sr->smb_data, "wb5.qq",
  42             &StructSize,            /* w */
  43             &OplockLevel,           /* b */
  44             /* reserved                   5. */
  45             &smb2fid.persistent,    /* q */
  46             &smb2fid.temporal);             /* q */
  47         if (rc || StructSize != 24)
  48                 return (SDRC_ERROR);
  49 

  50         status = smb2sr_lookup_fid(sr, &smb2fid);
  51         if (status)



  52                 goto errout;
  53         if ((node = sr->fid_ofile->f_node) == NULL) {
  54                 /* Not a regular file */
  55                 status = NT_STATUS_INVALID_PARAMETER;
  56                 goto errout;
  57         }
  58 
  59         /*
  60          * Process the oplock break ack.  We only expect levels
  61          * at or below the hightest break levels we send, which is
  62          * currently SMB2_OPLOCK_LEVEL_II.
  63          */
  64         switch (OplockLevel) {
  65         case SMB2_OPLOCK_LEVEL_NONE:    /* 0x00 */
  66                 brk = SMB_OPLOCK_BREAK_TO_NONE;
  67                 break;
  68 
  69         case SMB2_OPLOCK_LEVEL_II:      /* 0x01 */
  70                 brk = SMB_OPLOCK_BREAK_TO_LEVEL_II;
  71                 break;
  72 
  73         /* We don't break to these levels (yet). */
  74         case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */


  75         case SMB2_OPLOCK_LEVEL_BATCH:   /* 0x09 */


  76         case SMB2_OPLOCK_LEVEL_LEASE:   /* 0xFF */
  77         default: /* gcc -Wuninitialized */
  78                 status = NT_STATUS_INVALID_PARAMETER;









  79                 goto errout;


  80         }




  81 
  82         smb_oplock_ack(node, sr->fid_ofile, brk);


















  83 








  84         /*
  85          * Generate SMB2 Oplock Break response
  86          * [MS-SMB2] 2.2.25
  87          */
  88         StructSize = 24;
  89         (void) smb_mbc_encodef(
  90             &sr->reply, "wb5.qq",
  91             StructSize,                 /* w */
  92             OplockLevel,                /* b */
  93             /* reserved                   5. */
  94             smb2fid.persistent,         /* q */
  95             smb2fid.temporal);          /* q */
  96         return (SDRC_SUCCESS);
  97 
  98 errout:
  99         smb2sr_put_error(sr, status);
 100         return (SDRC_SUCCESS);
 101 }
 102 
 103 /*
 104  * Compose an SMB2 Oplock Break Notification packet, including
 105  * the SMB2 header and everything, in sr->reply.
 106  * The caller will send it and free the request.
 107  */
 108 void
 109 smb2_oplock_break_notification(smb_request_t *sr, uint8_t brk)
 110 {
 111         smb_ofile_t *ofile = sr->fid_ofile;
 112         smb2fid_t smb2fid;
 113         uint16_t StructSize;
 114         uint8_t OplockLevel;
 115 
 116         switch (brk) {



 117         default:
 118                 ASSERT(0);
 119                 /* FALLTHROUGH */
 120         case SMB_OPLOCK_BREAK_TO_NONE:
 121                 OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 122                 break;
 123         case SMB_OPLOCK_BREAK_TO_LEVEL_II:
 124                 OplockLevel = SMB2_OPLOCK_LEVEL_II;
 125                 break;
 126         }
 127 
 128         /*
 129          * SMB2 Header
 130          */
 131         sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
 132         sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
 133         sr->smb_tid = ofile->f_tree->t_tid;
 134         sr->smb_pid = 0;
 135         sr->smb_uid = 0;
 136         sr->smb2_messageid = UINT64_MAX;
 137         (void) smb2_encode_header(sr, B_FALSE);
 138 
 139         /*
 140          * SMB2 Oplock Break, variable part
 141          */
 142         StructSize = 24;
 143         smb2fid.persistent = 0;
 144         smb2fid.temporal = ofile->f_fid;
 145         (void) smb_mbc_encodef(
 146             &sr->reply, "wb5.qq",
 147             StructSize,         /* w */
 148             OplockLevel,        /* b */
 149             /* reserved           5. */
 150             smb2fid.persistent, /* q */
 151             smb2fid.temporal);  /* q */


































































































































 152 }
   1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * Dispatch function for SMB2_OPLOCK_BREAK
  18  */
  19 
  20 #include <smbsrv/smb2_kproto.h>
  21 
  22 #define BATCH_OR_EXCL   (OPLOCK_LEVEL_BATCH | OPLOCK_LEVEL_ONE)
  23 
  24 /* StructSize for the two "break" message formats. */
  25 #define SSZ_OPLOCK      24
  26 #define SSZ_LEASE       36
  27 
  28 /*
  29  * SMB2 Oplock Break Acknowledgement
  30  * [MS-SMB2] 3.3.5.22.1 Processing an Oplock Acknowledgment
  31  * Called via smb2_disp_table[]
  32  */
  33 smb_sdrc_t
  34 smb2_oplock_break_ack(smb_request_t *sr)
  35 {
  36         smb_ofile_t *ofile;
  37         smb2fid_t smb2fid;
  38         uint32_t status;
  39         uint32_t NewLevel;
  40         uint8_t smbOplockLevel;

  41         int rc = 0;
  42         uint16_t StructSize;
  43 
  44         /*
  45          * Decode the SMB2 Oplock Break Ack (24 bytes) or
  46          * Lease Break Ack (36 bytes), starting with just
  47          * the StructSize, which tells us what this is.
  48          */
  49         rc = smb_mbc_decodef(&sr->smb_data, "w", &StructSize);
  50         if (rc != 0)
  51                 return (SDRC_ERROR);
  52 
  53         if (StructSize == SSZ_LEASE) {
  54                 /* See smb2_lease.c */
  55                 return (smb2_lease_break_ack(sr));
  56         }
  57         if (StructSize != SSZ_OPLOCK)
  58                 return (SDRC_ERROR);
  59 
  60         /*
  61          * Decode an SMB2 Oplock Break Ack.
  62          * [MS-SMB2] 2.2.24.1
  63          * Note: Struct size decoded above.
  64          */
  65         rc = smb_mbc_decodef(
  66             &sr->smb_data, "b5.qq",
  67             &smbOplockLevel,                /* b */

  68             /* reserved                   5. */
  69             &smb2fid.persistent,    /* q */
  70             &smb2fid.temporal);             /* q */
  71         if (rc != 0)
  72                 return (SDRC_ERROR);
  73 
  74         /* Find the ofile */
  75         status = smb2sr_lookup_fid(sr, &smb2fid);
  76         /* Success or NT_STATUS_FILE_CLOSED */
  77 
  78         DTRACE_SMB2_START(op__OplockBreak, smb_request_t *, sr);
  79         if (status != 0)
  80                 goto errout;





  81 
  82         /*
  83          * Process an (old-style) oplock break ack.


  84          */
  85         switch (smbOplockLevel) {
  86         case SMB2_OPLOCK_LEVEL_NONE:    /* 0x00 */
  87                 NewLevel = OPLOCK_LEVEL_NONE;
  88                 break;

  89         case SMB2_OPLOCK_LEVEL_II:      /* 0x01 */
  90                 NewLevel = OPLOCK_LEVEL_TWO;
  91                 break;


  92         case SMB2_OPLOCK_LEVEL_EXCLUSIVE: /* 0x08 */
  93                 NewLevel = OPLOCK_LEVEL_ONE;
  94                 break;
  95         case SMB2_OPLOCK_LEVEL_BATCH:   /* 0x09 */
  96                 NewLevel = OPLOCK_LEVEL_BATCH;
  97                 break;
  98         case SMB2_OPLOCK_LEVEL_LEASE:   /* 0xFF */
  99         default:
 100                 NewLevel = OPLOCK_LEVEL_NONE;
 101                 break;
 102         }
 103 
 104         ofile = sr->fid_ofile;
 105         ofile->f_oplock.og_breaking = 0;
 106         status = smb_oplock_ack_break(sr, ofile, &NewLevel);
 107         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 108                 status = smb2sr_go_async(sr);
 109                 if (status != 0)
 110                         goto errout;
 111                 (void) smb_oplock_wait_break(ofile->f_node, 0);
 112                 status = 0;
 113         }
 114         if (status != 0) {
 115                 NewLevel = OPLOCK_LEVEL_NONE;
 116                 goto errout;
 117         }
 118 
 119         ofile->f_oplock.og_state = NewLevel;
 120         switch (NewLevel & OPLOCK_LEVEL_TYPE_MASK) {
 121         case OPLOCK_LEVEL_NONE:
 122                 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 123                 break;
 124         case OPLOCK_LEVEL_TWO:
 125                 smbOplockLevel = SMB2_OPLOCK_LEVEL_II;
 126                 break;
 127         case OPLOCK_LEVEL_ONE:
 128                 smbOplockLevel = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
 129                 break;
 130         case OPLOCK_LEVEL_BATCH:
 131                 smbOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
 132                 break;
 133         case OPLOCK_LEVEL_GRANULAR:
 134         default:
 135                 smbOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 136                 break;
 137         }
 138 
 139 errout:
 140         sr->smb2_status = status;
 141         DTRACE_SMB2_DONE(op__OplockBreak, smb_request_t *, sr);
 142         if (status) {
 143                 smb2sr_put_error(sr, status);
 144                 return (SDRC_SUCCESS);
 145         }
 146 
 147         /*
 148          * Encode an SMB2 Oplock Break Ack response
 149          * [MS-SMB2] 2.2.25.1
 150          */

 151         (void) smb_mbc_encodef(
 152             &sr->reply, "wb5.qq",
 153             SSZ_OPLOCK,                 /* w */
 154             smbOplockLevel,             /* b */
 155             /* reserved                   5. */
 156             smb2fid.persistent,         /* q */
 157             smb2fid.temporal);          /* q */

 158 


 159         return (SDRC_SUCCESS);
 160 }
 161 
 162 /*
 163  * Compose an SMB2 Oplock Break Notification packet, including
 164  * the SMB2 header and everything, in sr->reply.
 165  * The caller will send it and free the request.
 166  */
 167 void
 168 smb2_oplock_break_notification(smb_request_t *sr, uint32_t NewLevel)
 169 {
 170         smb_ofile_t *ofile = sr->fid_ofile;
 171         smb2fid_t smb2fid;
 172         uint16_t StructSize;
 173         uint8_t OplockLevel;
 174 
 175         /*
 176          * Convert internal level to SMB2
 177          */
 178         switch (NewLevel) {
 179         default:
 180                 ASSERT(0);
 181                 /* FALLTHROUGH */
 182         case OPLOCK_LEVEL_NONE:
 183                 OplockLevel = SMB2_OPLOCK_LEVEL_NONE;
 184                 break;
 185         case OPLOCK_LEVEL_TWO:
 186                 OplockLevel = SMB2_OPLOCK_LEVEL_II;
 187                 break;
 188         }
 189 
 190         /*
 191          * SMB2 Header
 192          */
 193         sr->smb2_cmd_code = SMB2_OPLOCK_BREAK;
 194         sr->smb2_hdr_flags = SMB2_FLAGS_SERVER_TO_REDIR;
 195         sr->smb_tid = 0;
 196         sr->smb_pid = 0;
 197         sr->smb2_ssnid = 0;
 198         sr->smb2_messageid = UINT64_MAX;
 199         (void) smb2_encode_header(sr, B_FALSE);
 200 
 201         /*
 202          * SMB2 Oplock Break, variable part
 203          */
 204         StructSize = 24;
 205         smb2fid.persistent = ofile->f_persistid;
 206         smb2fid.temporal = ofile->f_fid;
 207         (void) smb_mbc_encodef(
 208             &sr->reply, "wb5.qq",
 209             StructSize,         /* w */
 210             OplockLevel,        /* b */
 211             /* reserved           5. */
 212             smb2fid.persistent, /* q */
 213             smb2fid.temporal);  /* q */
 214 }
 215 
 216 /*
 217  * Client has an open handle and requests an oplock.
 218  * Convert SMB2 oplock request info in to internal form,
 219  * call common oplock code, convert result to SMB2.
 220  *
 221  * If necessary, "go async" here.
 222  */
 223 void
 224 smb2_oplock_acquire(smb_request_t *sr)
 225 {
 226         smb_arg_open_t *op = &sr->arg.open;
 227         smb_ofile_t *ofile = sr->fid_ofile;
 228         uint32_t status;
 229 
 230         /* Only disk trees get oplocks. */
 231         ASSERT((sr->tid_tree->t_res_type & STYPE_MASK) == STYPE_DISKTREE);
 232 
 233         /* Only plain files... */
 234         if (!smb_node_is_file(ofile->f_node)) {
 235                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 236                 return;
 237         }
 238 
 239         if (!smb_tree_has_feature(sr->tid_tree, SMB_TREE_OPLOCKS)) {
 240                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 241                 return;
 242         }
 243 
 244         /*
 245          * SMB2: Convert to internal form.
 246          */
 247         switch (op->op_oplock_level) {
 248         case SMB2_OPLOCK_LEVEL_BATCH:
 249                 op->op_oplock_state = OPLOCK_LEVEL_BATCH;
 250                 break;
 251         case SMB2_OPLOCK_LEVEL_EXCLUSIVE:
 252                 op->op_oplock_state = OPLOCK_LEVEL_ONE;
 253                 break;
 254         case SMB2_OPLOCK_LEVEL_II:
 255                 op->op_oplock_state = OPLOCK_LEVEL_TWO;
 256                 break;
 257         case SMB2_OPLOCK_LEVEL_LEASE:
 258                 ASSERT(0); /* Handled elsewhere */
 259                 /* FALLTHROUGH */
 260         case SMB2_OPLOCK_LEVEL_NONE:
 261         default:
 262                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 263                 return;
 264         }
 265 
 266         /*
 267          * Tree options may force shared oplocks,
 268          * in which case we reduce the request.
 269          */
 270         if (smb_tree_has_feature(sr->tid_tree, SMB_TREE_FORCE_L2_OPLOCK)) {
 271                 op->op_oplock_state = OPLOCK_LEVEL_TWO;
 272         }
 273 
 274         /*
 275          * Try exclusive first, if requested
 276          */
 277         if ((op->op_oplock_state & BATCH_OR_EXCL) != 0) {
 278                 status = smb_oplock_request(sr, ofile,
 279                     &op->op_oplock_state);
 280         } else {
 281                 status = NT_STATUS_OPLOCK_NOT_GRANTED;
 282         }
 283 
 284         /*
 285          * If exclusive failed (or the tree forced shared oplocks)
 286          * try for a shared oplock (Level II)
 287          */
 288         if (status == NT_STATUS_OPLOCK_NOT_GRANTED) {
 289                 op->op_oplock_state = OPLOCK_LEVEL_TWO;
 290                 status = smb_oplock_request(sr, ofile,
 291                     &op->op_oplock_state);
 292         }
 293 
 294         /*
 295          * Either of the above may have returned the
 296          * status code that says we should wait.
 297          */
 298         if (status == NT_STATUS_OPLOCK_BREAK_IN_PROGRESS) {
 299                 (void) smb2sr_go_async(sr);
 300                 (void) smb_oplock_wait_break(ofile->f_node, 0);
 301                 status = 0;
 302         }
 303 
 304         /*
 305          * Keep track of what we got (in ofile->f_oplock.og_state)
 306          * so we'll know what we had when sending a break later.
 307          * The og_dialect here is the oplock dialect, not the
 308          * SMB dialect.  No lease here, so SMB 2.0.
 309          */
 310         ofile->f_oplock.og_dialect = SMB_VERS_2_002;
 311         switch (status) {
 312         case NT_STATUS_SUCCESS:
 313                 ofile->f_oplock.og_state = op->op_oplock_state;
 314                 break;
 315         case NT_STATUS_OPLOCK_NOT_GRANTED:
 316                 ofile->f_oplock.og_state = 0;
 317                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 318                 return;
 319         default:
 320                 /* Caller did not check args sufficiently? */
 321                 cmn_err(CE_NOTE, "clnt %s oplock req. err 0x%x",
 322                     sr->session->ip_addr_str, status);
 323                 ofile->f_oplock.og_state = 0;
 324                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 325                 return;
 326         }
 327 
 328         /*
 329          * Have STATUS_SUCCESS
 330          * Convert internal oplock state to SMB2
 331          */
 332         if (op->op_oplock_state & OPLOCK_LEVEL_GRANULAR) {
 333                 ASSERT(0);
 334                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 335         } else if (op->op_oplock_state & OPLOCK_LEVEL_BATCH) {
 336                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_BATCH;
 337         } else if (op->op_oplock_state & OPLOCK_LEVEL_ONE) {
 338                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
 339         } else if (op->op_oplock_state & OPLOCK_LEVEL_TWO) {
 340                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_II;
 341         } else {
 342                 op->op_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
 343         }
 344 }