[CIFS] Fix allocation of buffers for new session setup routine to allow
longer user and domain names and allow passing sec options on mount
Signed-off-by: Steve French <sfrench@us.ibm.com>
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
index 79a202b..a61d17e 100644
--- a/fs/cifs/CHANGES
+++ b/fs/cifs/CHANGES
@@ -7,7 +7,8 @@
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
------------
diff --git a/fs/cifs/README b/fs/cifs/README
index 46c2cfa..7986d0d 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -443,7 +443,10 @@
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
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 87453a6b..6d7cf5f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -186,6 +186,7 @@
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 */
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 38f83db2..de405bf 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -396,6 +396,7 @@
int i;
struct TCP_Server_Info * server;
u16 count;
+ unsigned int secFlags;
if(ses->server)
server = ses->server;
@@ -407,9 +408,16 @@
(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;
@@ -439,8 +447,8 @@
&& (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"
@@ -498,12 +506,12 @@
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;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c0f98dd..876eb9e 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -915,32 +915,32 @@
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;
@@ -1173,6 +1173,10 @@
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) {
@@ -1776,6 +1780,7 @@
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);
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 70e32a8..7737edd 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -138,7 +138,7 @@
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 */
@@ -313,11 +313,12 @@
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;
@@ -351,7 +352,18 @@
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
@@ -365,10 +377,10 @@
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;
@@ -377,7 +389,7 @@
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
@@ -396,7 +408,7 @@
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 */
@@ -454,23 +466,14 @@
/* 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));
@@ -515,6 +518,7 @@
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);