aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/cifsencrypt.c
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2010-09-18 23:02:18 -0400
committerSteve French <sfrench@us.ibm.com>2010-09-29 15:04:29 -0400
commit2b149f11978b44199954710d32c0eecf6c9efd9c (patch)
treeefd48d4b64fc07a244890d1fced9c767ae4f369b /fs/cifs/cifsencrypt.c
parent5f98ca9afb9c004f8948c0d40920503de447918a (diff)
cifs NTLMv2/NTLMSSP ntlmv2 within ntlmssp autentication code
Attribue Value (AV) pairs or Target Info (TI) pairs are part of ntlmv2 authentication. Structure ntlmv2_resp had only definition for two av pairs. So removed it, and now allocation of av pairs is dynamic. For servers like Windows 7/2008, av pairs sent by server in challege packet (type 2 in the ntlmssp exchange/negotiation) can vary. Server sends them during ntlmssp negotiation. So when ntlmssp is used as an authentication mechanism, type 2 challenge packet from server has this information. Pluck it and use the entire blob for authenticaiton purpose. If user has not specified, extract (netbios) domain name from the av pairs which is used to calculate ntlmv2 hash. Servers like Windows 7 are particular about the AV pair blob. Servers like Windows 2003, are not very strict about the contents of av pair blob used during ntlmv2 authentication. So when security mechanism such as ntlmv2 is used (not ntlmv2 in ntlmssp), there is no negotiation and so genereate a minimal blob that gets used in ntlmv2 authentication as well as gets sent. Fields tilen and tilbob are session specific. AV pair values are defined. To calculate ntlmv2 response we need ti/av pair blob. For sec mech like ntlmssp, the blob is plucked from type 2 response from the server. From this blob, netbios name of the domain is retrieved, if user has not already provided, to be included in the Target String as part of ntlmv2 hash calculations. For sec mech like ntlmv2, create a minimal, two av pair blob. The allocated blob is freed in case of error. In case there is no error, this blob is used in calculating ntlmv2 response (in CalcNTLMv2_response) and is also copied on the response to the server, and then freed. The type 3 ntlmssp response is prepared on a buffer, 5 * sizeof of struct _AUTHENTICATE_MESSAGE, an empirical value large enough to hold _AUTHENTICATE_MESSAGE plus a blob with max possible 10 values as part of ntlmv2 response and lmv2 keys and domain, user, workstation names etc. Also, kerberos gets selected as a default mechanism if server supports it, over the other security mechanisms. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/cifsencrypt.c')
-rw-r--r--fs/cifs/cifsencrypt.c121
1 files changed, 115 insertions, 6 deletions
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c
index eed70cae127..730038a1298 100644
--- a/fs/cifs/cifsencrypt.c
+++ b/fs/cifs/cifsencrypt.c
@@ -27,6 +27,7 @@
27#include "md5.h" 27#include "md5.h"
28#include "cifs_unicode.h" 28#include "cifs_unicode.h"
29#include "cifsproto.h" 29#include "cifsproto.h"
30#include "ntlmssp.h"
30#include <linux/ctype.h> 31#include <linux/ctype.h>
31#include <linux/random.h> 32#include <linux/random.h>
32 33
@@ -262,6 +263,87 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
262} 263}
263#endif /* CIFS_WEAK_PW_HASH */ 264#endif /* CIFS_WEAK_PW_HASH */
264 265
266/* This is just a filler for ntlmv2 type of security mechanisms.
267 * Older servers are not very particular about the contents of av pairs
268 * in the blob and for sec mechs like ntlmv2, there is no negotiation
269 * as in ntlmssp, so unless domain and server netbios and dns names
270 * are specified, there is no way to obtain name. In case of ntlmssp,
271 * server provides that info in type 2 challenge packet
272 */
273static int
274build_avpair_blob(struct cifsSesInfo *ses)
275{
276 struct ntlmssp2_name *attrptr;
277
278 ses->tilen = 2 * sizeof(struct ntlmssp2_name);
279 ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL);
280 if (!ses->tiblob) {
281 ses->tilen = 0;
282 cERROR(1, "Challenge target info allocation failure");
283 return -ENOMEM;
284 }
285 attrptr = (struct ntlmssp2_name *) ses->tiblob;
286 attrptr->type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
287
288 return 0;
289}
290
291/* Server has provided av pairs/target info in the type 2 challenge
292 * packet and we have plucked it and stored within smb session.
293 * We parse that blob here to find netbios domain name to be used
294 * as part of ntlmv2 authentication (in Target String), if not already
295 * specified on the command line.
296 * If this function returns without any error but without fetching
297 * domain name, authentication may fail against some server but
298 * may not fail against other (those who are not very particular
299 * about target string i.e. for some, just user name might suffice.
300 */
301static int
302find_domain_name(struct cifsSesInfo *ses)
303{
304 unsigned int attrsize;
305 unsigned int type;
306 unsigned int onesize = sizeof(struct ntlmssp2_name);
307 unsigned char *blobptr;
308 unsigned char *blobend;
309 struct ntlmssp2_name *attrptr;
310
311 if (!ses->tilen || !ses->tiblob)
312 return 0;
313
314 blobptr = ses->tiblob;
315 blobend = ses->tiblob + ses->tilen;
316
317 while (blobptr + onesize < blobend) {
318 attrptr = (struct ntlmssp2_name *) blobptr;
319 type = le16_to_cpu(attrptr->type);
320 if (type == NTLMSSP_AV_EOL)
321 break;
322 blobptr += 2; /* advance attr type */
323 attrsize = le16_to_cpu(attrptr->length);
324 blobptr += 2; /* advance attr size */
325 if (blobptr + attrsize > blobend)
326 break;
327 if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
328 if (!attrsize)
329 break;
330 if (!ses->domainName) {
331 ses->domainName =
332 kmalloc(attrsize + 1, GFP_KERNEL);
333 if (!ses->domainName)
334 return -ENOMEM;
335 cifs_from_ucs2(ses->domainName,
336 (__le16 *)blobptr, attrsize, attrsize,
337 load_nls_default(), false);
338 break;
339 }
340 }
341 blobptr += attrsize; /* advance attr value */
342 }
343
344 return 0;
345}
346
265static int calc_ntlmv2_hash(struct cifsSesInfo *ses, 347static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
266 const struct nls_table *nls_cp) 348 const struct nls_table *nls_cp)
267{ 349{
@@ -321,7 +403,8 @@ calc_exit_2:
321 return rc; 403 return rc;
322} 404}
323 405
324void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf, 406int
407setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
325 const struct nls_table *nls_cp) 408 const struct nls_table *nls_cp)
326{ 409{
327 int rc; 410 int rc;
@@ -333,15 +416,29 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
333 buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); 416 buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
334 get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); 417 get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
335 buf->reserved2 = 0; 418 buf->reserved2 = 0;
336 buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE); 419
337 buf->names[0].length = 0; 420 if (ses->server->secType == RawNTLMSSP) {
338 buf->names[1].type = 0; 421 if (!ses->domainName) {
339 buf->names[1].length = 0; 422 rc = find_domain_name(ses);
423 if (rc) {
424 cERROR(1, "error %d finding domain name", rc);
425 goto setup_ntlmv2_rsp_ret;
426 }
427 }
428 } else {
429 rc = build_avpair_blob(ses);
430 if (rc) {
431 cERROR(1, "error %d building av pair blob", rc);
432 return rc;
433 }
434 }
340 435
341 /* calculate buf->ntlmv2_hash */ 436 /* calculate buf->ntlmv2_hash */
342 rc = calc_ntlmv2_hash(ses, nls_cp); 437 rc = calc_ntlmv2_hash(ses, nls_cp);
343 if (rc) 438 if (rc) {
344 cERROR(1, "could not get v2 hash rc %d", rc); 439 cERROR(1, "could not get v2 hash rc %d", rc);
440 goto setup_ntlmv2_rsp_ret;
441 }
345 CalcNTLMv2_response(ses, resp_buf); 442 CalcNTLMv2_response(ses, resp_buf);
346 443
347 /* now calculate the MAC key for NTLMv2 */ 444 /* now calculate the MAC key for NTLMv2 */
@@ -352,6 +449,15 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
352 memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf, 449 memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf,
353 sizeof(struct ntlmv2_resp)); 450 sizeof(struct ntlmv2_resp));
354 ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp); 451 ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp);
452
453 return 0;
454
455setup_ntlmv2_rsp_ret:
456 kfree(ses->tiblob);
457 ses->tiblob = NULL;
458 ses->tilen = 0;
459
460 return rc;
355} 461}
356 462
357void CalcNTLMv2_response(const struct cifsSesInfo *ses, 463void CalcNTLMv2_response(const struct cifsSesInfo *ses,
@@ -365,6 +471,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
365 hmac_md5_update(v2_session_response+8, 471 hmac_md5_update(v2_session_response+8,
366 sizeof(struct ntlmv2_resp) - 8, &context); 472 sizeof(struct ntlmv2_resp) - 8, &context);
367 473
474 if (ses->tilen)
475 hmac_md5_update(ses->tiblob, ses->tilen, &context);
476
368 hmac_md5_final(v2_session_response, &context); 477 hmac_md5_final(v2_session_response, &context);
369/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ 478/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
370} 479}