Skip to content

Commit

Permalink
[CIFS] NTLMv2 support part 5
Browse files Browse the repository at this point in the history
NTLMv2 authentication (stronger authentication than default NTLM) which
many servers support now works.  There was a problem with the construction
of the security blob in the older code.  Currently requires
	/proc/fs/cifs/Experimental to be set to 2
and
	/proc/fs/cifs/SecurityFlags to be set to 0x4004 (to require using
	NTLMv2 instead of default of NTLM)

Next we will check signing to make sure optional NTLMv2 packet signing also
works.

Signed-off-by: Steve French <sfrench@us.ibm.com>
  • Loading branch information
Steve French committed Jun 8, 2006
1 parent f3ffb68 commit 1717ffc
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 24 deletions.
4 changes: 3 additions & 1 deletion fs/cifs/CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ session setup needed for OS/2 and older servers such as Windows 95 and 98.
Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst
so we can do search (ls etc.) to OS/2. Do not send NTCreateX
or recent levels of FindFirst unless server says it supports NT SMBs
(instead use legacy equivalents from LANMAN dialect).
(instead use legacy equivalents from LANMAN dialect). Fix to allow
NTLMv2 authentication support (now can use stronger password hashing
on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004)

Version 1.43
------------
Expand Down
60 changes: 41 additions & 19 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,8 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password)
return 0;
}

int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info)
int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses,
const struct nls_table * nls_info)
{
char temp_hash[16];
struct HMACMD5Context ctx;
Expand Down Expand Up @@ -305,13 +306,15 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key)
}
#endif /* CIFS_WEAK_PW_HASH */

static int calc_ntlmv2_hash(const struct cifsSesInfo *ses,
char * ntv2_hash)
static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
int rc = 0;
int len;
char nt_hash[16];
struct HMACMD5Context * pctxt;
wchar_t * user;
wchar_t * domain;

pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL);

Expand All @@ -321,54 +324,73 @@ static int calc_ntlmv2_hash(const struct cifsSesInfo *ses,
/* calculate md4 hash of password */
E_md4hash(ses->password, nt_hash);

/* convERT Domainname to unicode and uppercase */
/* convert Domainname to unicode and uppercase */
hmac_md5_init_limK_to_64(nt_hash, 16, pctxt);

/* convert ses->userName to unicode and uppercase */

/* len = ... */ /* BB FIXME BB */

/* hmac_md5_update(user, len, pctxt); */
len = strlen(ses->userName);
user = kmalloc(2 + (len * 2), GFP_KERNEL);
if(user == NULL)
goto calc_exit_2;
len = cifs_strtoUCS(user, ses->userName, len, nls_cp);
UniStrupr(user);
hmac_md5_update((char *)user, 2*len, pctxt);

/* convert ses->domainName to unicode and uppercase */
if(ses->domainName) {
len = strlen(ses->domainName);

/* len = ... */ /* BB FIXME BB */
/* hmac_md5_update(domain, len, pctxt); */
domain = kmalloc(2 + (len * 2), GFP_KERNEL);
if(domain == NULL)
goto calc_exit_1;
len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp);
UniStrupr(domain);

hmac_md5_final(ntv2_hash, pctxt);
hmac_md5_update((char *)domain, 2*len, pctxt);

kfree(domain);
}
calc_exit_1:
kfree(user);
calc_exit_2:
/* BB FIXME what about bytes 24 through 40 of the signing key?
compare with the NTLM example */
hmac_md5_final(ses->server->mac_signing_key, pctxt);

return rc;
}

void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf)
void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf,
const struct nls_table * nls_cp)
{
int rc;
struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf;

buf->blob_signature = cpu_to_le32(0x00000101);
buf->reserved = 0;
buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
buf->reserved2 = 0;
buf->names[0].type = 0;
buf->names[0].length = 0;

/* calculate buf->ntlmv2_hash */
rc = calc_ntlmv2_hash(ses,buf->ntlmv2_hash);
rc = calc_ntlmv2_hash(ses, nls_cp);
if(rc)
cERROR(1,("could not get v2 hash rc %d",rc));
CalcNTLMv2_response(ses, resp_buf);
}

void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response)
void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response)
{
struct HMACMD5Context context;
/* rest of v2 struct already generated */
memcpy(v2_session_response + 8, ses->server->cryptKey,8);
/* gen_blob(v2_session_response + 16); */
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 */
hmac_md5_update(v2_session_response+8,
sizeof(struct ntlmv2_resp) - 8, &context);

hmac_md5_final(v2_session_response,&context);
cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
}
8 changes: 5 additions & 3 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,11 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
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);
extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *);
extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * );
extern void setup_ntlmv2_rsp(const struct cifsSesInfo *, char *);
extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *,
const struct nls_table *);
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * );
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
const struct nls_table *);
#ifdef CONFIG_CIFS_WEAK_PW_HASH
extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key);
#endif /* CIFS_WEAK_PW_HASH */
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
cpu_to_le16(sizeof(struct ntlmv2_resp));

/* calculate session key */
setup_ntlmv2_rsp(ses, v2_sess_key);
setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
if(first_time) /* should this be moved into common code
with similar ntlmv2 path? */
/* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
Expand Down

0 comments on commit 1717ffc

Please sign in to comment.