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)
66 SMB_STRUCT_DIR *dirp = NULL;
71 #if defined(HAVE_GRANTPT)
72 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
73 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) {
76 line = (char *)ptsname(master);
78 *slave = SMB_STRDUP(line);
83 ("findpty: Unable to create master/slave pty pair.\n"));
84 /* Stop fd leak on error. */
89 ("findpty: Allocated slave pty %s\n", *slave));
93 #endif /* HAVE_GRANTPT */
95 line = SMB_STRDUP("/dev/ptyXX");
100 dirp = sys_opendir("/dev");
106 while ((dpname = readdirname(dirp)) != NULL) {
107 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) {
109 ("pty: try to open %s, line was %s\n", dpname,
113 if ((master = sys_open(line, O_RDWR, 0)) >= 0) {
114 DEBUG(3, ("pty: opened %s\n", line));
127 static int dochild(int master, const char *slavedev, const struct passwd *pass,
128 const char *passwordprogram, bool as_root)
131 struct termios stermios;
134 char * const eptrs[1] = { NULL };
139 ("dochild: user doesn't exist in the UNIX password database.\n"));
146 gain_root_privilege();
148 /* Start new session - gets rid of controlling terminal. */
152 ("Weirdness, couldn't let go of controlling terminal\n"));
156 /* Open slave pty and acquire as new controlling terminal. */
157 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
159 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
162 #if defined(TIOCSCTTY)
163 if (ioctl(slave, TIOCSCTTY, 0) < 0)
165 DEBUG(3, ("Error in ioctl call for slave pty\n"));
168 #elif defined(I_PUSH) && defined(I_FIND)
169 if (ioctl(slave, I_FIND, "ptem") == 0) {
170 ioctl(slave, I_PUSH, "ptem");
172 if (ioctl(slave, I_FIND, "ldterm") == 0) {
173 ioctl(slave, I_PUSH, "ldterm");
180 /* Make slave stdin/out/err of child. */
182 if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
184 DEBUG(3, ("Could not re-direct stdin\n"));
187 if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
189 DEBUG(3, ("Could not re-direct stdout\n"));
192 if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
194 DEBUG(3, ("Could not re-direct stderr\n"));
200 /* Set proper terminal attributes - no echo, canonical input processing,
201 no map NL to CR/NL on output. */
203 if (tcgetattr(0, &stermios) < 0)
206 ("could not read default terminal attributes on pty\n"));
209 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
210 stermios.c_lflag |= ICANON;
212 stermios.c_oflag &= ~(ONLCR);
214 if (tcsetattr(0, TCSANOW, &stermios) < 0)
216 DEBUG(3, ("could not set attributes of pty\n"));
220 /* make us completely into the right uid */
223 become_user_permanently(uid, gid);
227 ("Invoking '%s' as password change program.\n",
230 /* execl() password-change application */
231 if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0)
233 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
239 static int expect(int master, char *issue, char *expected)
242 int attempts, timeout, nread, len;
245 for (attempts = 0; attempts < 2; attempts++) {
246 if (!strequal(issue, ".")) {
247 if (lp_passwd_chat_debug())
248 DEBUG(100, ("expect: sending [%s]\n", issue));
250 if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) {
251 DEBUG(2,("expect: (short) write returned %d\n", len ));
256 if (strequal(expected, "."))
259 /* Initial timeout. */
260 timeout = lp_passwd_chat_timeout() * 1000;
264 while ((len = read_socket_with_timeout(master, buffer + nread, 1,
265 sizeof(buffer) - nread - 1,
266 timeout, NULL)) > 0) {
271 /* Eat leading/trailing whitespace before match. */
272 char *str = SMB_STRDUP(buffer);
274 DEBUG(2,("expect: ENOMEM\n"));
277 trim_char(str, ' ', ' ');
279 if ((match = unix_wild_match(expected, str)) == True) {
280 /* Now data has started to return, lower timeout. */
281 timeout = lp_passwd_chat_timeout() * 100;
287 if (lp_passwd_chat_debug())
288 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
289 expected, buffer, match ? "yes" : "no" ));
295 DEBUG(2, ("expect: %s\n", strerror(errno)));
300 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
304 static void pwd_sub(char *buf)
306 all_string_sub(buf, "\\n", "\n", 0);
307 all_string_sub(buf, "\\r", "\r", 0);
308 all_string_sub(buf, "\\s", " ", 0);
309 all_string_sub(buf, "\\t", "\t", 0);
312 static int talktochild(int master, const char *seq)
314 TALLOC_CTX *frame = talloc_stackframe();
319 issue = talloc_strdup(frame, ".");
325 while (next_token_talloc(frame, &seq, &expected, NULL)) {
329 if (!expect(master, issue, expected)) {
330 DEBUG(3, ("Response %d incorrect\n", count));
335 if (!next_token_talloc(frame, &seq, &issue, NULL)) {
336 issue = talloc_strdup(frame, ".");
345 if (!strequal(issue, ".")) {
346 /* we have one final issue to send */
347 expected = talloc_strdup(frame, ".");
352 if (!expect(master, issue, expected)) {
361 static bool chat_with_program(char *passwordprogram, const struct passwd *pass,
362 char *chatsequence, bool as_root)
364 char *slavedev = NULL;
371 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
375 /* allocate a pseudo-terminal device */
376 if ((master = findpty(&slavedev)) < 0) {
377 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
382 * We need to temporarily stop CatchChild from eating
383 * SIGCLD signals as it also eats the exit status code. JRA.
386 CatchChildLeaveStatus();
388 if ((pid = sys_fork()) < 0) {
389 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
396 /* we now have a pty */
397 if (pid > 0) { /* This is the parent process */
398 /* Don't need this anymore in parent. */
401 if ((chstat = talktochild(master, chatsequence)) == False) {
402 DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
403 kill(pid, SIGKILL); /* be sure to end this process */
406 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
407 if (errno == EINTR) {
415 DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
422 * Go back to ignoring children.
429 DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
432 if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
433 DEBUG(3, ("chat_with_program: The process exited with status %d \
434 while we were waiting\n", WEXITSTATUS(wstat)));
437 #if defined(WIFSIGNALLED) && defined(WTERMSIG)
438 else if (WIFSIGNALLED(wstat)) {
439 DEBUG(3, ("chat_with_program: The process was killed by signal %d \
440 while we were waiting\n", WTERMSIG(wstat)));
448 * Lose any elevated privileges.
450 drop_effective_capability(KERNEL_OPLOCK_CAPABILITY);
451 drop_effective_capability(DMAPI_ACCESS_CAPABILITY);
453 /* make sure it doesn't freeze */
459 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
460 (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
461 chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
467 * The child should never return from dochild() ....
470 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
475 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
476 (chstat ? "" : "un"), pass->pw_name));
480 bool chgpasswd(const char *name, const struct passwd *pass,
481 const char *oldpass, const char *newpass, bool as_root)
483 char *passwordprogram = NULL;
484 char *chatsequence = NULL;
487 TALLOC_CTX *ctx = talloc_tos();
493 DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
495 #ifdef DEBUG_PASSWORD
496 DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
499 /* Take the passed information and test it for minimum criteria */
501 /* Password is same as old password */
502 if (strcmp(oldpass, newpass) == 0) {
503 /* don't allow same password */
504 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */
505 return (False); /* inform the user */
509 * Check the old and new passwords don't contain any control
513 len = strlen(oldpass);
514 for (i = 0; i < len; i++) {
515 if (iscntrl((int)oldpass[i])) {
516 DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
521 len = strlen(newpass);
522 for (i = 0; i < len; i++) {
523 if (iscntrl((int)newpass[i])) {
524 DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
530 if (lp_pam_password_change()) {
532 #ifdef HAVE_SETLOCALE
533 const char *prevlocale = setlocale(LC_ALL, "C");
540 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
542 ret = smb_pam_passchange(name, oldpass, newpass);
548 #ifdef HAVE_SETLOCALE
549 setlocale(LC_ALL, prevlocale);
556 /* A non-PAM password change just doen't make sense without a valid local user */
559 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
563 passwordprogram = talloc_strdup(ctx, lp_passwd_program());
564 if (!passwordprogram || !*passwordprogram) {
565 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
568 chatsequence = talloc_strdup(ctx, lp_passwd_chat());
569 if (!chatsequence || !*chatsequence) {
570 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
575 /* The password program *must* contain the user name to work. Fail if not. */
576 if (strstr_m(passwordprogram, "%u") == NULL) {
577 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
578 the string %%u, and the given string %s does not.\n", passwordprogram ));
583 passwordprogram = talloc_string_sub(ctx, passwordprogram, "%u", name);
584 if (!passwordprogram) {
588 /* note that we do NOT substitute the %o and %n in the password program
589 as this would open up a security hole where the user could use
590 a new password containing shell escape characters */
592 chatsequence = talloc_string_sub(ctx, chatsequence, "%u", name);
596 chatsequence = talloc_all_string_sub(ctx,
603 chatsequence = talloc_all_string_sub(ctx,
607 return chat_with_program(passwordprogram,
613 #else /* ALLOW_CHANGE_PASSWORD */
615 bool chgpasswd(const char *name, const struct passwd *pass,
616 const char *oldpass, const char *newpass, bool as_root)
618 DEBUG(0, ("chgpasswd: Unix Password changing not compiled in (user=%s)\n", name));
621 #endif /* ALLOW_CHANGE_PASSWORD */
623 /***********************************************************
624 Code to check the lanman hashed password.
625 ************************************************************/
627 bool check_lanman_password(char *user, uchar * pass1,
628 uchar * pass2, struct samu **hnd)
630 uchar unenc_new_pw[16];
631 uchar unenc_old_pw[16];
632 struct samu *sampass = NULL;
634 const uint8 *lanman_pw;
637 if ( !(sampass = samu_new(NULL)) ) {
638 DEBUG(0, ("samu_new() failed!\n"));
643 ret = pdb_getsampwnam(sampass, user);
647 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
648 TALLOC_FREE(sampass);
652 acct_ctrl = pdb_get_acct_ctrl (sampass);
653 lanman_pw = pdb_get_lanman_passwd (sampass);
655 if (acct_ctrl & ACB_DISABLED) {
656 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
657 TALLOC_FREE(sampass);
661 if (lanman_pw == NULL) {
662 if (acct_ctrl & ACB_PWNOTREQ) {
663 /* this saves the pointer for the caller */
667 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
668 TALLOC_FREE(sampass);
673 /* Get the new lanman hash. */
674 D_P16(lanman_pw, pass2, unenc_new_pw);
676 /* Use this to get the old lanman hash. */
677 D_P16(unenc_new_pw, pass1, unenc_old_pw);
679 /* Check that the two old passwords match. */
680 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
681 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
682 TALLOC_FREE(sampass);
686 /* this saves the pointer for the caller */
691 /***********************************************************
692 Code to change the lanman hashed password.
693 It nulls out the NT hashed password as it will
695 NOTE this function is designed to be called as root. Check the old password
696 is correct before calling. JRA.
697 ************************************************************/
699 bool change_lanman_password(struct samu *sampass, uchar *pass2)
701 static uchar null_pw[16];
702 uchar unenc_new_pw[16];
707 if (sampass == NULL) {
708 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
712 acct_ctrl = pdb_get_acct_ctrl(sampass);
713 pwd = pdb_get_lanman_passwd(sampass);
715 if (acct_ctrl & ACB_DISABLED) {
716 DEBUG(0,("change_lanman_password: account %s disabled.\n",
717 pdb_get_username(sampass)));
722 if (acct_ctrl & ACB_PWNOTREQ) {
724 memset(no_pw, '\0', 14);
725 E_P16(no_pw, null_pw);
727 /* Get the new lanman hash. */
728 D_P16(null_pw, pass2, unenc_new_pw);
730 DEBUG(0,("change_lanman_password: no lanman password !\n"));
734 /* Get the new lanman hash. */
735 D_P16(pwd, pass2, unenc_new_pw);
738 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
742 if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
743 return False; /* We lose the NT hash. Sorry. */
746 if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) {
747 TALLOC_FREE(sampass);
748 /* Not quite sure what this one qualifies as, but this will do */
752 /* Now flush the sam_passwd struct to persistent storage */
753 ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass));
758 /***********************************************************
759 Code to check and change the OEM hashed password.
760 ************************************************************/
762 NTSTATUS pass_oem_change(char *user,
763 uchar password_encrypted_with_lm_hash[516],
764 const uchar old_lm_hash_encrypted[16],
765 uchar password_encrypted_with_nt_hash[516],
766 const uchar old_nt_hash_encrypted[16],
767 uint32 *reject_reason)
769 char *new_passwd = NULL;
770 struct samu *sampass = NULL;
771 NTSTATUS nt_status = check_oem_password(user,
772 password_encrypted_with_lm_hash,
773 old_lm_hash_encrypted,
774 password_encrypted_with_nt_hash,
775 old_nt_hash_encrypted,
779 if (!NT_STATUS_IS_OK(nt_status)) {
783 /* We've already checked the old password here.... */
785 nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason);
788 memset(new_passwd, 0, strlen(new_passwd));
790 TALLOC_FREE(sampass);
795 /***********************************************************
796 Decrypt and verify a user password change.
798 The 516 byte long buffers are encrypted with the old NT and
799 old LM passwords, and if the NT passwords are present, both
800 buffers contain a unicode string.
802 After decrypting the buffers, check the password is correct by
803 matching the old hashed passwords with the passwords in the passdb.
805 ************************************************************/
807 static NTSTATUS check_oem_password(const char *user,
808 uchar password_encrypted_with_lm_hash[516],
809 const uchar old_lm_hash_encrypted[16],
810 uchar password_encrypted_with_nt_hash[516],
811 const uchar old_nt_hash_encrypted[16],
813 char **pp_new_passwd)
815 static uchar null_pw[16];
816 static uchar null_ntpw[16];
817 struct samu *sampass = NULL;
818 uint8 *password_encrypted;
819 const uint8 *encryption_key;
820 const uint8 *lanman_pw, *nt_pw;
823 uchar new_nt_hash[16];
824 uchar new_lm_hash[16];
829 bool nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted);
830 bool lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted);
834 if ( !(sampass = samu_new( NULL )) ) {
835 return NT_STATUS_NO_MEMORY;
839 ret = pdb_getsampwnam(sampass, user);
843 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
844 TALLOC_FREE(sampass);
845 return NT_STATUS_NO_SUCH_USER;
848 acct_ctrl = pdb_get_acct_ctrl(sampass);
850 if (acct_ctrl & ACB_DISABLED) {
851 DEBUG(2,("check_lanman_password: account %s disabled.\n", user));
852 TALLOC_FREE(sampass);
853 return NT_STATUS_ACCOUNT_DISABLED;
856 if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) {
857 /* construct a null password (in case one is needed */
860 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
865 /* save pointers to passwords so we don't have to keep looking them up */
866 if (lp_lanman_auth()) {
867 lanman_pw = pdb_get_lanman_passwd(sampass);
871 nt_pw = pdb_get_nt_passwd(sampass);
874 if (nt_pw && nt_pass_set) {
875 /* IDEAL Case: passwords are in unicode, and we can
876 * read use the password encrypted with the NT hash
878 password_encrypted = password_encrypted_with_nt_hash;
879 encryption_key = nt_pw;
880 } else if (lanman_pw && lm_pass_set) {
881 /* password may still be in unicode, but use LM hash version */
882 password_encrypted = password_encrypted_with_lm_hash;
883 encryption_key = lanman_pw;
884 } else if (nt_pass_set) {
885 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n",
887 TALLOC_FREE(sampass);
888 return NT_STATUS_WRONG_PASSWORD;
889 } else if (lm_pass_set) {
890 if (lp_lanman_auth()) {
891 DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n",
894 DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n",
897 TALLOC_FREE(sampass);
898 return NT_STATUS_WRONG_PASSWORD;
900 DEBUG(1, ("password change requested for user %s, but no password supplied!\n",
902 TALLOC_FREE(sampass);
903 return NT_STATUS_WRONG_PASSWORD;
907 * Decrypt the password with the key
909 SamOEMhash( password_encrypted, encryption_key, 516);
911 if (!decode_pw_buffer(talloc_tos(),
915 nt_pass_set ? STR_UNICODE : STR_ASCII)) {
916 TALLOC_FREE(sampass);
917 return NT_STATUS_WRONG_PASSWORD;
921 * To ensure we got the correct new password, hash it and
922 * use it as a key to test the passed old password.
926 /* NT passwords, verify the NT hash. */
928 /* Calculate the MD4 hash (NT compatible) of the password */
929 memset(new_nt_hash, '\0', 16);
930 E_md4hash(*pp_new_passwd, new_nt_hash);
934 * check the NT verifier
936 E_old_pw_hash(new_nt_hash, nt_pw, verifier);
937 if (memcmp(verifier, old_nt_hash_encrypted, 16)) {
938 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
939 TALLOC_FREE(sampass);
940 return NT_STATUS_WRONG_PASSWORD;
943 /* We could check the LM password here, but there is
944 * little point, we already know the password is
945 * correct, and the LM password might not even be
948 /* Further, LM hash generation algorithms
949 * differ with charset, so we could
950 * incorrectly fail a perfectly valid password
952 #ifdef DEBUG_PASSWORD
954 ("check_oem_password: password %s ok\n", *pp_new_passwd));
962 * check the lm verifier
964 E_old_pw_hash(new_nt_hash, lanman_pw, verifier);
965 if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
966 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
967 TALLOC_FREE(sampass);
968 return NT_STATUS_WRONG_PASSWORD;
970 #ifdef DEBUG_PASSWORD
972 ("check_oem_password: password %s ok\n", *pp_new_passwd));
979 if (lanman_pw && lm_pass_set) {
981 E_deshash(*pp_new_passwd, new_lm_hash);
984 * check the lm verifier
986 E_old_pw_hash(new_lm_hash, lanman_pw, verifier);
987 if (memcmp(verifier, old_lm_hash_encrypted, 16)) {
988 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
989 TALLOC_FREE(sampass);
990 return NT_STATUS_WRONG_PASSWORD;
993 #ifdef DEBUG_PASSWORD
995 ("check_oem_password: password %s ok\n", *pp_new_passwd));
1001 /* should not be reached */
1002 TALLOC_FREE(sampass);
1003 return NT_STATUS_WRONG_PASSWORD;
1006 /***********************************************************
1007 This routine takes the given password and checks it against
1008 the password history. Returns True if this password has been
1009 found in the history list.
1010 ************************************************************/
1012 static bool check_passwd_history(struct samu *sampass, const char *plaintext)
1014 uchar new_nt_p16[NT_HASH_LEN];
1015 uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN];
1017 const uint8 *pwhistory;
1020 uint32 pwHisLen, curr_pwHisLen;
1022 pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen);
1023 if (pwHisLen == 0) {
1027 pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen);
1028 if (!pwhistory || curr_pwHisLen == 0) {
1032 /* Only examine the minimum of the current history len and
1033 the stored history len. Avoids race conditions. */
1034 pwHisLen = MIN(pwHisLen,curr_pwHisLen);
1036 nt_pw = pdb_get_nt_passwd(sampass);
1038 E_md4hash(plaintext, new_nt_p16);
1040 if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) {
1041 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n",
1042 pdb_get_username(sampass) ));
1046 dump_data(100, new_nt_p16, NT_HASH_LEN);
1047 dump_data(100, pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen);
1049 memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN);
1050 for (i=0; i<pwHisLen; i++) {
1051 uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN];
1052 const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN];
1053 const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+
1054 PW_HISTORY_SALT_LEN];
1055 if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1056 /* Ignore zero valued entries. */
1059 /* Create salted versions of new to compare. */
1060 E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash);
1062 if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) {
1063 DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n",
1064 pdb_get_username(sampass) ));
1072 /***********************************************************
1073 Code to change the oem password. Changes both the lanman
1074 and NT hashes. Old_passwd is almost always NULL.
1075 NOTE this function is designed to be called as root. Check the old password
1076 is correct before calling. JRA.
1077 ************************************************************/
1079 NTSTATUS change_oem_password(struct samu *hnd, char *old_passwd, char *new_passwd, bool as_root, uint32 *samr_reject_reason)
1083 struct passwd *pass = NULL;
1084 const char *username = pdb_get_username(hnd);
1085 time_t can_change_time = pdb_get_pass_can_change_time(hnd);
1087 if (samr_reject_reason) {
1088 *samr_reject_reason = Undefined;
1091 /* check to see if the secdesc has previously been set to disallow */
1092 if (!pdb_get_pass_can_change(hnd)) {
1093 DEBUG(1, ("user %s does not have permissions to change password\n", username));
1094 if (samr_reject_reason) {
1095 *samr_reject_reason = REJECT_REASON_OTHER;
1097 return NT_STATUS_ACCOUNT_RESTRICTION;
1100 /* check to see if it is a Machine account and if the policy
1101 * denies machines to change the password. *
1102 * Should we deny also SRVTRUST and/or DOMSTRUST ? .SSS. */
1103 if (pdb_get_acct_ctrl(hnd) & ACB_WSTRUST) {
1104 if (pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &refuse) && refuse) {
1105 DEBUG(1, ("Machine %s cannot change password now, "
1106 "denied by Refuse Machine Password Change policy\n",
1108 if (samr_reject_reason) {
1109 *samr_reject_reason = REJECT_REASON_OTHER;
1111 return NT_STATUS_ACCOUNT_RESTRICTION;
1115 /* removed calculation here, becuase passdb now calculates
1116 based on policy. jmcd */
1117 if ((can_change_time != 0) && (time(NULL) < can_change_time)) {
1118 DEBUG(1, ("user %s cannot change password now, must "
1119 "wait until %s\n", username,
1120 http_timestring(can_change_time)));
1121 if (samr_reject_reason) {
1122 *samr_reject_reason = REJECT_REASON_OTHER;
1124 return NT_STATUS_ACCOUNT_RESTRICTION;
1127 if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) {
1128 DEBUG(1, ("user %s cannot change password - password too short\n",
1130 DEBUGADD(1, (" account policy min password len = %d\n", min_len));
1131 if (samr_reject_reason) {
1132 *samr_reject_reason = REJECT_REASON_TOO_SHORT;
1134 return NT_STATUS_PASSWORD_RESTRICTION;
1135 /* return NT_STATUS_PWD_TOO_SHORT; */
1138 if (check_passwd_history(hnd,new_passwd)) {
1139 if (samr_reject_reason) {
1140 *samr_reject_reason = REJECT_REASON_IN_HISTORY;
1142 return NT_STATUS_PASSWORD_RESTRICTION;
1145 pass = Get_Pwnam(username);
1147 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username));
1148 return NT_STATUS_ACCESS_DENIED;
1151 /* Use external script to check password complexity */
1152 if (lp_check_password_script() && *(lp_check_password_script())) {
1155 check_ret = smbrunsecret(lp_check_password_script(), new_passwd);
1156 DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret));
1158 if (check_ret != 0) {
1159 DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n"));
1160 if (samr_reject_reason) {
1161 *samr_reject_reason = REJECT_REASON_NOT_COMPLEX;
1163 return NT_STATUS_PASSWORD_RESTRICTION;
1168 * If unix password sync was requested, attempt to change
1169 * the /etc/passwd database first. Return failure if this cannot
1172 * This occurs before the oem change, because we don't want to
1173 * update it if chgpasswd failed.
1175 * Conditional on lp_unix_password_sync() because we don't want
1176 * to touch the unix db unless we have admin permission.
1179 if(lp_unix_password_sync() &&
1180 !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) {
1181 return NT_STATUS_ACCESS_DENIED;
1184 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
1185 return NT_STATUS_ACCESS_DENIED;
1188 /* Now write it into the file. */
1189 return pdb_update_sam_account (hnd);