2 Unix SMB/CIFS implementation.
3 Samba utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001-2004
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /* These comments regard the code to change the user's unix password: */
23 /* fork a child process to exec passwd and write to its
24 * tty to change a users password. This is running as the
25 * user who is attempting to change the password.
29 * This code was copied/borrowed and stolen from various sources.
30 * The primary source was the poppasswd.c from the authors of POPMail. This software
31 * was included as a client to change passwords using the 'passwd' program
32 * on the remote machine.
34 * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
35 * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
36 * and rights to modify, distribute or incorporate this change to the CAP suite or
37 * using it for any other reason are granted, so long as this disclaimer is left intact.
41 This code was hacked considerably for inclusion in Samba, primarily
42 by Andrew.Tridgell@anu.edu.au. The biggest change was the addition
43 of the "password chat" option, which allows the easy runtime
44 specification of the expected sequence of events to change a
50 extern struct passdb_ops pdb_ops;
52 static NTSTATUS check_oem_password(const char *user,
53 uchar password_encrypted_with_lm_hash[516],
54 const uchar old_lm_hash_encrypted[16],
55 uchar password_encrypted_with_nt_hash[516],
56 const uchar old_nt_hash_encrypted[16],
58 char **pp_new_passwd);
60 #if ALLOW_CHANGE_PASSWORD
62 static int findpty(char **slave)
69 #if defined(HAVE_GRANTPT)
70 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
71 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
75 *slave = (char *)ptsname(master);
79 ("findpty: Unable to create master/slave pty pair.\n"));
80 /* Stop fd leak on error. */
87 ("findpty: Allocated slave pty %s\n", *slave));
91 #endif /* HAVE_GRANTPT */
93 fstrcpy(line, "/dev/ptyXX");
95 dirp = sys_opendir("/dev");
98 while ((dpname = readdirname(dirp)) != NULL)
100 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
103 ("pty: try to open %s, line was %s\n", dpname,
107 if ((master = sys_open(line, O_RDWR, 0)) >= 0)
109 DEBUG(3, ("pty: opened %s\n", line));
121 static int dochild(int master, const char *slavedev, const struct passwd *pass,
122 const char *passwordprogram, bool as_root)
125 struct termios stermios;
132 ("dochild: user doesn't exist in the UNIX password database.\n"));
139 gain_root_privilege();
141 /* Start new session - gets rid of controlling terminal. */
145 ("Weirdness, couldn't let go of controlling terminal\n"));
149 /* Open slave pty and acquire as new controlling terminal. */
150 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
152 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
155 #if defined(I_PUSH) && defined(I_FIND)
156 if (ioctl(slave, I_FIND, "ptem") == 0) {
157 ioctl(slave, I_PUSH, "ptem");
159 if (ioctl(slave, I_FIND, "ldterm") == 0) {
160 ioctl(slave, I_PUSH, "ldterm");
162 #elif defined(TIOCSCTTY)
163 if (ioctl(slave, TIOCSCTTY, 0) < 0)
165 DEBUG(3, ("Error in ioctl call for slave pty\n"));
173 /* Make slave stdin/out/err of child. */
175 if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
177 DEBUG(3, ("Could not re-direct stdin\n"));
180 if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
182 DEBUG(3, ("Could not re-direct stdout\n"));
185 if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
187 DEBUG(3, ("Could not re-direct stderr\n"));
193 /* Set proper terminal attributes - no echo, canonical input processing,
194 no map NL to CR/NL on output. */
196 if (tcgetattr(0, &stermios) < 0)
199 ("could not read default terminal attributes on pty\n"));
202 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
203 stermios.c_lflag |= ICANON;
205 stermios.c_oflag &= ~(ONLCR);
207 if (tcsetattr(0, TCSANOW, &stermios) < 0)
209 DEBUG(3, ("could not set attributes of pty\n"));
213 /* make us completely into the right uid */
216 become_user_permanently(uid, gid);
220 ("Invoking '%s' as password change program.\n",
223 /* execl() password-change application */
224 if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
226 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
232 static int expect(int master, char *issue, char *expected)
235 int attempts, timeout, nread, len;
238 for (attempts = 0; attempts < 2; attempts++) {
239 if (!strequal(issue, ".")) {
240 if (lp_passwd_chat_debug())
241 DEBUG(100, ("expect: sending [%s]\n", issue));
243 if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
244 DEBUG(2,("expect: (short) write returned %d\n", len ));
249 if (strequal(expected, "."))
252 /* Initial timeout. */
253 timeout = lp_passwd_chat_timeout() * 1000;
257 while ((len = read_socket_with_timeout(master, buffer + nread, 1,
258 sizeof(buffer) - nread - 1,
259 timeout, NULL)) > 0) {
264 /* Eat leading/trailing whitespace before match. */
265 char *str = SMB_STRDUP(buffer);
267 DEBUG(2,("expect: ENOMEM\n"));
270 trim_char(str, ' ', ' ');
272 if ((match = unix_wild_match(expected, str)) == True) {
273 /* Now data has started to return, lower timeout. */
274 timeout = lp_passwd_chat_timeout() * 100;
280 if (lp_passwd_chat_debug())
281 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
282 expected, buffer, match ? "yes" : "no" ));
288 DEBUG(2, ("expect: %s\n", strerror(errno)));
293 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
297 static void pwd_sub(char *buf)
299 all_string_sub(buf, "\\n", "\n", 0);
300 all_string_sub(buf, "\\r", "\r", 0);
301 all_string_sub(buf, "\\s", " ", 0);
302 all_string_sub(buf, "\\t", "\t", 0);
305 static int talktochild(int master, const char *seq)
307 TALLOC_CTX *frame = talloc_stackframe();
312 issue = talloc_strdup(frame, ".");
318 while (next_token_talloc(frame, &seq, &expected, NULL)) {
322 if (!expect(master, issue, expected)) {
323 DEBUG(3, ("Response %d incorrect\n", count));
328 if (!next_token_talloc(frame, &seq, &issue, NULL)) {
329 issue = talloc_strdup(frame, ".");
338 if (!strequal(issue, ".")) {
339 /* we have one final issue to send */
340 expected = talloc_strdup(frame, ".");
345 if (!expect(master, issue, expected)) {
354 static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
355 char *chatsequence, bool as_root)
364 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
368 /* allocate a pseudo-terminal device */
369 if ((master = findpty(&slavedev)) < 0) {
370 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
375 * We need to temporarily stop CatchChild from eating
376 * SIGCLD signals as it also eats the exit status code. JRA.
379 CatchChildLeaveStatus();
381 if ((pid = sys_fork()) < 0) {
382 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
388 /* we now have a pty */
389 if (pid > 0) { /* This is the parent process */
390 if ((chstat = talktochild(master, chatsequence)) == False) {
391 DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
392 kill(pid, SIGKILL); /* be sure to end this process */
395 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
396 if (errno == EINTR) {
404 DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
411 * Go back to ignoring children.
418 DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
421 if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
422 DEBUG(3, ("chat_with_program: The process exited with status %d \
423 while we were waiting\n", WEXITSTATUS(wstat)));
426 #if defined(WIFSIGNALLED) && defined(WTERMSIG)
427 else if (WIFSIGNALLED(wstat)) {
428 DEBUG(3, ("chat_with_program: The process was killed by signal %d \
429 while we were waiting\n", WTERMSIG(wstat)));
437 * Lose any elevated privileges.
439 drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
440 drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
442 /* make sure it doesn't freeze */
448 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
449 (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
450 chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
456 * The child should never return from dochild() ....
459 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
464 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
465 (chstat ? "" : "un"), pass->pw_name));
469 bool chgpasswd(const char *name, const struct passwd *pass,
470 const char *oldpass, const char *newpass, bool as_root)
472 char *passwordprogram = NULL;
473 char *chatsequence = NULL;
476 TALLOC_CTX *ctx = talloc_tos();
482 DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
484 #ifdef DEBUG_PASSWORD
485 DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
488 /* Take the passed information and test it for minimum criteria */
490 /* Password is same as old password */
491 if (strcmp(oldpass, newpass) == 0) {
492 /* don't allow same password */
493 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */
494 return (False); /* inform the user */
498 * Check the old and new passwords don't contain any control
502 len = strlen(oldpass);
503 for (i = 0; i < len; i++) {
504 if (iscntrl((int)oldpass[i])) {
505 DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
510 len = strlen(newpass);
511 for (i = 0; i < len; i++) {
512 if (iscntrl((int)newpass[i])) {
513 DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
519 if (lp_pam_password_change()) {
526 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
528 ret = smb_pam_passchange(name, oldpass, newpass);
538 /* A non-PAM password change just doen't make sense without a valid local user */
541 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
545 passwordprogram = talloc_strdup(ctx, lp_passwd_program());
546 if (!passwordprogram || !*passwordprogram) {
547 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
550 chatsequence = talloc_strdup(ctx, lp_passwd_chat());
551 if (!chatsequence || !*chatsequence) {
552 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
557 /* The password program *must* contain the user name to work. Fail if not. */
558 if (strstr_m(passwordprogram, "%u") == NULL) {
559 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
560 the string %%u, and the given string %s does not.\n", passwordprogram ));
565 passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name);
566 if (!passwordprogram) {
570 /* note that we do NOT substitute the %o and %n in the password program
571 as this would open up a security hole where the user could use
572 a new password containing shell escape characters */
574 chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name);
578 chatsequence = talloc_all_string_sub(ctx,
585 chatsequence = talloc_all_string_sub(ctx,
589 return chat_with_program(passwordprogram,
595 #else /* ALLOW_CHANGE_PASSWORD */
597 bool chgpasswd(const char *name, const struct passwd *pass,
598 const char *oldpass, const char *newpass, bool as_root)
600 DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name));
603 #endif /* ALLOW_CHANGE_PASSWORD */
605 /***********************************************************
606 Code to check the lanman hashed password.
607 ************************************************************/
609 bool check_lanman_password(char *user, uchar * pass1,
610 uchar * pass2, struct samu **hnd)
612 uchar unenc_new_pw[16];
613 uchar unenc_old_pw[16];
614 struct samu *sampass = NULL;
616 const uint8 *lanman_pw;
619 if ( !(sampass = samu_new(NULL)) ) {
620 DEBUG(0, ("samu_new() failed!\n"));
625 ret = pdb_getsampwnam(sampass, user);
629 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
630 TALLOC_FREE(sampass);
634 acct_ctrl = pdb_get_acct_ctrl (sampass);
635 lanman_pw = pdb_get_lanman_passwd (sampass);
637 if (acct_ctrl & ACB_DISABLED) {
638 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
639 TALLOC_FREE(sampass);
643 if (lanman_pw == NULL) {
644 if (acct_ctrl & ACB_PWNOTREQ) {
645 /* this saves the pointer for the caller */
649 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
650 TALLOC_FREE(sampass);
655 /* Get the new lanman hash. */
656 D_P16(lanman_pw, pass2, unenc_new_pw);
658 /* Use this to get the old lanman hash. */
659 D_P16(unenc_new_pw, pass1, unenc_old_pw);
661 /* Check that the two old passwords match. */
662 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
663 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
664 TALLOC_FREE(sampass);
668 /* this saves the pointer for the caller */
673 /***********************************************************
674 Code to change the lanman hashed password.
675 It nulls out the NT hashed password as it will
677 NOTE this function is designed to be called as root. Check the old password
678 is correct before calling. JRA.
679 ************************************************************/
681 bool change_lanman_password(struct samu *sampass, uchar *pass2)
683 static uchar null_pw[16];
684 uchar unenc_new_pw[16];
689 if (sampass == NULL) {
690 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
694 acct_ctrl = pdb_get_acct_ctrl(sampass);
695 pwd = pdb_get_lanman_passwd(sampass);
697 if (acct_ctrl & ACB_DISABLED) {
698 DEBUG(0,("change_lanman_password: account %s disabled.\n",
699 pdb_get_username(sampass)));
704 if (acct_ctrl & ACB_PWNOTREQ) {
706 memset(no_pw, '\0', 14);
707 E_P16(no_pw, null_pw);
709 /* Get the new lanman hash. */
710 D_P16(null_pw, pass2, unenc_new_pw);
712 DEBUG(0,("change_lanman_password: no lanman password !\n"));
716 /* Get the new lanman hash. */
717 D_P16(pwd, pass2, unenc_new_pw);
720 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
724 if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
725 return False; /* We lose the NT hash. Sorry. */
728 if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) {
729 TALLOC_FREE(sampass);
730 /* Not quite sure what this one qualifies as, but this will do */
734 /* Now flush the sam_passwd struct to persistent storage */
735 ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass));
740 /***********************************************************
741 Code to check and change the OEM hashed password.
742 ************************************************************/
744 NTSTATUS pass_oem_change(char *user,
745 uchar password_encrypted_with_lm_hash[516],
746 const uchar old_lm_hash_encrypted[16],
747 uchar password_encrypted_with_nt_hash[516],
748 const uchar old_nt_hash_encrypted[16],
749 uint32 *reject_reason)
751 char *new_passwd = NULL;
752 struct samu *sampass = NULL;
753 NTSTATUS nt_status = check_oem_password(user,
754 password_encrypted_with_lm_hash,
755 old_lm_hash_encrypted,
756 password_encrypted_with_nt_hash,
757 old_nt_hash_encrypted,
761 if (!NT_STATUS_IS_OK(nt_status)) {
765 /* We've already checked the old password here.... */
767 nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason);
770 memset(new_passwd, 0, strlen(new_passwd));
772 TALLOC_FREE(sampass);
777 /***********************************************************
778 Decrypt and verify a user password change.
780 The 516 byte long buffers are encrypted with the old NT and
781 old LM passwords, and if the NT passwords are present, both
782 buffers contain a unicode string.
784 After decrypting the buffers, check the password is correct by
785 matching the old hashed passwords with the passwords in the passdb.
787 ************************************************************/
789 static NTSTATUS check_oem_password(const char *user,
790 uchar password_encrypted_with_lm_hash[516],
791 const uchar old_lm_hash_encrypted[16],
792 uchar password_encrypted_with_nt_hash[516],
793 const uchar old_nt_hash_encrypted[16],
795 char **pp_new_passwd)
797 static uchar null_pw[16];
798 static uchar null_ntpw[16];
799 struct samu *sampass = NULL;
800 uint8 *password_encrypted;
801 const uint8 *encryption_key;
802 const uint8 *lanman_pw, *nt_pw;
805 uchar new_nt_hash[16];
806 uchar new_lm_hash[16];
811 bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
812 bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
816 if ( !(sampass = samu_new( NULL )) ) {
817 return NT_STATUS_NO_MEMORY;
821 ret = pdb_getsampwnam(sampass, user);
825 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
826 TALLOC_FREE(sampass);
827 return NT_STATUS_NO_SUCH_USER;
830 acct_ctrl = pdb_get_acct_ctrl(sampass);
832 if (acct_ctrl & ACB_DISABLED) {
833 DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
834 TALLOC_FREE(sampass);
835 return NT_STATUS_ACCOUNT_DISABLED;
838 if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
839 /* construct a null password (in case one is needed */
842 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
847 /* save pointers to passwords so we don't have to keep looking them up */
848 if (lp_lanman_auth()) {
849 lanman_pw = pdb_get_lanman_passwd(sampass);
853 nt_pw = pdb_get_nt_passwd(sampass);
856 if (nt_pw && nt_pass_set) {
857 /* IDEAL Case: passwords are in unicode, and we can
858 * read use the password encrypted with the NT hash
860 password_encrypted = password_encrypted_with_nt_hash;
861 encryption_key = nt_pw;
862 } else if (lanman_pw && lm_pass_set) {
863 /* password may still be in unicode, but use LM hash version */
864 password_encrypted = password_encrypted_with_lm_hash;
865 encryption_key = lanman_pw;
866 } else if (nt_pass_set) {
867 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
869 TALLOC_FREE(sampass);
870 return NT_STATUS_WRONG_PASSWORD;
871 } else if (lm_pass_set) {
872 if (lp_lanman_auth()) {
873 DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
876 DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
879 TALLOC_FREE(sampass);
880 return NT_STATUS_WRONG_PASSWORD;
882 DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
884 TALLOC_FREE(sampass);
885 return NT_STATUS_WRONG_PASSWORD;
889 * Decrypt the password with the key
891 SamOEMhash( password_encrypted, encryption_key, 516);
893 if (!decode_pw_buffer(talloc_tos(),
897 nt_pass_set ? STR_UNICODE : STR_ASCII)) {
898 TALLOC_FREE(sampass);
899 return NT_STATUS_WRONG_PASSWORD;
903 * To ensure we got the correct new password, hash it and
904 * use it as a key to test the passed old password.
908 /* NT passwords, verify the NT hash. */
910 /* Calculate the MD4 hash (NT compatible) of the password */
911 memset(new_nt_hash, '\0', 16);
912 E_md4hash(*pp_new_passwd, new_nt_hash);
916 * check the NT verifier
918 E_old_pw_hash(new_nt_hash, nt_pw, verifier);
919 if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
920 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
921 TALLOC_FREE(sampass);
922 return NT_STATUS_WRONG_PASSWORD;
925 /* We could check the LM password here, but there is
926 * little point, we already know the password is
927 * correct, and the LM password might not even be
930 /* Further, LM hash generation algorithms
931 * differ with charset, so we could
932 * incorrectly fail a perfectly valid password
934 #ifdef DEBUG_PASSWORD
936 ("check_oem_password: password %s ok\n", *pp_new_passwd));
944 * check the lm verifier
946 E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
947 if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
948 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
949 TALLOC_FREE(sampass);
950 return NT_STATUS_WRONG_PASSWORD;
952 #ifdef DEBUG_PASSWORD
954 ("check_oem_password: password %s ok\n", *pp_new_passwd));
961 if (lanman_pw && lm_pass_set) {
963 E_deshash(*pp_new_passwd, new_lm_hash);
966 * check the lm verifier
968 E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
969 if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
970 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
971 TALLOC_FREE(sampass);
972 return NT_STATUS_WRONG_PASSWORD;
975 #ifdef DEBUG_PASSWORD
977 ("check_oem_password: password %s ok\n", *pp_new_passwd));
983 /* should not be reached */
984 TALLOC_FREE(sampass);
985 return NT_STATUS_WRONG_PASSWORD;
988 /***********************************************************
989 This routine takes the given password and checks it against
990 the password history. Returns True if this password has been
991 found in the history list.
992 ************************************************************/
994 static bool check_passwd_history(struct samu *sampass, const char *plaintext)
996 uchar new_nt_p16[NT_HASH_LEN];
997 uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN];
999 const uint8 *pwhistory;
1002 uint32 pwHisLen, curr_pwHisLen;
1004 pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
1005 if (pwHisLen == 0) {
1009 pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
1010 if (!pwhistory || curr_pwHisLen == 0) {
1014 /* Only examine the minimum of the current history len and
1015 the stored history len. Avoids race conditions. */
1016 pwHisLen = MIN(pwHisLen,curr_pwHisLen);
1018 nt_pw = pdb_get_nt_passwd(sampass);
1020 E_md4hash(plaintext, new_nt_p16);
1022 if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) {
1023 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1024 pdb_get_username(sampass) ));
1028 dump_data(100, new_nt_p16, NT_HASH_LEN);
1029 dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen);
1031 memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN);
1032 for (i=0; i<pwHisLen; i++) {
1033 uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
1034 const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
1035 const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+
1036 PW_HISTORY_SALT_LEN];
1037 if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1038 /* Ignore zero valued entries. */
1041 /* Create salted versions of new to compare. */
1042 E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash);
1044 if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1045 DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n",
1046 pdb_get_username(sampass) ));
1054 /***********************************************************
1055 Code to change the oem password. Changes both the lanman
1056 and NT hashes. Old_passwd is almost always NULL.
1057 NOTE this function is designed to be called as root. Check the old password
1058 is correct before calling. JRA.
1059 ************************************************************/
1061 NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
1065 struct passwd *pass = NULL;
1066 const char *username = pdb_get_username(hnd);
1067 time_t can_change_time = pdb_get_pass_can_change_time(hnd);
1069 if (samr_reject_reason) {
1070 *samr_reject_reason = Undefined;
1073 /* check to see if the secdesc has previously been set to disallow */
1074 if (!pdb_get_pass_can_change(hnd)) {
1075 DEBUG(1, ("user %s does not have permissions to change password\n", username));
1076 if (samr_reject_reason) {
1077 *samr_reject_reason = REJECT_REASON_OTHER;
1079 return NT_STATUS_ACCOUNT_RESTRICTION;
1082 /* check to see if it is a Machine account and if the policy
1083 * denies machines to change the password. *
1084 * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1085 if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
1086 if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
1087 DEBUG(1, ("Machine %s cannot change password now, "
1088 "denied by Refuse Machine Password Change policy\n",
1090 if (samr_reject_reason) {
1091 *samr_reject_reason = REJECT_REASON_OTHER;
1093 return NT_STATUS_ACCOUNT_RESTRICTION;
1097 /* removed calculation here, becuase passdb now calculates
1098 based on policy. jmcd */
1099 if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
1100 DEBUG(1, ("user %s cannot change password now, must "
1101 "wait until %s\n", username,
1102 http_timestring(can_change_time)));
1103 if (samr_reject_reason) {
1104 *samr_reject_reason = REJECT_REASON_OTHER;
1106 return NT_STATUS_ACCOUNT_RESTRICTION;
1109 if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
1110 DEBUG(1, ("user %s cannot change password - password too short\n",
1112 DEBUGADD(1, (" account policy min password len = %d\n", min_len));
1113 if (samr_reject_reason) {
1114 *samr_reject_reason = REJECT_REASON_TOO_SHORT;
1116 return NT_STATUS_PASSWORD_RESTRICTION;
1117 /* return NT_STATUS_PWD_TOO_SHORT; */
1120 if (check_passwd_history(hnd,new_passwd)) {
1121 if (samr_reject_reason) {
1122 *samr_reject_reason = REJECT_REASON_IN_HISTORY;
1124 return NT_STATUS_PASSWORD_RESTRICTION;
1127 pass = Get_Pwnam(username);
1129 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
1130 return NT_STATUS_ACCESS_DENIED;
1133 /* Use external script to check password complexity */
1134 if (lp_check_password_script() && *(lp_check_password_script())) {
1137 check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
1138 DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
1140 if (check_ret != 0) {
1141 DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
1142 if (samr_reject_reason) {
1143 *samr_reject_reason = REJECT_REASON_NOT_COMPLEX;
1145 return NT_STATUS_PASSWORD_RESTRICTION;
1150 * If unix password sync was requested, attempt to change
1151 * the /etc/passwd database first. Return failure if this cannot
1154 * This occurs before the oem change, because we don't want to
1155 * update it if chgpasswd failed.
1157 * Conditional on lp_unix_password_sync() because we don't want
1158 * to touch the unix db unless we have admin permission.
1161 if(lp_unix_password_sync() &&
1162 !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
1163 return NT_STATUS_ACCESS_DENIED;
1166 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
1167 return NT_STATUS_ACCESS_DENIED;
1170 /* Now write it into the file. */
1171 return pdb_update_sam_account (hnd);