Merge ../linux-2.6/
[sfrench/cifs-2.6.git] / fs / cifs / connect.c
index d2ec806a4f32b516cc7a320b39fb3974bc5dd2e2..876eb9ef85fecd83ae57042b2114cdd3b8355e00 100644 (file)
@@ -49,8 +49,6 @@
 
 static DECLARE_COMPLETION(cifsd_complete);
 
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
-                      unsigned char *p24);
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
                         unsigned char *p24);
 
@@ -70,6 +68,7 @@ struct smb_vol {
        gid_t linux_gid;
        mode_t file_mode;
        mode_t dir_mode;
+       unsigned secFlg;
        unsigned rw:1;
        unsigned retry:1;
        unsigned intr:1;
@@ -83,12 +82,7 @@ struct smb_vol {
        unsigned remap:1;   /* set to remap seven reserved chars in filenames */
        unsigned posix_paths:1;   /* unset to not ask for posix pathnames. */
        unsigned sfu_emul:1;
-       unsigned krb5:1;
-       unsigned ntlm:1;
-       unsigned ntlmv2:1;
        unsigned nullauth:1; /* attempt to authenticate with null user */
-       unsigned sign:1;
-       unsigned seal:1;     /* encrypt */
        unsigned nocase;     /* request case insensitive filenames */
        unsigned nobrl;      /* disable sending byte range locks to srv */
        unsigned int rsize;
@@ -369,21 +363,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        continue;
                if (bigbuf == NULL) {
                        bigbuf = cifs_buf_get();
-                       if(bigbuf == NULL) {
-                               cERROR(1,("No memory for large SMB response"));
+                       if (!bigbuf) {
+                               cERROR(1, ("No memory for large SMB response"));
                                msleep(3000);
                                /* retry will check if exiting */
                                continue;
                        }
-               } else if(isLargeBuf) {
-                       /* we are reusing a dirtry large buf, clear its start */
+               } else if (isLargeBuf) {
+                       /* we are reusing a dirty large buf, clear its start */
                        memset(bigbuf, 0, sizeof (struct smb_hdr));
                }
 
                if (smallbuf == NULL) {
                        smallbuf = cifs_small_buf_get();
-                       if(smallbuf == NULL) {
-                               cERROR(1,("No memory for SMB response"));
+                       if (!smallbuf) {
+                               cERROR(1, ("No memory for SMB response"));
                                msleep(1000);
                                /* retry will check if exiting */
                                continue;
@@ -403,12 +397,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                    kernel_recvmsg(csocket, &smb_msg,
                                 &iov, 1, 4, 0 /* BB see socket.h flags */);
 
-               if(server->tcpStatus == CifsExiting) {
+               if (server->tcpStatus == CifsExiting) {
                        break;
                } else if (server->tcpStatus == CifsNeedReconnect) {
-                       cFYI(1,("Reconnect after server stopped responding"));
+                       cFYI(1, ("Reconnect after server stopped responding"));
                        cifs_reconnect(server);
-                       cFYI(1,("call to reconnect done"));
+                       cFYI(1, ("call to reconnect done"));
                        csocket = server->ssocket;
                        continue;
                } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
@@ -417,15 +411,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                tcpStatus CifsNeedReconnect if server hung */
                        continue;
                } else if (length <= 0) {
-                       if(server->tcpStatus == CifsNew) {
-                               cFYI(1,("tcp session abend after SMBnegprot"));
+                       if (server->tcpStatus == CifsNew) {
+                               cFYI(1, ("tcp session abend after SMBnegprot"));
                                /* some servers kill the TCP session rather than
                                   returning an SMB negprot error, in which
                                   case reconnecting here is not going to help,
                                   and so simply return error to mount */
                                break;
                        }
-                       if(length == -EINTR) { 
+                       if (!try_to_freeze() && (length == -EINTR)) {
                                cFYI(1,("cifsd thread killed"));
                                break;
                        }
@@ -585,9 +579,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                                /* merge response - fix up 1st*/
                                                if(coalesce_t2(smb_buffer, 
                                                        mid_entry->resp_buf)) {
+                                                       mid_entry->multiRsp = 1;
                                                        break;
                                                } else {
                                                        /* all parts received */
+                                                       mid_entry->multiEnd = 1;
                                                        goto multi_t2_fnd; 
                                                }
                                        } else {
@@ -632,9 +628,14 @@ multi_t2_fnd:
                        wake_up_process(task_to_wake);
                } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
                    && (isMultiRsp == FALSE)) {                          
-                       cERROR(1, ("No task to wake, unknown frame rcvd!"));
+                       cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter));
                        cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
                                      sizeof(struct smb_hdr));
+#ifdef CONFIG_CIFS_DEBUG2
+                       cifs_dump_detail(smb_buffer);
+                       cifs_dump_mids(server);
+#endif /* CIFS_DEBUG2 */
+                       
                }
        } /* end while !EXITING */
 
@@ -784,7 +785,6 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 
        /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */
        vol->rw = TRUE;
-       vol->ntlm = TRUE;
        /* default is always to request posix paths. */
        vol->posix_paths = 1;
 
@@ -915,30 +915,35 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                                cERROR(1,("no security value specified"));
                                 continue;
                         } else if (strnicmp(value, "krb5i", 5) == 0) {
-                               vol->sign = 1;
-                               vol->krb5 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_KRB5 | 
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "krb5p", 5) == 0) {
-                               /* vol->seal = 1; 
-                                  vol->krb5 = 1; */
+                               /* vol->secFlg |= CIFSSEC_MUST_SEAL | 
+                                       CIFSSEC_MAY_KRB5; */ 
                                cERROR(1,("Krb5 cifs privacy not supported"));
                                return 1;
                        } else if (strnicmp(value, "krb5", 4) == 0) {
-                               vol->krb5 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_KRB5;
                        } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
-                               vol->ntlmv2 = 1;
-                               vol->sign = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlmv2", 6) == 0) {
-                               vol->ntlmv2 = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
                        } else if (strnicmp(value, "ntlmi", 5) == 0) {
-                               vol->ntlm = 1;
-                               vol->sign = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLM |
+                                       CIFSSEC_MUST_SIGN;
                        } else if (strnicmp(value, "ntlm", 4) == 0) {
                                /* ntlm is default so can be turned off too */
-                               vol->ntlm = 1;
+                               vol->secFlg |= CIFSSEC_MAY_NTLM;
                        } else if (strnicmp(value, "nontlm", 6) == 0) {
-                               vol->ntlm = 0;
+                               /* BB is there a better way to do this? */
+                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+                       } else if (strnicmp(value, "lanman", 6) == 0) {
+                                vol->secFlg |= CIFSSEC_MAY_LANMAN;
+#endif
                        } else if (strnicmp(value, "none", 4) == 0) {
-                               vol->nullauth = 1; 
+                               vol->nullauth = 1;
                         } else {
                                 cERROR(1,("bad security option: %s", value));
                                 return 1;
@@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        }
                        /* BB are there cases in which a comma can be valid in
                        a domain name and need special handling? */
-                       if (strnlen(value, 65) < 65) {
+                       if (strnlen(value, 256) < 256) {
                                vol->domainname = value;
                                cFYI(1, ("Domain name set"));
                        } else {
@@ -1168,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                        vol->no_psx_acl = 0;
                } else if (strnicmp(data, "noacl",5) == 0) {
                        vol->no_psx_acl = 1;
+               } else if (strnicmp(data, "sign",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SIGN;
+/*             } else if (strnicmp(data, "seal",4) == 0) {
+                       vol->secFlg |= CIFSSEC_MUST_SEAL; */
                } else if (strnicmp(data, "direct",6) == 0) {
                        vol->direct_io = 1;
                } else if (strnicmp(data, "forcedirectio",13) == 0) {
@@ -1762,11 +1771,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        if (volume_info.username)
                                strncpy(pSesInfo->userName,
                                        volume_info.username,MAX_USERNAME_SIZE);
-                       if (volume_info.domainname)
-                               strncpy(pSesInfo->domainName,
-                                       volume_info.domainname,MAX_USERNAME_SIZE);
+                       if (volume_info.domainname) {
+                               int len = strlen(volume_info.domainname);
+                               pSesInfo->domainName = 
+                                       kmalloc(len + 1, GFP_KERNEL);
+                               if(pSesInfo->domainName)
+                                       strcpy(pSesInfo->domainName,
+                                               volume_info.domainname);
+                       }
                        pSesInfo->linux_uid = volume_info.linux_uid;
+                       pSesInfo->overrideSecFlg = volume_info.secFlg;
                        down(&pSesInfo->sesSem);
+                       /* BB FIXME need to pass vol->secFlgs BB */
                        rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
                        up(&pSesInfo->sesSem);
                        if(!rc)
@@ -1980,7 +1996,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 
 static int
 CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-             char session_key[CIFS_SESSION_KEY_SIZE],
+             char session_key[CIFS_SESS_KEY_SIZE],
              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -2038,15 +2054,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
 
        pSMB->req_no_secext.CaseInsensitivePasswordLength = 
-               cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               cpu_to_le16(CIFS_SESS_KEY_SIZE);
 
        pSMB->req_no_secext.CaseSensitivePasswordLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
-       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE);
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
@@ -2054,7 +2070,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        bcc_ptr++;
                }
                if(user == NULL)
-                       bytes_returned = 0; /* skill null user */
+                       bytes_returned = 0; /* skip null user */
                else
                        bytes_returned =
                                cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
@@ -2148,6 +2164,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
+                               if(ses->serverOS)
+                                       kfree(ses->serverOS);
                                ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL);
                                if(ses->serverOS == NULL)
                                        goto sesssetup_nomem;
@@ -2160,6 +2178,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (remaining_words > 0) {
                                        len = UniStrnlen((wchar_t *)bcc_ptr,
                                                         remaining_words-1);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
@@ -2177,6 +2196,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        if (remaining_words > 0) {
                                                len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words);
           /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(2*(len+1),GFP_KERNEL);
                                                if(ses->serverDomain == NULL)
@@ -2187,15 +2208,20 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                ses->serverDomain[2*len] = 0;
                                                ses->serverDomain[1+(2*len)] = 0;
                                        } /* else no more room so create dummy domain string */
-                                       else
+                                       else {
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
                                                ses->serverDomain = 
                                                        kzalloc(2, GFP_KERNEL);
+                                       }
                                } else {        /* no room so create dummy domain and NOS string */
                                        /* if these kcallocs fail not much we
                                           can do, but better to not fail the
                                           sesssetup itself */
+                                       kfree(ses->serverDomain);
                                        ses->serverDomain =
                                            kzalloc(2, GFP_KERNEL);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS =
                                            kzalloc(2, GFP_KERNEL);
                                }
@@ -2204,6 +2230,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                if (((long) bcc_ptr + len) - (long)
                                    pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
+                                       kfree(ses->serverOS);
                                        ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverOS == NULL)
                                                goto sesssetup_nomem;
@@ -2214,6 +2241,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
+                                       kfree(ses->serverNOS);
                                        ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverNOS == NULL)
                                                goto sesssetup_nomem;
@@ -2223,6 +2251,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        bcc_ptr++;
 
                                        len = strnlen(bcc_ptr, 1024);
+                                       if(ses->serverDomain)
+                                               kfree(ses->serverDomain);
                                        ses->serverDomain = kzalloc(len + 1,GFP_KERNEL);
                                        if(ses->serverDomain == NULL)
                                                goto sesssetup_nomem;
@@ -2254,273 +2284,6 @@ sesssetup_nomem:        /* do not return an error on nomem for the info strings,
        return rc;
 }
 
-static int
-CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
-               char *SecurityBlob,int SecurityBlobLength,
-               const struct nls_table *nls_codepage)
-{
-       struct smb_hdr *smb_buffer;
-       struct smb_hdr *smb_buffer_response;
-       SESSION_SETUP_ANDX *pSMB;
-       SESSION_SETUP_ANDX *pSMBr;
-       char *bcc_ptr;
-       char *user;
-       char *domain;
-       int rc = 0;
-       int remaining_words = 0;
-       int bytes_returned = 0;
-       int len;
-       __u32 capabilities;
-       __u16 count;
-
-       cFYI(1, ("In spnego sesssetup "));
-       if(ses == NULL)
-               return -EINVAL;
-       user = ses->userName;
-       domain = ses->domainName;
-
-       smb_buffer = cifs_buf_get();
-       if (smb_buffer == NULL) {
-               return -ENOMEM;
-       }
-       smb_buffer_response = smb_buffer;
-       pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer;
-
-       /* send SMBsessionSetup here */
-       header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX,
-                       NULL /* no tCon exists yet */ , 12 /* wct */ );
-
-       smb_buffer->Mid = GetNextMid(ses->server);
-       pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
-       pSMB->req.AndXCommand = 0xFF;
-       if(ses->server->maxBuf > 64*1024)
-               ses->server->maxBuf = (64*1023);
-       pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
-       pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
-
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-               smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
-
-       capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
-           CAP_EXTENDED_SECURITY;
-       if (ses->capabilities & CAP_UNICODE) {
-               smb_buffer->Flags2 |= SMBFLG2_UNICODE;
-               capabilities |= CAP_UNICODE;
-       }
-       if (ses->capabilities & CAP_STATUS32) {
-               smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS;
-               capabilities |= CAP_STATUS32;
-       }
-       if (ses->capabilities & CAP_DFS) {
-               smb_buffer->Flags2 |= SMBFLG2_DFS;
-               capabilities |= CAP_DFS;
-       }
-       pSMB->req.Capabilities = cpu_to_le32(capabilities);
-
-       pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength);
-       bcc_ptr = pByteArea(smb_buffer);
-       memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength);
-       bcc_ptr += SecurityBlobLength;
-
-       if (ses->capabilities & CAP_UNICODE) {
-               if ((long) bcc_ptr % 2) {       /* must be word aligned for Unicode strings */
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;  /* convert num of 16 bit words to bytes */
-               bcc_ptr += 2;   /* trailing null */
-               if (domain == NULL)
-                       bytes_returned =
-                           cifs_strtoUCS((__le16 *) bcc_ptr,
-                                         "CIFS_LINUX_DOM", 32, nls_codepage);
-               else
-                       bytes_returned =
-                           cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64,
-                                         nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ",
-                                 32, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
-                                 nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-               bytes_returned =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
-                                 64, nls_codepage);
-               bcc_ptr += 2 * bytes_returned;
-               bcc_ptr += 2;
-       } else {
-               strncpy(bcc_ptr, user, 200);
-               bcc_ptr += strnlen(user, 200);
-               *bcc_ptr = 0;
-               bcc_ptr++;
-               if (domain == NULL) {
-                       strcpy(bcc_ptr, "CIFS_LINUX_DOM");
-                       bcc_ptr += strlen("CIFS_LINUX_DOM") + 1;
-               } else {
-                       strncpy(bcc_ptr, domain, 64);
-                       bcc_ptr += strnlen(domain, 64);
-                       *bcc_ptr = 0;
-                       bcc_ptr++;
-               }
-               strcpy(bcc_ptr, "Linux version ");
-               bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, system_utsname.release);
-               bcc_ptr += strlen(system_utsname.release) + 1;
-               strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
-               bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
-       }
-       count = (long) bcc_ptr - (long) pByteArea(smb_buffer);
-       smb_buffer->smb_buf_length += count;
-       pSMB->req.ByteCount = cpu_to_le16(count);
-
-       rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response,
-                        &bytes_returned, 1);
-       if (rc) {
-/*    rc = map_smb_to_linux_error(smb_buffer_response);  *//* done in SendReceive now */
-       } else if ((smb_buffer_response->WordCount == 3)
-                  || (smb_buffer_response->WordCount == 4)) {
-               __u16 action = le16_to_cpu(pSMBr->resp.Action);
-               __u16 blob_len =
-                   le16_to_cpu(pSMBr->resp.SecurityBlobLength);
-               if (action & GUEST_LOGIN)
-                       cFYI(1, (" Guest login"));      /* BB do we want to set anything in SesInfo struct ? */
-               if (ses) {
-                       ses->Suid = smb_buffer_response->Uid;   /* UID left in wire format (le) */
-                       cFYI(1, ("UID = %d ", ses->Suid));
-                       bcc_ptr = pByteArea(smb_buffer_response);       /* response can have either 3 or 4 word count - Samba sends 3 */
-
-                       /* BB Fix below to make endian neutral !! */
-
-                       if ((pSMBr->resp.hdr.WordCount == 3)
-                           || ((pSMBr->resp.hdr.WordCount == 4)
-                               && (blob_len <
-                                   pSMBr->resp.ByteCount))) {
-                               if (pSMBr->resp.hdr.WordCount == 4) {
-                                       bcc_ptr +=
-                                           blob_len;
-                                       cFYI(1,
-                                            ("Security Blob Length %d ",
-                                             blob_len));
-                               }
-
-                               if (smb_buffer->Flags2 & SMBFLG2_UNICODE) {
-                                       if ((long) (bcc_ptr) % 2) {
-                                               remaining_words =
-                                                   (BCC(smb_buffer_response)
-                                                    - 1) / 2;
-                                               bcc_ptr++;      /* Unicode strings must be word aligned */
-                                       } else {
-                                               remaining_words =
-                                                   BCC
-                                                   (smb_buffer_response) / 2;
-                                       }
-                                       len =
-                                           UniStrnlen((wchar_t *) bcc_ptr,
-                                                      remaining_words - 1);
-/* We look for obvious messed up bcc or strings in response so we do not go off
-   the end since (at least) WIN2K and Windows XP have a major bug in not null
-   terminating last Unicode string in response  */
-                                       ses->serverOS =
-                                           kzalloc(2 * (len + 1), GFP_KERNEL);
-                                       cifs_strfromUCS_le(ses->serverOS,
-                                                          (__le16 *)
-                                                          bcc_ptr, len,
-                                                          nls_codepage);
-                                       bcc_ptr += 2 * (len + 1);
-                                       remaining_words -= len + 1;
-                                       ses->serverOS[2 * len] = 0;
-                                       ses->serverOS[1 + (2 * len)] = 0;
-                                       if (remaining_words > 0) {
-                                               len = UniStrnlen((wchar_t *)bcc_ptr,
-                                                                remaining_words
-                                                                - 1);
-                                               ses->serverNOS =
-                                                   kzalloc(2 * (len + 1),
-                                                           GFP_KERNEL);
-                                               cifs_strfromUCS_le(ses->serverNOS,
-                                                                  (__le16 *)bcc_ptr,
-                                                                  len,
-                                                                  nls_codepage);
-                                               bcc_ptr += 2 * (len + 1);
-                                               ses->serverNOS[2 * len] = 0;
-                                               ses->serverNOS[1 + (2 * len)] = 0;
-                                               remaining_words -= len + 1;
-                                               if (remaining_words > 0) {
-                                                       len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
-                            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
-                                                       ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL);
-                                                       cifs_strfromUCS_le(ses->serverDomain,
-                                                            (__le16 *)bcc_ptr, 
-                                                            len, nls_codepage);
-                                                       bcc_ptr += 2*(len+1);
-                                                       ses->serverDomain[2*len] = 0;
-                                                       ses->serverDomain[1+(2*len)] = 0;
-                                               } /* else no more room so create dummy domain string */
-                                               else
-                                                       ses->serverDomain =
-                                                           kzalloc(2,GFP_KERNEL);
-                                       } else {        /* no room so create dummy domain and NOS string */
-                                               ses->serverDomain = kzalloc(2, GFP_KERNEL);
-                                               ses->serverNOS = kzalloc(2, GFP_KERNEL);
-                                       }
-                               } else {        /* ASCII */
-
-                                       len = strnlen(bcc_ptr, 1024);
-                                       if (((long) bcc_ptr + len) - (long)
-                                           pByteArea(smb_buffer_response)
-                                           <= BCC(smb_buffer_response)) {
-                                               ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
-                                               strncpy(ses->serverOS, bcc_ptr, len);
-
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0; /* null terminate the string */
-                                               bcc_ptr++;
-
-                                               len = strnlen(bcc_ptr, 1024);
-                                               ses->serverNOS = kzalloc(len + 1,GFP_KERNEL);
-                                               strncpy(ses->serverNOS, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-
-                                               len = strnlen(bcc_ptr, 1024);
-                                               ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
-                                               strncpy(ses->serverDomain, bcc_ptr, len);
-                                               bcc_ptr += len;
-                                               bcc_ptr[0] = 0;
-                                               bcc_ptr++;
-                                       } else
-                                               cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb ",
-                                                     len));
-                               }
-                       } else {
-                               cERROR(1,
-                                      (" Security Blob Length extends beyond end of SMB"));
-                       }
-               } else {
-                       cERROR(1, ("No session structure passed in."));
-               }
-       } else {
-               cERROR(1,
-                      (" Invalid Word count %d: ",
-                       smb_buffer_response->WordCount));
-               rc = -EIO;
-       }
-
-       if (smb_buffer)
-               cifs_buf_release(smb_buffer);
-
-       return rc;
-}
-
 static int
 CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                              struct cifsSesInfo *ses, int * pNTLMv2_flag,
@@ -2597,8 +2360,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
            /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
        if(sign_CIFS_PDUs)
                negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
-       if(ntlmv2_support)
-               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;
+/*     if(ntlmv2_support)
+               negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/
        /* setup pointers to domain name and workstation name */
        bcc_ptr += SecurityBlobLength;
 
@@ -2728,6 +2491,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 /* We look for obvious messed up bcc or strings in response so we do not go off
    the end since (at least) WIN2K and Windows XP have a major bug in not null
    terminating last Unicode string in response  */
+                                       if(ses->serverOS)
+                                               kfree(ses->serverOS);
                                        ses->serverOS =
                                            kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
@@ -2743,6 +2508,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -2760,6 +2526,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                if (remaining_words > 0) {
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
            /* last string is not always null terminated (for e.g. for Windows XP & 2000) */
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2 *
                                                                    (len +
@@ -2777,13 +2544,17 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                [1 + (2 * len)]
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
-                                               else
+                                               else {
+                                                       kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2,
                                                                    GFP_KERNEL);
+                                               }
                                        } else {        /* no room so create dummy domain and NOS string */
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(2, GFP_KERNEL);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2, GFP_KERNEL);
                                        }
@@ -2792,6 +2563,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                        if (((long) bcc_ptr + len) - (long)
                                            pByteArea(smb_buffer_response)
                                            <= BCC(smb_buffer_response)) {
+                                               if(ses->serverOS)
+                                                       kfree(ses->serverOS);
                                                ses->serverOS =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2803,6 +2576,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2812,6 +2586,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
+                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2937,14 +2712,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SecurityBlob->LmChallengeResponse.Buffer = 0;
 
        SecurityBlob->NtChallengeResponse.Length =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.MaximumLength =
-           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
-       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
+           cpu_to_le16(CIFS_SESS_KEY_SIZE);
+       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.Buffer =
            cpu_to_le32(SecurityBlobLength);
-       SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
-       bcc_ptr += CIFS_SESSION_KEY_SIZE;
+       SecurityBlobLength += CIFS_SESS_KEY_SIZE;
+       bcc_ptr += CIFS_SESS_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if (domain == NULL) {
@@ -3116,6 +2891,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 /* We look for obvious messed up bcc or strings in response so we do not go off
   the end since (at least) WIN2K and Windows XP have a major bug in not null
   terminating last Unicode string in response  */
+                                       if(ses->serverOS)
+                                               kfree(ses->serverOS);
                                        ses->serverOS =
                                            kzalloc(2 * (len + 1), GFP_KERNEL);
                                        cifs_strfromUCS_le(ses->serverOS,
@@ -3131,6 +2908,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -3147,6 +2925,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                if (remaining_words > 0) {
                                                        len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); 
      /* last string not always null terminated (e.g. for Windows XP & 2000) */
+                                                       if(ses->serverDomain)
+                                                               kfree(ses->serverDomain);
                                                        ses->serverDomain =
                                                            kzalloc(2 *
                                                                    (len +
@@ -3172,10 +2952,16 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                          len)]
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
-                                               else
+                                               else {
+                                                       if(ses->serverDomain)
+                                                               kfree(ses->serverDomain);
                                                        ses->serverDomain = kzalloc(2,GFP_KERNEL);
+                                               }
                                        } else {  /* no room so create dummy domain and NOS string */
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
                                                ses->serverDomain = kzalloc(2, GFP_KERNEL);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS = kzalloc(2, GFP_KERNEL);
                                        }
                                } else {        /* ASCII */
@@ -3183,6 +2969,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                        if (((long) bcc_ptr + len) - 
                         (long) pByteArea(smb_buffer_response) 
                             <= BCC(smb_buffer_response)) {
+                                               if(ses->serverOS)
+                                                       kfree(ses->serverOS);
                                                ses->serverOS = kzalloc(len + 1,GFP_KERNEL);
                                                strncpy(ses->serverOS,bcc_ptr, len);
 
@@ -3191,6 +2979,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
+                                               kfree(ses->serverNOS);
                                                ses->serverNOS = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverNOS, bcc_ptr, len);  
                                                bcc_ptr += len;
@@ -3198,6 +2987,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
+                                               if(ses->serverDomain)
+                                                       kfree(ses->serverDomain);
                                                ses->serverDomain = kzalloc(len+1,GFP_KERNEL);
                                                strncpy(ses->serverDomain, bcc_ptr, len);
                                                bcc_ptr += len;
@@ -3264,25 +3055,37 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        bcc_ptr = &pSMB->Password[0];
        if((ses->server->secMode) & SECMODE_USER) {
                pSMB->PasswordLength = cpu_to_le16(1);  /* minimum */
+               *bcc_ptr = 0; /* password is null byte */
                bcc_ptr++;              /* skip password */
+               /* already aligned so no need to do it below */
        } else {
-               pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+               pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
                /* BB FIXME add code to fail this if NTLMv2 or Kerberos
                   specified as required (when that support is added to
                   the vfs in the future) as only NTLM or the much
-                  weaker LANMAN (which we do not send) is accepted
+                  weaker LANMAN (which we do not send by default) is accepted
                   by Samba (not sure whether other servers allow
                   NTLMv2 password here) */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+               if((extended_security & CIFSSEC_MAY_LANMAN) && 
+                       (ses->server->secType == LANMAN))
+                       calc_lanman_hash(ses, bcc_ptr);
+               else
+#endif /* CIFS_WEAK_PW_HASH */
                SMBNTencrypt(ses->password,
                             ses->server->cryptKey,
                             bcc_ptr);
 
-               bcc_ptr += CIFS_SESSION_KEY_SIZE;
-               *bcc_ptr = 0;
-               bcc_ptr++; /* align */
+               bcc_ptr += CIFS_SESS_KEY_SIZE;
+               if(ses->capabilities & CAP_UNICODE) {
+                       /* must align unicode strings */
+                       *bcc_ptr = 0; /* null byte password */
+                       bcc_ptr++;
+               }
        }
 
-       if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+       if(ses->server->secMode & 
+                       (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
                smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
        if (ses->capabilities & CAP_STATUS32) {
@@ -3294,8 +3097,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        if (ses->capabilities & CAP_UNICODE) {
                smb_buffer->Flags2 |= SMBFLG2_UNICODE;
                length =
-                   cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage);
-               bcc_ptr += 2 * length;  /* convert num of 16 bit words to bytes */
+                   cifs_strtoUCS((__le16 *) bcc_ptr, tree, 
+                       6 /* max utf8 char length in bytes */ * 
+                       (/* server len*/ + 256 /* share len */), nls_codepage);
+               bcc_ptr += 2 * length;  /* convert num 16 bit words to bytes */
                bcc_ptr += 2;   /* skip trailing null */
        } else {                /* ASCII */
                strcpy(bcc_ptr, tree);
@@ -3350,7 +3155,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        }
                        /* else do not bother copying these informational fields */
                }
-               tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               if(smb_buffer_response->WordCount == 3)
+                       tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
+               else
+                       tcon->Flags = 0;
                cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
        } else if ((rc == 0) && tcon == NULL) {
         /* all we need to save for IPC$ connection */
@@ -3415,7 +3223,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                           struct nls_table * nls_info)
 {
        int rc = 0;
-       char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+       char ntlm_session_key[CIFS_SESS_KEY_SIZE];
        int ntlmv2_flag = FALSE;
        int first_time = 0;
 
@@ -3447,20 +3255,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
                        pSesInfo->server->timeZone));
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-               if(experimEnabled > 1)
-                       rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
-                                           &ntlmv2_flag, nls_info);    
-               else
-#endif
-               if (extended_security
+               if(experimEnabled < 2)
+                       rc = CIFS_SessSetup(xid, pSesInfo,
+                                           first_time, nls_info);
+               else if (extended_security
                                && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
-                       cFYI(1, ("New style sesssetup"));
-                       rc = CIFSSpnegoSessSetup(xid, pSesInfo,
-                               NULL /* security blob */, 
-                               0 /* blob length */,
-                               nls_info);
+                       rc = -EOPNOTSUPP;
                } else if (extended_security
                           && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                           && (pSesInfo->server->secType == RawNTLMSSP)) {