diff options
-rw-r--r-- | fs/cifs/cifsencrypt.c | 80 |
1 files changed, 69 insertions, 11 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 89fb94fac4b5..e3edd8a6840b 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -263,27 +263,85 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt, } #endif /* CIFS_WEAK_PW_HASH */ -/* This is just a filler for ntlmv2 type of security mechanisms. - * Older servers are not very particular about the contents of av pairs - * in the blob and for sec mechs like ntlmv2, there is no negotiation - * as in ntlmssp, so unless domain and server netbios and dns names - * are specified, there is no way to obtain name. In case of ntlmssp, - * server provides that info in type 2 challenge packet +/* Build a proper attribute value/target info pairs blob. + * Fill in netbios and dns domain name and workstation name + * and client time (total five av pairs and + one end of fields indicator. + * Allocate domain name which gets freed when session struct is deallocated. */ static int -build_avpair_blob(struct cifsSesInfo *ses) +build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp) { + unsigned int dlen; + unsigned int wlen; + unsigned int size = 6 * sizeof(struct ntlmssp2_name); + __le64 curtime; + char *defdmname = "WORKGROUP"; + unsigned char *blobptr; struct ntlmssp2_name *attrptr; - ses->tilen = 2 * sizeof(struct ntlmssp2_name); + if (!ses->domainName) { + ses->domainName = kstrdup(defdmname, GFP_KERNEL); + if (!ses->domainName) + return -ENOMEM; + } + + dlen = strlen(ses->domainName); + wlen = strlen(ses->server->hostname); + + /* The length of this blob is a size which is + * six times the size of a structure which holds name/size + + * two times the unicode length of a domain name + + * 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; cERROR(1, "Challenge target info allocation failure"); return -ENOMEM; } - attrptr = (struct ntlmssp2_name *) ses->tiblob; - attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); + + blobptr = ses->tiblob; + attrptr = (struct ntlmssp2_name *) blobptr; + + attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_DOMAIN_NAME); + attrptr->length = cpu_to_le16(2 * dlen); + blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); + cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp); + + blobptr += 2 * dlen; + attrptr = (struct ntlmssp2_name *) blobptr; + + attrptr->type = cpu_to_le16(NTLMSSP_AV_NB_COMPUTER_NAME); + attrptr->length = cpu_to_le16(2 * wlen); + blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); + cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp); + + blobptr += 2 * wlen; + attrptr = (struct ntlmssp2_name *) blobptr; + + attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_DOMAIN_NAME); + attrptr->length = cpu_to_le16(2 * dlen); + blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); + cifs_strtoUCS((__le16 *)blobptr, ses->domainName, dlen, nls_cp); + + blobptr += 2 * dlen; + attrptr = (struct ntlmssp2_name *) blobptr; + + attrptr->type = cpu_to_le16(NTLMSSP_AV_DNS_COMPUTER_NAME); + attrptr->length = cpu_to_le16(2 * wlen); + blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); + cifs_strtoUCS((__le16 *)blobptr, ses->server->hostname, wlen, nls_cp); + + blobptr += 2 * wlen; + attrptr = (struct ntlmssp2_name *) blobptr; + + attrptr->type = cpu_to_le16(NTLMSSP_AV_TIMESTAMP); + attrptr->length = cpu_to_le16(sizeof(__le64)); + blobptr = (unsigned char *)attrptr + sizeof(struct ntlmssp2_name); + curtime = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + memcpy(blobptr, &curtime, sizeof(__le64)); return 0; } @@ -429,7 +487,7 @@ setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, } } } else { - rc = build_avpair_blob(ses); + rc = build_avpair_blob(ses, nls_cp); if (rc) { cERROR(1, "error %d building av pair blob", rc); return rc; |