Print this page
NEX-19225 SMB client 2.1 hits redzone panic
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-16818 Add fksmbcl development tool
NEX-17264 SMB client test tp_smbutil_013 fails after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
and: (fix ref leaks)


   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 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.

  24  */
  25 
  26 /*
  27  * Support for SMB "signing" (message integrity)
  28  */
  29 
  30 #include <sys/param.h>
  31 #include <sys/systm.h>
  32 #include <sys/conf.h>
  33 #include <sys/proc.h>
  34 #include <sys/fcntl.h>
  35 #include <sys/socket.h>
  36 #include <sys/md4.h>
  37 #include <sys/md5.h>
  38 #include <sys/des.h>
  39 #include <sys/kmem.h>
  40 #include <sys/crypto/api.h>
  41 #include <sys/crypto/common.h>
  42 #include <sys/cmn_err.h>
  43 #include <sys/stream.h>
  44 #include <sys/strsun.h>
  45 #include <sys/sdt.h>
  46 
  47 #include <netsmb/smb_osdep.h>
  48 #include <netsmb/smb.h>
  49 #include <netsmb/smb_conn.h>
  50 #include <netsmb/smb_subr.h>
  51 #include <netsmb/smb_dev.h>
  52 #include <netsmb/smb_rq.h>

  53 
  54 #ifdef DEBUG
  55 /*
  56  * Set this to a small number to debug sequence numbers
  57  * that seem to get out of step.
  58  */
  59 int nsmb_signing_fudge = 0;
  60 #endif
  61 
  62 /* Mechanism definitions */
  63 static  crypto_mechanism_t crypto_mech_md5 = { CRYPTO_MECH_INVALID };
  64 
  65 void
  66 smb_crypto_mech_init(void)

  67 {
  68         crypto_mech_md5.cm_type = crypto_mech2id(SUN_CKM_MD5);
  69 }
  70 


  71 





  72 















  73 #define SMBSIGLEN       8       /* SMB signature length */
  74 #define SMBSIGOFF       14      /* SMB signature offset */
  75 
  76 /*
  77  * Compute HMAC-MD5 of packet data, using the stored MAC key.
  78  *
  79  * See similar code for the server side:
  80  * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
  81  */
  82 static int
  83 smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
  84         uint32_t seqno, uchar_t *signature)
  85 {
  86         crypto_context_t crypto_ctx;
  87         crypto_data_t key;
  88         crypto_data_t data;
  89         crypto_data_t digest;
  90         uchar_t mac[16];
  91         int status;
  92         /*
  93          * This union is a little bit of trickery to:
  94          * (1) get the sequence number int aligned, and
  95          * (2) reduce the number of digest calls, at the
  96          * cost of a copying 32 bytes instead of 8.
  97          * Both sides of this union are 2+32 bytes.
  98          */
  99         union {
 100                 struct {
 101                         uint8_t skip[2]; /* not used - just alignment */
 102                         uint8_t raw[SMB_HDRLEN];  /* header length (32) */
 103                 } r;
 104                 struct {
 105                         uint8_t skip[2]; /* not used - just alignment */
 106                         uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
 107                         uint32_t sig[2]; /* MAC signature, aligned! */
 108                         uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
 109                 } s;
 110         } smbhdr;
 111 
 112         ASSERT(mp != NULL);
 113         ASSERT(MBLKL(mp) >= SMB_HDRLEN);
 114         ASSERT(vcp->vc_mackey != NULL);
 115 












 116         /*
 117          * Make an aligned copy of the SMB header
 118          * and fill in the sequence number.
 119          */
 120         bcopy(mp->b_rptr, smbhdr.r.raw, SMB_HDRLEN);

 121         smbhdr.s.sig[0] = htolel(seqno);
 122         smbhdr.s.sig[1] = 0;
 123 




 124         /*
 125          * Compute the MAC: MD5(concat(Key, message))

 126          */
 127         if (crypto_mech_md5.cm_type == CRYPTO_MECH_INVALID) {
 128                 SMBSDEBUG("crypto_mech_md5 invalid\n");
 129                 return (CRYPTO_MECHANISM_INVALID);
 130         }
 131         status = crypto_digest_init(&crypto_mech_md5, &crypto_ctx, 0);
 132         if (status != CRYPTO_SUCCESS)
 133                 return (status);
 134 
 135         /* Digest the MAC Key */
 136         key.cd_format = CRYPTO_DATA_RAW;
 137         key.cd_offset = 0;
 138         key.cd_length = vcp->vc_mackeylen;
 139         key.cd_miscdata = 0;
 140         key.cd_raw.iov_base = (char *)vcp->vc_mackey;
 141         key.cd_raw.iov_len = vcp->vc_mackeylen;
 142         status = crypto_digest_update(crypto_ctx, &key, 0);
 143         if (status != CRYPTO_SUCCESS)
 144                 return (status);
 145 
 146         /* Digest the (copied) SMB header */
 147         data.cd_format = CRYPTO_DATA_RAW;
 148         data.cd_offset = 0;
 149         data.cd_length = SMB_HDRLEN;
 150         data.cd_miscdata = 0;
 151         data.cd_raw.iov_base = (char *)smbhdr.r.raw;
 152         data.cd_raw.iov_len = SMB_HDRLEN;
 153         status = crypto_digest_update(crypto_ctx, &data, 0);
 154         if (status != CRYPTO_SUCCESS)
 155                 return (status);
 156 
 157         /* Digest rest of the SMB message. */
 158         data.cd_format = CRYPTO_DATA_MBLK;
 159         data.cd_offset = SMB_HDRLEN;
 160         data.cd_length = msgdsize(mp) - SMB_HDRLEN;
 161         data.cd_miscdata = 0;
 162         data.cd_mp = mp;
 163         status = crypto_digest_update(crypto_ctx, &data, 0);
 164         if (status != CRYPTO_SUCCESS)
 165                 return (status);




 166 
 167         /* Final */
 168         digest.cd_format = CRYPTO_DATA_RAW;
 169         digest.cd_offset = 0;
 170         digest.cd_length = sizeof (mac);
 171         digest.cd_miscdata = 0;
 172         digest.cd_raw.iov_base = (char *)mac;
 173         digest.cd_raw.iov_len = sizeof (mac);
 174         status = crypto_digest_final(crypto_ctx, &digest, 0);
 175         if (status != CRYPTO_SUCCESS)
 176                 return (status);
 177 
 178         /*
 179          * Finally, store the signature.
 180          * (first 8 bytes of the mac)
 181          */
 182         if (signature)
 183                 bcopy(mac, signature, SMBSIGLEN);
 184 
 185         return (0);
 186 }
 187 
 188 /*
 189  * Sign a request with HMAC-MD5.
 190  */
 191 void
 192 smb_rq_sign(struct smb_rq *rqp)
 193 {
 194         struct smb_vc *vcp = rqp->sr_vc;
 195         mblk_t *mp = rqp->sr_rq.mb_top;
 196         uint8_t *sigloc;
 197         int status;
 198 
 199         /*
 200          * Our mblk allocation ensures this,
 201          * but just in case...
 202          */
 203         if (MBLKL(mp) < SMB_HDRLEN) {
 204                 if (!pullupmsg(mp, SMB_HDRLEN))
 205                         return;
 206         }
 207         sigloc = mp->b_rptr + SMBSIGOFF;
 208 
 209         if (vcp->vc_mackey == NULL) {
 210                 /*
 211                  * Signing is required, but we have no key yet
 212                  * fill in with the magic fake signing value.
 213                  * This happens with SPNEGO, NTLMSSP, ...
 214                  */
 215                 bcopy("BSRSPLY", sigloc, 8);
 216                 return;
 217         }
 218 
 219         /*
 220          * This will compute the MAC and store it
 221          * directly into the message at sigloc.
 222          */
 223         status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
 224         if (status != CRYPTO_SUCCESS) {
 225                 SMBSDEBUG("Crypto error %d", status);
 226                 bzero(sigloc, SMBSIGLEN);
 227         }
 228 }
 229 
 230 /*
 231  * Verify reply signature.
 232  */
 233 int
 234 smb_rq_verify(struct smb_rq *rqp)
 235 {
 236         struct smb_vc *vcp = rqp->sr_vc;
 237         mblk_t *mp = rqp->sr_rp.md_top;
 238         uint8_t sigbuf[SMBSIGLEN];
 239         uint8_t *sigloc;
 240         int fudge, rsn, status;
 241 
 242         /*
 243          * Note vc_mackey and vc_mackeylen gets filled in by
 244          * smb_usr_iod_work as the connection comes in.
 245          */
 246         if (vcp->vc_mackey == NULL) {
 247                 SMBSDEBUG("no mac key\n");
 248                 return (0);
 249         }
 250 
 251         /*
 252          * Let caller deal with empty reply or short messages by
 253          * returning zero.  Caller will fail later, in parsing.
 254          */
 255         if (mp == NULL) {
 256                 SMBSDEBUG("empty reply\n");
 257                 return (0);
 258         }
 259         if (MBLKL(mp) < SMB_HDRLEN) {
 260                 if (!pullupmsg(mp, SMB_HDRLEN))
 261                         return (0);
 262         }
 263         sigloc = mp->b_rptr + SMBSIGOFF;
 264 
 265         /*
 266          * Compute the expected signature in sigbuf.
 267          */
 268         rsn = rqp->sr_rseqno;
 269         status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
 270         if (status != CRYPTO_SUCCESS) {
 271                 SMBSDEBUG("Crypto error %d", status);
 272                 /*
 273                  * If we can't compute a MAC, then there's
 274                  * no point trying other seqno values.
 275                  */
 276                 return (EBADRPC);
 277         }
 278 
 279         /*
 280          * Compare the computed signature with the
 281          * one found in the message (at sigloc)
 282          */
 283         if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
 284                 return (0);
 285 
 286         SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n",
 287             vcp->vc_srvname, rqp->sr_mid, rsn);
 288 
 289 #ifdef DEBUG
 290         /*


   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 /*
  23  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 
  27 /*
  28  * Support for SMB "signing" (message integrity)
  29  */
  30 
  31 #include <sys/param.h>
  32 #include <sys/systm.h>
  33 #include <sys/conf.h>
  34 #include <sys/proc.h>
  35 #include <sys/fcntl.h>
  36 #include <sys/socket.h>
  37 #include <sys/md4.h>
  38 #include <sys/md5.h>
  39 #include <sys/des.h>
  40 #include <sys/kmem.h>


  41 #include <sys/cmn_err.h>
  42 #include <sys/stream.h>
  43 #include <sys/strsun.h>
  44 #include <sys/sdt.h>
  45 
  46 #include <netsmb/smb_osdep.h>
  47 #include <netsmb/smb.h>
  48 #include <netsmb/smb_conn.h>
  49 #include <netsmb/smb_subr.h>
  50 #include <netsmb/smb_dev.h>
  51 #include <netsmb/smb_rq.h>
  52 #include <netsmb/smb_signing.h>
  53 
  54 #ifdef DEBUG
  55 /*
  56  * Set this to a small number to debug sequence numbers
  57  * that seem to get out of step.
  58  */
  59 int nsmb_signing_fudge = 0;
  60 #endif
  61 
  62 /*
  63  * This is called just after session setup completes,
  64  * at the top of smb_iod_vc_work().  Initialize signing.
  65  */
  66 int
  67 smb_sign_init(smb_vc_t *vcp)
  68 {
  69         int rc;

  70 
  71         ASSERT(vcp->vc_ssnkey != NULL);
  72         ASSERT(vcp->vc_mackey == NULL);
  73 
  74         rc = smb_md5_getmech(&vcp->vc_signmech);
  75         if (rc != 0) {
  76                 cmn_err(CE_NOTE, "smb can't get signing mechanism");
  77                 return (EAUTH);
  78         }
  79 
  80         /*
  81          * Convert the session key to the MAC key.
  82          * SMB1 uses the whole session key.
  83          */
  84         vcp->vc_mackeylen = vcp->vc_ssnkeylen;
  85         vcp->vc_mackey = kmem_zalloc(vcp->vc_mackeylen, KM_SLEEP);
  86         bcopy(vcp->vc_ssnkey, vcp->vc_mackey, vcp->vc_mackeylen);
  87 
  88         /* The initial sequence number is two. */
  89         vcp->vc_next_seq = 2;
  90 
  91         return (0);
  92 }
  93 
  94 
  95 #define SMBSIGLEN       8       /* SMB signature length */
  96 #define SMBSIGOFF       14      /* SMB signature offset */
  97 
  98 /*
  99  * Compute HMAC-MD5 of packet data, using the stored MAC key.
 100  *
 101  * See similar code for the server side:
 102  * uts/common/fs/smbsrv/smb_signing.c : smb_sign_calc
 103  */
 104 static int
 105 smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp,
 106         uint32_t seqno, uchar_t *signature)
 107 {
 108         uchar_t digest[MD5_DIGEST_LENGTH];
 109         smb_sign_ctx_t ctx = 0;
 110         mblk_t *m = mp;
 111         int size;
 112         int rc;
 113 
 114         /*
 115          * This union is a little bit of trickery to:
 116          * (1) get the sequence number int aligned, and
 117          * (2) reduce the number of digest calls, at the
 118          * cost of a copying 32 bytes instead of 8.
 119          * Both sides of this union are 2+32 bytes.
 120          */
 121         union {
 122                 struct {
 123                         uint8_t skip[2]; /* not used - just alignment */
 124                         uint8_t raw[SMB_HDRLEN];  /* header length (32) */
 125                 } r;
 126                 struct {
 127                         uint8_t skip[2]; /* not used - just alignment */
 128                         uint8_t hdr[SMBSIGOFF]; /* sig. offset (14) */
 129                         uint32_t sig[2]; /* MAC signature, aligned! */
 130                         uint16_t ids[5]; /* pad, Tid, Pid, Uid, Mid */
 131                 } s;
 132         } smbhdr;
 133 
 134         if (vcp->vc_mackey == NULL)
 135                 return (-1);

 136 
 137         if ((rc = smb_md5_init(&ctx, &vcp->vc_signmech)) != 0)
 138                 return (rc);
 139 
 140         /* Digest the MAC Key */
 141         rc = smb_md5_update(ctx, vcp->vc_mackey, vcp->vc_mackeylen);
 142         if (rc != 0)
 143                 return (rc);
 144 
 145         /* Our caller should ensure mp has a contiguous header */
 146         ASSERT(m != NULL);
 147         ASSERT(MBLKL(m) >= SMB_HDRLEN);
 148 
 149         /*
 150          * Make an aligned copy of the SMB header,
 151          * fill in the sequence number, and digest.
 152          */
 153         size = SMB_HDRLEN;
 154         bcopy(m->b_rptr, smbhdr.r.raw, size);
 155         smbhdr.s.sig[0] = htolel(seqno);
 156         smbhdr.s.sig[1] = 0;
 157 
 158         rc = smb_md5_update(ctx, &smbhdr.r.raw, size);
 159         if (rc != 0)
 160                 return (rc);
 161 
 162         /*
 163          * Digest the rest of the SMB header packet, starting at
 164          * the data just after the SMB header.
 165          */
 166         size = MBLKL(m) - SMB_HDRLEN;
 167         rc = smb_md5_update(ctx, m->b_rptr + SMB_HDRLEN, size);
 168         if (rc != 0)
 169                 return (rc);
 170         m = m->b_cont;


 171 






















 172         /* Digest rest of the SMB message. */
 173         while (m != NULL) {
 174                 size = MBLKL(m);
 175                 if (size > 0) {
 176                         rc = smb_md5_update(ctx, m->b_rptr, size);
 177                         if (rc != 0)
 178                                 return (rc);
 179                 }
 180                 m = m->b_cont;
 181         }
 182         rc = smb_md5_final(ctx, digest);
 183         if (rc != 0)
 184                 return (rc);
 185 











 186         /*
 187          * Finally, store the signature.
 188          * (first 8 bytes of the mac)
 189          */
 190         if (signature != NULL)
 191                 bcopy(digest, signature, SMBSIGLEN);
 192 
 193         return (0);
 194 }
 195 
 196 /*
 197  * Sign a request with HMAC-MD5.
 198  */
 199 void
 200 smb_rq_sign(struct smb_rq *rqp)
 201 {
 202         struct smb_vc *vcp = rqp->sr_vc;
 203         mblk_t *mp = rqp->sr_rq.mb_top;
 204         uint8_t *sigloc;
 205         int status;
 206 
 207         /*
 208          * smb_rq_new() ensures this,
 209          * but just in case..
 210          */
 211         ASSERT(MBLKL(mp) >= SMB_HDRLEN);



 212         sigloc = mp->b_rptr + SMBSIGOFF;
 213 
 214         if (vcp->vc_mackey == NULL) {
 215                 /*
 216                  * Signing is required, but we have no key yet
 217                  * fill in with the magic fake signing value.
 218                  * This happens with SPNEGO, NTLMSSP, ...
 219                  */
 220                 bcopy("BSRSPLY", sigloc, 8);
 221                 return;
 222         }
 223 
 224         /*
 225          * This will compute the MAC and store it
 226          * directly into the message at sigloc.
 227          */
 228         status = smb_compute_MAC(vcp, mp, rqp->sr_seqno, sigloc);
 229         if (status != 0) {
 230                 SMBSDEBUG("Crypto error %d", status);
 231                 bzero(sigloc, SMBSIGLEN);
 232         }
 233 }
 234 
 235 /*
 236  * Verify reply signature.
 237  */
 238 int
 239 smb_rq_verify(struct smb_rq *rqp)
 240 {
 241         struct smb_vc *vcp = rqp->sr_vc;
 242         mblk_t *mp = rqp->sr_rp.md_top;
 243         uint8_t sigbuf[SMBSIGLEN];
 244         uint8_t *sigloc;
 245         int fudge, rsn, status;
 246 
 247         /*
 248          * Note vc_mackey and vc_mackeylen gets filled in by
 249          * smb_usr_iod_work as the connection comes in.
 250          */
 251         if (vcp->vc_mackey == NULL) {
 252                 SMBSDEBUG("no mac key\n");
 253                 return (0);
 254         }
 255 
 256         /*
 257          * Let caller deal with empty reply or short messages by
 258          * returning zero.  Caller will fail later, in parsing.
 259          */
 260         if (mp == NULL) {
 261                 SMBSDEBUG("empty reply\n");
 262                 return (0);
 263         }
 264 
 265         ASSERT(MBLKL(mp) >= SMB_HDRLEN);


 266         sigloc = mp->b_rptr + SMBSIGOFF;
 267 
 268         /*
 269          * Compute the expected signature in sigbuf.
 270          */
 271         rsn = rqp->sr_rseqno;
 272         status = smb_compute_MAC(vcp, mp, rsn, sigbuf);
 273         if (status != 0) {
 274                 SMBSDEBUG("Crypto error %d", status);
 275                 /*
 276                  * If we can't compute a MAC, then there's
 277                  * no point trying other seqno values.
 278                  */
 279                 return (EBADRPC);
 280         }
 281 
 282         /*
 283          * Compare the computed signature with the
 284          * one found in the message (at sigloc)
 285          */
 286         if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0)
 287                 return (0);
 288 
 289         SMBERROR("BAD signature, Server=%s MID=0x%x Seq=%d\n",
 290             vcp->vc_srvname, rqp->sr_mid, rsn);
 291 
 292 #ifdef DEBUG
 293         /*