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
49 #include "../libcli/auth/libcli_auth.h"
51 static NTSTATUS
check_oem_password(const char *user
,
52 uchar password_encrypted_with_lm_hash
[516],
53 const uchar old_lm_hash_encrypted
[16],
54 uchar password_encrypted_with_nt_hash
[516],
55 const uchar old_nt_hash_encrypted
[16],
57 char **pp_new_passwd
);
59 #if ALLOW_CHANGE_PASSWORD
61 static int findpty(char **slave
)
65 SMB_STRUCT_DIR
*dirp
= NULL
;
70 #if defined(HAVE_GRANTPT)
71 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
72 if ((master
= sys_open("/dev/ptmx", O_RDWR
, 0)) >= 0) {
75 line
= (char *)ptsname(master
);
77 *slave
= SMB_STRDUP(line
);
82 ("findpty: Unable to create master/slave pty pair.\n"));
83 /* Stop fd leak on error. */
88 ("findpty: Allocated slave pty %s\n", *slave
));
92 #endif /* HAVE_GRANTPT */
94 line
= SMB_STRDUP("/dev/ptyXX");
99 dirp
= sys_opendir("/dev");
105 while ((dpname
= readdirname(dirp
)) != NULL
) {
106 if (strncmp(dpname
, "pty", 3) == 0 && strlen(dpname
) == 5) {
108 ("pty: try to open %s, line was %s\n", dpname
,
112 if ((master
= sys_open(line
, O_RDWR
, 0)) >= 0) {
113 DEBUG(3, ("pty: opened %s\n", line
));
126 static int dochild(int master
, const char *slavedev
, const struct passwd
*pass
,
127 const char *passwordprogram
, bool as_root
)
130 struct termios stermios
;
133 char * const eptrs
[1] = { NULL
};
138 ("dochild: user doesn't exist in the UNIX password database.\n"));
145 gain_root_privilege();
147 /* Start new session - gets rid of controlling terminal. */
151 ("Weirdness, couldn't let go of controlling terminal\n"));
155 /* Open slave pty and acquire as new controlling terminal. */
156 if ((slave
= sys_open(slavedev
, O_RDWR
, 0)) < 0)
158 DEBUG(3, ("More weirdness, could not open %s\n", slavedev
));
161 #if defined(TIOCSCTTY) && !defined(SUNOS5)
163 * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
164 * see the discussion under
165 * https://bugzilla.samba.org/show_bug.cgi?id=5366.
167 if (ioctl(slave
, TIOCSCTTY
, 0) < 0)
169 DEBUG(3, ("Error in ioctl call for slave pty\n"));
172 #elif defined(I_PUSH) && defined(I_FIND)
173 if (ioctl(slave
, I_FIND
, "ptem") == 0) {
174 ioctl(slave
, I_PUSH
, "ptem");
176 if (ioctl(slave
, I_FIND
, "ldterm") == 0) {
177 ioctl(slave
, I_PUSH
, "ldterm");
184 /* Make slave stdin/out/err of child. */
186 if (dup2(slave
, STDIN_FILENO
) != STDIN_FILENO
)
188 DEBUG(3, ("Could not re-direct stdin\n"));
191 if (dup2(slave
, STDOUT_FILENO
) != STDOUT_FILENO
)
193 DEBUG(3, ("Could not re-direct stdout\n"));
196 if (dup2(slave
, STDERR_FILENO
) != STDERR_FILENO
)
198 DEBUG(3, ("Could not re-direct stderr\n"));
204 /* Set proper terminal attributes - no echo, canonical input processing,
205 no map NL to CR/NL on output. */
207 if (tcgetattr(0, &stermios
) < 0)
210 ("could not read default terminal attributes on pty\n"));
213 stermios
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
);
214 stermios
.c_lflag
|= ICANON
;
216 stermios
.c_oflag
&= ~(ONLCR
);
218 if (tcsetattr(0, TCSANOW
, &stermios
) < 0)
220 DEBUG(3, ("could not set attributes of pty\n"));
224 /* make us completely into the right uid */
227 become_user_permanently(uid
, gid
);
231 ("Invoking '%s' as password change program.\n",
234 /* execl() password-change application */
235 if (execle("/bin/sh", "sh", "-c", passwordprogram
, NULL
, eptrs
) < 0)
237 DEBUG(3, ("Bad status returned from %s\n", passwordprogram
));
243 static int expect(int master
, char *issue
, char *expected
)
246 int attempts
, timeout
, nread
;
250 for (attempts
= 0; attempts
< 2; attempts
++) {
252 if (!strequal(issue
, ".")) {
253 if (lp_passwd_chat_debug())
254 DEBUG(100, ("expect: sending [%s]\n", issue
));
256 if ((len
= sys_write(master
, issue
, strlen(issue
))) != strlen(issue
)) {
257 DEBUG(2,("expect: (short) write returned %d\n",
263 if (strequal(expected
, "."))
266 /* Initial timeout. */
267 timeout
= lp_passwd_chat_timeout() * 1000;
272 status
= read_fd_with_timeout(
273 master
, buffer
+ nread
, 1,
274 sizeof(buffer
) - nread
- 1,
277 if (!NT_STATUS_IS_OK(status
)) {
284 /* Eat leading/trailing whitespace before match. */
285 char *str
= SMB_STRDUP(buffer
);
287 DEBUG(2,("expect: ENOMEM\n"));
290 trim_char(str
, ' ', ' ');
292 if ((match
= unix_wild_match(expected
, str
)) == True
) {
293 /* Now data has started to return, lower timeout. */
294 timeout
= lp_passwd_chat_timeout() * 100;
300 if (lp_passwd_chat_debug())
301 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
302 expected
, buffer
, match
? "yes" : "no" ));
307 if (!NT_STATUS_IS_OK(status
)) {
308 DEBUG(2, ("expect: %s\n", nt_errstr(status
)));
313 DEBUG(10,("expect: returning %s\n", match
? "True" : "False" ));
317 static void pwd_sub(char *buf
)
319 all_string_sub(buf
, "\\n", "\n", 0);
320 all_string_sub(buf
, "\\r", "\r", 0);
321 all_string_sub(buf
, "\\s", " ", 0);
322 all_string_sub(buf
, "\\t", "\t", 0);
325 static int talktochild(int master
, const char *seq
)
327 TALLOC_CTX
*frame
= talloc_stackframe();
332 issue
= talloc_strdup(frame
, ".");
338 while (next_token_talloc(frame
, &seq
, &expected
, NULL
)) {
342 if (!expect(master
, issue
, expected
)) {
343 DEBUG(3, ("Response %d incorrect\n", count
));
348 if (!next_token_talloc(frame
, &seq
, &issue
, NULL
)) {
349 issue
= talloc_strdup(frame
, ".");
358 if (!strequal(issue
, ".")) {
359 /* we have one final issue to send */
360 expected
= talloc_strdup(frame
, ".");
365 if (!expect(master
, issue
, expected
)) {
374 static bool chat_with_program(char *passwordprogram
, const struct passwd
*pass
,
375 char *chatsequence
, bool as_root
)
377 char *slavedev
= NULL
;
384 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
388 /* allocate a pseudo-terminal device */
389 if ((master
= findpty(&slavedev
)) < 0) {
390 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass
->pw_name
));
395 * We need to temporarily stop CatchChild from eating
396 * SIGCLD signals as it also eats the exit status code. JRA.
399 CatchChildLeaveStatus();
401 if ((pid
= sys_fork()) < 0) {
402 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass
->pw_name
));
409 /* we now have a pty */
410 if (pid
> 0) { /* This is the parent process */
411 /* Don't need this anymore in parent. */
414 if ((chstat
= talktochild(master
, chatsequence
)) == False
) {
415 DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass
->pw_name
));
416 kill(pid
, SIGKILL
); /* be sure to end this process */
419 while ((wpid
= sys_waitpid(pid
, &wstat
, 0)) < 0) {
420 if (errno
== EINTR
) {
428 DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
435 * Go back to ignoring children.
442 DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
445 if (WIFEXITED(wstat
) && (WEXITSTATUS(wstat
) != 0)) {
446 DEBUG(3, ("chat_with_program: The process exited with status %d \
447 while we were waiting\n", WEXITSTATUS(wstat
)));
450 #if defined(WIFSIGNALLED) && defined(WTERMSIG)
451 else if (WIFSIGNALLED(wstat
)) {
452 DEBUG(3, ("chat_with_program: The process was killed by signal %d \
453 while we were waiting\n", WTERMSIG(wstat
)));
461 * Lose any elevated privileges.
463 drop_effective_capability(KERNEL_OPLOCK_CAPABILITY
);
464 drop_effective_capability(DMAPI_ACCESS_CAPABILITY
);
466 /* make sure it doesn't freeze */
472 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass
->pw_name
,
473 (int)getuid(), (int)getgid(), BOOLSTR(as_root
) ));
474 chstat
= dochild(master
, slavedev
, pass
, passwordprogram
, as_root
);
480 * The child should never return from dochild() ....
483 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat
));
488 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
489 (chstat
? "" : "un"), pass
->pw_name
));
493 bool chgpasswd(const char *name
, const struct passwd
*pass
,
494 const char *oldpass
, const char *newpass
, bool as_root
)
496 char *passwordprogram
= NULL
;
497 char *chatsequence
= NULL
;
500 TALLOC_CTX
*ctx
= talloc_tos();
506 DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root
), name
));
508 #ifdef DEBUG_PASSWORD
509 DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass
, newpass
));
512 /* Take the passed information and test it for minimum criteria */
514 /* Password is same as old password */
515 if (strcmp(oldpass
, newpass
) == 0) {
516 /* don't allow same password */
517 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name
)); /* log the attempt */
518 return (False
); /* inform the user */
522 * Check the old and new passwords don't contain any control
526 len
= strlen(oldpass
);
527 for (i
= 0; i
< len
; i
++) {
528 if (iscntrl((int)oldpass
[i
])) {
529 DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
534 len
= strlen(newpass
);
535 for (i
= 0; i
< len
; i
++) {
536 if (iscntrl((int)newpass
[i
])) {
537 DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
543 if (lp_pam_password_change()) {
545 #ifdef HAVE_SETLOCALE
546 const char *prevlocale
= setlocale(LC_ALL
, "C");
553 ret
= smb_pam_passchange(pass
->pw_name
, oldpass
, newpass
);
555 ret
= smb_pam_passchange(name
, oldpass
, newpass
);
561 #ifdef HAVE_SETLOCALE
562 setlocale(LC_ALL
, prevlocale
);
569 /* A non-PAM password change just doen't make sense without a valid local user */
572 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name
));
576 passwordprogram
= talloc_strdup(ctx
, lp_passwd_program());
577 if (!passwordprogram
|| !*passwordprogram
) {
578 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
581 chatsequence
= talloc_strdup(ctx
, lp_passwd_chat());
582 if (!chatsequence
|| !*chatsequence
) {
583 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
588 /* The password program *must* contain the user name to work. Fail if not. */
589 if (strstr_m(passwordprogram
, "%u") == NULL
) {
590 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
591 the string %%u, and the given string %s does not.\n", passwordprogram
));
596 passwordprogram
= talloc_string_sub(ctx
, passwordprogram
, "%u", name
);
597 if (!passwordprogram
) {
601 /* note that we do NOT substitute the %o and %n in the password program
602 as this would open up a security hole where the user could use
603 a new password containing shell escape characters */
605 chatsequence
= talloc_string_sub(ctx
, chatsequence
, "%u", name
);
609 chatsequence
= talloc_all_string_sub(ctx
,
616 chatsequence
= talloc_all_string_sub(ctx
,
620 return chat_with_program(passwordprogram
,
626 #else /* ALLOW_CHANGE_PASSWORD */
628 bool chgpasswd(const char *name
, const struct passwd
*pass
,
629 const char *oldpass
, const char *newpass
, bool as_root
)
631 DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name
));
634 #endif /* ALLOW_CHANGE_PASSWORD */
636 /***********************************************************
637 Code to check the lanman hashed password.
638 ************************************************************/
640 bool check_lanman_password(char *user
, uchar
* pass1
,
641 uchar
* pass2
, struct samu
**hnd
)
643 uchar unenc_new_pw
[16];
644 uchar unenc_old_pw
[16];
645 struct samu
*sampass
= NULL
;
647 const uint8
*lanman_pw
;
650 if ( !(sampass
= samu_new(NULL
)) ) {
651 DEBUG(0, ("samu_new() failed!\n"));
656 ret
= pdb_getsampwnam(sampass
, user
);
660 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
661 TALLOC_FREE(sampass
);
665 acct_ctrl
= pdb_get_acct_ctrl (sampass
);
666 lanman_pw
= pdb_get_lanman_passwd (sampass
);
668 if (acct_ctrl
& ACB_DISABLED
) {
669 DEBUG(0,("check_lanman_password: account %s disabled.\n", user
));
670 TALLOC_FREE(sampass
);
674 if (lanman_pw
== NULL
) {
675 if (acct_ctrl
& ACB_PWNOTREQ
) {
676 /* this saves the pointer for the caller */
680 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
681 TALLOC_FREE(sampass
);
686 /* Get the new lanman hash. */
687 D_P16(lanman_pw
, pass2
, unenc_new_pw
);
689 /* Use this to get the old lanman hash. */
690 D_P16(unenc_new_pw
, pass1
, unenc_old_pw
);
692 /* Check that the two old passwords match. */
693 if (memcmp(lanman_pw
, unenc_old_pw
, 16)) {
694 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
695 TALLOC_FREE(sampass
);
699 /* this saves the pointer for the caller */
704 /***********************************************************
705 Code to change the lanman hashed password.
706 It nulls out the NT hashed password as it will
708 NOTE this function is designed to be called as root. Check the old password
709 is correct before calling. JRA.
710 ************************************************************/
712 bool change_lanman_password(struct samu
*sampass
, uchar
*pass2
)
715 uchar unenc_new_pw
[16];
720 if (sampass
== NULL
) {
721 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
725 acct_ctrl
= pdb_get_acct_ctrl(sampass
);
726 pwd
= pdb_get_lanman_passwd(sampass
);
728 if (acct_ctrl
& ACB_DISABLED
) {
729 DEBUG(0,("change_lanman_password: account %s disabled.\n",
730 pdb_get_username(sampass
)));
735 if (acct_ctrl
& ACB_PWNOTREQ
) {
740 E_P16(no_pw
, null_pw
);
744 DEBUG(0,("change_lanman_password: no lanman password !\n"));
749 /* Get the new lanman hash. */
750 D_P16(pwd
, pass2
, unenc_new_pw
);
752 if (!pdb_set_lanman_passwd(sampass
, unenc_new_pw
, PDB_CHANGED
)) {
756 if (!pdb_set_nt_passwd (sampass
, NULL
, PDB_CHANGED
)) {
757 return False
; /* We lose the NT hash. Sorry. */
760 if (!pdb_set_pass_last_set_time (sampass
, time(NULL
), PDB_CHANGED
)) {
761 TALLOC_FREE(sampass
);
762 /* Not quite sure what this one qualifies as, but this will do */
766 /* Now flush the sam_passwd struct to persistent storage */
767 ret
= NT_STATUS_IS_OK(pdb_update_sam_account (sampass
));
772 /***********************************************************
773 Code to check and change the OEM hashed password.
774 ************************************************************/
776 NTSTATUS
pass_oem_change(char *user
,
777 uchar password_encrypted_with_lm_hash
[516],
778 const uchar old_lm_hash_encrypted
[16],
779 uchar password_encrypted_with_nt_hash
[516],
780 const uchar old_nt_hash_encrypted
[16],
781 enum samPwdChangeReason
*reject_reason
)
783 char *new_passwd
= NULL
;
784 struct samu
*sampass
= NULL
;
788 if (!(sampass
= samu_new(NULL
))) {
789 return NT_STATUS_NO_MEMORY
;
793 ret
= pdb_getsampwnam(sampass
, user
);
797 DEBUG(0,("pass_oem_change: getsmbpwnam returned NULL\n"));
798 TALLOC_FREE(sampass
);
799 return NT_STATUS_NO_SUCH_USER
;
802 nt_status
= check_oem_password(user
,
803 password_encrypted_with_lm_hash
,
804 old_lm_hash_encrypted
,
805 password_encrypted_with_nt_hash
,
806 old_nt_hash_encrypted
,
810 if (!NT_STATUS_IS_OK(nt_status
)) {
811 TALLOC_FREE(sampass
);
815 /* We've already checked the old password here.... */
817 nt_status
= change_oem_password(sampass
, NULL
, new_passwd
, True
, reject_reason
);
820 memset(new_passwd
, 0, strlen(new_passwd
));
822 TALLOC_FREE(sampass
);
827 /***********************************************************
828 Decrypt and verify a user password change.
830 The 516 byte long buffers are encrypted with the old NT and
831 old LM passwords, and if the NT passwords are present, both
832 buffers contain a unicode string.
834 After decrypting the buffers, check the password is correct by
835 matching the old hashed passwords with the passwords in the passdb.
837 ************************************************************/
839 static NTSTATUS
check_oem_password(const char *user
,
840 uchar password_encrypted_with_lm_hash
[516],
841 const uchar old_lm_hash_encrypted
[16],
842 uchar password_encrypted_with_nt_hash
[516],
843 const uchar old_nt_hash_encrypted
[16],
844 struct samu
*sampass
,
845 char **pp_new_passwd
)
849 uint8
*password_encrypted
;
850 const uint8
*encryption_key
;
851 const uint8
*lanman_pw
, *nt_pw
;
854 uchar new_nt_hash
[16];
855 uchar new_lm_hash
[16];
859 bool nt_pass_set
= (password_encrypted_with_nt_hash
&& old_nt_hash_encrypted
);
860 bool lm_pass_set
= (password_encrypted_with_lm_hash
&& old_lm_hash_encrypted
);
862 acct_ctrl
= pdb_get_acct_ctrl(sampass
);
864 /* I am convinced this check here is wrong, it is valid to
865 * change a password of a user that has a disabled account - gd */
867 if (acct_ctrl
& ACB_DISABLED
) {
868 DEBUG(2,("check_lanman_password: account %s disabled.\n", user
));
869 return NT_STATUS_ACCOUNT_DISABLED
;
872 if ((acct_ctrl
& ACB_PWNOTREQ
) && lp_null_passwords()) {
873 /* construct a null password (in case one is needed */
876 nt_lm_owf_gen(no_pw
, null_ntpw
, null_pw
);
881 /* save pointers to passwords so we don't have to keep looking them up */
882 if (lp_lanman_auth()) {
883 lanman_pw
= pdb_get_lanman_passwd(sampass
);
887 nt_pw
= pdb_get_nt_passwd(sampass
);
890 if (nt_pw
&& nt_pass_set
) {
891 /* IDEAL Case: passwords are in unicode, and we can
892 * read use the password encrypted with the NT hash
894 password_encrypted
= password_encrypted_with_nt_hash
;
895 encryption_key
= nt_pw
;
896 } else if (lanman_pw
&& lm_pass_set
) {
897 /* password may still be in unicode, but use LM hash version */
898 password_encrypted
= password_encrypted_with_lm_hash
;
899 encryption_key
= lanman_pw
;
900 } else if (nt_pass_set
) {
901 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
903 return NT_STATUS_WRONG_PASSWORD
;
904 } else if (lm_pass_set
) {
905 if (lp_lanman_auth()) {
906 DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
909 DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
912 return NT_STATUS_WRONG_PASSWORD
;
914 DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
916 return NT_STATUS_WRONG_PASSWORD
;
920 * Decrypt the password with the key
922 arcfour_crypt( password_encrypted
, encryption_key
, 516);
924 if (!decode_pw_buffer(talloc_tos(),
928 nt_pass_set
? CH_UTF16
: CH_DOS
)) {
929 return NT_STATUS_WRONG_PASSWORD
;
933 * To ensure we got the correct new password, hash it and
934 * use it as a key to test the passed old password.
938 /* NT passwords, verify the NT hash. */
940 /* Calculate the MD4 hash (NT compatible) of the password */
941 memset(new_nt_hash
, '\0', 16);
942 E_md4hash(*pp_new_passwd
, new_nt_hash
);
946 * check the NT verifier
948 E_old_pw_hash(new_nt_hash
, nt_pw
, verifier
);
949 if (memcmp(verifier
, old_nt_hash_encrypted
, 16)) {
950 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
951 return NT_STATUS_WRONG_PASSWORD
;
954 /* We could check the LM password here, but there is
955 * little point, we already know the password is
956 * correct, and the LM password might not even be
959 /* Further, LM hash generation algorithms
960 * differ with charset, so we could
961 * incorrectly fail a perfectly valid password
963 #ifdef DEBUG_PASSWORD
965 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
972 * check the lm verifier
974 E_old_pw_hash(new_nt_hash
, lanman_pw
, verifier
);
975 if (memcmp(verifier
, old_lm_hash_encrypted
, 16)) {
976 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
977 return NT_STATUS_WRONG_PASSWORD
;
979 #ifdef DEBUG_PASSWORD
981 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
987 if (lanman_pw
&& lm_pass_set
) {
989 E_deshash(*pp_new_passwd
, new_lm_hash
);
992 * check the lm verifier
994 E_old_pw_hash(new_lm_hash
, lanman_pw
, verifier
);
995 if (memcmp(verifier
, old_lm_hash_encrypted
, 16)) {
996 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
997 return NT_STATUS_WRONG_PASSWORD
;
1000 #ifdef DEBUG_PASSWORD
1002 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
1004 return NT_STATUS_OK
;
1007 /* should not be reached */
1008 return NT_STATUS_WRONG_PASSWORD
;
1011 bool password_in_history(uint8_t nt_pw
[NT_HASH_LEN
],
1012 uint32_t pw_history_len
,
1013 const uint8_t *pw_history
)
1015 static const uint8_t zero_md5_nt_pw
[SALTED_MD5_HASH_LEN
] = { 0, };
1018 dump_data(100, nt_pw
, NT_HASH_LEN
);
1019 dump_data(100, pw_history
, PW_HISTORY_ENTRY_LEN
* pw_history_len
);
1021 for (i
=0; i
<pw_history_len
; i
++) {
1022 uint8_t new_nt_pw_salted_md5_hash
[SALTED_MD5_HASH_LEN
];
1023 const uint8_t *current_salt
;
1024 const uint8_t *old_nt_pw_salted_md5_hash
;
1026 current_salt
= &pw_history
[i
*PW_HISTORY_ENTRY_LEN
];
1027 old_nt_pw_salted_md5_hash
= current_salt
+ PW_HISTORY_SALT_LEN
;
1029 if (memcmp(zero_md5_nt_pw
, old_nt_pw_salted_md5_hash
,
1030 SALTED_MD5_HASH_LEN
) == 0) {
1031 /* Ignore zero valued entries. */
1035 if (memcmp(zero_md5_nt_pw
, current_salt
,
1036 PW_HISTORY_SALT_LEN
) == 0)
1039 * New format: zero salt and then plain nt hash.
1040 * Directly compare the hashes.
1042 if (memcmp(nt_pw
, old_nt_pw_salted_md5_hash
,
1043 SALTED_MD5_HASH_LEN
) == 0)
1049 * Old format: md5sum of salted nt hash.
1050 * Create salted version of new pw to compare.
1052 E_md5hash(current_salt
, nt_pw
, new_nt_pw_salted_md5_hash
);
1054 if (memcmp(new_nt_pw_salted_md5_hash
,
1055 old_nt_pw_salted_md5_hash
,
1056 SALTED_MD5_HASH_LEN
) == 0) {
1064 /***********************************************************
1065 This routine takes the given password and checks it against
1066 the password history. Returns True if this password has been
1067 found in the history list.
1068 ************************************************************/
1070 static bool check_passwd_history(struct samu
*sampass
, const char *plaintext
)
1072 uchar new_nt_p16
[NT_HASH_LEN
];
1074 const uint8
*pwhistory
;
1075 uint32 pwHisLen
, curr_pwHisLen
;
1077 pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY
, &pwHisLen
);
1078 if (pwHisLen
== 0) {
1082 pwhistory
= pdb_get_pw_history(sampass
, &curr_pwHisLen
);
1083 if (!pwhistory
|| curr_pwHisLen
== 0) {
1087 /* Only examine the minimum of the current history len and
1088 the stored history len. Avoids race conditions. */
1089 pwHisLen
= MIN(pwHisLen
,curr_pwHisLen
);
1091 nt_pw
= pdb_get_nt_passwd(sampass
);
1093 E_md4hash(plaintext
, new_nt_p16
);
1095 if (!memcmp(nt_pw
, new_nt_p16
, NT_HASH_LEN
)) {
1096 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1097 pdb_get_username(sampass
) ));
1101 if (password_in_history(new_nt_p16
, pwHisLen
, pwhistory
)) {
1102 DEBUG(1,("check_passwd_history: proposed new password for "
1103 "user %s found in history list !\n",
1104 pdb_get_username(sampass
) ));
1110 /***********************************************************
1111 ************************************************************/
1113 NTSTATUS
check_password_complexity(const char *username
,
1114 const char *password
,
1115 enum samPwdChangeReason
*samr_reject_reason
)
1117 TALLOC_CTX
*tosctx
= talloc_tos();
1119 /* Use external script to check password complexity */
1120 if (lp_check_password_script() && *(lp_check_password_script())) {
1124 cmd
= talloc_string_sub(tosctx
, lp_check_password_script(), "%u", username
);
1126 return NT_STATUS_PASSWORD_RESTRICTION
;
1129 check_ret
= smbrunsecret(cmd
, password
);
1130 DEBUG(5,("check_password_complexity: check password script (%s) returned [%d]\n",
1134 if (check_ret
!= 0) {
1135 DEBUG(1,("check_password_complexity: "
1136 "check password script said new password is not good enough!\n"));
1137 if (samr_reject_reason
) {
1138 *samr_reject_reason
= SAM_PWD_CHANGE_NOT_COMPLEX
;
1140 return NT_STATUS_PASSWORD_RESTRICTION
;
1144 return NT_STATUS_OK
;
1147 /***********************************************************
1148 Code to change the oem password. Changes both the lanman
1149 and NT hashes. Old_passwd is almost always NULL.
1150 NOTE this function is designed to be called as root. Check the old password
1151 is correct before calling. JRA.
1152 ************************************************************/
1154 NTSTATUS
change_oem_password(struct samu
*hnd
, char *old_passwd
, char *new_passwd
, bool as_root
, enum samPwdChangeReason
*samr_reject_reason
)
1158 TALLOC_CTX
*tosctx
= talloc_tos();
1159 struct passwd
*pass
= NULL
;
1160 const char *username
= pdb_get_username(hnd
);
1161 time_t can_change_time
= pdb_get_pass_can_change_time(hnd
);
1164 if (samr_reject_reason
) {
1165 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1168 /* check to see if the secdesc has previously been set to disallow */
1169 if (!pdb_get_pass_can_change(hnd
)) {
1170 DEBUG(1, ("user %s does not have permissions to change password\n", username
));
1171 if (samr_reject_reason
) {
1172 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1174 return NT_STATUS_ACCOUNT_RESTRICTION
;
1177 /* check to see if it is a Machine account and if the policy
1178 * denies machines to change the password. *
1179 * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1180 if (pdb_get_acct_ctrl(hnd
) & ACB_WSTRUST
) {
1181 if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE
, &refuse
) && refuse
) {
1182 DEBUG(1, ("Machine %s cannot change password now, "
1183 "denied by Refuse Machine Password Change policy\n",
1185 if (samr_reject_reason
) {
1186 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1188 return NT_STATUS_ACCOUNT_RESTRICTION
;
1192 /* removed calculation here, because passdb now calculates
1193 based on policy. jmcd */
1194 if ((can_change_time
!= 0) && (time(NULL
) < can_change_time
)) {
1195 DEBUG(1, ("user %s cannot change password now, must "
1196 "wait until %s\n", username
,
1197 http_timestring(tosctx
, can_change_time
)));
1198 if (samr_reject_reason
) {
1199 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1201 return NT_STATUS_ACCOUNT_RESTRICTION
;
1204 if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN
, &min_len
) && (str_charnum(new_passwd
) < min_len
)) {
1205 DEBUG(1, ("user %s cannot change password - password too short\n",
1207 DEBUGADD(1, (" account policy min password len = %d\n", min_len
));
1208 if (samr_reject_reason
) {
1209 *samr_reject_reason
= SAM_PWD_CHANGE_PASSWORD_TOO_SHORT
;
1211 return NT_STATUS_PASSWORD_RESTRICTION
;
1212 /* return NT_STATUS_PWD_TOO_SHORT; */
1215 if (check_passwd_history(hnd
,new_passwd
)) {
1216 if (samr_reject_reason
) {
1217 *samr_reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
1219 return NT_STATUS_PASSWORD_RESTRICTION
;
1222 pass
= Get_Pwnam_alloc(tosctx
, username
);
1224 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username
));
1225 return NT_STATUS_ACCESS_DENIED
;
1228 status
= check_password_complexity(username
, new_passwd
, samr_reject_reason
);
1229 if (!NT_STATUS_IS_OK(status
)) {
1235 * If unix password sync was requested, attempt to change
1236 * the /etc/passwd database first. Return failure if this cannot
1239 * This occurs before the oem change, because we don't want to
1240 * update it if chgpasswd failed.
1242 * Conditional on lp_unix_password_sync() because we don't want
1243 * to touch the unix db unless we have admin permission.
1246 if(lp_unix_password_sync() &&
1247 !chgpasswd(username
, pass
, old_passwd
, new_passwd
, as_root
)) {
1249 return NT_STATUS_ACCESS_DENIED
;
1254 if (!pdb_set_plaintext_passwd (hnd
, new_passwd
)) {
1255 return NT_STATUS_ACCESS_DENIED
;
1258 /* Now write it into the file. */
1259 return pdb_update_sam_account (hnd
);