Skip to content

Commit

Permalink
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
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
  ...
  • Loading branch information
Linus Torvalds committed Jul 3, 2013
2 parents f39d420 + 7ac0feb commit d414153
Show file tree
Hide file tree
Showing 24 changed files with 1,034 additions and 505 deletions.
1 change: 1 addition & 0 deletions fs/cifs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 45 additions & 7 deletions fs/cifs/cifs_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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 ");
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions fs/cifs/cifs_unicode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
40 changes: 34 additions & 6 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -778,15 +789,32 @@ 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);

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:
Expand Down
11 changes: 7 additions & 4 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
}

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Loading

0 comments on commit d414153

Please sign in to comment.