or recent levels of FindFirst unless server says it supports NT SMBs
 (instead use legacy equivalents from LANMAN dialect). Fix to allow
 NTLMv2 authentication support (now can use stronger password hashing
-on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004)
+on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004).
+Allow override of global cifs security flags on mount via "sec=" option(s).
 
 Version 1.43
 ------------
 
                SFU does).  In the future the bottom 9 bits of the mode
                mode also will be emulated using queries of the security
                descriptor (ACL).
-sec            Security mode.  Allowed values are:
+ sign           Must use packet signing (helps avoid unwanted data modification
+               by intermediate systems in the route).  Note that signing
+               does not work with lanman or plaintext authentication.
+ sec            Security mode.  Allowed values are:
                        none    attempt to connection as a null user (no name)
                        krb5    Use Kerberos version 5 authentication
                        krb5i   Use Kerberos authentication and packet signing
 
        struct TCP_Server_Info *server; /* pointer to server info */
        atomic_t inUse; /* # of mounts (tree connections) on this 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;
        char *serverOS;         /* name of operating system underlying server */
 
        int i;
        struct TCP_Server_Info * server;
        u16 count;
+       unsigned int secFlags;
 
        if(ses->server)
                server = ses->server;
                      (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;
+       else /* if override flags set only sign/seal OR them with global auth */
+               secFlags = extended_security | ses->overrideSecFlg;
+
        pSMB->hdr.Mid = GetNextMid(server);
        pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
-       if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
+       if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5)
                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
        
        count = 0;
                        && (pSMBr->DialectIndex == LANMAN_PROT)) {
                struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
 
-               if((extended_security & CIFSSEC_MAY_LANMAN) || 
-                       (extended_security & CIFSSEC_MAY_PLNTXT))
+               if((secFlags & CIFSSEC_MAY_LANMAN) || 
+                       (secFlags & CIFSSEC_MAY_PLNTXT))
                        server->secType = LANMAN;
                else {
                        cERROR(1, ("mount failed weak security disabled"
 
        if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
-               if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0)
+               if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
 #endif /* CIFS_WEAK_PW_HASH */
                        cERROR(1,("Server requests plain text password"
                                  " but client support disabled"));
 
-       if(extended_security & CIFSSEC_MUST_NTLMV2)
+       if(secFlags & CIFSSEC_MUST_NTLMV2)
                server->secType = NTLMv2;
        else
                server->secType = NTLM;
 
                                cERROR(1,("no security value specified"));
                                 continue;
                         } else if (strnicmp(value, "krb5i", 5) == 0) {
-                               vol->secFlg = CIFSSEC_MAY_KRB5 | 
+                               vol->secFlg |= CIFSSEC_MAY_KRB5 | 
                                        CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "krb5p", 5) == 0) {
-                               /* vol->secFlg = CIFSSEC_MUST_SEAL | 
+                               /* vol->secFlg |= CIFSSEC_MUST_SEAL | 
                                        CIFSSEC_MAY_KRB5; */ 
                                cERROR(1,("Krb5 cifs privacy not supported"));
                                return 1;
                        } else if (strnicmp(value, "krb5", 4) == 0) {
-                               vol->secFlg = CIFSSEC_MAY_KRB5;
+                               vol->secFlg |= CIFSSEC_MAY_KRB5;
                        } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
-                               vol->secFlg = CIFSSEC_MAY_NTLMV2 |
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
                                        CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlmv2", 6) == 0) {
-                               vol->secFlg = CIFSSEC_MAY_NTLMV2;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
                        } else if (strnicmp(value, "ntlmi", 5) == 0) {
-                               vol->secFlg = CIFSSEC_MAY_NTLM |
+                               vol->secFlg |= CIFSSEC_MAY_NTLM |
                                        CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlm", 4) == 0) {
                                /* ntlm is default so can be turned off too */
-                               vol->secFlg = CIFSSEC_MAY_NTLM;
+                               vol->secFlg |= CIFSSEC_MAY_NTLM;
                        } else if (strnicmp(value, "nontlm", 6) == 0) {
                                /* BB is there a better way to do this? */
-                               vol->secFlg = CIFSSEC_MAY_NTLMV2;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                        } else if (strnicmp(value, "lanman", 6) == 0) {
-                                vol->secFlg = CIFSSEC_MAY_LANMAN;
+                                vol->secFlg |= CIFSSEC_MAY_LANMAN;
 #endif
                        } else if (strnicmp(value, "none", 4) == 0) {
                                vol->nullauth = 1;
                        vol->no_psx_acl = 0;
                } else if (strnicmp(data, "noacl",5) == 0) {
                        vol->no_psx_acl = 1;
+               } else if (strnicmp(data, "sign",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SIGN;
+/*             } else if (strnicmp(data, "seal",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SEAL; */
                } else if (strnicmp(data, "direct",6) == 0) {
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio",13) == 0) {
                                                volume_info.domainname);
                        }
                        pSesInfo->linux_uid = volume_info.linux_uid;
+                       pSesInfo->overrideSecFlg = volume_info.secFlg;
                        down(&pSesInfo->sesSem);
                        /* BB FIXME need to pass vol->secFlgs BB */
                        rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
 
                 strncpy(bcc_ptr, ses->userName, 300);
         }
        /* BB improve check for overflow */
-        bcc_ptr += strnlen(ses->userName, 200);
+        bcc_ptr += strnlen(ses->userName, 300);
        *bcc_ptr = 0;
         bcc_ptr++; /* account for null termination */
 
        int wct;
        struct smb_hdr *smb_buf;
        char *bcc_ptr;
+       char *str_area;
        SESSION_SETUP_ANDX *pSMB;
        __u32 capabilities;
        int count;
        int resp_buf_type = 0;
-       struct kvec iov[2];  /* BB split variable length info into 2nd iovec */
+       struct kvec iov[2];
        enum securityEnum type;
        __u16 action;
        int bytes_remaining;
        pSMB = (SESSION_SETUP_ANDX *)smb_buf;
 
        capabilities = cifs_ssetup_hdr(ses, pSMB);
-       bcc_ptr = pByteArea(smb_buf);
+
+       /* we will send the SMB in two pieces,
+       a fixed length beginning part, and a
+       second part which will include the strings
+       and rest of bcc area, in order to avoid having
+       to do a large buffer 17K allocation */
+        iov[0].iov_base = (char *)pSMB;
+        iov[0].iov_len = smb_buf->smb_buf_length + 4;
+
+       /* 2000 big enough to fit max user, domain, NOS name etc. */
+       str_area = kmalloc(2000, GFP_KERNEL);
+       bcc_ptr = str_area;
 
        if(type == LANMAN) {
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 
                calc_lanman_hash(ses, lnm_session_key);
 
-#ifdef CONFIG_CIFS_DEBUG2
+/* #ifdef CONFIG_CIFS_DEBUG2
                cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
                        CIFS_SESS_KEY_SIZE);
-#endif
+#endif */
                memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
                bcc_ptr += CIFS_SESS_KEY_SIZE;
 
                changed to do higher than lanman dialect and
                we reconnected would we ever calc signing_key? */
 
-               cERROR(1,("Negotiating LANMAN setting up strings"));
+               cFYI(1,("Negotiating LANMAN setting up strings"));
                /* Unicode not allowed for LANMAN dialects */
                ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
 #endif    
 
                if(first_time) /* should this be moved into common code 
                                  with similar ntlmv2 path? */
-                       cifs_calculate_mac_key( ses->server->mac_signing_key,
+                       cifs_calculate_mac_key(ses->server->mac_signing_key,
                                ntlm_session_key, ses->password);
                /* copy session key */
 
                /* BB set password lengths */
        }
 
-       count = (long) bcc_ptr - (long) pByteArea(smb_buf);
+       count = (long) bcc_ptr - (long) str_area;
        smb_buf->smb_buf_length += count;
 
-       /* if we switch to small buffers, count will need to be fewer
-          than 383 (strings less than 335 bytes) */
-
        BCC_LE(smb_buf) = cpu_to_le16(count);
 
-
-       /* BB FIXME check for other non ntlm code paths */
-
-       /* BB check is this too big for a small smb? */
-
-       iov[0].iov_base = (char *)pSMB;
-       iov[0].iov_len = smb_buf->smb_buf_length + 4;
-
-       rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0);
+       iov[1].iov_base = str_area;
+       iov[1].iov_len = count; 
+       rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
        /* SMB request buf freed in SendReceive2 */
 
        cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
                rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
        
 ssetup_exit:
+       kfree(str_area);
        if(resp_buf_type == CIFS_SMALL_BUFFER) {
                cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
                cifs_small_buf_release(iov[0].iov_base);