diff options
Diffstat (limited to 'usr/src/lib/smbsrv/libsmb/common/smb_auth.c')
-rw-r--r-- | usr/src/lib/smbsrv/libsmb/common/smb_auth.c | 138 |
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); |