[PATCH] cifs: Fix multiuser packet signing to use the right sequence number and mac...
authorSteve French <smfrench@austin.rr.com>
Fri, 29 Apr 2005 05:41:05 +0000 (22:41 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Fri, 29 Apr 2005 05:41:05 +0000 (22:41 -0700)
Signed-off-by: Steve French (sfrench@us.ibm.com)
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/cifs/CHANGES
fs/cifs/cifsencrypt.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/connect.c
fs/cifs/transport.c

index 7fd02697b12e47852cbbf60e2be51dbbce799514..43b3119a16edf5abae4106c36f685c6066163cb2 100644 (file)
@@ -5,7 +5,8 @@ transact response for an SMB request and search entry split across two frames.
 Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
 as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
 unless server explicitly claims to support them in CIFS Unix extensions
-POSIX ACL capability bit.
+POSIX ACL capability bit. Fix packet signing when multiuser mounting with
+different users from the same client to the same server.
 
 Version 1.31
 ------------
index 78829e7d8cd0187b327a8b051019848258754259..1959c7c4b185b48793ed81aee9d1cd61b50cc070 100644 (file)
@@ -50,7 +50,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char
        return 0;
 }
 
-int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
+int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server,
        __u32 * pexpected_response_sequence_number)
 {
        int rc = 0;
@@ -59,21 +59,21 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct cifsSesInfo * ses,
        /* BB remember to initialize sequence number elsewhere and initialize mac_signing key elsewhere BB */
        /* BB remember to add code to save expected sequence number in midQ entry BB */
 
-       if((cifs_pdu == NULL) || (ses == NULL))
+       if((cifs_pdu == NULL) || (server == NULL))
                return -EINVAL;
 
        if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) 
                return rc;
 
        spin_lock(&GlobalMid_Lock);
-       cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(ses->sequence_number);
+       cifs_pdu->Signature.Sequence.SequenceNumber = cpu_to_le32(server->sequence_number);
        cifs_pdu->Signature.Sequence.Reserved = 0;
        
-       *pexpected_response_sequence_number = ses->sequence_number++;
-       ses->sequence_number++;
+       *pexpected_response_sequence_number = server->sequence_number++;
+       server->sequence_number++;
        spin_unlock(&GlobalMid_Lock);
 
-       rc = cifs_calculate_signature(cifs_pdu, ses->mac_signing_key,smb_signature);
+       rc = cifs_calculate_signature(cifs_pdu, server->mac_signing_key,smb_signature);
        if(rc)
                memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
        else
@@ -190,7 +190,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_
        hmac_md5_update((const unsigned char *) unicode_buf,
                (user_name_len+dom_name_len)*2,&ctx);
 
-       hmac_md5_final(ses->mac_signing_key,&ctx);
+       hmac_md5_final(ses->server->mac_signing_key,&ctx);
        kfree(ucase_buf);
        kfree(unicode_buf);
        return 0;
@@ -200,7 +200,7 @@ void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_respon
        struct HMACMD5Context context;
        memcpy(v2_session_response + 8, ses->server->cryptKey,8);
        /* gen_blob(v2_session_response + 16); */
-       hmac_md5_init_limK_to_64(ses->mac_signing_key, 16, &context);
+       hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context);
 
        hmac_md5_update(ses->server->cryptKey,8,&context);
 /*     hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */
index 69aff1a7da9b3d1396dc430478afe75c0d19be50..1b3082d79379d872481aa3b109be42f408cb7c3f 100644 (file)
@@ -149,6 +149,8 @@ struct TCP_Server_Info {
        __u16 timeZone;
        char cryptKey[CIFS_CRYPTO_KEY_SIZE];
        char workstation_RFC1001_name[16]; /* 16th byte is always zero */
+       __u32 sequence_number; /* needed for CIFS PDU signature */
+       char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; 
 };
 
 /*
@@ -174,17 +176,16 @@ struct cifsSesInfo {
        struct TCP_Server_Info *server; /* pointer to server info */
        atomic_t inUse; /* # of mounts (tree connections) on this ses */
        enum statusEnum status;
-       __u32 sequence_number;  /* needed for CIFS PDU signature */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
        __u16 flags;
-       char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16];       
-       char *serverOS;         /* name of operating system underlying the server */
-       char *serverNOS;        /* name of network operating system that the server is running */
+       char *serverOS;         /* name of operating system underlying server */
+       char *serverNOS;        /* name of network operating system of server */
        char *serverDomain;     /* security realm of server */
        int Suid;               /* remote smb uid  */
        uid_t linux_uid;        /* local Linux uid */
        int capabilities;
-       char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
+       char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for 
+                               TCP names - will ipv6 and sctp addresses fit? */
        char userName[MAX_USERNAME_SIZE + 1];
        char domainName[MAX_USERNAME_SIZE + 1];
        char * password;
index 1b0070dfc51ceacc55cb568d64db7405e950e8d9..dd95c2bcbc25b869f0f059842fa5391d4fb1a1f5 100644 (file)
@@ -230,7 +230,7 @@ extern void tconInfoFree(struct cifsTconInfo *);
 
 extern int cifs_reconnect(struct TCP_Server_Info *server);
 
-extern int cifs_sign_smb(struct smb_hdr *, struct cifsSesInfo *,__u32 *);
+extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
 extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key,
        __u32 expected_sequence_number);
 extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass);
index 40470b9d5477a144331f10f12bd5bd7c2c7065be..814e709ca0cab6eebcd31cabd5939392423c08b7 100644 (file)
@@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
                        spin_lock(&GlobalMid_Lock);
                        if(server->tcpStatus != CifsExiting)
                                server->tcpStatus = CifsGood;
-                       spin_unlock(&GlobalMid_Lock);
+                       server->sequence_number = 0;
+                       spin_unlock(&GlobalMid_Lock);                   
        /*              atomic_set(&server->inFlight,0);*/
                        wake_up(&server->response_q);
                }
@@ -1352,6 +1353,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        } else
                                rc = 0;
                        memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16);
+                       srvTcp->sequence_number = 0;
                }
        }
 
@@ -2959,6 +2961,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
        int rc = 0;
        char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
        int ntlmv2_flag = FALSE;
+       int first_time = 0;
 
        /* what if server changes its buffer size after dropping the session? */
        if(pSesInfo->server->maxBuf == 0) /* no need to send on reconnect */ {
@@ -2977,12 +2980,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        spin_unlock(&GlobalMid_Lock);
 
                }
+               first_time = 1;
        }
        if (!rc) {
                pSesInfo->capabilities = pSesInfo->server->capabilities;
                if(linuxExtEnabled == 0)
                        pSesInfo->capabilities &= (~CAP_UNIX);
-               pSesInfo->sequence_number = 0;
+       /*      pSesInfo->sequence_number = 0;*/
                cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
@@ -3015,7 +3019,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                                v2_response = kmalloc(16 + 64 /* blob */, GFP_KERNEL);
                                        if(v2_response) {
                                                CalcNTLMv2_response(pSesInfo,v2_response);
-/*                                             cifs_calculate_ntlmv2_mac_key(pSesInfo->mac_signing_key, response, ntlm_session_key, */
+                               /*              if(first_time)
+                                                       cifs_calculate_ntlmv2_mac_key(
+                                                         pSesInfo->server->mac_signing_key, 
+                                                         response, ntlm_session_key, */
                                                kfree(v2_response);
                                        /* BB Put dummy sig in SessSetup PDU? */
                                        } else {
@@ -3028,9 +3035,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                                pSesInfo->server->cryptKey,
                                                ntlm_session_key);
 
-                                       cifs_calculate_mac_key(pSesInfo->mac_signing_key,
-                                               ntlm_session_key,
-                                               pSesInfo->password);
+                                       if(first_time)
+                                               cifs_calculate_mac_key(
+                                                       pSesInfo->server->mac_signing_key,
+                                                       ntlm_session_key,
+                                                       pSesInfo->password);
                                }
                        /* for better security the weaker lanman hash not sent
                           in AuthSessSetup so we no longer calculate it */
@@ -3046,8 +3055,11 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                                pSesInfo->server->cryptKey,
                                ntlm_session_key);
 
-                       cifs_calculate_mac_key(pSesInfo->mac_signing_key, 
-                               ntlm_session_key, pSesInfo->password);
+                       if(first_time)          
+                               cifs_calculate_mac_key(
+                                       pSesInfo->server->mac_signing_key,
+                                       ntlm_session_key, pSesInfo->password);
+
                        rc = CIFSSessSetup(xid, pSesInfo,
                                ntlm_session_key, nls_info);
                }
index af13e526b150ce3bf052eda83578bbb906f06d55..a9e4f989b7f744439989125e453017a7f323fa5b 100644 (file)
@@ -346,7 +346,7 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses,
        }
 
        /* BB can we sign efficiently in this path? */
-       rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+       rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
        midQ->midState = MID_REQUEST_SUBMITTED;
 /*     rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, piovec,
@@ -475,7 +475,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                return -EIO;
        }
 
-       rc = cifs_sign_smb(in_buf, ses, &midQ->sequence_number);
+       rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
 
        midQ->midState = MID_REQUEST_SUBMITTED;
        rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length,
@@ -559,8 +559,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
        }
   
        if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) {
-               cERROR(1,
-                      ("Frame too large received.  Length: %d  Xid: %d",
+               cERROR(1, ("Frame too large received.  Length: %d  Xid: %d",
                        receive_len, xid));
                rc = -EIO;
        } else {                /* rcvd frame is ok */
@@ -575,15 +574,20 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
                        dump_smb(out_buf, 92);
                        /* convert the length into a more usable form */
                        if((receive_len > 24) &&
-                          (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) {
-                               rc = cifs_verify_signature(out_buf, ses->mac_signing_key,midQ->sequence_number); /* BB fix BB */
-                               if(rc)
-                                       cFYI(1,("Unexpected signature received from server"));
+                          (ses->server->secMode & (SECMODE_SIGN_REQUIRED |
+                                       SECMODE_SIGN_ENABLED))) {
+                               rc = cifs_verify_signature(out_buf,
+                                               ses->server->mac_signing_key,
+                                               midQ->sequence_number+1);
+                               if(rc) {
+                                       cERROR(1,("Unexpected packet signature received from server"));
+                                       /* BB FIXME - add code to kill session here */
+                               }
                        }
 
                        *pbytes_returned = out_buf->smb_buf_length;
 
-                       /* BB special case reconnect tid and reconnect uid here? */
+                       /* BB special case reconnect tid and uid here? */
                        rc = map_smb_to_linux_error(out_buf);
 
                        /* convert ByteCount if necessary */