aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifssmb.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r--fs/cifs/cifssmb.c96
1 files changed, 83 insertions, 13 deletions
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 075d8fb3d376..5dc5a966bd5f 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -46,6 +46,7 @@ static struct {
46} protocols[] = { 46} protocols[] = {
47#ifdef CONFIG_CIFS_WEAK_PW_HASH 47#ifdef CONFIG_CIFS_WEAK_PW_HASH
48 {LANMAN_PROT, "\2LM1.2X002"}, 48 {LANMAN_PROT, "\2LM1.2X002"},
49 {LANMAN2_PROT, "\2LANMAN2.1"},
49#endif /* weak password hashing for legacy clients */ 50#endif /* weak password hashing for legacy clients */
50 {CIFS_PROT, "\2NT LM 0.12"}, 51 {CIFS_PROT, "\2NT LM 0.12"},
51 {POSIX_PROT, "\2POSIX 2"}, 52 {POSIX_PROT, "\2POSIX 2"},
@@ -58,6 +59,7 @@ static struct {
58} protocols[] = { 59} protocols[] = {
59#ifdef CONFIG_CIFS_WEAK_PW_HASH 60#ifdef CONFIG_CIFS_WEAK_PW_HASH
60 {LANMAN_PROT, "\2LM1.2X002"}, 61 {LANMAN_PROT, "\2LM1.2X002"},
62 {LANMAN2_PROT, "\2LANMAN2.1"},
61#endif /* weak password hashing for legacy clients */ 63#endif /* weak password hashing for legacy clients */
62 {CIFS_PROT, "\2NT LM 0.12"}, 64 {CIFS_PROT, "\2NT LM 0.12"},
63 {BAD_PROT, "\2"} 65 {BAD_PROT, "\2"}
@@ -67,13 +69,13 @@ static struct {
67/* define the number of elements in the cifs dialect array */ 69/* define the number of elements in the cifs dialect array */
68#ifdef CONFIG_CIFS_POSIX 70#ifdef CONFIG_CIFS_POSIX
69#ifdef CONFIG_CIFS_WEAK_PW_HASH 71#ifdef CONFIG_CIFS_WEAK_PW_HASH
70#define CIFS_NUM_PROT 3 72#define CIFS_NUM_PROT 4
71#else 73#else
72#define CIFS_NUM_PROT 2 74#define CIFS_NUM_PROT 2
73#endif /* CIFS_WEAK_PW_HASH */ 75#endif /* CIFS_WEAK_PW_HASH */
74#else /* not posix */ 76#else /* not posix */
75#ifdef CONFIG_CIFS_WEAK_PW_HASH 77#ifdef CONFIG_CIFS_WEAK_PW_HASH
76#define CIFS_NUM_PROT 2 78#define CIFS_NUM_PROT 3
77#else 79#else
78#define CIFS_NUM_PROT 1 80#define CIFS_NUM_PROT 1
79#endif /* CONFIG_CIFS_WEAK_PW_HASH */ 81#endif /* CONFIG_CIFS_WEAK_PW_HASH */
@@ -446,7 +448,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
446 goto neg_err_exit; 448 goto neg_err_exit;
447#ifdef CONFIG_CIFS_WEAK_PW_HASH 449#ifdef CONFIG_CIFS_WEAK_PW_HASH
448 } else if((pSMBr->hdr.WordCount == 13) 450 } else if((pSMBr->hdr.WordCount == 13)
449 && (pSMBr->DialectIndex == LANMAN_PROT)) { 451 && ((pSMBr->DialectIndex == LANMAN_PROT)
452 || (pSMBr->DialectIndex == LANMAN2_PROT))) {
453 __s16 tmp;
450 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; 454 struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
451 455
452 if((secFlags & CIFSSEC_MAY_LANMAN) || 456 if((secFlags & CIFSSEC_MAY_LANMAN) ||
@@ -472,12 +476,44 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
472 server->maxRw = 0;/* we do not need to use raw anyway */ 476 server->maxRw = 0;/* we do not need to use raw anyway */
473 server->capabilities = CAP_MPX_MODE; 477 server->capabilities = CAP_MPX_MODE;
474 } 478 }
475 server->timeZone = le16_to_cpu(rsp->ServerTimeZone); 479 tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
480 if (tmp == -1) {
481 /* OS/2 often does not set timezone therefore
482 * we must use server time to calc time zone.
483 * Could deviate slightly from the right zone.
484 * Smallest defined timezone difference is 15 minutes
485 * (i.e. Nepal). Rounding up/down is done to match
486 * this requirement.
487 */
488 int val, seconds, remain, result;
489 struct timespec ts, utc;
490 utc = CURRENT_TIME;
491 ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
492 le16_to_cpu(rsp->SrvTime.Time));
493 cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
494 (int)ts.tv_sec, (int)utc.tv_sec,
495 (int)(utc.tv_sec - ts.tv_sec)));
496 val = (int)(utc.tv_sec - ts.tv_sec);
497 seconds = val < 0 ? -val : val;
498 result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
499 remain = seconds % MIN_TZ_ADJ;
500 if(remain >= (MIN_TZ_ADJ / 2))
501 result += MIN_TZ_ADJ;
502 if(val < 0)
503 result = - result;
504 server->timeAdj = result;
505 } else {
506 server->timeAdj = (int)tmp;
507 server->timeAdj *= 60; /* also in seconds */
508 }
509 cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
510
476 511
477 /* BB get server time for time conversions and add 512 /* BB get server time for time conversions and add
478 code to use it and timezone since this is not UTC */ 513 code to use it and timezone since this is not UTC */
479 514
480 if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { 515 if (rsp->EncryptionKeyLength ==
516 cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
481 memcpy(server->cryptKey, rsp->EncryptionKey, 517 memcpy(server->cryptKey, rsp->EncryptionKey,
482 CIFS_CRYPTO_KEY_SIZE); 518 CIFS_CRYPTO_KEY_SIZE);
483 } else if (server->secMode & SECMODE_PW_ENCRYPT) { 519 } else if (server->secMode & SECMODE_PW_ENCRYPT) {
@@ -531,7 +567,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
531 cFYI(0, ("Max buf = %d", ses->server->maxBuf)); 567 cFYI(0, ("Max buf = %d", ses->server->maxBuf));
532 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); 568 GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
533 server->capabilities = le32_to_cpu(pSMBr->Capabilities); 569 server->capabilities = le32_to_cpu(pSMBr->Capabilities);
534 server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); 570 server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
571 server->timeAdj *= 60;
535 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { 572 if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
536 memcpy(server->cryptKey, pSMBr->u.EncryptionKey, 573 memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
537 CIFS_CRYPTO_KEY_SIZE); 574 CIFS_CRYPTO_KEY_SIZE);
@@ -1617,7 +1654,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1617 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ 1654 pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1618 1655
1619 pSMB->FileID = (__u16) smb_file_id; 1656 pSMB->FileID = (__u16) smb_file_id;
1620 pSMB->LastWriteTime = 0; 1657 pSMB->LastWriteTime = 0xFFFFFFFF;
1621 pSMB->ByteCount = 0; 1658 pSMB->ByteCount = 0;
1622 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, 1659 rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1623 (struct smb_hdr *) pSMBr, &bytes_returned, 0); 1660 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -2773,9 +2810,11 @@ GetExtAttrOut:
2773 2810
2774 2811
2775/* security id for everyone */ 2812/* security id for everyone */
2776const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; 2813const static struct cifs_sid sid_everyone =
2814 {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
2777/* group users */ 2815/* group users */
2778const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; 2816const static struct cifs_sid sid_user =
2817 {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
2779 2818
2780/* Convert CIFS ACL to POSIX form */ 2819/* Convert CIFS ACL to POSIX form */
2781static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len) 2820static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
@@ -2856,7 +2895,6 @@ qsec_out:
2856 return rc; 2895 return rc;
2857} 2896}
2858 2897
2859
2860/* Legacy Query Path Information call for lookup to old servers such 2898/* Legacy Query Path Information call for lookup to old servers such
2861 as Win9x/WinME */ 2899 as Win9x/WinME */
2862int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, 2900int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@@ -2898,7 +2936,16 @@ QInfRetry:
2898 if (rc) { 2936 if (rc) {
2899 cFYI(1, ("Send error in QueryInfo = %d", rc)); 2937 cFYI(1, ("Send error in QueryInfo = %d", rc));
2900 } else if (pFinfo) { /* decode response */ 2938 } else if (pFinfo) { /* decode response */
2939 struct timespec ts;
2940 __u32 time = le32_to_cpu(pSMBr->last_write_time);
2941 /* BB FIXME - add time zone adjustment BB */
2901 memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); 2942 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2943 ts.tv_nsec = 0;
2944 ts.tv_sec = time;
2945 /* decode time fields */
2946 pFinfo->ChangeTime = cifs_UnixTimeToNT(ts);
2947 pFinfo->LastWriteTime = pFinfo->ChangeTime;
2948 pFinfo->LastAccessTime = 0;
2902 pFinfo->AllocationSize = 2949 pFinfo->AllocationSize =
2903 cpu_to_le64(le32_to_cpu(pSMBr->size)); 2950 cpu_to_le64(le32_to_cpu(pSMBr->size));
2904 pFinfo->EndOfFile = pFinfo->AllocationSize; 2951 pFinfo->EndOfFile = pFinfo->AllocationSize;
@@ -2922,6 +2969,7 @@ int
2922CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, 2969CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2923 const unsigned char *searchName, 2970 const unsigned char *searchName,
2924 FILE_ALL_INFO * pFindData, 2971 FILE_ALL_INFO * pFindData,
2972 int legacy /* old style infolevel */,
2925 const struct nls_table *nls_codepage, int remap) 2973 const struct nls_table *nls_codepage, int remap)
2926{ 2974{
2927/* level 263 SMB_QUERY_FILE_ALL_INFO */ 2975/* level 263 SMB_QUERY_FILE_ALL_INFO */
@@ -2970,7 +3018,10 @@ QPathInfoRetry:
2970 byte_count = params + 1 /* pad */ ; 3018 byte_count = params + 1 /* pad */ ;
2971 pSMB->TotalParameterCount = cpu_to_le16(params); 3019 pSMB->TotalParameterCount = cpu_to_le16(params);
2972 pSMB->ParameterCount = pSMB->TotalParameterCount; 3020 pSMB->ParameterCount = pSMB->TotalParameterCount;
2973 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); 3021 if(legacy)
3022 pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3023 else
3024 pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2974 pSMB->Reserved4 = 0; 3025 pSMB->Reserved4 = 0;
2975 pSMB->hdr.smb_buf_length += byte_count; 3026 pSMB->hdr.smb_buf_length += byte_count;
2976 pSMB->ByteCount = cpu_to_le16(byte_count); 3027 pSMB->ByteCount = cpu_to_le16(byte_count);
@@ -2982,13 +3033,24 @@ QPathInfoRetry:
2982 } else { /* decode response */ 3033 } else { /* decode response */
2983 rc = validate_t2((struct smb_t2_rsp *)pSMBr); 3034 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2984 3035
2985 if (rc || (pSMBr->ByteCount < 40)) 3036 if (rc) /* BB add auto retry on EOPNOTSUPP? */
3037 rc = -EIO;
3038 else if (!legacy && (pSMBr->ByteCount < 40))
2986 rc = -EIO; /* bad smb */ 3039 rc = -EIO; /* bad smb */
3040 else if(legacy && (pSMBr->ByteCount < 24))
3041 rc = -EIO; /* 24 or 26 expected but we do not read last field */
2987 else if (pFindData){ 3042 else if (pFindData){
3043 int size;
2988 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 3044 __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3045 if(legacy) /* we do not read the last field, EAsize, fortunately
3046 since it varies by subdialect and on Set vs. Get, is
3047 two bytes or 4 bytes depending but we don't care here */
3048 size = sizeof(FILE_INFO_STANDARD);
3049 else
3050 size = sizeof(FILE_ALL_INFO);
2989 memcpy((char *) pFindData, 3051 memcpy((char *) pFindData,
2990 (char *) &pSMBr->hdr.Protocol + 3052 (char *) &pSMBr->hdr.Protocol +
2991 data_offset, sizeof (FILE_ALL_INFO)); 3053 data_offset, size);
2992 } else 3054 } else
2993 rc = -ENOMEM; 3055 rc = -ENOMEM;
2994 } 3056 }
@@ -3613,6 +3675,14 @@ getDFSRetry:
3613 strncpy(pSMB->RequestFileName, searchName, name_len); 3675 strncpy(pSMB->RequestFileName, searchName, name_len);
3614 } 3676 }
3615 3677
3678 if(ses->server) {
3679 if(ses->server->secMode &
3680 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
3681 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
3682 }
3683
3684 pSMB->hdr.Uid = ses->Suid;
3685
3616 params = 2 /* level */ + name_len /*includes null */ ; 3686 params = 2 /* level */ + name_len /*includes null */ ;
3617 pSMB->TotalDataCount = 0; 3687 pSMB->TotalDataCount = 0;
3618 pSMB->DataCount = 0; 3688 pSMB->DataCount = 0;