cifsencrypt.c 15.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *   fs/cifs/cifsencrypt.c
 *
4
 *   Copyright (C) International Business Machines  Corp., 2005,2006
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *   Author(s): Steve French (sfrench@us.ibm.com)
 *
 *   This library is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU Lesser General Public License for more details.
 *
 *   You should have received a copy of the GNU Lesser General Public License
 *   along with this library; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#include <linux/fs.h>
23
#include <linux/slab.h>
L
Linus Torvalds 已提交
24
#include "cifspdu.h"
S
Steve French 已提交
25
#include "cifsglob.h"
L
Linus Torvalds 已提交
26 27 28 29
#include "cifs_debug.h"
#include "md5.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
30
#include "ntlmssp.h"
31
#include <linux/ctype.h>
S
Steve French 已提交
32
#include <linux/random.h>
L
Linus Torvalds 已提交
33

S
Steve French 已提交
34
/* Calculate and return the CIFS signature based on the mac key and SMB PDU */
L
Linus Torvalds 已提交
35 36
/* the 16 byte signature must be allocated by the caller  */
/* Note we only use the 1st eight bytes */
S
Steve French 已提交
37
/* Note that the smb header signature field on input contains the
L
Linus Torvalds 已提交
38 39 40 41
	sequence number before this function is called */

extern void mdfour(unsigned char *out, unsigned char *in, int n);
extern void E_md4hash(const unsigned char *passwd, unsigned char *p16);
42
extern void SMBencrypt(unsigned char *passwd, const unsigned char *c8,
S
Steve French 已提交
43
		       unsigned char *p24);
44

S
Steve French 已提交
45
static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu,
46
				const struct session_key *key, char *signature)
L
Linus Torvalds 已提交
47
{
48
	struct	MD5Context context;
L
Linus Torvalds 已提交
49

50
	if ((cifs_pdu == NULL) || (signature == NULL) || (key == NULL))
L
Linus Torvalds 已提交
51 52
		return -EINVAL;

53 54 55
	cifs_MD5_init(&context);
	cifs_MD5_update(&context, (char *)&key->data, key->len);
	cifs_MD5_update(&context, cifs_pdu->Protocol, cifs_pdu->smb_buf_length);
56

57
	cifs_MD5_final(signature, &context);
58
	return 0;
L
Linus Torvalds 已提交
59 60
}

S
Steve French 已提交
61 62
int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server,
		  __u32 *pexpected_response_sequence_number)
L
Linus Torvalds 已提交
63 64 65 66
{
	int rc = 0;
	char smb_signature[20];

S
Steve French 已提交
67
	if ((cifs_pdu == NULL) || (server == NULL))
L
Linus Torvalds 已提交
68 69
		return -EINVAL;

S
Steve French 已提交
70
	if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
L
Linus Torvalds 已提交
71 72 73
		return rc;

	spin_lock(&GlobalMid_Lock);
74 75
	cifs_pdu->Signature.Sequence.SequenceNumber =
			cpu_to_le32(server->sequence_number);
L
Linus Torvalds 已提交
76
	cifs_pdu->Signature.Sequence.Reserved = 0;
77

78 79
	*pexpected_response_sequence_number = server->sequence_number++;
	server->sequence_number++;
L
Linus Torvalds 已提交
80 81
	spin_unlock(&GlobalMid_Lock);

82
	rc = cifs_calculate_signature(cifs_pdu, &server->session_key,
83
				      smb_signature);
S
Steve French 已提交
84
	if (rc)
L
Linus Torvalds 已提交
85 86 87 88 89 90 91
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
	else
		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);

	return rc;
}

S
Steve French 已提交
92
static int cifs_calc_signature2(const struct kvec *iov, int n_vec,
93
				const struct session_key *key, char *signature)
94
{
95
	struct  MD5Context context;
96
	int i;
97

98
	if ((iov == NULL) || (signature == NULL) || (key == NULL))
99
		return -EINVAL;
100

101 102
	cifs_MD5_init(&context);
	cifs_MD5_update(&context, (char *)&key->data, key->len);
103
	for (i = 0; i < n_vec; i++) {
104 105
		if (iov[i].iov_len == 0)
			continue;
S
Steve French 已提交
106
		if (iov[i].iov_base == NULL) {
107
			cERROR(1, "null iovec entry");
108
			return -EIO;
109
		}
S
Steve French 已提交
110
		/* The first entry includes a length field (which does not get
111
		   signed that occupies the first 4 bytes before the header */
S
Steve French 已提交
112
		if (i == 0) {
113
			if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
114
				break; /* nothing to sign or corrupt header */
115 116
			cifs_MD5_update(&context, iov[0].iov_base+4,
				  iov[0].iov_len-4);
117
		} else
118
			cifs_MD5_update(&context, iov[i].iov_base, iov[i].iov_len);
119
	}
120

121
	cifs_MD5_final(signature, &context);
122

123
	return 0;
124 125
}

126

S
Steve French 已提交
127
int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server,
128
		   __u32 *pexpected_response_sequence_number)
129 130 131
{
	int rc = 0;
	char smb_signature[20];
S
Steve French 已提交
132
	struct smb_hdr *cifs_pdu = iov[0].iov_base;
133

S
Steve French 已提交
134
	if ((cifs_pdu == NULL) || (server == NULL))
135 136
		return -EINVAL;

S
Steve French 已提交
137
	if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0)
138 139
		return rc;

S
Steve French 已提交
140 141
	spin_lock(&GlobalMid_Lock);
	cifs_pdu->Signature.Sequence.SequenceNumber =
142
				cpu_to_le32(server->sequence_number);
S
Steve French 已提交
143
	cifs_pdu->Signature.Sequence.Reserved = 0;
144

S
Steve French 已提交
145 146 147
	*pexpected_response_sequence_number = server->sequence_number++;
	server->sequence_number++;
	spin_unlock(&GlobalMid_Lock);
148

149
	rc = cifs_calc_signature2(iov, n_vec, &server->session_key,
150
				      smb_signature);
S
Steve French 已提交
151 152 153 154
	if (rc)
		memset(cifs_pdu->Signature.SecuritySignature, 0, 8);
	else
		memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8);
155

S
Steve French 已提交
156
	return rc;
157 158
}

159
int cifs_verify_signature(struct smb_hdr *cifs_pdu,
160
			  const struct session_key *session_key,
S
Steve French 已提交
161
			  __u32 expected_sequence_number)
L
Linus Torvalds 已提交
162
{
163
	unsigned int rc;
L
Linus Torvalds 已提交
164 165 166
	char server_response_sig[8];
	char what_we_think_sig_should_be[20];

167
	if (cifs_pdu == NULL || session_key == NULL)
L
Linus Torvalds 已提交
168 169 170 171 172 173
		return -EINVAL;

	if (cifs_pdu->Command == SMB_COM_NEGOTIATE)
		return 0;

	if (cifs_pdu->Command == SMB_COM_LOCKING_ANDX) {
174
		struct smb_com_lock_req *pSMB =
S
Steve French 已提交
175 176
			(struct smb_com_lock_req *)cifs_pdu;
	    if (pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)
L
Linus Torvalds 已提交
177 178 179
			return 0;
	}

180 181 182
	/* BB what if signatures are supposed to be on for session but
	   server does not send one? BB */

L
Linus Torvalds 已提交
183
	/* Do not need to verify session setups with signature "BSRSPYL "  */
184
	if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) == 0)
185 186
		cFYI(1, "dummy signature received for smb command 0x%x",
			cifs_pdu->Command);
L
Linus Torvalds 已提交
187 188 189

	/* save off the origiginal signature so we can modify the smb and check
		its signature against what the server sent */
190
	memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8);
L
Linus Torvalds 已提交
191

192 193
	cifs_pdu->Signature.Sequence.SequenceNumber =
					cpu_to_le32(expected_sequence_number);
L
Linus Torvalds 已提交
194 195
	cifs_pdu->Signature.Sequence.Reserved = 0;

196
	rc = cifs_calculate_signature(cifs_pdu, session_key,
L
Linus Torvalds 已提交
197 198
		what_we_think_sig_should_be);

199
	if (rc)
L
Linus Torvalds 已提交
200 201
		return rc;

202 203
/*	cifs_dump_mem("what we think it should be: ",
		      what_we_think_sig_should_be, 16); */
L
Linus Torvalds 已提交
204

205
	if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
L
Linus Torvalds 已提交
206 207 208 209 210 211 212
		return -EACCES;
	else
		return 0;

}

/* We fill in key by putting in 40 byte array which was allocated by caller */
213
int cifs_calculate_session_key(struct session_key *key, const char *rn,
214
			   const char *password)
L
Linus Torvalds 已提交
215 216 217 218 219 220
{
	char temp_key[16];
	if ((key == NULL) || (rn == NULL))
		return -EINVAL;

	E_md4hash(password, temp_key);
221 222 223
	mdfour(key->data.ntlm, temp_key, 16);
	memcpy(key->data.ntlm+16, rn, CIFS_SESS_KEY_SIZE);
	key->len = 40;
L
Linus Torvalds 已提交
224 225 226
	return 0;
}

227
#ifdef CONFIG_CIFS_WEAK_PW_HASH
228 229
void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
			char *lnm_session_key)
230 231 232 233 234
{
	int i;
	char password_with_pad[CIFS_ENCPWD_SIZE];

	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
235 236 237
	if (password)
		strncpy(password_with_pad, password, CIFS_ENCPWD_SIZE);

238
	if (!encrypt && global_secflags & CIFSSEC_MAY_PLNTXT) {
239 240 241 242 243
		memset(lnm_session_key, 0, CIFS_SESS_KEY_SIZE);
		memcpy(lnm_session_key, password_with_pad,
			CIFS_ENCPWD_SIZE);
		return;
	}
244

245 246 247 248 249 250 251 252 253 254 255
	/* calculate old style session key */
	/* calling toupper is less broken than repeatedly
	calling nls_toupper would be since that will never
	work for UTF8, but neither handles multibyte code pages
	but the only alternative would be converting to UCS-16 (Unicode)
	(using a routine something like UniStrupr) then
	uppercasing and then converting back from Unicode - which
	would only worth doing it if we knew it were utf8. Basically
	utf8 and other multibyte codepages each need their own strupper
	function since a byte at a time will ont work. */

256
	for (i = 0; i < CIFS_ENCPWD_SIZE; i++)
257 258
		password_with_pad[i] = toupper(password_with_pad[i]);

259 260
	SMBencrypt(password_with_pad, cryptkey, lnm_session_key);

261 262 263 264 265
	/* clear password before we return/free memory */
	memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
}
#endif /* CIFS_WEAK_PW_HASH */

266 267 268 269
/* 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.
270 271
 */
static int
272
build_avpair_blob(struct cifsSesInfo *ses, const struct nls_table *nls_cp)
273
{
274 275 276 277 278 279
	unsigned int dlen;
	unsigned int wlen;
	unsigned int size = 6 * sizeof(struct ntlmssp2_name);
	__le64  curtime;
	char *defdmname = "WORKGROUP";
	unsigned char *blobptr;
280 281
	struct ntlmssp2_name *attrptr;

282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
	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;
298 299 300 301 302 303
	ses->tiblob = kzalloc(ses->tilen, GFP_KERNEL);
	if (!ses->tiblob) {
		ses->tilen = 0;
		cERROR(1, "Challenge target info allocation failure");
		return -ENOMEM;
	}
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344

	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));
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388

	return 0;
}

/* Server has provided av pairs/target info in the type 2 challenge
 * packet and we have plucked it and stored within smb session.
 * We parse that blob here to find netbios domain name to be used
 * as part of ntlmv2 authentication (in Target String), if not already
 * specified on the command line.
 * If this function returns without any error but without fetching
 * domain name, authentication may fail against some server but
 * may not fail against other (those who are not very particular
 * about target string i.e. for some, just user name might suffice.
 */
static int
find_domain_name(struct cifsSesInfo *ses)
{
	unsigned int attrsize;
	unsigned int type;
	unsigned int onesize = sizeof(struct ntlmssp2_name);
	unsigned char *blobptr;
	unsigned char *blobend;
	struct ntlmssp2_name *attrptr;

	if (!ses->tilen || !ses->tiblob)
		return 0;

	blobptr = ses->tiblob;
	blobend = ses->tiblob + ses->tilen;

	while (blobptr + onesize < blobend) {
		attrptr = (struct ntlmssp2_name *) blobptr;
		type = le16_to_cpu(attrptr->type);
		if (type == NTLMSSP_AV_EOL)
			break;
		blobptr += 2; /* advance attr type */
		attrsize = le16_to_cpu(attrptr->length);
		blobptr += 2; /* advance attr size */
		if (blobptr + attrsize > blobend)
			break;
		if (type == NTLMSSP_AV_NB_DOMAIN_NAME) {
			if (!attrsize)
				break;
			if (!ses->domainName) {
389
				struct nls_table *default_nls;
390 391 392 393
				ses->domainName =
					kmalloc(attrsize + 1, GFP_KERNEL);
				if (!ses->domainName)
						return -ENOMEM;
394
				default_nls = load_nls_default();
395 396
				cifs_from_ucs2(ses->domainName,
					(__le16 *)blobptr, attrsize, attrsize,
397 398
					default_nls, false);
				unload_nls(default_nls);
399 400 401 402 403 404 405 406 407
				break;
			}
		}
		blobptr += attrsize; /* advance attr  value */
	}

	return 0;
}

408 409
static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
			    const struct nls_table *nls_cp)
S
Steve French 已提交
410 411 412
{
	int rc = 0;
	int len;
413 414
	char nt_hash[16];
	struct HMACMD5Context *pctxt;
415 416
	wchar_t *user;
	wchar_t *domain;
S
Steve French 已提交
417

418
	pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);
S
Steve French 已提交
419

420 421
	if (pctxt == NULL)
		return -ENOMEM;
422

423 424
	/* calculate md4 hash of password */
	E_md4hash(ses->password, nt_hash);
425

426 427
	/* convert Domainname to unicode and uppercase */
	hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);
S
Steve French 已提交
428 429

	/* convert ses->userName to unicode and uppercase */
S
Steve French 已提交
430 431
	len = strlen(ses->userName);
	user = kmalloc(2 + (len * 2), GFP_KERNEL);
432
	if (user == NULL)
S
Steve French 已提交
433
		goto calc_exit_2;
434
	len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp);
S
Steve French 已提交
435
	UniStrupr(user);
436
	hmac_md5_update((char *)user, 2*len, pctxt);
S
Steve French 已提交
437 438

	/* convert ses->domainName to unicode and uppercase */
439
	if (ses->domainName) {
S
Steve French 已提交
440
		len = strlen(ses->domainName);
S
Steve French 已提交
441

442
		domain = kmalloc(2 + (len * 2), GFP_KERNEL);
443
		if (domain == NULL)
S
Steve French 已提交
444
			goto calc_exit_1;
445 446
		len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len,
					nls_cp);
447 448 449 450
		/* the following line was removed since it didn't work well
		   with lower cased domain name that passed as an option.
		   Maybe converting the domain name earlier makes sense */
		/* UniStrupr(domain); */
S
Steve French 已提交
451

452
		hmac_md5_update((char *)domain, 2*len, pctxt);
453

S
Steve French 已提交
454 455 456 457 458
		kfree(domain);
	}
calc_exit_1:
	kfree(user);
calc_exit_2:
459
	/* BB FIXME what about bytes 24 through 40 of the signing key?
S
Steve French 已提交
460
	   compare with the NTLM example */
461
	hmac_md5_final(ses->ntlmv2_hash, pctxt);
462

463
	kfree(pctxt);
464 465 466
	return rc;
}

467 468
int
setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
469 470
		      const struct nls_table *nls_cp)
{
471
	int rc;
472
	struct ntlmv2_resp *buf = (struct ntlmv2_resp *)resp_buf;
473
	struct HMACMD5Context context;
S
Steve French 已提交
474 475 476 477

	buf->blob_signature = cpu_to_le32(0x00000101);
	buf->reserved = 0;
	buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
S
Steve French 已提交
478
	get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
S
Steve French 已提交
479
	buf->reserved2 = 0;
480 481 482 483 484 485 486 487 488 489

	if (ses->server->secType == RawNTLMSSP) {
		if (!ses->domainName) {
			rc = find_domain_name(ses);
			if (rc) {
				cERROR(1, "error %d finding domain name", rc);
				goto setup_ntlmv2_rsp_ret;
			}
		}
	} else {
490
		rc = build_avpair_blob(ses, nls_cp);
491 492 493 494 495
		if (rc) {
			cERROR(1, "error %d building av pair blob", rc);
			return rc;
		}
	}
S
Steve French 已提交
496

S
Steve French 已提交
497
	/* calculate buf->ntlmv2_hash */
S
Steve French 已提交
498
	rc = calc_ntlmv2_hash(ses, nls_cp);
499
	if (rc) {
500
		cERROR(1, "could not get v2 hash rc %d", rc);
501 502
		goto setup_ntlmv2_rsp_ret;
	}
503
	CalcNTLMv2_response(ses, resp_buf);
504

505 506
	/* now calculate the session key for NTLMv2 */
	hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context);
507
	hmac_md5_update(resp_buf, 16, &context);
508
	hmac_md5_final(ses->auth_key.data.ntlmv2.key, &context);
509

510
	memcpy(&ses->auth_key.data.ntlmv2.resp, resp_buf,
511
	       sizeof(struct ntlmv2_resp));
512
	ses->auth_key.len = 16 + sizeof(struct ntlmv2_resp);
513 514 515 516 517 518 519 520 521

	return 0;

setup_ntlmv2_rsp_ret:
	kfree(ses->tiblob);
	ses->tiblob = NULL;
	ses->tilen = 0;

	return rc;
S
Steve French 已提交
522 523
}

524 525
void CalcNTLMv2_response(const struct cifsSesInfo *ses,
			 char *v2_session_response)
526
{
527 528
	struct HMACMD5Context context;
	/* rest of v2 struct already generated */
529 530
	memcpy(v2_session_response + 8, ses->cryptKey, 8);
	hmac_md5_init_limK_to_64(ses->ntlmv2_hash, 16, &context);
531

532 533
	hmac_md5_update(v2_session_response+8,
			sizeof(struct ntlmv2_resp) - 8, &context);
534

535 536 537
	if (ses->tilen)
		hmac_md5_update(ses->tiblob, ses->tilen, &context);

538 539
	hmac_md5_final(v2_session_response, &context);
/*	cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
L
Linus Torvalds 已提交
540
}