浏览代码

[CIFS] Support for setting up SMB sessions to legacy lanman servers

Steve French 19 年之前
父节点
当前提交
3979877e56
共有 20 个文件被更改,包括 837 次插入76 次删除
  1. 38 2
      fs/Kconfig
  2. 5 0
      fs/cifs/CHANGES
  3. 1 1
      fs/cifs/Makefile
  4. 71 13
      fs/cifs/cifs_debug.c
  5. 4 0
      fs/cifs/cifs_debug.h
  6. 1 0
      fs/cifs/cifs_unicode.c
  7. 2 0
      fs/cifs/cifsencrypt.c
  8. 2 2
      fs/cifs/cifsfs.c
  9. 37 14
      fs/cifs/cifsglob.h
  10. 31 6
      fs/cifs/cifspdu.h
  11. 1 1
      fs/cifs/cifsproto.h
  12. 85 10
      fs/cifs/cifssmb.c
  13. 26 13
      fs/cifs/connect.c
  14. 1 1
      fs/cifs/dir.c
  15. 2 2
      fs/cifs/fcntl.c
  16. 2 1
      fs/cifs/inode.c
  17. 6 4
      fs/cifs/misc.c
  18. 10 6
      fs/cifs/readdir.c
  19. 511 0
      fs/cifs/sess.c
  20. 1 0
      fs/cifs/smbencrypt.c

+ 38 - 2
fs/Kconfig

@@ -1663,7 +1663,7 @@ config CIFS_STATS
 	  mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
 	  mounted by the cifs client to be displayed in /proc/fs/cifs/Stats
 
 
 config CIFS_STATS2
 config CIFS_STATS2
-	bool "CIFS extended statistics"
+	bool "Extended statistics"
 	depends on CIFS_STATS
 	depends on CIFS_STATS
 	help
 	help
 	  Enabling this option will allow more detailed statistics on SMB
 	  Enabling this option will allow more detailed statistics on SMB
@@ -1676,6 +1676,32 @@ config CIFS_STATS2
 	  Unless you are a developer or are doing network performance analysis
 	  Unless you are a developer or are doing network performance analysis
 	  or tuning, say N.
 	  or tuning, say N.
 
 
+config CIFS_WEAK_PW_HASH
+	bool "Support legacy servers which use weaker LANMAN security"
+	depends on CIFS
+	help
+	  Modern CIFS servers including Samba and most Windows versions
+	  (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos)
+	  security mechanisms. These hash the password more securely
+	  than the mechanisms used in the older LANMAN version of the
+          SMB protocol needed to establish sessions with old SMB servers.
+
+	  Enabling this option allows the cifs module to mount to older
+	  LANMAN based servers such as OS/2 and Windows 95, but such
+	  mounts may be less secure than mounts using NTLM or more recent
+	  security mechanisms if you are on a public network.  Unless you
+	  have a need to access old SMB servers (and are on a private 
+	  network) you probably want to say N.  Even if this support
+	  is enabled in the kernel build, they will not be used
+	  automatically. At runtime LANMAN mounts are disabled but
+	  can be set to required (or optional) either in
+	  /proc/fs/cifs (see fs/cifs/README for more detail) or via an
+	  option on the mount command. This support is disabled by 
+	  default in order to reduce the possibility of a downgrade
+	  attack.
+ 
+	  If unsure, say N.
+
 config CIFS_XATTR
 config CIFS_XATTR
         bool "CIFS extended attributes"
         bool "CIFS extended attributes"
         depends on CIFS
         depends on CIFS
@@ -1704,6 +1730,16 @@ config CIFS_POSIX
 	  (such as Samba 3.10 and later) which can negotiate
 	  (such as Samba 3.10 and later) which can negotiate
 	  CIFS POSIX ACL support.  If unsure, say N.
 	  CIFS POSIX ACL support.  If unsure, say N.
 
 
+config CIFS_DEBUG2
+	bool "Enable additional CIFS debugging routines
+	help
+	   Enabling this option adds a few more debugging routines
+	   to the cifs code which slightly increases the size of
+	   the cifs module and can cause additional logging of debug
+	   messages in some error paths, slowing performance. This
+	   option can be turned off unless you are debugging
+	   cifs problems.  If unsure, say N.
+	   
 config CIFS_EXPERIMENTAL
 config CIFS_EXPERIMENTAL
 	  bool "CIFS Experimental Features (EXPERIMENTAL)"
 	  bool "CIFS Experimental Features (EXPERIMENTAL)"
 	  depends on CIFS && EXPERIMENTAL
 	  depends on CIFS && EXPERIMENTAL
@@ -1719,7 +1755,7 @@ config CIFS_EXPERIMENTAL
 	    If unsure, say N.
 	    If unsure, say N.
 
 
 config CIFS_UPCALL
 config CIFS_UPCALL
-	  bool "CIFS Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
+	  bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
 	  depends on CIFS_EXPERIMENTAL
 	  depends on CIFS_EXPERIMENTAL
 	  select CONNECTOR
 	  select CONNECTOR
 	  help
 	  help

+ 5 - 0
fs/cifs/CHANGES

@@ -1,3 +1,8 @@
+Version 1.44
+------------
+Rewritten sessionsetup support, including support for legacy SMB
+session setup needed for OS/2 and older servers such as Windows 95 and 98.
+
 Version 1.43
 Version 1.43
 ------------
 ------------
 POSIX locking to servers which support CIFS POSIX Extensions
 POSIX locking to servers which support CIFS POSIX Extensions

+ 1 - 1
fs/cifs/Makefile

@@ -3,4 +3,4 @@
 #
 #
 obj-$(CONFIG_CIFS) += cifs.o
 obj-$(CONFIG_CIFS) += cifs.o
 
 
-cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o ntlmssp.o
+cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o

+ 71 - 13
fs/cifs/cifs_debug.c

@@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length)
 	char *charptr = data;
 	char *charptr = data;
 	char buf[10], line[80];
 	char buf[10], line[80];
 
 
-	printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", 
+	printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n", 
 		label, length, data);
 		label, length, data);
 	for (i = 0; i < length; i += 16) {
 	for (i = 0; i < length; i += 16) {
 		line[0] = 0;
 		line[0] = 0;
@@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length)
 	}
 	}
 }
 }
 
 
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr * smb)
+{
+	cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d",
+		  smb->Command, smb->Status.CifsError,
+		  smb->Flags, smb->Flags2, smb->Mid, smb->Pid));
+	cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb)));
+}
+
+
+void cifs_dump_mids(struct TCP_Server_Info * server)
+{
+	struct list_head *tmp;
+	struct mid_q_entry * mid_entry;
+
+	if(server == NULL)
+		return;
+
+	cERROR(1,("Dump pending requests:"));
+	spin_lock(&GlobalMid_Lock);
+	list_for_each(tmp, &server->pending_mid_q) {
+		mid_entry = list_entry(tmp, struct mid_q_entry, qhead);
+		if(mid_entry) {
+			cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d",
+				mid_entry->midState,
+				(int)mid_entry->command,
+				mid_entry->pid,
+				mid_entry->tsk,
+				mid_entry->mid));
+#ifdef CONFIG_CIFS_STATS2
+			cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld",
+				mid_entry->largeBuf,
+				mid_entry->resp_buf,
+				mid_entry->when_received,
+				jiffies));
+#endif /* STATS2 */
+			cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp,
+				  mid_entry->multiEnd));
+			if(mid_entry->resp_buf) {
+				cifs_dump_detail(mid_entry->resp_buf);
+				cifs_dump_mem("existing buf: ",
+					mid_entry->resp_buf,
+					62 /* fixme */);
+			}
+			
+		}
+	}
+	spin_unlock(&GlobalMid_Lock);
+}
+#endif /* CONFIG_CIFS_DEBUG2 */
+
 #ifdef CONFIG_PROC_FS
 #ifdef CONFIG_PROC_FS
 static int
 static int
 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
@@ -73,7 +124,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 
 
 	*beginBuffer = buf + offset;
 	*beginBuffer = buf + offset;
 
 
-	
 	length =
 	length =
 	    sprintf(buf,
 	    sprintf(buf,
 		    "Display Internal CIFS Data Structures for Debugging\n"
 		    "Display Internal CIFS Data Structures for Debugging\n"
@@ -397,10 +447,10 @@ static read_proc_t multiuser_mount_read;
 static write_proc_t multiuser_mount_write;
 static write_proc_t multiuser_mount_write;
 static read_proc_t extended_security_read;
 static read_proc_t extended_security_read;
 static write_proc_t extended_security_write;
 static write_proc_t extended_security_write;
-static read_proc_t ntlmv2_enabled_read;
+/* static read_proc_t ntlmv2_enabled_read;
 static write_proc_t ntlmv2_enabled_write;
 static write_proc_t ntlmv2_enabled_write;
 static read_proc_t packet_signing_enabled_read;
 static read_proc_t packet_signing_enabled_read;
-static write_proc_t packet_signing_enabled_write;
+static write_proc_t packet_signing_enabled_write;*/
 static read_proc_t experimEnabled_read;
 static read_proc_t experimEnabled_read;
 static write_proc_t experimEnabled_write;
 static write_proc_t experimEnabled_write;
 static read_proc_t linuxExtensionsEnabled_read;
 static read_proc_t linuxExtensionsEnabled_read;
@@ -469,7 +519,7 @@ cifs_proc_init(void)
 	if (pde)
 	if (pde)
 		pde->write_proc = lookupFlag_write;
 		pde->write_proc = lookupFlag_write;
 
 
-	pde =
+/*	pde =
 	    create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
 	    create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs,
 				ntlmv2_enabled_read, NULL);
 				ntlmv2_enabled_read, NULL);
 	if (pde)
 	if (pde)
@@ -479,7 +529,7 @@ cifs_proc_init(void)
 	    create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
 	    create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs,
 				packet_signing_enabled_read, NULL);
 				packet_signing_enabled_read, NULL);
 	if (pde)
 	if (pde)
-		pde->write_proc = packet_signing_enabled_write;
+		pde->write_proc = packet_signing_enabled_write;*/
 }
 }
 
 
 void
 void
@@ -496,9 +546,9 @@ cifs_proc_clean(void)
 #endif
 #endif
 	remove_proc_entry("MultiuserMount", proc_fs_cifs);
 	remove_proc_entry("MultiuserMount", proc_fs_cifs);
 	remove_proc_entry("OplockEnabled", proc_fs_cifs);
 	remove_proc_entry("OplockEnabled", proc_fs_cifs);
-	remove_proc_entry("NTLMV2Enabled",proc_fs_cifs);
+/*	remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */
 	remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
 	remove_proc_entry("ExtendedSecurity",proc_fs_cifs);
-	remove_proc_entry("PacketSigningEnabled",proc_fs_cifs);
+/*	remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */
 	remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
 	remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs);
 	remove_proc_entry("Experimental",proc_fs_cifs);
 	remove_proc_entry("Experimental",proc_fs_cifs);
 	remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
 	remove_proc_entry("LookupCacheEnabled",proc_fs_cifs);
@@ -787,7 +837,7 @@ extended_security_read(char *page, char **start, off_t off,
 {
 {
 	int len;
 	int len;
 
 
-	len = sprintf(page, "%d\n", extended_security);
+	len = sprintf(page, "0x%x\n", extended_security);
 
 
 	len -= off;
 	len -= off;
 	*start = page + off;
 	*start = page + off;
@@ -808,19 +858,25 @@ extended_security_write(struct file *file, const char __user *buffer,
 {
 {
 	char c;
 	char c;
 	int rc;
 	int rc;
+	cERROR(1,("size %ld",count)); /* BB removeme BB */
+	if((count < 2) || (count > 8))
+		return -EINVAL;
 
 
 	rc = get_user(c, buffer);
 	rc = get_user(c, buffer);
+
+/* BB fixme need to parse more characters in order to handle CIFSSEC flags */ 
+
 	if (rc)
 	if (rc)
 		return rc;
 		return rc;
 	if (c == '0' || c == 'n' || c == 'N')
 	if (c == '0' || c == 'n' || c == 'N')
-		extended_security = 0;
+		extended_security = CIFSSEC_DEF; /* default */
 	else if (c == '1' || c == 'y' || c == 'Y')
 	else if (c == '1' || c == 'y' || c == 'Y')
-		extended_security = 1;
+		extended_security = CIFSSEC_MAX;
 
 
 	return count;
 	return count;
 }
 }
 
 
-static int
+/* static int
 ntlmv2_enabled_read(char *page, char **start, off_t off,
 ntlmv2_enabled_read(char *page, char **start, off_t off,
 		       int count, int *eof, void *data)
 		       int count, int *eof, void *data)
 {
 {
@@ -855,6 +911,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer,
 		ntlmv2_support = 0;
 		ntlmv2_support = 0;
 	else if (c == '1' || c == 'y' || c == 'Y')
 	else if (c == '1' || c == 'y' || c == 'Y')
 		ntlmv2_support = 1;
 		ntlmv2_support = 1;
+	else if (c == '2')
+		ntlmv2_support = 2;
 
 
 	return count;
 	return count;
 }
 }
@@ -898,7 +956,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer,
 		sign_CIFS_PDUs = 2;
 		sign_CIFS_PDUs = 2;
 
 
 	return count;
 	return count;
-}
+} */
 
 
 
 
 #endif
 #endif

+ 4 - 0
fs/cifs/cifs_debug.h

@@ -24,6 +24,10 @@
 #define _H_CIFS_DEBUG
 #define _H_CIFS_DEBUG
 
 
 void cifs_dump_mem(char *label, void *data, int length);
 void cifs_dump_mem(char *label, void *data, int length);
+#ifdef CONFIG_CIFS_DEBUG2
+void cifs_dump_detail(struct smb_hdr *);
+void cifs_dump_mids(struct TCP_Server_Info *);
+#endif
 extern int traceSMB;		/* flag which enables the function below */
 extern int traceSMB;		/* flag which enables the function below */
 void dump_smb(struct smb_hdr *, int);
 void dump_smb(struct smb_hdr *, int);
 #define CIFS_INFO	0x01
 #define CIFS_INFO	0x01

+ 1 - 0
fs/cifs/cifs_unicode.c

@@ -22,6 +22,7 @@
 #include "cifs_unicode.h"
 #include "cifs_unicode.h"
 #include "cifs_uniupr.h"
 #include "cifs_uniupr.h"
 #include "cifspdu.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "cifs_debug.h"
 #include "cifs_debug.h"
 
 
 /*
 /*

+ 2 - 0
fs/cifs/cifsencrypt.c

@@ -225,6 +225,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
 	user_name_len = strlen(ses->userName);
 	user_name_len = strlen(ses->userName);
 	if(user_name_len > MAX_USERNAME_SIZE)
 	if(user_name_len > MAX_USERNAME_SIZE)
 		return -EINVAL;
 		return -EINVAL;
+	if(ses->domainName == NULL)
+		return -EINVAL; /* BB should we use CIFS_LINUX_DOM */
 	dom_name_len = strlen(ses->domainName);
 	dom_name_len = strlen(ses->domainName);
 	if(dom_name_len > MAX_USERNAME_SIZE)
 	if(dom_name_len > MAX_USERNAME_SIZE)
 		return -EINVAL;
 		return -EINVAL;

+ 2 - 2
fs/cifs/cifsfs.c

@@ -56,8 +56,8 @@ unsigned int experimEnabled = 0;
 unsigned int linuxExtEnabled = 1;
 unsigned int linuxExtEnabled = 1;
 unsigned int lookupCacheEnabled = 1;
 unsigned int lookupCacheEnabled = 1;
 unsigned int multiuser_mount = 0;
 unsigned int multiuser_mount = 0;
-unsigned int extended_security = 0;
-unsigned int ntlmv2_support = 0;
+unsigned int extended_security = CIFSSEC_DEF;
+/* unsigned int ntlmv2_support = 0; */
 unsigned int sign_CIFS_PDUs = 1;
 unsigned int sign_CIFS_PDUs = 1;
 extern struct task_struct * oplockThread; /* remove sparse warning */
 extern struct task_struct * oplockThread; /* remove sparse warning */
 struct task_struct * oplockThread = NULL;
 struct task_struct * oplockThread = NULL;

+ 37 - 14
fs/cifs/cifsglob.h

@@ -88,7 +88,8 @@ enum statusEnum {
 };
 };
 
 
 enum securityEnum {
 enum securityEnum {
-	NTLM = 0,		/* Legacy NTLM012 auth with NTLM hash */
+	LANMAN = 0,             /* Legacy LANMAN auth */
+	NTLM,			/* Legacy NTLM012 auth with NTLM hash */
 	NTLMv2,			/* Legacy NTLM auth with NTLMv2 hash */
 	NTLMv2,			/* Legacy NTLM auth with NTLMv2 hash */
 	RawNTLMSSP,		/* NTLMSSP without SPNEGO */
 	RawNTLMSSP,		/* NTLMSSP without SPNEGO */
 	NTLMSSP,		/* NTLMSSP via SPNEGO */
 	NTLMSSP,		/* NTLMSSP via SPNEGO */
@@ -179,7 +180,9 @@ struct cifsUidInfo {
 struct cifsSesInfo {
 struct cifsSesInfo {
 	struct list_head cifsSessionList;
 	struct list_head cifsSessionList;
 	struct semaphore sesSem;
 	struct semaphore sesSem;
+#if 0
 	struct cifsUidInfo *uidInfo;	/* pointer to user info */
 	struct cifsUidInfo *uidInfo;	/* pointer to user info */
+#endif
 	struct TCP_Server_Info *server;	/* pointer to server info */
 	struct TCP_Server_Info *server;	/* pointer to server info */
 	atomic_t inUse; /* # of mounts (tree connections) on this ses */
 	atomic_t inUse; /* # of mounts (tree connections) on this ses */
 	enum statusEnum status;
 	enum statusEnum status;
@@ -194,7 +197,7 @@ struct cifsSesInfo {
 	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for 
 	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for 
 				TCP names - will ipv6 and sctp addresses fit? */
 				TCP names - will ipv6 and sctp addresses fit? */
 	char userName[MAX_USERNAME_SIZE + 1];
 	char userName[MAX_USERNAME_SIZE + 1];
-	char domainName[MAX_USERNAME_SIZE + 1];
+	char * domainName;
 	char * password;
 	char * password;
 };
 };
 /* session flags */
 /* session flags */
@@ -391,9 +394,9 @@ struct mid_q_entry {
 	struct smb_hdr *resp_buf;	/* response buffer */
 	struct smb_hdr *resp_buf;	/* response buffer */
 	int midState;	/* wish this were enum but can not pass to wait_event */
 	int midState;	/* wish this were enum but can not pass to wait_event */
 	__u8 command;	/* smb command code */
 	__u8 command;	/* smb command code */
-	unsigned multiPart:1;	/* multiple responses to one SMB request */
 	unsigned largeBuf:1;    /* if valid response, is pointer to large buf */
 	unsigned largeBuf:1;    /* if valid response, is pointer to large buf */
-	unsigned multiResp:1;   /* multiple trans2 responses for one request  */
+	unsigned multiRsp:1;   /* multiple trans2 responses for one request  */
+	unsigned multiEnd:1; /* both received */
 };
 };
 
 
 struct oplock_q_entry {
 struct oplock_q_entry {
@@ -430,15 +433,35 @@ struct dir_notify_req {
 #define   CIFS_LARGE_BUFFER     2
 #define   CIFS_LARGE_BUFFER     2
 #define   CIFS_IOVEC            4    /* array of response buffers */
 #define   CIFS_IOVEC            4    /* array of response buffers */
 
 
-/* Type of session setup needed */
-#define   CIFS_PLAINTEXT	0
-#define   CIFS_LANMAN		1
-#define   CIFS_NTLM		2
-#define   CIFS_NTLMSSP_NEG	3
-#define   CIFS_NTLMSSP_AUTH	4
-#define   CIFS_SPNEGO_INIT	5
-#define   CIFS_SPNEGO_TARG	6
-
+/* Security Flags: indicate type of session setup needed */
+#define   CIFSSEC_MAY_SIGN	0x00001
+#define   CIFSSEC_MAY_NTLM	0x00002
+#define   CIFSSEC_MAY_NTLMV2	0x00004
+#define   CIFSSEC_MAY_KRB5	0x00008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MAY_LANMAN	0x00010
+#define   CIFSSEC_MAY_PLNTXT	0x00020
+#endif /* weak passwords */
+#define   CIFSSEC_MAY_SEAL	0x00040 /* not supported yet */
+
+#define   CIFSSEC_MUST_SIGN	0x01001
+/* note that only one of the following can be set so the
+result of setting MUST flags more than once will be to
+require use of the stronger protocol */
+#define   CIFSSEC_MUST_NTLM	0x02002
+#define   CIFSSEC_MUST_NTLMV2	0x04004
+#define   CIFSSEC_MUST_KRB5	0x08008
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define   CIFSSEC_MUST_LANMAN	0x10010
+#define   CIFSSEC_MUST_PLNTXT	0x20020
+#define   CIFSSEC_MASK          0x37037 /* current flags supported if weak */
+#else	  
+#define	  CIFSSEC_MASK          0x07007 /* flags supported if no weak config */
+#endif /* WEAK_PW_HASH */
+#define   CIFSSEC_MUST_SEAL	0x40040 /* not supported yet */
+
+#define   CIFSSEC_DEF  CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2
+#define   CIFSSEC_MAX  CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2
 /*
 /*
  *****************************************************************
  *****************************************************************
  * All constants go here
  * All constants go here
@@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled;
 GLOBAL_EXTERN unsigned int lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int lookupCacheEnabled;
 GLOBAL_EXTERN unsigned int extended_security;	/* if on, session setup sent 
 GLOBAL_EXTERN unsigned int extended_security;	/* if on, session setup sent 
 				with more secure ntlmssp2 challenge/resp */
 				with more secure ntlmssp2 challenge/resp */
-GLOBAL_EXTERN unsigned int ntlmv2_support;  /* better optional password hash */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
 GLOBAL_EXTERN unsigned int sign_CIFS_PDUs;  /* enable smb packet signing */
+GLOBAL_EXTERN unsigned int secFlags;
 GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int CIFSMaxBufSize;  /* max size not including hdr */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */
 GLOBAL_EXTERN unsigned int cifs_min_rcv;    /* min size of big ntwrk buf pool */

+ 31 - 6
fs/cifs/cifspdu.h

@@ -16,7 +16,7 @@
  *
  *
  *   You should have received a copy of the GNU Lesser General Public License
  *   You should have received a copy of the GNU Lesser General Public License
  *   along with this library; if not, write to the Free Software
  *   along with this library; if not, write to the Free Software
- *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
  */
 
 
 #ifndef _CIFSPDU_H
 #ifndef _CIFSPDU_H
@@ -24,8 +24,14 @@
 
 
 #include <net/sock.h>
 #include <net/sock.h>
 
 
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define LANMAN_PROT 0
+#define CIFS_PROT   1
+#else
 #define CIFS_PROT   0
 #define CIFS_PROT   0
-#define BAD_PROT    CIFS_PROT+1
+#endif
+#define POSIX_PROT  CIFS_PROT+1
+#define BAD_PROT 0xFFFF
 
 
 /* SMB command codes */
 /* SMB command codes */
 /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
 /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses
@@ -400,6 +406,25 @@ typedef struct negotiate_req {
 	unsigned char DialectsArray[1];
 	unsigned char DialectsArray[1];
 } __attribute__((packed)) NEGOTIATE_REQ;
 } __attribute__((packed)) NEGOTIATE_REQ;
 
 
+/* Dialect index is 13 for LANMAN */
+
+typedef struct lanman_neg_rsp {
+	struct smb_hdr hdr;	/* wct = 13 */
+	__le16 DialectIndex;
+	__le16 SecurityMode;
+	__le16 MaxBufSize;
+	__le16 MaxMpxCount;
+	__le16 MaxNumberVcs;
+	__le16 RawMode;
+	__le32 SessionKey;
+	__le32 ServerTime;
+	__le16 ServerTimeZone;
+	__le16 EncryptionKeyLength;
+	__le16 Reserved;
+	__u16  ByteCount;
+	unsigned char EncryptionKey[1];
+} __attribute__((packed)) LANMAN_NEG_RSP;
+
 typedef struct negotiate_rsp {
 typedef struct negotiate_rsp {
 	struct smb_hdr hdr;	/* wct = 17 */
 	struct smb_hdr hdr;	/* wct = 17 */
 	__le16 DialectIndex;
 	__le16 DialectIndex;
@@ -520,8 +545,8 @@ typedef union smb_com_session_setup_andx {
 		__le16 MaxMpxCount;
 		__le16 MaxMpxCount;
 		__le16 VcNumber;
 		__le16 VcNumber;
 		__u32 SessionKey;
 		__u32 SessionKey;
-		__le16 PassswordLength;
-		__u32 Reserved;
+		__le16 PasswordLength;
+		__u32 Reserved; /* encrypt key len and offset */
 		__le16 ByteCount;
 		__le16 ByteCount;
 		unsigned char AccountPassword[1];	/* followed by */
 		unsigned char AccountPassword[1];	/* followed by */
 		/* STRING AccountName */
 		/* STRING AccountName */
@@ -1844,13 +1869,13 @@ typedef struct {
 typedef struct {
 typedef struct {
 	__le32 DeviceType;
 	__le32 DeviceType;
 	__le32 DeviceCharacteristics;
 	__le32 DeviceCharacteristics;
-} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO;	/* device info, level 0x104 */
+} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */
 
 
 typedef struct {
 typedef struct {
 	__le32 Attributes;
 	__le32 Attributes;
 	__le32 MaxPathNameComponentLength;
 	__le32 MaxPathNameComponentLength;
 	__le32 FileSystemNameLen;
 	__le32 FileSystemNameLen;
-	char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */
+	char FileSystemName[52]; /* do not have to save this - get subset? */
 } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
 } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO;
 
 
 /******************************************************************************/
 /******************************************************************************/

+ 1 - 1
fs/cifs/cifsproto.h

@@ -69,7 +69,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct,
 				struct cifsSesInfo *ses,
 				struct cifsSesInfo *ses,
 				void ** request_buf);
 				void ** request_buf);
 extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
 extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
-			     const int stage, int * pNTLMv2_flg,
+			     const int stage, 
 			     const struct nls_table *nls_cp);
 			     const struct nls_table *nls_cp);
 #endif
 #endif
 extern __u16 GetNextMid(struct TCP_Server_Info *server);
 extern __u16 GetNextMid(struct TCP_Server_Info *server);

+ 85 - 10
fs/cifs/cifssmb.c

@@ -44,8 +44,11 @@ static struct {
 	int index;
 	int index;
 	char *name;
 	char *name;
 } protocols[] = {
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+	{LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
 	{CIFS_PROT, "\2NT LM 0.12"}, 
 	{CIFS_PROT, "\2NT LM 0.12"}, 
-	{CIFS_PROT, "\2POSIX 2"},
+	{POSIX_PROT, "\2POSIX 2"},
 	{BAD_PROT, "\2"}
 	{BAD_PROT, "\2"}
 };
 };
 #else
 #else
@@ -53,11 +56,29 @@ static struct {
 	int index;
 	int index;
 	char *name;
 	char *name;
 } protocols[] = {
 } protocols[] = {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+	{LANMAN_PROT, "\2LM1.2X002"},
+#endif /* weak password hashing for legacy clients */
 	{CIFS_PROT, "\2NT LM 0.12"}, 
 	{CIFS_PROT, "\2NT LM 0.12"}, 
 	{BAD_PROT, "\2"}
 	{BAD_PROT, "\2"}
 };
 };
 #endif
 #endif
 
 
+/* define the number of elements in the cifs dialect array */
+#ifdef CONFIG_CIFS_POSIX
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 3
+#else
+#define CIFS_NUM_PROT 2
+#endif /* CIFS_WEAK_PW_HASH */
+#else /* not posix */
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+#define CIFS_NUM_PROT 2
+#else
+#define CIFS_NUM_PROT 1
+#endif /* CONFIG_CIFS_WEAK_PW_HASH */
+#endif /* CIFS_POSIX */
+
 
 
 /* Mark as invalid, all open files on tree connections since they
 /* Mark as invalid, all open files on tree connections since they
    were closed when session to server was lost */
    were closed when session to server was lost */
@@ -322,7 +343,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
     /* potential retries of smb operations it turns out we can determine */
     /* potential retries of smb operations it turns out we can determine */
     /* from the mid flags when the request buffer can be resent without  */
     /* from the mid flags when the request buffer can be resent without  */
     /* having to use a second distinct buffer for the response */
     /* having to use a second distinct buffer for the response */
-	*response_buf = *request_buf; 
+	if(response_buf)
+		*response_buf = *request_buf; 
 
 
 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
 	header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
 			wct /*wct */ );
 			wct /*wct */ );
@@ -373,6 +395,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 	NEGOTIATE_RSP *pSMBr;
 	NEGOTIATE_RSP *pSMBr;
 	int rc = 0;
 	int rc = 0;
 	int bytes_returned;
 	int bytes_returned;
+	int i;
 	struct TCP_Server_Info * server;
 	struct TCP_Server_Info * server;
 	u16 count;
 	u16 count;
 
 
@@ -388,19 +411,71 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 		return rc;
 		return rc;
 	pSMB->hdr.Mid = GetNextMid(server);
 	pSMB->hdr.Mid = GetNextMid(server);
 	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
 	pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
-	if (extended_security)
-		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
-
-	count = strlen(protocols[0].name) + 1;
-	strncpy(pSMB->DialectsArray, protocols[0].name, 30);	
-    /* null guaranteed to be at end of source and target buffers anyway */
-
+/*	if (extended_security)
+		pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/
+	
+	count = 0;
+	for(i=0;i<CIFS_NUM_PROT;i++) {
+		strncpy(pSMB->DialectsArray+count, protocols[i].name, 16);
+		count += strlen(protocols[i].name) + 1;
+		/* null at end of source and target buffers anyway */
+	}
 	pSMB->hdr.smb_buf_length += count;
 	pSMB->hdr.smb_buf_length += count;
 	pSMB->ByteCount = cpu_to_le16(count);
 	pSMB->ByteCount = cpu_to_le16(count);
 
 
 	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
 	rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 			 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 	if (rc == 0) {
 	if (rc == 0) {
+		cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
+		/* Check wct = 1 error case */
+		if((pSMBr->hdr.WordCount < 13)  
+			|| (pSMBr->DialectIndex == BAD_PROT)) {
+			/* core returns wct = 1, but we do not ask for
+			core - otherwise it just comes when dialect
+			index is -1 indicating we could not negotiate
+			a common dialect */
+			rc = -EOPNOTSUPP;
+			goto neg_err_exit;
+		} else if((pSMBr->hdr.WordCount == 13) && 
+			(pSMBr->DialectIndex == LANMAN_PROT)) {
+			struct lanman_neg_rsp * rsp = 
+				(struct lanman_neg_rsp *)pSMBr;
+
+
+			/* BB Mark ses struct as negotiated lanman level BB */
+			server->secType = LANMAN;
+			server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode);
+			server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
+			server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
+				(__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+
+			/* BB what do we do with raw mode? BB */
+			server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
+			/* Do we have to set signing flags? no signing
+			was available LANMAN - default should be ok */
+
+			/* BB FIXME set default dummy capabilities since
+			they are not returned by the server in this dialect */
+
+			/* get server time for time conversions and add
+			code to use it and timezone since this is not UTC */	
+
+			if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
+				memcpy(server->cryptKey, rsp->EncryptionKey,
+					CIFS_CRYPTO_KEY_SIZE);
+			} else {
+				rc = -EIO;
+				goto neg_err_exit;
+			}
+
+			cFYI(1,("LANMAN negotiated")); /* BB removeme BB */
+			goto neg_err_exit;
+		} else if(pSMBr->hdr.WordCount != 17) {
+			/* unknown wct */
+			rc = -EOPNOTSUPP;
+			goto neg_err_exit;
+		}
+
 		server->secMode = pSMBr->SecurityMode;
 		server->secMode = pSMBr->SecurityMode;
 		if((server->secMode & SECMODE_USER) == 0)
 		if((server->secMode & SECMODE_USER) == 0)
 			cFYI(1,("share mode security"));
 			cFYI(1,("share mode security"));
@@ -479,7 +554,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 		}
 		}
 				
 				
 	}
 	}
-	
+neg_err_exit:	
 	cifs_buf_release(pSMB);
 	cifs_buf_release(pSMB);
 	return rc;
 	return rc;
 }
 }

+ 26 - 13
fs/cifs/connect.c

@@ -49,8 +49,6 @@
 
 
 static DECLARE_COMPLETION(cifsd_complete);
 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,
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
 			 unsigned char *p24);
 			 unsigned char *p24);
 
 
@@ -585,9 +583,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
 						/* merge response - fix up 1st*/
 						/* merge response - fix up 1st*/
 						if(coalesce_t2(smb_buffer, 
 						if(coalesce_t2(smb_buffer, 
 							mid_entry->resp_buf)) {
 							mid_entry->resp_buf)) {
+							mid_entry->multiRsp = 1;
 							break;
 							break;
 						} else {
 						} else {
 							/* all parts received */
 							/* all parts received */
+							mid_entry->multiEnd = 1;
 							goto multi_t2_fnd; 
 							goto multi_t2_fnd; 
 						}
 						}
 					} else {
 					} else {
@@ -632,9 +632,14 @@ multi_t2_fnd:
 			wake_up_process(task_to_wake);
 			wake_up_process(task_to_wake);
 		} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
 		} else if ((is_valid_oplock_break(smb_buffer, server) == FALSE)
 		    && (isMultiRsp == 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,
 			cifs_dump_mem("Received Data is: ",(char *)smb_buffer,
 				      sizeof(struct smb_hdr));
 				      sizeof(struct smb_hdr));
+#ifdef CONFIG_CIFS_DEBUG2
+			cifs_dump_detail(smb_buffer);
+			cifs_dump_mids(server);
+#endif /* CIFS_DEBUG2 */
+			
 		}
 		}
 	} /* end while !EXITING */
 	} /* end while !EXITING */
 
 
@@ -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
 			/* BB are there cases in which a comma can be valid in
 			a domain name and need special handling? */
 			a domain name and need special handling? */
-			if (strnlen(value, 65) < 65) {
+			if (strnlen(value, 256) < 256) {
 				vol->domainname = value;
 				vol->domainname = value;
 				cFYI(1, ("Domain name set"));
 				cFYI(1, ("Domain name set"));
 			} else {
 			} else {
@@ -1762,9 +1767,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
 			if (volume_info.username)
 			if (volume_info.username)
 				strncpy(pSesInfo->userName,
 				strncpy(pSesInfo->userName,
 					volume_info.username,MAX_USERNAME_SIZE);
 					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->linux_uid = volume_info.linux_uid;
 			down(&pSesInfo->sesSem);
 			down(&pSesInfo->sesSem);
 			rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
 			rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls);
@@ -2054,7 +2064,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 			bcc_ptr++;
 			bcc_ptr++;
 		}
 		}
 		if(user == NULL)
 		if(user == NULL)
-			bytes_returned = 0; /* skill null user */
+			bytes_returned = 0; /* skip null user */
 	        else
 	        else
 			bytes_returned =
 			bytes_returned =
 			        cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
 			        cifs_strtoUCS((__le16 *) bcc_ptr, user, 100,
@@ -2635,8 +2645,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
 	    /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
 	    /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128;
 	if(sign_CIFS_PDUs)
 	if(sign_CIFS_PDUs)
 		negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN;
 		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 */
 	/* setup pointers to domain name and workstation name */
 	bcc_ptr += SecurityBlobLength;
 	bcc_ptr += SecurityBlobLength;
 
 
@@ -3429,7 +3439,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
 			}
 			}
 			/* else do not bother copying these informational fields */
 			/* 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));
 		cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags));
 	} else if ((rc == 0) && tcon == NULL) {
 	} else if ((rc == 0) && tcon == NULL) {
         /* all we need to save for IPC$ connection */
         /* all we need to save for IPC$ connection */
@@ -3528,8 +3541,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
 			pSesInfo->server->timeZone));
 			pSesInfo->server->timeZone));
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 		if(experimEnabled > 1)
 		if(experimEnabled > 1)
-			rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */,
-					    &ntlmv2_flag, nls_info);	
+			rc = CIFS_SessSetup(xid, pSesInfo,
+					    first_time, nls_info);
 		else
 		else
 #endif
 #endif
 		if (extended_security
 		if (extended_security

+ 1 - 1
fs/cifs/dir.c

@@ -113,7 +113,7 @@ cifs_bp_rename_retry:
 	full_path[namelen+2] = 0;
 	full_path[namelen+2] = 0;
 BB remove above eight lines BB */
 BB remove above eight lines BB */
 
 
-/* Inode operations in similar order to how they appear in the Linux file fs.h */
+/* Inode operations in similar order to how they appear in Linux file fs.h */
 
 
 int
 int
 cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 cifs_create(struct inode *inode, struct dentry *direntry, int mode,

+ 2 - 2
fs/cifs/fcntl.c

@@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg)
 	if(full_path == NULL) {
 	if(full_path == NULL) {
 		rc = -ENOMEM;
 		rc = -ENOMEM;
 	} else {
 	} else {
-		cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */
+		cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg));
 		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, 
 		rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, 
 			GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
 			GENERIC_READ | SYNCHRONIZE, 0 /* create options */,
 			&netfid, &oplock,NULL, cifs_sb->local_nls,
 			&netfid, &oplock,NULL, cifs_sb->local_nls,
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 			cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
 		/* BB fixme - add this handle to a notify handle list */
 		/* BB fixme - add this handle to a notify handle list */
 		if(rc) {
 		if(rc) {
-			cERROR(1,("Could not open directory for notify"));  /* BB remove BB */
+			cFYI(1,("Could not open directory for notify"));
 		} else {
 		} else {
 			filter = convert_to_cifs_notify_flags(arg);
 			filter = convert_to_cifs_notify_flags(arg);
 			if(filter != 0) {
 			if(filter != 0) {

+ 2 - 1
fs/cifs/inode.c

@@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 
 
 	xid = GetXid();
 	xid = GetXid();
 
 
-	cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x",
+	cFYI(1, ("setattr on file %s attrs->iavalid 0x%x",
 		 direntry->d_name.name, attrs->ia_valid));
 		 direntry->d_name.name, attrs->ia_valid));
 
 
 	cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
 	cifs_sb = CIFS_SB(direntry->d_inode->i_sb);
@@ -1157,6 +1157,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 		   when the local oplock break takes longer to flush
 		   when the local oplock break takes longer to flush
 		   writebehind data than the SMB timeout for the SetPathInfo
 		   writebehind data than the SMB timeout for the SetPathInfo
 		   request would allow */
 		   request would allow */
+
 		open_file = find_writable_file(cifsInode);
 		open_file = find_writable_file(cifsInode);
 		if (open_file) {
 		if (open_file) {
 			__u16 nfid = open_file->netfid;
 			__u16 nfid = open_file->netfid;

+ 6 - 4
fs/cifs/misc.c

@@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free)
 	kfree(buf_to_free->serverDomain);
 	kfree(buf_to_free->serverDomain);
 	kfree(buf_to_free->serverNOS);
 	kfree(buf_to_free->serverNOS);
 	kfree(buf_to_free->password);
 	kfree(buf_to_free->password);
+	kfree(buf_to_free->domainName);
 	kfree(buf_to_free);
 	kfree(buf_to_free);
 }
 }
 
 
@@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv)
 		if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
 		if(pSMBr->ByteCount > sizeof(struct file_notify_information)) {
 			data_offset = le32_to_cpu(pSMBr->DataOffset);
 			data_offset = le32_to_cpu(pSMBr->DataOffset);
 
 
-			pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol
-				+ data_offset);
-			cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName,
+			pnotify = (struct file_notify_information *)
+				((char *)&pSMBr->hdr.Protocol + data_offset);
+			cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName,
 				pnotify->Action));  /* BB removeme BB */
 				pnotify->Action));  /* BB removeme BB */
-	             /*   cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */
+	             /*   cifs_dump_mem("Rcvd notify Data: ",buf,
+				sizeof(struct smb_hdr)+60); */
 			return TRUE;
 			return TRUE;
 		}
 		}
 		if(pSMBr->hdr.Status.CifsError) {
 		if(pSMBr->hdr.Status.CifsError) {

+ 10 - 6
fs/cifs/readdir.c

@@ -31,8 +31,8 @@
 #include "cifs_fs_sb.h"
 #include "cifs_fs_sb.h"
 #include "cifsfs.h"
 #include "cifsfs.h"
 
 
-/* BB fixme - add debug wrappers around this function to disable it fixme BB */
-/* static void dump_cifs_file_struct(struct file *file, char *label)
+#ifdef CONFIG_CIFS_DEBUG2
+static void dump_cifs_file_struct(struct file *file, char *label)
 {
 {
 	struct cifsFileInfo * cf;
 	struct cifsFileInfo * cf;
 
 
@@ -53,7 +53,8 @@
 		}
 		}
 		
 		
 	}
 	}
-} */
+}
+#endif /* DEBUG2 */
 
 
 /* Returns one if new inode created (which therefore needs to be hashed) */
 /* Returns one if new inode created (which therefore needs to be hashed) */
 /* Might check in the future if inode number changed so we can rehash inode */
 /* Might check in the future if inode number changed so we can rehash inode */
@@ -597,7 +598,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 	. and .. for the root of a drive and for those we need
 	. and .. for the root of a drive and for those we need
 	to start two entries earlier */
 	to start two entries earlier */
 
 
-/*	dump_cifs_file_struct(file, "In fce ");*/
+#ifdef CONFIG_CIFS_DEBUG2
+	dump_cifs_file_struct(file, "In fce ");
+#endif
 	if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
 	if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && 
 	     is_dir_changed(file)) || 
 	     is_dir_changed(file)) || 
 	   (index_to_find < first_entry_in_buffer)) {
 	   (index_to_find < first_entry_in_buffer)) {
@@ -980,9 +983,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
 			rc = cifs_filldir(current_entry, file, 
 			rc = cifs_filldir(current_entry, file, 
 					filldir, direntry,tmp_buf);
 					filldir, direntry,tmp_buf);
 			file->f_pos++;
 			file->f_pos++;
-			if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) {
+			if(file->f_pos == 
+				cifsFile->srch_inf.index_of_last_entry) {
 				cFYI(1,("last entry in buf at pos %lld %s",
 				cFYI(1,("last entry in buf at pos %lld %s",
-					file->f_pos,tmp_buf)); /* BB removeme BB */
+					file->f_pos,tmp_buf));
 				cifs_save_resume_key(current_entry,cifsFile);
 				cifs_save_resume_key(current_entry,cifsFile);
 				break;
 				break;
 			} else 
 			} else 

+ 511 - 0
fs/cifs/sess.c

@@ -0,0 +1,511 @@
+/*
+ *   fs/cifs/sess.c
+ *
+ *   SMB/CIFS session setup handling routines
+ *
+ *   Copyright (c) International Business Machines  Corp., 2006
+ *   Author(s): Steve French (sfrench@us.ibm.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_unicode.h"
+#include "cifs_debug.h"
+#include "ntlmssp.h"
+#include "nterr.h"
+#include <linux/ctype.h>
+
+extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
+                       unsigned char *p24);
+
+extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
+                         unsigned char *p24);
+
+#ifdef CONFIG_CIFS_EXPERIMENTAL
+
+static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
+{
+	__u32 capabilities = 0;
+
+	/* init fields common to all four types of SessSetup */
+	/* note that header is initialized to zero in header_assemble */
+	pSMB->req.AndXCommand = 0xFF;
+	pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
+	pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+
+	/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
+
+	/* BB verify whether signing required on neg or just on auth frame 
+	   (and NTLM case) */
+
+	capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
+			CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
+
+	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+		pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+
+	if (ses->capabilities & CAP_UNICODE) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
+		capabilities |= CAP_UNICODE;
+	}
+	if (ses->capabilities & CAP_STATUS32) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
+		capabilities |= CAP_STATUS32;
+	}
+	if (ses->capabilities & CAP_DFS) {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
+		capabilities |= CAP_DFS;
+	}
+	if (ses->capabilities & CAP_UNIX) {
+		capabilities |= CAP_UNIX;
+	}
+
+	/* BB check whether to init vcnum BB */
+	return capabilities;
+}
+
+void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+			    const struct nls_table * nls_cp)
+{
+	char * bcc_ptr = *pbcc_area;
+	int bytes_ret = 0;
+
+	/* BB FIXME add check that strings total less
+	than 335 or will need to send them as arrays */
+
+	/* align unicode strings, must be word aligned */
+	if ((long) bcc_ptr % 2)	{
+		*bcc_ptr = 0;
+		bcc_ptr++;
+	}
+	/* copy user */
+	if(ses->userName == NULL) {
+		/* BB what about null user mounts - check that we do this BB */
+	} else { /* 300 should be long enough for any conceivable user name */
+		bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
+					  300, nls_cp);
+	}
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2; /* account for null termination */
+	/* copy domain */
+	if(ses->domainName == NULL)
+		bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
+					  "CIFS_LINUX_DOM", 32, nls_cp);
+	else
+		bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 
+					  256, nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2;  /* account for null terminator */
+
+	/* Copy OS version */
+	bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
+				  nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+				  32, nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2; /* trailing null */
+
+	bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
+                                  32, nls_cp);
+	bcc_ptr += 2 * bytes_ret;
+	bcc_ptr += 2; /* trailing null */
+
+	*pbcc_area = bcc_ptr;
+}
+
+void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+			  const struct nls_table * nls_cp)
+{
+	char * bcc_ptr = *pbcc_area;
+
+	/* copy user */
+	/* BB what about null user mounts - check that we do this BB */
+        /* copy user */
+        if(ses->userName == NULL) {
+                /* BB what about null user mounts - check that we do this BB */
+        } else { /* 300 should be long enough for any conceivable user name */
+                strncpy(bcc_ptr, ses->userName, 300);
+        }
+	/* BB improve check for overflow */
+        bcc_ptr += strnlen(ses->userName, 200);
+	*bcc_ptr = 0;
+        bcc_ptr++; /* account for null termination */
+
+        /* copy domain */
+	
+        if(ses->domainName == NULL) {
+                strcpy(bcc_ptr, "CIFS_LINUX_DOM");
+		bcc_ptr += 14;  /* strlen(CIFS_LINUX_DOM) */
+ 	} else {
+                strncpy(bcc_ptr, ses->domainName, 256); 
+		bcc_ptr += strnlen(ses->domainName, 256);
+	}
+	*bcc_ptr = 0;
+	bcc_ptr++;
+
+	/* BB check for overflow here */
+
+	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;
+
+        *pbcc_area = bcc_ptr;
+}
+
+int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+	int rc = 0;
+	int words_left, len;
+	char * data = *pbcc_area;
+
+
+
+	cFYI(1,("bleft %d",bleft));
+
+
+	/* word align, if bytes remaining is not even */
+	if(bleft % 2) {
+		bleft--;
+		data++;
+	}
+	words_left = bleft / 2;
+
+	/* save off server operating system */
+	len = UniStrnlen((wchar_t *) data, words_left);
+
+/* 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(len >= words_left)
+		return rc;
+
+	if(ses->serverOS)
+		kfree(ses->serverOS);
+	/* UTF-8 string will not grow more than four times as big as UCS-16 */
+	ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
+	if(ses->serverOS != NULL) {
+		cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
+				   nls_cp);
+	}
+	data += 2 * (len + 1);
+	words_left -= len + 1;
+
+	/* save off server network operating system */
+	len = UniStrnlen((wchar_t *) data, words_left);
+
+	if(len >= words_left)
+		return rc;
+
+	if(ses->serverNOS)
+		kfree(ses->serverNOS);
+	ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
+	if(ses->serverNOS != NULL) {
+		cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
+				   nls_cp);
+		if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
+			cFYI(1,("NT4 server"));
+			ses->flags |= CIFS_SES_NT4;
+		}
+	}
+	data += 2 * (len + 1);
+	words_left -= len + 1;
+
+        /* save off server domain */
+        len = UniStrnlen((wchar_t *) data, words_left);
+
+        if(len > words_left)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+        ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
+        if(ses->serverDomain != NULL) {
+                cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
+                                   nls_cp);
+                ses->serverDomain[2*len] = 0;
+                ses->serverDomain[(2*len) + 1] = 0;
+        }
+        data += 2 * (len + 1);
+        words_left -= len + 1;
+	
+	cFYI(1,("words left: %d",words_left));
+
+	return rc;
+}
+
+int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+                            const struct nls_table * nls_cp)
+{
+	int rc = 0;
+	int len;
+	char * bcc_ptr = *pbcc_area;
+
+	cFYI(1,("decode sessetup ascii. bleft %d", bleft));
+	
+	len = strnlen(bcc_ptr, bleft);
+	if(len >= bleft)
+		return rc;
+	
+	if(ses->serverOS)
+		kfree(ses->serverOS);
+
+	ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
+	if(ses->serverOS)
+		strncpy(ses->serverOS, bcc_ptr, len);
+
+	bcc_ptr += len + 1;
+	bleft -= len + 1;
+
+	len = strnlen(bcc_ptr, bleft);
+	if(len >= bleft)
+		return rc;
+
+	if(ses->serverNOS)
+		kfree(ses->serverNOS);
+
+	ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
+	if(ses->serverNOS)
+		strncpy(ses->serverNOS, bcc_ptr, len);
+
+	bcc_ptr += len + 1;
+	bleft -= len + 1;
+
+        len = strnlen(bcc_ptr, bleft);
+        if(len > bleft)
+                return rc;
+
+        if(ses->serverDomain)
+                kfree(ses->serverDomain);
+
+        ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
+        if(ses->serverOS)
+                strncpy(ses->serverOS, bcc_ptr, len);
+
+        bcc_ptr += len + 1;
+	bleft -= len + 1;
+
+	cFYI(1,("ascii: bytes left %d",bleft));
+
+	return rc;
+}
+
+int 
+CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
+		const struct nls_table *nls_cp)
+{
+	int rc = 0;
+	int wct;
+	int i;
+	struct smb_hdr *smb_buf;
+	char *bcc_ptr;
+	SESSION_SETUP_ANDX *pSMB;
+	__u32 capabilities;
+	int count;
+	int resp_buf_type = 0;
+	struct kvec iov[1];
+	enum securityEnum type;
+	__u16 action;
+	int bytes_remaining;
+	
+	if(ses == NULL)
+		return -EINVAL;
+
+	type = ses->server->secType;
+	if(type == LANMAN) {
+#ifndef CONFIG_CIFS_WEAK_PW_HASH
+		/* LANMAN and plaintext are less secure and off by default.
+		So we make this explicitly be turned on in kconfig (in the
+		build) and turned on at runtime (changed from the default)
+		in proc/fs/cifs or via mount parm.  Unfortunately this is
+		needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
+		return -EOPNOTSUPP;
+#endif
+		wct = 10; /* lanman 2 style sessionsetup */
+	} else if(type == NTLM) /* NTLMv2 may retry NTLM */
+		wct = 13; /* old style NTLM sessionsetup */
+	else /* same size for negotiate or auth, NTLMSSP or extended security */
+		wct = 12;
+
+	rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
+			    (void **)&smb_buf);
+	if(rc)
+		return rc;
+
+	pSMB = (SESSION_SETUP_ANDX *)smb_buf;
+
+	capabilities = cifs_ssetup_hdr(ses, pSMB);
+	bcc_ptr = pByteArea(smb_buf);
+
+	if(type == LANMAN) {
+#ifdef CONFIG_CIFS_WEAK_PW_HASH
+		char lnm_session_key[CIFS_SESSION_KEY_SIZE];
+		char password_with_pad[CIFS_ENCPWD_SIZE];
+
+		/* no capabilities flags in old lanman negotiation */
+
+		pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE; 
+		/* BB calculate hash with password */
+		/* and copy into bcc */
+
+		memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+		strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
+
+		/* calculate old style session key */
+		/* toupper may be less broken then repeatedly calling
+		nls_toupper would be, but neither handles multibyte code pages
+		but the only alternative would be converting to UCS-16 (Unicode)
+		uppercasing and converting back which is only worth doing if
+		we knew it were utf8. utf8 code page needs its own
+		toupper and tolower and strnicmp functions */
+		
+		for(i = 0; i< CIFS_ENCPWD_SIZE; i++) {
+			password_with_pad[i] = toupper(password_with_pad[i]);
+		}
+
+		SMBencrypt(password_with_pad, ses->server->cryptKey,
+			   lnm_session_key);
+
+#ifdef CONFIG_CIFS_DEBUG2
+		cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
+			CIFS_SESSION_KEY_SIZE);
+#endif
+		/* clear password before we return/free memory */
+		memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
+		memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE);
+		bcc_ptr += CIFS_SESSION_KEY_SIZE;
+
+		/* can not sign if LANMAN negotiated so no need
+		to calculate signing key? but what if server
+		changed to do higher than lanman dialect and
+		we reconnected would we ever calc signing_key? */
+
+		cERROR(1,("Negotiating LANMAN setting up strings"));
+		/* Unicode not allowed for LANMAN dialects */
+		ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+#endif    
+	} else if (type == NTLM) {
+		char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+
+		pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
+		pSMB->req_no_secext.CaseInsensitivePasswordLength =
+			cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+		pSMB->req_no_secext.CaseSensitivePasswordLength =
+			cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+	
+		/* calculate session key */
+		SMBNTencrypt(ses->password, ses->server->cryptKey,
+			     ntlm_session_key);
+
+		if(first_time) /* should this be moved into common code 
+				  with similar ntlmv2 path? */
+			cifs_calculate_mac_key(
+				ses->server->mac_signing_key,
+				ntlm_session_key, ses->password);
+		/* copy session key */
+
+		memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
+		bcc_ptr += CIFS_SESSION_KEY_SIZE;
+		memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
+		bcc_ptr += CIFS_SESSION_KEY_SIZE;
+		if(ses->capabilities & CAP_UNICODE)
+			unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
+		else
+			ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
+	} else /* NTLMSSP or SPNEGO */ {
+		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
+		capabilities |= CAP_EXTENDED_SECURITY;
+		pSMB->req.Capabilities = cpu_to_le32(capabilities);
+		/* BB set password lengths */
+	}
+
+	count = (long) bcc_ptr - (long) pByteArea(smb_buf);
+	smb_buf->smb_buf_length += count;
+
+	/* if we switch to small buffers, count will need to be fewer
+	   than 383 (strings less than 335 bytes) */
+
+	BCC_LE(smb_buf) = cpu_to_le16(count);
+
+
+	/* BB FIXME check for other non ntlm code paths */
+
+	/* BB check is this too big for a small smb? */
+
+	iov[0].iov_base = (char *)pSMB;
+	iov[0].iov_len = smb_buf->smb_buf_length + 4;
+
+	rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0);
+	/* SMB request buf freed in SendReceive2 */
+
+	cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
+	if(rc)
+		goto ssetup_exit;
+
+	pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
+	smb_buf = (struct smb_hdr *)iov[0].iov_base;
+
+	if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
+		rc = -EIO;
+		cERROR(1,("bad word count %d", smb_buf->WordCount));
+		goto ssetup_exit;
+	}
+	action = le16_to_cpu(pSMB->resp.Action);
+	if (action & GUEST_LOGIN)
+		cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
+	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
+	cFYI(1, ("UID = %d ", ses->Suid));
+	/* response can have either 3 or 4 word count - Samba sends 3 */
+	/* and lanman response is 3 */
+	bytes_remaining = BCC(smb_buf);
+	bcc_ptr = pByteArea(smb_buf);
+
+	if(smb_buf->WordCount == 4) {
+		__u16 blob_len;
+		blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
+		bcc_ptr += blob_len;
+		if(blob_len > bytes_remaining) {
+			cERROR(1,("bad security blob length %d", blob_len));
+			rc = -EINVAL;
+			goto ssetup_exit;
+		}
+		bytes_remaining -= blob_len;
+	}	
+
+	/* BB check if Unicode and decode strings */
+	if(smb_buf->Flags2 & SMBFLG2_UNICODE)
+		rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
+						   ses, nls_cp);
+	else
+		rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
+	
+ssetup_exit:
+	if(resp_buf_type == CIFS_SMALL_BUFFER) {
+		cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
+		cifs_small_buf_release(iov[0].iov_base);
+	} else if(resp_buf_type == CIFS_LARGE_BUFFER)
+		cifs_buf_release(iov[0].iov_base);
+
+	return rc;
+}
+#endif /* CONFIG_CIFS_EXPERIMENTAL */

+ 1 - 0
fs/cifs/smbencrypt.c

@@ -30,6 +30,7 @@
 #include <linux/random.h>
 #include <linux/random.h>
 #include "cifs_unicode.h"
 #include "cifs_unicode.h"
 #include "cifspdu.h"
 #include "cifspdu.h"
+#include "cifsglob.h"
 #include "md5.h"
 #include "md5.h"
 #include "cifs_debug.h"
 #include "cifs_debug.h"
 #include "cifsencrypt.h"
 #include "cifsencrypt.h"