static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx, const char *username, const char *domain, const char *workstation, const DATA_BLOB *challenge, const DATA_BLOB *lm_response, const DATA_BLOB *nt_response, uint32_t flags, DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key, char **error_string, char **unix_name) { NTSTATUS nt_status; struct samr_Password lm_pw, nt_pw; struct samr_Password *lm_pwd, *nt_pwd; TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified"); if (!mem_ctx) { nt_status = NT_STATUS_NO_MEMORY; } else { E_md4hash(opt_password, nt_pw.hash); if (E_deshash(opt_password, lm_pw.hash)) { lm_pwd = &lm_pw; } else { lm_pwd = NULL; } nt_pwd = &nt_pw; nt_status = ntlm_password_check(mem_ctx, lpcfg_lanman_auth(lp_ctx), lpcfg_ntlm_auth(lp_ctx), MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, challenge, lm_response, nt_response, username, username, domain, lm_pwd, nt_pwd, user_session_key, lm_session_key); if (NT_STATUS_IS_OK(nt_status)) { if (unix_name) { if (asprintf(unix_name, "%s%c%s", domain, *lpcfg_winbind_separator(lp_ctx), username) < 0) { nt_status = NT_STATUS_NO_MEMORY; } } } else { DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", domain, username, workstation, nt_errstr(nt_status))); } talloc_free(mem_ctx); } if (error_string) { *error_string = strdup(nt_errstr(nt_status)); } return nt_status; }
static bool test_wbc_change_password(struct torture_context *tctx) { wbcErr ret; const char *oldpass = getenv("PASSWORD"); const char *newpass = "******"; struct samr_CryptPassword new_nt_password; struct samr_CryptPassword new_lm_password; struct samr_Password old_nt_hash_enc; struct samr_Password old_lanman_hash_enc; uint8_t old_nt_hash[16]; uint8_t old_lanman_hash[16]; uint8_t new_nt_hash[16]; uint8_t new_lanman_hash[16]; struct wbcChangePasswordParams params; if (oldpass == NULL) { torture_skip(tctx, "skipping wbcChangeUserPassword test as old password cannot be retrieved\n"); } ZERO_STRUCT(params); E_md4hash(oldpass, old_nt_hash); E_md4hash(newpass, new_nt_hash); if (lpcfg_client_lanman_auth(tctx->lp_ctx) && E_deshash(newpass, new_lanman_hash) && E_deshash(oldpass, old_lanman_hash)) { /* E_deshash returns false for 'long' passwords (> 14 DOS chars). This allows us to match Win2k, which does not store a LM hash for these passwords (which would reduce the effective password length to 14) */ encode_pw_buffer(new_lm_password.data, newpass, STR_UNICODE); arcfour_crypt(new_lm_password.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash); params.old_password.response.old_lm_hash_enc_length = sizeof(old_lanman_hash_enc.hash); params.old_password.response.old_lm_hash_enc_data = old_lanman_hash_enc.hash; params.new_password.response.lm_length = sizeof(new_lm_password.data); params.new_password.response.lm_data = new_lm_password.data; } else { ZERO_STRUCT(new_lm_password); ZERO_STRUCT(old_lanman_hash_enc); } encode_pw_buffer(new_nt_password.data, newpass, STR_UNICODE); arcfour_crypt(new_nt_password.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash); params.old_password.response.old_nt_hash_enc_length = sizeof(old_nt_hash_enc.hash); params.old_password.response.old_nt_hash_enc_data = old_nt_hash_enc.hash; params.new_password.response.nt_length = sizeof(new_nt_password.data); params.new_password.response.nt_data = new_nt_password.data; params.level = WBC_CHANGE_PASSWORD_LEVEL_RESPONSE; params.account_name = getenv("USERNAME"); params.domain_name = "SAMBA-TEST"; ret = wbcChangeUserPasswordEx(¶ms, NULL, NULL, NULL); torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, "wbcChangeUserPassword failed"); if (!test_wbc_authenticate_user_int(tctx, "Koo8irei")) { return false; } ret = wbcChangeUserPassword(getenv("USERNAME"), "Koo8irei", getenv("PASSWORD")); torture_assert_wbc_equal(tctx, ret, WBC_ERR_SUCCESS, "wbcChangeUserPassword failed"); return test_wbc_authenticate_user_int(tctx, getenv("PASSWORD")); }
NTSTATUS encrypt_user_info(TALLOC_CTX *mem_ctx, struct auth_context *auth_context, enum auth_password_state to_state, const struct auth_usersupplied_info *user_info_in, const struct auth_usersupplied_info **user_info_encrypted) { NTSTATUS nt_status; struct auth_usersupplied_info *user_info_temp; switch (to_state) { case AUTH_PASSWORD_RESPONSE: switch (user_info_in->password_state) { case AUTH_PASSWORD_PLAIN: { const struct auth_usersupplied_info *user_info_temp2; nt_status = encrypt_user_info(mem_ctx, auth_context, AUTH_PASSWORD_HASH, user_info_in, &user_info_temp2); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } user_info_in = user_info_temp2; /* fall through */ } case AUTH_PASSWORD_HASH: { const uint8_t *challenge; DATA_BLOB chall_blob; user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); if (!user_info_temp) { return NT_STATUS_NO_MEMORY; } if (!talloc_reference(user_info_temp, user_info_in)) { return NT_STATUS_NO_MEMORY; } *user_info_temp = *user_info_in; user_info_temp->mapped_state = to_state; nt_status = auth_get_challenge(auth_context, &challenge); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } chall_blob = data_blob_talloc(mem_ctx, challenge, 8); if (lp_client_ntlmv2_auth(auth_context->lp_ctx)) { DATA_BLOB names_blob = NTLMv2_generate_names_blob(mem_ctx, lp_netbios_name(auth_context->lp_ctx), lp_workgroup(auth_context->lp_ctx)); DATA_BLOB lmv2_response, ntlmv2_response, lmv2_session_key, ntlmv2_session_key; if (!SMBNTLMv2encrypt_hash(user_info_temp, user_info_in->client.account_name, user_info_in->client.domain_name, user_info_in->password.hash.nt->hash, &chall_blob, &names_blob, &lmv2_response, &ntlmv2_response, &lmv2_session_key, &ntlmv2_session_key)) { data_blob_free(&names_blob); return NT_STATUS_NO_MEMORY; } data_blob_free(&names_blob); user_info_temp->password.response.lanman = lmv2_response; user_info_temp->password.response.nt = ntlmv2_response; data_blob_free(&lmv2_session_key); data_blob_free(&ntlmv2_session_key); } else { DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, 24); SMBOWFencrypt(user_info_in->password.hash.nt->hash, challenge, blob.data); user_info_temp->password.response.nt = blob; if (lp_client_lanman_auth(auth_context->lp_ctx) && user_info_in->password.hash.lanman) { DATA_BLOB lm_blob = data_blob_talloc(mem_ctx, NULL, 24); SMBOWFencrypt(user_info_in->password.hash.lanman->hash, challenge, blob.data); user_info_temp->password.response.lanman = lm_blob; } else { /* if not sending the LM password, send the NT password twice */ user_info_temp->password.response.lanman = user_info_temp->password.response.nt; } } user_info_in = user_info_temp; /* fall through */ } case AUTH_PASSWORD_RESPONSE: *user_info_encrypted = user_info_in; } break; case AUTH_PASSWORD_HASH: { switch (user_info_in->password_state) { case AUTH_PASSWORD_PLAIN: { struct samr_Password lanman; struct samr_Password nt; user_info_temp = talloc(mem_ctx, struct auth_usersupplied_info); if (!user_info_temp) { return NT_STATUS_NO_MEMORY; } if (!talloc_reference(user_info_temp, user_info_in)) { return NT_STATUS_NO_MEMORY; } *user_info_temp = *user_info_in; user_info_temp->mapped_state = to_state; if (E_deshash(user_info_in->password.plaintext, lanman.hash)) { user_info_temp->password.hash.lanman = talloc(user_info_temp, struct samr_Password); *user_info_temp->password.hash.lanman = lanman; } else { user_info_temp->password.hash.lanman = NULL; } E_md4hash(user_info_in->password.plaintext, nt.hash); user_info_temp->password.hash.nt = talloc(user_info_temp, struct samr_Password); *user_info_temp->password.hash.nt = nt; user_info_in = user_info_temp; /* fall through */ } case AUTH_PASSWORD_HASH: *user_info_encrypted = user_info_in; break; default: return NT_STATUS_INVALID_PARAMETER; break; } break; }
static int calc_ntlmv2_hash(struct cifs_ses *ses, char *ntlmv2_hash, const struct nls_table *nls_cp) { int rc = 0; int len; char nt_hash[CIFS_NTHASH_SIZE]; __le16 *user; wchar_t *domain; wchar_t *server; if (!ses->server->secmech.sdeschmacmd5) { cifs_dbg(VFS, "%s: can't generate ntlmv2 hash\n", __func__); return -1; } /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash, nls_cp); rc = crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, CIFS_NTHASH_SIZE); if (rc) { cifs_dbg(VFS, "%s: Could not set NT Hash as a key\n", __func__); return rc; } rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); if (rc) { cifs_dbg(VFS, "%s: could not init hmacmd5\n", __func__); return rc; } /* convert ses->user_name to unicode */ len = ses->user_name ? strlen(ses->user_name) : 0; user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) { rc = -ENOMEM; return rc; } if (len) { len = cifs_strtoUTF16(user, ses->user_name, len, nls_cp); UniStrupr(user); } else { memset(user, '\0', 2); } rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)user, 2 * len); kfree(user); if (rc) { cifs_dbg(VFS, "%s: Could not update with user\n", __func__); return rc; } /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { len = strlen(ses->domainName); domain = kmalloc(2 + (len * 2), GFP_KERNEL); if (domain == NULL) { rc = -ENOMEM; return rc; } len = cifs_strtoUTF16((__le16 *)domain, ses->domainName, len, nls_cp); rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)domain, 2 * len); kfree(domain); if (rc) { cifs_dbg(VFS, "%s: Could not update with domain\n", __func__); return rc; } } else if (ses->serverName) { len = strlen(ses->serverName); server = kmalloc(2 + (len * 2), GFP_KERNEL); if (server == NULL) { rc = -ENOMEM; return rc; } len = cifs_strtoUTF16((__le16 *)server, ses->serverName, len, nls_cp); rc = crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)server, 2 * len); kfree(server); if (rc) { cifs_dbg(VFS, "%s: Could not update with server\n", __func__); return rc; } } rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, ntlmv2_hash); if (rc) cifs_dbg(VFS, "%s: Could not generate md5 hash\n", __func__); return rc; }
void SMBNTencrypt(const char *passwd, const uint8_t *c8, uint8_t *p24) { uint8_t nt_hash[16]; E_md4hash(passwd, nt_hash); SMBNTencrypt_hash(nt_hash, c8, p24); }
static NTSTATUS authsam_password_check_and_record(struct auth4_context *auth_context, TALLOC_CTX *mem_ctx, struct ldb_dn *domain_dn, struct ldb_message *msg, uint16_t acct_flags, const struct auth_usersupplied_info *user_info, DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key, bool *authoritative) { NTSTATUS nt_status; NTSTATUS auth_status; TALLOC_CTX *tmp_ctx; int i, ret; int history_len = 0; struct ldb_context *sam_ctx = auth_context->sam_ctx; const char * const attrs[] = { "pwdHistoryLength", NULL }; struct ldb_message *dom_msg; struct samr_Password *lm_pwd; struct samr_Password *nt_pwd; bool am_rodc; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return NT_STATUS_NO_MEMORY; } /* * This call does more than what it appears to do, it also * checks for the account lockout. * * It is done here so that all parts of Samba that read the * password refuse to even operate on it if the account is * locked out, to avoid mistakes like CVE-2013-4496. */ nt_status = samdb_result_passwords(tmp_ctx, auth_context->lp_ctx, msg, &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(tmp_ctx); return nt_status; } if (lm_pwd == NULL && nt_pwd == NULL) { if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) { /* * we don't have passwords for this * account. We are an RODC, and this account * may be one for which we either are denied * REPL_SECRET replication or we haven't yet * done the replication. We return * NT_STATUS_NOT_IMPLEMENTED which tells the * auth code to try the next authentication * mechanism. We also send a message to our * drepl server to tell it to try and * replicate the secrets for this account. * * TODO: Should we only trigger this is detected * there's a chance that the password might be * replicated, we should be able to detect this * based on msDS-NeverRevealGroup. */ auth_sam_trigger_repl_secret(auth_context, auth_context->msg_ctx, auth_context->event_ctx, msg->dn); TALLOC_FREE(tmp_ctx); return NT_STATUS_NOT_IMPLEMENTED; } } auth_status = authsam_password_ok(auth_context, tmp_ctx, acct_flags, lm_pwd, nt_pwd, user_info, user_sess_key, lm_sess_key); if (NT_STATUS_IS_OK(auth_status)) { if (user_sess_key->data) { talloc_steal(mem_ctx, user_sess_key->data); } if (lm_sess_key->data) { talloc_steal(mem_ctx, lm_sess_key->data); } TALLOC_FREE(tmp_ctx); return NT_STATUS_OK; } *user_sess_key = data_blob_null; *lm_sess_key = data_blob_null; if (!NT_STATUS_EQUAL(auth_status, NT_STATUS_WRONG_PASSWORD)) { TALLOC_FREE(tmp_ctx); return auth_status; } /* * We only continue if this was a wrong password * and we'll always return NT_STATUS_WRONG_PASSWORD * no matter what error happens. */ /* pull the domain password property attributes */ ret = dsdb_search_one(sam_ctx, tmp_ctx, &dom_msg, domain_dn, LDB_SCOPE_BASE, attrs, 0, "objectClass=domain"); if (ret == LDB_SUCCESS) { history_len = ldb_msg_find_attr_as_uint(dom_msg, "pwdHistoryLength", 0); } else if (ret == LDB_ERR_NO_SUCH_OBJECT) { DEBUG(3,("Couldn't find domain %s: %s!\n", ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); } else { DEBUG(3,("error finding domain %s: %s!\n", ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); } for (i = 1; i < MIN(history_len, 3); i++) { struct samr_Password zero_string_hash; struct samr_Password zero_string_des_hash; struct samr_Password *nt_history_pwd = NULL; struct samr_Password *lm_history_pwd = NULL; NTTIME pwdLastSet; struct timeval tv_now; NTTIME now; int allowed_period_mins; NTTIME allowed_period; nt_status = samdb_result_passwords_from_history(tmp_ctx, auth_context->lp_ctx, msg, i, &lm_history_pwd, &nt_history_pwd); if (!NT_STATUS_IS_OK(nt_status)) { /* * If we don't find element 'i' we won't find * 'i+1' ... */ break; } /* * We choose to avoid any issues * around different LM and NT history * lengths by only checking the NT * history */ if (nt_history_pwd == NULL) { /* * If we don't find element 'i' we won't find * 'i+1' ... */ break; } /* Skip over all-zero hashes in the history */ if (all_zero(nt_history_pwd->hash, sizeof(nt_history_pwd->hash))) { continue; } /* * This looks odd, but the password_hash module writes this in if * (somehow) we didn't have an old NT hash */ E_md4hash("", zero_string_hash.hash); if (memcmp(nt_history_pwd->hash, zero_string_hash.hash, 16) == 0) { continue; } E_deshash("", zero_string_des_hash.hash); if (!lm_history_pwd || memcmp(lm_history_pwd->hash, zero_string_des_hash.hash, 16) == 0) { lm_history_pwd = NULL; } auth_status = authsam_password_ok(auth_context, tmp_ctx, acct_flags, lm_history_pwd, nt_history_pwd, user_info, user_sess_key, lm_sess_key); if (!NT_STATUS_IS_OK(auth_status)) { /* * If this was not a correct password, try the next * one from the history */ *user_sess_key = data_blob_null; *lm_sess_key = data_blob_null; continue; } if (i != 1) { /* * The authentication was OK, but not against * the previous password, which is stored at index 1. * * We just return the original wrong password. * This skips the update of the bad pwd count, * because this is almost certainly user error * (or automatic login on a computer using a cached * password from before the password change), * not an attack. */ TALLOC_FREE(tmp_ctx); return NT_STATUS_WRONG_PASSWORD; } if (user_info->password_state != AUTH_PASSWORD_RESPONSE) { /* * The authentication was OK against the previous password, * but it's not a NTLM network authentication. * * We just return the original wrong password. * This skips the update of the bad pwd count, * because this is almost certainly user error * (or automatic login on a computer using a cached * password from before the password change), * not an attack. */ TALLOC_FREE(tmp_ctx); return NT_STATUS_WRONG_PASSWORD; } /* * If the password was OK, it's a NTLM network authentication * and it was the previous password. * * Now we see if it is within the grace period, * so that we don't break cached sessions on other computers * before the user can lock and unlock their other screens * (resetting their cached password). * * See http://support.microsoft.com/kb/906305 * OldPasswordAllowedPeriod ("old password allowed period") * is specified in minutes. The default is 60. */ allowed_period_mins = lpcfg_old_password_allowed_period(auth_context->lp_ctx); /* * NTTIME uses 100ns units */ allowed_period = allowed_period_mins * 60 * 1000*1000*10; pwdLastSet = samdb_result_nttime(msg, "pwdLastSet", 0); tv_now = timeval_current(); now = timeval_to_nttime(&tv_now); if (now < pwdLastSet) { /* * time jump? * * We just return the original wrong password. * This skips the update of the bad pwd count, * because this is almost certainly user error * (or automatic login on a computer using a cached * password from before the password change), * not an attack. */ TALLOC_FREE(tmp_ctx); return NT_STATUS_WRONG_PASSWORD; } if ((now - pwdLastSet) >= allowed_period) { /* * The allowed period is over. * * We just return the original wrong password. * This skips the update of the bad pwd count, * because this is almost certainly user error * (or automatic login on a computer using a cached * password from before the password change), * not an attack. */ TALLOC_FREE(tmp_ctx); return NT_STATUS_WRONG_PASSWORD; } /* * We finally allow the authentication with the * previous password within the allowed period. */ if (user_sess_key->data) { talloc_steal(mem_ctx, user_sess_key->data); } if (lm_sess_key->data) { talloc_steal(mem_ctx, lm_sess_key->data); } TALLOC_FREE(tmp_ctx); return auth_status; } /* * If we are not in the allowed period or match an old password, * we didn't return early. Now update the badPwdCount et al. */ nt_status = authsam_update_bad_pwd_count(auth_context->sam_ctx, msg, domain_dn); if (!NT_STATUS_IS_OK(nt_status)) { /* * We need to return the original * NT_STATUS_WRONG_PASSWORD error, so there isn't * anything more we can do than write something into * the log */ DEBUG(0, ("Failed to note bad password for user [%s]: %s\n", user_info->mapped.account_name, nt_errstr(nt_status))); } if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) { *authoritative = false; } TALLOC_FREE(tmp_ctx); return NT_STATUS_WRONG_PASSWORD; }
/* Calculate the NTLMv2 response for the given challenge, using the specified authentication identity (username and domain), password and client nonce. challenge: Identity \0 Challenge Size \0 Server Challenge + Client Challenge */ static void netntlmv2_crypt_all(int count) { HMACMD5Context ctx; unsigned char ntlm[16]; unsigned char ntlm_v2_hash[16]; uchar *identity = NULL; int identity_length = 0; int16 identity_usc[129]; int identity_usc_length = 0; int challenge_size = 0; memset(ntlm, 0, 16); memset(ntlm_v2_hash, 0, 16); memset(output, 0, 16); memset(identity_usc, 0, 129); identity_usc_length = 0; /* --- HMAC #1 Caculations --- */ /* Convert identity (username + domain) string to NT unicode */ identity_length = strlen((char *)challenge); identity = challenge; ntlmv2_mbstowcs(identity_usc, identity, identity_length); identity_usc_length = ntlmv2_wcslen(identity_usc) * sizeof(int16); /* Generate 16-byte NTLM hash */ E_md4hash(saved_plain, ntlm); /* Generate 16-byte NTLMv2 Hash */ /* HMAC-MD5(Username + Domain, NTLM Hash) */ hmac_md5_init_limK_to_64(ntlm, 16, &ctx); hmac_md5_update((const unsigned char *)identity_usc, identity_usc_length, &ctx); hmac_md5_final(ntlm_v2_hash, &ctx); /* --- Blob Construction --- */ /* The blob consists of the target (from Type 2 message), client nonce and timestamp. This data was provided by the client during authentication and we can use it as is. */ /* --- HMAC #2 Caculations --- */ /* The (server) challenge from the Type 2 message is concatenated with the blob. The HMAC-MD5 message authentication code algorithm is applied to this value using the 16-byte NTLMv2 hash (calculated above) as the key. This results in a 16-byte output value. */ /* Generate 16-byte non-client nonce portion of NTLMv2 Response HMAC-MD5(Challenge + Nonce, NTLMv2 Hash) The length of the challenge was set in netntlmv2_get_salt(). We find the server challenge and blob following the identity and challenge size value. challenge -> Identity \0 Size (2 bytes) \0 Server Challenge + Client Challenge (Blob) */ challenge_size = (*(challenge + identity_length + 1) << 8) | *(challenge + identity_length + 2); hmac_md5_init_limK_to_64(ntlm_v2_hash, 16, &ctx); hmac_md5_update(challenge + identity_length + 1 + 2 + 1, challenge_size, &ctx); hmac_md5_final(output, &ctx); }
static bool test_lm_ntlm_broken(enum ntlm_break break_which) { bool pass = True; NTSTATUS nt_status; uint32 flags = 0; DATA_BLOB lm_response = data_blob(NULL, 24); DATA_BLOB nt_response = data_blob(NULL, 24); DATA_BLOB session_key = data_blob(NULL, 16); uchar lm_key[8]; uchar user_session_key[16]; uchar lm_hash[16]; uchar nt_hash[16]; DATA_BLOB chall = get_challenge(); char *error_string; ZERO_STRUCT(lm_key); ZERO_STRUCT(user_session_key); flags |= WBFLAG_PAM_LMKEY; flags |= WBFLAG_PAM_USER_SESSION_KEY; SMBencrypt(opt_password,chall.data,lm_response.data); E_deshash(opt_password, lm_hash); SMBNTencrypt(opt_password,chall.data,nt_response.data); E_md4hash(opt_password, nt_hash); SMBsesskeygen_ntv1(nt_hash, session_key.data); switch (break_which) { case BREAK_NONE: break; case BREAK_LM: lm_response.data[0]++; break; case BREAK_NT: nt_response.data[0]++; break; case NO_LM: data_blob_free(&lm_response); break; case NO_NT: data_blob_free(&nt_response); break; } nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, &chall, &lm_response, &nt_response, flags, lm_key, user_session_key, &error_string, NULL); data_blob_free(&lm_response); if (!NT_STATUS_IS_OK(nt_status)) { d_printf("%s (0x%x)\n", error_string, NT_STATUS_V(nt_status)); SAFE_FREE(error_string); return break_which == BREAK_NT; } if (memcmp(lm_hash, lm_key, sizeof(lm_key)) != 0) { DEBUG(1, ("LM Key does not match expectations!\n")); DEBUG(1, ("lm_key:\n")); dump_data(1, lm_key, 8); DEBUG(1, ("expected:\n")); dump_data(1, lm_hash, 8); pass = False; } if (break_which == NO_NT) { if (memcmp(lm_hash, user_session_key, 8) != 0) { DEBUG(1, ("NT Session Key does not match expectations (should be LM hash)!\n")); DEBUG(1, ("user_session_key:\n")); dump_data(1, user_session_key, sizeof(user_session_key)); DEBUG(1, ("expected:\n")); dump_data(1, lm_hash, sizeof(lm_hash)); pass = False; } } else { if (memcmp(session_key.data, user_session_key, sizeof(user_session_key)) != 0) { DEBUG(1, ("NT Session Key does not match expectations!\n")); DEBUG(1, ("user_session_key:\n")); dump_data(1, user_session_key, 16); DEBUG(1, ("expected:\n")); dump_data(1, session_key.data, session_key.length); pass = False; } } return pass; }
bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext) { uchar new_lanman_p16[LM_HASH_LEN]; uchar new_nt_p16[NT_HASH_LEN]; uchar *pwhistory; uint32 pwHistLen; uint32 current_history_len; if (!plaintext) return False; /* Calculate the MD4 hash (NT compatible) of the password */ E_md4hash(plaintext, new_nt_p16); if (!pdb_set_nt_passwd (sampass, new_nt_p16, PDB_CHANGED)) return False; if (!E_deshash(plaintext, new_lanman_p16)) { /* E_deshash returns false for 'long' passwords (> 14 DOS chars). This allows us to match Win2k, which does not store a LM hash for these passwords (which would reduce the effective password length to 14 */ if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED)) return False; } else { if (!pdb_set_lanman_passwd (sampass, new_lanman_p16, PDB_CHANGED)) return False; } if (!pdb_set_plaintext_pw_only (sampass, plaintext, PDB_CHANGED)) return False; if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) return False; if ((pdb_get_acct_ctrl(sampass) & ACB_NORMAL) == 0) { /* * No password history for non-user accounts */ return true; } pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen); if (pwHistLen == 0) { /* Set the history length to zero. */ pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED); return true; } /* * We need to make sure we don't have a race condition here - * the account policy history length can change between when * the pw_history was first loaded into the struct samu struct * and now.... JRA. */ pwhistory = (uchar *)pdb_get_pw_history(sampass, ¤t_history_len); if ((current_history_len != 0) && (pwhistory == NULL)) { DEBUG(1, ("pdb_set_plaintext_passwd: pwhistory == NULL!\n")); return false; } if (current_history_len < pwHistLen) { /* * Ensure we have space for the needed history. This * also takes care of an account which did not have * any history at all so far, i.e. pwhistory==NULL */ uchar *new_history = talloc_zero_array( sampass, uchar, pwHistLen*PW_HISTORY_ENTRY_LEN); if (!new_history) { return False; } memcpy(new_history, pwhistory, current_history_len*PW_HISTORY_ENTRY_LEN); pwhistory = new_history; } /* * Make room for the new password in the history list. */ if (pwHistLen > 1) { memmove(&pwhistory[PW_HISTORY_ENTRY_LEN], pwhistory, (pwHistLen-1)*PW_HISTORY_ENTRY_LEN ); } /* * Fill the salt area with 0-s: this indicates that * a plain nt hash is stored in the has area. * The old format was to store a 16 byte salt and * then an md5hash of the nt_hash concatenated with * the salt. */ memset(pwhistory, 0, PW_HISTORY_SALT_LEN); /* * Store the plain nt hash in the second 16 bytes. * The old format was to store the md5 hash of * the salt+newpw. */ memcpy(&pwhistory[PW_HISTORY_SALT_LEN], new_nt_p16, SALTED_MD5_HASH_LEN); pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED); return True; }
static NTSTATUS ntlmssp_client_challenge(struct ntlmssp_state *ntlmssp_state, const DATA_BLOB reply, DATA_BLOB *next_request) { uint32 chal_flags, ntlmssp_command, unkn1, unkn2; DATA_BLOB server_domain_blob; DATA_BLOB challenge_blob; DATA_BLOB struct_blob = data_blob(NULL, 0); char *server_domain; const char *chal_parse_string; const char *auth_gen_string; DATA_BLOB lm_response = data_blob(NULL, 0); DATA_BLOB nt_response = data_blob(NULL, 0); DATA_BLOB session_key = data_blob(NULL, 0); DATA_BLOB encrypted_session_key = data_blob(NULL, 0); NTSTATUS nt_status; if (!msrpc_parse(&reply, "CdBd", "NTLMSSP", &ntlmssp_command, &server_domain_blob, &chal_flags)) { DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#1)\n")); dump_data(2, (const char *)reply.data, reply.length); return NT_STATUS_INVALID_PARAMETER; } data_blob_free(&server_domain_blob); DEBUG(3, ("Got challenge flags:\n")); debug_ntlmssp_flags(chal_flags); ntlmssp_handle_neg_flags(ntlmssp_state, chal_flags, lp_client_lanman_auth()); if (ntlmssp_state->unicode) { if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { chal_parse_string = "CdUdbddB"; } else { chal_parse_string = "CdUdbdd"; } auth_gen_string = "CdBBUUUBd"; } else { if (chal_flags & NTLMSSP_CHAL_TARGET_INFO) { chal_parse_string = "CdAdbddB"; } else { chal_parse_string = "CdAdbdd"; } auth_gen_string = "CdBBAAABd"; } DEBUG(3, ("NTLMSSP: Set final flags:\n")); debug_ntlmssp_flags(ntlmssp_state->neg_flags); if (!msrpc_parse(&reply, chal_parse_string, "NTLMSSP", &ntlmssp_command, &server_domain, &chal_flags, &challenge_blob, 8, &unkn1, &unkn2, &struct_blob)) { DEBUG(1, ("Failed to parse the NTLMSSP Challenge: (#2)\n")); dump_data(2, (const char *)reply.data, reply.length); return NT_STATUS_INVALID_PARAMETER; } ntlmssp_state->server_domain = talloc_strdup(ntlmssp_state->mem_ctx, server_domain); SAFE_FREE(server_domain); if (challenge_blob.length != 8) { data_blob_free(&struct_blob); return NT_STATUS_INVALID_PARAMETER; } if (!ntlmssp_state->password) { static const uchar zeros[16]; /* do nothing - blobs are zero length */ /* session key is all zeros */ session_key = data_blob_talloc(ntlmssp_state->mem_ctx, zeros, 16); /* not doing NLTM2 without a password */ ntlmssp_state->neg_flags &= ~NTLMSSP_NEGOTIATE_NTLM2; } else if (ntlmssp_state->use_ntlmv2) { if (!struct_blob.length) { /* be lazy, match win2k - we can't do NTLMv2 without it */ DEBUG(1, ("Server did not provide 'target information', required for NTLMv2\n")); return NT_STATUS_INVALID_PARAMETER; } /* TODO: if the remote server is standalone, then we should replace 'domain' with the server name as supplied above */ if (!SMBNTLMv2encrypt(ntlmssp_state->user, ntlmssp_state->domain, ntlmssp_state->password, &challenge_blob, &struct_blob, &lm_response, &nt_response, &session_key)) { data_blob_free(&challenge_blob); data_blob_free(&struct_blob); return NT_STATUS_NO_MEMORY; } } else if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_NTLM2) { struct MD5Context md5_session_nonce_ctx; uchar nt_hash[16]; uchar session_nonce[16]; uchar session_nonce_hash[16]; uchar user_session_key[16]; E_md4hash(ntlmssp_state->password, nt_hash); lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24); generate_random_buffer(lm_response.data, 8); memset(lm_response.data+8, 0, 16); memcpy(session_nonce, challenge_blob.data, 8); memcpy(&session_nonce[8], lm_response.data, 8); MD5Init(&md5_session_nonce_ctx); MD5Update(&md5_session_nonce_ctx, challenge_blob.data, 8); MD5Update(&md5_session_nonce_ctx, lm_response.data, 8); MD5Final(session_nonce_hash, &md5_session_nonce_ctx); DEBUG(5, ("NTLMSSP challenge set by NTLM2\n")); DEBUG(5, ("challenge is: \n")); dump_data(5, (const char *)session_nonce_hash, 8); nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24); SMBNTencrypt(ntlmssp_state->password, session_nonce_hash, nt_response.data); session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); SMBsesskeygen_ntv1(nt_hash, NULL, user_session_key); hmac_md5(user_session_key, session_nonce, sizeof(session_nonce), session_key.data); dump_data_pw("NTLM2 session key:\n", session_key.data, session_key.length); } else { uchar lm_hash[16]; uchar nt_hash[16]; E_deshash(ntlmssp_state->password, lm_hash); E_md4hash(ntlmssp_state->password, nt_hash); /* lanman auth is insecure, it may be disabled */ if (lp_client_lanman_auth()) { lm_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24); SMBencrypt(ntlmssp_state->password,challenge_blob.data, lm_response.data); } nt_response = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 24); SMBNTencrypt(ntlmssp_state->password,challenge_blob.data, nt_response.data); session_key = data_blob_talloc(ntlmssp_state->mem_ctx, NULL, 16); if ((ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_LM_KEY) && lp_client_lanman_auth()) { SMBsesskeygen_lmv1(lm_hash, lm_response.data, session_key.data); dump_data_pw("LM session key\n", session_key.data, session_key.length); } else { SMBsesskeygen_ntv1(nt_hash, NULL, session_key.data); dump_data_pw("NT session key:\n", session_key.data, session_key.length); } } data_blob_free(&struct_blob); /* Key exchange encryptes a new client-generated session key with the password-derived key */ if (ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_KEY_EXCH) { /* Make up a new session key */ uint8 client_session_key[16]; generate_random_buffer(client_session_key, sizeof(client_session_key)); /* Encrypt the new session key with the old one */ encrypted_session_key = data_blob(client_session_key, sizeof(client_session_key)); dump_data_pw("KEY_EXCH session key:\n", encrypted_session_key.data, encrypted_session_key.length); SamOEMhash(encrypted_session_key.data, session_key.data, encrypted_session_key.length); dump_data_pw("KEY_EXCH session key (enc):\n", encrypted_session_key.data, encrypted_session_key.length); /* Mark the new session key as the 'real' session key */ data_blob_free(&session_key); session_key = data_blob_talloc(ntlmssp_state->mem_ctx, client_session_key, sizeof(client_session_key)); } /* this generates the actual auth packet */ if (!msrpc_gen(next_request, auth_gen_string, "NTLMSSP", NTLMSSP_AUTH, lm_response.data, lm_response.length, nt_response.data, nt_response.length, ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->get_global_myname(), encrypted_session_key.data, encrypted_session_key.length, ntlmssp_state->neg_flags)) { return NT_STATUS_NO_MEMORY; } data_blob_free(&encrypted_session_key); data_blob_free(&ntlmssp_state->chal); ntlmssp_state->chal = challenge_blob; ntlmssp_state->lm_resp = lm_response; ntlmssp_state->nt_resp = nt_response; ntlmssp_state->session_key = session_key; ntlmssp_state->expected_state = NTLMSSP_UNKNOWN; if (!NT_STATUS_IS_OK(nt_status = ntlmssp_sign_init(ntlmssp_state))) { DEBUG(1, ("Could not setup NTLMSSP signing/sealing system (error was: %s)\n", nt_errstr(nt_status))); return nt_status; } return NT_STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID *dom_sid, const char *clear_pw, enum netdom_domain_t dom_type ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND sam_pol, domain_pol, user_pol; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; char *acct_name; const char *const_acct_name; uint32 user_rid; uint32 num_rids, *name_types, *user_rids; uint32 flags = 0x3e8; uint32 acb_info = ACB_WSTRUST; uint32 acct_flags=0; uint32 fields_present; uchar pwbuf[532]; SAM_USERINFO_CTR ctr; SAM_USER_INFO_25 p25; const int infolevel = 25; struct MD5Context md5ctx; uchar md5buffer[16]; DATA_BLOB digested_session_key; uchar md4_trust_password[16]; /* Open the domain */ if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) { DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n", nt_errstr(status) )); return status; } status = rpccli_samr_connect(pipe_hnd, mem_ctx, SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol); if ( !NT_STATUS_IS_OK(status) ) return status; status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol, SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol); if ( !NT_STATUS_IS_OK(status) ) return status; /* Create domain user */ acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); strlower_m(acct_name); const_acct_name = acct_name; /* Don't try to set any acb_info flags other than ACB_WSTRUST */ acct_flags = SAMR_GENERIC_READ | SAMR_GENERIC_WRITE | SAMR_GENERIC_EXECUTE | SAMR_STANDARD_WRITEDAC | SAMR_STANDARD_DELETE | SAMR_USER_SETPASS | SAMR_USER_GETATTR | SAMR_USER_SETATTR; DEBUG(10, ("Creating account with flags: %d\n",acct_flags)); status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol, acct_name, acb_info, acct_flags, &user_pol, &user_rid); if ( !NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) { d_fprintf(stderr, "Creation of workstation account failed\n"); /* If NT_STATUS_ACCESS_DENIED then we have a valid username/password combo but the user does not have administrator access. */ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) d_fprintf(stderr, "User specified does not have administrator privileges\n"); return status; } /* We *must* do this.... don't ask... */ if (NT_STATUS_IS_OK(status)) { rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol); } status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx, &domain_pol, flags, 1, &const_acct_name, &num_rids, &user_rids, &name_types); if ( !NT_STATUS_IS_OK(status) ) return status; if ( name_types[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0])); return NT_STATUS_INVALID_WORKSTATION; } user_rid = user_rids[0]; /* Open handle on user */ status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol, SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol); if (!NT_STATUS_IS_OK(status)) { return status; } /* Create a random machine account password and generate the hash */ E_md4hash(clear_pw, md4_trust_password); encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE); generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer)); digested_session_key = data_blob_talloc(mem_ctx, 0, 16); MD5Init(&md5ctx); MD5Update(&md5ctx, md5buffer, sizeof(md5buffer)); MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length); MD5Final(digested_session_key.data, &md5ctx); SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key); memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer)); /* Fill in the additional account flags now */ acb_info |= ACB_PWNOEXP; if ( dom_type == ND_TYPE_AD ) { #if !defined(ENCTYPE_ARCFOUR_HMAC) acb_info |= ACB_USE_DES_KEY_ONLY; #endif ;; } /* Set password and account flags on machine account */ ZERO_STRUCT(ctr); ZERO_STRUCT(p25); fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS; init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf); ctr.switch_value = infolevel; ctr.info.id25 = &p25; status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, infolevel, &cli->user_session_key, &ctr); if ( !NT_STATUS_IS_OK(status) ) { d_fprintf( stderr, "Failed to set password for machine account (%s)\n", nt_errstr(status)); return status; } rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol); cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */ return status; }
/* Calculate the NTLMv2 response for the given challenge, using the specified authentication identity (username and domain), password and client nonce. challenge: Identity length, Identity\0, Challenge Size, Server Challenge + Client Challenge */ static int crypt_all(int *pcount, struct db_salt *salt) { int count = *pcount; int identity_length, challenge_size; int i = 0; /* --- HMAC #1 Calculations --- */ identity_length = challenge[0]; challenge_size = (*(challenge + 1 + identity_length + 1) << 8) | *(challenge + 1 + identity_length + 2); #ifdef _OPENMP #pragma omp parallel for for(i=0; i<count; i++) #endif { unsigned char ntlm_v2_hash[16]; HMACMD5Context ctx; if (!keys_prepared) { unsigned char ntlm[16]; int len; /* Generate 16-byte NTLM hash */ len = E_md4hash(saved_plain[i], saved_len[i], ntlm); // We do key setup of the next HMAC_MD5 here (once per salt) hmac_md5_init_K16(ntlm, &saved_ctx[i]); if (len <= 0) saved_plain[i][-len] = 0; // match truncation } /* HMAC-MD5(Username + Domain, NTLM Hash) */ memcpy(&ctx, &saved_ctx[i], sizeof(ctx)); hmac_md5_update((unsigned char *)&challenge[1], identity_length, &ctx); hmac_md5_final(ntlm_v2_hash, &ctx); /* --- Blob Construction --- */ /* The blob consists of the target (from Type 2 message), client nonce and timestamp. This data was provided by the client during authentication and we can use it as is. */ /* --- HMAC #2 Caculations --- */ /* The (server) challenge from the Type 2 message is concatenated with the blob. The HMAC-MD5 message authentication code algorithm is applied to this value using the 16-byte NTLMv2 hash (calculated above) as the key. This results in a 16-byte output value. */ /* Generate 16-byte non-client nonce portion of NTLMv2 Response HMAC-MD5(Challenge + Nonce, NTLMv2 Hash) The length of the challenge was set in get_salt(). We find the server challenge and blob following the identity and challenge size value. challenge -> Identity length, Identity\0, Size (2 bytes), Server Challenge + Client Challenge (Blob) */ hmac_md5(ntlm_v2_hash, challenge + 1 + identity_length + 1 + 2, challenge_size, (unsigned char*)output[i]); } keys_prepared = 1; return count; }
bool pdb_set_plaintext_passwd(struct samu *sampass, const char *plaintext) { uchar new_lanman_p16[LM_HASH_LEN]; uchar new_nt_p16[NT_HASH_LEN]; if (!plaintext) return False; /* Calculate the MD4 hash (NT compatible) of the password */ E_md4hash(plaintext, new_nt_p16); if (!pdb_set_nt_passwd (sampass, new_nt_p16, PDB_CHANGED)) return False; if (!E_deshash(plaintext, new_lanman_p16)) { /* E_deshash returns false for 'long' passwords (> 14 DOS chars). This allows us to match Win2k, which does not store a LM hash for these passwords (which would reduce the effective password length to 14 */ if (!pdb_set_lanman_passwd (sampass, NULL, PDB_CHANGED)) return False; } else { if (!pdb_set_lanman_passwd (sampass, new_lanman_p16, PDB_CHANGED)) return False; } if (!pdb_set_plaintext_pw_only (sampass, plaintext, PDB_CHANGED)) return False; if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) return False; /* Store the password history. */ if (pdb_get_acct_ctrl(sampass) & ACB_NORMAL) { uchar *pwhistory; uint32 pwHistLen; pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHistLen); if (pwHistLen != 0){ uint32 current_history_len; /* We need to make sure we don't have a race condition here - the account policy history length can change between when the pw_history was first loaded into the struct samu struct and now.... JRA. */ pwhistory = (uchar *)pdb_get_pw_history(sampass, ¤t_history_len); if (current_history_len != pwHistLen) { /* After closing and reopening struct samu the history values will sync up. We can't do this here. */ /* current_history_len > pwHistLen is not a problem - we have more history than we need. */ if (current_history_len < pwHistLen) { /* Ensure we have space for the needed history. */ uchar *new_history = (uchar *)TALLOC(sampass, pwHistLen*PW_HISTORY_ENTRY_LEN); if (!new_history) { return False; } /* And copy it into the new buffer. */ if (current_history_len) { memcpy(new_history, pwhistory, current_history_len*PW_HISTORY_ENTRY_LEN); } /* Clearing out any extra space. */ memset(&new_history[current_history_len*PW_HISTORY_ENTRY_LEN], '\0', (pwHistLen-current_history_len)*PW_HISTORY_ENTRY_LEN); /* Finally replace it. */ pwhistory = new_history; } } if (pwhistory && pwHistLen){ /* Make room for the new password in the history list. */ if (pwHistLen > 1) { memmove(&pwhistory[PW_HISTORY_ENTRY_LEN], pwhistory, (pwHistLen -1)*PW_HISTORY_ENTRY_LEN ); } /* Create the new salt as the first part of the history entry. */ generate_random_buffer(pwhistory, PW_HISTORY_SALT_LEN); /* Generate the md5 hash of the salt+new password as the second part of the history entry. */ E_md5hash(pwhistory, new_nt_p16, &pwhistory[PW_HISTORY_SALT_LEN]); pdb_set_pw_history(sampass, pwhistory, pwHistLen, PDB_CHANGED); } else { DEBUG (10,("pdb_get_set.c: pdb_set_plaintext_passwd: pwhistory was NULL!\n")); } } else { /* Set the history length to zero. */ pdb_set_pw_history(sampass, NULL, 0, PDB_CHANGED); } } return True; }
void SMBNTencrypt(const char *passwd, uchar *c8, uchar *p24) { uchar nt_hash[16]; E_md4hash(passwd, nt_hash); SMBNTencrypt_hash(nt_hash, c8, p24); }
static int crypt_all(int *pcount, struct db_salt *salt) { int count = *pcount; int i; size_t *lws = local_work_size ? &local_work_size : NULL; /* Don't do more than requested */ global_work_size = local_work_size ? (count + local_work_size - 1) / local_work_size * local_work_size : count; /* Self-test cludge */ if (idx_offset > 4 * (global_work_size + 1)) idx_offset = 0; if (new_keys) { if (key_idx > key_offset) HANDLE_CLERROR(clEnqueueWriteBuffer(queue[gpu_id], cl_saved_key, CL_FALSE, key_offset, key_idx - key_offset, saved_key + key_offset, 0, NULL, NULL), "Failed transferring keys"); HANDLE_CLERROR(clEnqueueWriteBuffer(queue[gpu_id], cl_saved_idx, CL_FALSE, idx_offset, 4 * (global_work_size + 1) - idx_offset, saved_idx + (idx_offset / 4), 0, NULL, multi_profilingEvent[0]), "Failed transferring index"); HANDLE_CLERROR(clEnqueueNDRangeKernel(queue[gpu_id], krb5pa_md5_nthash, 1, NULL, &global_work_size, lws, 0, NULL, multi_profilingEvent[1]), "Failed running first kernel"); new_keys = 0; } HANDLE_CLERROR(clEnqueueNDRangeKernel(queue[gpu_id], crypt_kernel, 1, NULL, &global_work_size, lws, 0, NULL, multi_profilingEvent[2]), "Failed running second kernel"); HANDLE_CLERROR(clEnqueueReadBuffer(queue[gpu_id], cl_result, CL_TRUE, 0, BINARY_SIZE * global_work_size, output, 0, NULL, multi_profilingEvent[3]), "failed reading results back"); for (i = 0; i < count; i++) { unsigned char *binary = &((unsigned char*)output)[BINARY_SIZE * i]; // Check for known plaintext if (binary[14] == '2' && binary[15] == '0') { salt_t *salt = (salt_t*)saltblob; unsigned char K[KEY_SIZE]; unsigned char K1[KEY_SIZE]; unsigned char K3[KEY_SIZE]; unsigned char plaintext[TIMESTAMP_SIZE]; const unsigned char one[] = { 1, 0, 0, 0 }; char *password; // K = MD4(UTF-16LE(password)) // This is not thread safe password = get_key(i); E_md4hash((unsigned char*)password, strlen(password), K); // K1 = HMAC-MD5(K, 1) // 1 is encoded as little endian in 4 bytes (0x01000000) hmac_md5(K, (unsigned char*)&one, 4, K1); // K3 = HMAC-MD5(K1, CHECKSUM) hmac_md5(K1, (unsigned char*)salt->checksum, CHECKSUM_SIZE, K3); // Decrypt the timestamp RC4_single(K3, KEY_SIZE, salt->timestamp, TIMESTAMP_SIZE, plaintext); if (plaintext[28] == 'Z') { // create checksum K2 = HMAC-MD5(K1, plaintext) hmac_md5(K1, plaintext, TIMESTAMP_SIZE, binary); } } } return count; }
static bool test_ntlm_in_both(void) { bool pass = True; NTSTATUS nt_status; uint32 flags = 0; DATA_BLOB nt_response = data_blob(NULL, 24); DATA_BLOB session_key = data_blob(NULL, 16); uint8 lm_key[8]; uint8 lm_hash[16]; uint8 user_session_key[16]; uint8 nt_hash[16]; DATA_BLOB chall = get_challenge(); char *error_string; ZERO_STRUCT(lm_key); ZERO_STRUCT(user_session_key); flags |= WBFLAG_PAM_LMKEY; flags |= WBFLAG_PAM_USER_SESSION_KEY; SMBNTencrypt(opt_password,chall.data,nt_response.data); E_md4hash(opt_password, nt_hash); SMBsesskeygen_ntv1(nt_hash, session_key.data); E_deshash(opt_password, lm_hash); nt_status = contact_winbind_auth_crap(opt_username, opt_domain, opt_workstation, &chall, &nt_response, &nt_response, flags, lm_key, user_session_key, &error_string, NULL); data_blob_free(&nt_response); if (!NT_STATUS_IS_OK(nt_status)) { d_printf("%s (0x%x)\n", error_string, NT_STATUS_V(nt_status)); SAFE_FREE(error_string); return False; } if (memcmp(lm_hash, lm_key, sizeof(lm_key)) != 0) { DEBUG(1, ("LM Key does not match expectations!\n")); DEBUG(1, ("lm_key:\n")); dump_data(1, lm_key, 8); DEBUG(1, ("expected:\n")); dump_data(1, lm_hash, 8); pass = False; } if (memcmp(session_key.data, user_session_key, sizeof(user_session_key)) != 0) { DEBUG(1, ("NT Session Key does not match expectations!\n")); DEBUG(1, ("user_session_key:\n")); dump_data(1, user_session_key, 16); DEBUG(1, ("expected:\n")); dump_data(1, session_key.data, session_key.length); pass = False; } return pass; }
int net_rpc_join_newstyle(int argc, const char **argv) { /* libsmb variables */ struct cli_state *cli; TALLOC_CTX *mem_ctx; uint32 acb_info = ACB_WSTRUST; uint32 sec_channel_type; /* rpc variables */ POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol; DOM_SID *domain_sid; uint32 user_rid; /* Password stuff */ char *clear_trust_password = NULL; uchar pwbuf[516]; SAM_USERINFO_CTR ctr; SAM_USER_INFO_24 p24; SAM_USER_INFO_10 p10; uchar md4_trust_password[16]; /* Misc */ NTSTATUS result; int retval = 1; char *domain; uint32 num_rids, *name_types, *user_rids; uint32 flags = 0x3e8; char *acct_name; const char *const_acct_name; /* check what type of join */ if (argc >= 0) { sec_channel_type = get_sec_channel_type(argv[0]); } else { sec_channel_type = get_sec_channel_type(NULL); } switch (sec_channel_type) { case SEC_CHAN_WKSTA: acb_info = ACB_WSTRUST; break; case SEC_CHAN_BDC: acb_info = ACB_SVRTRUST; break; #if 0 case SEC_CHAN_DOMAIN: acb_info = ACB_DOMTRUST; break; #endif } /* Connect to remote machine */ if (!(cli = net_make_ipc_connection(NET_FLAGS_PDC))) return 1; if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) { DEBUG(0, ("Could not initialise talloc context\n")); goto done; } /* Fetch domain sid */ if (!cli_nt_session_open(cli, PI_LSARPC)) { DEBUG(0, ("Error connecting to LSA pipe\n")); goto done; } CHECK_RPC_ERR(cli_lsa_open_policy(cli, mem_ctx, True, SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol), "error opening lsa policy handle"); CHECK_RPC_ERR(cli_lsa_query_info_policy(cli, mem_ctx, &lsa_pol, 5, &domain, &domain_sid), "error querying info policy"); cli_lsa_close(cli, mem_ctx, &lsa_pol); cli_nt_session_close(cli); /* Done with this pipe */ /* Create domain user */ if (!cli_nt_session_open(cli, PI_SAMR)) { DEBUG(0, ("Error connecting to SAM pipe\n")); goto done; } CHECK_RPC_ERR(cli_samr_connect(cli, mem_ctx, SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol), "could not connect to SAM database"); CHECK_RPC_ERR(cli_samr_open_domain(cli, mem_ctx, &sam_pol, SEC_RIGHTS_MAXIMUM_ALLOWED, domain_sid, &domain_pol), "could not open domain"); /* Create domain user */ acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname()); strlower_m(acct_name); const_acct_name = acct_name; result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol, acct_name, acb_info, 0xe005000b, &user_pol, &user_rid); if (!NT_STATUS_IS_OK(result) && !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) { d_printf("Creation of workstation account failed\n"); /* If NT_STATUS_ACCESS_DENIED then we have a valid username/password combo but the user does not have administrator access. */ if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) d_printf("User specified does not have administrator privileges\n"); goto done; } /* We *must* do this.... don't ask... */ if (NT_STATUS_IS_OK(result)) cli_samr_close(cli, mem_ctx, &user_pol); CHECK_RPC_ERR_DEBUG(cli_samr_lookup_names(cli, mem_ctx, &domain_pol, flags, 1, &const_acct_name, &num_rids, &user_rids, &name_types), ("error looking up rid for user %s: %s\n", acct_name, nt_errstr(result))); if (name_types[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0])); goto done; } user_rid = user_rids[0]; /* Open handle on user */ CHECK_RPC_ERR_DEBUG( cli_samr_open_user(cli, mem_ctx, &domain_pol, SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol), ("could not re-open existing user %s: %s\n", acct_name, nt_errstr(result))); /* Create a random machine account password */ { char *str; str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); clear_trust_password = SMB_STRDUP(str); E_md4hash(clear_trust_password, md4_trust_password); } encode_pw_buffer(pwbuf, clear_trust_password, STR_UNICODE); /* Set password on machine account */ ZERO_STRUCT(ctr); ZERO_STRUCT(p24); init_sam_user_info24(&p24, (char *)pwbuf,24); ctr.switch_value = 24; ctr.info.id24 = &p24; CHECK_RPC_ERR(cli_samr_set_userinfo(cli, mem_ctx, &user_pol, 24, &cli->user_session_key, &ctr), "error setting trust account password"); /* Why do we have to try to (re-)set the ACB to be the same as what we passed in the samr_create_dom_user() call? When a NT workstation is joined to a domain by an administrator the acb_info is set to 0x80. For a normal user with "Add workstations to the domain" rights the acb_info is 0x84. I'm not sure whether it is supposed to make a difference or not. NT seems to cope with either value so don't bomb out if the set userinfo2 level 0x10 fails. -tpot */ ZERO_STRUCT(ctr); ctr.switch_value = 0x10; ctr.info.id10 = &p10; init_sam_user_info10(&p10, acb_info); /* Ignoring the return value is necessary for joining a domain as a normal user with "Add workstation to domain" privilege. */ result = cli_samr_set_userinfo2(cli, mem_ctx, &user_pol, 0x10, &cli->user_session_key, &ctr); /* Now check the whole process from top-to-bottom */ cli_samr_close(cli, mem_ctx, &user_pol); cli_nt_session_close(cli); /* Done with this pipe */ if (!cli_nt_session_open(cli, PI_NETLOGON)) { DEBUG(0,("Error connecting to NETLOGON pipe\n")); goto done; } /* ensure that schannel uses the right domain */ fstrcpy(cli->domain, domain); result = cli_nt_establish_netlogon(cli, sec_channel_type, md4_trust_password); if (!NT_STATUS_IS_OK(result)) { DEBUG(0, ("Error domain join verification (reused connection): %s\n\n", nt_errstr(result))); if ( NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) && (sec_channel_type == SEC_CHAN_BDC) ) { d_printf("Please make sure that no computer account\n" "named like this machine (%s) exists in the domain\n", global_myname()); } goto done; } /* Now store the secret in the secrets database */ strupper_m(domain); if (!secrets_store_domain_sid(domain, domain_sid)) { DEBUG(0, ("error storing domain sid for %s\n", domain)); goto done; } if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) { DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain)); } /* double-check, connection from scratch */ retval = net_rpc_join_ok(domain); done: /* Close down pipe - this will clean up open policy handles */ if (cli->nt_pipe_fnum[cli->pipe_idx]) cli_nt_session_close(cli); /* Display success or failure */ if (retval != 0) { fprintf(stderr,"Unable to join domain %s.\n",domain); } else { printf("Joined domain %s.\n",domain); } cli_shutdown(cli); SAFE_FREE(clear_trust_password); return retval; }
static int calc_ntlmv2_hash(struct cifsSesInfo *ses, char *ntlmv2_hash, const struct nls_table *nls_cp) { int rc = 0; int len; char nt_hash[CIFS_NTHASH_SIZE]; wchar_t *user; wchar_t *domain; wchar_t *server; if (!ses->server->secmech.sdeschmacmd5) { cERROR(1, "calc_ntlmv2_hash: can't generate ntlmv2 hash\n"); return -1; } /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); crypto_shash_setkey(ses->server->secmech.hmacmd5, nt_hash, CIFS_NTHASH_SIZE); rc = crypto_shash_init(&ses->server->secmech.sdeschmacmd5->shash); if (rc) { cERROR(1, "calc_ntlmv2_hash: could not init hmacmd5\n"); return rc; } /* convert ses->userName to unicode and uppercase */ len = strlen(ses->userName); user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) { cERROR(1, "calc_ntlmv2_hash: user mem alloc failure\n"); rc = -ENOMEM; goto calc_exit_2; } len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)user, 2 * len); /* convert ses->domainName to unicode and uppercase */ if (ses->domainName) { len = strlen(ses->domainName); domain = kmalloc(2 + (len * 2), GFP_KERNEL); if (domain == NULL) { cERROR(1, "calc_ntlmv2_hash: domain mem alloc failure"); rc = -ENOMEM; goto calc_exit_1; } len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, nls_cp); crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)domain, 2 * len); kfree(domain); } else if (ses->serverName) { len = strlen(ses->serverName); server = kmalloc(2 + (len * 2), GFP_KERNEL); if (server == NULL) { cERROR(1, "calc_ntlmv2_hash: server mem alloc failure"); rc = -ENOMEM; goto calc_exit_1; } len = cifs_strtoUCS((__le16 *)server, ses->serverName, len, nls_cp); crypto_shash_update(&ses->server->secmech.sdeschmacmd5->shash, (char *)server, 2 * len); kfree(server); } rc = crypto_shash_final(&ses->server->secmech.sdeschmacmd5->shash, ntlmv2_hash); calc_exit_1: kfree(user); calc_exit_2: return rc; }
int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv) { /* libsmb variables */ struct cli_state *cli; TALLOC_CTX *mem_ctx; uint32 acb_info = ACB_WSTRUST; uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; enum netr_SchannelType sec_channel_type; struct rpc_pipe_client *pipe_hnd = NULL; struct dcerpc_binding_handle *b = NULL; /* rpc variables */ struct policy_handle lsa_pol, sam_pol, domain_pol, user_pol; struct dom_sid *domain_sid; uint32 user_rid; /* Password stuff */ char *clear_trust_password = NULL; struct samr_CryptPassword crypt_pwd; uchar md4_trust_password[16]; union samr_UserInfo set_info; /* Misc */ NTSTATUS status, result; int retval = 1; const char *domain = NULL; char *acct_name; struct lsa_String lsa_acct_name; uint32 acct_flags=0; uint32_t access_granted = 0; union lsa_PolicyInformation *info = NULL; struct samr_Ids user_rids; struct samr_Ids name_types; /* check what type of join */ if (argc >= 0) { sec_channel_type = get_sec_channel_type(argv[0]); } else { sec_channel_type = get_sec_channel_type(NULL); } switch (sec_channel_type) { case SEC_CHAN_WKSTA: acb_info = ACB_WSTRUST; break; case SEC_CHAN_BDC: acb_info = ACB_SVRTRUST; break; #if 0 case SEC_CHAN_DOMAIN: acb_info = ACB_DOMTRUST; break; #endif default: DEBUG(0,("secure channel type %d not yet supported\n", sec_channel_type)); break; } /* Make authenticated connection to remote machine */ status = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli); if (!NT_STATUS_IS_OK(status)) { return 1; } if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) { DEBUG(0, ("Could not initialise talloc context\n")); goto done; } /* Fetch domain sid */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n", nt_errstr(status) )); goto done; } b = pipe_hnd->binding_handle; CHECK_RPC_ERR(rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true, SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol), "error opening lsa policy handle"); CHECK_DCERPC_ERR(dcerpc_lsa_QueryInfoPolicy(b, mem_ctx, &lsa_pol, LSA_POLICY_INFO_ACCOUNT_DOMAIN, &info, &result), "error querying info policy"); domain = info->account_domain.name.string; domain_sid = info->account_domain.sid; dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result); TALLOC_FREE(pipe_hnd); /* Done with this pipe */ /* Bail out if domain didn't get set. */ if (!domain) { DEBUG(0, ("Could not get domain name.\n")); goto done; } /* Create domain user */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n", nt_errstr(status) )); goto done; } b = pipe_hnd->binding_handle; CHECK_DCERPC_ERR(dcerpc_samr_Connect2(b, mem_ctx, pipe_hnd->desthost, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_LOOKUP_DOMAIN, &sam_pol, &result), "could not connect to SAM database"); CHECK_DCERPC_ERR(dcerpc_samr_OpenDomain(b, mem_ctx, &sam_pol, SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 | SAMR_DOMAIN_ACCESS_CREATE_USER | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, domain_sid, &domain_pol, &result), "could not open domain"); /* Create domain user */ if ((acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname())) == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } strlower_m(acct_name); init_lsa_String(&lsa_acct_name, acct_name); acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE | SEC_STD_WRITE_DAC | SEC_STD_DELETE | SAMR_USER_ACCESS_SET_PASSWORD | SAMR_USER_ACCESS_GET_ATTRIBUTES | SAMR_USER_ACCESS_SET_ATTRIBUTES; DEBUG(10, ("Creating account with flags: %d\n",acct_flags)); status = dcerpc_samr_CreateUser2(b, mem_ctx, &domain_pol, &lsa_acct_name, acb_info, acct_flags, &user_pol, &access_granted, &user_rid, &result); if (!NT_STATUS_IS_OK(status)) { goto done; } if (!NT_STATUS_IS_OK(result) && !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) { status = result; d_fprintf(stderr,_("Creation of workstation account failed\n")); /* If NT_STATUS_ACCESS_DENIED then we have a valid username/password combo but the user does not have administrator access. */ if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) d_fprintf(stderr, _("User specified does not have " "administrator privileges\n")); goto done; } /* We *must* do this.... don't ask... */ if (NT_STATUS_IS_OK(result)) { dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); } CHECK_DCERPC_ERR_DEBUG(dcerpc_samr_LookupNames(b, mem_ctx, &domain_pol, 1, &lsa_acct_name, &user_rids, &name_types, &result), ("error looking up rid for user %s: %s/%s\n", acct_name, nt_errstr(status), nt_errstr(result))); if (name_types.ids[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0])); goto done; } user_rid = user_rids.ids[0]; /* Open handle on user */ CHECK_DCERPC_ERR_DEBUG( dcerpc_samr_OpenUser(b, mem_ctx, &domain_pol, SEC_FLAG_MAXIMUM_ALLOWED, user_rid, &user_pol, &result), ("could not re-open existing user %s: %s/%s\n", acct_name, nt_errstr(status), nt_errstr(result))); /* Create a random machine account password */ clear_trust_password = generate_random_str(talloc_tos(), DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); E_md4hash(clear_trust_password, md4_trust_password); /* Set password on machine account */ init_samr_CryptPassword(clear_trust_password, &cli->user_session_key, &crypt_pwd); set_info.info24.password = crypt_pwd; set_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON; CHECK_DCERPC_ERR(dcerpc_samr_SetUserInfo2(b, mem_ctx, &user_pol, 24, &set_info, &result), "error setting trust account password"); /* Why do we have to try to (re-)set the ACB to be the same as what we passed in the samr_create_dom_user() call? When a NT workstation is joined to a domain by an administrator the acb_info is set to 0x80. For a normal user with "Add workstations to the domain" rights the acb_info is 0x84. I'm not sure whether it is supposed to make a difference or not. NT seems to cope with either value so don't bomb out if the set userinfo2 level 0x10 fails. -tpot */ set_info.info16.acct_flags = acb_info; /* Ignoring the return value is necessary for joining a domain as a normal user with "Add workstation to domain" privilege. */ status = dcerpc_samr_SetUserInfo(b, mem_ctx, &user_pol, 16, &set_info, &result); dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); TALLOC_FREE(pipe_hnd); /* Done with this pipe */ /* Now check the whole process from top-to-bottom */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Error connecting to NETLOGON pipe. Error was %s\n", nt_errstr(status) )); goto done; } status = rpccli_netlogon_setup_creds(pipe_hnd, cli->desthost, /* server name */ domain, /* domain */ global_myname(), /* client name */ global_myname(), /* machine account name */ md4_trust_password, sec_channel_type, &neg_flags); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error in domain join verification (credential setup failed): %s\n\n", nt_errstr(status))); if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && (sec_channel_type == SEC_CHAN_BDC) ) { d_fprintf(stderr, _("Please make sure that no computer " "account\nnamed like this machine " "(%s) exists in the domain\n"), global_myname()); } goto done; } /* We can only check the schannel connection if the client is allowed to do this and the server supports it. If not, just assume success (after all the rpccli_netlogon_setup_creds() succeeded, and we'll do the same again (setup creds) in net_rpc_join_ok(). JRA. */ if (lp_client_schannel() && (neg_flags & NETLOGON_NEG_SCHANNEL)) { struct rpc_pipe_client *netlogon_schannel_pipe; status = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon.syntax_id, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, &pipe_hnd->dc, &netlogon_schannel_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error in domain join verification (schannel setup failed): %s\n\n", nt_errstr(status))); if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && (sec_channel_type == SEC_CHAN_BDC) ) { d_fprintf(stderr, _("Please make sure that no " "computer account\nnamed " "like this machine (%s) " "exists in the domain\n"), global_myname()); } goto done; } TALLOC_FREE(netlogon_schannel_pipe); } TALLOC_FREE(pipe_hnd); /* Now store the secret in the secrets database */ strupper_m(CONST_DISCARD(char *, domain)); if (!secrets_store_domain_sid(domain, domain_sid)) { DEBUG(0, ("error storing domain sid for %s\n", domain)); goto done; } if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) { DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain)); } /* double-check, connection from scratch */ status = net_rpc_join_ok(c, domain, cli->desthost, &cli->dest_ss); retval = NT_STATUS_IS_OK(status) ? 0 : -1; done: /* Display success or failure */ if (domain) { if (retval != 0) { fprintf(stderr,_("Unable to join domain %s.\n"),domain); } else { printf(_("Joined domain %s.\n"),domain); } } cli_shutdown(cli); TALLOC_FREE(clear_trust_password); return retval; }
NTSTATUS dcerpc_samr_chgpasswd_user2(struct dcerpc_binding_handle *h, TALLOC_CTX *mem_ctx, const char *srv_name_slash, const char *username, const char *newpassword, const char *oldpassword, NTSTATUS *presult) { NTSTATUS status; struct samr_CryptPassword new_nt_password; struct samr_CryptPassword new_lm_password; struct samr_Password old_nt_hash_enc; struct samr_Password old_lanman_hash_enc; uint8_t old_nt_hash[16]; uint8_t old_lanman_hash[16]; uint8_t new_nt_hash[16]; uint8_t new_lanman_hash[16]; struct lsa_String server, account; DEBUG(10,("rpccli_samr_chgpasswd_user2\n")); init_lsa_String(&server, srv_name_slash); init_lsa_String(&account, username); /* Calculate the MD4 hash (NT compatible) of the password */ E_md4hash(oldpassword, old_nt_hash); E_md4hash(newpassword, new_nt_hash); if (lp_client_lanman_auth() && E_deshash(newpassword, new_lanman_hash) && E_deshash(oldpassword, old_lanman_hash)) { /* E_deshash returns false for 'long' passwords (> 14 DOS chars). This allows us to match Win2k, which does not store a LM hash for these passwords (which would reduce the effective password length to 14) */ encode_pw_buffer(new_lm_password.data, newpassword, STR_UNICODE); arcfour_crypt(new_lm_password.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash); } else { ZERO_STRUCT(new_lm_password); ZERO_STRUCT(old_lanman_hash_enc); } encode_pw_buffer(new_nt_password.data, newpassword, STR_UNICODE); arcfour_crypt(new_nt_password.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash); status = dcerpc_samr_ChangePasswordUser2(h, mem_ctx, &server, &account, &new_nt_password, &old_nt_hash_enc, true, &new_lm_password, &old_lanman_hash_enc, presult); return status; }
/* * do a password change using DCERPC/SAMR calls * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) * 2. try samr_ChangePasswordUser3 * 3. try samr_ChangePasswordUser2 * 4. try samr_OemChangePasswordUser2 * (not yet: 5. try samr_ChangePasswordUser) */ static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r) { NTSTATUS status; struct libnet_RpcConnect c; #if 0 struct policy_handle user_handle; struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6; struct samr_ChangePasswordUser pw; #endif struct samr_OemChangePasswordUser2 oe2; struct samr_ChangePasswordUser2 pw2; struct samr_ChangePasswordUser3 pw3; struct lsa_String server, account; struct lsa_AsciiString a_server, a_account; struct samr_CryptPassword nt_pass, lm_pass; struct samr_Password nt_verifier, lm_verifier; uint8_t old_nt_hash[16], new_nt_hash[16]; uint8_t old_lm_hash[16], new_lm_hash[16]; struct samr_DomInfo1 *dominfo = NULL; struct userPwdChangeFailureInformation *reject = NULL; ZERO_STRUCT(c); /* prepare connect to the SAMR pipe of the users domain PDC */ c.level = LIBNET_RPC_CONNECT_PDC; c.in.name = r->samr.in.domain_name; c.in.dcerpc_iface = &ndr_table_samr; c.in.dcerpc_flags = DCERPC_ANON_FALLBACK; /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */ status = libnet_RpcConnect(ctx, mem_ctx, &c); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "Connection to SAMR pipe of PDC of domain '%s' failed: %s", r->samr.in.domain_name, nt_errstr(status)); return status; } /* prepare password change for account */ server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe)); account.string = r->samr.in.account_name; E_md4hash(r->samr.in.oldpassword, old_nt_hash); E_md4hash(r->samr.in.newpassword, new_nt_hash); E_deshash(r->samr.in.oldpassword, old_lm_hash); E_deshash(r->samr.in.newpassword, new_lm_hash); /* prepare samr_ChangePasswordUser3 */ encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE); arcfour_crypt(lm_pass.data, old_nt_hash, 516); E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE); arcfour_crypt(nt_pass.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); pw3.in.server = &server; pw3.in.account = &account; pw3.in.nt_password = &nt_pass; pw3.in.nt_verifier = &nt_verifier; pw3.in.lm_change = 1; pw3.in.lm_password = &lm_pass; pw3.in.lm_verifier = &lm_verifier; pw3.in.password3 = NULL; pw3.out.dominfo = &dominfo; pw3.out.reject = &reject; /* 2. try samr_ChangePasswordUser3 */ status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser3 failed: %s", nt_errstr(status)); r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser3 for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(status)); } goto disconnect; } /* prepare samr_ChangePasswordUser2 */ encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE); arcfour_crypt(lm_pass.data, old_lm_hash, 516); E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE); arcfour_crypt(nt_pass.data, old_nt_hash, 516); E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash); pw2.in.server = &server; pw2.in.account = &account; pw2.in.nt_password = &nt_pass; pw2.in.nt_verifier = &nt_verifier; pw2.in.lm_change = 1; pw2.in.lm_password = &lm_pass; pw2.in.lm_verifier = &lm_verifier; /* 3. try samr_ChangePasswordUser2 */ status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser2 for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(status)); } goto disconnect; } /* prepare samr_OemChangePasswordUser2 */ a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe)); a_account.string = r->samr.in.account_name; encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII); arcfour_crypt(lm_pass.data, old_lm_hash, 516); E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash); oe2.in.server = &a_server; oe2.in.account = &a_account; oe2.in.password = &lm_pass; oe2.in.hash = &lm_verifier; /* 4. try samr_OemChangePasswordUser2 */ status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2); if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) { if (!NT_STATUS_IS_OK(oe2.out.result)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(status)); } goto disconnect; } #if 0 /* prepare samr_ChangePasswordUser */ E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash); E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash); E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash); E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash); E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash); E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash); /* TODO: ask for a user_handle */ pw.in.handle = &user_handle; pw.in.lm_present = 1; pw.in.old_lm_crypted = &hash1; pw.in.new_lm_crypted = &hash2; pw.in.nt_present = 1; pw.in.old_nt_crypted = &hash3; pw.in.new_nt_crypted = &hash4; pw.in.cross1_present = 1; pw.in.nt_cross = &hash5; pw.in.cross2_present = 1; pw.in.lm_cross = &hash6; /* 5. try samr_ChangePasswordUser */ status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw); if (!NT_STATUS_IS_OK(status)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser failed: %s", nt_errstr(status)); goto disconnect; } /* check result of samr_ChangePasswordUser */ if (!NT_STATUS_IS_OK(pw.out.result)) { r->samr.out.error_string = talloc_asprintf(mem_ctx, "samr_ChangePasswordUser for '%s\\%s' failed: %s", r->samr.in.domain_name, r->samr.in.account_name, nt_errstr(pw.out.result)); if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) { status = pw.out.result; goto disconnect; } goto disconnect; } #endif disconnect: /* close connection */ talloc_free(c.out.dcerpc_pipe); return status; }