2 Unix SMB/CIFS implementation.
3 Samba utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001-2002
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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /* fork a child process to exec passwd and write to its
23 * tty to change a users password. This is running as the
24 * user who is attempting to change the password.
28 * This code was copied/borrowed and stolen from various sources.
29 * The primary source was the poppasswd.c from the authors of POPMail. This software
30 * was included as a client to change passwords using the 'passwd' program
31 * on the remote machine.
33 * This routine is called by set_user_password() in password.c only if ALLOW_PASSWORD_CHANGE
34 * is defined in the compiler directives located in the Makefile.
36 * This code has been hacked by Bob Nance (nance@niehs.nih.gov) and Evan Patterson
37 * (patters2@niehs.nih.gov) at the National Institute of Environmental Health Sciences
38 * and rights to modify, distribute or incorporate this change to the CAP suite or
39 * using it for any other reason are granted, so long as this disclaimer is left intact.
43 This code was hacked considerably for inclusion in Samba, primarily
44 by Andrew.Tridgell@anu.edu.au. The biggest change was the addition
45 of the "password chat" option, which allows the easy runtime
46 specification of the expected sequence of events to change a
52 extern struct passdb_ops pdb_ops;
54 static NTSTATUS check_oem_password(const char *user,
55 uchar * lmdata, const uchar * lmhash,
56 const uchar * ntdata, const uchar * nthash,
57 SAM_ACCOUNT **hnd, char *new_passwd,
60 #if ALLOW_CHANGE_PASSWORD
62 static int findpty(char **slave)
69 #if defined(HAVE_GRANTPT)
70 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
71 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
75 *slave = (char *)ptsname(master);
79 ("findpty: Unable to create master/slave pty pair.\n"));
80 /* Stop fd leak on error. */
87 ("findpty: Allocated slave pty %s\n", *slave));
91 #endif /* HAVE_GRANTPT */
93 fstrcpy(line, "/dev/ptyXX");
95 dirp = opendir("/dev");
98 while ((dpname = readdirname(dirp)) != NULL)
100 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5)
103 ("pty: try to open %s, line was %s\n", dpname,
107 if ((master = sys_open(line, O_RDWR, 0)) >= 0)
109 DEBUG(3, ("pty: opened %s\n", line));
121 static int dochild(int master, const char *slavedev, const struct passwd *pass,
122 const char *passwordprogram, BOOL as_root)
125 struct termios stermios;
132 ("dochild: user doesn't exist in the UNIX password database.\n"));
139 gain_root_privilege();
141 /* Start new session - gets rid of controlling terminal. */
145 ("Weirdness, couldn't let go of controlling terminal\n"));
149 /* Open slave pty and acquire as new controlling terminal. */
150 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
152 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
156 ioctl(slave, I_PUSH, "ptem");
157 ioctl(slave, I_PUSH, "ldterm");
158 #elif defined(TIOCSCTTY)
159 if (ioctl(slave, TIOCSCTTY, 0) < 0)
161 DEBUG(3, ("Error in ioctl call for slave pty\n"));
169 /* Make slave stdin/out/err of child. */
171 if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
173 DEBUG(3, ("Could not re-direct stdin\n"));
176 if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
178 DEBUG(3, ("Could not re-direct stdout\n"));
181 if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
183 DEBUG(3, ("Could not re-direct stderr\n"));
189 /* Set proper terminal attributes - no echo, canonical input processing,
190 no map NL to CR/NL on output. */
192 if (tcgetattr(0, &stermios) < 0)
195 ("could not read default terminal attributes on pty\n"));
198 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
199 stermios.c_lflag |= ICANON;
201 stermios.c_oflag &= ~(ONLCR);
203 if (tcsetattr(0, TCSANOW, &stermios) < 0)
205 DEBUG(3, ("could not set attributes of pty\n"));
209 /* make us completely into the right uid */
212 become_user_permanently(uid, gid);
216 ("Invoking '%s' as password change program.\n",
219 /* execl() password-change application */
220 if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
222 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
228 static int expect(int master, char *issue, char *expected)
231 int attempts, timeout, nread, len;
234 for (attempts = 0; attempts < 2; attempts++) {
235 if (!strequal(issue, ".")) {
236 if (lp_passwd_chat_debug())
237 DEBUG(100, ("expect: sending [%s]\n", issue));
239 if ((len = write(master, issue, strlen(issue))) != strlen(issue)) {
240 DEBUG(2,("expect: (short) write returned %d\n", len ));
245 if (strequal(expected, "."))
248 /* Initial timeout. */
249 timeout = lp_passwd_chat_timeout() * 1000;
253 while ((len = read_socket_with_timeout(master, buffer + nread, 1,
254 sizeof(buffer) - nread - 1,
260 /* Eat leading/trailing whitespace before match. */
262 pstrcpy( str, buffer);
263 trim_char( str, ' ', ' ');
265 if ((match = (unix_wild_match(expected, str) == 0))) {
266 /* Now data has started to return, lower timeout. */
267 timeout = lp_passwd_chat_timeout() * 100;
272 if (lp_passwd_chat_debug())
273 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
274 expected, buffer, match ? "yes" : "no" ));
280 DEBUG(2, ("expect: %s\n", strerror(errno)));
285 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
289 static void pwd_sub(char *buf)
291 all_string_sub(buf, "\\n", "\n", 0);
292 all_string_sub(buf, "\\r", "\r", 0);
293 all_string_sub(buf, "\\s", " ", 0);
294 all_string_sub(buf, "\\t", "\t", 0);
297 static int talktochild(int master, const char *seq)
300 fstring issue, expected;
304 while (next_token(&seq, expected, NULL, sizeof(expected)))
309 if (!expect(master, issue, expected))
311 DEBUG(3, ("Response %d incorrect\n", count));
315 if (!next_token(&seq, issue, NULL, sizeof(issue)))
320 if (!strequal(issue, ".")) {
321 /* we have one final issue to send */
322 fstrcpy(expected, ".");
323 if (!expect(master, issue, expected))
330 static BOOL chat_with_program(char *passwordprogram, struct passwd *pass,
331 char *chatsequence, BOOL as_root)
340 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
344 /* allocate a pseudo-terminal device */
345 if ((master = findpty(&slavedev)) < 0) {
346 DEBUG(3, ("Cannot Allocate pty for password change: %s\n", pass->pw_name));
351 * We need to temporarily stop CatchChild from eating
352 * SIGCLD signals as it also eats the exit status code. JRA.
355 CatchChildLeaveStatus();
357 if ((pid = sys_fork()) < 0) {
358 DEBUG(3, ("Cannot fork() child for password change: %s\n", pass->pw_name));
364 /* we now have a pty */
365 if (pid > 0) { /* This is the parent process */
366 if ((chstat = talktochild(master, chatsequence)) == False) {
367 DEBUG(3, ("Child failed to change password: %s\n", pass->pw_name));
368 kill(pid, SIGKILL); /* be sure to end this process */
371 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
372 if (errno == EINTR) {
380 DEBUG(3, ("The process is no longer waiting!\n\n"));
387 * Go back to ignoring children.
394 DEBUG(3, ("We were waiting for the wrong process ID\n"));
397 if (WIFEXITED(wstat) == 0) {
398 DEBUG(3, ("The process exited while we were waiting\n"));
401 if (WEXITSTATUS(wstat) != 0) {
402 DEBUG(3, ("The status of the process exiting was %d\n",
411 * Lose any oplock capabilities.
413 oplock_set_capability(False, False);
415 /* make sure it doesn't freeze */
421 DEBUG(3, ("Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
422 (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
423 chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
429 * The child should never return from dochild() ....
432 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
437 DEBUG(3, ("Password change %ssuccessful for user %s\n",
438 (chstat ? "" : "un"), pass->pw_name));
442 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
444 pstring passwordprogram;
445 pstring chatsequence;
452 DEBUG(1, ("NULL username specfied to chgpasswd()!\n"));
455 pass = Get_Pwnam(name);
457 DEBUG(1, ("Username does not exist in system passwd!\n"));
465 DEBUG(3, ("Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
468 DEBUG(100, ("Passwords: old=%s new=%s\n", oldpass, newpass));
471 /* Take the passed information and test it for minimum criteria */
472 /* Minimum password length */
473 if (strlen(newpass) < lp_min_passwd_length()) {
474 /* too short, must be at least MINPASSWDLENGTH */
475 DEBUG(0, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
476 name, lp_min_passwd_length()));
477 return (False); /* inform the user */
480 /* Password is same as old password */
481 if (strcmp(oldpass, newpass) == 0) {
482 /* don't allow same password */
483 DEBUG(2, ("Password Change: %s, New password is same as old\n", name)); /* log the attempt */
484 return (False); /* inform the user */
488 * Check the old and new passwords don't contain any control
492 len = strlen(oldpass);
493 for (i = 0; i < len; i++) {
494 if (iscntrl((int)oldpass[i])) {
495 DEBUG(0, ("chat_with_program: oldpass contains control characters (disallowed).\n"));
500 len = strlen(newpass);
501 for (i = 0; i < len; i++) {
502 if (iscntrl((int)newpass[i])) {
503 DEBUG(0, ("chat_with_program: newpass contains control characters (disallowed).\n"));
509 if (lp_pam_password_change()) {
516 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
518 ret = smb_pam_passchange(name, oldpass, newpass);
528 /* A non-PAM password change just doen't make sense without a valid local user */
531 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
535 pstrcpy(passwordprogram, lp_passwd_program());
536 pstrcpy(chatsequence, lp_passwd_chat());
538 if (!*chatsequence) {
539 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
543 if (!*passwordprogram) {
544 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
549 /* The password program *must* contain the user name to work. Fail if not. */
550 if (strstr(passwordprogram, "%u") == NULL) {
551 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
552 the string %%u, and the given string %s does not.\n", passwordprogram ));
557 pstring_sub(passwordprogram, "%u", name);
558 /* note that we do NOT substitute the %o and %n in the password program
559 as this would open up a security hole where the user could use
560 a new password containing shell escape characters */
562 pstring_sub(chatsequence, "%u", name);
563 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
564 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
565 return (chat_with_program
566 (passwordprogram, pass, chatsequence, as_root));
569 #else /* ALLOW_CHANGE_PASSWORD */
571 BOOL chgpasswd(const char *name, const char *oldpass, const char *newpass, BOOL as_root)
573 DEBUG(0, ("Password changing not compiled in (user=%s)\n", name));
576 #endif /* ALLOW_CHANGE_PASSWORD */
578 /***********************************************************
579 Code to check the lanman hashed password.
580 ************************************************************/
582 BOOL check_lanman_password(char *user, uchar * pass1,
583 uchar * pass2, SAM_ACCOUNT **hnd)
585 uchar unenc_new_pw[16];
586 uchar unenc_old_pw[16];
587 SAM_ACCOUNT *sampass = NULL;
589 const uint8 *lanman_pw;
593 ret = pdb_getsampwnam(sampass, user);
597 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
598 pdb_free_sam(&sampass);
602 acct_ctrl = pdb_get_acct_ctrl (sampass);
603 lanman_pw = pdb_get_lanman_passwd (sampass);
605 if (acct_ctrl & ACB_DISABLED) {
606 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
607 pdb_free_sam(&sampass);
611 if (lanman_pw == NULL) {
612 if (acct_ctrl & ACB_PWNOTREQ) {
613 /* this saves the pointer for the caller */
617 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
618 pdb_free_sam(&sampass);
623 /* Get the new lanman hash. */
624 D_P16(lanman_pw, pass2, unenc_new_pw);
626 /* Use this to get the old lanman hash. */
627 D_P16(unenc_new_pw, pass1, unenc_old_pw);
629 /* Check that the two old passwords match. */
630 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
631 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
632 pdb_free_sam(&sampass);
636 /* this saves the pointer for the caller */
641 /***********************************************************
642 Code to change the lanman hashed password.
643 It nulls out the NT hashed password as it will
645 NOTE this function is designed to be called as root. Check the old password
646 is correct before calling. JRA.
647 ************************************************************/
649 BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar *pass2)
651 static uchar null_pw[16];
652 uchar unenc_new_pw[16];
657 if (sampass == NULL) {
658 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
662 acct_ctrl = pdb_get_acct_ctrl(sampass);
663 pwd = pdb_get_lanman_passwd(sampass);
665 if (acct_ctrl & ACB_DISABLED) {
666 DEBUG(0,("change_lanman_password: account %s disabled.\n",
667 pdb_get_username(sampass)));
672 if (acct_ctrl & ACB_PWNOTREQ) {
674 memset(no_pw, '\0', 14);
675 E_P16(no_pw, null_pw);
677 /* Get the new lanman hash. */
678 D_P16(null_pw, pass2, unenc_new_pw);
680 DEBUG(0,("change_lanman_password: no lanman password !\n"));
684 /* Get the new lanman hash. */
685 D_P16(pwd, pass2, unenc_new_pw);
688 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
692 if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
693 return False; /* We lose the NT hash. Sorry. */
696 if (!pdb_set_pass_changed_now (sampass)) {
697 pdb_free_sam(&sampass);
698 /* Not quite sure what this one qualifies as, but this will do */
702 /* Now flush the sam_passwd struct to persistent storage */
703 ret = pdb_update_sam_account (sampass);
708 /***********************************************************
709 Code to check and change the OEM hashed password.
710 ************************************************************/
712 NTSTATUS pass_oem_change(char *user,
713 uchar * lmdata, uchar * lmhash,
714 uchar * ntdata, uchar * nthash)
717 SAM_ACCOUNT *sampass = NULL;
718 NTSTATUS nt_status = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
719 &sampass, new_passwd, sizeof(new_passwd));
721 if (!NT_STATUS_IS_OK(nt_status))
724 /* We've already checked the old password here.... */
726 nt_status = change_oem_password(sampass, NULL, new_passwd, True);
729 memset(new_passwd, 0, sizeof(new_passwd));
731 pdb_free_sam(&sampass);
736 /***********************************************************
737 Code to check the OEM hashed password.
739 this function ignores the 516 byte nt OEM hashed password
740 but does use the lm OEM password to check the nt hashed-hash.
742 ************************************************************/
744 static NTSTATUS check_oem_password(const char *user,
745 uchar * lmdata, const uchar * lmhash,
746 const uchar * ntdata, const uchar * nthash,
747 SAM_ACCOUNT **hnd, char *new_passwd,
750 static uchar null_pw[16];
751 static uchar null_ntpw[16];
752 SAM_ACCOUNT *sampass = NULL;
753 const uint8 *lanman_pw, *nt_pw;
757 uchar unenc_old_ntpw[16];
759 uchar unenc_old_pw[16];
763 BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
767 pdb_init_sam(&sampass);
770 ret = pdb_getsampwnam(sampass, user);
774 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
775 pdb_free_sam(&sampass);
776 return NT_STATUS_WRONG_PASSWORD;
778 TODO: check what Win2k returns for this:
779 return NT_STATUS_NO_SUCH_USER;
783 acct_ctrl = pdb_get_acct_ctrl(sampass);
785 if (acct_ctrl & ACB_DISABLED) {
786 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
787 pdb_free_sam(&sampass);
788 return NT_STATUS_ACCOUNT_DISABLED;
791 /* construct a null password (in case one is needed */
794 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
796 /* save pointers to passwords so we don't have to keep looking them up */
797 lanman_pw = pdb_get_lanman_passwd(sampass);
798 nt_pw = pdb_get_nt_passwd(sampass);
800 /* check for null passwords */
801 if (lanman_pw == NULL) {
802 if (!(acct_ctrl & ACB_PWNOTREQ)) {
803 DEBUG(0,("check_oem_password: no lanman password !\n"));
804 pdb_free_sam(&sampass);
805 return NT_STATUS_WRONG_PASSWORD;
809 if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
810 if (!(acct_ctrl & ACB_PWNOTREQ)) {
811 DEBUG(0,("check_oem_password: no ntlm password !\n"));
812 pdb_free_sam(&sampass);
813 return NT_STATUS_WRONG_PASSWORD;
818 * Call the hash function to get the new password.
820 SamOEMhash( lmdata, lanman_pw, 516);
823 * The length of the new password is in the last 4 bytes of
827 new_pw_len = IVAL(lmdata, 512);
829 if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
830 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
831 pdb_free_sam(&sampass);
832 return NT_STATUS_WRONG_PASSWORD;
837 * nt passwords are in unicode
839 pull_ucs2(NULL, new_passwd,
840 (const smb_ucs2_t *)&lmdata[512 - new_pw_len],
841 new_passwd_size, new_pw_len, 0);
843 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
844 new_passwd[new_pw_len] = 0;
848 * To ensure we got the correct new password, hash it and
849 * use it as a key to test the passed old password.
852 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
856 * Now use new_p16 as the key to see if the old
859 D_P16(new_p16, lmhash, unenc_old_pw);
861 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
862 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
863 pdb_free_sam(&sampass);
864 return NT_STATUS_WRONG_PASSWORD;
867 #ifdef DEBUG_PASSWORD
869 ("check_oem_password: password %s ok\n", new_passwd));
876 * Now use new_p16 as the key to see if the old
879 D_P16(new_ntp16, lmhash, unenc_old_pw);
880 D_P16(new_ntp16, nthash, unenc_old_ntpw);
882 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
883 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
884 pdb_free_sam(&sampass);
885 return NT_STATUS_WRONG_PASSWORD;
888 if (memcmp(nt_pw, unenc_old_ntpw, 16)) {
889 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
890 pdb_free_sam(&sampass);
891 return NT_STATUS_WRONG_PASSWORD;
893 #ifdef DEBUG_PASSWORD
894 DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
901 /***********************************************************
902 Code to change the oem password. Changes both the lanman
903 and NT hashes. Old_passwd is almost always NULL.
904 NOTE this function is designed to be called as root. Check the old password
905 is correct before calling. JRA.
906 ************************************************************/
908 NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root)
913 if (time(NULL) < pdb_get_pass_can_change_time(hnd)) {
914 DEBUG(1, ("user %s cannot change password now, must wait until %s\n",
915 pdb_get_username(hnd), http_timestring(pdb_get_pass_can_change_time(hnd))));
916 return NT_STATUS_PASSWORD_RESTRICTION;
919 if (account_policy_get(AP_MIN_PASSWORD_LEN, &min_len) && (strlen(new_passwd) < min_len)) {
920 DEBUG(1, ("user %s cannot change password - password too short\n",
921 pdb_get_username(hnd)));
922 DEBUGADD(1, (" account policy min password len = %d\n", min_len));
923 return NT_STATUS_PASSWORD_RESTRICTION;
924 /* return NT_STATUS_PWD_TOO_SHORT; */
927 /* Take the passed information and test it for minimum criteria */
928 /* Minimum password length */
929 if (strlen(new_passwd) < lp_min_passwd_length()) {
930 /* too short, must be at least MINPASSWDLENGTH */
931 DEBUG(1, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
932 pdb_get_username(hnd), lp_min_passwd_length()));
933 return NT_STATUS_PASSWORD_RESTRICTION;
934 /* return NT_STATUS_PWD_TOO_SHORT; */
937 /* TODO: Add cracklib support here */
940 * If unix password sync was requested, attempt to change
941 * the /etc/passwd database first. Return failure if this cannot
944 * This occurs before the oem change, because we don't want to
945 * update it if chgpasswd failed.
947 * Conditional on lp_unix_password_sync() because we don't want
948 * to touch the unix db unless we have admin permission.
951 if(lp_unix_password_sync() &&
952 !chgpasswd(pdb_get_username(hnd), old_passwd, new_passwd, as_root)) {
953 return NT_STATUS_ACCESS_DENIED;
956 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
957 return NT_STATUS_ACCESS_DENIED;
960 /* Now write it into the file. */
961 ret = pdb_update_sam_account (hnd);
964 return NT_STATUS_ACCESS_DENIED;