Skip to content

Commit 2b149f1

Browse files
shirishpargaonkarSteve French
authored andcommitted
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>
1 parent 5f98ca9 commit 2b149f1

File tree

8 files changed

+225
-53
lines changed

8 files changed

+225
-53
lines changed

fs/cifs/cifsencrypt.c

Lines changed: 115 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "md5.h"
2828
#include "cifs_unicode.h"
2929
#include "cifsproto.h"
30+
#include "ntlmssp.h"
3031
#include <linux/ctype.h>
3132
#include <linux/random.h>
3233

@@ -262,6 +263,87 @@ void calc_lanman_hash(const char *password, const char *cryptkey, bool encrypt,
262263
}
263264
#endif /* CIFS_WEAK_PW_HASH */
264265

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+
*/
273+
static int
274+
build_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+
*/
301+
static int
302+
find_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+
265347
static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
266348
const struct nls_table *nls_cp)
267349
{
@@ -321,7 +403,8 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses,
321403
return rc;
322404
}
323405

324-
void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
406+
int
407+
setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
325408
const struct nls_table *nls_cp)
326409
{
327410
int rc;
@@ -333,15 +416,29 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
333416
buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME));
334417
get_random_bytes(&buf->client_chal, sizeof(buf->client_chal));
335418
buf->reserved2 = 0;
336-
buf->names[0].type = cpu_to_le16(NTLMSSP_DOMAIN_TYPE);
337-
buf->names[0].length = 0;
338-
buf->names[1].type = 0;
339-
buf->names[1].length = 0;
419+
420+
if (ses->server->secType == RawNTLMSSP) {
421+
if (!ses->domainName) {
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+
}
340435

341436
/* calculate buf->ntlmv2_hash */
342437
rc = calc_ntlmv2_hash(ses, nls_cp);
343-
if (rc)
438+
if (rc) {
344439
cERROR(1, "could not get v2 hash rc %d", rc);
440+
goto setup_ntlmv2_rsp_ret;
441+
}
345442
CalcNTLMv2_response(ses, resp_buf);
346443

347444
/* now calculate the MAC key for NTLMv2 */
@@ -352,6 +449,15 @@ void setup_ntlmv2_rsp(struct cifsSesInfo *ses, char *resp_buf,
352449
memcpy(&ses->server->session_key.data.ntlmv2.resp, resp_buf,
353450
sizeof(struct ntlmv2_resp));
354451
ses->server->session_key.len = 16 + sizeof(struct ntlmv2_resp);
452+
453+
return 0;
454+
455+
setup_ntlmv2_rsp_ret:
456+
kfree(ses->tiblob);
457+
ses->tiblob = NULL;
458+
ses->tilen = 0;
459+
460+
return rc;
355461
}
356462

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

474+
if (ses->tilen)
475+
hmac_md5_update(ses->tiblob, ses->tilen, &context);
476+
368477
hmac_md5_final(v2_session_response, &context);
369478
/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */
370479
}

fs/cifs/cifsglob.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,8 @@ struct cifsSesInfo {
222222
char userName[MAX_USERNAME_SIZE + 1];
223223
char *domainName;
224224
char *password;
225+
unsigned int tilen; /* length of the target info blob */
226+
unsigned char *tiblob; /* target info blob in challenge response */
225227
bool need_reconnect:1; /* connection reset, uid now invalid */
226228
};
227229
/* no more than one of the following three session flags may be set */

fs/cifs/cifspdu.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,6 @@ struct ntlmv2_resp {
663663
__le64 time;
664664
__u64 client_chal; /* random */
665665
__u32 reserved2;
666-
struct ntlmssp2_name names[2];
667666
/* array of name entries could follow ending in minimum 4 byte struct */
668667
} __attribute__((packed));
669668

fs/cifs/cifsproto.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ extern int cifs_verify_signature(struct smb_hdr *,
368368
extern int cifs_calculate_session_key(struct session_key *key, const char *rn,
369369
const char *pass);
370370
extern void CalcNTLMv2_response(const struct cifsSesInfo *, char *);
371-
extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
371+
extern int setup_ntlmv2_rsp(struct cifsSesInfo *, char *,
372372
const struct nls_table *);
373373
#ifdef CONFIG_CIFS_WEAK_PW_HASH
374374
extern void calc_lanman_hash(const char *password, const char *cryptkey,

fs/cifs/cifssmb.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -603,13 +603,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
603603
rc = 0;
604604
else
605605
rc = -EINVAL;
606-
607-
if (server->sec_kerberos || server->sec_mskerberos)
608-
server->secType = Kerberos;
609-
else if (server->sec_ntlmssp)
610-
server->secType = RawNTLMSSP;
611-
else
612-
rc = -EOPNOTSUPP;
606+
if (server->secType == Kerberos) {
607+
if (!server->sec_kerberos &&
608+
!server->sec_mskerberos)
609+
rc = -EOPNOTSUPP;
610+
} else if (server->secType == RawNTLMSSP) {
611+
if (!server->sec_ntlmssp)
612+
rc = -EOPNOTSUPP;
613+
} else
614+
rc = -EOPNOTSUPP;
613615
}
614616
} else
615617
server->capabilities &= ~CAP_EXTENDED_SECURITY;

fs/cifs/connect.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
17401740
if (ses == NULL)
17411741
goto get_ses_fail;
17421742

1743+
ses->tilen = 0;
1744+
ses->tiblob = NULL;
17431745
/* new SMB session uses our server ref */
17441746
ses->server = server;
17451747
if (server->addr.sockAddr6.sin6_family == AF_INET6)

fs/cifs/ntlmssp.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@
6161
#define NTLMSSP_NEGOTIATE_KEY_XCH 0x40000000
6262
#define NTLMSSP_NEGOTIATE_56 0x80000000
6363

64+
/* Define AV Pair Field IDs */
65+
enum av_field_type {
66+
NTLMSSP_AV_EOL = 0,
67+
NTLMSSP_AV_NB_COMPUTER_NAME,
68+
NTLMSSP_AV_NB_DOMAIN_NAME,
69+
NTLMSSP_AV_DNS_COMPUTER_NAME,
70+
NTLMSSP_AV_DNS_DOMAIN_NAME,
71+
NTLMSSP_AV_DNS_TREE_NAME,
72+
NTLMSSP_AV_FLAGS,
73+
NTLMSSP_AV_TIMESTAMP,
74+
NTLMSSP_AV_RESTRICTION,
75+
NTLMSSP_AV_TARGET_NAME,
76+
NTLMSSP_AV_CHANNEL_BINDINGS
77+
};
78+
6479
/* Although typedefs are not commonly used for structure definitions */
6580
/* in the Linux kernel, in this particular case they are useful */
6681
/* to more closely match the standards document for NTLMSSP from */

0 commit comments

Comments
 (0)