NTSTATUS rpccli_samr_chgpasswd_user2(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, const char *username, const char *newpassword, const char *oldpassword) { NTSTATUS result = NT_STATUS_UNSUCCESSFUL; 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; uchar old_nt_hash[16]; uchar old_lanman_hash[16]; uchar new_nt_hash[16]; uchar new_lanman_hash[16]; struct lsa_String server, account; DEBUG(10,("rpccli_samr_chgpasswd_user2\n")); init_lsa_String(&server, cli->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); result = rpccli_samr_ChangePasswordUser2(cli, mem_ctx, &server, &account, &new_nt_password, &old_nt_hash_enc, true, &new_lm_password, &old_lanman_hash_enc); return result; }
NTSTATUS dcerpc_samr_chgpasswd_user(struct dcerpc_binding_handle *h, TALLOC_CTX *mem_ctx, struct policy_handle *user_handle, const char *newpassword, const char *oldpassword, NTSTATUS *presult) { NTSTATUS status; struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6; uchar old_nt_hash[16]; uchar old_lm_hash[16]; uchar new_nt_hash[16]; uchar new_lm_hash[16]; ZERO_STRUCT(old_nt_hash); ZERO_STRUCT(old_lm_hash); ZERO_STRUCT(new_nt_hash); ZERO_STRUCT(new_lm_hash); DEBUG(10,("rpccli_samr_chgpasswd_user\n")); E_md4hash(oldpassword, old_nt_hash); E_md4hash(newpassword, new_nt_hash); E_deshash(oldpassword, old_lm_hash); E_deshash(newpassword, new_lm_hash); 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); status = dcerpc_samr_ChangePasswordUser(h, mem_ctx, user_handle, true, &hash1, &hash2, true, &hash3, &hash4, true, &hash5, true, &hash6, presult); return status; }
NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, struct policy_handle *user_handle, const char *newpassword, const char *oldpassword) { NTSTATUS result = NT_STATUS_UNSUCCESSFUL; struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6; uchar old_nt_hash[16]; uchar old_lm_hash[16]; uchar new_nt_hash[16]; uchar new_lm_hash[16]; ZERO_STRUCT(old_nt_hash); ZERO_STRUCT(old_lm_hash); ZERO_STRUCT(new_nt_hash); ZERO_STRUCT(new_lm_hash); DEBUG(10,("rpccli_samr_chgpasswd_user\n")); E_md4hash(oldpassword, old_nt_hash); E_md4hash(newpassword, new_nt_hash); E_deshash(oldpassword, old_lm_hash); E_deshash(newpassword, new_lm_hash); 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); result = rpccli_samr_ChangePasswordUser(cli, mem_ctx, user_handle, true, &hash1, &hash2, true, &hash3, &hash4, true, &hash5, true, &hash6); return result; }
NTSTATUS dcerpc_samr_chgpasswd_user3(struct dcerpc_binding_handle *h, TALLOC_CTX *mem_ctx, const char *srv_name_slash, const char *username, const char *newpassword, const char *oldpassword, struct samr_DomInfo1 **dominfo1, struct userPwdChangeFailureInformation **reject, 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_user3\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_ChangePasswordUser3(h, mem_ctx, &server, &account, &new_nt_password, &old_nt_hash_enc, true, &new_lm_password, &old_lanman_hash_enc, NULL, dominfo1, reject, presult); return status; }
bool cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password, const char *old_password) { char param[1024]; unsigned char data[532]; char *p = param; unsigned char old_pw_hash[16]; unsigned char new_pw_hash[16]; unsigned int data_len; unsigned int param_len = 0; char *rparam = NULL; char *rdata = NULL; unsigned int rprcnt, rdrcnt; if (strlen(user) >= sizeof(fstring)-1) { DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user)); return False; } SSVAL(p,0,214); /* SamOEMChangePassword command. */ p += 2; strlcpy(p, "zsT", sizeof(param)-PTR_DIFF(p,param)); p = skip_string(param,sizeof(param),p); strlcpy(p, "B516B16", sizeof(param)-PTR_DIFF(p,param)); p = skip_string(param,sizeof(param),p); strlcpy(p,user, sizeof(param)-PTR_DIFF(p,param)); p = skip_string(param,sizeof(param),p); SSVAL(p,0,532); p += 2; param_len = PTR_DIFF(p,param); /* * Get the Lanman hash of the old password, we * use this as the key to make_oem_passwd_hash(). */ E_deshash(old_password, old_pw_hash); encode_pw_buffer(data, new_password, STR_ASCII); #ifdef DEBUG_PASSWORD DEBUG(100,("make_oem_passwd_hash\n")); dump_data(100, data, 516); #endif arcfour_crypt( (unsigned char *)data, (unsigned char *)old_pw_hash, 516); /* * Now place the old password hash in the data. */ E_deshash(new_password, new_pw_hash); E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]); data_len = 532; if (!cli_api(cli, param, param_len, 4, /* param, length, max */ (char *)data, data_len, 0, /* data, length, max */ &rparam, &rprcnt, &rdata, &rdrcnt)) { DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n", user )); return False; } if (rparam) { cli->rap_error = SVAL(rparam,0); } SAFE_FREE(rparam); SAFE_FREE(rdata); return (cli->rap_error == 0); }
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")); }
BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password, const char *old_password) { pstring param; unsigned char data[532]; char *p = param; unsigned char old_pw_hash[16]; unsigned char new_pw_hash[16]; unsigned int data_len; unsigned int param_len = 0; char *rparam = NULL; char *rdata = NULL; unsigned int rprcnt, rdrcnt; if (strlen(user) >= sizeof(fstring)-1) { DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user)); return False; } SSVAL(p,0,214); /* SamOEMChangePassword command. */ p += 2; pstrcpy_base(p, "zsT", param); p = skip_string(param,sizeof(param),p); pstrcpy_base(p, "B516B16", param); p = skip_string(param,sizeof(param),p); pstrcpy_base(p,user, param); p = skip_string(param,sizeof(param),p); SSVAL(p,0,532); p += 2; param_len = PTR_DIFF(p,param); /* * Get the Lanman hash of the old password, we * use this as the key to make_oem_passwd_hash(). */ E_deshash(old_password, old_pw_hash); encode_pw_buffer(data, new_password, STR_ASCII); #ifdef DEBUG_PASSWORD DEBUG(100,("make_oem_passwd_hash\n")); dump_data(100, (char *)data, 516); #endif SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, 516); /* * Now place the old password hash in the data. */ E_deshash(new_password, new_pw_hash); E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]); data_len = 532; if (cli_send_trans(cli,SMBtrans, PIPE_LANMAN, /* name */ 0,0, /* fid, flags */ NULL,0,0, /* setup, length, max */ param,param_len,2, /* param, length, max */ (char *)data,data_len,0 /* data, length, max */ ) == False) { DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n", user )); return False; } if (!cli_receive_trans(cli,SMBtrans, &rparam, &rprcnt, &rdata, &rdrcnt)) { DEBUG(0,("cli_oem_change_password: Failed to recieve reply to password change for user %s\n", user )); return False; } if (rparam) { cli->rap_error = SVAL(rparam,0); } SAFE_FREE(rparam); SAFE_FREE(rdata); return (cli->rap_error == 0); }
/* samr_ChangePasswordUser3 */ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser3 *r) { NTSTATUS status; DATA_BLOB new_password; struct ldb_context *sam_ctx = NULL; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL }; struct samr_Password *nt_pwd, *lm_pwd; DATA_BLOB nt_pwd_blob; struct samr_DomInfo1 *dominfo = NULL; struct userPwdChangeFailureInformation *reject = NULL; enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR; uint8_t new_nt_hash[16], new_lm_hash[16]; struct samr_Password nt_verifier, lm_verifier; *r->out.dominfo = NULL; *r->out.reject = NULL; if (r->in.nt_password == NULL || r->in.nt_verifier == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm and nt password hashes in order to decrypt the incoming passwords */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ status = NT_STATUS_WRONG_PASSWORD; goto failed; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) ) { goto failed; } if (!nt_pwd) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* decrypt the password we have been given */ nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash)); arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob); data_blob_free(&nt_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); status = NT_STATUS_WRONG_PASSWORD; goto failed; } if (r->in.nt_verifier == NULL) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check NT verifier */ mdfour(new_nt_hash, new_password.data, new_password.length); E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check LM verifier (really not needed as we just checked the * much stronger NT hash, but the RPC-SAMR test checks for * this) */ if (lm_pwd && r->in.lm_verifier != NULL) { char *new_pass; if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_UTF16, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, &new_password, NULL, NULL, lm_pwd, nt_pwd, /* this is a user password change */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); goto failed; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_TRANSACTION_ABORTED; goto failed; } return NT_STATUS_OK; failed: reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation); if (reject != NULL) { reject->extendedFailureReason = reason; *r->out.reject = reject; } *r->out.dominfo = dominfo; return status; }
/* samr_OemChangePasswordUser2 */ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_OemChangePasswordUser2 *r) { NTSTATUS status; DATA_BLOB new_password, new_unicode_password; char *new_pass; struct samr_CryptPassword *pwbuf = r->in.password; struct ldb_context *sam_ctx; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "objectSid", "dBCSPwd", NULL }; struct samr_Password *lm_pwd; DATA_BLOB lm_pwd_blob; uint8_t new_lm_hash[16]; struct samr_Password lm_verifier; size_t unicode_pw_len; if (pwbuf == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (r->in.hash == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* this call can only work with lanman auth */ if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm password hash in order to decrypt the incoming password */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ return NT_STATUS_WRONG_PASSWORD; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, NULL); if (!NT_STATUS_IS_OK(status) || !lm_pwd) { return NT_STATUS_WRONG_PASSWORD; } /* decrypt the password we have been given */ lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob); data_blob_free(&lm_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UTF16, (const char *)new_password.data, new_password.length, (void **)&new_unicode_password.data, &unicode_pw_len, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n")); return NT_STATUS_WRONG_PASSWORD; } new_unicode_password.length = unicode_pw_len; E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* Start transaction */ ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, &new_unicode_password, NULL, NULL, lm_pwd, NULL, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }
/* samr_ChangePasswordUser3 */ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser3 *r) { NTSTATUS status; DATA_BLOB new_password; struct ldb_context *sam_ctx = NULL; struct ldb_dn *user_dn; int ret; struct ldb_message **res, *mod; const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL }; struct samr_Password *nt_pwd, *lm_pwd; DATA_BLOB nt_pwd_blob; struct samr_DomInfo1 *dominfo = NULL; struct samr_ChangeReject *reject = NULL; enum samr_RejectReason reason = SAMR_REJECT_OTHER; uint8_t new_nt_hash[16], new_lm_hash[16]; struct samr_Password nt_verifier, lm_verifier; *r->out.dominfo = NULL; *r->out.reject = NULL; if (r->in.nt_password == NULL || r->in.nt_verifier == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* To change a password we need to open as system */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx)); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret) { talloc_free(sam_ctx); DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm and nt password hashes in order to decrypt the incoming passwords */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ status = NT_STATUS_WRONG_PASSWORD; goto failed; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) ) { goto failed; } if (!nt_pwd) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* decrypt the password we have been given */ nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash)); arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob); data_blob_free(&nt_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) { ldb_transaction_cancel(sam_ctx); DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (r->in.nt_verifier == NULL) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check NT verifier */ mdfour(new_nt_hash, new_password.data, new_password.length); E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check LM verifier (really not needed as we just checked the * much stronger NT hash, but the RPC-SAMR test checks for * this) */ if (lm_pwd && r->in.lm_verifier != NULL) { char *new_pass; if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_UTF16, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } mod = ldb_msg_new(mem_ctx); if (mod == NULL) { status = NT_STATUS_NO_MEMORY; goto failed; } mod->dn = ldb_dn_copy(mod, user_dn); if (!mod->dn) { status = NT_STATUS_NO_MEMORY; goto failed; } /* set the password on the user DN specified. This may fail * due to password policies */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, mod, &new_password, NULL, NULL, true, /* this is a user password change */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { goto failed; } /* The above call only setup the modifications, this actually * makes the write to the database. */ ret = samdb_replace(sam_ctx, mem_ctx, mod); if (ret != 0) { DEBUG(2,("samdb_replace failed to change password for %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_UNSUCCESSFUL; goto failed; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != 0) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); status = NT_STATUS_TRANSACTION_ABORTED; goto failed; } return NT_STATUS_OK; failed: ldb_transaction_cancel(sam_ctx); talloc_free(sam_ctx); reject = talloc(mem_ctx, struct samr_ChangeReject); *r->out.dominfo = dominfo; *r->out.reject = reject; if (reject == NULL) { return status; } ZERO_STRUCTP(reject); reject->reason = reason; return status; }
/* samr_OemChangePasswordUser2 */ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_OemChangePasswordUser2 *r) { NTSTATUS status; DATA_BLOB new_password, new_unicode_password; char *new_pass; struct samr_CryptPassword *pwbuf = r->in.password; struct ldb_context *sam_ctx; struct ldb_dn *user_dn; int ret; struct ldb_message **res, *mod; const char * const attrs[] = { "objectSid", "dBCSPwd", NULL }; struct samr_Password *lm_pwd; DATA_BLOB lm_pwd_blob; uint8_t new_lm_hash[16]; struct samr_Password lm_verifier; size_t unicode_pw_len; if (pwbuf == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (r->in.hash == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* To change a password we need to open as system */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx)); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } ret = ldb_transaction_start(sam_ctx); if (ret) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm password hash in order to decrypt the incoming password */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { ldb_transaction_cancel(sam_ctx); /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ return NT_STATUS_WRONG_PASSWORD; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, NULL); if (!NT_STATUS_IS_OK(status) || !lm_pwd) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } /* decrypt the password we have been given */ lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob); data_blob_free(&lm_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) { ldb_transaction_cancel(sam_ctx); DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n")); ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UTF16, (const char *)new_password.data, new_password.length, (void **)&new_unicode_password.data, &unicode_pw_len, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n")); ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } new_unicode_password.length = unicode_pw_len; E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_WRONG_PASSWORD; } mod = ldb_msg_new(mem_ctx); if (mod == NULL) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_NO_MEMORY; } mod->dn = ldb_dn_copy(mod, user_dn); if (!mod->dn) { ldb_transaction_cancel(sam_ctx); return NT_STATUS_NO_MEMORY; } /* set the password on the user DN specified. This may fail * due to password policies */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, mod, &new_unicode_password, NULL, NULL, true, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* The above call only setup the modifications, this actually * makes the write to the database. */ ret = samdb_replace(sam_ctx, mem_ctx, mod); if (ret != 0) { DEBUG(2,("Failed to modify record to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); ldb_transaction_cancel(sam_ctx); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != 0) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }
/* * 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; }