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 "system/terminal.h"
50 #include "system/passwd.h"
51 #include "system/filesys.h"
52 #include "../libcli/auth/libcli_auth.h"
53 #include "../lib/crypto/arcfour.h"
54 #include "rpc_server/samr/srv_samr_util.h"
58 #ifndef ALLOW_CHANGE_PASSWORD
59 #if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID))
60 #define ALLOW_CHANGE_PASSWORD 1
64 #if ALLOW_CHANGE_PASSWORD
66 static int findpty(char **slave
)
70 SMB_STRUCT_DIR
*dirp
= NULL
;
75 #if defined(HAVE_GRANTPT)
76 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
77 if ((master
= sys_open("/dev/ptmx", O_RDWR
, 0)) >= 0) {
80 line
= (char *)ptsname(master
);
82 *slave
= SMB_STRDUP(line
);
87 ("findpty: Unable to create master/slave pty pair.\n"));
88 /* Stop fd leak on error. */
93 ("findpty: Allocated slave pty %s\n", *slave
));
97 #endif /* HAVE_GRANTPT */
99 line
= SMB_STRDUP("/dev/ptyXX");
104 dirp
= sys_opendir("/dev");
110 while ((dpname
= readdirname(dirp
)) != NULL
) {
111 if (strncmp(dpname
, "pty", 3) == 0 && strlen(dpname
) == 5) {
113 ("pty: try to open %s, line was %s\n", dpname
,
117 if ((master
= sys_open(line
, O_RDWR
, 0)) >= 0) {
118 DEBUG(3, ("pty: opened %s\n", line
));
131 static int dochild(int master
, const char *slavedev
, const struct passwd
*pass
,
132 const char *passwordprogram
, bool as_root
)
135 struct termios stermios
;
138 char * const eptrs
[1] = { NULL
};
143 ("dochild: user doesn't exist in the UNIX password database.\n"));
150 gain_root_privilege();
152 /* Start new session - gets rid of controlling terminal. */
156 ("Weirdness, couldn't let go of controlling terminal\n"));
160 /* Open slave pty and acquire as new controlling terminal. */
161 if ((slave
= sys_open(slavedev
, O_RDWR
, 0)) < 0)
163 DEBUG(3, ("More weirdness, could not open %s\n", slavedev
));
166 #if defined(TIOCSCTTY) && !defined(SUNOS5)
168 * On patched Solaris 10 TIOCSCTTY is defined but seems not to work,
169 * see the discussion under
170 * https://bugzilla.samba.org/show_bug.cgi?id=5366.
172 if (ioctl(slave
, TIOCSCTTY
, 0) < 0)
174 DEBUG(3, ("Error in ioctl call for slave pty\n"));
177 #elif defined(I_PUSH) && defined(I_FIND)
178 if (ioctl(slave
, I_FIND
, "ptem") == 0) {
179 ioctl(slave
, I_PUSH
, "ptem");
181 if (ioctl(slave
, I_FIND
, "ldterm") == 0) {
182 ioctl(slave
, I_PUSH
, "ldterm");
189 /* Make slave stdin/out/err of child. */
191 if (dup2(slave
, STDIN_FILENO
) != STDIN_FILENO
)
193 DEBUG(3, ("Could not re-direct stdin\n"));
196 if (dup2(slave
, STDOUT_FILENO
) != STDOUT_FILENO
)
198 DEBUG(3, ("Could not re-direct stdout\n"));
201 if (dup2(slave
, STDERR_FILENO
) != STDERR_FILENO
)
203 DEBUG(3, ("Could not re-direct stderr\n"));
209 /* Set proper terminal attributes - no echo, canonical input processing,
210 no map NL to CR/NL on output. */
212 if (tcgetattr(0, &stermios
) < 0)
215 ("could not read default terminal attributes on pty\n"));
218 stermios
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
);
219 stermios
.c_lflag
|= ICANON
;
221 stermios
.c_oflag
&= ~(ONLCR
);
223 if (tcsetattr(0, TCSANOW
, &stermios
) < 0)
225 DEBUG(3, ("could not set attributes of pty\n"));
229 /* make us completely into the right uid */
232 become_user_permanently(uid
, gid
);
236 ("Invoking '%s' as password change program.\n",
239 /* execl() password-change application */
240 if (execle("/bin/sh", "sh", "-c", passwordprogram
, NULL
, eptrs
) < 0)
242 DEBUG(3, ("Bad status returned from %s\n", passwordprogram
));
248 static int expect(int master
, char *issue
, char *expected
)
251 int attempts
, timeout
, nread
;
255 for (attempts
= 0; attempts
< 2; attempts
++) {
257 if (!strequal(issue
, ".")) {
258 if (lp_passwd_chat_debug())
259 DEBUG(100, ("expect: sending [%s]\n", issue
));
261 if ((len
= sys_write(master
, issue
, strlen(issue
))) != strlen(issue
)) {
262 DEBUG(2,("expect: (short) write returned %d\n",
268 if (strequal(expected
, "."))
271 /* Initial timeout. */
272 timeout
= lp_passwd_chat_timeout() * 1000;
277 status
= read_fd_with_timeout(
278 master
, buffer
+ nread
, 1,
279 sizeof(buffer
) - nread
- 1,
282 if (!NT_STATUS_IS_OK(status
)) {
283 DEBUG(2, ("expect: read error %s\n",
291 /* Eat leading/trailing whitespace before match. */
292 char *str
= SMB_STRDUP(buffer
);
294 DEBUG(2,("expect: ENOMEM\n"));
297 trim_char(str
, ' ', ' ');
299 if ((match
= unix_wild_match(expected
, str
)) == True
) {
300 /* Now data has started to return, lower timeout. */
301 timeout
= lp_passwd_chat_timeout() * 100;
307 if (lp_passwd_chat_debug())
308 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
309 expected
, buffer
, match
? "yes" : "no" ));
314 if (!NT_STATUS_IS_OK(status
)) {
315 DEBUG(2, ("expect: %s\n", nt_errstr(status
)));
320 DEBUG(10,("expect: returning %s\n", match
? "True" : "False" ));
324 static void pwd_sub(char *buf
)
326 all_string_sub(buf
, "\\n", "\n", 0);
327 all_string_sub(buf
, "\\r", "\r", 0);
328 all_string_sub(buf
, "\\s", " ", 0);
329 all_string_sub(buf
, "\\t", "\t", 0);
332 static int talktochild(int master
, const char *seq
)
334 TALLOC_CTX
*frame
= talloc_stackframe();
339 issue
= talloc_strdup(frame
, ".");
345 while (next_token_talloc(frame
, &seq
, &expected
, NULL
)) {
349 if (!expect(master
, issue
, expected
)) {
350 DEBUG(3, ("Response %d incorrect\n", count
));
355 if (!next_token_talloc(frame
, &seq
, &issue
, NULL
)) {
356 issue
= talloc_strdup(frame
, ".");
365 if (!strequal(issue
, ".")) {
366 /* we have one final issue to send */
367 expected
= talloc_strdup(frame
, ".");
372 if (!expect(master
, issue
, expected
)) {
381 static bool chat_with_program(char *passwordprogram
, const struct passwd
*pass
,
382 char *chatsequence
, bool as_root
)
384 char *slavedev
= NULL
;
391 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
395 /* allocate a pseudo-terminal device */
396 if ((master
= findpty(&slavedev
)) < 0) {
397 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass
->pw_name
));
402 * We need to temporarily stop CatchChild from eating
403 * SIGCLD signals as it also eats the exit status code. JRA.
406 CatchChildLeaveStatus();
408 if ((pid
= sys_fork()) < 0) {
409 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass
->pw_name
));
416 /* we now have a pty */
417 if (pid
> 0) { /* This is the parent process */
418 /* Don't need this anymore in parent. */
421 if ((chstat
= talktochild(master
, chatsequence
)) == False
) {
422 DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass
->pw_name
));
423 kill(pid
, SIGKILL
); /* be sure to end this process */
426 while ((wpid
= sys_waitpid(pid
, &wstat
, 0)) < 0) {
427 if (errno
== EINTR
) {
435 DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
442 * Go back to ignoring children.
449 DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
452 if (WIFEXITED(wstat
) && (WEXITSTATUS(wstat
) != 0)) {
453 DEBUG(3, ("chat_with_program: The process exited with status %d \
454 while we were waiting\n", WEXITSTATUS(wstat
)));
457 #if defined(WIFSIGNALLED) && defined(WTERMSIG)
458 else if (WIFSIGNALLED(wstat
)) {
459 DEBUG(3, ("chat_with_program: The process was killed by signal %d \
460 while we were waiting\n", WTERMSIG(wstat
)));
468 * Lose any elevated privileges.
470 drop_effective_capability(KERNEL_OPLOCK_CAPABILITY
);
471 drop_effective_capability(DMAPI_ACCESS_CAPABILITY
);
473 /* make sure it doesn't freeze */
479 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass
->pw_name
,
480 (int)getuid(), (int)getgid(), BOOLSTR(as_root
) ));
481 chstat
= dochild(master
, slavedev
, pass
, passwordprogram
, as_root
);
487 * The child should never return from dochild() ....
490 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat
));
495 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
496 (chstat
? "" : "un"), pass
->pw_name
));
500 bool chgpasswd(const char *name
, const char *rhost
, const struct passwd
*pass
,
501 const char *oldpass
, const char *newpass
, bool as_root
)
503 char *passwordprogram
= NULL
;
504 char *chatsequence
= NULL
;
507 TALLOC_CTX
*ctx
= talloc_tos();
513 DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root
), name
));
515 #ifdef DEBUG_PASSWORD
516 DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass
, newpass
));
519 /* Take the passed information and test it for minimum criteria */
521 /* Password is same as old password */
522 if (strcmp(oldpass
, newpass
) == 0) {
523 /* don't allow same password */
524 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name
)); /* log the attempt */
525 return (False
); /* inform the user */
529 * Check the old and new passwords don't contain any control
533 len
= strlen(oldpass
);
534 for (i
= 0; i
< len
; i
++) {
535 if (iscntrl((int)oldpass
[i
])) {
536 DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
541 len
= strlen(newpass
);
542 for (i
= 0; i
< len
; i
++) {
543 if (iscntrl((int)newpass
[i
])) {
544 DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
550 if (lp_pam_password_change()) {
552 #ifdef HAVE_SETLOCALE
553 const char *prevlocale
= setlocale(LC_ALL
, "C");
560 ret
= smb_pam_passchange(pass
->pw_name
, rhost
,
563 ret
= smb_pam_passchange(name
, rhost
, oldpass
,
570 #ifdef HAVE_SETLOCALE
571 setlocale(LC_ALL
, prevlocale
);
578 /* A non-PAM password change just doen't make sense without a valid local user */
581 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name
));
585 passwordprogram
= talloc_strdup(ctx
, lp_passwd_program());
586 if (!passwordprogram
|| !*passwordprogram
) {
587 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
590 chatsequence
= talloc_strdup(ctx
, lp_passwd_chat());
591 if (!chatsequence
|| !*chatsequence
) {
592 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
597 /* The password program *must* contain the user name to work. Fail if not. */
598 if (strstr_m(passwordprogram
, "%u") == NULL
) {
599 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
600 the string %%u, and the given string %s does not.\n", passwordprogram
));
605 passwordprogram
= talloc_string_sub(ctx
, passwordprogram
, "%u", name
);
606 if (!passwordprogram
) {
610 /* note that we do NOT substitute the %o and %n in the password program
611 as this would open up a security hole where the user could use
612 a new password containing shell escape characters */
614 chatsequence
= talloc_string_sub(ctx
, chatsequence
, "%u", name
);
618 chatsequence
= talloc_all_string_sub(ctx
,
625 chatsequence
= talloc_all_string_sub(ctx
,
629 return chat_with_program(passwordprogram
,
635 #else /* ALLOW_CHANGE_PASSWORD */
637 bool chgpasswd(const char *name
, const struct passwd
*pass
,
638 const char *oldpass
, const char *newpass
, bool as_root
)
640 DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name
));
643 #endif /* ALLOW_CHANGE_PASSWORD */
645 /***********************************************************
646 Decrypt and verify a user password change.
648 The 516 byte long buffers are encrypted with the old NT and
649 old LM passwords, and if the NT passwords are present, both
650 buffers contain a unicode string.
652 After decrypting the buffers, check the password is correct by
653 matching the old hashed passwords with the passwords in the passdb.
655 ************************************************************/
657 static NTSTATUS
check_oem_password(const char *user
,
658 uchar password_encrypted_with_lm_hash
[516],
659 const uchar old_lm_hash_encrypted
[16],
660 uchar password_encrypted_with_nt_hash
[516],
661 const uchar old_nt_hash_encrypted
[16],
662 struct samu
*sampass
,
663 char **pp_new_passwd
)
667 uint8
*password_encrypted
;
668 const uint8
*encryption_key
;
669 const uint8
*lanman_pw
, *nt_pw
;
672 uchar new_nt_hash
[16];
673 uchar new_lm_hash
[16];
677 bool nt_pass_set
= (password_encrypted_with_nt_hash
&& old_nt_hash_encrypted
);
678 bool lm_pass_set
= (password_encrypted_with_lm_hash
&& old_lm_hash_encrypted
);
680 acct_ctrl
= pdb_get_acct_ctrl(sampass
);
682 /* I am convinced this check here is wrong, it is valid to
683 * change a password of a user that has a disabled account - gd */
685 if (acct_ctrl
& ACB_DISABLED
) {
686 DEBUG(2,("check_lanman_password: account %s disabled.\n", user
));
687 return NT_STATUS_ACCOUNT_DISABLED
;
690 if ((acct_ctrl
& ACB_PWNOTREQ
) && lp_null_passwords()) {
691 /* construct a null password (in case one is needed */
694 nt_lm_owf_gen(no_pw
, null_ntpw
, null_pw
);
699 /* save pointers to passwords so we don't have to keep looking them up */
700 if (lp_lanman_auth()) {
701 lanman_pw
= pdb_get_lanman_passwd(sampass
);
705 nt_pw
= pdb_get_nt_passwd(sampass
);
708 if (nt_pw
&& nt_pass_set
) {
709 /* IDEAL Case: passwords are in unicode, and we can
710 * read use the password encrypted with the NT hash
712 password_encrypted
= password_encrypted_with_nt_hash
;
713 encryption_key
= nt_pw
;
714 } else if (lanman_pw
&& lm_pass_set
) {
715 /* password may still be in unicode, but use LM hash version */
716 password_encrypted
= password_encrypted_with_lm_hash
;
717 encryption_key
= lanman_pw
;
718 } else if (nt_pass_set
) {
719 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
721 return NT_STATUS_WRONG_PASSWORD
;
722 } else if (lm_pass_set
) {
723 if (lp_lanman_auth()) {
724 DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
727 DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
730 return NT_STATUS_WRONG_PASSWORD
;
732 DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
734 return NT_STATUS_WRONG_PASSWORD
;
738 * Decrypt the password with the key
740 arcfour_crypt( password_encrypted
, encryption_key
, 516);
742 if (!decode_pw_buffer(talloc_tos(),
746 nt_pass_set
? CH_UTF16
: CH_DOS
)) {
747 return NT_STATUS_WRONG_PASSWORD
;
751 * To ensure we got the correct new password, hash it and
752 * use it as a key to test the passed old password.
756 /* NT passwords, verify the NT hash. */
758 /* Calculate the MD4 hash (NT compatible) of the password */
759 memset(new_nt_hash
, '\0', 16);
760 E_md4hash(*pp_new_passwd
, new_nt_hash
);
764 * check the NT verifier
766 E_old_pw_hash(new_nt_hash
, nt_pw
, verifier
);
767 if (memcmp(verifier
, old_nt_hash_encrypted
, 16)) {
768 DEBUG(0, ("check_oem_password: old nt "
769 "password doesn't match.\n"));
770 return NT_STATUS_WRONG_PASSWORD
;
773 /* We could check the LM password here, but there is
774 * little point, we already know the password is
775 * correct, and the LM password might not even be
778 /* Further, LM hash generation algorithms
779 * differ with charset, so we could
780 * incorrectly fail a perfectly valid password
782 #ifdef DEBUG_PASSWORD
784 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
791 * check the lm verifier
793 E_old_pw_hash(new_nt_hash
, lanman_pw
, verifier
);
794 if (memcmp(verifier
, old_lm_hash_encrypted
, 16)) {
795 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
796 return NT_STATUS_WRONG_PASSWORD
;
798 #ifdef DEBUG_PASSWORD
800 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
806 if (lanman_pw
&& lm_pass_set
) {
808 E_deshash(*pp_new_passwd
, new_lm_hash
);
811 * check the lm verifier
813 E_old_pw_hash(new_lm_hash
, lanman_pw
, verifier
);
814 if (memcmp(verifier
, old_lm_hash_encrypted
, 16)) {
815 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
816 return NT_STATUS_WRONG_PASSWORD
;
819 #ifdef DEBUG_PASSWORD
821 ("check_oem_password: password %s ok\n", *pp_new_passwd
));
826 /* should not be reached */
827 return NT_STATUS_WRONG_PASSWORD
;
830 static bool password_in_history(uint8_t nt_pw
[NT_HASH_LEN
],
831 uint32_t pw_history_len
,
832 const uint8_t *pw_history
)
834 static const uint8_t zero_md5_nt_pw
[SALTED_MD5_HASH_LEN
] = { 0, };
837 dump_data(100, nt_pw
, NT_HASH_LEN
);
838 dump_data(100, pw_history
, PW_HISTORY_ENTRY_LEN
* pw_history_len
);
840 for (i
=0; i
<pw_history_len
; i
++) {
841 uint8_t new_nt_pw_salted_md5_hash
[SALTED_MD5_HASH_LEN
];
842 const uint8_t *current_salt
;
843 const uint8_t *old_nt_pw_salted_md5_hash
;
845 current_salt
= &pw_history
[i
*PW_HISTORY_ENTRY_LEN
];
846 old_nt_pw_salted_md5_hash
= current_salt
+ PW_HISTORY_SALT_LEN
;
848 if (memcmp(zero_md5_nt_pw
, old_nt_pw_salted_md5_hash
,
849 SALTED_MD5_HASH_LEN
) == 0) {
850 /* Ignore zero valued entries. */
854 if (memcmp(zero_md5_nt_pw
, current_salt
,
855 PW_HISTORY_SALT_LEN
) == 0)
858 * New format: zero salt and then plain nt hash.
859 * Directly compare the hashes.
861 if (memcmp(nt_pw
, old_nt_pw_salted_md5_hash
,
862 SALTED_MD5_HASH_LEN
) == 0)
868 * Old format: md5sum of salted nt hash.
869 * Create salted version of new pw to compare.
871 E_md5hash(current_salt
, nt_pw
, new_nt_pw_salted_md5_hash
);
873 if (memcmp(new_nt_pw_salted_md5_hash
,
874 old_nt_pw_salted_md5_hash
,
875 SALTED_MD5_HASH_LEN
) == 0) {
883 /***********************************************************
884 This routine takes the given password and checks it against
885 the password history. Returns True if this password has been
886 found in the history list.
887 ************************************************************/
889 static bool check_passwd_history(struct samu
*sampass
, const char *plaintext
)
891 uchar new_nt_p16
[NT_HASH_LEN
];
893 const uint8
*pwhistory
;
894 uint32 pwHisLen
, curr_pwHisLen
;
896 pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY
, &pwHisLen
);
901 pwhistory
= pdb_get_pw_history(sampass
, &curr_pwHisLen
);
902 if (!pwhistory
|| curr_pwHisLen
== 0) {
906 /* Only examine the minimum of the current history len and
907 the stored history len. Avoids race conditions. */
908 pwHisLen
= MIN(pwHisLen
,curr_pwHisLen
);
910 nt_pw
= pdb_get_nt_passwd(sampass
);
912 E_md4hash(plaintext
, new_nt_p16
);
914 if (!memcmp(nt_pw
, new_nt_p16
, NT_HASH_LEN
)) {
915 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
916 pdb_get_username(sampass
) ));
920 if (password_in_history(new_nt_p16
, pwHisLen
, pwhistory
)) {
921 DEBUG(1,("check_passwd_history: proposed new password for "
922 "user %s found in history list !\n",
923 pdb_get_username(sampass
) ));
929 /***********************************************************
930 ************************************************************/
932 NTSTATUS
check_password_complexity(const char *username
,
933 const char *password
,
934 enum samPwdChangeReason
*samr_reject_reason
)
936 TALLOC_CTX
*tosctx
= talloc_tos();
940 /* Use external script to check password complexity */
941 if ((lp_check_password_script() == NULL
)
942 || (*(lp_check_password_script()) == '\0')) {
946 cmd
= talloc_string_sub(tosctx
, lp_check_password_script(), "%u",
949 return NT_STATUS_PASSWORD_RESTRICTION
;
952 check_ret
= smbrunsecret(cmd
, password
);
953 DEBUG(5,("check_password_complexity: check password script (%s) "
954 "returned [%d]\n", cmd
, check_ret
));
957 if (check_ret
!= 0) {
958 DEBUG(1,("check_password_complexity: "
959 "check password script said new password is not good "
961 if (samr_reject_reason
) {
962 *samr_reject_reason
= SAM_PWD_CHANGE_NOT_COMPLEX
;
964 return NT_STATUS_PASSWORD_RESTRICTION
;
970 /***********************************************************
971 Code to change the oem password. Changes both the lanman
972 and NT hashes. Old_passwd is almost always NULL.
973 NOTE this function is designed to be called as root. Check the old password
974 is correct before calling. JRA.
975 ************************************************************/
977 static NTSTATUS
change_oem_password(struct samu
*hnd
, const char *rhost
,
978 char *old_passwd
, char *new_passwd
,
980 enum samPwdChangeReason
*samr_reject_reason
)
984 TALLOC_CTX
*tosctx
= talloc_tos();
985 struct passwd
*pass
= NULL
;
986 const char *username
= pdb_get_username(hnd
);
987 time_t can_change_time
= pdb_get_pass_can_change_time(hnd
);
990 if (samr_reject_reason
) {
991 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
994 /* check to see if the secdesc has previously been set to disallow */
995 if (!pdb_get_pass_can_change(hnd
)) {
996 DEBUG(1, ("user %s does not have permissions to change password\n", username
));
997 if (samr_reject_reason
) {
998 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1000 return NT_STATUS_ACCOUNT_RESTRICTION
;
1003 /* check to see if it is a Machine account and if the policy
1004 * denies machines to change the password. *
1005 * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1006 if (pdb_get_acct_ctrl(hnd
) & ACB_WSTRUST
) {
1007 if (pdb_get_account_policy(PDB_POLICY_REFUSE_MACHINE_PW_CHANGE
, &refuse
) && refuse
) {
1008 DEBUG(1, ("Machine %s cannot change password now, "
1009 "denied by Refuse Machine Password Change policy\n",
1011 if (samr_reject_reason
) {
1012 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1014 return NT_STATUS_ACCOUNT_RESTRICTION
;
1018 /* removed calculation here, because passdb now calculates
1019 based on policy. jmcd */
1020 if ((can_change_time
!= 0) && (time(NULL
) < can_change_time
)) {
1021 DEBUG(1, ("user %s cannot change password now, must "
1022 "wait until %s\n", username
,
1023 http_timestring(tosctx
, can_change_time
)));
1024 if (samr_reject_reason
) {
1025 *samr_reject_reason
= SAM_PWD_CHANGE_NO_ERROR
;
1027 return NT_STATUS_ACCOUNT_RESTRICTION
;
1030 if (pdb_get_account_policy(PDB_POLICY_MIN_PASSWORD_LEN
, &min_len
) && (str_charnum(new_passwd
) < min_len
)) {
1031 DEBUG(1, ("user %s cannot change password - password too short\n",
1033 DEBUGADD(1, (" account policy min password len = %d\n", min_len
));
1034 if (samr_reject_reason
) {
1035 *samr_reject_reason
= SAM_PWD_CHANGE_PASSWORD_TOO_SHORT
;
1037 return NT_STATUS_PASSWORD_RESTRICTION
;
1038 /* return NT_STATUS_PWD_TOO_SHORT; */
1041 if (check_passwd_history(hnd
,new_passwd
)) {
1042 if (samr_reject_reason
) {
1043 *samr_reject_reason
= SAM_PWD_CHANGE_PWD_IN_HISTORY
;
1045 return NT_STATUS_PASSWORD_RESTRICTION
;
1048 pass
= Get_Pwnam_alloc(tosctx
, username
);
1050 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username
));
1051 return NT_STATUS_ACCESS_DENIED
;
1054 status
= check_password_complexity(username
, new_passwd
, samr_reject_reason
);
1055 if (!NT_STATUS_IS_OK(status
)) {
1061 * If unix password sync was requested, attempt to change
1062 * the /etc/passwd database first. Return failure if this cannot
1065 * This occurs before the oem change, because we don't want to
1066 * update it if chgpasswd failed.
1068 * Conditional on lp_unix_password_sync() because we don't want
1069 * to touch the unix db unless we have admin permission.
1072 if(lp_unix_password_sync() &&
1073 !chgpasswd(username
, rhost
, pass
, old_passwd
, new_passwd
,
1076 return NT_STATUS_ACCESS_DENIED
;
1081 if (!pdb_set_plaintext_passwd (hnd
, new_passwd
)) {
1082 return NT_STATUS_ACCESS_DENIED
;
1085 /* Now write it into the file. */
1086 return pdb_update_sam_account (hnd
);
1089 /***********************************************************
1090 Code to check and change the OEM hashed password.
1091 ************************************************************/
1093 NTSTATUS
pass_oem_change(char *user
, const char *rhost
,
1094 uchar password_encrypted_with_lm_hash
[516],
1095 const uchar old_lm_hash_encrypted
[16],
1096 uchar password_encrypted_with_nt_hash
[516],
1097 const uchar old_nt_hash_encrypted
[16],
1098 enum samPwdChangeReason
*reject_reason
)
1100 char *new_passwd
= NULL
;
1101 struct samu
*sampass
= NULL
;
1105 if (!(sampass
= samu_new(NULL
))) {
1106 return NT_STATUS_NO_MEMORY
;
1110 ret
= pdb_getsampwnam(sampass
, user
);
1114 DEBUG(0,("pass_oem_change: getsmbpwnam returned NULL\n"));
1115 TALLOC_FREE(sampass
);
1116 return NT_STATUS_NO_SUCH_USER
;
1119 nt_status
= check_oem_password(user
,
1120 password_encrypted_with_lm_hash
,
1121 old_lm_hash_encrypted
,
1122 password_encrypted_with_nt_hash
,
1123 old_nt_hash_encrypted
,
1127 if (!NT_STATUS_IS_OK(nt_status
)) {
1128 TALLOC_FREE(sampass
);
1132 /* We've already checked the old password here.... */
1134 nt_status
= change_oem_password(sampass
, rhost
, NULL
, new_passwd
,
1135 True
, reject_reason
);
1138 memset(new_passwd
, 0, strlen(new_passwd
));
1140 TALLOC_FREE(sampass
);