summaryrefslogtreecommitdiff
path: root/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/smbsrv/libsmb/common/smb_auth.c')
-rw-r--r--usr/src/lib/smbsrv/libsmb/common/smb_auth.c138
1 files changed, 90 insertions, 48 deletions
diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
index d8950616db..ccd33ca1af 100644
--- a/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_auth.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -303,7 +303,6 @@ smb_auth_ntlmv2_hash(unsigned char *ntlm_hash,
return (SMBAUTH_FAILURE);
(void) utf8_strupr(username);
- (void) utf8_strupr(ntdomain);
data_len = strlen(username) + strlen(ntdomain);
buf = (unsigned char *)malloc((data_len + 1) * sizeof (char));
@@ -397,6 +396,7 @@ smb_auth_set_info(char *username,
unsigned short blob_len;
unsigned char blob_buf[SMBAUTH_BLOB_MAXLEN];
int rc;
+ char *uppercase_dom;
auth->lmcompatibility_lvl = lmcomp_lvl;
if (lmcomp_lvl == 2) {
@@ -421,12 +421,23 @@ smb_auth_set_info(char *username,
(void) memcpy(auth->hash, ntlm_hash, SMBAUTH_HASH_SZ);
}
+ if (!domain)
+ return (-1);
+
+ if ((uppercase_dom = strdup(domain)) == NULL)
+ return (-1);
+
+ (void) utf8_strupr(uppercase_dom);
+
if (smb_auth_ntlmv2_hash(auth->hash, username,
- domain, auth->hash_v2) != SMBAUTH_SUCCESS)
+ uppercase_dom, auth->hash_v2) != SMBAUTH_SUCCESS) {
+ free(uppercase_dom);
return (-1);
+ }
/* generate data blob */
- smb_auth_gen_data_blob(&auth->data_blob, domain);
+ smb_auth_gen_data_blob(&auth->data_blob, uppercase_dom);
+ free(uppercase_dom);
blob_len = smb_auth_blob_to_string(&auth->data_blob, blob_buf);
/* generate NTLMv2 response */
@@ -538,67 +549,90 @@ smb_ntlmv2_password_ok(
unsigned char *ntlm_hash,
unsigned char *passwd,
int pwdlen,
+ char *domain,
char *username)
{
unsigned char *clnt_blob;
int clnt_blob_len;
unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
unsigned char *ntlmv2_resp;
- boolean_t ok;
+ boolean_t ok = B_FALSE;
+ char *dest[3];
+ int i;
clnt_blob_len = pwdlen - SMBAUTH_HASH_SZ;
clnt_blob = &passwd[SMBAUTH_HASH_SZ];
+ dest[0] = domain;
+ if ((dest[1] = strdup(domain)) == NULL)
+ return (B_FALSE);
+ (void) utf8_strupr(dest[1]);
+ dest[2] = "";
/*
* 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
*
- * * The NTLMv2 Hash is created from:
+ * The NTLMv2 Hash is created from:
* - NTLM hash
* - user's username, and
* - the name of the logon destination(i.e. the NetBIOS name of either
- * the SMB server or NT Domain against which the suer is trying to
+ * the SMB server or NT Domain against which the user is trying to
* authenticate.
*
- * (N.L.) With my experience, this is not exactly true. It's really
- * tricky how the NTLMv2 hash is generated by the Windows client when
- * logging into a standalone server using NTLMv2 challenge / response.
- * The NTLMv2 hash is actually created with the destination info=""
- * as opposed to the SMB server name mentioned in the book.
+ * Experiments show this is not exactly the case.
+ * For Windows Server 2003, the domain name needs to be included and
+ * converted to uppercase. For Vista, the domain name needs to be
+ * included also, but leave the case alone. And in some cases it needs
+ * to be empty. All three variants are tried here.
*/
- if (smb_auth_ntlmv2_hash(ntlm_hash, username, "", ntlmv2_hash) !=
- SMBAUTH_SUCCESS) {
- return (B_FALSE);
- }
ntlmv2_resp = (unsigned char *)malloc(SMBAUTH_HASH_SZ + clnt_blob_len);
- if (ntlmv2_resp == NULL)
- return (B_FALSE);
-
- if (smb_auth_v2_response(ntlmv2_hash, challenge,
- clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0) {
- free(ntlmv2_resp);
+ if (ntlmv2_resp == NULL) {
+ free(dest[1]);
return (B_FALSE);
}
- ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
+ for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
+ if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
+ ntlmv2_hash) != SMBAUTH_SUCCESS)
+ break;
+
+ if (smb_auth_v2_response(ntlmv2_hash, challenge,
+ clen, clnt_blob, clnt_blob_len, ntlmv2_resp) < 0)
+ break;
+
+ ok = (bcmp(passwd, ntlmv2_resp, pwdlen) == 0);
+ if (ok == B_TRUE)
+ break;
+ }
+
+ free(dest[1]);
free(ntlmv2_resp);
return (ok);
}
-static int
+static boolean_t
smb_lmv2_password_ok(
unsigned char *challenge,
uint32_t clen,
unsigned char *ntlm_hash,
unsigned char *passwd,
+ char *domain,
char *username)
{
unsigned char *clnt_challenge;
unsigned char ntlmv2_hash[SMBAUTH_HASH_SZ];
unsigned char lmv2_resp[SMBAUTH_LM_RESP_SZ];
+ boolean_t ok = B_FALSE;
+ char *dest[3];
+ int i;
clnt_challenge = &passwd[SMBAUTH_HASH_SZ];
+ dest[0] = domain;
+ if ((dest[1] = strdup(domain)) == NULL)
+ return (B_FALSE);
+ (void) utf8_strupr(dest[1]);
+ dest[2] = "";
/*
* 15.5.2 The NTLMv2 Password Hash, pg. 279, of the "Implementing CIFS"
@@ -610,23 +644,31 @@ smb_lmv2_password_ok(
* the SMB server or NT Domain against which the suer is trying to
* authenticate.
*
- * (N.L.) With my experience, this is not exactly true. It's really
- * tricky how the NTLMv2 hash is generated by the Windows client when
- * logging into a standalone server using LMv2 challenge/response.
- * The NTLMv2 hash is actually created with the destination info = ""
- * as opposed to the SMB server name mentioned in the book.
+ * Experiments show this is not exactly the case.
+ * For Windows Server 2003, the domain name needs to be included and
+ * converted to uppercase. For Vista, the domain name needs to be
+ * included also, but leave the case alone. And in some cases it needs
+ * to be empty. All three variants are tried here.
*/
- if (smb_auth_ntlmv2_hash(ntlm_hash, username, "", ntlmv2_hash) !=
- SMBAUTH_SUCCESS) {
- return (B_FALSE);
- }
- if (smb_auth_v2_response(ntlmv2_hash, challenge,
- clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
- lmv2_resp) < 0) {
- return (B_FALSE);
+
+ for (i = 0; i < (sizeof (dest) / sizeof (char *)); i++) {
+ if (smb_auth_ntlmv2_hash(ntlm_hash, username, dest[i],
+ ntlmv2_hash) != SMBAUTH_SUCCESS)
+ break;
+
+ if (smb_auth_v2_response(ntlmv2_hash, challenge,
+ clen, clnt_challenge, SMBAUTH_V2_CLNT_CHALLENGE_SZ,
+ lmv2_resp) < 0)
+ break;
+
+ ok = (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
+ if (ok == B_TRUE)
+ break;
+
}
- return (bcmp(passwd, lmv2_resp, SMBAUTH_LM_RESP_SZ) == 0);
+ free(dest[1]);
+ return (ok);
}
/*
@@ -644,17 +686,17 @@ smb_auth_validate_lm(
smb_passwd_t *smbpw,
unsigned char *passwd,
int pwdlen,
+ char *domain,
char *username)
{
- int lmlevel;
boolean_t ok = B_FALSE;
+ int64_t lmlevel;
if (pwdlen != SMBAUTH_LM_RESP_SZ)
return (B_FALSE);
- smb_config_rdlock();
- lmlevel = smb_config_getnum(SMB_CI_LM_LEVEL);
- smb_config_unlock();
+ if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
+ return (B_FALSE);
if (lmlevel <= 3) {
ok = smb_lm_password_ok(challenge, clen, smbpw->pw_lmhash,
@@ -663,7 +705,7 @@ smb_auth_validate_lm(
if (!ok)
ok = smb_lmv2_password_ok(challenge, clen, smbpw->pw_nthash,
- passwd, username);
+ passwd, domain, username);
return (ok);
}
@@ -683,21 +725,21 @@ smb_auth_validate_nt(
smb_passwd_t *smbpw,
unsigned char *passwd,
int pwdlen,
+ char *domain,
char *username)
{
- int lmlevel;
+ int64_t lmlevel;
boolean_t ok;
- smb_config_rdlock();
- lmlevel = smb_config_getnum(SMB_CI_LM_LEVEL);
- smb_config_unlock();
+ if (smb_config_getnum(SMB_CI_LM_LEVEL, &lmlevel) != SMBD_SMF_OK)
+ return (B_FALSE);
if ((lmlevel == 5) && (pwdlen <= SMBAUTH_LM_RESP_SZ))
return (B_FALSE);
if (pwdlen > SMBAUTH_LM_RESP_SZ)
ok = smb_ntlmv2_password_ok(challenge, clen,
- smbpw->pw_nthash, passwd, pwdlen, username);
+ smbpw->pw_nthash, passwd, pwdlen, domain, username);
else
ok = smb_ntlm_password_ok(challenge, clen,
smbpw->pw_nthash, passwd);