Commit 750d1151 authored by Steve French's avatar Steve French
Browse files

[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: default avatarSteve French <sfrench@us.ibm.com>
parent 124a27fe
......@@ -7,7 +7,8 @@ so we can do search (ls etc.) to OS/2. Do not send NTCreateX
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
------------
......
......@@ -443,7 +443,10 @@ A partial list of the supported mount options follows:
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
......
......@@ -186,6 +186,7 @@ struct cifsSesInfo {
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 */
......
......@@ -396,6 +396,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
int i;
struct TCP_Server_Info * server;
u16 count;
unsigned int secFlags;
if(ses->server)
server = ses->server;
......@@ -407,9 +408,16 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
(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 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
&& (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 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
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;
......
......@@ -915,32 +915,32 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
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 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
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 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
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);
......
......@@ -138,7 +138,7 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
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 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
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 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
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 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
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 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
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 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
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 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* 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 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
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);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment