|
@@ -46,6 +46,7 @@ static struct {
|
|
|
} 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"},
|
|
@@ -58,6 +59,7 @@ static struct {
|
|
|
} 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"}
|
|
@@ -67,13 +69,13 @@ 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 3
|
|
|
+#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 2
|
|
|
+#define CIFS_NUM_PROT 3
|
|
|
#else
|
|
|
#define CIFS_NUM_PROT 1
|
|
|
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
|
|
@@ -446,7 +448,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|
|
goto neg_err_exit;
|
|
|
#ifdef CONFIG_CIFS_WEAK_PW_HASH
|
|
|
} else if((pSMBr->hdr.WordCount == 13)
|
|
|
- && (pSMBr->DialectIndex == LANMAN_PROT)) {
|
|
|
+ && ((pSMBr->DialectIndex == LANMAN_PROT)
|
|
|
+ || (pSMBr->DialectIndex == LANMAN2_PROT))) {
|
|
|
+ __s16 tmp;
|
|
|
struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
|
|
|
|
|
|
if((secFlags & CIFSSEC_MAY_LANMAN) ||
|
|
@@ -472,12 +476,44 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|
|
server->maxRw = 0;/* we do not need to use raw anyway */
|
|
|
server->capabilities = CAP_MPX_MODE;
|
|
|
}
|
|
|
- server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
|
|
|
+ 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(le16_to_cpu(rsp->SrvTime.Date),
|
|
|
+ le16_to_cpu(rsp->SrvTime.Time));
|
|
|
+ cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
|
|
|
+ (int)ts.tv_sec, (int)utc.tv_sec,
|
|
|
+ (int)(utc.tv_sec - ts.tv_sec)));
|
|
|
+ val = (int)(utc.tv_sec - ts.tv_sec);
|
|
|
+ seconds = val < 0 ? -val : 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 */
|
|
|
+ }
|
|
|
+ cFYI(1,("server->timeAdj: %d seconds", 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)) {
|
|
|
+ if (rsp->EncryptionKeyLength ==
|
|
|
+ cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
|
|
|
memcpy(server->cryptKey, rsp->EncryptionKey,
|
|
|
CIFS_CRYPTO_KEY_SIZE);
|
|
|
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
|
|
@@ -531,7 +567,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
|
|
|
cFYI(0, ("Max buf = %d", ses->server->maxBuf));
|
|
|
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
|
|
|
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
|
|
|
- server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
|
|
|
+ server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
|
|
|
+ server->timeAdj *= 60;
|
|
|
if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
|
|
|
memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
|
|
|
CIFS_CRYPTO_KEY_SIZE);
|
|
@@ -1617,7 +1654,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
|
|
|
pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
|
|
|
|
|
|
pSMB->FileID = (__u16) smb_file_id;
|
|
|
- pSMB->LastWriteTime = 0;
|
|
|
+ pSMB->LastWriteTime = 0xFFFFFFFF;
|
|
|
pSMB->ByteCount = 0;
|
|
|
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
|
|
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
|
@@ -2773,9 +2810,11 @@ GetExtAttrOut:
|
|
|
|
|
|
|
|
|
/* security id for everyone */
|
|
|
-const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
|
|
|
+const static struct cifs_sid sid_everyone =
|
|
|
+ {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
|
|
|
/* group users */
|
|
|
-const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
|
|
|
+const static struct cifs_sid sid_user =
|
|
|
+ {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
|
|
|
|
|
|
/* Convert CIFS ACL to POSIX form */
|
|
|
static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
|
|
@@ -2856,7 +2895,6 @@ qsec_out:
|
|
|
return rc;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
/* Legacy Query Path Information call for lookup to old servers such
|
|
|
as Win9x/WinME */
|
|
|
int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
|
|
@@ -2898,7 +2936,16 @@ QInfRetry:
|
|
|
if (rc) {
|
|
|
cFYI(1, ("Send error in QueryInfo = %d", rc));
|
|
|
} else if (pFinfo) { /* decode response */
|
|
|
+ struct timespec ts;
|
|
|
+ __u32 time = le32_to_cpu(pSMBr->last_write_time);
|
|
|
+ /* BB FIXME - add time zone adjustment BB */
|
|
|
memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
|
|
|
+ ts.tv_nsec = 0;
|
|
|
+ ts.tv_sec = time;
|
|
|
+ /* decode time fields */
|
|
|
+ pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
|
|
|
+ pFinfo->LastWriteTime = pFinfo->ChangeTime;
|
|
|
+ pFinfo->LastAccessTime = 0;
|
|
|
pFinfo->AllocationSize =
|
|
|
cpu_to_le64(le32_to_cpu(pSMBr->size));
|
|
|
pFinfo->EndOfFile = pFinfo->AllocationSize;
|
|
@@ -2922,6 +2969,7 @@ int
|
|
|
CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
|
|
|
const unsigned char *searchName,
|
|
|
FILE_ALL_INFO * pFindData,
|
|
|
+ int legacy /* old style infolevel */,
|
|
|
const struct nls_table *nls_codepage, int remap)
|
|
|
{
|
|
|
/* level 263 SMB_QUERY_FILE_ALL_INFO */
|
|
@@ -2970,7 +3018,10 @@ QPathInfoRetry:
|
|
|
byte_count = params + 1 /* pad */ ;
|
|
|
pSMB->TotalParameterCount = cpu_to_le16(params);
|
|
|
pSMB->ParameterCount = pSMB->TotalParameterCount;
|
|
|
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
|
|
|
+ if(legacy)
|
|
|
+ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
|
|
|
+ else
|
|
|
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
|
|
|
pSMB->Reserved4 = 0;
|
|
|
pSMB->hdr.smb_buf_length += byte_count;
|
|
|
pSMB->ByteCount = cpu_to_le16(byte_count);
|
|
@@ -2982,13 +3033,24 @@ QPathInfoRetry:
|
|
|
} else { /* decode response */
|
|
|
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
|
|
|
|
|
|
- if (rc || (pSMBr->ByteCount < 40))
|
|
|
+ if (rc) /* BB add auto retry on EOPNOTSUPP? */
|
|
|
+ rc = -EIO;
|
|
|
+ else if (!legacy && (pSMBr->ByteCount < 40))
|
|
|
rc = -EIO; /* bad smb */
|
|
|
+ else if(legacy && (pSMBr->ByteCount < 24))
|
|
|
+ rc = -EIO; /* 24 or 26 expected but we do not read last field */
|
|
|
else if (pFindData){
|
|
|
+ int size;
|
|
|
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
|
|
|
+ if(legacy) /* we do not read the last field, EAsize, fortunately
|
|
|
+ since it varies by subdialect and on Set vs. Get, is
|
|
|
+ two bytes or 4 bytes depending but we don't care here */
|
|
|
+ size = sizeof(FILE_INFO_STANDARD);
|
|
|
+ else
|
|
|
+ size = sizeof(FILE_ALL_INFO);
|
|
|
memcpy((char *) pFindData,
|
|
|
(char *) &pSMBr->hdr.Protocol +
|
|
|
- data_offset, sizeof (FILE_ALL_INFO));
|
|
|
+ data_offset, size);
|
|
|
} else
|
|
|
rc = -ENOMEM;
|
|
|
}
|
|
@@ -3613,6 +3675,14 @@ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ pSMB->hdr.Uid = ses->Suid;
|
|
|
+
|
|
|
params = 2 /* level */ + name_len /*includes null */ ;
|
|
|
pSMB->TotalDataCount = 0;
|
|
|
pSMB->DataCount = 0;
|