[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>
This commit is contained in:
parent
124a27fe32
commit
750d1151a6
@ -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
|
or recent levels of FindFirst unless server says it supports NT SMBs
|
||||||
(instead use legacy equivalents from LANMAN dialect). Fix to allow
|
(instead use legacy equivalents from LANMAN dialect). Fix to allow
|
||||||
NTLMv2 authentication support (now can use stronger password hashing
|
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
|
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
|
SFU does). In the future the bottom 9 bits of the mode
|
||||||
mode also will be emulated using queries of the security
|
mode also will be emulated using queries of the security
|
||||||
descriptor (ACL).
|
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)
|
none attempt to connection as a null user (no name)
|
||||||
krb5 Use Kerberos version 5 authentication
|
krb5 Use Kerberos version 5 authentication
|
||||||
krb5i Use Kerberos authentication and packet signing
|
krb5i Use Kerberos authentication and packet signing
|
||||||
|
@ -186,6 +186,7 @@ struct cifsSesInfo {
|
|||||||
struct TCP_Server_Info *server; /* pointer to server info */
|
struct TCP_Server_Info *server; /* pointer to server info */
|
||||||
atomic_t inUse; /* # of mounts (tree connections) on this ses */
|
atomic_t inUse; /* # of mounts (tree connections) on this ses */
|
||||||
enum statusEnum status;
|
enum statusEnum status;
|
||||||
|
unsigned overrideSecFlg; /* if non-zero override global sec flags */
|
||||||
__u16 ipc_tid; /* special tid for connection to IPC share */
|
__u16 ipc_tid; /* special tid for connection to IPC share */
|
||||||
__u16 flags;
|
__u16 flags;
|
||||||
char *serverOS; /* name of operating system underlying server */
|
char *serverOS; /* name of operating system underlying server */
|
||||||
|
@ -396,6 +396,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||||||
int i;
|
int i;
|
||||||
struct TCP_Server_Info * server;
|
struct TCP_Server_Info * server;
|
||||||
u16 count;
|
u16 count;
|
||||||
|
unsigned int secFlags;
|
||||||
|
|
||||||
if(ses->server)
|
if(ses->server)
|
||||||
server = ses->server;
|
server = ses->server;
|
||||||
@ -407,9 +408,16 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||||||
(void **) &pSMB, (void **) &pSMBr);
|
(void **) &pSMB, (void **) &pSMBr);
|
||||||
if (rc)
|
if (rc)
|
||||||
return 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.Mid = GetNextMid(server);
|
||||||
pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
|
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;
|
pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
@ -439,8 +447,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|||||||
&& (pSMBr->DialectIndex == LANMAN_PROT)) {
|
&& (pSMBr->DialectIndex == LANMAN_PROT)) {
|
||||||
struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
|
struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
|
||||||
|
|
||||||
if((extended_security & CIFSSEC_MAY_LANMAN) ||
|
if((secFlags & CIFSSEC_MAY_LANMAN) ||
|
||||||
(extended_security & CIFSSEC_MAY_PLNTXT))
|
(secFlags & CIFSSEC_MAY_PLNTXT))
|
||||||
server->secType = LANMAN;
|
server->secType = LANMAN;
|
||||||
else {
|
else {
|
||||||
cERROR(1, ("mount failed weak security disabled"
|
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)
|
if((server->secMode & SECMODE_PW_ENCRYPT) == 0)
|
||||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||||
if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0)
|
if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0)
|
||||||
#endif /* CIFS_WEAK_PW_HASH */
|
#endif /* CIFS_WEAK_PW_HASH */
|
||||||
cERROR(1,("Server requests plain text password"
|
cERROR(1,("Server requests plain text password"
|
||||||
" but client support disabled"));
|
" but client support disabled"));
|
||||||
|
|
||||||
if(extended_security & CIFSSEC_MUST_NTLMV2)
|
if(secFlags & CIFSSEC_MUST_NTLMV2)
|
||||||
server->secType = NTLMv2;
|
server->secType = NTLMv2;
|
||||||
else
|
else
|
||||||
server->secType = NTLM;
|
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"));
|
cERROR(1,("no security value specified"));
|
||||||
continue;
|
continue;
|
||||||
} else if (strnicmp(value, "krb5i", 5) == 0) {
|
} else if (strnicmp(value, "krb5i", 5) == 0) {
|
||||||
vol->secFlg = CIFSSEC_MAY_KRB5 |
|
vol->secFlg |= CIFSSEC_MAY_KRB5 |
|
||||||
CIFSSEC_MUST_SIGN;
|
CIFSSEC_MUST_SIGN;
|
||||||
} else if (strnicmp(value, "krb5p", 5) == 0) {
|
} else if (strnicmp(value, "krb5p", 5) == 0) {
|
||||||
/* vol->secFlg = CIFSSEC_MUST_SEAL |
|
/* vol->secFlg |= CIFSSEC_MUST_SEAL |
|
||||||
CIFSSEC_MAY_KRB5; */
|
CIFSSEC_MAY_KRB5; */
|
||||||
cERROR(1,("Krb5 cifs privacy not supported"));
|
cERROR(1,("Krb5 cifs privacy not supported"));
|
||||||
return 1;
|
return 1;
|
||||||
} else if (strnicmp(value, "krb5", 4) == 0) {
|
} else if (strnicmp(value, "krb5", 4) == 0) {
|
||||||
vol->secFlg = CIFSSEC_MAY_KRB5;
|
vol->secFlg |= CIFSSEC_MAY_KRB5;
|
||||||
} else if (strnicmp(value, "ntlmv2i", 7) == 0) {
|
} else if (strnicmp(value, "ntlmv2i", 7) == 0) {
|
||||||
vol->secFlg = CIFSSEC_MAY_NTLMV2 |
|
vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
|
||||||
CIFSSEC_MUST_SIGN;
|
CIFSSEC_MUST_SIGN;
|
||||||
} else if (strnicmp(value, "ntlmv2", 6) == 0) {
|
} else if (strnicmp(value, "ntlmv2", 6) == 0) {
|
||||||
vol->secFlg = CIFSSEC_MAY_NTLMV2;
|
vol->secFlg |= CIFSSEC_MAY_NTLMV2;
|
||||||
} else if (strnicmp(value, "ntlmi", 5) == 0) {
|
} else if (strnicmp(value, "ntlmi", 5) == 0) {
|
||||||
vol->secFlg = CIFSSEC_MAY_NTLM |
|
vol->secFlg |= CIFSSEC_MAY_NTLM |
|
||||||
CIFSSEC_MUST_SIGN;
|
CIFSSEC_MUST_SIGN;
|
||||||
} else if (strnicmp(value, "ntlm", 4) == 0) {
|
} else if (strnicmp(value, "ntlm", 4) == 0) {
|
||||||
/* ntlm is default so can be turned off too */
|
/* 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) {
|
} else if (strnicmp(value, "nontlm", 6) == 0) {
|
||||||
/* BB is there a better way to do this? */
|
/* 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
|
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
||||||
} else if (strnicmp(value, "lanman", 6) == 0) {
|
} else if (strnicmp(value, "lanman", 6) == 0) {
|
||||||
vol->secFlg = CIFSSEC_MAY_LANMAN;
|
vol->secFlg |= CIFSSEC_MAY_LANMAN;
|
||||||
#endif
|
#endif
|
||||||
} else if (strnicmp(value, "none", 4) == 0) {
|
} else if (strnicmp(value, "none", 4) == 0) {
|
||||||
vol->nullauth = 1;
|
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;
|
vol->no_psx_acl = 0;
|
||||||
} else if (strnicmp(data, "noacl",5) == 0) {
|
} else if (strnicmp(data, "noacl",5) == 0) {
|
||||||
vol->no_psx_acl = 1;
|
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) {
|
} else if (strnicmp(data, "direct",6) == 0) {
|
||||||
vol->direct_io = 1;
|
vol->direct_io = 1;
|
||||||
} else if (strnicmp(data, "forcedirectio",13) == 0) {
|
} 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);
|
volume_info.domainname);
|
||||||
}
|
}
|
||||||
pSesInfo->linux_uid = volume_info.linux_uid;
|
pSesInfo->linux_uid = volume_info.linux_uid;
|
||||||
|
pSesInfo->overrideSecFlg = volume_info.secFlg;
|
||||||
down(&pSesInfo->sesSem);
|
down(&pSesInfo->sesSem);
|
||||||
/* BB FIXME need to pass vol->secFlgs BB */
|
/* BB FIXME need to pass vol->secFlgs BB */
|
||||||
rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
|
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);
|
strncpy(bcc_ptr, ses->userName, 300);
|
||||||
}
|
}
|
||||||
/* BB improve check for overflow */
|
/* BB improve check for overflow */
|
||||||
bcc_ptr += strnlen(ses->userName, 200);
|
bcc_ptr += strnlen(ses->userName, 300);
|
||||||
*bcc_ptr = 0;
|
*bcc_ptr = 0;
|
||||||
bcc_ptr++; /* account for null termination */
|
bcc_ptr++; /* account for null termination */
|
||||||
|
|
||||||
@ -313,11 +313,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||||||
int wct;
|
int wct;
|
||||||
struct smb_hdr *smb_buf;
|
struct smb_hdr *smb_buf;
|
||||||
char *bcc_ptr;
|
char *bcc_ptr;
|
||||||
|
char *str_area;
|
||||||
SESSION_SETUP_ANDX *pSMB;
|
SESSION_SETUP_ANDX *pSMB;
|
||||||
__u32 capabilities;
|
__u32 capabilities;
|
||||||
int count;
|
int count;
|
||||||
int resp_buf_type = 0;
|
int resp_buf_type = 0;
|
||||||
struct kvec iov[2]; /* BB split variable length info into 2nd iovec */
|
struct kvec iov[2];
|
||||||
enum securityEnum type;
|
enum securityEnum type;
|
||||||
__u16 action;
|
__u16 action;
|
||||||
int bytes_remaining;
|
int bytes_remaining;
|
||||||
@ -351,7 +352,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||||||
pSMB = (SESSION_SETUP_ANDX *)smb_buf;
|
pSMB = (SESSION_SETUP_ANDX *)smb_buf;
|
||||||
|
|
||||||
capabilities = cifs_ssetup_hdr(ses, pSMB);
|
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) {
|
if(type == LANMAN) {
|
||||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
#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);
|
calc_lanman_hash(ses, lnm_session_key);
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_DEBUG2
|
/* #ifdef CONFIG_CIFS_DEBUG2
|
||||||
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
|
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
|
||||||
CIFS_SESS_KEY_SIZE);
|
CIFS_SESS_KEY_SIZE);
|
||||||
#endif
|
#endif */
|
||||||
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
|
memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
|
||||||
bcc_ptr += 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
|
changed to do higher than lanman dialect and
|
||||||
we reconnected would we ever calc signing_key? */
|
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 */
|
/* Unicode not allowed for LANMAN dialects */
|
||||||
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
|
||||||
#endif
|
#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
|
if(first_time) /* should this be moved into common code
|
||||||
with similar ntlmv2 path? */
|
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);
|
ntlm_session_key, ses->password);
|
||||||
/* copy session key */
|
/* copy session key */
|
||||||
|
|
||||||
@ -454,23 +466,14 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
|
|||||||
/* BB set password lengths */
|
/* 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;
|
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);
|
BCC_LE(smb_buf) = cpu_to_le16(count);
|
||||||
|
|
||||||
|
iov[1].iov_base = str_area;
|
||||||
/* BB FIXME check for other non ntlm code paths */
|
iov[1].iov_len = count;
|
||||||
|
rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0);
|
||||||
/* 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);
|
|
||||||
/* SMB request buf freed in SendReceive2 */
|
/* SMB request buf freed in SendReceive2 */
|
||||||
|
|
||||||
cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
|
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);
|
rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
|
||||||
|
|
||||||
ssetup_exit:
|
ssetup_exit:
|
||||||
|
kfree(str_area);
|
||||||
if(resp_buf_type == CIFS_SMALL_BUFFER) {
|
if(resp_buf_type == CIFS_SMALL_BUFFER) {
|
||||||
cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
|
cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
|
||||||
cifs_small_buf_release(iov[0].iov_base);
|
cifs_small_buf_release(iov[0].iov_base);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user