diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/Kconfig | 30 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 11 | ||||
-rw-r--r-- | fs/cifs/cifs_swn.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.c | 9 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 89 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 8 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 37 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 28 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 10 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 107 | ||||
-rw-r--r-- | fs/cifs/connect.c | 32 | ||||
-rw-r--r-- | fs/cifs/dir.c | 2 | ||||
-rw-r--r-- | fs/cifs/file.c | 50 | ||||
-rw-r--r-- | fs/cifs/fs_context.c | 25 | ||||
-rw-r--r-- | fs/cifs/fs_context.h | 3 | ||||
-rw-r--r-- | fs/cifs/fscache.c | 41 | ||||
-rw-r--r-- | fs/cifs/fscache.h | 23 | ||||
-rw-r--r-- | fs/cifs/inode.c | 25 | ||||
-rw-r--r-- | fs/cifs/misc.c | 50 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 23 | ||||
-rw-r--r-- | fs/cifs/sess.c | 257 | ||||
-rw-r--r-- | fs/cifs/smb2maperror.c | 1 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 2 | ||||
-rw-r--r-- | fs/cifs/smbencrypt.c | 139 |
25 files changed, 210 insertions, 796 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 7364950a9ef4..3b7e3b9e4fd2 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -4,19 +4,16 @@ config CIFS depends on INET select NLS select CRYPTO - select CRYPTO_MD4 select CRYPTO_MD5 select CRYPTO_SHA256 select CRYPTO_SHA512 select CRYPTO_CMAC select CRYPTO_HMAC - select CRYPTO_LIB_ARC4 select CRYPTO_AEAD2 select CRYPTO_CCM select CRYPTO_GCM select CRYPTO_ECB select CRYPTO_AES - select CRYPTO_LIB_DES select KEYS select DNS_RESOLVER select ASN1 @@ -85,33 +82,6 @@ config CIFS_ALLOW_INSECURE_LEGACY If unsure, say Y. -config CIFS_WEAK_PW_HASH - bool "Support legacy servers which use weaker LANMAN security" - depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY - help - Modern CIFS servers including Samba and most Windows versions - (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) - security mechanisms. These hash the password more securely - than the mechanisms used in the older LANMAN version of the - SMB protocol but LANMAN based authentication is needed to - establish sessions with some old SMB servers. - - Enabling this option allows the cifs module to mount to older - LANMAN based servers such as OS/2 and Windows 95, but such - mounts may be less secure than mounts using NTLM or more recent - security mechanisms if you are on a public network. Unless you - have a need to access old SMB servers (and are on a private - network) you probably want to say N. Even if this support - is enabled in the kernel build, LANMAN authentication will not be - used automatically. At runtime LANMAN mounts are disabled but - can be set to required (or optional) either in - /proc/fs/cifs (see Documentation/admin-guide/cifs/usage.rst for - more detail) or via an option on the mount command. This support - is disabled by default in order to reduce the possibility of a - downgrade attack. - - If unsure, say N. - config CIFS_UPCALL bool "Kerberos/SPNEGO advanced session setup" depends on CIFS diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 8857ac7e7a14..51a824fc926a 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -250,9 +250,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY seq_printf(m, ",ALLOW_INSECURE_LEGACY"); #endif -#ifdef CONFIG_CIFS_WEAK_PW_HASH - seq_printf(m, ",WEAK_PW_HASH"); -#endif #ifdef CONFIG_CIFS_POSIX seq_printf(m, ",CIFS_POSIX"); #endif @@ -929,14 +926,6 @@ cifs_security_flags_handle_must_flags(unsigned int *flags) *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 (CIFSSEC_MUST_LANMAN && - (*flags & CIFSSEC_MUST_LANMAN) == CIFSSEC_MUST_LANMAN) - *flags = CIFSSEC_MUST_LANMAN; - else if (CIFSSEC_MUST_PLNTXT && - (*flags & CIFSSEC_MUST_PLNTXT) == CIFSSEC_MUST_PLNTXT) - *flags = CIFSSEC_MUST_PLNTXT; *flags |= signflags; } diff --git a/fs/cifs/cifs_swn.c b/fs/cifs/cifs_swn.c index 93b47818c6c2..12bde7bfda86 100644 --- a/fs/cifs/cifs_swn.c +++ b/fs/cifs/cifs_swn.c @@ -147,8 +147,6 @@ static int cifs_swn_send_register_message(struct cifs_swn_reg *swnreg) goto nlmsg_fail; } break; - case LANMAN: - case NTLM: case NTLMv2: case RawNTLMSSP: ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb); diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 9bd03a231032..171ad8b42107 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -358,14 +358,9 @@ cifs_strndup_from_utf16(const char *src, const int maxlen, if (!dst) return NULL; cifs_from_utf16(dst, (__le16 *) src, len, maxlen, codepage, - NO_MAP_UNI_RSVD); + NO_MAP_UNI_RSVD); } else { - len = strnlen(src, maxlen); - len++; - dst = kmalloc(len, GFP_KERNEL); - if (!dst) - return NULL; - strlcpy(dst, src, len); + dst = kstrndup(src, maxlen, GFP_KERNEL); } return dst; diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index ecf15d845dbd..6679e07e533e 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -22,7 +22,7 @@ #include <linux/random.h> #include <linux/highmem.h> #include <linux/fips.h> -#include <crypto/arc4.h> +#include "../cifs_common/arc4.h" #include <crypto/aead.h> int __cifs_calc_signature(struct smb_rqst *rqst, @@ -250,87 +250,6 @@ int cifs_verify_signature(struct smb_rqst *rqst, } -/* first calculate 24 bytes ntlm response and then 16 byte session key */ -int setup_ntlm_response(struct cifs_ses *ses, const struct nls_table *nls_cp) -{ - int rc = 0; - unsigned int temp_len = CIFS_SESS_KEY_SIZE + CIFS_AUTH_RESP_SIZE; - char temp_key[CIFS_SESS_KEY_SIZE]; - - if (!ses) - return -EINVAL; - - ses->auth_key.response = kmalloc(temp_len, GFP_KERNEL); - if (!ses->auth_key.response) - return -ENOMEM; - - ses->auth_key.len = temp_len; - - rc = SMBNTencrypt(ses->password, ses->server->cryptkey, - ses->auth_key.response + CIFS_SESS_KEY_SIZE, nls_cp); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NTLM response, error: %d\n", - __func__, rc); - return rc; - } - - rc = E_md4hash(ses->password, temp_key, nls_cp); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", - __func__, rc); - return rc; - } - - rc = mdfour(ses->auth_key.response, temp_key, CIFS_SESS_KEY_SIZE); - if (rc) - cifs_dbg(FYI, "%s Can't generate NTLM session key, error: %d\n", - __func__, rc); - - return rc; -} - -#ifdef CONFIG_CIFS_WEAK_PW_HASH -int calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, - char *lnm_session_key) -{ - int i, len; - int rc; - char password_with_pad[CIFS_ENCPWD_SIZE] = {0}; - - if (password) { - for (len = 0; len < CIFS_ENCPWD_SIZE; len++) - if (!password[len]) - break; - - memcpy(password_with_pad, password, len); - } - - if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) { - memcpy(lnm_session_key, password_with_pad, - CIFS_ENCPWD_SIZE); - return 0; - } - - /* calculate old style session key */ - /* calling toupper is less broken than repeatedly - calling nls_toupper would be since that will never - work for UTF8, but neither handles multibyte code pages - but the only alternative would be converting to UCS-16 (Unicode) - (using a routine something like UniStrupr) then - uppercasing and then converting back from Unicode - which - would only worth doing it if we knew it were utf8. Basically - utf8 and other multibyte codepages each need their own strupper - function since a byte at a time will ont work. */ - - for (i = 0; i < CIFS_ENCPWD_SIZE; i++) - password_with_pad[i] = toupper(password_with_pad[i]); - - rc = SMBencrypt(password_with_pad, cryptkey, lnm_session_key); - - return rc; -} -#endif /* CIFS_WEAK_PW_HASH */ - /* Build a proper attribute value/target info pairs blob. * Fill in netbios and dns domain name and workstation name * and client time (total five av pairs and + one end of fields indicator. @@ -780,9 +699,9 @@ calc_seckey(struct cifs_ses *ses) return -ENOMEM; } - arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE); - arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key, - CIFS_CPHTXT_SIZE); + cifs_arc4_setkey(ctx_arc4, ses->auth_key.response, CIFS_SESS_KEY_SIZE); + cifs_arc4_crypt(ctx_arc4, ses->ntlmssp->ciphertext, sec_key, + CIFS_CPHTXT_SIZE); /* make secondary_key/nonce as session key */ memcpy(ses->auth_key.response, sec_key, CIFS_SESS_KEY_SIZE); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 64b71c4e2a9d..8c20bfa187ac 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -399,7 +399,6 @@ cifs_evict_inode(struct inode *inode) { truncate_inode_pages_final(&inode->i_data); clear_inode(inode); - cifs_fscache_release_inode_cookie(inode); } static void @@ -438,15 +437,9 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses) seq_puts(s, ",sec="); switch (ses->sectype) { - case LANMAN: - seq_puts(s, "lanman"); - break; case NTLMv2: seq_puts(s, "ntlmv2"); break; - case NTLM: - seq_puts(s, "ntlm"); - break; case Kerberos: seq_puts(s, "krb5"); break; @@ -1755,7 +1748,6 @@ MODULE_DESCRIPTION MODULE_VERSION(CIFS_VERSION); MODULE_SOFTDEP("ecb"); MODULE_SOFTDEP("hmac"); -MODULE_SOFTDEP("md4"); MODULE_SOFTDEP("md5"); MODULE_SOFTDEP("nls"); MODULE_SOFTDEP("aes"); diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index c0bfc2f01030..c068f7d8d879 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -114,8 +114,6 @@ enum statusEnum { enum securityEnum { Unspecified = 0, /* not specified */ - LANMAN, /* Legacy LANMAN auth */ - NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ Kerberos, /* Kerberos via SPNEGO */ @@ -634,7 +632,6 @@ struct TCP_Server_Info { struct session_key session_key; unsigned long lstrp; /* when we got last response from this server */ struct cifs_secmech secmech; /* crypto sec mech functs, descriptors */ -#define CIFS_NEGFLAVOR_LANMAN 0 /* wct == 13, LANMAN */ #define CIFS_NEGFLAVOR_UNENCAP 1 /* wct == 17, but no ext_sec */ #define CIFS_NEGFLAVOR_EXTENDED 2 /* wct == 17, ext_sec bit set */ char negflavor; /* NEGOTIATE response flavor */ @@ -1611,6 +1608,11 @@ struct dfs_info3_param { int ttl; }; +struct file_list { + struct list_head list; + struct cifsFileInfo *cfile; +}; + /* * common struct for holding inode info when searching for or updating an * inode with new info @@ -1729,16 +1731,8 @@ static inline bool is_retryable_error(int error) /* Security Flags: indicate type of session setup needed */ #define CIFSSEC_MAY_SIGN 0x00001 -#define CIFSSEC_MAY_NTLM 0x00002 #define CIFSSEC_MAY_NTLMV2 0x00004 #define CIFSSEC_MAY_KRB5 0x00008 -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFSSEC_MAY_LANMAN 0x00010 -#define CIFSSEC_MAY_PLNTXT 0x00020 -#else -#define CIFSSEC_MAY_LANMAN 0 -#define CIFSSEC_MAY_PLNTXT 0 -#endif /* weak passwords */ #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ #define CIFSSEC_MAY_NTLMSSP 0x00080 /* raw ntlmssp with ntlmv2 */ @@ -1746,32 +1740,19 @@ static inline bool is_retryable_error(int error) /* note that only one of the following can be set so the result of setting MUST flags more than once will be to require use of the stronger protocol */ -#define CIFSSEC_MUST_NTLM 0x02002 #define CIFSSEC_MUST_NTLMV2 0x04004 #define CIFSSEC_MUST_KRB5 0x08008 -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFSSEC_MUST_LANMAN 0x10010 -#define CIFSSEC_MUST_PLNTXT 0x20020 -#ifdef CONFIG_CIFS_UPCALL -#define CIFSSEC_MASK 0xBF0BF /* allows weak security but also krb5 */ -#else -#define CIFSSEC_MASK 0xB70B7 /* current flags supported if weak */ -#endif /* UPCALL */ -#else /* do not allow weak pw hash */ -#define CIFSSEC_MUST_LANMAN 0 -#define CIFSSEC_MUST_PLNTXT 0 #ifdef CONFIG_CIFS_UPCALL #define CIFSSEC_MASK 0x8F08F /* flags supported if no weak allowed */ #else #define CIFSSEC_MASK 0x87087 /* flags supported if no weak allowed */ #endif /* UPCALL */ -#endif /* WEAK_PW_HASH */ #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ #define CIFSSEC_MUST_NTLMSSP 0x80080 /* raw ntlmssp with ntlmv2 */ #define CIFSSEC_DEF (CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_NTLMSSP) -#define CIFSSEC_MAX (CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2) -#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) +#define CIFSSEC_MAX (CIFSSEC_MUST_NTLMV2) +#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_NTLMSSP) /* ***************************************************************** * All constants go here @@ -1935,10 +1916,6 @@ static inline char *get_security_type_str(enum securityEnum sectype) return "Kerberos"; case NTLMv2: return "NTLMv2"; - case NTLM: - return "NTLM"; - case LANMAN: - return "LANMAN"; default: return "Unknown"; } diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index f6e235001358..dc920e206336 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -14,13 +14,7 @@ #include <asm/unaligned.h> #include "smbfsctl.h" -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define LANMAN_PROT 0 -#define LANMAN2_PROT 1 -#define CIFS_PROT 2 -#else #define CIFS_PROT 0 -#endif #define POSIX_PROT (CIFS_PROT+1) #define BAD_PROT 0xFFFF @@ -505,30 +499,8 @@ typedef struct negotiate_req { unsigned char DialectsArray[1]; } __attribute__((packed)) NEGOTIATE_REQ; -/* Dialect index is 13 for LANMAN */ - #define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */ -typedef struct lanman_neg_rsp { - struct smb_hdr hdr; /* wct = 13 */ - __le16 DialectIndex; - __le16 SecurityMode; - __le16 MaxBufSize; - __le16 MaxMpxCount; - __le16 MaxNumberVcs; - __le16 RawMode; - __le32 SessionKey; - struct { - __le16 Time; - __le16 Date; - } __attribute__((packed)) SrvTime; - __le16 ServerTimeZone; - __le16 EncryptionKeyLength; - __le16 Reserved; - __u16 ByteCount; - unsigned char EncryptionKey[1]; -} __attribute__((packed)) LANMAN_NEG_RSP; - #define READ_RAW_ENABLE 1 #define WRITE_RAW_ENABLE 2 #define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index e0def0f0714b..f9740c21ca3d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -498,19 +498,12 @@ extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *, __u32 *); extern int cifs_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, __u32 expected_sequence_number); -extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *, - const struct nls_table *); -extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *); extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *); extern void cifs_crypto_secmech_release(struct TCP_Server_Info *server); extern int calc_seckey(struct cifs_ses *); extern int generate_smb30signingkey(struct cifs_ses *); extern int generate_smb311signingkey(struct cifs_ses *); -#ifdef CONFIG_CIFS_WEAK_PW_HASH -extern int calc_lanman_hash(const char *password, const char *cryptkey, - bool encrypt, char *lnm_session_key); -#endif /* CIFS_WEAK_PW_HASH */ extern int CIFSSMBCopy(unsigned int xid, struct cifs_tcon *source_tcon, const char *fromName, @@ -547,11 +540,8 @@ extern int check_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, const unsigned char *path); -extern int mdfour(unsigned char *, unsigned char *, int); extern int E_md4hash(const unsigned char *passwd, unsigned char *p16, const struct nls_table *codepage); -extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8, - unsigned char *p24); extern int cifs_setup_volume_info(struct smb3_fs_context *ctx, const char *mntopts, const char *devname); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 65d1a65bfc37..a8e41c1e80ca 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -42,10 +42,6 @@ static struct { int index; char *name; } protocols[] = { -#ifdef CONFIG_CIFS_WEAK_PW_HASH - {LANMAN_PROT, "\2LM1.2X002"}, - {LANMAN2_PROT, "\2LANMAN2.1"}, -#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {POSIX_PROT, "\2POSIX 2"}, {BAD_PROT, "\2"} @@ -55,10 +51,6 @@ static struct { int index; char *name; } protocols[] = { -#ifdef CONFIG_CIFS_WEAK_PW_HASH - {LANMAN_PROT, "\2LM1.2X002"}, - {LANMAN2_PROT, "\2LANMAN2.1"}, -#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {BAD_PROT, "\2"} }; @@ -66,17 +58,9 @@ static struct { /* define the number of elements in the cifs dialect array */ #ifdef CONFIG_CIFS_POSIX -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 4 -#else #define CIFS_NUM_PROT 2 -#endif /* CIFS_WEAK_PW_HASH */ #else /* not posix */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 3 -#else #define CIFS_NUM_PROT 1 -#endif /* CONFIG_CIFS_WEAK_PW_HASH */ #endif /* CIFS_POSIX */ /* @@ -475,89 +459,6 @@ cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) return 0; } -#ifdef CONFIG_CIFS_WEAK_PW_HASH -static int -decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) -{ - __s16 tmp; - struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; - - if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) - return -EOPNOTSUPP; - - server->sec_mode = le16_to_cpu(rsp->SecurityMode); - server->maxReq = min_t(unsigned int, - le16_to_cpu(rsp->MaxMpxCount), - cifs_max_pending); - set_credits(server, server->maxReq); - server->maxBuf = le16_to_cpu(rsp->MaxBufSize); - /* set up max_read for readpages check */ - server->max_read = server->maxBuf; - /* even though we do not use raw we might as well set this - accurately, in case we ever find a need for it */ - if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { - server->max_rw = 0xFF00; - server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; - } else { - server->max_rw = 0;/* do not need to use raw anyway */ - server->capabilities = CAP_MPX_MODE; - } - tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); - if (tmp == -1) { - /* OS/2 often does not set timezone therefore - * we must use server time to calc time zone. - * Could deviate slightly from the right zone. - * Smallest defined timezone difference is 15 minutes - * (i.e. Nepal). Rounding up/down is done to match - * this requirement. - */ - int val, seconds, remain, result; - struct timespec64 ts; - time64_t utc = ktime_get_real_seconds(); - ts = cnvrtDosUnixTm(rsp->SrvTime.Date, - rsp->SrvTime.Time, 0); - cifs_dbg(FYI, "SrvTime %lld sec since 1970 (utc: %lld) diff: %lld\n", - ts.tv_sec, utc, - utc - ts.tv_sec); - val = (int)(utc - ts.tv_sec); - seconds = abs(val); - result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; - remain = seconds % MIN_TZ_ADJ; - if (remain >= (MIN_TZ_ADJ / 2)) - result += MIN_TZ_ADJ; - if (val < 0) - result = -result; - server->timeAdj = result; - } else { - server->timeAdj = (int)tmp; - server->timeAdj *= 60; /* also in seconds */ - } - cifs_dbg(FYI, "server->timeAdj: %d seconds\n", server->timeAdj); - - - /* BB get server time for time conversions and add - code to use it and timezone since this is not UTC */ - - if (rsp->EncryptionKeyLength == - cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { - memcpy(server->cryptkey, rsp->EncryptionKey, - CIFS_CRYPTO_KEY_SIZE); - } else if (server->sec_mode & SECMODE_PW_ENCRYPT) { - return -EIO; /* need cryptkey unless plain text */ - } - - cifs_dbg(FYI, "LANMAN negotiated\n"); - return 0; -} -#else -static inline int -decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr) -{ - cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n"); - return -EOPNOTSUPP; -} -#endif - static bool should_set_ext_sec_flag(enum securityEnum sectype) { @@ -626,16 +527,12 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) server->dialect = le16_to_cpu(pSMBr->DialectIndex); cifs_dbg(FYI, "Dialect: %d\n", server->dialect); /* Check wct = 1 error case */ - if ((pSMBr->hdr.WordCount < 13) || (server->dialect == BAD_PROT)) { + if ((pSMBr->hdr.WordCount <= 13) || (server->dialect == BAD_PROT)) { /* core returns wct = 1, but we do not ask for core - otherwise small wct just comes when dialect index is -1 indicating we could not negotiate a common dialect */ rc = -EOPNOTSUPP; goto neg_err_exit; - } else if (pSMBr->hdr.WordCount == 13) { - server->negflavor = CIFS_NEGFLAVOR_LANMAN; - rc = decode_lanman_negprot_rsp(server, pSMBr); - goto signing_check; } else if (pSMBr->hdr.WordCount != 17) { /* unknown wct */ rc = -EOPNOTSUPP; @@ -677,7 +574,6 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses) server->capabilities &= ~CAP_EXTENDED_SECURITY; } -signing_check: if (!rc) rc = cifs_enable_signing(server, ses->sign); neg_err_exit: @@ -2101,6 +1997,7 @@ cifs_writev_complete(struct work_struct *work) else if (wdata->result < 0) SetPageError(page); end_page_writeback(page); + cifs_readpage_to_fscache(inode, page); put_page(page); } if (wdata->result != -EAGAIN) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3781eee9360a..0db344807ef1 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3684,38 +3684,6 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, *bcc_ptr = 0; /* password is null byte */ bcc_ptr++; /* skip password */ /* already aligned so no need to do it below */ - } else { - pSMB->PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); - /* BB FIXME add code to fail this if NTLMv2 or Kerberos - specified as required (when that support is added to - the vfs in the future) as only NTLM or the much - weaker LANMAN (which we do not send by default) is accepted - by Samba (not sure whether other servers allow - NTLMv2 password here) */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((global_secflags & CIFSSEC_MAY_LANMAN) && - (ses->sectype == LANMAN)) - calc_lanman_hash(tcon->password, ses->server->cryptkey, - ses->server->sec_mode & - SECMODE_PW_ENCRYPT ? true : false, - bcc_ptr); - else -#endif /* CIFS_WEAK_PW_HASH */ - rc = SMBNTencrypt(tcon->password, ses->server->cryptkey, - bcc_ptr, nls_codepage); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NTLM rsp. Error: %d\n", - __func__, rc); - cifs_buf_release(smb_buffer); - return rc; - } - - bcc_ptr += CIFS_AUTH_RESP_SIZE; - if (ses->capabilities & CAP_UNICODE) { - /* must align unicode strings */ - *bcc_ptr = 0; /* null byte password */ - bcc_ptr++; - } } if (ses->server->sign) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 79402ca0ddfa..5f8a302ffcb2 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -100,7 +100,7 @@ build_path_from_dentry_optional_prefix(struct dentry *direntry, void *page, if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_USE_PREFIX_PATH) pplen = cifs_sb->prepath ? strlen(cifs_sb->prepath) + 1 : 0; - s = dentry_path_raw(direntry, page, PAGE_SIZE); + s = dentry_path_raw(direntry, page, PATH_MAX); if (IS_ERR(s)) return s; if (!s[1]) // for root we want "", not "/" diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 0a72840a88f1..d0216472f1c6 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -377,6 +377,8 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file) struct cifsLockInfo *li, *tmp; struct super_block *sb = inode->i_sb; + cifs_fscache_release_inode_cookie(inode); + /* * Delete any outstanding lock records. We'll lose them when the file * is closed anyway. @@ -882,8 +884,10 @@ int cifs_close(struct inode *inode, struct file *file) if ((cinode->oplock == CIFS_CACHE_RHW_FLG) && cinode->lease_granted && dclose) { - if (test_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) + if (test_bit(CIFS_INO_MODIFIED_ATTR, &cinode->flags)) { inode->i_ctime = inode->i_mtime = current_time(inode); + cifs_fscache_update_inode_cookie(inode); + } spin_lock(&cinode->deferred_lock); cifs_add_deferred_close(cfile, dclose); if (cfile->deferred_close_scheduled && @@ -4170,6 +4174,10 @@ static vm_fault_t cifs_page_mkwrite(struct vm_fault *vmf) { struct page *page = vmf->page; + struct file *file = vmf->vma->vm_file; + struct inode *inode = file_inode(file); + + cifs_fscache_wait_on_page_write(inode, page); lock_page(page); return VM_FAULT_LOCKED; @@ -4235,13 +4243,16 @@ cifs_readv_complete(struct work_struct *work) (rdata->result == -EAGAIN && got_bytes)) { flush_dcache_page(page); SetPageUptodate(page); - } + } else + SetPageError(page); unlock_page(page); if (rdata->result == 0 || (rdata->result == -EAGAIN && got_bytes)) cifs_readpage_to_fscache(rdata->mapping->host, page); + else + cifs_fscache_uncache_page(rdata->mapping->host, page); got_bytes -= min_t(unsigned int, PAGE_SIZE, got_bytes); @@ -4848,34 +4859,33 @@ void cifs_oplock_break(struct work_struct *work) oplock_break_ack: /* - * releasing stale oplock after recent reconnect of smb session using - * a now incorrect file handle is not a data integrity issue but do - * not bother sending an oplock release if session to server still is - * disconnected since oplock already released by the server - */ - if (!cfile->oplock_break_cancelled) { - rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid, - cinode); - cifs_dbg(FYI, "Oplock release rc = %d\n", rc); - } - /* * When oplock break is received and there are no active * file handles but cached, then schedule deferred close immediately. * So, new open will not use cached handle. */ spin_lock(&CIFS_I(inode)->deferred_lock); is_deferred = cifs_is_deferred_close(cfile, &dclose); + spin_unlock(&CIFS_I(inode)->deferred_lock); if (is_deferred && cfile->deferred_close_scheduled && delayed_work_pending(&cfile->deferred)) { - /* - * If there is no pending work, mod_delayed_work queues new work. - * So, Increase the ref count to avoid use-after-free. - */ - if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0)) - cifsFileInfo_get(cfile); + if (cancel_delayed_work(&cfile->deferred)) { + _cifsFileInfo_put(cfile, false, false); + goto oplock_break_done; + } } - spin_unlock(&CIFS_I(inode)->deferred_lock); + /* + * releasing stale oplock after recent reconnect of smb session using + * a now incorrect file handle is not a data integrity issue but do + * not bother sending an oplock release if session to server still is + * disconnected since oplock already released by the server + */ + if (!cfile->oplock_break_cancelled) { + rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid, + cinode); + cifs_dbg(FYI, "Oplock release rc = %d\n", rc); + } +oplock_break_done: _cifsFileInfo_put(cfile, false /* do not wait for ourself */, false); cifs_done_oplock_break(cinode); } diff --git a/fs/cifs/fs_context.c b/fs/cifs/fs_context.c index eed59bc1d913..3109def8e199 100644 --- a/fs/cifs/fs_context.c +++ b/fs/cifs/fs_context.c @@ -57,12 +57,9 @@ static const match_table_t cifs_secflavor_tokens = { { Opt_sec_krb5p, "krb5p" }, { Opt_sec_ntlmsspi, "ntlmsspi" }, { Opt_sec_ntlmssp, "ntlmssp" }, - { Opt_ntlm, "ntlm" }, - { Opt_sec_ntlmi, "ntlmi" }, { Opt_sec_ntlmv2, "nontlm" }, { Opt_sec_ntlmv2, "ntlmv2" }, { Opt_sec_ntlmv2i, "ntlmv2i" }, - { Opt_sec_lanman, "lanman" }, { Opt_sec_none, "none" }, { Opt_sec_err, NULL } @@ -221,23 +218,12 @@ cifs_parse_security_flavors(struct fs_context *fc, char *value, struct smb3_fs_c case Opt_sec_ntlmssp: ctx->sectype = RawNTLMSSP; break; - case Opt_sec_ntlmi: - ctx->sign = true; - fallthrough; - case Opt_ntlm: - ctx->sectype = NTLM; - break; case Opt_sec_ntlmv2i: ctx->sign = true; fallthrough; case Opt_sec_ntlmv2: ctx->sectype = NTLMv2; break; -#ifdef CONFIG_CIFS_WEAK_PW_HASH - case Opt_sec_lanman: - ctx->sectype = LANMAN; - break; -#endif case Opt_sec_none: ctx->nullauth = 1; break; @@ -1266,10 +1252,17 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, ctx->posix_paths = 1; break; case Opt_unix: - if (result.negated) + if (result.negated) { + if (ctx->linux_ext == 1) + pr_warn_once("conflicting posix mount options specified\n"); ctx->linux_ext = 0; - else ctx->no_linux_ext = 1; + } else { + if (ctx->no_linux_ext == 1) + pr_warn_once("conflicting posix mount options specified\n"); + ctx->linux_ext = 1; + ctx->no_linux_ext = 0; + } break; case Opt_nocase: ctx->nocase = 1; diff --git a/fs/cifs/fs_context.h b/fs/cifs/fs_context.h index b6243972edf3..a42ba71d7a81 100644 --- a/fs/cifs/fs_context.h +++ b/fs/cifs/fs_context.h @@ -47,11 +47,8 @@ enum cifs_sec_param { Opt_sec_krb5p, Opt_sec_ntlmsspi, Opt_sec_ntlmssp, - Opt_ntlm, - Opt_sec_ntlmi, Opt_sec_ntlmv2, Opt_sec_ntlmv2i, - Opt_sec_lanman, Opt_sec_none, Opt_sec_err diff --git a/fs/cifs/fscache.c b/fs/cifs/fscache.c index dd625033cd6b..fab47fa7df74 100644 --- a/fs/cifs/fscache.c +++ b/fs/cifs/fscache.c @@ -176,29 +176,34 @@ void cifs_fscache_release_inode_cookie(struct inode *inode) auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec; cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); + /* fscache_relinquish_cookie does not seem to update auxdata */ + fscache_update_cookie(cifsi->fscache, &auxdata); fscache_relinquish_cookie(cifsi->fscache, &auxdata, false); cifsi->fscache = NULL; } } -static void cifs_fscache_disable_inode_cookie(struct inode *inode) +void cifs_fscache_update_inode_cookie(struct inode *inode) { + struct cifs_fscache_inode_auxdata auxdata; struct cifsInodeInfo *cifsi = CIFS_I(inode); if (cifsi->fscache) { + memset(&auxdata, 0, sizeof(auxdata)); + auxdata.eof = cifsi->server_eof; + auxdata.last_write_time_sec = cifsi->vfs_inode.i_mtime.tv_sec; + auxdata.last_change_time_sec = cifsi->vfs_inode.i_ctime.tv_sec; + auxdata.last_write_time_nsec = cifsi->vfs_inode.i_mtime.tv_nsec; + auxdata.last_change_time_nsec = cifsi->vfs_inode.i_ctime.tv_nsec; + cifs_dbg(FYI, "%s: (0x%p)\n", __func__, cifsi->fscache); - fscache_uncache_all_inode_pages(cifsi->fscache, inode); - fscache_relinquish_cookie(cifsi->fscache, NULL, true); - cifsi->fscache = NULL; + fscache_update_cookie(cifsi->fscache, &auxdata); } } void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) { - if ((filp->f_flags & O_ACCMODE) != O_RDONLY) - cifs_fscache_disable_inode_cookie(inode); - else - cifs_fscache_enable_inode_cookie(inode); + cifs_fscache_enable_inode_cookie(inode); } void cifs_fscache_reset_inode_cookie(struct inode *inode) @@ -310,6 +315,8 @@ void __cifs_readpage_to_fscache(struct inode *inode, struct page *page) struct cifsInodeInfo *cifsi = CIFS_I(inode); int ret; + WARN_ON(!cifsi->fscache); + cifs_dbg(FYI, "%s: (fsc: %p, p: %p, i: %p)\n", __func__, cifsi->fscache, page, inode); ret = fscache_write_page(cifsi->fscache, page, @@ -334,3 +341,21 @@ void __cifs_fscache_invalidate_page(struct page *page, struct inode *inode) fscache_wait_on_page_write(cookie, page); fscache_uncache_page(cookie, page); } + +void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page) +{ + struct cifsInodeInfo *cifsi = CIFS_I(inode); + struct fscache_cookie *cookie = cifsi->fscache; + + cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie); + fscache_wait_on_page_write(cookie, page); +} + +void __cifs_fscache_uncache_page(struct inode *inode, struct page *page) +{ + struct cifsInodeInfo *cifsi = CIFS_I(inode); + struct fscache_cookie *cookie = cifsi->fscache; + + cifs_dbg(FYI, "%s: (0x%p/0x%p)\n", __func__, page, cookie); + fscache_uncache_page(cookie, page); +} diff --git a/fs/cifs/fscache.h b/fs/cifs/fscache.h index 3d55cb2ef055..82e856b9cf89 100644 --- a/fs/cifs/fscache.h +++ b/fs/cifs/fscache.h @@ -55,10 +55,13 @@ extern void cifs_fscache_get_super_cookie(struct cifs_tcon *); extern void cifs_fscache_release_super_cookie(struct cifs_tcon *); extern void cifs_fscache_release_inode_cookie(struct inode *); +extern void cifs_fscache_update_inode_cookie(struct inode *inode); extern void cifs_fscache_set_inode_cookie(struct inode *, struct file *); extern void cifs_fscache_reset_inode_cookie(struct inode *); extern void __cifs_fscache_invalidate_page(struct page *, struct inode *); +extern void __cifs_fscache_wait_on_page_write(struct inode *inode, struct page *page); +extern void __cifs_fscache_uncache_page(struct inode *inode, struct page *page); extern int cifs_fscache_release_page(struct page *page, gfp_t gfp); extern int __cifs_readpage_from_fscache(struct inode *, struct page *); extern int __cifs_readpages_from_fscache(struct inode *, @@ -76,6 +79,20 @@ static inline void cifs_fscache_invalidate_page(struct page *page, __cifs_fscache_invalidate_page(page, inode); } +static inline void cifs_fscache_wait_on_page_write(struct inode *inode, + struct page *page) +{ + if (PageFsCache(page)) + __cifs_fscache_wait_on_page_write(inode, page); +} + +static inline void cifs_fscache_uncache_page(struct inode *inode, + struct page *page) +{ + if (PageFsCache(page)) + __cifs_fscache_uncache_page(inode, page); +} + static inline int cifs_readpage_from_fscache(struct inode *inode, struct page *page) { @@ -123,6 +140,7 @@ static inline void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon) {} static inline void cifs_fscache_release_inode_cookie(struct inode *inode) {} +static inline void cifs_fscache_update_inode_cookie(struct inode *inode) {} static inline void cifs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) {} static inline void cifs_fscache_reset_inode_cookie(struct inode *inode) {} @@ -133,6 +151,11 @@ static inline int cifs_fscache_release_page(struct page *page, gfp_t gfp) static inline void cifs_fscache_invalidate_page(struct page *page, struct inode *inode) {} +static inline void cifs_fscache_wait_on_page_write(struct inode *inode, + struct page *page) {} +static inline void cifs_fscache_uncache_page(struct inode *inode, + struct page *page) {} + static inline int cifs_readpage_from_fscache(struct inode *inode, struct page *page) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index b96b253e7635..50c01cff4c84 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1625,7 +1625,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) goto unlink_out; } - cifs_close_all_deferred_files(tcon); + cifs_close_deferred_file(CIFS_I(inode)); if (cap_unix(tcon->ses) && (CIFS_UNIX_POSIX_PATH_OPS_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))) { rc = CIFSPOSIXDelFile(xid, tcon, full_path, @@ -2084,6 +2084,7 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir, FILE_UNIX_BASIC_INFO *info_buf_target; unsigned int xid; int rc, tmprc; + int retry_count = 0; if (flags & ~RENAME_NOREPLACE) return -EINVAL; @@ -2113,10 +2114,24 @@ cifs_rename2(struct user_namespace *mnt_userns, struct inode *source_dir, goto cifs_rename_exit; } - cifs_close_all_deferred_files(tcon); + cifs_close_deferred_file(CIFS_I(d_inode(source_dentry))); + if (d_inode(target_dentry) != NULL) + cifs_close_deferred_file(CIFS_I(d_inode(target_dentry))); + rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, to_name); + if (rc == -EACCES) { + while (retry_count < 3) { + cifs_close_all_deferred_files(tcon); + rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry, + to_name); + if (rc != -EACCES) + break; + retry_count++; + } + } + /* * No-replace is the natural behavior for CIFS, so skip unlink hacks. */ @@ -2282,6 +2297,7 @@ cifs_revalidate_mapping(struct inode *inode) { int rc; unsigned long *flags = &CIFS_I(inode)->flags; + struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); /* swapfiles are not supposed to be shared */ if (IS_SWAPFILE(inode)) @@ -2293,11 +2309,16 @@ cifs_revalidate_mapping(struct inode *inode) return rc; if (test_and_clear_bit(CIFS_INO_INVALID_MAPPING, flags)) { + /* for cache=singleclient, do not invalidate */ + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE) + goto skip_invalidate; + rc = cifs_invalidate_mapping(inode); if (rc) set_bit(CIFS_INO_INVALID_MAPPING, flags); } +skip_invalidate: clear_bit_unlock(CIFS_INO_LOCK, flags); smp_mb__after_atomic(); wake_up_bit(flags, CIFS_INO_LOCK); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 844abeb2b48f..9469f1cf0b46 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -723,13 +723,31 @@ void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode) { struct cifsFileInfo *cfile = NULL; - struct cifs_deferred_close *dclose; + struct file_list *tmp_list, *tmp_next_list; + struct list_head file_head; + + if (cifs_inode == NULL) + return; + INIT_LIST_HEAD(&file_head); + spin_lock(&cifs_inode->open_file_lock); list_for_each_entry(cfile, &cifs_inode->openFileList, flist) { - spin_lock(&cifs_inode->deferred_lock); - if (cifs_is_deferred_close(cfile, &dclose)) - mod_delayed_work(deferredclose_wq, &cfile->deferred, 0); - spin_unlock(&cifs_inode->deferred_lock); + if (delayed_work_pending(&cfile->deferred)) { + if (cancel_delayed_work(&cfile->deferred)) { + tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC); + if (tmp_list == NULL) + continue; + tmp_list->cfile = cfile; + list_add_tail(&tmp_list->list, &file_head); + } + } + } + spin_unlock(&cifs_inode->open_file_lock); + + list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) { + _cifsFileInfo_put(tmp_list->cfile, true, false); + list_del(&tmp_list->list); + kfree(tmp_list); } } @@ -738,20 +756,30 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon) { struct cifsFileInfo *cfile; struct list_head *tmp; + struct file_list *tmp_list, *tmp_next_list; + struct list_head file_head; + INIT_LIST_HEAD(&file_head); spin_lock(&tcon->open_file_lock); list_for_each(tmp, &tcon->openFileList) { cfile = list_entry(tmp, struct cifsFileInfo, tlist); if (delayed_work_pending(&cfile->deferred)) { - /* - * If there is no pending work, mod_delayed_work queues new work. - * So, Increase the ref count to avoid use-after-free. - */ - if (!mod_delayed_work(deferredclose_wq, &cfile->deferred, 0)) - cifsFileInfo_get(cfile); + if (cancel_delayed_work(&cfile->deferred)) { + tmp_list = kmalloc(sizeof(struct file_list), GFP_ATOMIC); + if (tmp_list == NULL) + continue; + tmp_list->cfile = cfile; + list_add_tail(&tmp_list->list, &file_head); + } } } spin_unlock(&tcon->open_file_lock); + + list_for_each_entry_safe(tmp_list, tmp_next_list, &file_head, list) { + _cifsFileInfo_put(tmp_list->cfile, true, false); + list_del(&tmp_list->list); + kfree(tmp_list); + } } /* parses DFS refferal V3 structure diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index bfee176b901d..54d77c99e21c 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -369,7 +369,7 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb, */ static int -initiate_cifs_search(const unsigned int xid, struct file *file, +_initiate_cifs_search(const unsigned int xid, struct file *file, const char *full_path) { __u16 search_flags; @@ -451,6 +451,27 @@ error_exit: return rc; } +static int +initiate_cifs_search(const unsigned int xid, struct file *file, + const char *full_path) +{ + int rc, retry_count = 0; + + do { + rc = _initiate_cifs_search(xid, file, full_path); + /* + * If we don't have enough credits to start reading the + * directory just try again after short wait. + */ + if (rc != -EDEADLK) + break; + + usleep_range(512, 2048); + } while (retry_count++ < 5); + + return rc; +} + /* return length of unicode string in bytes */ static int cifs_unicode_bytelen(const char *str) { diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c5785fd3f52e..118403fbeda2 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -799,30 +799,16 @@ cifs_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested) } case CIFS_NEGFLAVOR_UNENCAP: switch (requested) { - case NTLM: case NTLMv2: return requested; case Unspecified: if (global_secflags & CIFSSEC_MAY_NTLMV2) return NTLMv2; - if (global_secflags & CIFSSEC_MAY_NTLM) - return NTLM; break; default: break; } - fallthrough; /* to attempt LANMAN authentication next */ - case CIFS_NEGFLAVOR_LANMAN: - switch (requested) { - case LANMAN: - return requested; - case Unspecified: - if (global_secflags & CIFSSEC_MAY_LANMAN) - return LANMAN; - fallthrough; - default: - return Unspecified; - } + fallthrough; default: return Unspecified; } @@ -877,7 +863,7 @@ sess_alloc_buffer(struct sess_data *sess_data, int wct) return 0; out_free_smb_buf: - kfree(smb_buf); + cifs_small_buf_release(smb_buf); sess_data->iov[0].iov_base = NULL; sess_data->iov[0].iov_len = 0; sess_data->buf0_type = CIFS_NO_BUFFER; @@ -947,230 +933,6 @@ sess_sendreceive(struct sess_data *sess_data) return rc; } -/* - * LANMAN and plaintext are less secure and off by default. - * So we make this explicitly be turned on in kconfig (in the - * build) and turned on at runtime (changed from the default) - * in proc/fs/cifs or via mount parm. Unfortunately this is - * needed for old Win (e.g. Win95), some obscure NAS and OS/2 - */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH -static void -sess_auth_lanman(struct sess_data *sess_data) -{ - int rc = 0; - struct smb_hdr *smb_buf; - SESSION_SETUP_ANDX *pSMB; - char *bcc_ptr; - struct cifs_ses *ses = sess_data->ses; - char lnm_session_key[CIFS_AUTH_RESP_SIZE]; - __u16 bytes_remaining; - - /* lanman 2 style sessionsetup */ - /* wct = 10 */ - rc = sess_alloc_buffer(sess_data, 10); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - bcc_ptr = sess_data->iov[2].iov_base; - (void)cifs_ssetup_hdr(ses, pSMB); - - pSMB->req.hdr.Flags2 &= ~SMBFLG2_UNICODE; - - if (ses->user_name != NULL) { - /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_AUTH_RESP_SIZE); - - /* Calculate hash with password and copy into bcc_ptr. - * Encryption Key (stored as in cryptkey) gets used if the - * security mode bit in Negotiate Protocol response states - * to use challenge/response method (i.e. Password bit is 1). - */ - rc = calc_lanman_hash(ses->password, ses->server->cryptkey, - ses->server->sec_mode & SECMODE_PW_ENCRYPT ? - true : false, lnm_session_key); - if (rc) - goto out; - - memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_AUTH_RESP_SIZE); - bcc_ptr += CIFS_AUTH_RESP_SIZE; - } else { - pSMB->old_req.PasswordLength = 0; - } - - /* - * can not sign if LANMAN negotiated so no need - * to calculate signing key? but what if server - * changed to do higher than lanman dialect and - * we reconnected would we ever calc signing_key? - */ - - cifs_dbg(FYI, "Negotiating LANMAN setting up strings\n"); - /* Unicode not allowed for LANMAN dialects */ - ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); - - sess_data->iov[2].iov_len = (long) bcc_ptr - - (long) sess_data->iov[2].iov_base; - - rc = sess_sendreceive(sess_data); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; - - /* lanman response has a word count of 3 */ - if (smb_buf->WordCount != 3) { - rc = -EIO; - cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); - goto out; - } - - if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) - cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ - - ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ - cifs_dbg(FYI, "UID = %llu\n", ses->Suid); - - bytes_remaining = get_bcc(smb_buf); - bcc_ptr = pByteArea(smb_buf); - - /* BB check if Unicode and decode strings */ - if (bytes_remaining == 0) { - /* no string area to decode, do nothing */ - } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { - /* unicode string area must be word-aligned */ - if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { - ++bcc_ptr; - --bytes_remaining; - } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } - - rc = sess_establish_session(sess_data); -out: - sess_data->result = rc; - sess_data->func = NULL; - sess_free_buffer(sess_data); -} - -#endif - -static void -sess_auth_ntlm(struct sess_data *sess_data) -{ - int rc = 0; - struct smb_hdr *smb_buf; - SESSION_SETUP_ANDX *pSMB; - char *bcc_ptr; - struct cifs_ses *ses = sess_data->ses; - __u32 capabilities; - __u16 bytes_remaining; - - /* old style NTLM sessionsetup */ - /* wct = 13 */ - rc = sess_alloc_buffer(sess_data, 13); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - bcc_ptr = sess_data->iov[2].iov_base; - capabilities = cifs_ssetup_hdr(ses, pSMB); - - pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); - if (ses->user_name != NULL) { - pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_AUTH_RESP_SIZE); - pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_AUTH_RESP_SIZE); - - /* calculate ntlm response and session key */ - rc = setup_ntlm_response(ses, sess_data->nls_cp); - if (rc) { - cifs_dbg(VFS, "Error %d during NTLM authentication\n", - rc); - goto out; - } - - /* copy ntlm response */ - memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, - CIFS_AUTH_RESP_SIZE); - bcc_ptr += CIFS_AUTH_RESP_SIZE; - memcpy(bcc_ptr, ses->auth_key.response + CIFS_SESS_KEY_SIZE, - CIFS_AUTH_RESP_SIZE); - bcc_ptr += CIFS_AUTH_RESP_SIZE; - } else { - pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; - pSMB->req_no_secext.CaseSensitivePasswordLength = 0; - } - - if (ses->capabilities & CAP_UNICODE) { - /* unicode strings must be word aligned */ - if (sess_data->iov[0].iov_len % 2) { - *bcc_ptr = 0; - bcc_ptr++; - } - unicode_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); - } else { - ascii_ssetup_strings(&bcc_ptr, ses, sess_data->nls_cp); - } - - - sess_data->iov[2].iov_len = (long) bcc_ptr - - (long) sess_data->iov[2].iov_base; - - rc = sess_sendreceive(sess_data); - if (rc) - goto out; - - pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; - smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base; - - if (smb_buf->WordCount != 3) { - rc = -EIO; - cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount); - goto out; - } - - if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN) - cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */ - - ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ - cifs_dbg(FYI, "UID = %llu\n", ses->Suid); - - bytes_remaining = get_bcc(smb_buf); - bcc_ptr = pByteArea(smb_buf); - - /* BB check if Unicode and decode strings */ - if (bytes_remaining == 0) { - /* no string area to decode, do nothing */ - } else if (smb_buf->Flags2 & SMBFLG2_UNICODE) { - /* unicode string area must be word-aligned */ - if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) { - ++bcc_ptr; - --bytes_remaining; - } - decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } else { - decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, - sess_data->nls_cp); - } - - rc = sess_establish_session(sess_data); -out: - sess_data->result = rc; - sess_data->func = NULL; - sess_free_buffer(sess_data); - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; -} - static void sess_auth_ntlmv2(struct sess_data *sess_data) { @@ -1675,21 +1437,6 @@ static int select_sec(struct cifs_ses *ses, struct sess_data *sess_data) } switch (type) { - case LANMAN: - /* LANMAN and plaintext are less secure and off by default. - * So we make this explicitly be turned on in kconfig (in the - * build) and turned on at runtime (changed from the default) - * in proc/fs/cifs or via mount parm. Unfortunately this is - * needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ -#ifdef CONFIG_CIFS_WEAK_PW_HASH - sess_data->func = sess_auth_lanman; - break; -#else - return -EOPNOTSUPP; -#endif - case NTLM: - sess_data->func = sess_auth_ntlm; - break; case NTLMv2: sess_data->func = sess_auth_ntlmv2; break; diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c index cea39bcecbab..181514b8770d 100644 --- a/fs/cifs/smb2maperror.c +++ b/fs/cifs/smb2maperror.c @@ -1,6 +1,5 @@ // SPDX-License-Identifier: LGPL-2.1 /* - * fs/smb2/smb2maperror.c * * Functions which do error mapping of SMB2 status codes to POSIX errors * diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 2dfd0d8297eb..ddc0e8f97872 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3590,6 +3590,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, return rc; } + filemap_invalidate_lock(inode->i_mapping); /* * We implement the punch hole through ioctl, so we need remove the page * caches first, otherwise the data may be inconsistent with the server. @@ -3607,6 +3608,7 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, sizeof(struct file_zero_data_information), CIFSMaxBufSize, NULL, NULL); free_xid(xid); + filemap_invalidate_unlock(inode->i_mapping); return rc; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 781d14e5f2af..b6d2e3591927 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2426,7 +2426,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len) memcpy(aclptr, &acl, sizeof(struct cifs_acl)); buf->ccontext.DataLength = cpu_to_le32(ptr - (__u8 *)&buf->sd); - *len = ptr - (__u8 *)buf; + *len = roundup(ptr - (__u8 *)buf, 8); return buf; } diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 39a938443e3e..10047cc55286 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -18,13 +18,13 @@ #include <linux/string.h> #include <linux/kernel.h> #include <linux/random.h> -#include <crypto/des.h> #include "cifs_fs_sb.h" #include "cifs_unicode.h" #include "cifspdu.h" #include "cifsglob.h" #include "cifs_debug.h" #include "cifsproto.h" +#include "../cifs_common/md4.h" #ifndef false #define false 0 @@ -38,126 +38,29 @@ #define SSVALX(buf,pos,val) (CVAL(buf,pos)=(val)&0xFF,CVAL(buf,pos+1)=(val)>>8) #define SSVAL(buf,pos,val) SSVALX((buf),(pos),((__u16)(val))) -static void -str_to_key(unsigned char *str, unsigned char *key) -{ - int i; - - key[0] = str[0] >> 1; - key[1] = ((str[0] & 0x01) << 6) | (str[1] >> 2); - key[2] = ((str[1] & 0x03) << 5) | (str[2] >> 3); - key[3] = ((str[2] & 0x07) << 4) | (str[3] >> 4); - key[4] = ((str[3] & 0x0F) << 3) | (str[4] >> 5); - key[5] = ((str[4] & 0x1F) << 2) | (str[5] >> 6); - key[6] = ((str[5] & 0x3F) << 1) | (str[6] >> 7); - key[7] = str[6] & 0x7F; - for (i = 0; i < 8; i++) - key[i] = (key[i] << 1); -} - -static int -smbhash(unsigned char *out, const unsigned char *in, unsigned char *key) -{ - unsigned char key2[8]; - struct des_ctx ctx; - - str_to_key(key, key2); - - if (fips_enabled) { - cifs_dbg(VFS, "FIPS compliance enabled: DES not permitted\n"); - return -ENOENT; - } - - des_expand_key(&ctx, key2, DES_KEY_SIZE); - des_encrypt(&ctx, out, in); - memzero_explicit(&ctx, sizeof(ctx)); - - return 0; -} - -static int -E_P16(unsigned char *p14, unsigned char *p16) -{ - int rc; - unsigned char sp8[8] = - { 0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; - - rc = smbhash(p16, sp8, p14); - if (rc) - return rc; - rc = smbhash(p16 + 8, sp8, p14 + 7); - return rc; -} - -static int -E_P24(unsigned char *p21, const unsigned char *c8, unsigned char *p24) -{ - int rc; - - rc = smbhash(p24, c8, p21); - if (rc) - return rc; - rc = smbhash(p24 + 8, c8, p21 + 7); - if (rc) - return rc; - rc = smbhash(p24 + 16, c8, p21 + 14); - return rc; -} - /* produce a md4 message digest from data of length n bytes */ -int +static int mdfour(unsigned char *md4_hash, unsigned char *link_str, int link_len) { int rc; - struct crypto_shash *md4 = NULL; - struct sdesc *sdescmd4 = NULL; - - rc = cifs_alloc_hash("md4", &md4, &sdescmd4); - if (rc) - goto mdfour_err; + struct md4_ctx mctx; - rc = crypto_shash_init(&sdescmd4->shash); + rc = cifs_md4_init(&mctx); if (rc) { - cifs_dbg(VFS, "%s: Could not init md4 shash\n", __func__); + cifs_dbg(VFS, "%s: Could not init MD4\n", __func__); goto mdfour_err; } - rc = crypto_shash_update(&sdescmd4->shash, link_str, link_len); + rc = cifs_md4_update(&mctx, link_str, link_len); if (rc) { - cifs_dbg(VFS, "%s: Could not update with link_str\n", __func__); + cifs_dbg(VFS, "%s: Could not update MD4\n", __func__); goto mdfour_err; } - rc = crypto_shash_final(&sdescmd4->shash, md4_hash); + rc = cifs_md4_final(&mctx, md4_hash); if (rc) - cifs_dbg(VFS, "%s: Could not generate md4 hash\n", __func__); - -mdfour_err: - cifs_free_hash(&md4, &sdescmd4); - return rc; -} - -/* - This implements the X/Open SMB password encryption - It takes a password, a 8 byte "crypt key" and puts 24 bytes of - encrypted password into p24 */ -/* Note that password must be uppercased and null terminated */ -int -SMBencrypt(unsigned char *passwd, const unsigned char *c8, unsigned char *p24) -{ - int rc; - unsigned char p14[14], p16[16], p21[21]; + cifs_dbg(VFS, "%s: Could not finalize MD4\n", __func__); - memset(p14, '\0', 14); - memset(p16, '\0', 16); - memset(p21, '\0', 21); - - memcpy(p14, passwd, 14); - rc = E_P16(p14, p16); - if (rc) - return rc; - - memcpy(p21, p16, 16); - rc = E_P24(p21, c8, p24); +mdfour_err: return rc; } @@ -186,25 +89,3 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16, return rc; } - -/* Does the NT MD4 hash then des encryption. */ -int -SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24, - const struct nls_table *codepage) -{ - int rc; - unsigned char p16[16], p21[21]; - - memset(p16, '\0', 16); - memset(p21, '\0', 21); - - rc = E_md4hash(passwd, p16, codepage); - if (rc) { - cifs_dbg(FYI, "%s Can't generate NT hash, error: %d\n", - __func__, rc); - return rc; - } - memcpy(p21, p16, 16); - rc = E_P24(p21, c8, p24); - return rc; -} |