]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Jul 2013 21:06:30 +0000 (14:06 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Jul 2013 21:06:30 +0000 (14:06 -0700)
Pull cifs updates from Steve French:
 "Various CIFS/SMB2/SMB3 updates for 3.11.  Includes bug fixes - SMB3
  support should be much more stable with key DFS fix and also signing
  possible now (although is more work to do to get SMB3 signing working
  well with multiuser).

  Mounts using the new SMB 3.02 dialect can now be done (specify
  "vers=3.02" on mount) against the most current Microsoft systems.

  Also includes a big cleanup of the cifs/smb2/smb3 authentication code
  from Jeff which fixes some long standing problems with the way allowed
  authentication flavors and signing are configured.

  Some followon patches later in the cycle will clean up allocation of
  structures for the various security mechanisms depending on what
  dialect is chosen (reduces memory usage a little) and to add support
  for the secure negotiate fsctl (for smb3) which prevents downgrade
  attacks."

* 'for-next' of git://git.samba.org/sfrench/cifs-2.6: (39 commits)
  cifs: fill TRANS2_QUERY_FILE_INFO ByteCount fields
  cifs: fix SMB2 signing enablement in cifs_enable_signing
  [CIFS] Fix build warning
  [CIFS] SMB3 Signing enablement
  [CIFS] Do not set DFS flag on SMB2 open
  [CIFS] fix static checker warning
  cifs: try to handle the MUST SecurityFlags sanely
  When server doesn't provide SecurityBuffer on SMB2Negotiate pick default
  Handle big endianness in NTLM (ntlmv2) authentication
  revalidate directories instiantiated via FIND_* in order to handle DFS referrals
  SMB2 FSCTL and IOCTL worker function
  Charge at least one credit, if server says that it supports multicredit
  Remove typo
  Some missing share flags
  cifs: using strlcpy instead of strncpy
  Update headers to update various SMB3 ioctl definitions
  Update cifs version number
  Add ability to dipslay SMB3 share flags and capabilities for debugging
  Add some missing SMB3 and SMB3.02 flags
  Add SMB3.02 dialect support
  ...

24 files changed:
fs/cifs/Kconfig
fs/cifs/cifs_debug.c
fs/cifs/cifs_unicode.h
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/misc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2glob.h
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/smbfsctl.h
fs/cifs/transport.c

index 2906ee2764082786520718e4e4a490b9f3211ac6..603f18a65c121e5586f903baff101a8637bdb852 100644 (file)
@@ -10,6 +10,7 @@ config CIFS
        select CRYPTO_ECB
        select CRYPTO_DES
        select CRYPTO_SHA256
+       select CRYPTO_CMAC
        help
          This is the client VFS module for the Common Internet File System
          (CIFS) protocol which is the successor to the Server Message Block
index d59748346020f9302be6a5cf66730b9190f0af9d..f3ac4154cbb606707956d9fbbd2a64ec553a9ceb 100644 (file)
@@ -213,7 +213,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                                                   tcon->nativeFileSystem);
                                }
                                seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x"
-                                       "\nPathComponentMax: %d Status: 0x%d",
+                                       "\n\tPathComponentMax: %d Status: 0x%d",
                                        le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics),
                                        le32_to_cpu(tcon->fsAttrInfo.Attributes),
                                        le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength),
@@ -224,6 +224,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                                        seq_puts(m, " type: CDROM ");
                                else
                                        seq_printf(m, " type: %d ", dev_type);
+                               if (server->ops->dump_share_caps)
+                                       server->ops->dump_share_caps(m, tcon);
 
                                if (tcon->need_reconnect)
                                        seq_puts(m, "\tDISCONNECTED ");
@@ -595,9 +597,36 @@ static int cifs_security_flags_proc_open(struct inode *inode, struct file *file)
        return single_open(file, cifs_security_flags_proc_show, NULL);
 }
 
+/*
+ * Ensure that if someone sets a MUST flag, that we disable all other MAY
+ * flags except for the ones corresponding to the given MUST flag. If there are
+ * multiple MUST flags, then try to prefer more secure ones.
+ */
+static void
+cifs_security_flags_handle_must_flags(unsigned int *flags)
+{
+       unsigned int signflags = *flags & CIFSSEC_MUST_SIGN;
+
+       if ((*flags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
+               *flags = CIFSSEC_MUST_KRB5;
+       else if ((*flags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
+               *flags = CIFSSEC_MUST_NTLMSSP;
+       else if ((*flags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
+               *flags = CIFSSEC_MUST_NTLMV2;
+       else if ((*flags & CIFSSEC_MUST_NTLM) == CIFSSEC_MUST_NTLM)
+               *flags = CIFSSEC_MUST_NTLM;
+       else if ((*flags & CIFSSEC_MUST_LANMAN) == CIFSSEC_MUST_LANMAN)
+               *flags = CIFSSEC_MUST_LANMAN;
+       else if ((*flags & CIFSSEC_MUST_PLNTXT) == CIFSSEC_MUST_PLNTXT)
+               *flags = CIFSSEC_MUST_PLNTXT;
+
+       *flags |= signflags;
+}
+
 static ssize_t cifs_security_flags_proc_write(struct file *file,
                const char __user *buffer, size_t count, loff_t *ppos)
 {
+       int rc;
        unsigned int flags;
        char flags_string[12];
        char c;
@@ -620,26 +649,35 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
                        global_secflags = CIFSSEC_MAX;
                        return count;
                } else if (!isdigit(c)) {
-                       cifs_dbg(VFS, "invalid flag %c\n", c);
+                       cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
+                                       flags_string);
                        return -EINVAL;
                }
        }
-       /* else we have a number */
 
-       flags = simple_strtoul(flags_string, NULL, 0);
+       /* else we have a number */
+       rc = kstrtouint(flags_string, 0, &flags);
+       if (rc) {
+               cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
+                               flags_string);
+               return rc;
+       }
 
        cifs_dbg(FYI, "sec flags 0x%x\n", flags);
 
-       if (flags <= 0)  {
-               cifs_dbg(VFS, "invalid security flags %s\n", flags_string);
+       if (flags == 0)  {
+               cifs_dbg(VFS, "Invalid SecurityFlags: %s\n", flags_string);
                return -EINVAL;
        }
 
        if (flags & ~CIFSSEC_MASK) {
-               cifs_dbg(VFS, "attempt to set unsupported security flags 0x%x\n",
+               cifs_dbg(VFS, "Unsupported security flags: 0x%x\n",
                         flags & ~CIFSSEC_MASK);
                return -EINVAL;
        }
+
+       cifs_security_flags_handle_must_flags(&flags);
+
        /* flags look ok - update the global security flags for cifs module */
        global_secflags = flags;
        if (global_secflags & CIFSSEC_MUST_SIGN) {
index 4fb097468e214feb00b8602dd6dd658b20fafd88..fe8d6276410a5613230743f20312d4f283db2f4f 100644 (file)
@@ -327,14 +327,14 @@ UniToupper(register wchar_t uc)
 /*
  * UniStrupr:  Upper case a unicode string
  */
-static inline wchar_t *
-UniStrupr(register wchar_t *upin)
+static inline __le16 *
+UniStrupr(register __le16 *upin)
 {
-       register wchar_t *up;
+       register __le16 *up;
 
        up = upin;
        while (*up) {           /* For all characters */
-               *up = UniToupper(*up);
+               *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
                up++;
        }
        return upin;            /* Return input pointer */
index 71436d1fca13bede14a8a25ac6a9ae126e80dede..3d8bf941d1269ff3afa45baf1ed9f5aee8491431 100644 (file)
@@ -276,7 +276,6 @@ int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
                strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);
 
        if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
-               memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
                memcpy(lnm_session_key, password_with_pad,
                        CIFS_ENCPWD_SIZE);
                return 0;
@@ -414,7 +413,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
        int rc = 0;
        int len;
        char nt_hash[CIFS_NTHASH_SIZE];
-       wchar_t *user;
+       __le16 *user;
        wchar_t *domain;
        wchar_t *server;
 
@@ -439,7 +438,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
                return rc;
        }
 
-       /* convert ses->user_name to unicode and uppercase */
+       /* convert ses->user_name to unicode */
        len = ses->user_name ? strlen(ses->user_name) : 0;
        user = kmalloc(2 + (len * 2), GFP_KERNEL);
        if (user == NULL) {
@@ -448,7 +447,7 @@ static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash,
        }
 
        if (len) {
-               len = cifs_strtoUTF16((__le16 *)user, ses->user_name, len, nls_cp);
+               len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp);
                UniStrupr(user);
        } else {
                memset(user, '\0', 2);
@@ -536,7 +535,7 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
                return rc;
        }
 
-       if (ses->server->secType == RawNTLMSSP)
+       if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED)
                memcpy(ses->auth_key.response + offset,
                        ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
        else
@@ -568,7 +567,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
        char ntlmv2_hash[16];
        unsigned char *tiblob = NULL; /* target info blob */
 
-       if (ses->server->secType == RawNTLMSSP) {
+       if (ses->server->negflavor == CIFS_NEGFLAVOR_EXTENDED) {
                if (!ses->domainName) {
                        rc = find_domain_name(ses, nls_cp);
                        if (rc) {
@@ -706,6 +705,9 @@ calc_seckey(struct cifs_ses *ses)
 void
 cifs_crypto_shash_release(struct TCP_Server_Info *server)
 {
+       if (server->secmech.cmacaes)
+               crypto_free_shash(server->secmech.cmacaes);
+
        if (server->secmech.hmacsha256)
                crypto_free_shash(server->secmech.hmacsha256);
 
@@ -715,6 +717,8 @@ cifs_crypto_shash_release(struct TCP_Server_Info *server)
        if (server->secmech.hmacmd5)
                crypto_free_shash(server->secmech.hmacmd5);
 
+       kfree(server->secmech.sdesccmacaes);
+
        kfree(server->secmech.sdeschmacsha256);
 
        kfree(server->secmech.sdeschmacmd5);
@@ -748,6 +752,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
                goto crypto_allocate_hmacsha256_fail;
        }
 
+       server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
+       if (IS_ERR(server->secmech.cmacaes)) {
+               cifs_dbg(VFS, "could not allocate crypto cmac-aes");
+               rc = PTR_ERR(server->secmech.cmacaes);
+               goto crypto_allocate_cmacaes_fail;
+       }
+
        size = sizeof(struct shash_desc) +
                        crypto_shash_descsize(server->secmech.hmacmd5);
        server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
@@ -778,8 +789,22 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
        server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
        server->secmech.sdeschmacsha256->shash.flags = 0x0;
 
+       size = sizeof(struct shash_desc) +
+                       crypto_shash_descsize(server->secmech.cmacaes);
+       server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
+       if (!server->secmech.sdesccmacaes) {
+               cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
+               rc = -ENOMEM;
+               goto crypto_allocate_cmacaes_sdesc_fail;
+       }
+       server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
+       server->secmech.sdesccmacaes->shash.flags = 0x0;
+
        return 0;
 
+crypto_allocate_cmacaes_sdesc_fail:
+       kfree(server->secmech.sdeschmacsha256);
+
 crypto_allocate_hmacsha256_sdesc_fail:
        kfree(server->secmech.sdescmd5);
 
@@ -787,6 +812,9 @@ crypto_allocate_md5_sdesc_fail:
        kfree(server->secmech.sdeschmacmd5);
 
 crypto_allocate_hmacmd5_sdesc_fail:
+       crypto_free_shash(server->secmech.cmacaes);
+
+crypto_allocate_cmacaes_fail:
        crypto_free_shash(server->secmech.hmacsha256);
 
 crypto_allocate_hmacsha256_fail:
index a445e71746fabdcaf308d6a2fbe9365e40cba849..4bdd547dbf6fb3d10a2b2b962b710b722d0b9685 100644 (file)
@@ -312,11 +312,14 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
 }
 
 static void
-cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server)
+cifs_show_security(struct seq_file *s, struct cifs_ses *ses)
 {
+       if (ses->sectype == Unspecified)
+               return;
+
        seq_printf(s, ",sec=");
 
-       switch (server->secType) {
+       switch (ses->sectype) {
        case LANMAN:
                seq_printf(s, "lanman");
                break;
@@ -338,7 +341,7 @@ cifs_show_security(struct seq_file *s, struct TCP_Server_Info *server)
                break;
        }
 
-       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->sign)
                seq_printf(s, "i");
 }
 
@@ -369,7 +372,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
        srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr;
 
        seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string);
-       cifs_show_security(s, tcon->ses->server);
+       cifs_show_security(s, tcon->ses);
        cifs_show_cache_flavor(s, cifs_sb);
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)
index d05b3028e3b96ef7c99eaa202d10bc22630489e7..ea723a5e8226231d64cd85eab065c7f91801a3a0 100644 (file)
@@ -132,5 +132,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* CONFIG_CIFS_NFSD_EXPORT */
 
-#define CIFS_VERSION   "2.0"
+#define CIFS_VERSION   "2.01"
 #endif                         /* _CIFSFS_H */
index 4f07f6fbe4944c5e6f8bdf12c30b4eaed9397976..e66b08882548eb90597fcb6ea0f86139a710b204 100644 (file)
@@ -101,20 +101,14 @@ enum statusEnum {
 };
 
 enum securityEnum {
-       LANMAN = 0,                     /* Legacy LANMAN auth */
+       Unspecified = 0,        /* not specified */
+       LANMAN,                 /* Legacy LANMAN auth */
        NTLM,                   /* Legacy NTLM012 auth with NTLM hash */
        NTLMv2,                 /* Legacy NTLM auth with NTLMv2 hash */
        RawNTLMSSP,             /* NTLMSSP without SPNEGO, NTLMv2 hash */
-/*     NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */
        Kerberos,               /* Kerberos via SPNEGO */
 };
 
-enum protocolEnum {
-       TCP = 0,
-       SCTP
-       /* Netbios frames protocol not supported at this time */
-};
-
 struct session_key {
        unsigned int len;
        char *response;
@@ -131,9 +125,11 @@ struct cifs_secmech {
        struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
        struct crypto_shash *md5; /* md5 hash function */
        struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
+       struct crypto_shash *cmacaes; /* block-cipher based MAC function */
        struct sdesc *sdeschmacmd5;  /* ctxt to generate ntlmv2 hash, CR1 */
        struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
        struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
+       struct sdesc *sdesccmacaes;  /* ctxt to generate smb3 signature */
 };
 
 /* per smb session structure/fields */
@@ -181,6 +177,7 @@ enum smb_version {
        Smb_20,
        Smb_21,
        Smb_30,
+       Smb_302,
 };
 
 struct mid_q_entry;
@@ -228,6 +225,7 @@ struct smb_version_operations {
        void (*dump_detail)(void *);
        void (*clear_stats)(struct cifs_tcon *);
        void (*print_stats)(struct seq_file *m, struct cifs_tcon *);
+       void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *);
        /* verify the message */
        int (*check_message)(char *, unsigned int);
        bool (*is_oplock_break)(char *, struct TCP_Server_Info *);
@@ -367,6 +365,8 @@ struct smb_version_operations {
        void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
        /* generate new lease key */
        void (*new_lease_key)(struct cifs_fid *fid);
+       /* The next two functions will need to be changed to per smb session */
+       void (*generate_signingkey)(struct TCP_Server_Info *server);
        int (*calc_signature)(struct smb_rqst *rqst,
                                   struct TCP_Server_Info *server);
 };
@@ -387,6 +387,8 @@ struct smb_version_values {
        unsigned int    cap_nt_find;
        unsigned int    cap_large_files;
        unsigned int    oplock_read;
+       __u16           signing_enabled;
+       __u16           signing_required;
 };
 
 #define HEADER_SIZE(server) (server->vals->header_size)
@@ -407,7 +409,8 @@ struct smb_vol {
        kgid_t backupgid;
        umode_t file_mode;
        umode_t dir_mode;
-       unsigned secFlg;
+       enum securityEnum sectype; /* sectype requested via mnt opts */
+       bool sign; /* was signing requested via mnt opts? */
        bool retry:1;
        bool intr:1;
        bool setuids:1;
@@ -441,6 +444,7 @@ struct smb_vol {
        bool mfsymlinks:1; /* use Minshall+French Symlinks */
        bool multiuser:1;
        bool rwpidforward:1; /* pid forward for read/write operations */
+       bool nosharesock;
        unsigned int rsize;
        unsigned int wsize;
        bool sockopt_tcp_nodelay:1;
@@ -514,6 +518,7 @@ struct TCP_Server_Info {
        struct task_struct *tsk;
        char server_GUID[16];
        __u16 sec_mode;
+       bool sign; /* is signing enabled on this connection? */
        bool session_estab; /* mark when very first sess is established */
 #ifdef CONFIG_CIFS_SMB2
        int echo_credits;  /* echo reserved slots */
@@ -521,7 +526,6 @@ struct TCP_Server_Info {
        bool echoes:1; /* enable echoes */
 #endif
        u16 dialect; /* dialect index that server chose */
-       enum securityEnum secType;
        bool oplocks:1; /* enable oplocks */
        unsigned int maxReq;    /* Clients should submit no more */
        /* than maxReq distinct unanswered SMBs to the server when using  */
@@ -540,12 +544,17 @@ struct TCP_Server_Info {
        int timeAdj;  /* Adjust for difference in server time zone in sec */
        __u64 CurrentMid;         /* multiplex id - rotating counter */
        char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
+       char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* for signing, protected by srv_mutex */
        struct session_key session_key;
        unsigned long lstrp; /* when we got last response from this server */
        struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */
+#define        CIFS_NEGFLAVOR_LANMAN   0       /* wct == 13, LANMAN */
+#define        CIFS_NEGFLAVOR_UNENCAP  1       /* wct == 17, but no ext_sec */
+#define        CIFS_NEGFLAVOR_EXTENDED 2       /* wct == 17, ext_sec bit set */
+       char    negflavor;      /* NEGOTIATE response flavor */
        /* extended security flavors that server supports */
        bool    sec_ntlmssp;            /* supports NTLMSSP */
        bool    sec_kerberosu2u;        /* supports U2U Kerberos */
@@ -697,7 +706,6 @@ struct cifs_ses {
        enum statusEnum status;
        unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
-       __u16 flags;
        __u16 vcnum;
        char *serverOS;         /* name of operating system underlying server */
        char *serverNOS;        /* name of network operating system of server */
@@ -714,21 +722,14 @@ struct cifs_ses {
        char *password;
        struct session_key auth_key;
        struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
+       enum securityEnum sectype; /* what security flavor was specified? */
+       bool sign;              /* is signing required? */
        bool need_reconnect:1; /* connection reset, uid now invalid */
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
 #endif /* CONFIG_CIFS_SMB2 */
 };
 
-/* no more than one of the following three session flags may be set */
-#define CIFS_SES_NT4 1
-#define CIFS_SES_OS2 2
-#define CIFS_SES_W9X 4
-/* following flag is set for old servers such as OS2 (and Win95?)
-   which do not negotiate NTLM or POSIX dialects, but instead
-   negotiate one of the older LANMAN dialects */
-#define CIFS_SES_LANMAN 8
-
 static inline bool
 cap_unix(struct cifs_ses *ses)
 {
@@ -816,7 +817,7 @@ struct cifs_tcon {
 #ifdef CONFIG_CIFS_SMB2
        bool print:1;           /* set if connection to printer share */
        bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
-       __u32 capabilities;
+       __le32 capabilities;
        __u32 share_flags;
        __u32 maximal_access;
        __u32 vol_serial_number;
@@ -1348,7 +1349,7 @@ require use of the stronger protocol */
 #define   CIFSSEC_MUST_SEAL    0x40040 /* not supported yet */
 #define   CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */
 
-#define   CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLMSSP)
+#define   CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_NTLMSSP)
 #define   CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2)
 #define   CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP)
 /*
@@ -1494,4 +1495,7 @@ extern struct smb_version_values smb21_values;
 #define SMB30_VERSION_STRING   "3.0"
 extern struct smb_version_operations smb30_operations;
 extern struct smb_version_values smb30_values;
+#define SMB302_VERSION_STRING  "3.02"
+/*extern struct smb_version_operations smb302_operations;*/ /* not needed yet */
+extern struct smb_version_values smb302_values;
 #endif /* _CIFS_GLOB_H */
index e996ff6b26d1886f63a6c162a09a996e80edf32a..11ca24a8e054ef11472ba634472e6e8622008305 100644 (file)
  */
 #define CIFS_SESS_KEY_SIZE (16)
 
+/*
+ * Size of the smb3 signing key
+ */
+#define SMB3_SIGN_KEY_SIZE (16)
+
 #define CIFS_CLIENT_CHALLENGE_SIZE (8)
 #define CIFS_SERVER_CHALLENGE_SIZE (8)
 #define CIFS_HMAC_MD5_HASH_SIZE (16)
@@ -531,7 +536,7 @@ typedef struct lanman_neg_rsp {
 #define READ_RAW_ENABLE 1
 #define WRITE_RAW_ENABLE 2
 #define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE)
-
+#define SMB1_CLIENT_GUID_SIZE (16)
 typedef struct negotiate_rsp {
        struct smb_hdr hdr;     /* wct = 17 */
        __le16 DialectIndex; /* 0xFFFF = no dialect acceptable */
@@ -553,7 +558,7 @@ typedef struct negotiate_rsp {
                /* followed by 16 bytes of server GUID */
                /* then security blob if cap_extended_security negotiated */
                struct {
-                       unsigned char GUID[16];
+                       unsigned char GUID[SMB1_CLIENT_GUID_SIZE];
                        unsigned char SecurityBlob[1];
                } __attribute__((packed)) extended_response;
        } __attribute__((packed)) u;
@@ -1315,6 +1320,14 @@ typedef struct smb_com_ntransact_rsp {
        /* parms and data follow */
 } __attribute__((packed)) NTRANSACT_RSP;
 
+/* See MS-SMB 2.2.7.2.1.1 */
+struct srv_copychunk {
+       __le64 SourceOffset;
+       __le64 DestinationOffset;
+       __le32 CopyLength;
+       __u32  Reserved;
+} __packed;
+
 typedef struct smb_com_transaction_ioctl_req {
        struct smb_hdr hdr;     /* wct = 23 */
        __u8 MaxSetupCount;
index dda188a94332bfbf569121680d3207360e1acc3a..c8ff018fae6887640c277269c649feae49545ce2 100644 (file)
@@ -118,6 +118,8 @@ extern void header_assemble(struct smb_hdr *, char /* command */ ,
 extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
                                struct cifs_ses *ses,
                                void **request_buf);
+extern enum securityEnum select_sectype(struct TCP_Server_Info *server,
+                               enum securityEnum requested);
 extern int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
                          const struct nls_table *nls_cp);
 extern struct timespec cifs_NTtimeToUnix(__le64 utc_nanoseconds_since_1601);
@@ -212,6 +214,7 @@ extern int cifs_negotiate_protocol(const unsigned int xid,
                                   struct cifs_ses *ses);
 extern int cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
                              struct nls_table *nls_info);
+extern int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required);
 extern int CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses);
 
 extern int CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
@@ -433,6 +436,7 @@ extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
 extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
 extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
 extern int calc_seckey(struct cifs_ses *);
+extern void generate_smb3signingkey(struct TCP_Server_Info *);
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 extern int calc_lanman_hash(const char *password, const char *cryptkey,
index a58dc77cc4430d57d8c8226c3120f3a12519fb00..a89c4cb4e6cf64e8cbd92fe6f7ceb6b7e941eca3 100644 (file)
@@ -367,6 +367,185 @@ vt2_err:
        return -EINVAL;
 }
 
+static int
+decode_ext_sec_blob(struct cifs_ses *ses, NEGOTIATE_RSP *pSMBr)
+{
+       int     rc = 0;
+       u16     count;
+       char    *guid = pSMBr->u.extended_response.GUID;
+       struct TCP_Server_Info *server = ses->server;
+
+       count = get_bcc(&pSMBr->hdr);
+       if (count < SMB1_CLIENT_GUID_SIZE)
+               return -EIO;
+
+       spin_lock(&cifs_tcp_ses_lock);
+       if (server->srv_count > 1) {
+               spin_unlock(&cifs_tcp_ses_lock);
+               if (memcmp(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE) != 0) {
+                       cifs_dbg(FYI, "server UID changed\n");
+                       memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
+               }
+       } else {
+               spin_unlock(&cifs_tcp_ses_lock);
+               memcpy(server->server_GUID, guid, SMB1_CLIENT_GUID_SIZE);
+       }
+
+       if (count == SMB1_CLIENT_GUID_SIZE) {
+               server->sec_ntlmssp = true;
+       } else {
+               count -= SMB1_CLIENT_GUID_SIZE;
+               rc = decode_negTokenInit(
+                       pSMBr->u.extended_response.SecurityBlob, count, server);
+               if (rc != 1)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+int
+cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required)
+{
+       bool srv_sign_required = server->sec_mode & server->vals->signing_required;
+       bool srv_sign_enabled = server->sec_mode & server->vals->signing_enabled;
+       bool mnt_sign_enabled = global_secflags & CIFSSEC_MAY_SIGN;
+
+       /*
+        * Is signing required by mnt options? If not then check
+        * global_secflags to see if it is there.
+        */
+       if (!mnt_sign_required)
+               mnt_sign_required = ((global_secflags & CIFSSEC_MUST_SIGN) ==
+                                               CIFSSEC_MUST_SIGN);
+
+       /*
+        * If signing is required then it's automatically enabled too,
+        * otherwise, check to see if the secflags allow it.
+        */
+       mnt_sign_enabled = mnt_sign_required ? mnt_sign_required :
+                               (global_secflags & CIFSSEC_MAY_SIGN);
+
+       /* If server requires signing, does client allow it? */
+       if (srv_sign_required) {
+               if (!mnt_sign_enabled) {
+                       cifs_dbg(VFS, "Server requires signing, but it's disabled in SecurityFlags!");
+                       return -ENOTSUPP;
+               }
+               server->sign = true;
+       }
+
+       /* If client requires signing, does server allow it? */
+       if (mnt_sign_required) {
+               if (!srv_sign_enabled) {
+                       cifs_dbg(VFS, "Server does not support signing!");
+                       return -ENOTSUPP;
+               }
+               server->sign = true;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+static int
+decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
+{
+       __s16 tmp;
+       struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
+
+       if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
+               return -EOPNOTSUPP;
+
+       server->sec_mode = le16_to_cpu(rsp->SecurityMode);
+       server->maxReq = min_t(unsigned int,
+                              le16_to_cpu(rsp->MaxMpxCount),
+                              cifs_max_pending);
+       set_credits(server, server->maxReq);
+       server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
+       server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
+       /* even though we do not use raw we might as well set this
+       accurately, in case we ever find a need for it */
+       if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
+               server->max_rw = 0xFF00;
+               server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
+       } else {
+               server->max_rw = 0;/* do not need to use raw anyway */
+               server->capabilities = CAP_MPX_MODE;
+       }
+       tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
+       if (tmp == -1) {
+               /* OS/2 often does not set timezone therefore
+                * we must use server time to calc time zone.
+                * Could deviate slightly from the right zone.
+                * Smallest defined timezone difference is 15 minutes
+                * (i.e. Nepal).  Rounding up/down is done to match
+                * this requirement.
+                */
+               int val, seconds, remain, result;
+               struct timespec ts, utc;
+               utc = CURRENT_TIME;
+               ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
+                                   rsp->SrvTime.Time, 0);
+               cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
+                        (int)ts.tv_sec, (int)utc.tv_sec,
+                        (int)(utc.tv_sec - ts.tv_sec));
+               val = (int)(utc.tv_sec - ts.tv_sec);
+               seconds = abs(val);
+               result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
+               remain = seconds % MIN_TZ_ADJ;
+               if (remain >= (MIN_TZ_ADJ / 2))
+                       result += MIN_TZ_ADJ;
+               if (val < 0)
+                       result = -result;
+               server->timeAdj = result;
+       } else {
+               server->timeAdj = (int)tmp;
+               server->timeAdj *= 60; /* also in seconds */
+       }
+       cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
+
+
+       /* BB get server time for time conversions and add
+       code to use it and timezone since this is not UTC */
+
+       if (rsp->EncryptionKeyLength ==
+                       cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
+               memcpy(server->cryptkey, rsp->EncryptionKey,
+                       CIFS_CRYPTO_KEY_SIZE);
+       } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
+               return -EIO; /* need cryptkey unless plain text */
+       }
+
+       cifs_dbg(FYI, "LANMAN negotiated\n");
+       return 0;
+}
+#else
+static inline int
+decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
+{
+       cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
+       return -EOPNOTSUPP;
+}
+#endif
+
+static bool
+should_set_ext_sec_flag(enum securityEnum sectype)
+{
+       switch (sectype) {
+       case RawNTLMSSP:
+       case Kerberos:
+               return true;
+       case Unspecified:
+               if (global_secflags &
+                   (CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP))
+                       return true;
+               /* Fallthrough */
+       default:
+               return false;
+       }
+}
+
 int
 CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
 {
@@ -375,41 +554,24 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
        int rc = 0;
        int bytes_returned;
        int i;
-       struct TCP_Server_Info *server;
+       struct TCP_Server_Info *server = ses->server;
        u16 count;
-       unsigned int secFlags;
 
-       if (ses->server)
-               server = ses->server;
-       else {
-               rc = -EIO;
-               return rc;
+       if (!server) {
+               WARN(1, "%s: server is NULL!\n", __func__);
+               return -EIO;
        }
+
        rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
                      (void **) &pSMB, (void **) &pSMBr);
        if (rc)
                return rc;
 
-       /* if any of auth flags (ie not sign or seal) are overriden use them */
-       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               secFlags = ses->overrideSecFlg;  /* BB FIXME fix sign flags? */
-       else /* if override flags set only sign/seal OR them with global auth */
-               secFlags = global_secflags | ses->overrideSecFlg;
-
-       cifs_dbg(FYI, "secFlags 0x%x\n", secFlags);
-
        pSMB->hdr.Mid = get_next_mid(server);
        pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS);
 
-       if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
-               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) {
-               cifs_dbg(FYI, "Kerberos only mechanism, enable extended security\n");
-               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP)
-               pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) {
-               cifs_dbg(FYI, "NTLMSSP only mechanism, enable extended security\n");
+       if (should_set_ext_sec_flag(ses->sectype)) {
+               cifs_dbg(FYI, "Requesting extended security.");
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
        }
 
@@ -436,127 +598,21 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
                could not negotiate a common dialect */
                rc = -EOPNOTSUPP;
                goto neg_err_exit;
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-       } else if ((pSMBr->hdr.WordCount == 13)
-                       && ((server->dialect == LANMAN_PROT)
-                               || (server->dialect == LANMAN2_PROT))) {
-               __s16 tmp;
-               struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
-
-               if ((secFlags & CIFSSEC_MAY_LANMAN) ||
-                       (secFlags & CIFSSEC_MAY_PLNTXT))
-                       server->secType = LANMAN;
-               else {
-                       cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
-                       rc = -EOPNOTSUPP;
-                       goto neg_err_exit;
-               }
-               server->sec_mode = le16_to_cpu(rsp->SecurityMode);
-               server->maxReq = min_t(unsigned int,
-                                      le16_to_cpu(rsp->MaxMpxCount),
-                                      cifs_max_pending);
-               set_credits(server, server->maxReq);
-               server->maxBuf = le16_to_cpu(rsp->MaxBufSize);
-               server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
-               /* even though we do not use raw we might as well set this
-               accurately, in case we ever find a need for it */
-               if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
-                       server->max_rw = 0xFF00;
-                       server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
-               } else {
-                       server->max_rw = 0;/* do not need to use raw anyway */
-                       server->capabilities = CAP_MPX_MODE;
-               }
-               tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
-               if (tmp == -1) {
-                       /* OS/2 often does not set timezone therefore
-                        * we must use server time to calc time zone.
-                        * Could deviate slightly from the right zone.
-                        * Smallest defined timezone difference is 15 minutes
-                        * (i.e. Nepal).  Rounding up/down is done to match
-                        * this requirement.
-                        */
-                       int val, seconds, remain, result;
-                       struct timespec ts, utc;
-                       utc = CURRENT_TIME;
-                       ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
-                                           rsp->SrvTime.Time, 0);
-                       cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
-                                (int)ts.tv_sec, (int)utc.tv_sec,
-                                (int)(utc.tv_sec - ts.tv_sec));
-                       val = (int)(utc.tv_sec - ts.tv_sec);
-                       seconds = abs(val);
-                       result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
-                       remain = seconds % MIN_TZ_ADJ;
-                       if (remain >= (MIN_TZ_ADJ / 2))
-                               result += MIN_TZ_ADJ;
-                       if (val < 0)
-                               result = -result;
-                       server->timeAdj = result;
-               } else {
-                       server->timeAdj = (int)tmp;
-                       server->timeAdj *= 60; /* also in seconds */
-               }
-               cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj);
-
-
-               /* BB get server time for time conversions and add
-               code to use it and timezone since this is not UTC */
-
-               if (rsp->EncryptionKeyLength ==
-                               cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
-                       memcpy(ses->server->cryptkey, rsp->EncryptionKey,
-                               CIFS_CRYPTO_KEY_SIZE);
-               } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
-                       rc = -EIO; /* need cryptkey unless plain text */
-                       goto neg_err_exit;
-               }
-
-               cifs_dbg(FYI, "LANMAN negotiated\n");
-               /* we will not end up setting signing flags - as no signing
-               was in LANMAN and server did not return the flags on */
-               goto signing_check;
-#else /* weak security disabled */
        } else if (pSMBr->hdr.WordCount == 13) {
-               cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
-               rc = -EOPNOTSUPP;
-#endif /* WEAK_PW_HASH */
-               goto neg_err_exit;
+               server->negflavor = CIFS_NEGFLAVOR_LANMAN;
+               rc = decode_lanman_negprot_rsp(server, pSMBr);
+               goto signing_check;
        } else if (pSMBr->hdr.WordCount != 17) {
                /* unknown wct */
                rc = -EOPNOTSUPP;
                goto neg_err_exit;
        }
-       /* else wct == 17 NTLM */
+       /* else wct == 17, NTLM or better */
+
        server->sec_mode = pSMBr->SecurityMode;
        if ((server->sec_mode & SECMODE_USER) == 0)
                cifs_dbg(FYI, "share mode security\n");
 
-       if ((server->sec_mode & SECMODE_PW_ENCRYPT) == 0)
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-               if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
-#endif /* CIFS_WEAK_PW_HASH */
-                       cifs_dbg(VFS, "Server requests plain text password but client support disabled\n");
-
-       if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2)
-               server->secType = NTLMv2;
-       else if (secFlags & CIFSSEC_MAY_NTLM)
-               server->secType = NTLM;
-       else if (secFlags & CIFSSEC_MAY_NTLMV2)
-               server->secType = NTLMv2;
-       else if (secFlags & CIFSSEC_MAY_KRB5)
-               server->secType = Kerberos;
-       else if (secFlags & CIFSSEC_MAY_NTLMSSP)
-               server->secType = RawNTLMSSP;
-       else if (secFlags & CIFSSEC_MAY_LANMAN)
-               server->secType = LANMAN;
-       else {
-               rc = -EOPNOTSUPP;
-               cifs_dbg(VFS, "Invalid security type\n");
-               goto neg_err_exit;
-       }
-       /* else ... any others ...? */
-
        /* one byte, so no need to convert this or EncryptionKeyLen from
           little endian */
        server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount),
@@ -569,90 +625,26 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
        server->capabilities = le32_to_cpu(pSMBr->Capabilities);
        server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
        server->timeAdj *= 60;
+
        if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+               server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
                memcpy(ses->server->cryptkey, pSMBr->u.EncryptionKey,
                       CIFS_CRYPTO_KEY_SIZE);
        } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC ||
                        server->capabilities & CAP_EXTENDED_SECURITY) &&
                                (pSMBr->EncryptionKeyLength == 0)) {
-               /* decode security blob */
-               count = get_bcc(&pSMBr->hdr);
-               if (count < 16) {
-                       rc = -EIO;
-                       goto neg_err_exit;
-               }
-               spin_lock(&cifs_tcp_ses_lock);
-               if (server->srv_count > 1) {
-                       spin_unlock(&cifs_tcp_ses_lock);
-                       if (memcmp(server->server_GUID,
-                                  pSMBr->u.extended_response.
-                                  GUID, 16) != 0) {
-                               cifs_dbg(FYI, "server UID changed\n");
-                               memcpy(server->server_GUID,
-                                       pSMBr->u.extended_response.GUID,
-                                       16);
-                       }
-               } else {
-                       spin_unlock(&cifs_tcp_ses_lock);
-                       memcpy(server->server_GUID,
-                              pSMBr->u.extended_response.GUID, 16);
-               }
-
-               if (count == 16) {
-                       server->secType = RawNTLMSSP;
-               } else {
-                       rc = decode_negTokenInit(pSMBr->u.extended_response.
-                                                SecurityBlob, count - 16,
-                                                server);
-                       if (rc == 1)
-                               rc = 0;
-                       else
-                               rc = -EINVAL;
-                       if (server->secType == Kerberos) {
-                               if (!server->sec_kerberos &&
-                                               !server->sec_mskerberos)
-                                       rc = -EOPNOTSUPP;
-                       } else if (server->secType == RawNTLMSSP) {
-                               if (!server->sec_ntlmssp)
-                                       rc = -EOPNOTSUPP;
-                       } else
-                                       rc = -EOPNOTSUPP;
-               }
+               server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
+               rc = decode_ext_sec_blob(ses, pSMBr);
        } else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
                rc = -EIO; /* no crypt key only if plain text pwd */
-               goto neg_err_exit;
-       } else
-               server->capabilities &= ~CAP_EXTENDED_SECURITY;
-
-#ifdef CONFIG_CIFS_WEAK_PW_HASH
-signing_check:
-#endif
-       if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
-               /* MUST_SIGN already includes the MAY_SIGN FLAG
-                  so if this is zero it means that signing is disabled */
-               cifs_dbg(FYI, "Signing disabled\n");
-               if (server->sec_mode & SECMODE_SIGN_REQUIRED) {
-                       cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
-                       rc = -EOPNOTSUPP;
-               }
-               server->sec_mode &=
-                       ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-       } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
-               /* signing required */
-               cifs_dbg(FYI, "Must sign - secFlags 0x%x\n", secFlags);
-               if ((server->sec_mode &
-                       (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) {
-                       cifs_dbg(VFS, "signing required but server lacks support\n");
-                       rc = -EOPNOTSUPP;
-               } else
-                       server->sec_mode |= SECMODE_SIGN_REQUIRED;
        } else {
-               /* signing optional ie CIFSSEC_MAY_SIGN */
-               if ((server->sec_mode & SECMODE_SIGN_REQUIRED) == 0)
-                       server->sec_mode &=
-                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+               server->negflavor = CIFS_NEGFLAVOR_UNENCAP;
+               server->capabilities &= ~CAP_EXTENDED_SECURITY;
        }
 
+signing_check:
+       if (!rc)
+               rc = cifs_enable_signing(server, ses->sign);
 neg_err_exit:
        cifs_buf_release(pSMB);
 
@@ -777,9 +769,8 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses)
 
        pSMB->hdr.Mid = get_next_mid(ses->server);
 
-       if (ses->server->sec_mode &
-                  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+       if (ses->server->sign)
+               pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        pSMB->hdr.Uid = ses->Suid;
 
@@ -1540,8 +1531,7 @@ cifs_readv_callback(struct mid_q_entry *mid)
        switch (mid->mid_state) {
        case MID_RESPONSE_RECEIVED:
                /* result already set, check signature */
-               if (server->sec_mode &
-                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+               if (server->sign) {
                        int rc = 0;
 
                        rc = cifs_verify_signature(&rqst, server,
@@ -3940,6 +3930,7 @@ QFileInfoRetry:
        pSMB->Pad = 0;
        pSMB->Fid = netfid;
        inc_rfc1001_len(pSMB, byte_count);
+       pSMB->t2.ByteCount = cpu_to_le16(byte_count);
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -4108,6 +4099,7 @@ UnixQFileInfoRetry:
        pSMB->Pad = 0;
        pSMB->Fid = netfid;
        inc_rfc1001_len(pSMB, byte_count);
+       pSMB->t2.ByteCount = cpu_to_le16(byte_count);
 
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -4794,11 +4786,8 @@ getDFSRetry:
                strncpy(pSMB->RequestFileName, search_name, name_len);
        }
 
-       if (ses->server) {
-               if (ses->server->sec_mode &
-                  (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-       }
+       if (ses->server && ses->server->sign)
+               pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        pSMB->hdr.Uid = ses->Suid;
 
index e3bc39bb9d12b224d7cda96e2e55b9babed68c0b..afcb8a1a33b7dcb273eba95331248a781b42e27a 100644 (file)
@@ -85,7 +85,7 @@ enum {
        Opt_acl, Opt_noacl, Opt_locallease,
        Opt_sign, Opt_seal, Opt_noac,
        Opt_fsc, Opt_mfsymlinks,
-       Opt_multiuser, Opt_sloppy,
+       Opt_multiuser, Opt_sloppy, Opt_nosharesock,
 
        /* Mount options which take numeric value */
        Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -165,6 +165,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_mfsymlinks, "mfsymlinks" },
        { Opt_multiuser, "multiuser" },
        { Opt_sloppy, "sloppy" },
+       { Opt_nosharesock, "nosharesock" },
 
        { Opt_backupuid, "backupuid=%s" },
        { Opt_backupgid, "backupgid=%s" },
@@ -275,6 +276,7 @@ static const match_table_t cifs_smb_version_tokens = {
        { Smb_20, SMB20_VERSION_STRING},
        { Smb_21, SMB21_VERSION_STRING },
        { Smb_30, SMB30_VERSION_STRING },
+       { Smb_302, SMB302_VERSION_STRING },
 };
 
 static int ip_connect(struct TCP_Server_Info *server);
@@ -1024,44 +1026,48 @@ static int cifs_parse_security_flavors(char *value,
 
        substring_t args[MAX_OPT_ARGS];
 
+       /*
+        * With mount options, the last one should win. Reset any existing
+        * settings back to default.
+        */
+       vol->sectype = Unspecified;
+       vol->sign = false;
+
        switch (match_token(value, cifs_secflavor_tokens, args)) {
-       case Opt_sec_krb5:
-               vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_SIGN;
-               break;
-       case Opt_sec_krb5i:
-               vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MUST_SIGN;
-               break;
        case Opt_sec_krb5p:
-               /* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */
-               cifs_dbg(VFS, "Krb5 cifs privacy not supported\n");
-               break;
-       case Opt_sec_ntlmssp:
-               vol->secFlg |= CIFSSEC_MAY_NTLMSSP;
+               cifs_dbg(VFS, "sec=krb5p is not supported!\n");
+               return 1;
+       case Opt_sec_krb5i:
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_sec_krb5:
+               vol->sectype = Kerberos;
                break;
        case Opt_sec_ntlmsspi:
-               vol->secFlg |= CIFSSEC_MAY_NTLMSSP | CIFSSEC_MUST_SIGN;
-               break;
-       case Opt_ntlm:
-               /* ntlm is default so can be turned off too */
-               vol->secFlg |= CIFSSEC_MAY_NTLM;
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_sec_ntlmssp:
+               vol->sectype = RawNTLMSSP;
                break;
        case Opt_sec_ntlmi:
-               vol->secFlg |= CIFSSEC_MAY_NTLM | CIFSSEC_MUST_SIGN;
-               break;
-       case Opt_sec_ntlmv2:
-               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_ntlm:
+               vol->sectype = NTLM;
                break;
        case Opt_sec_ntlmv2i:
-               vol->secFlg |= CIFSSEC_MAY_NTLMV2 | CIFSSEC_MUST_SIGN;
+               vol->sign = true;
+               /* Fallthrough */
+       case Opt_sec_ntlmv2:
+               vol->sectype = NTLMv2;
                break;
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
        case Opt_sec_lanman:
-               vol->secFlg |= CIFSSEC_MAY_LANMAN;
+               vol->sectype = LANMAN;
                break;
 #endif
        case Opt_sec_none:
                vol->nullauth = 1;
-               vol->secFlg |= CIFSSEC_MAY_NTLM;
                break;
        default:
                cifs_dbg(VFS, "bad security option: %s\n", value);
@@ -1119,6 +1125,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
                vol->ops = &smb30_operations;
                vol->vals = &smb30_values;
                break;
+       case Smb_302:
+               vol->ops = &smb30_operations; /* currently identical with 3.0 */
+               vol->vals = &smb302_values;
+               break;
 #endif
        default:
                cifs_dbg(VFS, "Unknown vers= option specified: %s\n", value);
@@ -1424,7 +1434,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        vol->local_lease = 1;
                        break;
                case Opt_sign:
-                       vol->secFlg |= CIFSSEC_MUST_SIGN;
+                       vol->sign = true;
                        break;
                case Opt_seal:
                        /* we do not do the following in secFlags because seal
@@ -1455,6 +1465,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                case Opt_sloppy:
                        sloppy = true;
                        break;
+               case Opt_nosharesock:
+                       vol->nosharesock = true;
+                       break;
 
                /* Numeric Values */
                case Opt_backupuid:
@@ -1978,47 +1991,21 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
 static bool
 match_security(struct TCP_Server_Info *server, struct smb_vol *vol)
 {
-       unsigned int secFlags;
-
-       if (vol->secFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               secFlags = vol->secFlg;
-       else
-               secFlags = global_secflags | vol->secFlg;
-
-       switch (server->secType) {
-       case LANMAN:
-               if (!(secFlags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)))
-                       return false;
-               break;
-       case NTLMv2:
-               if (!(secFlags & CIFSSEC_MAY_NTLMV2))
-                       return false;
-               break;
-       case NTLM:
-               if (!(secFlags & CIFSSEC_MAY_NTLM))
-                       return false;
-               break;
-       case Kerberos:
-               if (!(secFlags & CIFSSEC_MAY_KRB5))
-                       return false;
-               break;
-       case RawNTLMSSP:
-               if (!(secFlags & CIFSSEC_MAY_NTLMSSP))
-                       return false;
-               break;
-       default:
-               /* shouldn't happen */
+       /*
+        * The select_sectype function should either return the vol->sectype
+        * that was specified, or "Unspecified" if that sectype was not
+        * compatible with the given NEGOTIATE request.
+        */
+       if (select_sectype(server, vol->sectype) == Unspecified)
                return false;
-       }
 
-       /* now check if signing mode is acceptable */
-       if ((secFlags & CIFSSEC_MAY_SIGN) == 0 &&
-           (server->sec_mode & SECMODE_SIGN_REQUIRED))
-                       return false;
-       else if (((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) &&
-                (server->sec_mode &
-                 (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED)) == 0)
-                       return false;
+       /*
+        * Now check if signing mode is acceptable. No need to check
+        * global_secflags at this point since if MUST_SIGN is set then
+        * the server->sign had better be too.
+        */
+       if (vol->sign && !server->sign)
+               return false;
 
        return true;
 }
@@ -2027,6 +2014,9 @@ static int match_server(struct TCP_Server_Info *server, struct smb_vol *vol)
 {
        struct sockaddr *addr = (struct sockaddr *)&vol->dstaddr;
 
+       if (vol->nosharesock)
+               return 0;
+
        if ((server->vals != vol->vals) || (server->ops != vol->ops))
                return 0;
 
@@ -2216,7 +2206,11 @@ out_err:
 
 static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
 {
-       switch (ses->server->secType) {
+       if (vol->sectype != Unspecified &&
+           vol->sectype != ses->sectype)
+               return 0;
+
+       switch (ses->sectype) {
        case Kerberos:
                if (!uid_eq(vol->cred_uid, ses->cred_uid))
                        return 0;
@@ -2493,7 +2487,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
        ses->cred_uid = volume_info->cred_uid;
        ses->linux_uid = volume_info->linux_uid;
 
-       ses->overrideSecFlg = volume_info->secFlg;
+       ses->sectype = volume_info->sectype;
+       ses->sign = volume_info->sign;
 
        mutex_lock(&ses->session_mutex);
        rc = cifs_negotiate_protocol(xid, ses);
@@ -3656,7 +3651,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                   NTLMv2 password here) */
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
-                   (ses->server->secType == LANMAN))
+                   (ses->sectype == LANMAN))
                        calc_lanman_hash(tcon->password, ses->server->cryptkey,
                                         ses->server->sec_mode &
                                            SECMODE_PW_ENCRYPT ? true : false,
@@ -3674,8 +3669,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                }
        }
 
-       if (ses->server->sec_mode &
-                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->sign)
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_STATUS32) {
@@ -3738,7 +3732,7 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
                }
                bcc_ptr += length + 1;
                bytes_left -= (length + 1);
-               strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
+               strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
                /* mostly informational -- no need to fail on error here */
                kfree(tcon->nativeFileSystem);
@@ -3827,7 +3821,6 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
        int rc = -ENOSYS;
        struct TCP_Server_Info *server = ses->server;
 
-       ses->flags = 0;
        ses->capabilities = server->capabilities;
        if (linuxExtEnabled == 0)
                ses->capabilities &= (~server->vals->cap_unix);
@@ -3848,6 +3841,8 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
                        server->sequence_number = 0x2;
                        server->session_estab = true;
                        ses->auth_key.response = NULL;
+                       if (server->ops->generate_signingkey)
+                               server->ops->generate_signingkey(server);
                }
                mutex_unlock(&server->srv_mutex);
 
@@ -3870,23 +3865,11 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
 static int
 cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses)
 {
-       switch (ses->server->secType) {
-       case Kerberos:
-               vol->secFlg = CIFSSEC_MUST_KRB5;
+       vol->sectype = ses->sectype;
+
+       /* krb5 is special, since we don't need username or pw */
+       if (vol->sectype == Kerberos)
                return 0;
-       case NTLMv2:
-               vol->secFlg = CIFSSEC_MUST_NTLMV2;
-               break;
-       case NTLM:
-               vol->secFlg = CIFSSEC_MUST_NTLM;
-               break;
-       case RawNTLMSSP:
-               vol->secFlg = CIFSSEC_MUST_NTLMSSP;
-               break;
-       case LANMAN:
-               vol->secFlg = CIFSSEC_MUST_LANMAN;
-               break;
-       }
 
        return cifs_set_cifscreds(vol, ses);
 }
@@ -3912,6 +3895,8 @@ cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid)
        vol_info->nocase = master_tcon->nocase;
        vol_info->local_lease = master_tcon->local_lease;
        vol_info->no_linux_ext = !master_tcon->unix_ext;
+       vol_info->sectype = master_tcon->ses->sectype;
+       vol_info->sign = master_tcon->ses->sign;
 
        rc = cifs_set_vol_auth(vol_info, master_tcon->ses);
        if (rc) {
index 1bec014779fd8e92a679643fd1a554de68fbd96a..f7d4b2285efea06fee58d52b94e72a332412cb1a 100644 (file)
@@ -267,8 +267,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
                if (treeCon->nocase)
                        buffer->Flags  |= SMBFLG_CASELESS;
                if ((treeCon->ses) && (treeCon->ses->server))
-                       if (treeCon->ses->server->sec_mode &
-                         (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+                       if (treeCon->ses->server->sign)
                                buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
        }
 
index f1213799de1a2603b1f8f1c8d42f8b0fb2cb5a64..ab877846939499c18cb454c83ed26c43dc60040c 100644 (file)
@@ -126,6 +126,22 @@ out:
        dput(dentry);
 }
 
+/*
+ * Is it possible that this directory might turn out to be a DFS referral
+ * once we go to try and use it?
+ */
+static bool
+cifs_dfs_is_possible(struct cifs_sb_info *cifs_sb)
+{
+#ifdef CONFIG_CIFS_DFS_UPCALL
+       struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
+
+       if (tcon->Flags & SMB_SHARE_IS_IN_DFS)
+               return true;
+#endif
+       return false;
+}
+
 static void
 cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
 {
@@ -135,6 +151,19 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
        if (fattr->cf_cifsattrs & ATTR_DIRECTORY) {
                fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode;
                fattr->cf_dtype = DT_DIR;
+               /*
+                * Windows CIFS servers generally make DFS referrals look
+                * like directories in FIND_* responses with the reparse
+                * attribute flag also set (since DFS junctions are
+                * reparse points). We must revalidate at least these
+                * directory inodes before trying to use them (if
+                * they are DFS we will get PATH_NOT_COVERED back
+                * when queried directly and can then try to connect
+                * to the DFS target)
+                */
+               if (cifs_dfs_is_possible(cifs_sb) &&
+                   (fattr->cf_cifsattrs & ATTR_REPARSE))
+                       fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
        } else {
                fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
                fattr->cf_dtype = DT_REG;
index f230571a7ab30d1c7d809eafbfdf9cb5724c2dd3..79358e341fd2ea63cff42e6d608c58f65b5f9804 100644 (file)
@@ -138,8 +138,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
        capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
                        CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
 
-       if (ses->server->sec_mode &
-           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (ses->server->sign)
                pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_UNICODE) {
@@ -310,11 +309,10 @@ decode_unicode_ssetup(char **pbcc_area, int bleft, struct cifs_ses *ses,
        return;
 }
 
-static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
-                              struct cifs_ses *ses,
-                              const struct nls_table *nls_cp)
+static void decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
+                               struct cifs_ses *ses,
+                               const struct nls_table *nls_cp)
 {
-       int rc = 0;
        int len;
        char *bcc_ptr = *pbcc_area;
 
@@ -322,24 +320,22 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 
        len = strnlen(bcc_ptr, bleft);
        if (len >= bleft)
-               return rc;
+               return;
 
        kfree(ses->serverOS);
 
        ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
        if (ses->serverOS)
                strncpy(ses->serverOS, bcc_ptr, len);
-       if (strncmp(ses->serverOS, "OS/2", 4) == 0) {
+       if (strncmp(ses->serverOS, "OS/2", 4) == 0)
                cifs_dbg(FYI, "OS/2 server\n");
-                       ses->flags |= CIFS_SES_OS2;
-       }
 
        bcc_ptr += len + 1;
        bleft -= len + 1;
 
        len = strnlen(bcc_ptr, bleft);
        if (len >= bleft)
-               return rc;
+               return;
 
        kfree(ses->serverNOS);
 
@@ -352,7 +348,7 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
 
        len = strnlen(bcc_ptr, bleft);
        if (len > bleft)
-               return rc;
+               return;
 
        /* No domain field in LANMAN case. Domain is
           returned by old servers in the SMB negprot response */
@@ -360,8 +356,6 @@ static int decode_ascii_ssetup(char **pbcc_area, __u16 bleft,
           but thus do return domain here we could add parsing
           for it later, but it is not very important */
        cifs_dbg(FYI, "ascii: bytes left %d\n", bleft);
-
-       return rc;
 }
 
 int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
@@ -432,8 +426,7 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
        flags = NTLMSSP_NEGOTIATE_56 |  NTLMSSP_REQUEST_TARGET |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->sec_mode &
-                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+       if (ses->server->sign) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
                if (!ses->server->session_estab)
                        flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
@@ -471,8 +464,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
                NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO |
                NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE |
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
-       if (ses->server->sec_mode &
-          (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+       if (ses->server->sign) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
                if (!ses->server->session_estab)
                        flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
@@ -558,6 +550,56 @@ setup_ntlmv2_ret:
        return rc;
 }
 
+enum securityEnum
+select_sectype(struct TCP_Server_Info *server, enum securityEnum requested)
+{
+       switch (server->negflavor) {
+       case CIFS_NEGFLAVOR_EXTENDED:
+               switch (requested) {
+               case Kerberos:
+               case RawNTLMSSP:
+                       return requested;
+               case Unspecified:
+                       if (server->sec_ntlmssp &&
+                           (global_secflags & CIFSSEC_MAY_NTLMSSP))
+                               return RawNTLMSSP;
+                       if ((server->sec_kerberos || server->sec_mskerberos) &&
+                           (global_secflags & CIFSSEC_MAY_KRB5))
+                               return Kerberos;
+                       /* Fallthrough */
+               default:
+                       return Unspecified;
+               }
+       case CIFS_NEGFLAVOR_UNENCAP:
+               switch (requested) {
+               case NTLM:
+               case NTLMv2:
+                       return requested;
+               case Unspecified:
+                       if (global_secflags & CIFSSEC_MAY_NTLMV2)
+                               return NTLMv2;
+                       if (global_secflags & CIFSSEC_MAY_NTLM)
+                               return NTLM;
+                       /* Fallthrough */
+               default:
+                       return Unspecified;
+               }
+       case CIFS_NEGFLAVOR_LANMAN:
+               switch (requested) {
+               case LANMAN:
+                       return requested;
+               case Unspecified:
+                       if (global_secflags & CIFSSEC_MAY_LANMAN)
+                               return LANMAN;
+                       /* Fallthrough */
+               default:
+                       return Unspecified;
+               }
+       default:
+               return Unspecified;
+       }
+}
+
 int
 CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
               const struct nls_table *nls_cp)
@@ -579,11 +621,18 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
        u16 blob_len;
        char *ntlmsspblob = NULL;
 
-       if (ses == NULL)
+       if (ses == NULL) {
+               WARN(1, "%s: ses == NULL!", __func__);
                return -EINVAL;
+       }
 
-       type = ses->server->secType;
+       type = select_sectype(ses->server, ses->sectype);
        cifs_dbg(FYI, "sess setup type %d\n", type);
+       if (type == Unspecified) {
+               cifs_dbg(VFS, "Unable to select appropriate authentication method!");
+               return -EINVAL;
+       }
+
        if (type == RawNTLMSSP) {
                /* if memory allocation is successful, caller of this function
                 * frees it.
@@ -643,8 +692,6 @@ ssetup_ntlmssp_authenticate:
        }
        bcc_ptr = str_area;
 
-       ses->flags &= ~CIFS_SES_LANMAN;
-
        iov[1].iov_base = NULL;
        iov[1].iov_len = 0;
 
@@ -668,7 +715,6 @@ ssetup_ntlmssp_authenticate:
                                 ses->server->sec_mode & SECMODE_PW_ENCRYPT ?
                                        true : false, lnm_session_key);
 
-               ses->flags |= CIFS_SES_LANMAN;
                memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE);
                bcc_ptr += CIFS_AUTH_RESP_SIZE;
 
@@ -938,8 +984,7 @@ ssetup_ntlmssp_authenticate:
                }
                decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
        } else {
-               rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining,
-                                        ses, nls_cp);
+               decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
        }
 
 ssetup_exit:
index 3efdb9d5c0b8a704789070f1e0aedfaffcb9ec39..e813f04511d8875dfa81b5a472cea2a932a417cd 100644 (file)
@@ -449,8 +449,7 @@ cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
         * WRITEX header, not including the 4 byte RFC1001 length.
         */
        if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
-           (!(server->capabilities & CAP_UNIX) &&
-            (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
+           (!(server->capabilities & CAP_UNIX) && server->sign))
                wsize = min_t(unsigned int, wsize,
                                server->maxBuf - sizeof(WRITE_REQ) + 4);
 
@@ -765,20 +764,14 @@ smb_set_file_info(struct inode *inode, const char *full_path,
        }
        tcon = tlink_tcon(tlink);
 
-       /*
-        * NT4 apparently returns success on this call, but it doesn't really
-        * work.
-        */
-       if (!(tcon->ses->flags & CIFS_SES_NT4)) {
-               rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf,
-                                       cifs_sb->local_nls,
+       rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf, cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc == 0) {
-                       cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
-                       goto out;
-               } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
-                       goto out;
+       if (rc == 0) {
+               cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+               goto out;
+       } else if (rc != -EOPNOTSUPP && rc != -EINVAL) {
+               goto out;
        }
 
        cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
@@ -964,4 +957,6 @@ struct smb_version_values smb1_values = {
        .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
        .cap_large_files = CAP_LARGE_FILES,
        .oplock_read = OPLOCK_READ,
+       .signing_enabled = SECMODE_SIGN_ENABLED,
+       .signing_required = SECMODE_SIGN_REQUIRED,
 };
index 7c0e2143e775e04f183ccad271de61e73bc2edf3..c38350851b0883cd6074b04f5aa36398b2528e3c 100644 (file)
@@ -54,5 +54,7 @@
 #define SMB2_SIGNATURE_SIZE (16)
 #define SMB2_NTLMV2_SESSKEY_SIZE (16)
 #define SMB2_HMACSHA256_SIZE (32)
+#define SMB2_CMACAES_SIZE (16)
+#define SMB3_SIGNKEY_SIZE (16)
 
 #endif /* _SMB2_GLOB_H */
index 10383d8c015b12c4aa7bd936972e58bca97a648b..b0c43345cd981c082e3de5965e647a5432197605 100644 (file)
@@ -266,6 +266,10 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
                  ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
                break;
        case SMB2_IOCTL:
+               *off = le32_to_cpu(
+                 ((struct smb2_ioctl_rsp *)hdr)->OutputOffset);
+               *len = le32_to_cpu(((struct smb2_ioctl_rsp *)hdr)->OutputCount);
+               break;
        case SMB2_CHANGE_NOTIFY:
        default:
                /* BB FIXME for unimplemented cases above */
index f2e76f3b0c6166aeb345d5a02a0f4bdde5b84731..6d15cab95b9908baf0509bceef86fbeb79c93ebd 100644 (file)
@@ -280,6 +280,25 @@ smb2_clear_stats(struct cifs_tcon *tcon)
 #endif
 }
 
+static void
+smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon)
+{
+       seq_puts(m, "\n\tShare Capabilities:");
+       if (tcon->capabilities & SMB2_SHARE_CAP_DFS)
+               seq_puts(m, " DFS,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
+               seq_puts(m, " CONTINUOUS AVAILABILITY,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT)
+               seq_puts(m, " SCALEOUT,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER)
+               seq_puts(m, " CLUSTER,");
+       if (tcon->capabilities & SMB2_SHARE_CAP_ASYMMETRIC)
+               seq_puts(m, " ASYMMETRIC,");
+       if (tcon->capabilities == 0)
+               seq_puts(m, " None");
+       seq_printf(m, "\tShare Flags: 0x%x", tcon->share_flags);
+}
+
 static void
 smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 {
@@ -292,7 +311,6 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
        seq_printf(m, "\nSessionSetups: %d sent %d failed",
                   atomic_read(&sent[SMB2_SESSION_SETUP_HE]),
                   atomic_read(&failed[SMB2_SESSION_SETUP_HE]));
-#define SMB2LOGOFF             0x0002 /* trivial request/resp */
        seq_printf(m, "\nLogoffs: %d sent %d failed",
                   atomic_read(&sent[SMB2_LOGOFF_HE]),
                   atomic_read(&failed[SMB2_LOGOFF_HE]));
@@ -645,6 +663,7 @@ struct smb_version_operations smb30_operations = {
        .dump_detail = smb2_dump_detail,
        .clear_stats = smb2_clear_stats,
        .print_stats = smb2_print_stats,
+       .dump_share_caps = smb2_dump_share_caps,
        .is_oplock_break = smb2_is_valid_oplock_break,
        .need_neg = smb2_need_neg,
        .negotiate = smb2_negotiate,
@@ -690,6 +709,7 @@ struct smb_version_operations smb30_operations = {
        .get_lease_key = smb2_get_lease_key,
        .set_lease_key = smb2_set_lease_key,
        .new_lease_key = smb2_new_lease_key,
+       .generate_signingkey = generate_smb3signingkey,
        .calc_signature = smb3_calc_signature,
 };
 
@@ -709,6 +729,8 @@ struct smb_version_values smb20_values = {
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
        .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
 
 struct smb_version_values smb21_values = {
@@ -727,6 +749,8 @@ struct smb_version_values smb21_values = {
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
        .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
 
 struct smb_version_values smb30_values = {
@@ -745,4 +769,26 @@ struct smb_version_values smb30_values = {
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
        .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
+};
+
+struct smb_version_values smb302_values = {
+       .version_string = SMB302_VERSION_STRING,
+       .protocol_id = SMB302_PROT_ID,
+       .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU,
+       .large_lock_type = 0,
+       .exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
+       .shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
+       .unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
+       .header_size = sizeof(struct smb2_hdr),
+       .max_header_size = MAX_SMB2_HDR_SIZE,
+       .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
+       .lock_cmd = SMB2_LOCK,
+       .cap_unix = 0,
+       .cap_nt_find = SMB2_NT_FIND,
+       .cap_large_files = SMB2_LARGE_FILES,
+       .oplock_read = SMB2_OPLOCK_LEVEL_II,
+       .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
 };
index 2b95ce2b54e80c5a2f60c84b7029e43270b524f6..2b312e4eeaa6c281192c622bc3d54e0327077626 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/smb2pdu.c
  *
- *   Copyright (C) International Business Machines  Corp., 2009, 2012
+ *   Copyright (C) International Business Machines  Corp., 2009, 2013
  *                 Etersoft, 2012
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Pavel Shilovsky (pshilovsky@samba.org) 2012
@@ -108,19 +108,33 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
        if (!tcon)
                goto out;
 
+       /* BB FIXME when we do write > 64K add +1 for every 64K in req or rsp */
+       /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
+       /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
+       if ((tcon->ses) &&
+           (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+               hdr->CreditCharge = cpu_to_le16(1);
+       /* else CreditCharge MBZ */
+
        hdr->TreeId = tcon->tid;
        /* Uid is not converted */
        if (tcon->ses)
                hdr->SessionId = tcon->ses->Suid;
-       /* BB check following DFS flags BB */
-       /* BB do we have to add check for SHI1005_FLAGS_DFS_ROOT too? */
-       if (tcon->share_flags & SHI1005_FLAGS_DFS)
-               hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS;
-       /* BB how does SMB2 do case sensitive? */
-       /* if (tcon->nocase)
-               hdr->Flags |= SMBFLG_CASELESS; */
-       if (tcon->ses && tcon->ses->server &&
-           (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED))
+
+       /*
+        * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also would have
+        * to pass the path on the Open SMB prefixed by \\server\share.
+        * Not sure when we would need to do the augmented path (if ever) and
+        * setting this flag breaks the SMB2 open operation since it is
+        * illegal to send an empty path name (without \\server\share prefix)
+        * when the DFS flag is set in the SMB open header. We could
+        * consider setting the flag on all operations other than open
+        * but it is safer to net set it for now.
+        */
+/*     if (tcon->share_flags & SHI1005_FLAGS_DFS)
+               hdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
+
+       if (tcon->ses && tcon->ses->server && tcon->ses->server->sign)
                hdr->Flags |= SMB2_FLAGS_SIGNED;
 out:
        pdu->StructureSize2 = cpu_to_le16(parmsize);
@@ -328,34 +342,22 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        struct kvec iov[1];
        int rc = 0;
        int resp_buftype;
-       struct TCP_Server_Info *server;
-       unsigned int sec_flags;
-       u16 temp = 0;
+       struct TCP_Server_Info *server = ses->server;
        int blob_offset, blob_length;
        char *security_blob;
        int flags = CIFS_NEG_OP;
 
        cifs_dbg(FYI, "Negotiate protocol\n");
 
-       if (ses->server)
-               server = ses->server;
-       else {
-               rc = -EIO;
-               return rc;
+       if (!server) {
+               WARN(1, "%s: server is NULL!\n", __func__);
+               return -EIO;
        }
 
        rc = small_smb2_init(SMB2_NEGOTIATE, NULL, (void **) &req);
        if (rc)
                return rc;
 
-       /* if any of auth flags (ie not sign or seal) are overriden use them */
-       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               sec_flags = ses->overrideSecFlg;  /* BB FIXME fix sign flags?*/
-       else /* if override flags set only sign/seal OR them with global auth */
-               sec_flags = global_secflags | ses->overrideSecFlg;
-
-       cifs_dbg(FYI, "sec_flags 0x%x\n", sec_flags);
-
        req->hdr.SessionId = 0;
 
        req->Dialects[0] = cpu_to_le16(ses->server->vals->protocol_id);
@@ -364,12 +366,12 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        inc_rfc1001_len(req, 2);
 
        /* only one of SMB2 signing flags may be set in SMB2 request */
-       if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
-               temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
-       else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */
-               temp = SMB2_NEGOTIATE_SIGNING_ENABLED;
-
-       req->SecurityMode = cpu_to_le16(temp);
+       if (ses->sign)
+               req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED);
+       else if (global_secflags & CIFSSEC_MAY_SIGN)
+               req->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED);
+       else
+               req->SecurityMode = 0;
 
        req->Capabilities = cpu_to_le32(ses->server->vals->req_capabilities);
 
@@ -399,6 +401,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
                cifs_dbg(FYI, "negotiated smb2.1 dialect\n");
        else if (rsp->DialectRevision == cpu_to_le16(SMB30_PROT_ID))
                cifs_dbg(FYI, "negotiated smb3.0 dialect\n");
+       else if (rsp->DialectRevision == cpu_to_le16(SMB302_PROT_ID))
+               cifs_dbg(FYI, "negotiated smb3.02 dialect\n");
        else {
                cifs_dbg(VFS, "Illegal dialect returned by server %d\n",
                         le16_to_cpu(rsp->DialectRevision));
@@ -407,6 +411,8 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        }
        server->dialect = le16_to_cpu(rsp->DialectRevision);
 
+       /* SMB2 only has an extended negflavor */
+       server->negflavor = CIFS_NEGFLAVOR_EXTENDED;
        server->maxBuf = le32_to_cpu(rsp->MaxTransactSize);
        server->max_read = le32_to_cpu(rsp->MaxReadSize);
        server->max_write = le32_to_cpu(rsp->MaxWriteSize);
@@ -418,44 +424,22 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
 
        security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
                                               &rsp->hdr);
-       if (blob_length == 0) {
-               cifs_dbg(VFS, "missing security blob on negprot\n");
-               rc = -EIO;
-               goto neg_exit;
-       }
-
-       cifs_dbg(FYI, "sec_flags 0x%x\n", sec_flags);
-       if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) {
-               cifs_dbg(FYI, "Signing required\n");
-               if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED |
-                     SMB2_NEGOTIATE_SIGNING_ENABLED))) {
-                       cifs_dbg(VFS, "signing required but server lacks support\n");
-                       rc = -EOPNOTSUPP;
-                       goto neg_exit;
-               }
-               server->sec_mode |= SECMODE_SIGN_REQUIRED;
-       } else if (sec_flags & CIFSSEC_MAY_SIGN) {
-               cifs_dbg(FYI, "Signing optional\n");
-               if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
-                       cifs_dbg(FYI, "Server requires signing\n");
-                       server->sec_mode |= SECMODE_SIGN_REQUIRED;
-               } else {
-                       server->sec_mode &=
-                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-               }
-       } else {
-               cifs_dbg(FYI, "Signing disabled\n");
-               if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
-                       cifs_dbg(VFS, "Server requires packet signing to be enabled in /proc/fs/cifs/SecurityFlags\n");
-                       rc = -EOPNOTSUPP;
-                       goto neg_exit;
-               }
-               server->sec_mode &=
-                       ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
-       }
+       /*
+        * See MS-SMB2 section 2.2.4: if no blob, client picks default which
+        * for us will be
+        *      ses->sectype = RawNTLMSSP;
+        * but for time being this is our only auth choice so doesn't matter.
+        * We just found a server which sets blob length to zero expecting raw.
+        */
+       if (blob_length == 0)
+               cifs_dbg(FYI, "missing security blob on negprot\n");
 
+       rc = cifs_enable_signing(server, ses->sign);
 #ifdef CONFIG_SMB2_ASN1  /* BB REMOVEME when updated asn1.c ready */
-       rc = decode_neg_token_init(security_blob, blob_length,
+       if (rc)
+               goto neg_exit;
+       if (blob_length)
+               rc = decode_neg_token_init(security_blob, blob_length,
                                   &server->sec_type);
        if (rc == 1)
                rc = 0;
@@ -480,9 +464,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        int rc = 0;
        int resp_buftype;
        __le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
-       struct TCP_Server_Info *server;
-       unsigned int sec_flags;
-       u8 temp = 0;
+       struct TCP_Server_Info *server = ses->server;
        u16 blob_length = 0;
        char *security_blob;
        char *ntlmssp_blob = NULL;
@@ -490,11 +472,9 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
 
        cifs_dbg(FYI, "Session Setup\n");
 
-       if (ses->server)
-               server = ses->server;
-       else {
-               rc = -EIO;
-               return rc;
+       if (!server) {
+               WARN(1, "%s: server is NULL!\n", __func__);
+               return -EIO;
        }
 
        /*
@@ -505,7 +485,8 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        if (!ses->ntlmssp)
                return -ENOMEM;
 
-       ses->server->secType = RawNTLMSSP;
+       /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
+       ses->sectype = RawNTLMSSP;
 
 ssetup_ntlmssp_authenticate:
        if (phase == NtLmChallenge)
@@ -515,28 +496,19 @@ ssetup_ntlmssp_authenticate:
        if (rc)
                return rc;
 
-       /* if any of auth flags (ie not sign or seal) are overriden use them */
-       if (ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL)))
-               sec_flags = ses->overrideSecFlg;  /* BB FIXME fix sign flags?*/
-       else /* if override flags set only sign/seal OR them with global auth */
-               sec_flags = global_secflags | ses->overrideSecFlg;
-
-       cifs_dbg(FYI, "sec_flags 0x%x\n", sec_flags);
-
        req->hdr.SessionId = 0; /* First session, not a reauthenticate */
        req->VcNumber = 0; /* MBZ */
        /* to enable echos and oplocks */
        req->hdr.CreditRequest = cpu_to_le16(3);
 
        /* only one of SMB2 signing flags may be set in SMB2 request */
-       if ((sec_flags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN)
-               temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
-       else if (ses->server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED)
-               temp = SMB2_NEGOTIATE_SIGNING_REQUIRED;
-       else if (sec_flags & CIFSSEC_MAY_SIGN) /* MAY_SIGN is a single flag */
-               temp = SMB2_NEGOTIATE_SIGNING_ENABLED;
-
-       req->SecurityMode = temp;
+       if (server->sign)
+               req->SecurityMode = SMB2_NEGOTIATE_SIGNING_REQUIRED;
+       else if (global_secflags & CIFSSEC_MAY_SIGN) /* one flag unlike MUST_ */
+               req->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+       else
+               req->SecurityMode = 0;
+
        req->Capabilities = 0;
        req->Channel = 0; /* MBZ */
 
@@ -679,7 +651,7 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 
         /* since no tcon, smb2_init can not do this, so do here */
        req->hdr.SessionId = ses->Suid;
-       if (server->sec_mode & SECMODE_SIGN_REQUIRED)
+       if (server->sign)
                req->hdr.Flags |= SMB2_FLAGS_SIGNED;
 
        rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
@@ -788,11 +760,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        }
 
        tcon->share_flags = le32_to_cpu(rsp->ShareFlags);
+       tcon->capabilities = rsp->Capabilities; /* we keep caps little endian */
        tcon->maximal_access = le32_to_cpu(rsp->MaximalAccess);
        tcon->tidStatus = CifsGood;
        tcon->need_reconnect = false;
        tcon->tid = rsp->hdr.TreeId;
-       strncpy(tcon->treeName, tree, MAX_TREE_SIZE);
+       strlcpy(tcon->treeName, tree, sizeof(tcon->treeName));
 
        if ((rsp->Capabilities & SMB2_SHARE_CAP_DFS) &&
            ((tcon->share_flags & SHI1005_FLAGS_DFS) == 0))
@@ -1036,6 +1009,122 @@ creat_exit:
        return rc;
 }
 
+/*
+ *     SMB2 IOCTL is used for both IOCTLs and FSCTLs
+ */
+int
+SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+          u64 volatile_fid, u32 opcode, bool is_fsctl, char *in_data,
+          u32 indatalen, char **out_data, u32 *plen /* returned data len */)
+{
+       struct smb2_ioctl_req *req;
+       struct smb2_ioctl_rsp *rsp;
+       struct TCP_Server_Info *server;
+       struct cifs_ses *ses = tcon->ses;
+       struct kvec iov[2];
+       int resp_buftype;
+       int num_iovecs;
+       int rc = 0;
+
+       cifs_dbg(FYI, "SMB2 IOCTL\n");
+
+       /* zero out returned data len, in case of error */
+       if (plen)
+               *plen = 0;
+
+       if (ses && (ses->server))
+               server = ses->server;
+       else
+               return -EIO;
+
+       rc = small_smb2_init(SMB2_IOCTL, tcon, (void **) &req);
+       if (rc)
+               return rc;
+
+       req->CtlCode = cpu_to_le32(opcode);
+       req->PersistentFileId = persistent_fid;
+       req->VolatileFileId = volatile_fid;
+
+       if (indatalen) {
+               req->InputCount = cpu_to_le32(indatalen);
+               /* do not set InputOffset if no input data */
+               req->InputOffset =
+                      cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer) - 4);
+               iov[1].iov_base = in_data;
+               iov[1].iov_len = indatalen;
+               num_iovecs = 2;
+       } else
+               num_iovecs = 1;
+
+       req->OutputOffset = 0;
+       req->OutputCount = 0; /* MBZ */
+
+       /*
+        * Could increase MaxOutputResponse, but that would require more
+        * than one credit. Windows typically sets this smaller, but for some
+        * ioctls it may be useful to allow server to send more. No point
+        * limiting what the server can send as long as fits in one credit
+        */
+       req->MaxOutputResponse = cpu_to_le32(0xFF00); /* < 64K uses 1 credit */
+
+       if (is_fsctl)
+               req->Flags = cpu_to_le32(SMB2_0_IOCTL_IS_FSCTL);
+       else
+               req->Flags = 0;
+
+       iov[0].iov_base = (char *)req;
+       /* 4 for rfc1002 length field */
+       iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+       if (indatalen)
+               inc_rfc1001_len(req, indatalen);
+
+       rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0);
+       rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base;
+
+       if (rc != 0) {
+               if (tcon)
+                       cifs_stats_fail_inc(tcon, SMB2_IOCTL_HE);
+               goto ioctl_exit;
+       }
+
+       /* check if caller wants to look at return data or just return rc */
+       if ((plen == NULL) || (out_data == NULL))
+               goto ioctl_exit;
+
+       *plen = le32_to_cpu(rsp->OutputCount);
+
+       /* We check for obvious errors in the output buffer length and offset */
+       if (*plen == 0)
+               goto ioctl_exit; /* server returned no data */
+       else if (*plen > 0xFF00) {
+               cifs_dbg(VFS, "srv returned invalid ioctl length: %d\n", *plen);
+               *plen = 0;
+               rc = -EIO;
+               goto ioctl_exit;
+       }
+
+       if (get_rfc1002_length(rsp) < le32_to_cpu(rsp->OutputOffset) + *plen) {
+               cifs_dbg(VFS, "Malformed ioctl resp: len %d offset %d\n", *plen,
+                       le32_to_cpu(rsp->OutputOffset));
+               *plen = 0;
+               rc = -EIO;
+               goto ioctl_exit;
+       }
+
+       *out_data = kmalloc(*plen, GFP_KERNEL);
+       if (*out_data == NULL) {
+               rc = -ENOMEM;
+               goto ioctl_exit;
+       }
+
+       memcpy(*out_data, rsp->hdr.ProtocolId + le32_to_cpu(rsp->OutputOffset),
+              *plen);
+ioctl_exit:
+       free_rsp_buf(resp_buftype, rsp);
+       return rc;
+}
+
 int
 SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
           u64 persistent_fid, u64 volatile_fid)
@@ -1384,8 +1473,7 @@ smb2_readv_callback(struct mid_q_entry *mid)
        case MID_RESPONSE_RECEIVED:
                credits_received = le16_to_cpu(buf->CreditRequest);
                /* result already set, check signature */
-               if (server->sec_mode &
-                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+               if (server->sign) {
                        int rc;
 
                        rc = smb2_verify_signature(&rqst, server);
index 4cb4ced258cb333d326e9fc5ccd353313ec0c8d4..f31043b26bd3226ac4ea309d1c29c3ca3f64df2b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/smb2pdu.h
  *
- *   Copyright (c) International Business Machines  Corp., 2009, 2010
+ *   Copyright (c) International Business Machines  Corp., 2009, 2013
  *                 Etersoft, 2012
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *              Pavel Shilovsky (pshilovsky@samba.org) 2012
@@ -170,6 +170,7 @@ struct smb2_negotiate_req {
 #define SMB20_PROT_ID 0x0202
 #define SMB21_PROT_ID 0x0210
 #define SMB30_PROT_ID 0x0300
+#define SMB302_PROT_ID 0x0302
 #define BAD_PROT_ID   0xFFFF
 
 /* SecurityMode flags */
@@ -283,10 +284,17 @@ struct smb2_tree_connect_rsp {
 #define SHI1005_FLAGS_ALLOW_NAMESPACE_CACHING          0x00000400
 #define SHI1005_FLAGS_ACCESS_BASED_DIRECTORY_ENUM      0x00000800
 #define SHI1005_FLAGS_FORCE_LEVELII_OPLOCK             0x00001000
-#define SHI1005_FLAGS_ENABLE_HASH                      0x00002000
+#define SHI1005_FLAGS_ENABLE_HASH_V1                   0x00002000
+#define SHI1005_FLAGS_ENABLE_HASH_V2                   0x00004000
+#define SHI1005_FLAGS_ENCRYPT_DATA                     0x00008000
+#define SHI1005_FLAGS_ALL                              0x0000FF33
 
 /* Possible share capabilities */
-#define SMB2_SHARE_CAP_DFS     cpu_to_le32(0x00000008)
+#define SMB2_SHARE_CAP_DFS     cpu_to_le32(0x00000008) /* all dialects */
+#define SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY cpu_to_le32(0x00000010) /* 3.0 */
+#define SMB2_SHARE_CAP_SCALEOUT        cpu_to_le32(0x00000020) /* 3.0 */
+#define SMB2_SHARE_CAP_CLUSTER cpu_to_le32(0x00000040) /* 3.0 */
+#define SMB2_SHARE_CAP_ASYMMETRIC cpu_to_le32(0x00000080) /* 3.02 */
 
 struct smb2_tree_disconnect_req {
        struct smb2_hdr hdr;
@@ -477,6 +485,75 @@ struct create_lease {
        struct lease_context lcontext;
 } __packed;
 
+/* this goes in the ioctl buffer when doing a copychunk request */
+struct copychunk_ioctl {
+       char SourceKey[24];
+       __le32 ChunkCount; /* we are only sending 1 */
+       __le32 Reserved;
+       /* array will only be one chunk long for us */
+       __le64 SourceOffset;
+       __le64 TargetOffset;
+       __le32 Length; /* how many bytes to copy */
+       __u32 Reserved2;
+} __packed;
+
+/* Response and Request are the same format */
+struct validate_negotiate_info {
+       __le32 Capabilities;
+       __u8   Guid[SMB2_CLIENT_GUID_SIZE];
+       __le16 SecurityMode;
+       __le16 DialectCount;
+       __le16 Dialect[1];
+} __packed;
+
+#define RSS_CAPABLE    0x00000001
+#define RDMA_CAPABLE   0x00000002
+
+struct network_interface_info_ioctl_rsp {
+       __le32 Next; /* next interface. zero if this is last one */
+       __le32 IfIndex;
+       __le32 Capability; /* RSS or RDMA Capable */
+       __le32 Reserved;
+       __le64 LinkSpeed;
+       char    SockAddr_Storage[128];
+} __packed;
+
+#define NO_FILE_ID 0xFFFFFFFFFFFFFFFFULL /* general ioctls to srv not to file */
+
+struct smb2_ioctl_req {
+       struct smb2_hdr hdr;
+       __le16 StructureSize;   /* Must be 57 */
+       __u16 Reserved;
+       __le32 CtlCode;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __le32 InputOffset;
+       __le32 InputCount;
+       __le32 MaxInputResponse;
+       __le32 OutputOffset;
+       __le32 OutputCount;
+       __le32 MaxOutputResponse;
+       __le32 Flags;
+       __u32  Reserved2;
+       char   Buffer[0];
+} __packed;
+
+struct smb2_ioctl_rsp {
+       struct smb2_hdr hdr;
+       __le16 StructureSize;   /* Must be 57 */
+       __u16 Reserved;
+       __le32 CtlCode;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __le32 InputOffset;
+       __le32 InputCount;
+       __le32 OutputOffset;
+       __le32 OutputCount;
+       __le32 Flags;
+       __u32  Reserved2;
+       /* char * buffer[] */
+} __packed;
+
 /* Currently defined values for close flags */
 #define SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB       cpu_to_le16(0x0001)
 struct smb2_close_req {
@@ -517,17 +594,25 @@ struct smb2_flush_rsp {
        __le16 Reserved;
 } __packed;
 
+/* For read request Flags field below, following flag is defined for SMB3.02 */
+#define SMB2_READFLAG_READ_UNBUFFERED  0x01
+
+/* Channel field for read and write: exactly one of following flags can be set*/
+#define SMB2_CHANNEL_NONE              0x00000000
+#define SMB2_CHANNEL_RDMA_V1           0x00000001 /* SMB3 or later */
+#define SMB2_CHANNEL_RDMA_V1_INVALIDATE 0x00000001 /* SMB3.02 or later */
+
 struct smb2_read_req {
        struct smb2_hdr hdr;
        __le16 StructureSize; /* Must be 49 */
        __u8   Padding; /* offset from start of SMB2 header to place read */
-       __u8   Reserved;
+       __u8   Flags; /* MBZ unless SMB3.02 or later */
        __le32 Length;
        __le64 Offset;
        __u64  PersistentFileId; /* opaque endianness */
        __u64  VolatileFileId; /* opaque endianness */
        __le32 MinimumCount;
-       __le32 Channel; /* Reserved MBZ */
+       __le32 Channel; /* MBZ except for SMB3 or later */
        __le32 RemainingBytes;
        __le16 ReadChannelInfoOffset; /* Reserved MBZ */
        __le16 ReadChannelInfoLength; /* Reserved MBZ */
@@ -545,8 +630,9 @@ struct smb2_read_rsp {
        __u8   Buffer[1];
 } __packed;
 
-/* For write request Flags field below the following flag is defined: */
-#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+/* For write request Flags field below the following flags are defined: */
+#define SMB2_WRITEFLAG_WRITE_THROUGH   0x00000001      /* SMB2.1 or later */
+#define SMB2_WRITEFLAG_WRITE_UNBUFFERED        0x00000002      /* SMB3.02 or later */
 
 struct smb2_write_req {
        struct smb2_hdr hdr;
index 2aa3535e38ced630c3c6e7716ff3540769e46873..d4e1eb807457d440f0d75c278fa789dcd4dc5732 100644 (file)
@@ -111,6 +111,10 @@ extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
                     __u32 desired_access, __u32 create_disposition,
                     __u32 file_attributes, __u32 create_options,
                     __u8 *oplock, struct smb2_file_all_info *buf);
+extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
+                    u64 persistent_fid, u64 volatile_fid, u32 opcode,
+                    bool is_fsctl, char *in_data, u32 indatalen,
+                    char **out_data, u32 *plen /* returned data len */);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
                      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
index 01f0ac8007809a9514ac72ae34f066914168afb0..09b4fbaadeb6d5c9c79f835f6763b66028e4466d 100644 (file)
@@ -116,11 +116,155 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        return rc;
 }
 
+void
+generate_smb3signingkey(struct TCP_Server_Info *server)
+{
+       unsigned char zero = 0x0;
+       __u8 i[4] = {0, 0, 0, 1};
+       __u8 L[4] = {0, 0, 0, 128};
+       int rc = 0;
+       unsigned char prfhash[SMB2_HMACSHA256_SIZE];
+       unsigned char *hashptr = prfhash;
+
+       memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
+       memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
+
+       rc = crypto_shash_setkey(server->secmech.hmacsha256,
+               server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not set with session key\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               i, 4);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with n\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               "SMB2AESCMAC", 12);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               &zero, 1);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with zero\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               "SmbSign", 8);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+                               L, 4);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not update with L\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
+                               hashptr);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
+               goto smb3signkey_ret;
+       }
+
+       memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);
+
+smb3signkey_ret:
+       return;
+}
+
 int
 smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
-       cifs_dbg(FYI, "smb3 signatures not supported yet\n");
-       return -EOPNOTSUPP;
+       int i, rc;
+       unsigned char smb3_signature[SMB2_CMACAES_SIZE];
+       unsigned char *sigptr = smb3_signature;
+       struct kvec *iov = rqst->rq_iov;
+       int n_vec = rqst->rq_nvec;
+       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+       memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
+       memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+
+       rc = crypto_shash_setkey(server->secmech.cmacaes,
+               server->smb3signingkey, SMB2_CMACAES_SIZE);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
+               return rc;
+       }
+
+       rc = crypto_shash_init(&server->secmech.sdesccmacaes->shash);
+       if (rc) {
+               cifs_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
+               return rc;
+       }
+
+       for (i = 0; i < n_vec; i++) {
+               if (iov[i].iov_len == 0)
+                       continue;
+               if (iov[i].iov_base == NULL) {
+                       cifs_dbg(VFS, "null iovec entry");
+                       return -EIO;
+               }
+               /*
+                * The first entry includes a length field (which does not get
+                * signed that occupies the first 4 bytes before the header).
+                */
+               if (i == 0) {
+                       if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
+                               break; /* nothing to sign or corrupt header */
+                       rc =
+                       crypto_shash_update(
+                               &server->secmech.sdesccmacaes->shash,
+                               iov[i].iov_base + 4, iov[i].iov_len - 4);
+               } else {
+                       rc =
+                       crypto_shash_update(
+                               &server->secmech.sdesccmacaes->shash,
+                               iov[i].iov_base, iov[i].iov_len);
+               }
+               if (rc) {
+                       cifs_dbg(VFS, "%s: Couldn't update cmac aes with payload\n",
+                                                       __func__);
+                       return rc;
+               }
+       }
+
+       /* now hash over the rq_pages array */
+       for (i = 0; i < rqst->rq_npages; i++) {
+               struct kvec p_iov;
+
+               cifs_rqst_page_to_kvec(rqst, i, &p_iov);
+               crypto_shash_update(&server->secmech.sdesccmacaes->shash,
+                                       p_iov.iov_base, p_iov.iov_len);
+               kunmap(rqst->rq_pages[i]);
+       }
+
+       rc = crypto_shash_final(&server->secmech.sdesccmacaes->shash,
+                                               sigptr);
+       if (rc)
+               cifs_dbg(VFS, "%s: Could not generate cmac aes\n", __func__);
+
+       memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+
+       return rc;
 }
 
 /* must be called with server->srv_mutex held */
@@ -275,8 +419,7 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 
        dump_smb(mid->resp_buf, min_t(u32, 80, len));
        /* convert the length into a more usable form */
-       if ((len > 24) &&
-           (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
+       if (len > 24 && server->sign) {
                int rc;
 
                rc = smb2_verify_signature(&rqst, server);
index 7056b891e087519d7116f015987def8bf31c1ccc..d952ee48f4dcc629a5d1e91c3470cbd2bd6d1aec 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/smbfsctl.h: SMB, CIFS, SMB2 FSCTL definitions
  *
- *   Copyright (c) International Business Machines  Corp., 2002,2009
+ *   Copyright (c) International Business Machines  Corp., 2002,2013
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
 /* IOCTL information */
 /*
  * List of ioctl/fsctl function codes that are or could be useful in the
- * future to remote clients like cifs or SMB2 client.  There is probably
+ * future to remote clients like cifs or SMB2/SMB3 client.  This is probably
  * a slightly larger set of fsctls that NTFS local filesystem could handle,
  * including the seven below that we do not have struct definitions for.
  * Even with protocol definitions for most of these now available, we still
  * remotely.  Some of the following, such as the encryption/compression ones
  * could be invoked from tools via a specialized hook into the VFS rather
  * than via the standard vfs entry points
+ *
+ * See MS-SMB2 Section 2.2.31 (last checked June 2013, all of that list are
+ * below). Additional detail on less common ones can be found in MS-FSCC
+ * section 2.3.
  */
+#define FSCTL_DFS_GET_REFERRALS      0x00060194
+#define FSCTL_DFS_GET_REFERRALS_EX   0x000601B0
 #define FSCTL_REQUEST_OPLOCK_LEVEL_1 0x00090000
 #define FSCTL_REQUEST_OPLOCK_LEVEL_2 0x00090004
 #define FSCTL_REQUEST_BATCH_OPLOCK   0x00090008
 #define FSCTL_SET_SHORT_NAME_BEHAVIOR 0x000901B4 /* BB add struct */
 #define FSCTL_QUERY_ALLOCATED_RANGES 0x000940CF /* BB add struct */
 #define FSCTL_SET_DEFECT_MANAGEMENT  0x00098134 /* BB add struct */
+#define FSCTL_FILE_LEVEL_TRIM        0x00098208 /* BB add struct */
 #define FSCTL_SIS_LINK_FILES         0x0009C104
 #define FSCTL_PIPE_PEEK              0x0011400C /* BB add struct */
 #define FSCTL_PIPE_TRANSCEIVE        0x0011C017 /* BB add struct */
 /* strange that the number for this op is not sequential with previous op */
 #define FSCTL_PIPE_WAIT              0x00110018 /* BB add struct */
+/* Enumerate previous versions of a file */
+#define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064
+/* Retrieve an opaque file reference for server-side data movement ie copy */
+#define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078
+#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */
 #define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */
 #define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */
+#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204 /* BB add struct */
+/* Perform server-side data movement */
+#define FSCTL_SRV_COPYCHUNK 0x001440F2
+#define FSCTL_SRV_COPYCHUNK_WRITE 0x001480F2
+#define FSCTL_QUERY_NETWORK_INTERFACE_INFO 0x001401FC /* BB add struct */
+#define FSCTL_SRV_READ_HASH          0x001441BB /* BB add struct */
 
 #define IO_REPARSE_TAG_MOUNT_POINT   0xA0000003
 #define IO_REPARSE_TAG_HSM           0xC0000004
 #define IO_REPARSE_TAG_SIS           0x80000007
+
+/* fsctl flags */
+/* If Flags is set to this value, the request is an FSCTL not ioctl request */
+#define SMB2_0_IOCTL_IS_FSCTL          0x00000001
+
index bfbf4700d160f8a4d54f7cc0446a35c4de8c747d..1996d6ceb8338651dd1fce8df90af787ae2ad680 100644 (file)
@@ -463,7 +463,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst)
        struct mid_q_entry *mid;
 
        /* enable signing if server requires it */
-       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if (server->sign)
                hdr->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        mid = AllocMidQEntry(hdr, server);
@@ -612,7 +612,7 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
        dump_smb(mid->resp_buf, min_t(u32, 92, len));
 
        /* convert the length into a more usable form */
-       if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+       if (server->sign) {
                struct kvec iov;
                int rc = 0;
                struct smb_rqst rqst = { .rq_iov = &iov,