cifs: Cleanup and thus reduce smb session structure and fields used during authentication
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>
Thu, 28 Oct 2010 14:53:07 +0000 (09:53 -0500)
committerSteve French <sfrench@us.ibm.com>
Fri, 29 Oct 2010 01:47:33 +0000 (01:47 +0000)
Removed following fields from smb session structure
 cryptkey, ntlmv2_hash, tilen, tiblob
and ntlmssp_auth structure is allocated dynamically only if the auth mech
in NTLMSSP.

response field within a session_key structure is used to initially store the
target info (either plucked from type 2 challenge packet in case of NTLMSSP
or fabricated in case of NTLMv2 without extended security) and then to store
Message Authentication Key (mak) (session key + client response).

Server challenge or cryptkey needed during a NTLMSSP authentication
is now part of ntlmssp_auth structure which gets allocated and freed
once authenticaiton process is done.

Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
fs/cifs/cifsencrypt.c
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/sess.c

index ef95a27..f856732 100644 (file)
@@ -328,15 +328,15 @@ build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
         * two times the unicode length of a server name +
         * size of a timestamp (which is 8 bytes).
         */
-       ses->tilen = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8;
-       ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL);
-       if (!ses->tiblob) {
-               ses->tilen = 0;
+       ses->auth_key.len = size + 2 * (2 * dlen) + 2 * (2 * wlen) + 8;
+       ses->auth_key.response = kzalloc(ses->auth_key.len, GFP_KERNEL);
+       if (!ses->auth_key.response) {
+               ses->auth_key.len = 0;
                cERROR(1, "Challenge target info allocation failure");
                return -ENOMEM;
        }
 
-       blobptr = ses->tiblob;
+       blobptr = ses->auth_key.response;
        attrptr = (struct ntlmssp2_name *) blobptr;
 
        attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME);
@@ -400,11 +400,11 @@ find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
        unsigned char *blobend;
        struct ntlmssp2_name *attrptr;
 
-       if (!ses->tilen || !ses->tiblob)
+       if (!ses->auth_key.len || !ses->auth_key.response)
                return 0;
 
-       blobptr = ses->tiblob;
-       blobend = ses->tiblob + ses->tilen;
+       blobptr = ses->auth_key.response;
+       blobend = blobptr + ses->auth_key.len;
 
        while (blobptr + onesize < blobend) {
                attrptr = (struct ntlmssp2_name *) blobptr;
@@ -436,7 +436,7 @@ find_domain_name(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
        return 0;
 }
 
-static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
+static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash,
                            const struct nls_table *nls_cp)
 {
        int rc = 0;
@@ -509,7 +509,7 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
        }
 
        rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash,
-                                       ses->ntlmv2_hash);
+                                       ntlmv2_hash);
 
 calc_exit_1:
        kfree(user);
@@ -518,7 +518,7 @@ calc_exit_2:
 }
 
 static int
-CalcNTLMv2_response(const struct cifsSesInfo *ses)
+CalcNTLMv2_response(const struct cifsSesInfo *ses, char *ntlmv2_hash)
 {
        int rc;
        unsigned int offset = CIFS_SESS_KEY_SIZE + 8;
@@ -529,7 +529,7 @@ CalcNTLMv2_response(const struct cifsSesInfo *ses)
        }
 
        crypto_shash_setkey(ses->server->secmech.hmacmd5,
-                               ses->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
+                               ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
 
        rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
        if (rc) {
@@ -539,7 +539,7 @@ CalcNTLMv2_response(const struct cifsSesInfo *ses)
 
        if (ses->server->secType == RawNTLMSSP)
                memcpy(ses->auth_key.response + offset,
-                       ses->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
+                       ses->ntlmssp->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
        else
                memcpy(ses->auth_key.response + offset,
                        ses->server->cryptkey, CIFS_SERVER_CHALLENGE_SIZE);
@@ -558,7 +558,10 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
 {
        int rc;
        int baselen;
+       unsigned int tilen;
        struct ntlmv2_resp *buf;
+       char ntlmv2_hash[16];
+       unsigned char *tiblob = NULL; /* target info blob */
 
        if (ses->server->secType == RawNTLMSSP) {
                if (!ses->domainName) {
@@ -572,18 +575,22 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
                rc = build_avpair_blob(ses, nls_cp);
                if (rc) {
                        cERROR(1, "error %d building av pair blob", rc);
-                       return rc;
+                       goto setup_ntlmv2_rsp_ret;
                }
        }
 
        baselen = CIFS_SESS_KEY_SIZE + sizeof(struct ntlmv2_resp);
-       ses->auth_key.len = baselen + ses->tilen;
-       ses->auth_key.response = kmalloc(ses->auth_key.len, GFP_KERNEL);
+       tilen = ses->auth_key.len;
+       tiblob = ses->auth_key.response;
+
+       ses->auth_key.response = kmalloc(baselen + tilen, GFP_KERNEL);
        if (!ses->auth_key.response) {
                rc = ENOMEM;
+               ses->auth_key.len = 0;
                cERROR(1, "%s: Can't allocate auth blob", __func__);
                goto setup_ntlmv2_rsp_ret;
        }
+       ses->auth_key.len += baselen;
 
        buf = (struct ntlmv2_resp *)
                        (ses->auth_key.response + CIFS_SESS_KEY_SIZE);
@@ -593,17 +600,17 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
        get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
        buf->reserved2 = 0;
 
-       memcpy(ses->auth_key.response + baselen, ses->tiblob, ses->tilen);
+       memcpy(ses->auth_key.response + baselen, tiblob, tilen);
 
        /* calculate ntlmv2_hash */
-       rc = calc_ntlmv2_hash(ses, nls_cp);
+       rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
        if (rc) {
                cERROR(1, "could not get v2 hash rc %d", rc);
                goto setup_ntlmv2_rsp_ret;
        }
 
        /* calculate first part of the client response (CR1) */
-       rc = CalcNTLMv2_response(ses);
+       rc = CalcNTLMv2_response(ses, ntlmv2_hash);
        if (rc) {
                cERROR(1, "Could not calculate CR1  rc: %d", rc);
                goto setup_ntlmv2_rsp_ret;
@@ -611,7 +618,7 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
 
        /* now calculate the session key for NTLMv2 */
        crypto_shash_setkey(ses->server->secmech.hmacmd5,
-               ses->ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
+               ntlmv2_hash, CIFS_HMAC_MD5_HASH_SIZE);
 
        rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash);
        if (rc) {
@@ -627,9 +634,7 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
                ses->auth_key.response);
 
 setup_ntlmv2_rsp_ret:
-       kfree(ses->tiblob);
-       ses->tiblob = NULL;
-       ses->tilen = 0;
+       kfree(tiblob);
 
        return rc;
 }
@@ -657,7 +662,7 @@ calc_seckey(struct cifsSesInfo *ses)
                                        CIFS_SESS_KEY_SIZE);
 
        sg_init_one(&sgin, sec_key, CIFS_SESS_KEY_SIZE);
-       sg_init_one(&sgout, ses->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
+       sg_init_one(&sgout, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
 
        rc = crypto_blkcipher_encrypt(&desc, &sgout, &sgin, CIFS_CPHTXT_SIZE);
        if (rc) {
index b736951..f259e4d 100644 (file)
@@ -119,11 +119,12 @@ struct cifs_secmech {
        struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
 };
 
-/* per smb connection structure/fields */
+/* per smb session structure/fields */
 struct ntlmssp_auth {
        __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */
        __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */
        unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */
+       char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlmssp */
 };
 
 struct cifs_cred {
@@ -241,12 +242,8 @@ struct cifsSesInfo {
        char userName[MAX_USERNAME_SIZE + 1];
        char *domainName;
        char *password;
-       char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlmssp */
        struct session_key auth_key;
-       char ntlmv2_hash[16];
-       unsigned int tilen; /* length of the target info blob */
-       unsigned char *tiblob; /* target info blob in challenge response */
-       struct ntlmssp_auth ntlmssp; /* ciphertext, flags */
+       struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
        bool need_reconnect:1; /* connection reset, uid now invalid */
 };
 /* no more than one of the following three session flags may be set */
index 4d8004c..9eb327d 100644 (file)
@@ -1818,8 +1818,6 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
        if (ses == NULL)
                goto get_ses_fail;
 
-       ses->tilen = 0;
-       ses->tiblob = NULL;
        /* new SMB session uses our server ref */
        ses->server = server;
        if (server->addr.sockAddr6.sin6_family == AF_INET6)
@@ -1840,10 +1838,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
                        goto get_ses_fail;
        }
        if (volume_info->domainname) {
-               int len = strlen(volume_info->domainname);
-               ses->domainName = kmalloc(len + 1, GFP_KERNEL);
-               if (ses->domainName)
-                       strcpy(ses->domainName, volume_info->domainname);
+               ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL);
+               if (!ses->domainName)
+                       goto get_ses_fail;
        }
        ses->cred_uid = volume_info->cred_uid;
        ses->linux_uid = volume_info->linux_uid;
@@ -3213,6 +3210,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
        kfree(ses->auth_key.response);
        ses->auth_key.response = NULL;
        ses->auth_key.len = 0;
+       kfree(ses->ntlmssp);
+       ses->ntlmssp = NULL;
 
        return rc;
 }
index f74c5a8..7b01d3f 100644 (file)
@@ -399,23 +399,22 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len,
                return -EINVAL;
        }
 
-       memcpy(ses->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE);
+       memcpy(ses->ntlmssp->cryptkey, pblob->Challenge, CIFS_CRYPTO_KEY_SIZE);
        /* BB we could decode pblob->NegotiateFlags; some may be useful */
        /* In particular we can examine sign flags */
        /* BB spec says that if AvId field of MsvAvTimestamp is populated then
                we must set the MIC field of the AUTHENTICATE_MESSAGE */
-       ses->ntlmssp.server_flags = le32_to_cpu(pblob->NegotiateFlags);
+       ses->ntlmssp->server_flags = le32_to_cpu(pblob->NegotiateFlags);
        tioffset = cpu_to_le16(pblob->TargetInfoArray.BufferOffset);
        tilen = cpu_to_le16(pblob->TargetInfoArray.Length);
-       ses->tilen = tilen;
-       if (ses->tilen) {
-               ses->tiblob = kmalloc(tilen, GFP_KERNEL);
-               if (!ses->tiblob) {
+       if (tilen) {
+               ses->auth_key.response = kmalloc(tilen, GFP_KERNEL);
+               if (!ses->auth_key.response) {
                        cERROR(1, "Challenge target info allocation failure");
-                       ses->tilen = 0;
                        return -ENOMEM;
                }
-               memcpy(ses->tiblob,  bcc_ptr + tioffset, ses->tilen);
+               memcpy(ses->auth_key.response, bcc_ptr + tioffset, tilen);
+               ses->auth_key.len = tilen;
        }
 
        return 0;
@@ -545,9 +544,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer,
        sec_blob->WorkstationName.MaximumLength = 0;
        tmp += 2;
 
-       if ((ses->ntlmssp.server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
+       if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) &&
                        !calc_seckey(ses)) {
-               memcpy(tmp, ses->ntlmssp.ciphertext, CIFS_CPHTXT_SIZE);
+               memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE);
                sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer);
                sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE);
                sec_blob->SessionKey.MaximumLength =
@@ -601,8 +600,16 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses,
                return -EINVAL;
 
        type = ses->server->secType;
-
        cFYI(1, "sess setup type %d", type);
+       if (type == RawNTLMSSP) {
+               /* if memory allocation is successful, caller of this function
+                * frees it.
+                */
+               ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
+               if (!ses->ntlmssp)
+                       return -ENOMEM;
+       }
+
 ssetup_ntlmssp_authenticate:
        if (phase == NtLmChallenge)
                phase = NtLmAuthenticate; /* if ntlmssp, now final phase */