This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "rpc_server/common/common.h"
#include "rpc_server/samr/dcesrv_samr.h"
#include "system/time.h"
-#include "lib/crypto/crypto.h"
+#include "../lib/crypto/crypto.h"
#include "dsdb/common/flags.h"
#include "libcli/ldap/ldap.h"
#include "dsdb/samdb/samdb.h"
#include "auth/auth.h"
#include "rpc_server/samr/proto.h"
#include "libcli/auth/libcli_auth.h"
-#include "db_wrap.h"
+#include "../lib/util/util_ldb.h"
+#include "param/param.h"
/*
samr_ChangePasswordUser
*/
-NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
- struct samr_ChangePasswordUser *r)
+NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
+ TALLOC_CTX *mem_ctx,
+ struct samr_ChangePasswordUser *r)
{
struct dcesrv_handle *h;
struct samr_account_state *a_state;
struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
struct samr_Password *lm_pwd, *nt_pwd;
NTSTATUS status = NT_STATUS_OK;
- const char * const attrs[] = { "lmPwdHash", "ntPwdHash" , NULL };
+ const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };
DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
present */
return NT_STATUS_INVALID_PARAMETER_MIX;
}
- if (!r->in.cross1_present || !r->in.nt_cross) {
- return NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED;
- }
- if (!r->in.cross2_present || !r->in.lm_cross) {
- return NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED;
- }
/* To change a password we need to open as system */
- sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
+ 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;
}
}
msg = res[0];
- status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
+ status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
+ msg, &lm_pwd, &nt_pwd);
if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_WRONG_PASSWORD;
return NT_STATUS_WRONG_PASSWORD;
}
- /* check the nt cross hash */
- D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
- if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
- ldb_transaction_cancel(sam_ctx);
- return NT_STATUS_WRONG_PASSWORD;
+ /* The NT Cross is not required by Win2k3 R2, but if present
+ check the nt cross hash */
+ if (r->in.cross1_present && r->in.nt_cross) {
+ D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
+ if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
}
- /* check the lm cross hash */
- D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
- if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
- ldb_transaction_cancel(sam_ctx);
- return NT_STATUS_WRONG_PASSWORD;
+ /* The LM Cross is not required by Win2k3 R2, but if present
+ check the lm cross hash */
+ if (r->in.cross2_present && r->in.lm_cross) {
+ D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
+ if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
}
msg = ldb_msg_new(mem_ctx);
status = samdb_set_password(sam_ctx, mem_ctx,
a_state->account_dn, a_state->domain_state->domain_dn,
msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
- True, /* this is a user password change */
- True, /* run restriction tests */
+ true, /* this is a user password change */
NULL,
NULL);
if (!NT_STATUS_IS_OK(status)) {
ret = samdb_replace(sam_ctx, mem_ctx, msg);
if (ret != 0) {
DEBUG(2,("Failed to modify record to change password on %s: %s\n",
- ldb_dn_linearize(mem_ctx, a_state->account_dn),
+ ldb_dn_get_linearized(a_state->account_dn),
ldb_errstring(sam_ctx)));
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
ret = ldb_transaction_commit(sam_ctx);
if (ret != 0) {
DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
- ldb_dn_linearize(mem_ctx, a_state->account_dn),
+ ldb_dn_get_linearized(a_state->account_dn),
ldb_errstring(sam_ctx)));
return NT_STATUS_TRANSACTION_ABORTED;
}
/*
samr_OemChangePasswordUser2
*/
-NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct samr_OemChangePasswordUser2 *r)
{
NTSTATUS status;
- char new_pass[512];
- uint32_t new_pass_len;
+ DATA_BLOB new_password, new_unicode_password;
+ char *new_pass;
struct samr_CryptPassword *pwbuf = r->in.password;
struct ldb_context *sam_ctx;
- const struct ldb_dn *user_dn;
+ struct ldb_dn *user_dn;
int ret;
struct ldb_message **res, *mod;
- const char * const attrs[] = { "objectSid", "lmPwdHash", NULL };
+ 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;
+ ssize_t unicode_pw_len;
if (pwbuf == NULL) {
- return NT_STATUS_WRONG_PASSWORD;
+ 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, system_session(mem_ctx));
+ 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;
}
user_dn = res[0]->dn;
- status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
+ 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;
arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
data_blob_free(&lm_pwd_blob);
- if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
- &new_pass_len, STR_ASCII)) {
+ 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) == -1) {
+ DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
+ ldb_transaction_cancel(sam_ctx);
+ return NT_STATUS_WRONG_PASSWORD;
+ }
- /* check LM verifier */
- if (lm_pwd == NULL || r->in.hash == NULL) {
+ unicode_pw_len = 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);
+ if (unicode_pw_len == -1) {
+ 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);
* due to password policies */
status = samdb_set_password(sam_ctx, mem_ctx,
user_dn, NULL,
- mod, new_pass,
+ mod, &new_unicode_password,
NULL, NULL,
- True, /* this is a user password change */
- True, /* run restriction tests */
+ true, /* this is a user password change */
NULL,
NULL);
if (!NT_STATUS_IS_OK(status)) {
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_linearize(mem_ctx, user_dn),
+ ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
ldb_transaction_cancel(sam_ctx);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
ret = ldb_transaction_commit(sam_ctx);
if (ret != 0) {
DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
- ldb_dn_linearize(mem_ctx, user_dn),
+ ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
return NT_STATUS_TRANSACTION_ABORTED;
}
/*
samr_ChangePasswordUser3
*/
-NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
+NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx,
struct samr_ChangePasswordUser3 *r)
{
NTSTATUS status;
- char new_pass[512];
- uint32_t new_pass_len;
+ DATA_BLOB new_password;
struct ldb_context *sam_ctx = NULL;
- const struct ldb_dn *user_dn;
+ struct ldb_dn *user_dn;
int ret;
struct ldb_message **res, *mod;
- const char * const attrs[] = { "ntPwdHash", "lmPwdHash", NULL };
+ const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
struct samr_Password *nt_pwd, *lm_pwd;
DATA_BLOB nt_pwd_blob;
struct samr_DomInfo1 *dominfo = NULL;
uint8_t new_nt_hash[16], new_lm_hash[16];
struct samr_Password nt_verifier, lm_verifier;
- ZERO_STRUCT(r->out);
+ *r->out.dominfo = NULL;
+ *r->out.reject = NULL;
if (r->in.nt_password == NULL ||
r->in.nt_verifier == NULL) {
}
/* To change a password we need to open as system */
- sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
+ 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;
}
user_dn = res[0]->dn;
- status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
+ 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;
}
arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
data_blob_free(&nt_pwd_blob);
- if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
- &new_pass_len, STR_UNICODE)) {
+ 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"));
- status = NT_STATUS_WRONG_PASSWORD;
- goto failed;
+ return NT_STATUS_WRONG_PASSWORD;
}
-
+
if (r->in.nt_verifier == NULL) {
status = NT_STATUS_WRONG_PASSWORD;
goto failed;
}
/* check NT verifier */
- E_md4hash(new_pass, new_nt_hash);
+ 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 */
+ /* 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) {
- 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;
+ 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) != -1) {
+ 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) {
- return NT_STATUS_NO_MEMORY;
+ status = NT_STATUS_NO_MEMORY;
+ goto failed;
}
mod->dn = ldb_dn_copy(mod, user_dn);
* due to password policies */
status = samdb_set_password(sam_ctx, mem_ctx,
user_dn, NULL,
- mod, new_pass,
+ mod, &new_password,
NULL, NULL,
- True, /* this is a user password change */
- True, /* run restriction tests */
+ true, /* this is a user password change */
&reason,
&dominfo);
if (!NT_STATUS_IS_OK(status)) {
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_linearize(mem_ctx, user_dn),
+ ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
status = NT_STATUS_UNSUCCESSFUL;
goto failed;
ret = ldb_transaction_commit(sam_ctx);
if (ret != 0) {
DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
- ldb_dn_linearize(mem_ctx, user_dn),
+ ldb_dn_get_linearized(user_dn),
ldb_errstring(sam_ctx)));
status = NT_STATUS_TRANSACTION_ABORTED;
goto failed;
talloc_free(sam_ctx);
reject = talloc(mem_ctx, struct samr_ChangeReject);
- r->out.dominfo = dominfo;
- r->out.reject = reject;
+ *r->out.dominfo = dominfo;
+ *r->out.reject = reject;
if (reject == NULL) {
return status;
easy - just a subset of samr_ChangePasswordUser3
*/
-NTSTATUS samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
struct samr_ChangePasswordUser2 *r)
{
struct samr_ChangePasswordUser3 r2;
+ struct samr_DomInfo1 *dominfo = NULL;
+ struct samr_ChangeReject *reject = NULL;
r2.in.server = r->in.server;
r2.in.account = r->in.account;
r2.in.lm_password = r->in.lm_password;
r2.in.lm_verifier = r->in.lm_verifier;
r2.in.password3 = NULL;
+ r2.out.dominfo = &dominfo;
+ r2.out.reject = &reject;
- return samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
+ return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
}
*/
NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
void *sam_ctx,
- const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
+ struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
TALLOC_CTX *mem_ctx,
struct ldb_message *msg,
struct samr_CryptPassword *pwbuf)
{
NTSTATUS nt_status;
- char new_pass[512];
- uint32_t new_pass_len;
+ DATA_BLOB new_password;
DATA_BLOB session_key = data_blob(NULL, 0);
nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
arcfour_crypt_blob(pwbuf->data, 516, &session_key);
- if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
- &new_pass_len, STR_UNICODE)) {
+ 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;
}
-
+
/* set the password - samdb needs to know both the domain and user DNs,
so the domain password policy can be used */
return samdb_set_password(sam_ctx, mem_ctx,
account_dn, domain_dn,
- msg, new_pass,
+ msg, &new_password,
NULL, NULL,
- False, /* This is a password set, not change */
- True, /* run restriction tests */
+ false, /* This is a password set, not change */
NULL, NULL);
}
*/
NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
struct ldb_context *sam_ctx,
- const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
+ struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
TALLOC_CTX *mem_ctx,
struct ldb_message *msg,
struct samr_CryptPasswordEx *pwbuf)
{
NTSTATUS nt_status;
- char new_pass[512];
- uint32_t new_pass_len;
+ DATA_BLOB new_password;
DATA_BLOB co_session_key;
DATA_BLOB session_key = data_blob(NULL, 0);
struct MD5Context ctx;
arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
- if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
- &new_pass_len, STR_UNICODE)) {
+ 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;
}
-
+
/* set the password - samdb needs to know both the domain and user DNs,
so the domain password policy can be used */
return samdb_set_password(sam_ctx, mem_ctx,
account_dn, domain_dn,
- msg, new_pass,
+ msg, &new_password,
NULL, NULL,
- False, /* This is a password set, not change */
- True, /* run restriction tests */
+ false, /* This is a password set, not change */
NULL, NULL);
}