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_SESSION_SETUP
  18  *
  19  * Note that the Capabilities supplied in this request are an inferior
  20  * subset of those given to us previously in the SMB2 Negotiate request.
  21  * We need to remember the full set of capabilities from SMB2 Negotiate,
  22  * and therefore ignore the subset of capabilities supplied here.
  23  */
  24 
  25 #include <smbsrv/smb2_kproto.h>
  26 
  27 static void smb2_ss_adjust_credits(smb_request_t *);
  28 
  29 smb_sdrc_t
  30 smb2_session_setup(smb_request_t *sr)
  31 {
  32         smb_arg_sessionsetup_t  *sinfo;
  33         smb_user_t *prev_user;
  34         uint16_t StructureSize;
  35         uint8_t  Flags;
  36         uint8_t  SecurityMode;
  37         uint32_t Capabilities;  /* ignored - see above */
  38         uint32_t Channel;
  39         uint16_t SecBufOffset;
  40         uint16_t SecBufLength;
  41         uint64_t PrevSsnId;
  42         uint16_t SessionFlags;
  43         uint32_t status;
  44         int skip;
  45         int rc = 0;
  46 
  47         sinfo = smb_srm_zalloc(sr, sizeof (smb_arg_sessionsetup_t));
  48         sr->sr_ssetup = sinfo;
  49 
  50         rc = smb_mbc_decodef(
  51             &sr->smb_data, "wbbllwwq",
  52             &StructureSize, /* w */
  53             &Flags,         /* b */
  54             &SecurityMode,  /* b */
  55             &Capabilities,  /* l */
  56             &Channel,               /* l */
  57             &SecBufOffset,  /* w */
  58             &SecBufLength,  /* w */
  59             &PrevSsnId);    /* q */
  60         if (rc)
  61                 return (SDRC_ERROR);
  62 
  63         /*
  64          * We're normally positioned at the security buffer now,
  65          * but there could be some padding before it.
  66          */
  67         skip = (SecBufOffset + sr->smb2_cmd_hdr) -
  68             sr->smb_data.chain_offset;
  69         if (skip < 0)
  70                 return (SDRC_ERROR);
  71         if (skip > 0)
  72                 (void) smb_mbc_decodef(&sr->smb_data, "#.", skip);
  73 
  74         /*
  75          * Get the security buffer
  76          */
  77         sinfo->ssi_iseclen = SecBufLength;
  78         sinfo->ssi_isecblob = smb_srm_zalloc(sr, sinfo->ssi_iseclen);
  79         rc = smb_mbc_decodef(&sr->smb_data, "#c",
  80             sinfo->ssi_iseclen, sinfo->ssi_isecblob);
  81         if (rc)
  82                 return (SDRC_ERROR);
  83 
  84         /*
  85          * Decoded everything.  Dtrace probe,
  86          * then no more early returns.
  87          */
  88         DTRACE_SMB2_START(op__SessionSetup, smb_request_t *, sr);
  89 
  90         /*
  91          * [MS-SMB2] 3.3.5.5 Receiving an SMB2 SESSION_SETUP Request
  92          *
  93          * If we support 3.x, RejectUnencryptedAccess is TRUE,
  94          * global EncryptData is TRUE, but we're not talking
  95          * 3.x or the client doesn't support encryption,
  96          * return ACCESS_DENIED.
  97          *
  98          * If RejectUnencryptedAccess is TRUE, we force max_protocol
  99          * to at least 3.0.
 100          */
 101         if (sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED &&
 102             (sr->session->dialect < SMB_VERS_3_0 ||
 103             !SMB3_CLIENT_ENCRYPTS(sr))) {
 104                 status = NT_STATUS_ACCESS_DENIED;
 105                 goto errout;
 106         }
 107 
 108         /*
 109          * SMB3 multi-channel features are not supported.
 110          * Once they are, this will check the dialect and
 111          * whether multi-channel was negotiated, i.e.
 112          *      if (sr->session->dialect < SMB_VERS_3_0 ||
 113          *          s->IsMultiChannelCapable == False)
 114          *              return (error...)
 115          */
 116         if (Flags & SMB2_SESSION_FLAG_BINDING) {
 117                 status = NT_STATUS_REQUEST_NOT_ACCEPTED;
 118                 goto errout;
 119         }
 120 
 121         /*
 122          * The real auth. work happens in here.
 123          */
 124         status = smb_authenticate_ext(sr);
 125 
 126         SecBufOffset = SMB2_HDR_SIZE + 8;
 127         SecBufLength = sinfo->ssi_oseclen;
 128         SessionFlags = 0;
 129 
 130         switch (status) {
 131 
 132         case NT_STATUS_SUCCESS: /* Authenticated */
 133                 if ((sr->uid_user->u_flags & SMB_USER_FLAG_GUEST) != 0)
 134                         SessionFlags |= SMB2_SESSION_FLAG_IS_GUEST;
 135                 if ((sr->uid_user->u_flags & SMB_USER_FLAG_ANON) != 0)
 136                         SessionFlags |= SMB2_SESSION_FLAG_IS_NULL;
 137                 if (sr->uid_user->u_encrypt != SMB_CONFIG_DISABLED)
 138                         SessionFlags |= SMB2_SESSION_FLAG_ENCRYPT_DATA;
 139                 smb2_ss_adjust_credits(sr);
 140 
 141                 /*
 142                  * PrevSsnId is a session that the client is reporting as
 143                  * having gone away, and for which we might not yet have seen
 144                  * a disconnect. Find the session and log it off as if we had
 145                  * received a disconnect.  Note that the client is allowed to
 146                  * set PrevSsnID to the _current_ SessionID, so skip the lookup
 147                  * in that case. Only allow this session logoff if we owned it.
 148                  */
 149                 if (PrevSsnId == 0 ||
 150                     PrevSsnId == sr->smb2_ssnid)
 151                         break;
 152                 prev_user = smb_server_lookup_ssnid(sr->sr_server, PrevSsnId);
 153                 if (prev_user != NULL) {
 154                         if (smb_is_same_user(prev_user->u_cred, sr->user_cr)) {
 155                                 /* Treat this as if we lost the connection */
 156                                 prev_user->preserve_opens =
 157                                     SMB2_DH_PRESERVE_SOME;
 158                                 smb_user_logoff(prev_user);
 159                         }
 160                         smb_user_release(prev_user); /* from lookup */
 161                 }
 162                 break;
 163 
 164         /*
 165          * This is not really an error, but tells the client
 166          * it should send another session setup request.
 167          * Not smb2_put_error because we send a payload.
 168          */
 169         case NT_STATUS_MORE_PROCESSING_REQUIRED:
 170                 sr->smb2_status = status;
 171                 break;
 172 
 173         default:
 174 errout:
 175                 SecBufLength = 0;
 176                 sr->smb2_status = status;
 177                 break;
 178         }
 179 
 180         /* sr->smb2_status set above */
 181         DTRACE_SMB2_DONE(op__SessionSetup, smb_request_t *, sr);
 182 
 183         /*
 184          * SMB2 Session Setup reply
 185          */
 186 
 187         rc = smb_mbc_encodef(
 188             &sr->reply,
 189             "wwww#c",
 190             9,  /* StructSize */        /* w */
 191             SessionFlags,               /* w */
 192             SecBufOffset,               /* w */
 193             SecBufLength,               /* w */
 194             SecBufLength,               /* # */
 195             sinfo->ssi_osecblob);    /* c */
 196         if (rc)
 197                 sr->smb2_status = NT_STATUS_INTERNAL_ERROR;
 198 
 199         return (SDRC_SUCCESS);
 200 }
 201 
 202 /*
 203  * After a successful authentication, raise s_max_credits up to the
 204  * normal maximum that clients are allowed to request.  Also, if we
 205  * haven't yet given them their initial credits, do that now.
 206  *
 207  * Normally, clients will request some credits with session setup,
 208  * but in case they don't request enough to raise s_cur_credits
 209  * up to the configured initial_credits, increase the requested
 210  * credits of this SR sufficiently to make that happen.  The actual
 211  * increase happens in the dispatch code after we return.
 212  */
 213 static void
 214 smb2_ss_adjust_credits(smb_request_t *sr)
 215 {
 216         smb_session_t *s = sr->session;
 217 
 218         mutex_enter(&s->s_credits_mutex);
 219         s->s_max_credits = s->s_cfg.skc_maximum_credits;
 220 
 221         if (s->s_cur_credits < s->s_cfg.skc_initial_credits) {
 222                 uint16_t grant;
 223 
 224                 /* How many credits we want to grant with this SR. */
 225                 grant = s->s_cfg.skc_initial_credits - s->s_cur_credits;
 226 
 227                 /*
 228                  * Do we need to increase the smb2_credit_request?
 229                  * One might prefer to read this expression as:
 230                  *      ((credit_request - credit_charge) < grant)
 231                  * but we know credit_charge == 1 and would rather not
 232                  * deal with a possibly negative value on the left,
 233                  * so adding credit_charge to both sides...
 234                  */
 235                 if (sr->smb2_credit_request < (grant + 1)) {
 236                         sr->smb2_credit_request = (grant + 1);
 237                 }
 238         }
 239 
 240         mutex_exit(&s->s_credits_mutex);
 241 }