From patchwork Sat Apr 24 11:57:50 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 50895 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.samba.org (fn.samba.org [216.83.154.106]) by ozlabs.org (Postfix) with ESMTP id 82E57B7D1B for ; Sat, 24 Apr 2010 21:58:20 +1000 (EST) Received: from fn.samba.org (localhost [127.0.0.1]) by lists.samba.org (Postfix) with ESMTP id D3FD6AD218; Sat, 24 Apr 2010 05:58:22 -0600 (MDT) X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on fn.samba.org X-Spam-Level: X-Spam-Status: No, score=-3.4 required=3.8 tests=AWL, BAYES_00, NO_MORE_FUNN, SPF_PASS autolearn=no version=3.2.5 X-Original-To: linux-cifs-client@lists.samba.org Delivered-To: linux-cifs-client@lists.samba.org Received: from cdptpa-omtalb.mail.rr.com (cdptpa-omtalb.mail.rr.com [75.180.132.122]) by lists.samba.org (Postfix) with ESMTP id 851F8AD218 for ; Sat, 24 Apr 2010 05:57:57 -0600 (MDT) X-Authority-Analysis: v=1.1 cv=ozfpW0B87ixv+y7a1W07/YoomWMeieABhgxoD9XXnPM= c=1 sm=0 a=P-LAC25ueGMA:10 a=ld/erqUjW76FpBUqCqkKeA==:17 a=20KFwNOVAAAA:8 a=YT_rQbkYHrKZCTn14a0A:9 a=_ynH1HJV8R0qvv25dDgA:7 a=TzzxISTOzeBJWIk2dlSzbNjJhckA:4 a=jEp0ucaQiEUA:10 a=3_XypHtRLHJfxLvA:21 a=547eE3qmiUf0Rz1N:21 a=ld/erqUjW76FpBUqCqkKeA==:117 X-Cloudmark-Score: 0 X-Originating-IP: 71.70.153.3 Received: from [71.70.153.3] ([71.70.153.3:37879] helo=mail.poochiereds.net) by cdptpa-oedge01.mail.rr.com (envelope-from ) (ecelerity 2.2.2.39 r()) with ESMTP id 5E/4C-25246-1CCD2DB4; Sat, 24 Apr 2010 11:57:54 +0000 Received: by mail.poochiereds.net (Postfix, from userid 4447) id 17FFE5809D; Sat, 24 Apr 2010 07:57:53 -0400 (EDT) From: Jeff Layton To: smfrench@gmail.com Date: Sat, 24 Apr 2010 07:57:50 -0400 Message-Id: <1272110272-20686-10-git-send-email-jlayton@redhat.com> X-Mailer: git-send-email 1.6.6.1 In-Reply-To: <1272110272-20686-1-git-send-email-jlayton@redhat.com> References: <1272110272-20686-1-git-send-email-jlayton@redhat.com> Cc: linux-cifs-client@lists.samba.org Subject: [linux-cifs-client] [PATCH 09/11] cifs: allow mixed secTypes on a socket X-BeenThere: linux-cifs-client@lists.samba.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: The Linux CIFS VFS client List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-cifs-client-bounces@lists.samba.org Errors-To: linux-cifs-client-bounces@lists.samba.org Allow secType to be set on a per-session basis. This allows us to mix secTypes on a single socket. Also, add a "sign" bool to cifsSesInfo and determine whether signing should be enabled at session setup time. Try to clarify the code that makes decisions about what sectype to use by using a securityEnum in the volume info instead of a set of flags. Signed-off-by: Jeff Layton --- fs/cifs/cifsglob.h | 12 ++- fs/cifs/cifspdu.h | 2 + fs/cifs/cifssmb.c | 127 ++------------------------------ fs/cifs/connect.c | 202 ++++++++++++++++++++++++++++++++++++++++++++------- fs/cifs/file.c | 12 +-- fs/cifs/misc.c | 6 +- fs/cifs/sess.c | 34 +++++---- fs/cifs/transport.c | 12 +-- 8 files changed, 218 insertions(+), 189 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 4a99487..1ececf4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -80,12 +80,13 @@ enum statusEnum { }; enum securityEnum { - PLAINTXT = 0, /* Legacy with Plaintext passwords */ + Undefined = 0, /* Uninitialized */ + Anonymous, /* Anonymous login */ + Plaintext, /* Legacy with plaintext passwords */ LANMAN, /* Legacy LANMAN auth */ NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ - RawNTLMSSP, /* NTLMSSP without SPNEGO, NTLMv2 hash */ -/* NTLMSSP, */ /* can use rawNTLMSSP instead of NTLMSSP via SPNEGO */ + NTLMSSP, /* NTLMSSP, NTLMv1 hash */ Kerberos, /* Kerberos via SPNEGO */ }; @@ -160,7 +161,6 @@ struct TCP_Server_Info { struct task_struct *tsk; char server_GUID[16]; char secMode; - enum securityEnum secType; unsigned int maxReq; /* Clients should submit no more */ /* than maxReq distinct unanswered SMBs to the server when using */ /* multiplexed reads or writes */ @@ -186,6 +186,7 @@ struct TCP_Server_Info { unsigned long lstrp; /* when we got last response from this server */ u16 dialect; /* dialect index that server chose */ /* extended security flavors that server supports */ + bool ext_security; /* extended security should be used */ bool sec_kerberos; /* supports plain Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_kerberosu2u; /* supports U2U Kerberos */ @@ -218,7 +219,7 @@ struct cifsSesInfo { struct TCP_Server_Info *server; /* pointer to server info */ int ses_count; /* reference counter */ enum statusEnum status; - unsigned overrideSecFlg; /* if non-zero override global sec flags */ + enum securityEnum secType; __u16 ipc_tid; /* special tid for connection to IPC share */ __u16 flags; __u16 vcnum; @@ -233,6 +234,7 @@ struct cifsSesInfo { char userName[MAX_USERNAME_SIZE + 1]; char *domainName; char *password; + bool sign:1; /* packet signing enabled */ bool need_reconnect:1; /* connection reset, uid now invalid */ }; /* no more than one of the following three session flags may be set */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 14d036d..d72960c 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -530,6 +530,8 @@ typedef struct negotiate_rsp { #define SECMODE_SIGN_ENABLED 0x04 /* SMB security signatures enabled */ #define SECMODE_SIGN_REQUIRED 0x08 /* SMB security signatures required */ +#define SECMODE_SIGN (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED) + /* Negotiate response Capabilities */ #define CAP_RAW_MODE 0x00000001 #define CAP_MPX_MODE 0x00000002 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index c65c341..7ba0b1f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -353,46 +353,18 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) int rc = 0; int bytes_returned; int i; - struct TCP_Server_Info *server; + struct TCP_Server_Info *server = ses->server; u16 count; - unsigned int secFlags; - if (ses->server) - server = ses->server; - else { - rc = -EIO; - return rc; - } rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ , (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; /* BB FIXME fix sign flags? */ - else /* if override flags set only sign/seal OR them with global auth */ - secFlags = global_secflags | ses->overrideSecFlg; - - cFYI(1, "secFlags 0x%x", secFlags); - pSMB->hdr.Mid = GetNextMid(server); - pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); - - if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { - cFYI(1, "Kerberos only mechanism, enable extended security"); + pSMB->hdr.Flags2 |= SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS; + if (server->ext_security) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - } -#ifdef CONFIG_CIFS_EXPERIMENTAL - else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { - cFYI(1, "NTLMSSP only mechanism, enable extended security"); - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - } -#endif count = 0; for (i = 0; i < CIFS_NUM_PROT; i++) { @@ -424,15 +396,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) __s16 tmp; struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr; - if ((secFlags & CIFSSEC_MAY_LANMAN) || - (secFlags & CIFSSEC_MAY_PLNTXT)) - server->secType = LANMAN; - else { - cERROR(1, "mount failed weak security disabled" - " in /proc/fs/cifs/SecurityFlags"); - rc = -EOPNOTSUPP; - goto neg_err_exit; - } server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); server->maxReq = le16_to_cpu(rsp->MaxMpxCount); server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), @@ -496,7 +459,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(1, "LANMAN negotiated"); /* we will not end up setting signing flags - as no signing was in LANMAN and server did not return the flags on */ - goto signing_check; + goto neg_err_exit; #else /* weak security disabled */ } else if (pSMBr->hdr.WordCount == 13) { cERROR(1, "mount failed, cifs module not built " @@ -514,36 +477,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if ((server->secMode & SECMODE_USER) == 0) cFYI(1, "share mode security"); - if ((server->secMode & SECMODE_PW_ENCRYPT) == 0) -#ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) -#endif /* CIFS_WEAK_PW_HASH */ - cERROR(1, "Server requests plain text password" - " but client support disabled"); - - if ((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) - server->secType = NTLMv2; - else if (secFlags & CIFSSEC_MAY_NTLM) - server->secType = NTLM; - else if (secFlags & CIFSSEC_MAY_NTLMV2) - server->secType = NTLMv2; - else if (secFlags & CIFSSEC_MAY_KRB5) - server->secType = Kerberos; - else if (secFlags & CIFSSEC_MAY_NTLMSSP) - server->secType = RawNTLMSSP; - else if (secFlags & CIFSSEC_MAY_LANMAN) - server->secType = LANMAN; -/* #ifdef CONFIG_CIFS_EXPERIMENTAL - else if (secFlags & CIFSSEC_MAY_PLNTXT) - server->secType = ?? -#endif */ - else { - rc = -EOPNOTSUPP; - cERROR(1, "Invalid security type"); - goto neg_err_exit; - } - /* else ... any others ...? */ - /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); @@ -594,7 +527,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } if (count == 16) { - server->secType = RawNTLMSSP; + ses->secType = NTLMSSP; } else { rc = decode_negTokenInit(pSMBr->u.extended_response. SecurityBlob, count - 16, @@ -603,48 +536,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) rc = 0; else rc = -EINVAL; - - if (server->sec_kerberos || server->sec_mskerberos) - server->secType = Kerberos; - else if (server->sec_ntlmssp) - server->secType = RawNTLMSSP; - else - rc = -EOPNOTSUPP; } } else server->capabilities &= ~CAP_EXTENDED_SECURITY; -#ifdef CONFIG_CIFS_WEAK_PW_HASH -signing_check: -#endif - if ((secFlags & CIFSSEC_MAY_SIGN) == 0) { - /* MUST_SIGN already includes the MAY_SIGN FLAG - so if this is zero it means that signing is disabled */ - cFYI(1, "Signing disabled"); - if (server->secMode & SECMODE_SIGN_REQUIRED) { - cERROR(1, "Server requires " - "packet signing to be enabled in " - "/proc/fs/cifs/SecurityFlags."); - rc = -EOPNOTSUPP; - } - server->secMode &= - ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); - } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { - /* signing required */ - cFYI(1, "Must sign - secFlags 0x%x", secFlags); - if ((server->secMode & - (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { - cERROR(1, "signing required but server lacks support"); - rc = -EOPNOTSUPP; - } else - server->secMode |= SECMODE_SIGN_REQUIRED; - } else { - /* signing optional ie CIFSSEC_MAY_SIGN */ - if ((server->secMode & SECMODE_SIGN_REQUIRED) == 0) - server->secMode &= - ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); - } - neg_err_exit: cifs_buf_release(pSMB); @@ -718,9 +613,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) pSMB->hdr.Mid = GetNextMid(ses->server); - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if (ses->sign) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->hdr.Uid = ses->Suid; @@ -4158,11 +4052,8 @@ getDFSRetry: strncpy(pSMB->RequestFileName, searchName, name_len); } - if (ses->server) { - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - } + if (ses->sign) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; pSMB->hdr.Uid = ses->Suid; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index fba6b78..c5cbe7d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -70,7 +70,7 @@ struct smb_vol { gid_t linux_gid; mode_t file_mode; mode_t dir_mode; - unsigned secFlg; + enum securityEnum sectype; bool retry:1; bool intr:1; bool setuids:1; @@ -87,10 +87,10 @@ struct smb_vol { bool posix_paths:1; /* unset to not ask for posix pathnames. */ bool no_linux_ext:1; bool sfu_emul:1; - bool nullauth:1; /* attempt to authenticate with null user */ bool nocase:1; /* request case insensitive filenames */ bool nobrl:1; /* disable sending byte range locks to srv */ bool mand_lock:1; /* send mandatory not posix byte range lock reqs */ + bool sign:1; bool seal:1; /* request transport encryption on share */ bool nodfs:1; /* Do not request DFS, even if available */ bool local_lease:1; /* check leases only on local system, not remote */ @@ -872,7 +872,7 @@ cifs_parse_mount_options(char *options, const char *devname, return 1; /* needs_arg; */ } else if (!*value) { /* null user, ie anonymous, authentication */ - vol->nullauth = 1; + vol->sectype = Anonymous; } if (strnlen(value, 200) < 200) { vol->username = value; @@ -978,42 +978,39 @@ cifs_parse_mount_options(char *options, const char *devname, cERROR(1, "no security value specified"); continue; } else if (strnicmp(value, "krb5i", 5) == 0) { - vol->secFlg |= CIFSSEC_MAY_KRB5 | - CIFSSEC_MUST_SIGN; + vol->sectype = Kerberos; + vol->sign = true; } else if (strnicmp(value, "krb5p", 5) == 0) { - /* 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->sectype = Kerberos; #ifdef CONFIG_CIFS_EXPERIMENTAL } else if (strnicmp(value, "ntlmsspi", 8) == 0) { - vol->secFlg |= CIFSSEC_MAY_NTLMSSP | - CIFSSEC_MUST_SIGN; + vol->sectype = NTLMSSP; + vol->sign = true; } else if (strnicmp(value, "ntlmssp", 7) == 0) { - vol->secFlg |= CIFSSEC_MAY_NTLMSSP; + vol->sectype = NTLMSSP; #endif } else if (strnicmp(value, "ntlmv2i", 7) == 0) { - vol->secFlg |= CIFSSEC_MAY_NTLMV2 | - CIFSSEC_MUST_SIGN; + vol->sectype = NTLMv2; + vol->sign = true; } else if (strnicmp(value, "ntlmv2", 6) == 0) { - vol->secFlg |= CIFSSEC_MAY_NTLMV2; + vol->sectype = NTLMv2; } else if (strnicmp(value, "ntlmi", 5) == 0) { - vol->secFlg |= CIFSSEC_MAY_NTLM | - CIFSSEC_MUST_SIGN; + vol->sectype = NTLM; + vol->sign = true; } else if (strnicmp(value, "ntlm", 4) == 0) { - /* ntlm is default so can be turned off too */ - vol->secFlg |= CIFSSEC_MAY_NTLM; + vol->sectype = NTLM; } else if (strnicmp(value, "nontlm", 6) == 0) { /* BB is there a better way to do this? */ - vol->secFlg |= CIFSSEC_MAY_NTLMV2; + vol->sectype = NTLMv2; #ifdef CONFIG_CIFS_WEAK_PW_HASH } else if (strnicmp(value, "lanman", 6) == 0) { - vol->secFlg |= CIFSSEC_MAY_LANMAN; + vol->sectype = LANMAN; #endif } else if (strnicmp(value, "none", 4) == 0) { - vol->nullauth = 1; + vol->sectype = Anonymous; } else { cERROR(1, "bad security option: %s", value); return 1; @@ -1316,12 +1313,11 @@ cifs_parse_mount_options(char *options, const char *devname, vol->local_lease = 1; #endif } else if (strnicmp(data, "sign", 4) == 0) { - vol->secFlg |= CIFSSEC_MUST_SIGN; + vol->sign = 1; } else if (strnicmp(data, "seal", 4) == 0) { /* we do not do the following in secFlags because seal is a per tree connection (mount) not a per socket or per-smb connection option in the protocol */ - /* vol->secFlg |= CIFSSEC_MUST_SEAL; */ vol->seal = 1; } else if (strnicmp(data, "direct", 6) == 0) { vol->direct_io = 1; @@ -1380,6 +1376,150 @@ cifs_parse_mount_options(char *options, const char *devname, return 0; } +#ifdef CONFIG_CIFS_WEAK_PW_HASH +static enum securityEnum +check_lanman(void) +{ + /* only allow if secflags say it's ok */ + if (global_secflags & (CIFSSEC_MAY_LANMAN|CIFSSEC_MAY_PLNTXT)) + return LANMAN; + + return Undefined; +} + +static bool +check_plaintext(struct TCP_Server_Info *server) { + if (server->secMode & SECMODE_PW_ENCRYPT) + return true; + if (global_secflags & CIFSSEC_MAY_PLNTXT) + return true; + cERROR(1, "Server requested plaintext password, but support is " + "disabled in /proc/fs/cifs/SecurityFlags"); + return false; +} +#else /* CONFIG_CIFS_WEAK_PW_HASH */ +static enum securityEnum +check_lanman(void) +{ + return Undefined; +} + +static bool +check_plaintext(struct TCP_Server_Info *server) { + return false; +} +#endif /* CONFIG_CIFS_WEAK_PW_HASH */ + +static bool +use_extended_security(struct smb_vol *vol) +{ + if (vol->sectype == Kerberos || vol->sectype == NTLMSSP) + return true; + return false; +} + +/* decide whether session has signing enabled */ +static int +set_ses_signing(struct cifsSesInfo *ses, struct smb_vol *vol) +{ + /* no signing on anonymous login */ + if (ses->secType == Anonymous) { + ses->sign = false; + } else if (vol->sign || global_secflags & SECMODE_SIGN_REQUIRED) { + if (ses->server->secMode & SECMODE_SIGN) { + ses->sign = true; + } else { + cERROR(1, "mount options specify signing, but server " + "does not support it."); + return -EINVAL; + } + } else if (global_secflags & SECMODE_SIGN) { + if (ses->server->secMode & SECMODE_SIGN_REQUIRED) + ses->sign = true; + } else if (ses->server->secMode & SECMODE_SIGN_REQUIRED) { + cERROR(1, "server requires signing, but client has it" + "disabled in /proc/fs/cifs/SecurityFlags"); + return -EINVAL; + } + + return 0; +} + +/* + * determine the security type to use for session + * + * The decision is based on several inputs: + * + * 1) the global security flags (/proc/fs/cifs/SecurityFlags) + * 2) mount options (vol->sectype) + * 3) what the server actually supports (several fields in TCP_Server_Info) + * + * ...this is far more complicated than it ought to be, but we're saddled + * with legacy interfaces (SecurityFlags in particular). + */ +static enum securityEnum +smb_ses_sectype(struct cifsSesInfo *ses, struct smb_vol *vol) +{ + struct TCP_Server_Info *server = ses->server; + enum securityEnum type; + + /* don't change an existing session */ + if (ses->secType != Undefined) + return ses->secType; + + switch(vol->sectype) { + case Undefined: + break; + case Anonymous: + case NTLMSSP: + case NTLMv2: + case NTLM: + case LANMAN: + return vol->sectype; + case Kerberos: + if (server->sec_kerberos || server->sec_mskerberos) + return Kerberos; + cERROR(1, "Server doesn't support kerberos auth."); + return Undefined; + default: + cERROR(1, "Unknown secType=%d", vol->sectype); + return Undefined; + } + + /* + * no sec= option, determine based on global_secflags and what the + * server supports. + */ + + /* + * extended security requires either krb5 or NTLMSSP. krb5 auth must + * be specified in mount opts. That leaves NTLMSSP if it wasn't. + */ + if (server->capabilities & CAP_EXTENDED_SECURITY) + return NTLMSSP; + + /* check for lanman first if server dialect is ancient */ + if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT) { + type = check_lanman(); + if (type != Undefined && !check_plaintext(server)) + return Undefined; + } + + if (type != Undefined) + return type; + + if ((global_secflags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) + return NTLMv2; + if (global_secflags & CIFSSEC_MAY_NTLM) + return NTLM; + if (global_secflags & CIFSSEC_MAY_NTLMV2) + return NTLMv2; + if (global_secflags & CIFSSEC_MAY_LANMAN) + return LANMAN; + + return Undefined; +} + static struct TCP_Server_Info * cifs_find_tcp_session(struct sockaddr_storage *addr, unsigned short int port) { @@ -1530,6 +1670,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) tcp_ses->sequence_number = 0; INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); INIT_LIST_HEAD(&tcp_ses->smb_ses_list); + tcp_ses->ext_security = use_extended_security(volume_info); /* * at this point we are the only ones with the pointer @@ -1707,10 +1848,16 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) strcpy(ses->domainName, volume_info->domainname); } ses->linux_uid = volume_info->linux_uid; - ses->overrideSecFlg = volume_info->secFlg; mutex_lock(&ses->session_mutex); rc = cifs_negotiate_protocol(xid, ses); + if (!rc) { + ses->secType = smb_ses_sectype(ses, volume_info); + if (ses->secType == Undefined) + rc = -EOPNOTSUPP; + } + if (!rc) + rc = set_ses_signing(ses, volume_info); if (!rc) rc = cifs_setup_session(xid, ses, volume_info->local_nls); mutex_unlock(&ses->session_mutex); @@ -2512,7 +2659,7 @@ try_mount_again: goto out; } - if (volume_info->nullauth) { + if (volume_info->sectype == Anonymous) { cFYI(1, "null user"); volume_info->username = ""; } else if (volume_info->username) { @@ -2759,7 +2906,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, NTLMv2 password here) */ #ifdef CONFIG_CIFS_WEAK_PW_HASH if ((global_secflags & CIFSSEC_MAY_LANMAN) && - (ses->server->secType == LANMAN)) + (ses->secType == LANMAN)) calc_lanman_hash(tcon->password, ses->server->cryptKey, ses->server->secMode & SECMODE_PW_ENCRYPT ? true : false, @@ -2777,8 +2924,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, } } - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + if (ses->sign) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (ses->capabilities & CAP_STATUS32) { diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5f1f768..c30e8fe 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1132,10 +1132,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, if (rc != 0) break; } - if (experimEnabled || (pTcon->ses->server && - ((pTcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - == 0))) { + if (experimEnabled || !pTcon->ses->sign) { struct kvec iov[2]; unsigned int len; @@ -1397,11 +1394,8 @@ static int cifs_writepages(struct address_space *mapping, if (cifs_sb->wsize < PAGE_CACHE_SIZE) return generic_writepages(mapping, wbc); - if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) - if (cifs_sb->tcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - if (!experimEnabled) - return generic_writepages(mapping, wbc); + if (cifs_sb->tcon->ses->sign && !experimEnabled) + return generic_writepages(mapping, wbc); iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL); if (iov == NULL) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1394aa3..ca58ec1 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -369,10 +369,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , buffer->Flags2 |= SMBFLG2_DFS; if (treeCon->nocase) buffer->Flags |= SMBFLG_CASELESS; - if ((treeCon->ses) && (treeCon->ses->server)) - if (treeCon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + if (treeCon->ses->sign) + buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; } /* endian conversion of flags is now done just before sending */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7707389..fd6921c 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -139,8 +139,7 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + if (ses->sign) pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (ses->capabilities & CAP_UNICODE) { @@ -222,7 +221,7 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, bcc_ptr++; } */ /* copy user */ - if (ses->userName == NULL) { + if (ses->secType == Anonymous) { /* null user mount */ *bcc_ptr = 0; *(bcc_ptr+1) = 0; @@ -426,8 +425,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + if (ses->sign) flags |= NTLMSSP_NEGOTIATE_SIGN; if (ses->server->secMode & SECMODE_SIGN_REQUIRED) flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; @@ -463,8 +461,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NT_ONLY | NTLMSSP_NEGOTIATE_NTLM; - if (ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + if (ses->sign) flags |= NTLMSSP_NEGOTIATE_SIGN; if (ses->server->secMode & SECMODE_SIGN_REQUIRED) flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; @@ -588,14 +585,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, first_time = is_first_ses_reconnect(ses); read_unlock(&cifs_tcp_ses_lock); - type = ses->server->secType; + type = ses->secType; cFYI(1, "sess setup type %d", type); ssetup_ntlmssp_authenticate: if (phase == NtLmChallenge) phase = NtLmAuthenticate; /* if ntlmssp, now final phase */ - if (type == LANMAN) { + switch(type) { + case LANMAN: #ifndef CONFIG_CIFS_WEAK_PW_HASH /* LANMAN and plaintext are less secure and off by default. So we make this explicitly be turned on in kconfig (in the @@ -605,11 +603,15 @@ ssetup_ntlmssp_authenticate: return -EOPNOTSUPP; #endif wct = 10; /* lanman 2 style sessionsetup */ - } else if ((type == NTLM) || (type == NTLMv2)) { - /* For NTLMv2 failures eventually may need to retry NTLM */ - wct = 13; /* old style NTLM sessionsetup */ - } else /* same size: negotiate or auth, NTLMSSP or extended security */ + break; + case NTLM: + case NTLMv2: + case Anonymous: + wct = 13; + break; + default: wct = 12; + } rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, (void **)&smb_buf); @@ -675,7 +677,7 @@ ssetup_ntlmssp_authenticate: /* Unicode not allowed for LANMAN dialects */ ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); #endif - } else if (type == NTLM) { + } else if (type == NTLM || type == Anonymous) { char ntlm_session_key[CIFS_SESS_KEY_SIZE]; pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); @@ -809,7 +811,7 @@ ssetup_ntlmssp_authenticate: #endif /* CONFIG_CIFS_UPCALL */ } else { #ifdef CONFIG_CIFS_EXPERIMENTAL - if (type == RawNTLMSSP) { + if (type == NTLMSSP) { if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { cERROR(1, "NTLMSSP requires Unicode support"); rc = -ENOSYS; @@ -874,7 +876,7 @@ ssetup_ntlmssp_authenticate: pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; smb_buf = (struct smb_hdr *)iov[0].iov_base; - if ((type == RawNTLMSSP) && (smb_buf->Status.CifsError == + if ((type == NTLMSSP) && (smb_buf->Status.CifsError == cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) { if (phase != NtLmNegotiate) { cERROR(1, "Unexpected more processing error"); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 28f563c..8a7a58e 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -540,9 +540,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, dump_smb(midQ->resp_buf, 80); /* convert the length into a more usable form */ - if ((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | - SECMODE_SIGN_ENABLED))) { + if (receive_len > 24 && ses->sign) { rc = cifs_verify_signature(midQ->resp_buf, &ses->server->mac_signing_key, midQ->sequence_number+1); @@ -728,9 +726,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, dump_smb(out_buf, 92); /* convert the length into a more usable form */ - if ((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | - SECMODE_SIGN_ENABLED))) { + if (receive_len > 24 && ses->sign) { rc = cifs_verify_signature(out_buf, &ses->server->mac_signing_key, midQ->sequence_number+1); @@ -978,9 +974,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, dump_smb(out_buf, 92); /* convert the length into a more usable form */ - if ((receive_len > 24) && - (ses->server->secMode & (SECMODE_SIGN_REQUIRED | - SECMODE_SIGN_ENABLED))) { + if (receive_len > 24 && ses->sign) { rc = cifs_verify_signature(out_buf, &ses->server->mac_signing_key, midQ->sequence_number+1);