Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 213391
b: refs/heads/master
c: 2b149f1
h: refs/heads/master
i:
  213389: a7324f0
  213387: 9bed75c
  213383: f798c0d
  213375: 47289bf
v: v3
  • Loading branch information
Shirish Pargaonkar authored and Steve French committed Sep 29, 2010
1 parent e8bfb54 commit ff82f64
Show file tree
Hide file tree
Showing 9 changed files with 226 additions and 54 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5f98ca9afb9c004f8948c0d40920503de447918a
refs/heads/master: 2b149f11978b44199954710d32c0eecf6c9efd9c
121 changes: 115 additions & 6 deletions trunk/fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "md5.h"
#include "cifs_unicode.h"
#include "cifsproto.h"
#include "ntlmssp.h"
#include <linux/ctype.h>
#include <linux/random.h>

Expand Down Expand Up @@ -262,6 +263,87 @@ 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
*/
static int
build_avpair_blob(struct cifsSesInfo *ses)
{
struct ntlmssp2_name *attrptr;

ses->tilen = 2 * sizeof(struct ntlmssp2_name);
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);

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) {
ses->domainName =
kmalloc(attrsize + 1, GFP_KERNEL);
if (!ses->domainName)
return -ENOMEM;
cifs_from_ucs2(ses->domainName,
(__le16 *)blobptr, attrsize, attrsize,
load_nls_default(), false);
break;
}
}
blobptr += attrsize; /* advance attr value */
}

return 0;
}

static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
const struct nls_table *nls_cp)
{
Expand Down Expand Up @@ -321,7 +403,8 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
return rc;
}

void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
int
setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
const struct nls_table *nls_cp)
{
int rc;
Expand All @@ -333,15 +416,29 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
buf->reserved2 = 0;
buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
buf->names[0].length = 0;
buf->names[1].type = 0;
buf->names[1].length = 0;

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 {
rc = build_avpair_blob(ses);
if (rc) {
cERROR(1, "error %d building av pair blob", rc);
return rc;
}
}

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

/* now calculate the MAC key for NTLMv2 */
Expand All @@ -352,6 +449,15 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf,
sizeof(struct ntlmv2_resp));
ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp);

return 0;

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

return rc;
}

void CalcNTLMv2_response(const struct cifsSesInfo *ses,
Expand All @@ -365,6 +471,9 @@ void CalcNTLMv2_response(const struct cifsSesInfo *ses,
hmac_md5_update(v2_session_response+8,
sizeof(struct ntlmv2_resp) - 8, &context);

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

hmac_md5_final(v2_session_response, &context);
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
}
2 changes: 2 additions & 0 deletions trunk/fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,8 @@ struct cifsSesInfo {
char userName[MAX_USERNAME_SIZE + 1];
char *domainName;
char *password;
unsigned int tilen; /* length of the target info blob */
unsigned char *tiblob; /* target info blob in challenge response */
bool need_reconnect:1; /* connection reset, uid now invalid */
};
/* no more than one of the following three session flags may be set */
Expand Down
1 change: 0 additions & 1 deletion trunk/fs/cifs/cifspdu.h
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,6 @@ struct ntlmv2_resp {
__le64 time;
__u64 client_chal; /* random */
__u32 reserved2;
struct ntlmssp2_name names[2];
/* array of name entries could follow ending in minimum 4 byte struct */
} __attribute__((packed));

Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ extern int cifs_verify_signature(struct smb_hdr *,
extern int cifs_calculate_session_key(struct session_key *key, const char *rn,
const char *pass);
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
const struct nls_table *);
#ifdef CONFIG_CIFS_WEAK_PW_HASH
extern void calc_lanman_hash(const char *password, const char *cryptkey,
Expand Down
16 changes: 9 additions & 7 deletions trunk/fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,13 +603,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
rc = 0;
else
rc = -EINVAL;

if (server->sec_kerberos || server->sec_mskerberos)
server->secType = Kerberos;
else if (server->sec_ntlmssp)
server->secType = RawNTLMSSP;
else
rc = -EOPNOTSUPP;
if (server->secType == Kerberos) {
if (!server->sec_kerberos &&
!server->sec_mskerberos)
rc = -EOPNOTSUPP;
} else if (server->secType == RawNTLMSSP) {
if (!server->sec_ntlmssp)
rc = -EOPNOTSUPP;
} else
rc = -EOPNOTSUPP;
}
} else
server->capabilities &= ~CAP_EXTENDED_SECURITY;
Expand Down
2 changes: 2 additions & 0 deletions trunk/fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,8 @@ 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)
Expand Down
15 changes: 15 additions & 0 deletions trunk/fs/cifs/ntlmssp.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
#define NTLMSSP_NEGOTIATE_56 0x80000000

/* Define AV Pair Field IDs */
enum av_field_type {
NTLMSSP_AV_EOL = 0,
NTLMSSP_AV_NB_COMPUTER_NAME,
NTLMSSP_AV_NB_DOMAIN_NAME,
NTLMSSP_AV_DNS_COMPUTER_NAME,
NTLMSSP_AV_DNS_DOMAIN_NAME,
NTLMSSP_AV_DNS_TREE_NAME,
NTLMSSP_AV_FLAGS,
NTLMSSP_AV_TIMESTAMP,
NTLMSSP_AV_RESTRICTION,
NTLMSSP_AV_TARGET_NAME,
NTLMSSP_AV_CHANNEL_BINDINGS
};

/* Although typedefs are not commonly used for structure definitions */
/* in the Linux kernel, in this particular case they are useful */
/* to more closely match the standards document for NTLMSSP from */
Expand Down
Loading

0 comments on commit ff82f64

Please sign in to comment.