s3-chgpasswd: split out a check_password_complexity() function.
[ira/wip.git] / source3 / smbd / chgpasswd.c
index aef5adb72f361b45fbc320bcd7cc1683f5d23f63..2da36b2fe6cbeec82c59e49145e4fb8f5d7782ec 100644 (file)
    */
 
 #include "includes.h"
-
-extern struct passdb_ops pdb_ops;
+#include "../libcli/auth/libcli_auth.h"
 
 static NTSTATUS check_oem_password(const char *user,
                                   uchar password_encrypted_with_lm_hash[516],
                                   const uchar old_lm_hash_encrypted[16],
                                   uchar password_encrypted_with_nt_hash[516],
                                   const uchar old_nt_hash_encrypted[16],
-                                  struct samu **hnd,
+                                  struct samu *sampass,
                                   char **pp_new_passwd);
 
 #if ALLOW_CHANGE_PASSWORD
 
 static int findpty(char **slave)
 {
-       int master;
-       static fstring line;
-       SMB_STRUCT_DIR *dirp;
+       int master = -1;
+       char *line = NULL;
+       SMB_STRUCT_DIR *dirp = NULL;
        const char *dpname;
 
+       *slave = NULL;
+
 #if defined(HAVE_GRANTPT)
        /* Try to open /dev/ptmx. If that fails, fall through to old method. */
-       if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
-       {
+       if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
                grantpt(master);
                unlockpt(master);
-               *slave = (char *)ptsname(master);
-               if (*slave == NULL)
-               {
+               line = (char *)ptsname(master);
+               if (line) {
+                       *slave = SMB_STRDUP(line);
+               }
+
+               if (*slave == NULL) {
                        DEBUG(0,
                              ("findpty: Unable to create master/slave pty pair.\n"));
                        /* Stop fd leak on error. */
                        close(master);
                        return -1;
-               }
-               else
-               {
+               } else {
                        DEBUG(10,
                              ("findpty: Allocated slave pty %s\n", *slave));
                        return (master);
@@ -90,22 +91,25 @@ static int findpty(char **slave)
        }
 #endif /* HAVE_GRANTPT */
 
-       fstrcpy(line, "/dev/ptyXX");
+       line = SMB_STRDUP("/dev/ptyXX");
+       if (!line) {
+               return (-1);
+       }
 
        dirp = sys_opendir("/dev");
-       if (!dirp)
+       if (!dirp) {
+               SAFE_FREE(line);
                return (-1);
-       while ((dpname = readdirname(dirp)) != NULL)
-       {
-               if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
-               {
+       }
+
+       while ((dpname = readdirname(dirp)) != NULL) {
+               if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
                        DEBUG(3,
                              ("pty: try to open %s, line was %s\n", dpname,
                               line));
                        line[8] = dpname[3];
                        line[9] = dpname[4];
-                       if ((master = sys_open(line, O_RDWR, 0)) >= 0)
-                       {
+                       if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
                                DEBUG(3, ("pty: opened %s\n", line));
                                line[5] = 't';
                                *slave = line;
@@ -115,6 +119,7 @@ static int findpty(char **slave)
                }
        }
        sys_closedir(dirp);
+       SAFE_FREE(line);
        return (-1);
 }
 
@@ -125,6 +130,7 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass,
        struct termios stermios;
        gid_t gid;
        uid_t uid;
+       char * const eptrs[1] = { NULL };
 
        if (pass == NULL)
        {
@@ -152,19 +158,24 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass,
                DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
                return (False);
        }
-#if defined(I_PUSH) && defined(I_FIND)
+#if defined(TIOCSCTTY) && !defined(SUNOS5)
+       /*
+        * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
+        * see the discussion under
+        * https://bugzilla.samba.org/show_bug.cgi?id=5366.
+        */
+       if (ioctl(slave, TIOCSCTTY, 0) < 0)
+       {
+               DEBUG(3, ("Error in ioctl call for slave pty\n"));
+               /* return(False); */
+       }
+#elif defined(I_PUSH) && defined(I_FIND)
        if (ioctl(slave, I_FIND, "ptem") == 0) {
                ioctl(slave, I_PUSH, "ptem");
        }
        if (ioctl(slave, I_FIND, "ldterm") == 0) {
                ioctl(slave, I_PUSH, "ldterm");
        }
-#elif defined(TIOCSCTTY)
-       if (ioctl(slave, TIOCSCTTY, 0) < 0)
-       {
-               DEBUG(3, ("Error in ioctl call for slave pty\n"));
-               /* return(False); */
-       }
 #endif
 
        /* Close master. */
@@ -172,17 +183,17 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass,
 
        /* Make slave stdin/out/err of child. */
 
-       if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
+       if (dup2(slave, STDIN_FILENO) != STDIN_FILENO)
        {
                DEBUG(3, ("Could not re-direct stdin\n"));
                return (False);
        }
-       if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
+       if (dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
        {
                DEBUG(3, ("Could not re-direct stdout\n"));
                return (False);
        }
-       if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
+       if (dup2(slave, STDERR_FILENO) != STDERR_FILENO)
        {
                DEBUG(3, ("Could not re-direct stderr\n"));
                return (False);
@@ -221,7 +232,7 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass,
               passwordprogram));
 
        /* execl() password-change application */
-       if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
+       if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
        {
                DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
                return (False);
@@ -232,16 +243,19 @@ static int dochild(int master, const char *slavedev, const struct passwd *pass,
 static int expect(int master, char *issue, char *expected)
 {
        char buffer[1024];
-       int attempts, timeout, nread, len;
+       int attempts, timeout, nread;
+       size_t len;
        bool match = False;
 
        for (attempts = 0; attempts < 2; attempts++) {
+               NTSTATUS status;
                if (!strequal(issue, ".")) {
                        if (lp_passwd_chat_debug())
                                DEBUG(100, ("expect: sending [%s]\n", issue));
 
                        if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
-                               DEBUG(2,("expect: (short) write returned %d\n", len ));
+                               DEBUG(2,("expect: (short) write returned %d\n",
+                                        (int)len ));
                                return False;
                        }
                }
@@ -254,9 +268,15 @@ static int expect(int master, char *issue, char *expected)
                nread = 0;
                buffer[nread] = 0;
 
-               while ((len = read_socket_with_timeout(master, buffer + nread, 1,
-                                                      sizeof(buffer) - nread - 1,
-                                                      timeout, NULL)) > 0) {
+               while (True) {
+                       status = read_fd_with_timeout(
+                               master, buffer + nread, 1,
+                               sizeof(buffer) - nread - 1,
+                               timeout, &len);
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               break;
+                       }
                        nread += len;
                        buffer[nread] = 0;
 
@@ -284,8 +304,8 @@ static int expect(int master, char *issue, char *expected)
                if (match)
                        break;
 
-               if (len < 0) {
-                       DEBUG(2, ("expect: %s\n", strerror(errno)));
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(2, ("expect: %s\n", nt_errstr(status)));
                        return False;
                }
        }
@@ -304,41 +324,57 @@ static void pwd_sub(char *buf)
 
 static int talktochild(int master, const char *seq)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        int count = 0;
-       fstring issue, expected;
+       char *issue;
+       char *expected;
 
-       fstrcpy(issue, ".");
+       issue = talloc_strdup(frame, ".");
+       if (!issue) {
+               TALLOC_FREE(frame);
+               return false;
+       }
 
-       while (next_token(&seq, expected, NULL, sizeof(expected)))
-       {
+       while (next_token_talloc(frame, &seq, &expected, NULL)) {
                pwd_sub(expected);
                count++;
 
-               if (!expect(master, issue, expected))
-               {
+               if (!expect(master, issue, expected)) {
                        DEBUG(3, ("Response %d incorrect\n", count));
-                       return False;
+                       TALLOC_FREE(frame);
+                       return false;
                }
 
-               if (!next_token(&seq, issue, NULL, sizeof(issue)))
-                       fstrcpy(issue, ".");
-
+               if (!next_token_talloc(frame, &seq, &issue, NULL)) {
+                       issue = talloc_strdup(frame, ".");
+                       if (!issue) {
+                               TALLOC_FREE(frame);
+                               return false;
+                       }
+               }
                pwd_sub(issue);
        }
+
        if (!strequal(issue, ".")) {
                /* we have one final issue to send */
-               fstrcpy(expected, ".");
-               if (!expect(master, issue, expected))
+               expected = talloc_strdup(frame, ".");
+               if (!expected) {
+                       TALLOC_FREE(frame);
+                       return false;
+               }
+               if (!expect(master, issue, expected)) {
+                       TALLOC_FREE(frame);
                        return False;
+               }
        }
-
+       TALLOC_FREE(frame);
        return (count > 0);
 }
 
 static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
                              char *chatsequence, bool as_root)
 {
-       char *slavedev;
+       char *slavedev = NULL;
        int master;
        pid_t pid, wpid;
        int wstat;
@@ -364,6 +400,7 @@ static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
 
        if ((pid = sys_fork()) < 0) {
                DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
+               SAFE_FREE(slavedev);
                close(master);
                CatchChild();
                return (False);
@@ -371,6 +408,9 @@ static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
 
        /* we now have a pty */
        if (pid > 0) {                  /* This is the parent process */
+               /* Don't need this anymore in parent. */
+               SAFE_FREE(slavedev);
+
                if ((chstat = talktochild(master, chatsequence)) == False) {
                        DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
                        kill(pid, SIGKILL);     /* be sure to end this process */
@@ -502,6 +542,9 @@ bool chgpasswd(const char *name, const struct passwd *pass,
 #ifdef WITH_PAM
        if (lp_pam_password_change()) {
                bool ret;
+#ifdef HAVE_SETLOCALE
+               const char *prevlocale = setlocale(LC_ALL, "C");
+#endif
 
                if (as_root)
                        become_root();
@@ -515,6 +558,10 @@ bool chgpasswd(const char *name, const struct passwd *pass,
                if (as_root)
                        unbecome_root();
 
+#ifdef HAVE_SETLOCALE
+               setlocale(LC_ALL, prevlocale);
+#endif
+
                return ret;
        }
 #endif
@@ -664,7 +711,7 @@ bool check_lanman_password(char *user, uchar * pass1,
 
 bool change_lanman_password(struct samu *sampass, uchar *pass2)
 {
-       static uchar null_pw[16];
+       uchar null_pw[16];
        uchar unenc_new_pw[16];
        bool ret;
        uint32 acct_ctrl;
@@ -687,20 +734,21 @@ bool change_lanman_password(struct samu *sampass, uchar *pass2)
        if (pwd == NULL) { 
                if (acct_ctrl & ACB_PWNOTREQ) {
                        uchar no_pw[14];
-                       memset(no_pw, '\0', 14);
+
+                       ZERO_STRUCT(no_pw);
+
                        E_P16(no_pw, null_pw);
 
-                       /* Get the new lanman hash. */
-                       D_P16(null_pw, pass2, unenc_new_pw);
+                       pwd = null_pw;
                } else {
                        DEBUG(0,("change_lanman_password: no lanman password !\n"));
                        return False;
                }
-       } else {
-               /* Get the new lanman hash. */
-               D_P16(pwd, pass2, unenc_new_pw);
        }
 
+       /* Get the new lanman hash. */
+       D_P16(pwd, pass2, unenc_new_pw);
+
        if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
                return False;
        }
@@ -730,19 +778,37 @@ NTSTATUS pass_oem_change(char *user,
                         const uchar old_lm_hash_encrypted[16],
                         uchar password_encrypted_with_nt_hash[516],
                         const uchar old_nt_hash_encrypted[16],
-                        uint32 *reject_reason)
+                        enum samPwdChangeReason *reject_reason)
 {
        char *new_passwd = NULL;
        struct samu *sampass = NULL;
-       NTSTATUS nt_status = check_oem_password(user,
-                                               password_encrypted_with_lm_hash,
-                                               old_lm_hash_encrypted,
-                                               password_encrypted_with_nt_hash,
-                                               old_nt_hash_encrypted,
-                                               &sampass,
-                                               &new_passwd);
+       NTSTATUS nt_status;
+       bool ret = false;
+
+       if (!(sampass = samu_new(NULL))) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       become_root();
+       ret = pdb_getsampwnam(sampass, user);
+       unbecome_root();
+
+       if (ret == false) {
+               DEBUG(0,("pass_oem_change: getsmbpwnam returned NULL\n"));
+               TALLOC_FREE(sampass);
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       nt_status = check_oem_password(user,
+                                      password_encrypted_with_lm_hash,
+                                      old_lm_hash_encrypted,
+                                      password_encrypted_with_nt_hash,
+                                      old_nt_hash_encrypted,
+                                      sampass,
+                                      &new_passwd);
 
        if (!NT_STATUS_IS_OK(nt_status)) {
+               TALLOC_FREE(sampass);
                return nt_status;
        }
 
@@ -775,50 +841,34 @@ static NTSTATUS check_oem_password(const char *user,
                                   const uchar old_lm_hash_encrypted[16],
                                   uchar password_encrypted_with_nt_hash[516],
                                   const uchar old_nt_hash_encrypted[16],
-                                  struct samu **hnd,
+                                  struct samu *sampass,
                                   char **pp_new_passwd)
 {
-       static uchar null_pw[16];
-       static uchar null_ntpw[16];
-       struct samu *sampass = NULL;
+       uchar null_pw[16];
+       uchar null_ntpw[16];
        uint8 *password_encrypted;
        const uint8 *encryption_key;
        const uint8 *lanman_pw, *nt_pw;
        uint32 acct_ctrl;
-       uint32 new_pw_len;
+       size_t new_pw_len;
        uchar new_nt_hash[16];
        uchar new_lm_hash[16];
        uchar verifier[16];
        char no_pw[2];
-       bool ret;
 
        bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
        bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
 
-       *hnd = NULL;
-
-       if ( !(sampass = samu_new( NULL )) ) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       become_root();
-       ret = pdb_getsampwnam(sampass, user);
-       unbecome_root();
-
-       if (ret == False) {
-               DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
-               TALLOC_FREE(sampass);
-               return NT_STATUS_NO_SUCH_USER;
-       }
-
        acct_ctrl = pdb_get_acct_ctrl(sampass);
+#if 0
+       /* I am convinced this check here is wrong, it is valid to
+        * change a password of a user that has a disabled account - gd */
 
        if (acct_ctrl & ACB_DISABLED) {
                DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
-               TALLOC_FREE(sampass);
                return NT_STATUS_ACCOUNT_DISABLED;
        }
-
+#endif
        if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
                /* construct a null password (in case one is needed */
                no_pw[0] = 0;
@@ -850,7 +900,6 @@ static NTSTATUS check_oem_password(const char *user,
        } else if (nt_pass_set) {
                DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", 
                          user));
-               TALLOC_FREE(sampass);
                return NT_STATUS_WRONG_PASSWORD;
        } else if (lm_pass_set) {
                if (lp_lanman_auth()) {
@@ -860,26 +909,23 @@ static NTSTATUS check_oem_password(const char *user,
                        DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n", 
                                  user));
                }
-               TALLOC_FREE(sampass);
                return NT_STATUS_WRONG_PASSWORD;
        } else {
                DEBUG(1, ("password change requested for user %s, but no password supplied!\n", 
                          user));
-               TALLOC_FREE(sampass);
                return NT_STATUS_WRONG_PASSWORD;
        }
 
        /*
         * Decrypt the password with the key
         */
-       SamOEMhash( password_encrypted, encryption_key, 516);
+       arcfour_crypt( password_encrypted, encryption_key, 516);
 
        if (!decode_pw_buffer(talloc_tos(),
                                password_encrypted,
                                pp_new_passwd,
                                &new_pw_len,
-                               nt_pass_set ? STR_UNICODE : STR_ASCII)) {
-               TALLOC_FREE(sampass);
+                               nt_pass_set ? CH_UTF16 : CH_DOS)) {
                return NT_STATUS_WRONG_PASSWORD;
        }
 
@@ -902,7 +948,6 @@ static NTSTATUS check_oem_password(const char *user,
                        E_old_pw_hash(new_nt_hash, nt_pw, verifier);
                        if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
                                DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
-                               TALLOC_FREE(sampass);
                                return NT_STATUS_WRONG_PASSWORD;
                        }
 
@@ -919,7 +964,6 @@ static NTSTATUS check_oem_password(const char *user,
                        DEBUG(100,
                              ("check_oem_password: password %s ok\n", *pp_new_passwd));
 #endif
-                       *hnd = sampass;
                        return NT_STATUS_OK;
                }
 
@@ -930,14 +974,12 @@ static NTSTATUS check_oem_password(const char *user,
                        E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
                        if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
                                DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
-                               TALLOC_FREE(sampass);
                                return NT_STATUS_WRONG_PASSWORD;
                        }
 #ifdef DEBUG_PASSWORD
                        DEBUG(100,
                              ("check_oem_password: password %s ok\n", *pp_new_passwd));
 #endif
-                       *hnd = sampass;
                        return NT_STATUS_OK;
                }
        }
@@ -952,7 +994,6 @@ static NTSTATUS check_oem_password(const char *user,
                E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
                if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
                        DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
-                       TALLOC_FREE(sampass);
                        return NT_STATUS_WRONG_PASSWORD;
                }
 
@@ -960,12 +1001,10 @@ static NTSTATUS check_oem_password(const char *user,
                DEBUG(100,
                      ("check_oem_password: password %s ok\n", *pp_new_passwd));
 #endif
-               *hnd = sampass;
                return NT_STATUS_OK;
        }
 
        /* should not be reached */
-       TALLOC_FREE(sampass);
        return NT_STATUS_WRONG_PASSWORD;
 }
 
@@ -985,7 +1024,7 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext)
        int i;
        uint32 pwHisLen, curr_pwHisLen;
 
-       pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
+       pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHisLen);
        if (pwHisLen == 0) {
                return False;
        }
@@ -1035,6 +1074,43 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext)
        return found;
 }
 
+/***********************************************************
+************************************************************/
+
+NTSTATUS check_password_complexity(const char *username,
+                                  const char *password,
+                                  enum samPwdChangeReason *samr_reject_reason)
+{
+       TALLOC_CTX *tosctx = talloc_tos();
+
+       /* Use external script to check password complexity */
+       if (lp_check_password_script() && *(lp_check_password_script())) {
+               int check_ret;
+               char *cmd;
+
+               cmd = talloc_string_sub(tosctx, lp_check_password_script(), "%u", username);
+               if (!cmd) {
+                       return NT_STATUS_PASSWORD_RESTRICTION;
+               }
+
+               check_ret = smbrunsecret(cmd, password);
+               DEBUG(5,("check_password_complexity: check password script (%s) returned [%d]\n",
+                       cmd, check_ret));
+               TALLOC_FREE(cmd);
+
+               if (check_ret != 0) {
+                       DEBUG(1,("check_password_complexity: "
+                               "check password script said new password is not good enough!\n"));
+                       if (samr_reject_reason) {
+                               *samr_reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
+                       }
+                       return NT_STATUS_PASSWORD_RESTRICTION;
+               }
+       }
+
+       return NT_STATUS_OK;
+}
+
 /***********************************************************
  Code to change the oem password. Changes both the lanman
  and NT hashes.  Old_passwd is almost always NULL.
@@ -1042,23 +1118,25 @@ static bool check_passwd_history(struct samu *sampass, const char *plaintext)
  is correct before calling. JRA.
 ************************************************************/
 
-NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
+NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, enum samPwdChangeReason *samr_reject_reason)
 {
        uint32 min_len;
        uint32 refuse;
+       TALLOC_CTX *tosctx = talloc_tos();
        struct passwd *pass = NULL;
        const char *username = pdb_get_username(hnd);
        time_t can_change_time = pdb_get_pass_can_change_time(hnd);
+       NTSTATUS status;
 
        if (samr_reject_reason) {
-               *samr_reject_reason = Undefined;
+               *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
        }
 
        /* check to see if the secdesc has previously been set to disallow */
        if (!pdb_get_pass_can_change(hnd)) {
                DEBUG(1, ("user %s does not have permissions to change password\n", username));
                if (samr_reject_reason) {
-                       *samr_reject_reason = REJECT_REASON_OTHER;
+                       *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
                }
                return NT_STATUS_ACCOUNT_RESTRICTION;
        }
@@ -1067,12 +1145,12 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw
         * denies machines to change the password. *
         * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
        if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
-               if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
+               if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
                        DEBUG(1, ("Machine %s cannot change password now, "
                                  "denied by Refuse Machine Password Change policy\n",
                                  username));
                        if (samr_reject_reason) {
-                               *samr_reject_reason = REJECT_REASON_OTHER;
+                               *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
                        }
                        return NT_STATUS_ACCOUNT_RESTRICTION;
                }
@@ -1083,19 +1161,19 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw
        if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
                DEBUG(1, ("user %s cannot change password now, must "
                          "wait until %s\n", username,
-                         http_timestring(can_change_time)));
+                         http_timestring(tosctx, can_change_time)));
                if (samr_reject_reason) {
-                       *samr_reject_reason = REJECT_REASON_OTHER;
+                       *samr_reject_reason = SAM_PWD_CHANGE_NO_ERROR;
                }
                return NT_STATUS_ACCOUNT_RESTRICTION;
        }
 
-       if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
+       if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
                DEBUG(1, ("user %s cannot change password - password too short\n", 
                          username));
                DEBUGADD(1, (" account policy min password len = %d\n", min_len));
                if (samr_reject_reason) {
-                       *samr_reject_reason = REJECT_REASON_TOO_SHORT;
+                       *samr_reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
                }
                return NT_STATUS_PASSWORD_RESTRICTION;
 /*             return NT_STATUS_PWD_TOO_SHORT; */
@@ -1103,31 +1181,21 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw
 
        if (check_passwd_history(hnd,new_passwd)) {
                if (samr_reject_reason) {
-                       *samr_reject_reason = REJECT_REASON_IN_HISTORY;
+                       *samr_reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
                }
                return NT_STATUS_PASSWORD_RESTRICTION;
        }
 
-       pass = Get_Pwnam(username);
+       pass = Get_Pwnam_alloc(tosctx, username);
        if (!pass) {
                DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       /* Use external script to check password complexity */
-       if (lp_check_password_script() && *(lp_check_password_script())) {
-               int check_ret;
-
-               check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
-               DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
-
-               if (check_ret != 0) {
-                       DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
-                       if (samr_reject_reason) {
-                               *samr_reject_reason = REJECT_REASON_NOT_COMPLEX;
-                       }
-                       return NT_STATUS_PASSWORD_RESTRICTION;
-               }
+       status = check_password_complexity(username, new_passwd, samr_reject_reason);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(pass);
+               return status;
        }
 
        /*
@@ -1144,9 +1212,12 @@ NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passw
        
        if(lp_unix_password_sync() &&
                !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
+               TALLOC_FREE(pass);
                return NT_STATUS_ACCESS_DENIED;
        }
 
+       TALLOC_FREE(pass);
+
        if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
                return NT_STATUS_ACCESS_DENIED;
        }