cifs: break out lanman NEGOTIATE handling into separate function

...this also gets rid of some #ifdef ugliness too.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Acked-by: Pavel Shilovsky <piastry@etersoft.ru>
Signed-off-by: Steve French <sfrench@us.ibm.com>
This commit is contained in:
Jeff Layton 2013-05-26 07:00:57 -04:00 committed by Steve French
parent 31d9e2bd5f
commit 2190eca1d0
1 changed files with 97 additions and 88 deletions

View File

@ -417,6 +417,96 @@ decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
return 0;
}
#ifdef CONFIG_CIFS_WEAK_PW_HASH
static int
decode_lanman_negprot_rsp(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr,
unsigned int secFlags)
{
__s16 tmp;
struct lanman_neg_rsp *rsp = (struct lanman_neg_rsp *)pSMBr;
if (server->dialect != LANMAN_PROT && server->dialect != LANMAN2_PROT)
return -EOPNOTSUPP;
if ((secFlags & CIFSSEC_MAY_LANMAN) || (secFlags & CIFSSEC_MAY_PLNTXT))
server->secType = LANMAN;
else {
cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
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);
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
/* 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 timespec ts, utc;
utc = CURRENT_TIME;
ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
rsp->SrvTime.Time, 0);
cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
(int)ts.tv_sec, (int)utc.tv_sec,
(int)(utc.tv_sec - ts.tv_sec));
val = (int)(utc.tv_sec - 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,
unsigned int secFlags)
{
cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
return -EOPNOTSUPP;
}
#endif
int
CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
{
@ -485,98 +575,19 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
could not negotiate a common dialect */
rc = -EOPNOTSUPP;
goto neg_err_exit;
#ifdef CONFIG_CIFS_WEAK_PW_HASH
} else if ((pSMBr->hdr.WordCount == 13)
&& ((server->dialect == LANMAN_PROT)
|| (server->dialect == LANMAN2_PROT))) {
__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 {
cifs_dbg(VFS, "mount failed weak security disabled in /proc/fs/cifs/SecurityFlags\n");
rc = -EOPNOTSUPP;
goto neg_err_exit;
}
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);
server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
/* 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 timespec ts, utc;
utc = CURRENT_TIME;
ts = cnvrtDosUnixTm(rsp->SrvTime.Date,
rsp->SrvTime.Time, 0);
cifs_dbg(FYI, "SrvTime %d sec since 1970 (utc: %d) diff: %d\n",
(int)ts.tv_sec, (int)utc.tv_sec,
(int)(utc.tv_sec - ts.tv_sec));
val = (int)(utc.tv_sec - 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(ses->server->cryptkey, rsp->EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
} else if (server->sec_mode & SECMODE_PW_ENCRYPT) {
rc = -EIO; /* need cryptkey unless plain text */
goto neg_err_exit;
}
cifs_dbg(FYI, "LANMAN negotiated\n");
/* 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;
#else /* weak security disabled */
} else if (pSMBr->hdr.WordCount == 13) {
cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
rc = -EOPNOTSUPP;
#endif /* WEAK_PW_HASH */
goto neg_err_exit;
rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
if (!rc)
goto signing_check;
else
goto neg_err_exit;
} else if (pSMBr->hdr.WordCount != 17) {
/* unknown wct */
rc = -EOPNOTSUPP;
goto neg_err_exit;
}
/* else wct == 17 NTLM */
/* else wct == 17, NTLM or better */
server->sec_mode = pSMBr->SecurityMode;
if ((server->sec_mode & SECMODE_USER) == 0)
cifs_dbg(FYI, "share mode security\n");
@ -634,9 +645,7 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
if (rc)
goto neg_err_exit;
#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 */