r11195: Add a new helper function (needed by my kpasswdd work, but hooked in
authorAndrew Bartlett <abartlet@samba.org>
Thu, 20 Oct 2005 03:17:42 +0000 (03:17 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:44:59 +0000 (13:44 -0500)
for netlogon as well) to change/set a user's password, given only
their SID.

This avoids the callers doing the lookups, and also performs the
actual 'set', as these callers do not wish any further buisness with
the entry.

Andrew Bartlett
(This used to be commit 060a2a7bcca6b58d50bc4e0930c13616742a55d3)

source4/rpc_server/netlogon/dcerpc_netlogon.c
source4/rpc_server/samr/samr_password.c

index 99701fc4f1de4e764a130f65d3d166c236ac89fd..472fcca785524a4fa93e020025ec28f90f94a6bf 100644 (file)
@@ -223,13 +223,13 @@ static NTSTATUS netr_ServerAuthenticate3(struct dcesrv_call_state *dce_call, TAL
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       pipe_state->creds->account_name = talloc_reference(pipe_state->creds, r->in.account_name);
+       pipe_state->creds->account_name = talloc_steal(pipe_state->creds, r->in.account_name);
        
-       pipe_state->creds->computer_name = talloc_reference(pipe_state->creds, r->in.computer_name);
+       pipe_state->creds->computer_name = talloc_steal(pipe_state->creds, r->in.computer_name);
 
        pipe_state->creds->secure_channel_type = r->in.secure_channel_type;
 
-       pipe_state->creds->rid = *r->out.rid;
+       pipe_state->creds->sid = samdb_result_dom_sid(pipe_state->creds, msgs[0], "objectSid");
 
        pipe_state->creds->domain = talloc_strdup(pipe_state->creds, lp_workgroup());
 
@@ -305,19 +305,8 @@ static NTSTATUS netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLO
 {
        struct server_pipe_state *pipe_state = dce_call->context->private;
 
-       void *sam_ctx;
-       int num_records;
-       int num_records_domain;
-       int ret;
-       struct ldb_message **msgs;
-       struct ldb_message **msgs_domain;
+       struct ldb_context *sam_ctx;
        NTSTATUS nt_status;
-       struct ldb_message *mod;
-       struct dom_sid *domain_sid;
-
-       const char *attrs[] = {"objectSid", NULL };
-
-       const char **domain_attrs = attrs;
 
        nt_status = netr_creds_server_step_check(pipe_state, &r->in.credential, &r->out.return_authenticator);
        NT_STATUS_NOT_OK_RETURN(nt_status);
@@ -326,79 +315,18 @@ static NTSTATUS netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLO
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
        }
-       /* pull the user attributes */
-       num_records = gendb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs,
-                                  "(&(sAMAccountName=%s)(objectclass=user))", 
-                                  pipe_state->creds->account_name);
-       if (num_records == -1) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       if (num_records == 0) {
-               DEBUG(3,("Couldn't find user [%s] in samdb.\n", 
-                        pipe_state->creds->account_name));
-               return NT_STATUS_NO_SUCH_USER;
-       }
-
-       if (num_records > 1) {
-               DEBUG(0,("Found %d records matching user [%s]\n", num_records, 
-                        pipe_state->creds->account_name));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid");
-       if (!domain_sid) {
-               DEBUG(0,("no objectSid in user record\n"));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       /* find the domain's DN */
-       num_records_domain = gendb_search(sam_ctx, mem_ctx, NULL, 
-                                         &msgs_domain, domain_attrs,
-                                         "(&(objectSid=%s)(objectclass=domain))", 
-                                         ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
-       if (num_records_domain == -1) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       if (num_records_domain == 0) {
-               DEBUG(3,("Couldn't find domain [%s] in samdb.\n", 
-                        dom_sid_string(mem_ctx, domain_sid)));
-               return NT_STATUS_NO_SUCH_USER;
-       }
 
-       if (num_records_domain > 1) {
-               DEBUG(0,("Found %d records matching domain [%s]\n", 
-                        num_records_domain, dom_sid_string(mem_ctx, domain_sid)));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       mod = talloc_zero(mem_ctx, struct ldb_message);
-       NT_STATUS_HAVE_NO_MEMORY(mod);
-       mod->dn = talloc_reference(mod, msgs[0]->dn);
-    
        creds_des_decrypt(pipe_state->creds, &r->in.new_password);
 
-       /* set the password - samdb needs to know both the domain and user DNs,
-          so the domain password policy can be used */
-       nt_status = samdb_set_password(sam_ctx, mod,
-                                      msgs[0]->dn,
-                                      msgs_domain[0]->dn,
-                                      mod,
-                                      NULL, /* Don't have plaintext */
-                                      NULL, &r->in.new_password,
-                                      False, /* This is not considered a password change */
-                                      False, /* don't restrict this password change (match w2k3) */
-                                      NULL);
-       NT_STATUS_NOT_OK_RETURN(nt_status);
-
-       ret = samdb_replace(sam_ctx, mem_ctx, mod);
-       if (ret != 0) {
-               /* we really need samdb.c to return NTSTATUS */
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       return NT_STATUS_OK;
+       /* Using the sid for the account as the key, set the password */
+       nt_status = samdb_set_password_sid(sam_ctx, mem_ctx, 
+                                          pipe_state->creds->sid,
+                                          NULL, /* Don't have plaintext */
+                                          NULL, &r->in.new_password,
+                                          False, /* This is not considered a password change */
+                                          False, /* don't restrict this password change (match w2k3) */
+                                          NULL, NULL);
+       return nt_status;
 }
 
 
@@ -1013,24 +941,14 @@ static NTSTATUS netr_ServerPasswordSet2(struct dcesrv_call_state *dce_call, TALL
 {
        struct server_pipe_state *pipe_state = dce_call->context->private;
 
-       void *sam_ctx;
-       int num_records;
-       int num_records_domain;
-       int ret;
-       struct ldb_message **msgs;
-       struct ldb_message **msgs_domain;
+       struct ldb_context *sam_ctx;
        NTSTATUS nt_status;
-       struct ldb_message *mod;
-       struct dom_sid *domain_sid;
        char new_pass[512];
        uint32_t new_pass_len;
+       BOOL ret;
 
        struct samr_CryptPassword password_buf;
 
-       const char *attrs[] = {"objectSid", NULL };
-
-       const char **domain_attrs = attrs;
-
        nt_status = netr_creds_server_step_check(pipe_state, &r->in.credential, &r->out.return_authenticator);
        NT_STATUS_NOT_OK_RETURN(nt_status);
 
@@ -1038,58 +956,7 @@ static NTSTATUS netr_ServerPasswordSet2(struct dcesrv_call_state *dce_call, TALL
        if (sam_ctx == NULL) {
                return NT_STATUS_INVALID_SYSTEM_SERVICE;
        }
-       /* pull the user attributes */
-       num_records = gendb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs,
-                                  "(&(sAMAccountName=%s)(objectclass=user))", 
-                                  pipe_state->creds->account_name);
-       if (num_records == -1) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       if (num_records == 0) {
-               DEBUG(3,("Couldn't find user [%s] in samdb.\n", 
-                        pipe_state->creds->account_name));
-               return NT_STATUS_NO_SUCH_USER;
-       }
-
-       if (num_records > 1) {
-               DEBUG(0,("Found %d records matching user [%s]\n", num_records, 
-                        pipe_state->creds->account_name));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid");
-       if (!domain_sid) {
-               DEBUG(0,("no objectSid in user record\n"));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       /* find the domain's DN */
-       num_records_domain = gendb_search(sam_ctx, mem_ctx, NULL, 
-                                         &msgs_domain, domain_attrs,
-                                         "(&(objectSid=%s)(objectclass=domain))", 
-                                         ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
-       if (num_records_domain == -1) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       if (num_records_domain == 0) {
-               DEBUG(3,("Couldn't find domain [%s] in samdb.\n", 
-                        ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)));
-               return NT_STATUS_NO_SUCH_USER;
-       }
 
-       if (num_records_domain > 1) {
-               DEBUG(0,("Found %d records matching domain [%s]\n", 
-                        num_records_domain, 
-                        ldap_encode_ndr_dom_sid(mem_ctx, domain_sid)));
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
-       mod = talloc_zero(mem_ctx, struct ldb_message);
-       NT_STATUS_HAVE_NO_MEMORY(mod);
-       mod->dn = talloc_reference(mod, msgs[0]->dn);
-    
        memcpy(password_buf.data, r->in.new_password.data, 512);
        SIVAL(password_buf.data,512,r->in.new_password.length);
        creds_arcfour_crypt(pipe_state->creds, password_buf.data, 516);
@@ -1101,26 +968,15 @@ static NTSTATUS netr_ServerPasswordSet2(struct dcesrv_call_state *dce_call, TALL
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       /* set the password - samdb needs to know both the domain and user DNs,
-          so the domain password policy can be used */
-       nt_status = samdb_set_password(sam_ctx, mod,
-                                      msgs[0]->dn,
-                                      msgs_domain[0]->dn,
-                                      mod, new_pass, /* we have plaintext */
-                                      NULL, NULL,
-                                      False, /* This is not considered a password change */
-                                      False, /* don't restrict this password change (match w2k3) */
-                                      NULL);
-       ZERO_STRUCT(new_pass);
-       NT_STATUS_NOT_OK_RETURN(nt_status);
-
-       ret = samdb_replace(sam_ctx, mem_ctx, mod);
-       if (ret != 0) {
-               /* we really need samdb.c to return NTSTATUS */
-               return NT_STATUS_UNSUCCESSFUL;
-       }
-
-       return NT_STATUS_OK;
+       /* Using the sid for the account as the key, set the password */
+       nt_status = samdb_set_password_sid(sam_ctx, mem_ctx,
+                                          pipe_state->creds->sid,
+                                          new_pass, /* we have plaintext */
+                                          NULL, NULL,
+                                          False, /* This is not considered a password change */
+                                          False, /* don't restrict this password change (match w2k3) */
+                                          NULL, NULL);
+       return nt_status;
 }
 
 
index 6fab23161946adaa4bba106cd49462ee6bb1f97e..2b04903ebd2fea3e46c5dd5d49a0cdf1d6fd2dc9 100644 (file)
@@ -125,6 +125,7 @@ NTSTATUS samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX
                                    msg, NULL, &new_lmPwdHash, &new_ntPwdHash, 
                                    True, /* this is a user password change */
                                    True, /* run restriction tests */
+                                   NULL,
                                    NULL);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -150,7 +151,7 @@ NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_
        uint32_t new_pass_len;
        struct samr_CryptPassword *pwbuf = r->in.password;
        struct ldb_context *sam_ctx;
-       const struct ldb_dn *user_dn, *domain_dn;
+       const struct ldb_dn *user_dn;
        int ret;
        struct ldb_message **res, *mod;
        const char * const attrs[] = { "objectSid", "lmPwdHash", "unicodePwd", NULL };
@@ -158,7 +159,6 @@ NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_
        DATA_BLOB lm_pwd_blob;
        uint8_t new_lm_hash[16];
        struct samr_Password lm_verifier;
-       struct dom_sid *domain_sid;
 
        if (pwbuf == NULL) {
                return NT_STATUS_WRONG_PASSWORD;
@@ -210,19 +210,6 @@ NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_
                return NT_STATUS_WRONG_PASSWORD;
        }
 
-       /* work out the domain dn */
-       domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
-       if (domain_sid == NULL) {
-               return NT_STATUS_NO_SUCH_USER;
-       }
-
-       domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
-                                   "(objectSid=%s)", 
-                                   ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
-       if (!domain_dn) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
-       }
-
        mod = ldb_msg_new(mem_ctx);
        if (mod == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -236,11 +223,12 @@ NTSTATUS samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_
        /* set the password - samdb needs to know both the domain and user DNs,
           so the domain password policy can be used */
        status = samdb_set_password(sam_ctx, mem_ctx,
-                                   user_dn, domain_dn
+                                   user_dn, NULL
                                    mod, new_pass, 
                                    NULL, NULL,
                                    True, /* this is a user password change */
                                    True, /* run restriction tests */
+                                   NULL, 
                                    NULL);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -267,14 +255,10 @@ NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
        char new_pass[512];
        uint32_t new_pass_len;
        struct ldb_context *sam_ctx;
-       const struct ldb_dn *user_dn, *domain_dn = NULL;
+       const struct ldb_dn *user_dn;
        int ret;
        struct ldb_message **res, *mod;
-       const char * const attrs[] = { "objectSid", "ntPwdHash", "lmPwdHash", "unicodePwd", NULL };
-       const char * const dom_attrs[] = { "minPwdLength", "pwdHistoryLength", 
-                                          "pwdProperties", "minPwdAge", "maxPwdAge", 
-                                          NULL };
-       struct dom_sid *domain_sid;
+       const char * const attrs[] = { "ntPwdHash", "lmPwdHash", "unicodePwd", NULL };
        struct samr_Password *nt_pwd, *lm_pwd;
        DATA_BLOB nt_pwd_blob;
        struct samr_DomInfo1 *dominfo;
@@ -358,21 +342,6 @@ NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
        }
 
 
-       /* work out the domain dn */
-       domain_sid = samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
-       if (domain_sid == NULL) {
-               status = NT_STATUS_NO_SUCH_DOMAIN;
-               goto failed;
-       }
-
-       domain_dn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
-                                   "(objectSid=%s)", 
-                                   ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
-       if (!domain_dn) {
-               status = NT_STATUS_INTERNAL_DB_CORRUPTION;
-               goto failed;
-       }
-
        mod = ldb_msg_new(mem_ctx);
        if (mod == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -387,12 +356,13 @@ NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
        /* set the password - samdb needs to know both the domain and user DNs,
           so the domain password policy can be used */
        status = samdb_set_password(sam_ctx, mem_ctx,
-                                   user_dn, domain_dn
+                                   user_dn, NULL
                                    mod, new_pass, 
                                    NULL, NULL,
                                    True, /* this is a user password change */
                                    True, /* run restriction tests */
-                                   &reason);
+                                   &reason, 
+                                   &dominfo);
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
        }
@@ -407,26 +377,11 @@ NTSTATUS samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
        return NT_STATUS_OK;
 
 failed:
-       if (domain_dn) {
-               ret = gendb_search_dn(sam_ctx, mem_ctx,
-                                     domain_dn, &res, dom_attrs);
-               
-               if (ret != 1) {
-                       return status;
-               }
-       }
 
-       /* on failure we need to fill in the reject reasons */
-       dominfo = talloc(mem_ctx, struct samr_DomInfo1);
-       if (dominfo == NULL) {
-               return status;
-       }
        reject = talloc(mem_ctx, struct samr_ChangeReject);
        if (reject == NULL) {
                return status;
        }
-
-       ZERO_STRUCTP(dominfo);
        ZERO_STRUCTP(reject);
 
        reject->reason = reason;
@@ -434,16 +389,6 @@ failed:
        r->out.dominfo = dominfo;
        r->out.reject = reject;
 
-       if (!domain_dn) {
-               return status;
-       }
-
-       dominfo->min_password_length     = samdb_result_uint (res[0], "minPwdLength", 0);
-       dominfo->password_properties     = samdb_result_uint (res[0], "pwdProperties", 0);
-       dominfo->password_history_length = samdb_result_uint (res[0], "pwdHistoryLength", 0);
-       dominfo->max_password_age        = samdb_result_int64(res[0], "maxPwdAge", 0);
-       dominfo->min_password_age        = samdb_result_int64(res[0], "minPwdAge", 0);
-
        return status;
 }
 
@@ -489,7 +434,7 @@ static BOOL samdb_password_complexity_ok(const char *pass)
   called. This allows the caller to combine the change with other
   changes (as is needed by some of the set user info levels)
 */
-NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
+NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
                            const struct ldb_dn *user_dn,
                            const struct ldb_dn *domain_dn,
                            struct ldb_message *mod,
@@ -498,12 +443,13 @@ NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
                            struct samr_Password *ntNewHash,
                            BOOL user_change,
                            BOOL restrictions,
-                           uint32_t *reject_reason)
+                           uint32_t *reject_reason,
+                           struct samr_DomInfo1 **_dominfo)
 {
        const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
                                            "ntPwdHistory", "unicodePwd", 
                                            "lmPwdHash", "ntPwdHash", "badPwdCount", 
-                                           NULL };
+                                           "objectSid", NULL };
        const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
                                              "maxPwdAge", "minPwdAge", 
                                              "minPwdLength", "pwdLastSet", NULL };
@@ -517,6 +463,7 @@ NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
        struct samr_Password local_lmNewHash, local_ntNewHash;
        int lmPwdHistory_len, ntPwdHistory_len;
        uint_t kvno;
+       struct dom_sid *domain_sid;
        struct ldb_message **res;
        int count;
        time_t now = time(NULL);
@@ -543,16 +490,47 @@ NTSTATUS samdb_set_password(void *ctx, TALLOC_CTX *mem_ctx,
        pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
        kvno =               samdb_result_uint(res[0],   "msDS-KeyVersionNumber", 0);
 
-       /* pull the domain parameters */
-       count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
-       if (count != 1) {
-               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       if (domain_dn) {
+               /* pull the domain parameters */
+               count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
+               if (count != 1) {
+                       return NT_STATUS_NO_SUCH_DOMAIN;
+               }
+       } else {
+               /* work out the domain sid, and pull the domain from there */
+               domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
+               if (domain_sid == NULL) {
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+
+               count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
+                                    "(objectSid=%s)", 
+                                    ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
+               if (count != 1) {
+                       return NT_STATUS_NO_SUCH_DOMAIN;
+               }
        }
+
        pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
        pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
        minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
        minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
 
+       if (_dominfo) {
+               struct samr_DomInfo1 *dominfo;
+               /* on failure we need to fill in the reject reasons */
+               dominfo = talloc(mem_ctx, struct samr_DomInfo1);
+               if (dominfo == NULL) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               dominfo->min_password_length     = minPwdLength;
+               dominfo->password_properties     = pwdProperties;
+               dominfo->password_history_length = pwdHistoryLength;
+               dominfo->max_password_age        = minPwdAge;
+               dominfo->min_password_age        = minPwdAge;
+               *_dominfo = dominfo;
+       }
+
        if (new_pass) {
                /* check the various password restrictions */
                if (restrictions && minPwdLength > strlen_m(new_pass)) {
@@ -780,7 +758,7 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
                                  NULL, NULL,
                                  False, /* This is a password set, not change */
                                  True, /* run restriction tests */
-                                 NULL);
+                                 NULL, NULL);
 }
 
 
@@ -790,7 +768,7 @@ NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
   password when applied
 */
 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
-                             void *sam_ctx,
+                             struct ldb_context *sam_ctx,
                              const struct ldb_dn *account_dn, const struct ldb_dn *domain_dn,
                              TALLOC_CTX *mem_ctx,
                              struct ldb_message *msg, 
@@ -834,6 +812,66 @@ NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
                                  NULL, NULL,
                                  False, /* This is a password set, not change */
                                  True, /* run restriction tests */
-                                 NULL);
+                                 NULL, NULL);
 }
 
+/*
+  set the user password using plaintext, obeying any user or domain
+  password restrictions
+
+  This wrapper function takes a SID as input, rather than a user DN,
+  and actually performs the password change
+
+*/
+NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
+                               const struct dom_sid *user_sid,
+                               const char *new_pass,
+                               struct samr_Password *lmNewHash, 
+                               struct samr_Password *ntNewHash,
+                               BOOL user_change,
+                               BOOL restrictions,
+                               uint32_t *reject_reason,
+                               struct samr_DomInfo1 **_dominfo) 
+{
+       NTSTATUS nt_status;
+       struct ldb_dn *user_dn;
+       struct ldb_message *msg;
+       int count;
+       int ret;
+
+       user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
+                                 "((objectSid=%s)(objectClass=user))", 
+                                 ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
+       if (count != 1) {
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       msg = ldb_msg_new(mem_ctx);
+       if (msg == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       msg->dn = ldb_dn_copy(msg, user_dn);
+       if (!msg->dn) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       nt_status = samdb_set_password(ctx, mem_ctx,
+                                      user_dn, NULL,
+                                      msg, new_pass, 
+                                      lmNewHash, ntNewHash,
+                                      user_change, /* This is a password set, not change */
+                                      restrictions, /* run restriction tests */
+                                      reject_reason, _dominfo);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
+       }
+       
+       /* modify the samdb record */
+       ret = samdb_replace(ctx, mem_ctx, msg);
+       if (ret != 0) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       return NT_STATUS_OK;
+}