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:
parent
31d9e2bd5f
commit
2190eca1d0
1 changed files with 97 additions and 88 deletions
|
@ -417,6 +417,96 @@ decode_ext_sec_blob(struct TCP_Server_Info *server, NEGOTIATE_RSP *pSMBr)
|
||||||
return 0;
|
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
|
int
|
||||||
CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
|
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 */
|
could not negotiate a common dialect */
|
||||||
rc = -EOPNOTSUPP;
|
rc = -EOPNOTSUPP;
|
||||||
goto neg_err_exit;
|
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) {
|
} else if (pSMBr->hdr.WordCount == 13) {
|
||||||
cifs_dbg(VFS, "mount failed, cifs module not built with CIFS_WEAK_PW_HASH support\n");
|
rc = decode_lanman_negprot_rsp(server, pSMBr, secFlags);
|
||||||
rc = -EOPNOTSUPP;
|
if (!rc)
|
||||||
#endif /* WEAK_PW_HASH */
|
goto signing_check;
|
||||||
goto neg_err_exit;
|
else
|
||||||
|
goto neg_err_exit;
|
||||||
} else if (pSMBr->hdr.WordCount != 17) {
|
} else if (pSMBr->hdr.WordCount != 17) {
|
||||||
/* unknown wct */
|
/* unknown wct */
|
||||||
rc = -EOPNOTSUPP;
|
rc = -EOPNOTSUPP;
|
||||||
goto neg_err_exit;
|
goto neg_err_exit;
|
||||||
}
|
}
|
||||||
/* else wct == 17 NTLM */
|
/* else wct == 17, NTLM or better */
|
||||||
|
|
||||||
server->sec_mode = pSMBr->SecurityMode;
|
server->sec_mode = pSMBr->SecurityMode;
|
||||||
if ((server->sec_mode & SECMODE_USER) == 0)
|
if ((server->sec_mode & SECMODE_USER) == 0)
|
||||||
cifs_dbg(FYI, "share mode security\n");
|
cifs_dbg(FYI, "share mode security\n");
|
||||||
|
@ -634,9 +645,7 @@ CIFSSMBNegotiate(const unsigned int xid, struct cifs_ses *ses)
|
||||||
if (rc)
|
if (rc)
|
||||||
goto neg_err_exit;
|
goto neg_err_exit;
|
||||||
|
|
||||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
|
||||||
signing_check:
|
signing_check:
|
||||||
#endif
|
|
||||||
if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
|
if ((secFlags & CIFSSEC_MAY_SIGN) == 0) {
|
||||||
/* MUST_SIGN already includes the MAY_SIGN FLAG
|
/* MUST_SIGN already includes the MAY_SIGN FLAG
|
||||||
so if this is zero it means that signing is disabled */
|
so if this is zero it means that signing is disabled */
|
||||||
|
|
Loading…
Add table
Reference in a new issue