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 static NTSTATUS
check_oem_password(const char *user
,
51 uchar password_encrypted_with_lm_hash
[516],
52 const uchar old_lm_hash_encrypted
[16],
53 uchar password_encrypted_with_nt_hash
[516],
54 const uchar old_nt_hash_encrypted
[16],
56 char **pp_new_passwd
);
58 #if ALLOW_CHANGE_PASSWORD
60 static int findpty(char **slave
)
64 SMB_STRUCT_DIR
*dirp
= NULL
;
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) {
74 line
= (char *)ptsname(master
);
76 *slave
= SMB_STRDUP(line
);
81 ("findpty: Unable to create master/slave pty pair.\n"));
82 /* Stop fd leak on error. */
87 ("findpty: Allocated slave pty %s\n", *slave
));
91 #endif /* HAVE_GRANTPT */
93 line
= SMB_STRDUP("/dev/ptyXX");
98 dirp
= sys_opendir("/dev");
104 while ((dpname
= readdirname(dirp
)) != NULL
) {
105 if (strncmp(dpname
, "pty", 3) == 0 && strlen(dpname
) == 5) {
107 ("pty: try to open %s, line was %s\n", dpname
,
111 if ((master
= sys_open(line
, O_RDWR
, 0)) >= 0) {
112 DEBUG(3, ("pty: opened %s\n", line
));
125 static int dochild(int master
, const char *slavedev
, const struct passwd
*pass
,
126 const char *passwordprogram
, bool as_root
)
129 struct termios stermios
;
132 char * const eptrs
[1] = { NULL
};
137 ("dochild: user doesn't exist in the UNIX password database.\n"));
144 gain_root_privilege();
146 /* Start new session - gets rid of controlling terminal. */
150 ("Weirdness, couldn't let go of controlling terminal\n"));
154 /* Open slave pty and acquire as new controlling terminal. */
155 if ((slave
= sys_open(slavedev
, O_RDWR
, 0)) < 0)
157 DEBUG(3, ("More weirdness, could not open %s\n", slavedev
));
160 #if defined(TIOCSCTTY) && !defined(SUNOS5)
162 * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
163 * see the discussion under
164 * https://bugzilla.samba.org/show_bug.cgi?id=5366.
166 if (ioctl(slave
, TIOCSCTTY
, 0) < 0)
168 DEBUG(3, ("Error in ioctl call for slave pty\n"));
171 #elif defined(I_PUSH) && defined(I_FIND)
172 if (ioctl(slave
, I_FIND
, "ptem") == 0) {
173 ioctl(slave
, I_PUSH
, "ptem");
175 if (ioctl(slave
, I_FIND
, "ldterm") == 0) {
176 ioctl(slave
, I_PUSH
, "ldterm");
183 /* Make slave stdin/out/err of child. */
185 if (dup2(slave
, STDIN_FILENO
) != STDIN_FILENO
)
187 DEBUG(3, ("Could not re-direct stdin\n"));
190 if (dup2(slave
, STDOUT_FILENO
) != STDOUT_FILENO
)
192 DEBUG(3, ("Could not re-direct stdout\n"));
195 if (dup2(slave
, STDERR_FILENO
) != STDERR_FILENO
)
197 DEBUG(3, ("Could not re-direct stderr\n"));
203 /* Set proper terminal attributes - no echo, canonical input processing,
204 no map NL to CR/NL on output. */
206 if (tcgetattr(0, &stermios
) < 0)
209 ("could not read default terminal attributes on pty\n"));
212 stermios
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
);
213 stermios
.c_lflag
|= ICANON
;
215 stermios
.c_oflag
&= ~(ONLCR
);
217 if (tcsetattr(0, TCSANOW
, &stermios
) < 0)
219 DEBUG(3, ("could not set attributes of pty\n"));
223 /* make us completely into the right uid */
226 become_user_permanently(uid
, gid
);
230 ("Invoking '%s' as password change program.\n",
233 /* execl() password-change application */
234 if (execle("/bin/sh", "sh", "-c", passwordprogram
, NULL
, eptrs
) < 0)
236 DEBUG(3, ("Bad status returned from %s\n", passwordprogram
));
242 static int expect(int master
, char *issue
, char *expected
)
245 int attempts
, timeout
, nread
;
249 for (attempts
= 0; attempts
< 2; attempts
++) {
251 if (!strequal(issue
, ".")) {
252 if (lp_passwd_chat_debug())
253 DEBUG(100, ("expect: sending [%s]\n", issue
));
255 if ((len
= sys_write(master
, issue
, strlen(issue
))) != strlen(issue
)) {
256 DEBUG(2,("expect: (short) write returned %d\n",
262 if (strequal(expected
, "."))
265 /* Initial timeout. */
266 timeout
= lp_passwd_chat_timeout() * 1000;
271 status
= read_fd_with_timeout(
272 master
, buffer
+ nread
, 1,
273 sizeof(buffer
) - nread
- 1,
276 if (!NT_STATUS_IS_OK(status
)) {
283 /* Eat leading/trailing whitespace before match. */
284 char *str
= SMB_STRDUP(buffer
);
286 DEBUG(2,("expect: ENOMEM\n"));
289 trim_char(str
, ' ', ' ');
291 if ((match
= unix_wild_match(expected
, str
)) == True
) {
292 /* Now data has started to return, lower timeout. */
293 timeout
= lp_passwd_chat_timeout() * 100;
299 if (lp_passwd_chat_debug())
300 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
301 expected
, buffer
, match
? "yes" : "no" ));
306 if (!NT_STATUS_IS_OK(status
)) {
307 DEBUG(2, ("expect: %s\n", nt_errstr(status
)));
312 DEBUG(10,("expect: returning %s\n", match
? "True" : "False" ));
316 static void pwd_sub(char *buf
)
318 all_string_sub(buf
, "\\n", "\n", 0);
319 all_string_sub(buf
, "\\r", "\r", 0);
320 all_string_sub(buf
, "\\s", " ", 0);
321 all_string_sub(buf
, "\\t", "\t", 0);
324 static int talktochild(int master
, const char *seq
)
326 TALLOC_CTX
*frame
= talloc_stackframe();
331 issue
= talloc_strdup(frame
, ".");
337 while (next_token_talloc(frame
, &seq
, &expected
, NULL
)) {
341 if (!expect(master
, issue
, expected
)) {
342 DEBUG(3, ("Response %d incorrect\n", count
));
347 if (!next_token_talloc(frame
, &seq
, &issue
, NULL
)) {
348 issue
= talloc_strdup(frame
, ".");
357 if (!strequal(issue
, ".")) {
358 /* we have one final issue to send */
359 expected
= talloc_strdup(frame
, ".");
364 if (!expect(master
, issue
, expected
)) {
373 static bool chat_with_program(char *passwordprogram
, const struct passwd
*pass
,
374 char *chatsequence
, bool as_root
)
376 char *slavedev
= NULL
;
383 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
387 /* allocate a pseudo-terminal device */
388 if ((master
= findpty(&slavedev
)) < 0) {
389 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass
->pw_name
));
394 * We need to temporarily stop CatchChild from eating
395 * SIGCLD signals as it also eats the exit status code. JRA.
398 CatchChildLeaveStatus();
400 if ((pid
= sys_fork()) < 0) {
401 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass
->pw_name
));
408 /* we now have a pty */
409 if (pid
> 0) { /* This is the parent process */
410 /* Don't need this anymore in parent. */
413 if ((chstat
= talktochild(master
, chatsequence
)) == False
) {
414 DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass
->pw_name
));
415 kill(pid
, SIGKILL
); /* be sure to end this process */
418 while ((wpid
= sys_waitpid(pid
, &wstat
, 0)) < 0) {
419 if (errno
== EINTR
) {
427 DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
434 * Go back to ignoring children.
441 DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
444 if (WIFEXITED(wstat
) && (WEXITSTATUS(wstat
) != 0)) {
445 DEBUG(3, ("chat_with_program: The process exited with status %d \
446 while we were waiting\n", WEXITSTATUS(wstat
)));
449 #if defined(WIFSIGNALLED) && defined(WTERMSIG)
450 else if (WIFSIGNALLED(wstat
)) {
451 DEBUG(3, ("chat_with_program: The process was killed by signal %d \
452 while we were waiting\n", WTERMSIG(wstat
)));
460 * Lose any elevated privileges.
462 drop_effective_capability(KERNEL_OPLOCK_CAPABILITY
);
463 drop_effective_capability(DMAPI_ACCESS_CAPABILITY
);
465 /* make sure it doesn't freeze */
471 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass
->pw_name
,
472 (int)getuid(), (int)getgid(), BOOLSTR(as_root
) ));
473 chstat
= dochild(master
, slavedev
, pass
, passwordprogram
, as_root
);
479 * The child should never return from dochild() ....
482 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat
));
487 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
488 (chstat
? "" : "un"), pass
->pw_name
));
492 bool chgpasswd(const char *name
, const struct passwd
*pass
,
493 const char *oldpass
, const char *newpass
, bool as_root
)
495 char *passwordprogram
= NULL
;
496 char *chatsequence
= NULL
;
499 TALLOC_CTX
*ctx
= talloc_tos();
505 DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root
), name
));
507 #ifdef DEBUG_PASSWORD
508 DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass
, newpass
));
511 /* Take the passed information and test it for minimum criteria */
513 /* Password is same as old password */
514 if (strcmp(oldpass
, newpass
) == 0) {
515 /* don't allow same password */
516 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name
)); /* log the attempt */
517 return (False
); /* inform the user */
521 * Check the old and new passwords don't contain any control
525 len
= strlen(oldpass
);
526 for (i
= 0; i
< len
; i
++) {
527 if (iscntrl((int)oldpass
[i
])) {
528 DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
533 len
= strlen(newpass
);
534 for (i
= 0; i
< len
; i
++) {
535 if (iscntrl((int)newpass
[i
])) {
536 DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
542 if (lp_pam_password_change()) {
544 #ifdef HAVE_SETLOCALE
545 const char *prevlocale
= setlocale(LC_ALL
, "C");
552 ret
= smb_pam_passchange(pass
->pw_name
, oldpass
, newpass
);
554 ret
= smb_pam_passchange(name
, oldpass
, newpass
);
560 #ifdef HAVE_SETLOCALE
561 setlocale(LC_ALL
, prevlocale
);
568 /* A non-PAM password change just doen't make sense without a valid local user */
571 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name
));
575 passwordprogram
= talloc_strdup(ctx
, lp_passwd_program());
576 if (!passwordprogram
|| !*passwordprogram
) {
577 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
580 chatsequence
= talloc_strdup(ctx
, lp_passwd_chat());
581 if (!chatsequence
|| !*chatsequence
) {
582 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
587 /* The password program *must* contain the user name to work. Fail if not. */
588 if (strstr_m(passwordprogram
, "%u") == NULL
) {
589 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
590 the string %%u, and the given string %s does not.\n", passwordprogram
));
595 passwordprogram
= talloc_string_sub(ctx
, passwordprogram
, "%u", name
);
596 if (!passwordprogram
) {
600 /* note that we do NOT substitute the %o and %n in the password program
601 as this would open up a security hole where the user could use
602 a new password containing shell escape characters */
604 chatsequence
= talloc_string_sub(ctx
, chatsequence
, "%u", name
);
608 chatsequence
= talloc_all_string_sub(ctx
,
615 chatsequence
= talloc_all_string_sub(ctx
,
619 return chat_with_program(passwordprogram
,
625 #else /* ALLOW_CHANGE_PASSWORD */
627 bool chgpasswd(const char *name
, const struct passwd
*pass
,
628 const char *oldpass
, const char *newpass
, bool as_root
)
630 DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name
));
633 #endif /* ALLOW_CHANGE_PASSWORD */
635 /***********************************************************
636 Code to check the lanman hashed password.
637 ************************************************************/
639 bool check_lanman_password(char *user
, uchar
* pass1
,
640 uchar
* pass2
, struct samu
**hnd
)
642 uchar unenc_new_pw
[16];
643 uchar unenc_old_pw
[16];
644 struct samu
*sampass
= NULL
;
646 const uint8
*lanman_pw
;
649 if ( !(sampass
= samu_new(NULL
)) ) {
650 DEBUG(0, ("samu_new() failed!\n"));
655 ret
= pdb_getsampwnam(sampass
, user
);
659 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
660 TALLOC_FREE(sampass
);
664 acct_ctrl
= pdb_get_acct_ctrl (sampass
);
665 lanman_pw
= pdb_get_lanman_passwd (sampass
);
667 if (acct_ctrl
& ACB_DISABLED
) {
668 DEBUG(0,("check_lanman_password: account %s disabled.\n", user
));
669 TALLOC_FREE(sampass
);
673 if (lanman_pw
== NULL
) {
674 if (acct_ctrl
& ACB_PWNOTREQ
) {
675 /* this saves the pointer for the caller */
679 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
680 TALLOC_FREE(sampass
);
685 /* Get the new lanman hash. */
686 D_P16(lanman_pw
, pass2
, unenc_new_pw
);
688 /* Use this to get the old lanman hash. */
689 D_P16(unenc_new_pw
, pass1
, unenc_old_pw
);
691 /* Check that the two old passwords match. */
692 if (memcmp(lanman_pw
, unenc_old_pw
, 16)) {
693 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
694 TALLOC_FREE(sampass
);
698 /* this saves the pointer for the caller */
703 /***********************************************************
704 Code to change the lanman hashed password.
705 It nulls out the NT hashed password as it will
707 NOTE this function is designed to be called as root. Check the old password
708 is correct before calling. JRA.
709 ************************************************************/
711 bool change_lanman_password(struct samu
*sampass
, uchar
*pass2
)
714 uchar unenc_new_pw
[16];
719 if (sampass
== NULL
) {
720 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
724 acct_ctrl
= pdb_get_acct_ctrl(sampass
);
725 pwd
= pdb_get_lanman_passwd(sampass
);
727 if (acct_ctrl
& ACB_DISABLED
) {
728 DEBUG(0,("change_lanman_password: account %s disabled.\n",
729 pdb_get_username(sampass
)));
734 if (acct_ctrl
& ACB_PWNOTREQ
) {
739 E_P16(no_pw
, null_pw
);
743 DEBUG(0,("change_lanman_password: no lanman password !\n"));
748 /* Get the new lanman hash. */
749 D_P16(pwd
, pass2
, unenc_new_pw
);
751 if (!pdb_set_lanman_passwd(sampass
, unenc_new_pw
, PDB_CHANGED
)) {
755 if (!pdb_set_nt_passwd (sampass
, NULL
, PDB_CHANGED
)) {
756 return False
; /* We lose the NT hash. Sorry. */
759 if (!pdb_set_pass_last_set_time (sampass
, time(NULL
), PDB_CHANGED
)) {
760 TALLOC_FREE(sampass
);
761 /* Not quite sure what this one qualifies as, but this will do */
765 /* Now flush the sam_passwd struct to persistent storage */
766 ret
= NT_STATUS_IS_OK(pdb_update_sam_account (sampass
));
771 /***********************************************************
772 Code to check and change the OEM hashed password.
773 ************************************************************/
775 NTSTATUS
pass_oem_change(char *user
,
776 uchar password_encrypted_with_lm_hash
[516],
777 const uchar old_lm_hash_encrypted
[16],
778 uchar password_encrypted_with_nt_hash
[516],
779 const uchar old_nt_hash_encrypted
[16],
780 uint32
*reject_reason
)
782 char *new_passwd
= NULL
;
783 struct samu
*sampass
= NULL
;
787 if (!(sampass
= samu_new(NULL
))) {
788 return NT_STATUS_NO_MEMORY
;
792 ret
= pdb_getsampwnam(sampass
, user
);
796 DEBUG(0,("pass_oem_change: getsmbpwnam returned NULL\n"));
797 TALLOC_FREE(sampass
);
798 return NT_STATUS_NO_SUCH_USER
;
801 nt_status
= check_oem_password(user
,
802 password_encrypted_with_lm_hash
,
803 old_lm_hash_encrypted
,
804 password_encrypted_with_nt_hash
,
805 old_nt_hash_encrypted
,
809 if (!NT_STATUS_IS_OK(nt_status
)) {
810 TALLOC_FREE(sampass
);
814 /* We've already checked the old password here.... */
816 nt_status
= change_oem_password(sampass
, NULL
, new_passwd
, True
, reject_reason
);
819 memset(new_passwd
, 0, strlen(new_passwd
));
821 TALLOC_FREE(sampass
);
826 /***********************************************************
827 Decrypt and verify a user password change.
829 The 516 byte long buffers are encrypted with the old NT and
830 old LM passwords, and if the NT passwords are present, both
831 buffers contain a unicode string.
833 After decrypting the buffers, check the password is correct by
834 matching the old hashed passwords with the passwords in the passdb.
836 ************************************************************/
838 static NTSTATUS
check_oem_password(const char *user
,
839 uchar password_encrypted_with_lm_hash
[516],
840 const uchar old_lm_hash_encrypted
[16],
841 uchar password_encrypted_with_nt_hash
[516],
842 const uchar old_nt_hash_encrypted
[16],
843 struct samu
*sampass
,
844 char **pp_new_passwd
)
848 uint8
*password_encrypted
;
849 const uint8
*encryption_key
;
850 const uint8
*lanman_pw
, *nt_pw
;
853 uchar new_nt_hash
[16];
854 uchar new_lm_hash
[16];
858 bool nt_pass_set
= (password_encrypted_with_nt_hash
&& old_nt_hash_encrypted
);
859 bool lm_pass_set
= (password_encrypted_with_lm_hash
&& old_lm_hash_encrypted
);
861 acct_ctrl
= pdb_get_acct_ctrl(sampass
);
863 /* I am convinced this check here is wrong, it is valid to
864 * change a password of a user that has a disabled account - gd */
866 if (acct_ctrl
& ACB_DISABLED
) {
867 DEBUG(2,("check_lanman_password: account %s disabled.\n", user
));
868 return NT_STATUS_ACCOUNT_DISABLED
;
871 if ((acct_ctrl
& ACB_PWNOTREQ
) && lp_null_passwords()) {
872 /* construct a null password (in case one is needed */
875 nt_lm_owf_gen(no_pw
, null_ntpw
, null_pw
);
880 /* save pointers to passwords so we don't have to keep looking them up */
881 if (lp_lanman_auth()) {
882 lanman_pw
= pdb_get_lanman_passwd(sampass
);
886 nt_pw
= pdb_get_nt_passwd(sampass
);
889 if (nt_pw
&& nt_pass_set
) {
890 /* IDEAL Case: passwords are in unicode, and we can
891 * read use the password encrypted with the NT hash
893 password_encrypted
= password_encrypted_with_nt_hash
;
894 encryption_key
= nt_pw
;
895 } else if (lanman_pw
&& lm_pass_set
) {
896 /* password may still be in unicode, but use LM hash version */
897 password_encrypted
= password_encrypted_with_lm_hash
;
898 encryption_key
= lanman_pw
;
899 } else if (nt_pass_set
) {
900 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
902 return NT_STATUS_WRONG_PASSWORD
;
903 } else if (lm_pass_set
) {
904 if (lp_lanman_auth()) {
905 DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
908 DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
911 return NT_STATUS_WRONG_PASSWORD
;
913 DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
915 return NT_STATUS_WRONG_PASSWORD
;
919 * Decrypt the password with the key
921 SamOEMhash( password_encrypted
, encryption_key
, 516);
923 if (!decode_pw_buffer(talloc_tos(),
927 nt_pass_set
? STR_UNICODE
: STR_ASCII
)) {
928 return NT_STATUS_WRONG_PASSWORD
;
932 * To ensure we got the correct new password, hash it and
933 * use it as a key to test the passed old password.
937 /* NT passwords, verify the NT hash. */
939 /* Calculate the MD4 hash (NT compatible) of the password */
940 memset(new_nt_hash
, '\0', 16);
941 E_md4hash(*pp_new_passwd
, new_nt_hash
);
945 * check the NT verifier
947 E_old_pw_hash(new_nt_hash
, nt_pw
, verifier
);
948 if (memcmp(verifier
, old_nt_hash_encrypted
, 16)) {
949 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
950 return NT_STATUS_WRONG_PASSWORD
;
953 /* We could check the LM password here, but there is
954 * little point, we already know the password is
955 * correct, and the LM password might not even be
958 /* Further, LM hash generation algorithms
959 * differ with charset, so we could
960 * incorrectly fail a perfectly valid password
962 #ifdef DEBUG_PASSWORD
964 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
971 * check the lm verifier
973 E_old_pw_hash(new_nt_hash
, lanman_pw
, verifier
);
974 if (memcmp(verifier
, old_lm_hash_encrypted
, 16)) {
975 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
976 return NT_STATUS_WRONG_PASSWORD
;
978 #ifdef DEBUG_PASSWORD
980 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
986 if (lanman_pw
&& lm_pass_set
) {
988 E_deshash(*pp_new_passwd
, new_lm_hash
);
991 * check the lm verifier
993 E_old_pw_hash(new_lm_hash
, lanman_pw
, verifier
);
994 if (memcmp(verifier
, old_lm_hash_encrypted
, 16)) {
995 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
996 return NT_STATUS_WRONG_PASSWORD
;
999 #ifdef DEBUG_PASSWORD
1001 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
1003 return NT_STATUS_OK
;
1006 /* should not be reached */
1007 return NT_STATUS_WRONG_PASSWORD
;
1010 /***********************************************************
1011 This routine takes the given password and checks it against
1012 the password history. Returns True if this password has been
1013 found in the history list.
1014 ************************************************************/
1016 static bool check_passwd_history(struct samu
*sampass
, const char *plaintext
)
1018 uchar new_nt_p16
[NT_HASH_LEN
];
1019 uchar zero_md5_nt_pw
[SALTED_MD5_HASH_LEN
];
1021 const uint8
*pwhistory
;
1024 uint32 pwHisLen
, curr_pwHisLen
;
1026 pdb_get_account_policy(AP_PASSWORD_HISTORY
, &pwHisLen
);
1027 if (pwHisLen
== 0) {
1031 pwhistory
= pdb_get_pw_history(sampass
, &curr_pwHisLen
);
1032 if (!pwhistory
|| curr_pwHisLen
== 0) {
1036 /* Only examine the minimum of the current history len and
1037 the stored history len. Avoids race conditions. */
1038 pwHisLen
= MIN(pwHisLen
,curr_pwHisLen
);
1040 nt_pw
= pdb_get_nt_passwd(sampass
);
1042 E_md4hash(plaintext
, new_nt_p16
);
1044 if (!memcmp(nt_pw
, new_nt_p16
, NT_HASH_LEN
)) {
1045 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1046 pdb_get_username(sampass
) ));
1050 dump_data(100, new_nt_p16
, NT_HASH_LEN
);
1051 dump_data(100, pwhistory
, PW_HISTORY_ENTRY_LEN
*pwHisLen
);
1053 memset(zero_md5_nt_pw
, '\0', SALTED_MD5_HASH_LEN
);
1054 for (i
=0; i
<pwHisLen
; i
++) {
1055 uchar new_nt_pw_salted_md5_hash
[SALTED_MD5_HASH_LEN
];
1056 const uchar
*current_salt
= &pwhistory
[i
*PW_HISTORY_ENTRY_LEN
];
1057 const uchar
*old_nt_pw_salted_md5_hash
= &pwhistory
[(i
*PW_HISTORY_ENTRY_LEN
)+
1058 PW_HISTORY_SALT_LEN
];
1059 if (!memcmp(zero_md5_nt_pw
, old_nt_pw_salted_md5_hash
, SALTED_MD5_HASH_LEN
)) {
1060 /* Ignore zero valued entries. */
1063 /* Create salted versions of new to compare. */
1064 E_md5hash(current_salt
, new_nt_p16
, new_nt_pw_salted_md5_hash
);
1066 if (!memcmp(new_nt_pw_salted_md5_hash
, old_nt_pw_salted_md5_hash
, SALTED_MD5_HASH_LEN
)) {
1067 DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n",
1068 pdb_get_username(sampass
) ));
1076 /***********************************************************
1077 Code to change the oem password. Changes both the lanman
1078 and NT hashes. Old_passwd is almost always NULL.
1079 NOTE this function is designed to be called as root. Check the old password
1080 is correct before calling. JRA.
1081 ************************************************************/
1083 NTSTATUS
change_oem_password(struct samu
*hnd
, char *old_passwd
, char *new_passwd
, bool as_root
, uint32
*samr_reject_reason
)
1087 struct passwd
*pass
= NULL
;
1088 const char *username
= pdb_get_username(hnd
);
1089 time_t can_change_time
= pdb_get_pass_can_change_time(hnd
);
1091 if (samr_reject_reason
) {
1092 *samr_reject_reason
= Undefined
;
1095 /* check to see if the secdesc has previously been set to disallow */
1096 if (!pdb_get_pass_can_change(hnd
)) {
1097 DEBUG(1, ("user %s does not have permissions to change password\n", username
));
1098 if (samr_reject_reason
) {
1099 *samr_reject_reason
= SAMR_REJECT_OTHER
;
1101 return NT_STATUS_ACCOUNT_RESTRICTION
;
1104 /* check to see if it is a Machine account and if the policy
1105 * denies machines to change the password. *
1106 * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1107 if (pdb_get_acct_ctrl(hnd
) & ACB_WSTRUST
) {
1108 if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE
, &refuse
) && refuse
) {
1109 DEBUG(1, ("Machine %s cannot change password now, "
1110 "denied by Refuse Machine Password Change policy\n",
1112 if (samr_reject_reason
) {
1113 *samr_reject_reason
= SAMR_REJECT_OTHER
;
1115 return NT_STATUS_ACCOUNT_RESTRICTION
;
1119 /* removed calculation here, becuase passdb now calculates
1120 based on policy. jmcd */
1121 if ((can_change_time
!= 0) && (time(NULL
) < can_change_time
)) {
1122 DEBUG(1, ("user %s cannot change password now, must "
1123 "wait until %s\n", username
,
1124 http_timestring(talloc_tos(), can_change_time
)));
1125 if (samr_reject_reason
) {
1126 *samr_reject_reason
= SAMR_REJECT_OTHER
;
1128 return NT_STATUS_ACCOUNT_RESTRICTION
;
1131 if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN
, &min_len
) && (str_charnum(new_passwd
) < min_len
)) {
1132 DEBUG(1, ("user %s cannot change password - password too short\n",
1134 DEBUGADD(1, (" account policy min password len = %d\n", min_len
));
1135 if (samr_reject_reason
) {
1136 *samr_reject_reason
= SAMR_REJECT_TOO_SHORT
;
1138 return NT_STATUS_PASSWORD_RESTRICTION
;
1139 /* return NT_STATUS_PWD_TOO_SHORT; */
1142 if (check_passwd_history(hnd
,new_passwd
)) {
1143 if (samr_reject_reason
) {
1144 *samr_reject_reason
= SAMR_REJECT_IN_HISTORY
;
1146 return NT_STATUS_PASSWORD_RESTRICTION
;
1149 pass
= Get_Pwnam_alloc(talloc_tos(), username
);
1151 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username
));
1152 return NT_STATUS_ACCESS_DENIED
;
1155 /* Use external script to check password complexity */
1156 if (lp_check_password_script() && *(lp_check_password_script())) {
1159 check_ret
= smbrunsecret(lp_check_password_script(), new_passwd
);
1160 DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret
));
1162 if (check_ret
!= 0) {
1163 DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
1164 if (samr_reject_reason
) {
1165 *samr_reject_reason
= SAMR_REJECT_COMPLEXITY
;
1168 return NT_STATUS_PASSWORD_RESTRICTION
;
1173 * If unix password sync was requested, attempt to change
1174 * the /etc/passwd database first. Return failure if this cannot
1177 * This occurs before the oem change, because we don't want to
1178 * update it if chgpasswd failed.
1180 * Conditional on lp_unix_password_sync() because we don't want
1181 * to touch the unix db unless we have admin permission.
1184 if(lp_unix_password_sync() &&
1185 !chgpasswd(username
, pass
, old_passwd
, new_passwd
, as_root
)) {
1187 return NT_STATUS_ACCESS_DENIED
;
1192 if (!pdb_set_plaintext_passwd (hnd
, new_passwd
)) {
1193 return NT_STATUS_ACCESS_DENIED
;
1196 /* Now write it into the file. */
1197 return pdb_update_sam_account (hnd
);