linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / fs / cifs / connect.c
index 5d394c7..ddc5118 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *   fs/cifs/connect.c
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2006
+ *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -49,6 +49,8 @@
 
 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);
 
@@ -68,7 +70,6 @@ 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;
@@ -82,7 +83,12 @@ 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;
@@ -364,21 +370,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        continue;
                if (bigbuf == NULL) {
                        bigbuf = cifs_buf_get();
-                       if (!bigbuf) {
-                               cERROR(1, ("No memory for large SMB response"));
+                       if(bigbuf == NULL) {
+                               cERROR(1,("No memory for large SMB response"));
                                msleep(3000);
                                /* retry will check if exiting */
                                continue;
                        }
-               } else if (isLargeBuf) {
-                       /* we are reusing a dirty large buf, clear its start */
+               } else if(isLargeBuf) {
+                       /* we are reusing a dirtry large buf, clear its start */
                        memset(bigbuf, 0, sizeof (struct smb_hdr));
                }
 
                if (smallbuf == NULL) {
                        smallbuf = cifs_small_buf_get();
-                       if (!smallbuf) {
-                               cERROR(1, ("No memory for SMB response"));
+                       if(smallbuf == NULL) {
+                               cERROR(1,("No memory for SMB response"));
                                msleep(1000);
                                /* retry will check if exiting */
                                continue;
@@ -398,12 +404,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)) {
@@ -412,15 +418,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 (!try_to_freeze() && (length == -EINTR)) {
+                       if(length == -EINTR) { 
                                cFYI(1,("cifsd thread killed"));
                                break;
                        }
@@ -559,7 +565,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        
 
                dump_smb(smb_buffer, length);
-               if (checkSMB(smb_buffer, smb_buffer->Mid, total_read+4)) {
+               if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) {
                        cifs_dump_mem("Bad SMB: ", smb_buffer, 48);
                        continue;
                }
@@ -580,11 +586,9 @@ 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 {
@@ -613,10 +617,6 @@ multi_t2_fnd:
 #ifdef CONFIG_CIFS_STATS2
                                mid_entry->when_received = jiffies;
 #endif
-                               /* so we do not time out requests to  server
-                               which is still responding (since server could
-                               be busy but not dead) */
-                               server->lstrp = jiffies;
                                break;
                        }
                }
@@ -633,14 +633,9 @@ 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! NumMids %d", midCount.counter));
+                       cERROR(1, ("No task to wake, unknown frame rcvd!"));
                        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 */
 
@@ -790,6 +785,7 @@ 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;
 
@@ -920,35 +916,30 @@ 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->secFlg |= CIFSSEC_MAY_KRB5 | 
-                                       CIFSSEC_MUST_SIGN;
+                               vol->sign = 1;
+                               vol->krb5 = 1;
                        } else if (strnicmp(value, "krb5p", 5) == 0) {
-                               /* vol->secFlg |= CIFSSEC_MUST_SEAL | 
-                                       CIFSSEC_MAY_KRB5; */ 
+                               /* vol->seal = 1; 
+                                  vol->krb5 = 1; */
                                cERROR(1,("Krb5 cifs privacy not supported"));
                                return 1;
                        } else if (strnicmp(value, "krb5", 4) == 0) {
-                               vol->secFlg |= CIFSSEC_MAY_KRB5;
+                               vol->krb5 = 1;
                        } else if (strnicmp(value, "ntlmv2i", 7) == 0) {
-                               vol->secFlg |= CIFSSEC_MAY_NTLMV2 |
-                                       CIFSSEC_MUST_SIGN;
+                               vol->ntlmv2 = 1;
+                               vol->sign = 1;
                        } else if (strnicmp(value, "ntlmv2", 6) == 0) {
-                               vol->secFlg |= CIFSSEC_MAY_NTLMV2;
+                               vol->ntlmv2 = 1;
                        } else if (strnicmp(value, "ntlmi", 5) == 0) {
-                               vol->secFlg |= CIFSSEC_MAY_NTLM |
-                                       CIFSSEC_MUST_SIGN;
+                               vol->ntlm = 1;
+                               vol->sign = 1;
                        } else if (strnicmp(value, "ntlm", 4) == 0) {
                                /* ntlm is default so can be turned off too */
-                               vol->secFlg |= CIFSSEC_MAY_NTLM;
+                               vol->ntlm = 1;
                        } else if (strnicmp(value, "nontlm", 6) == 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
+                               vol->ntlm = 0;
                        } else if (strnicmp(value, "none", 4) == 0) {
-                               vol->nullauth = 1;
+                               vol->nullauth = 1; 
                         } else {
                                 cERROR(1,("bad security option: %s", value));
                                 return 1;
@@ -986,7 +977,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, 256) < 256) {
+                       if (strnlen(value, 65) < 65) {
                                vol->domainname = value;
                                cFYI(1, ("Domain name set"));
                        } else {
@@ -1178,10 +1169,6 @@ 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) {
@@ -1271,35 +1258,33 @@ find_unc(__be32 new_target_ip_addr, char *uncName, char *userName)
 
        read_lock(&GlobalSMBSeslock);
        list_for_each(tmp, &GlobalTreeConnectionList) {
-               cFYI(1, ("Next tcon"));
+               cFYI(1, ("Next tcon - "));
                tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
                if (tcon->ses) {
                        if (tcon->ses->server) {
                                cFYI(1,
-                                    ("old ip addr: %x == new ip %x ?",
+                                    (" old ip addr: %x == new ip %x ?",
                                      tcon->ses->server->addr.sockAddr.sin_addr.
                                      s_addr, new_target_ip_addr));
                                if (tcon->ses->server->addr.sockAddr.sin_addr.
                                    s_addr == new_target_ip_addr) {
-       /* BB lock tcon, server and tcp session and increment use count here? */
+       /* BB lock tcon and server and tcp session and increment use count here? */
                                        /* found a match on the TCP session */
                                        /* BB check if reconnection needed */
-                                       cFYI(1,("IP match, old UNC: %s new: %s",
+                                       cFYI(1,("Matched ip, old UNC: %s == new: %s ?",
                                              tcon->treeName, uncName));
                                        if (strncmp
                                            (tcon->treeName, uncName,
                                             MAX_TREE_SIZE) == 0) {
                                                cFYI(1,
-                                                    ("and old usr: %s new: %s",
+                                                    ("Matched UNC, old user: %s == new: %s ?",
                                                      tcon->treeName, uncName));
                                                if (strncmp
                                                    (tcon->ses->userName,
                                                     userName,
                                                     MAX_USERNAME_SIZE) == 0) {
                                                        read_unlock(&GlobalSMBSeslock);
-                                                       /* matched smb session
-                                                       (user name */
-                                                       return tcon;
+                                                       return tcon;/* also matched user (smb session)*/
                                                }
                                        }
                                }
@@ -1492,14 +1477,6 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
                        rc = smb_send(*csocket, smb_buf, 0x44,
                                (struct sockaddr *)psin_server);
                        kfree(ses_init_buf);
-                       msleep(1); /* RFC1001 layer in at least one server 
-                                     requires very short break before negprot
-                                     presumably because not expecting negprot
-                                     to follow so fast.  This is a simple
-                                     solution that works without 
-                                     complicating the code and causes no
-                                     significant slowing down on mount
-                                     for everyone else */
                }
                /* else the negprot may still work without this 
                even though malloc failed */
@@ -1778,18 +1755,11 @@ 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) {
-                               int len = strlen(volume_info.domainname);
-                               pSesInfo->domainName = 
-                                       kmalloc(len + 1, GFP_KERNEL);
-                               if(pSesInfo->domainName)
-                                       strcpy(pSesInfo->domainName,
-                                               volume_info.domainname);
-                       }
+                       if (volume_info.domainname)
+                               strncpy(pSesInfo->domainName,
+                                       volume_info.domainname,MAX_USERNAME_SIZE);
                        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)
@@ -1951,45 +1921,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                cifs_sb->tcon = tcon;
                tcon->ses = pSesInfo;
 
-               /* do not care if following two calls succeed - informational */
+               /* do not care if following two calls succeed - informational only */
                CIFSSMBQFSDeviceInfo(xid, tcon);
                CIFSSMBQFSAttributeInfo(xid, tcon);
-
                if (tcon->ses->capabilities & CAP_UNIX) {
                        if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
-                               __u64 cap = 
-                                      le64_to_cpu(tcon->fsUnixInfo.Capability);
-                               cap &= CIFS_UNIX_CAP_MASK;
-                               if(volume_info.no_psx_acl)
-                                       cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
-                               else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
-                                       cFYI(1,("negotiated posix acl support"));
-                                       sb->s_flags |= MS_POSIXACL;
+                               if(!volume_info.no_psx_acl) {
+                                       if(CIFS_UNIX_POSIX_ACL_CAP & 
+                                          le64_to_cpu(tcon->fsUnixInfo.Capability))
+                                               cFYI(1,("server negotiated posix acl support"));
+                                               sb->s_flags |= MS_POSIXACL;
                                }
 
-                               if(volume_info.posix_paths == 0)
-                                       cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
-                               else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
-                                       cFYI(1,("negotiate posix pathnames"));
-                                       cifs_sb->mnt_cifs_flags |= 
-                                               CIFS_MOUNT_POSIX_PATHS;
-                               }
-                                       
-                               cFYI(1,("Negotiate caps 0x%x",(int)cap));
-#ifdef CONFIG_CIFS_DEBUG2
-                               if(cap & CIFS_UNIX_FCNTL_CAP)
-                                       cFYI(1,("FCNTL cap"));
-                               if(cap & CIFS_UNIX_EXTATTR_CAP)
-                                       cFYI(1,("EXTATTR cap"));
-                               if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
-                                       cFYI(1,("POSIX path cap"));
-                               if(cap & CIFS_UNIX_XATTR_CAP)
-                                       cFYI(1,("XATTR cap"));
-                               if(cap & CIFS_UNIX_POSIX_ACL_CAP)
-                                       cFYI(1,("POSIX ACL cap"));
-#endif /* CIFS_DEBUG2 */
-                               if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
-                                       cFYI(1,("setting capabilities failed"));
+                               /* Try and negotiate POSIX pathnames if we can. */
+                               if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP &
+                                   le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+                                       if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP))  {
+                                               cFYI(1,("negotiated posix pathnames support"));
+                                               cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS;
+                                       } else {
+                                               cFYI(1,("posix pathnames support requested but not supported"));
+                                       }
                                }
                        }
                }
@@ -2014,7 +1966,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_SESS_KEY_SIZE],
+             char session_key[CIFS_SESSION_KEY_SIZE],
              const struct nls_table *nls_codepage)
 {
        struct smb_hdr *smb_buffer;
@@ -2072,15 +2024,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_SESS_KEY_SIZE);
+               cpu_to_le16(CIFS_SESSION_KEY_SIZE);
 
        pSMB->req_no_secext.CaseSensitivePasswordLength =
-           cpu_to_le16(CIFS_SESS_KEY_SIZE);
+           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
        bcc_ptr = pByteArea(smb_buffer);
-       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;
+       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;
 
        if (ses->capabilities & CAP_UNICODE) {
                if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */
@@ -2088,7 +2040,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                        bcc_ptr++;
                }
                if(user == NULL)
-                       bytes_returned = 0; /* skip null user */
+                       bytes_returned = 0; /* skill null user */
                else
                        bytes_returned =
                                cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
@@ -2182,8 +2134,6 @@ 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;
@@ -2196,7 +2146,6 @@ 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;
@@ -2214,8 +2163,6 @@ 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)
@@ -2226,20 +2173,15 @@ 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 {
-                                               if(ses->serverDomain)
-                                                       kfree(ses->serverDomain);
+                                       else
                                                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);
                                }
@@ -2248,7 +2190,6 @@ 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;
@@ -2259,7 +2200,6 @@ 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;
@@ -2269,8 +2209,6 @@ 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;
@@ -2302,6 +2240,271 @@ 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;
+       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,
@@ -2323,7 +2526,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        __u32 negotiate_flags, capabilities;
        __u16 count;
 
-       cFYI(1, ("In NTLMSSP sesssetup (negotiate)"));
+       cFYI(1, ("In NTLMSSP sesssetup (negotiate) "));
        if(ses == NULL)
                return -EINVAL;
        domain = ses->domainName;
@@ -2373,13 +2576,12 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        SecurityBlob->MessageType = NtLmNegotiate;
        negotiate_flags =
            NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM |
-           NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM |
-           NTLMSSP_NEGOTIATE_56 |
+           NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | 0x80000000 |
            /* 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;
 
@@ -2387,11 +2589,26 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        SecurityBlob->WorkstationName.Length = 0;
        SecurityBlob->WorkstationName.MaximumLength = 0;
 
-       /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent
-       along with username on auth request (ie the response to challenge) */
-       SecurityBlob->DomainName.Buffer = 0;
-       SecurityBlob->DomainName.Length = 0;
-       SecurityBlob->DomainName.MaximumLength = 0;
+       if (domain == NULL) {
+               SecurityBlob->DomainName.Buffer = 0;
+               SecurityBlob->DomainName.Length = 0;
+               SecurityBlob->DomainName.MaximumLength = 0;
+       } else {
+               __u16 len;
+               negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED;
+               strncpy(bcc_ptr, domain, 63);
+               len = strnlen(domain, 64);
+               SecurityBlob->DomainName.MaximumLength =
+                   cpu_to_le16(len);
+               SecurityBlob->DomainName.Buffer =
+                   cpu_to_le32((long) &SecurityBlob->
+                               DomainString -
+                               (long) &SecurityBlob->Signature);
+               bcc_ptr += len;
+               SecurityBlobLength += len;
+               SecurityBlob->DomainName.Length =
+                   cpu_to_le16(len);
+       }
        if (ses->capabilities & CAP_UNICODE) {
                if ((long) bcc_ptr % 2) {
                        *bcc_ptr = 0;
@@ -2461,7 +2678,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                              SecurityBlob2->MessageType));
                } else if (ses) {
                        ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ 
-                       cFYI(1, ("UID = %d", ses->Suid));
+                       cFYI(1, ("UID = %d ", ses->Suid));
                        if ((pSMBr->resp.hdr.WordCount == 3)
                            || ((pSMBr->resp.hdr.WordCount == 4)
                                && (blob_len <
@@ -2469,17 +2686,17 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 
                                if (pSMBr->resp.hdr.WordCount == 4) {
                                        bcc_ptr += blob_len;
-                                       cFYI(1, ("Security Blob Length %d",
+                                       cFYI(1,
+                                            ("Security Blob Length %d ",
                                              blob_len));
                                }
 
-                               cFYI(1, ("NTLMSSP Challenge rcvd"));
+                               cFYI(1, ("NTLMSSP Challenge rcvd "));
 
                                memcpy(ses->server->cryptKey,
                                       SecurityBlob2->Challenge,
                                       CIFS_CRYPTO_KEY_SIZE);
-                               if(SecurityBlob2->NegotiateFlags & 
-                                       cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
+                               if(SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2))
                                        *pNTLMv2_flag = TRUE;
 
                                if((SecurityBlob2->NegotiateFlags & 
@@ -2509,8 +2726,6 @@ 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,
@@ -2526,7 +2741,6 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
-                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -2544,7 +2758,6 @@ 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 +
@@ -2562,17 +2775,13 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                                [1 + (2 * len)]
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
-                                               else {
-                                                       kfree(ses->serverDomain);
+                                               else
                                                        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);
                                        }
@@ -2581,8 +2790,6 @@ 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);
@@ -2594,7 +2801,6 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2604,7 +2810,6 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
 
                                                len = strnlen(bcc_ptr, 1024);
-                                               kfree(ses->serverDomain);
                                                ses->serverDomain =
                                                    kzalloc(len + 1,
                                                            GFP_KERNEL);
@@ -2614,7 +2819,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                                bcc_ptr++;
                                        } else
                                                cFYI(1,
-                                                    ("Variable field of length %d extends beyond end of smb",
+                                                    ("Variable field of length %d extends beyond end of smb ",
                                                      len));
                                }
                        } else {
@@ -2626,7 +2831,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                }
        } else {
                cERROR(1,
-                      (" Invalid Word count %d:",
+                      (" Invalid Word count %d: ",
                        smb_buffer_response->WordCount));
                rc = -EIO;
        }
@@ -2730,14 +2935,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
        SecurityBlob->LmChallengeResponse.Buffer = 0;
 
        SecurityBlob->NtChallengeResponse.Length =
-           cpu_to_le16(CIFS_SESS_KEY_SIZE);
+           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.MaximumLength =
-           cpu_to_le16(CIFS_SESS_KEY_SIZE);
-       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE);
+           cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+       memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE);
        SecurityBlob->NtChallengeResponse.Buffer =
            cpu_to_le32(SecurityBlobLength);
-       SecurityBlobLength += CIFS_SESS_KEY_SIZE;
-       bcc_ptr += CIFS_SESS_KEY_SIZE;
+       SecurityBlobLength += CIFS_SESSION_KEY_SIZE;
+       bcc_ptr += CIFS_SESSION_KEY_SIZE;
 
        if (ses->capabilities & CAP_UNICODE) {
                if (domain == NULL) {
@@ -2909,8 +3114,6 @@ 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,
@@ -2926,7 +3129,6 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                 bcc_ptr,
                                                                 remaining_words
                                                                 - 1);
-                                               kfree(ses->serverNOS);
                                                ses->serverNOS =
                                                    kzalloc(2 * (len + 1),
                                                            GFP_KERNEL);
@@ -2943,8 +3145,6 @@ 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 +
@@ -2970,16 +3170,10 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                                                          len)]
                                                            = 0;
                                                } /* else no more room so create dummy domain string */
-                                               else {
-                                                       if(ses->serverDomain)
-                                                               kfree(ses->serverDomain);
+                                               else
                                                        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 */
@@ -2987,8 +3181,6 @@ 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);
 
@@ -2997,7 +3189,6 @@ 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;
@@ -3005,8 +3196,6 @@ 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;
@@ -3073,37 +3262,25 @@ 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_SESS_KEY_SIZE);
+               pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_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 by default) is accepted
+                  weaker LANMAN (which we do not send) 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_SESS_KEY_SIZE;
-               if(ses->capabilities & CAP_UNICODE) {
-                       /* must align unicode strings */
-                       *bcc_ptr = 0; /* null byte password */
-                       bcc_ptr++;
-               }
+               bcc_ptr += CIFS_SESSION_KEY_SIZE;
+               *bcc_ptr = 0;
+               bcc_ptr++; /* align */
        }
 
-       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) {
@@ -3115,10 +3292,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
        if (ses->capabilities & CAP_UNICODE) {
                smb_buffer->Flags2 |= SMBFLG2_UNICODE;
                length =
-                   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 */
+                   cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage);
+               bcc_ptr += 2 * length;  /* convert num of 16 bit words to bytes */
                bcc_ptr += 2;   /* skip trailing null */
        } else {                /* ASCII */
                strcpy(bcc_ptr, tree);
@@ -3173,10 +3348,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        }
                        /* else do not bother copying these informational fields */
                }
-               if(smb_buffer_response->WordCount == 3)
-                       tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
-               else
-                       tcon->Flags = 0;
+               tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
                cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
        } else if ((rc == 0) && tcon == NULL) {
         /* all we need to save for IPC$ connection */
@@ -3241,7 +3413,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                           struct nls_table * nls_info)
 {
        int rc = 0;
-       char ntlm_session_key[CIFS_SESS_KEY_SIZE];
+       char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
        int ntlmv2_flag = FALSE;
        int first_time = 0;
 
@@ -3273,17 +3445,18 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
                        pSesInfo->server->timeZone));
-               if(experimEnabled < 2)
-                       rc = CIFS_SessSetup(xid, pSesInfo,
-                                           first_time, nls_info);
-               else if (extended_security
+               if (extended_security
                                && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
-                       rc = -EOPNOTSUPP;
+                       cFYI(1, ("New style sesssetup "));
+                       rc = CIFSSpnegoSessSetup(xid, pSesInfo,
+                               NULL /* security blob */, 
+                               0 /* blob length */,
+                               nls_info);
                } else if (extended_security
                           && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
                           && (pSesInfo->server->secType == RawNTLMSSP)) {
-                       cFYI(1, ("NTLMSSP sesssetup"));
+                       cFYI(1, ("NTLMSSP sesssetup "));
                        rc = CIFSNTLMSSPNegotiateSessSetup(xid,
                                                pSesInfo,
                                                &ntlmv2_flag,