cifs: store password in tcon

cifs: store password in tcon

Each tcon has its own password for share-level security. Store it in
the tcon and wipe it clean and free it when freeing the tcon. When
doing the tree connect with share-level security, use the tcon password
instead of the session password.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0fb934d..94c1ca0 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -242,6 +242,7 @@
 	struct cifsSesInfo *ses;	/* pointer to session associated with */
 	char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */
 	char *nativeFileSystem;
+	char *password;		/* for share-level security */
 	__u16 tid;		/* The 2 byte tree id */
 	__u16 Flags;		/* optional support bits */
 	enum statusEnum tidStatus;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 3a84a37..3caadf1 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -2282,9 +2282,12 @@
 
 		/* volume_info->password freed at unmount */
 		if (volume_info->password) {
-			pSesInfo->password = volume_info->password;
-			/* set to NULL to prevent freeing on exit */
-			volume_info->password = NULL;
+			pSesInfo->password = kstrdup(volume_info->password,
+						     GFP_KERNEL);
+			if (!pSesInfo->password) {
+				rc = -ENOMEM;
+				goto mount_fail_check;
+			}
 		}
 		if (volume_info->username)
 			strncpy(pSesInfo->userName, volume_info->username,
@@ -2324,7 +2327,16 @@
 				rc = -ENOMEM;
 				goto mount_fail_check;
 			}
+
 			tcon->ses = pSesInfo;
+			if (volume_info->password) {
+				tcon->password = kstrdup(volume_info->password,
+							 GFP_KERNEL);
+				if (!tcon->password) {
+					rc = -ENOMEM;
+					goto mount_fail_check;
+				}
+			}
 
 			/* check for null share name ie connect to dfs root */
 			if ((strchr(volume_info->UNC + 3, '\\') == NULL)
@@ -3532,15 +3544,14 @@
 		   NTLMv2 password here) */
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 		if ((extended_security & CIFSSEC_MAY_LANMAN) &&
-			(ses->server->secType == LANMAN))
-			calc_lanman_hash(ses->password, ses->server->cryptKey,
+		    (ses->server->secType == LANMAN))
+			calc_lanman_hash(tcon->password, ses->server->cryptKey,
 					 ses->server->secMode &
 					    SECMODE_PW_ENCRYPT ? true : false,
 					 bcc_ptr);
 		else
 #endif /* CIFS_WEAK_PW_HASH */
-		SMBNTencrypt(ses->password,
-			     ses->server->cryptKey,
+		SMBNTencrypt(tcon->password, ses->server->cryptKey,
 			     bcc_ptr);
 
 		bcc_ptr += CIFS_SESS_KEY_SIZE;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 7c3f4b9..a051360 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -132,6 +132,10 @@
 	}
 	atomic_dec(&tconInfoAllocCount);
 	kfree(buf_to_free->nativeFileSystem);
+	if (buf_to_free->password) {
+		memset(buf_to_free->password, 0, strlen(buf_to_free->password));
+		kfree(buf_to_free->password);
+	}
 	kfree(buf_to_free);
 }