[CIFS] Fix oops when Windows server sent bad domain name null terminator
[sfrench/cifs-2.6.git] / fs / cifs / sess.c
index 22b4c35dcfe3e4bfbc067b56880f5fb958df50ae..758464630893e8082339f6018ce16cf74028e9e5 100644 (file)
@@ -90,7 +90,9 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
        } */
        /* copy user */
        if(ses->userName == NULL) {
-               /* BB what about null user mounts - check that we do this BB */
+               /* null user mount */
+               *bcc_ptr = 0;
+               *(bcc_ptr+1) = 0;
        } else { /* 300 should be long enough for any conceivable user name */
                bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
                                          300, nls_cp);
@@ -98,10 +100,13 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
        bcc_ptr += 2 * bytes_ret;
        bcc_ptr += 2; /* account for null termination */
        /* copy domain */
-       if(ses->domainName == NULL)
-               bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
-                                         "CIFS_LINUX_DOM", 32, nls_cp);
-       else
+       if(ses->domainName == NULL) {
+               /* Sending null domain better than using a bogus domain name (as
+               we did briefly in 2.6.18) since server will use its default */
+               *bcc_ptr = 0;
+               *(bcc_ptr+1) = 0;
+               bytes_ret = 0;
+       } else
                bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 
                                          256, nls_cp);
        bcc_ptr += 2 * bytes_ret;
@@ -144,13 +149,11 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
 
         /* copy domain */
        
-        if(ses->domainName == NULL) {
-                strcpy(bcc_ptr, "CIFS_LINUX_DOM");
-               bcc_ptr += 14;  /* strlen(CIFS_LINUX_DOM) */
-       } else {
+        if(ses->domainName != NULL) {
                 strncpy(bcc_ptr, ses->domainName, 256); 
                bcc_ptr += strnlen(ses->domainName, 256);
-       }
+       } /* else we will send a null domain name 
+            so the server will default to its own domain */
        *bcc_ptr = 0;
        bcc_ptr++;
 
@@ -179,11 +182,14 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf
        cFYI(1,("bleft %d",bleft));
 
 
-       /* word align, if bytes remaining is not even */
-       if(bleft % 2) {
-               bleft--;
-               data++;
-       }
+       /* SMB header is unaligned, so cifs servers word align start of
+          Unicode strings */
+       data++;
+       bleft--; /* Windows servers do not always double null terminate
+                   their final Unicode string - in which case we
+                   now will not attempt to decode the byte of junk
+                   which follows it */
+                   
        words_left = bleft / 2;
 
        /* save off server operating system */
@@ -268,6 +274,10 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
        ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
        if(ses->serverOS)
                strncpy(ses->serverOS, bcc_ptr, len);
+       if(strncmp(ses->serverOS, "OS/2",4) == 0) {
+                       cFYI(1,("OS/2 server"));
+                       ses->flags |= CIFS_SES_OS2;
+       }
 
        bcc_ptr += len + 1;
        bleft -= len + 1;
@@ -290,16 +300,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
         if(len > bleft)
                 return rc;
 
-        if(ses->serverDomain)
-                kfree(ses->serverDomain);
-
-        ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
-        if(ses->serverOS)
-                strncpy(ses->serverOS, bcc_ptr, len);
-
-        bcc_ptr += len + 1;
-       bleft -= len + 1;
-
+       /* No domain field in LANMAN case. Domain is
+          returned by old servers in the SMB negprot response */
+       /* BB For newer servers which do not support Unicode,
+          but thus do return domain here we could add parsing
+          for it later, but it is not very important */
        cFYI(1,("ascii: bytes left %d",bleft));
 
        return rc;
@@ -366,6 +371,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
        str_area = kmalloc(2000, GFP_KERNEL);
        bcc_ptr = str_area;
 
+       ses->flags &= ~CIFS_SES_LANMAN;
+
        if(type == LANMAN) {
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
                char lnm_session_key[CIFS_SESS_KEY_SIZE];
@@ -377,7 +384,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
                /* and copy into bcc */
 
                calc_lanman_hash(ses, lnm_session_key);
-
+               ses->flags |= CIFS_SES_LANMAN; 
 /* #ifdef CONFIG_CIFS_DEBUG2
                cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
                        CIFS_SESS_KEY_SIZE);