[CIFS] Workaround incomplete byte length returned by some
authorSteve French <sfrench@us.ibm.com>
Thu, 12 Oct 2006 17:49:24 +0000 (17:49 +0000)
committerSteve French <sfrench@us.ibm.com>
Thu, 12 Oct 2006 17:49:24 +0000 (17:49 +0000)
servers on small SMB responses

Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/cifsproto.h
fs/cifs/misc.c

index 4a4fd2dbca6318978af328abd36af2458e074a13..f1f8225102f0a6dead4670ef95c6fa42fe0917e3 100644 (file)
@@ -55,7 +55,7 @@ extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
                                struct smb_hdr * /* input */ ,
                                struct smb_hdr * /* out */ ,
                                int * /* bytes returned */);
-extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
+extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
 extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
 extern int is_size_safe_to_change(struct cifsInodeInfo *);
 extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
index ca6e9b1413fa8f4ac95170a87c4202c2e5b0c5d5..bbc9cd34b6ea42f02d85e9e31c140824b4ab5dd8 100644 (file)
@@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
 }
 
 int
-checkSMB(struct smb_hdr *smb, __u16 mid, int length)
+checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
 {
        __u32 len = smb->smb_buf_length;
        __u32 clc_len;  /* calculated length */
        cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
-       if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
-           (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
-               if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
-                       if (((unsigned int)length >= 
-                               sizeof (struct smb_hdr) - 1)
+
+       if (length < 2 + sizeof (struct smb_hdr)) {
+               if ((length >= sizeof (struct smb_hdr) - 1)
                            && (smb->Status.CifsError != 0)) {
-                               smb->WordCount = 0;
-                               /* some error cases do not return wct and bcc */
+                       smb->WordCount = 0;
+                       /* some error cases do not return wct and bcc */
+                       return 0;
+               } else if ((length == sizeof(struct smb_hdr) + 1) && 
+                               (smb->WordCount == 0)) {
+                       char * tmp = (char *)smb;
+                       /* Need to work around a bug in two servers here */
+                       /* First, check if the part of bcc they sent was zero */
+                       if (tmp[sizeof(struct smb_hdr)] == 0) {
+                               /* some servers return only half of bcc
+                                * on simple responses (wct, bcc both zero)
+                                * in particular have seen this on
+                                * ulogoffX and FindClose. This leaves
+                                * one byte of bcc potentially unitialized
+                                */
+                               /* zero rest of bcc */
+                               tmp[sizeof(struct smb_hdr)+1] = 0;
                                return 0;
-                       } else {
-                               cERROR(1, ("Length less than smb header size"));
                        }
+                       cERROR(1,("rcvd invalid byte count (bcc)"));
+               } else {
+                       cERROR(1, ("Length less than smb header size"));
                }
-               if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
-                       cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
+               return 1;
+       }
+       if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+               cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
                                   smb->Mid));
                return 1;
        }
@@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
                return 1;
        clc_len = smbCalcSize_LE(smb);
 
-       if(4 + len != (unsigned int)length) {
+       if(4 + len != length) {
                cERROR(1, ("Length read does not match RFC1001 length %d",len));
                return 1;
        }