diff options
Diffstat (limited to 'fs/cifs/cifssmb.c')
-rw-r--r-- | fs/cifs/cifssmb.c | 96 |
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 */ |
2776 | const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; | 2813 | const 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 */ |
2778 | const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; | 2816 | const 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 */ |
2781 | static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len) | 2820 | static 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 */ |
2862 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | 2900 | int 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 | |||
2922 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 2969 | CIFSSMBQPathInfo(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; |