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 #ifdef HAVE_WORKING_CRACKLIB
55 #ifndef HAVE_CRACKLIB_DICTPATH
56 #ifndef CRACKLIB_DICTPATH
57 #define CRACKLIB_DICTPATH SAMBA_CRACKLIB_DICTPATH
62 extern struct passdb_ops pdb_ops;
64 static NTSTATUS check_oem_password(const char *user,
65 uchar * lmdata, const uchar * lmhash,
66 const uchar * ntdata, const uchar * nthash,
67 SAM_ACCOUNT **hnd, char *new_passwd,
70 #if ALLOW_CHANGE_PASSWORD
72 static int findpty(char **slave)
79 #if defined(HAVE_GRANTPT)
80 /* Try to open /dev/ptmx. If that fails, fall through to old method. */
81 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0)
85 *slave = (char *)ptsname(master);
89 ("findpty: Unable to create master/slave pty pair.\n"));
90 /* Stop fd leak on error. */
97 ("findpty: Allocated slave pty %s\n", *slave));
101 #endif /* HAVE_GRANTPT */
103 fstrcpy(line, "/dev/ptyXX");
105 dirp = opendir("/dev");
108 while ((dpname = readdirname(dirp)) != NULL)
110 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)
119 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;
142 ("dochild: user doesn't exist in the UNIX password database.\n"));
149 gain_root_privilege();
151 /* Start new session - gets rid of controlling terminal. */
155 ("Weirdness, couldn't let go of controlling terminal\n"));
159 /* Open slave pty and acquire as new controlling terminal. */
160 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0)
162 DEBUG(3, ("More weirdness, could not open %s\n", slavedev));
166 ioctl(slave, I_PUSH, "ptem");
167 ioctl(slave, I_PUSH, "ldterm");
168 #elif defined(TIOCSCTTY)
169 if (ioctl(slave, TIOCSCTTY, 0) < 0)
171 DEBUG(3, ("Error in ioctl call for slave pty\n"));
179 /* Make slave stdin/out/err of child. */
181 if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO)
183 DEBUG(3, ("Could not re-direct stdin\n"));
186 if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO)
188 DEBUG(3, ("Could not re-direct stdout\n"));
191 if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO)
193 DEBUG(3, ("Could not re-direct stderr\n"));
199 /* Set proper terminal attributes - no echo, canonical input processing,
200 no map NL to CR/NL on output. */
202 if (tcgetattr(0, &stermios) < 0)
205 ("could not read default terminal attributes on pty\n"));
208 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
209 stermios.c_lflag |= ICANON;
211 stermios.c_oflag &= ~(ONLCR);
213 if (tcsetattr(0, TCSANOW, &stermios) < 0)
215 DEBUG(3, ("could not set attributes of pty\n"));
219 /* make us completely into the right uid */
222 become_user_permanently(uid, gid);
226 ("Invoking '%s' as password change program.\n",
229 /* execl() password-change application */
230 if (execl("/bin/sh", "sh", "-c", passwordprogram, NULL) < 0)
232 DEBUG(3, ("Bad status returned from %s\n", passwordprogram));
238 static int expect(int master, char *issue, char *expected)
241 int attempts, timeout, nread, len;
244 for (attempts = 0; attempts < 2; attempts++) {
245 if (!strequal(issue, ".")) {
246 if (lp_passwd_chat_debug())
247 DEBUG(100, ("expect: sending [%s]\n", issue));
249 if ((len = write(master, issue, strlen(issue))) != strlen(issue)) {
250 DEBUG(2,("expect: (short) write returned %d\n", len ));
255 if (strequal(expected, "."))
258 /* Initial timeout. */
259 timeout = lp_passwd_chat_timeout() * 1000;
263 while ((len = read_socket_with_timeout(master, buffer + nread, 1,
264 sizeof(buffer) - nread - 1,
270 /* Eat leading/trailing whitespace before match. */
272 pstrcpy( str, buffer);
273 trim_char( str, ' ', ' ');
275 if ((match = (unix_wild_match(expected, str) == 0))) {
276 /* Now data has started to return, lower timeout. */
277 timeout = lp_passwd_chat_timeout() * 100;
282 if (lp_passwd_chat_debug())
283 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n",
284 expected, buffer, match ? "yes" : "no" ));
290 DEBUG(2, ("expect: %s\n", strerror(errno)));
295 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" ));
299 static void pwd_sub(char *buf)
301 all_string_sub(buf, "\\n", "\n", 0);
302 all_string_sub(buf, "\\r", "\r", 0);
303 all_string_sub(buf, "\\s", " ", 0);
304 all_string_sub(buf, "\\t", "\t", 0);
307 static int talktochild(int master, const char *seq)
310 fstring issue, expected;
314 while (next_token(&seq, expected, NULL, sizeof(expected)))
319 if (!expect(master, issue, expected))
321 DEBUG(3, ("Response %d incorrect\n", count));
325 if (!next_token(&seq, issue, NULL, sizeof(issue)))
330 if (!strequal(issue, ".")) {
331 /* we have one final issue to send */
332 fstrcpy(expected, ".");
333 if (!expect(master, issue, expected))
340 static BOOL chat_with_program(char *passwordprogram, struct passwd *pass,
341 char *chatsequence, BOOL as_root)
350 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n"));
354 /* allocate a pseudo-terminal device */
355 if ((master = findpty(&slavedev)) < 0) {
356 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name));
361 * We need to temporarily stop CatchChild from eating
362 * SIGCLD signals as it also eats the exit status code. JRA.
365 CatchChildLeaveStatus();
367 if ((pid = sys_fork()) < 0) {
368 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name));
374 /* we now have a pty */
375 if (pid > 0) { /* This is the parent process */
376 if ((chstat = talktochild(master, chatsequence)) == False) {
377 DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name));
378 kill(pid, SIGKILL); /* be sure to end this process */
381 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) {
382 if (errno == EINTR) {
390 DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n"));
397 * Go back to ignoring children.
404 DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n"));
407 if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) {
408 DEBUG(3, ("chat_with_program: The process exited with status %d \
409 while we were waiting\n", WEXITSTATUS(wstat)));
412 #if defined(WIFSIGNALLED) && defined(WTERMSIG)
413 else if (WIFSIGNALLED(wstat)) {
414 DEBUG(3, ("chat_with_program: The process was killed by signal %d \
415 while we were waiting\n", WTERMSIG(wstat)));
423 * Lose any oplock capabilities.
425 oplock_set_capability(False, False);
427 /* make sure it doesn't freeze */
433 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name,
434 (int)getuid(), (int)getgid(), BOOLSTR(as_root) ));
435 chstat = dochild(master, slavedev, pass, passwordprogram, as_root);
441 * The child should never return from dochild() ....
444 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat));
449 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n",
450 (chstat ? "" : "un"), pass->pw_name));
454 BOOL chgpasswd(const char *name, const struct passwd *pass,
455 const char *oldpass, const char *newpass, BOOL as_root)
457 pstring passwordprogram;
458 pstring chatsequence;
466 DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name));
469 DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass));
472 /* Take the passed information and test it for minimum criteria */
474 /* Password is same as old password */
475 if (strcmp(oldpass, newpass) == 0) {
476 /* don't allow same password */
477 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */
478 return (False); /* inform the user */
482 * Check the old and new passwords don't contain any control
486 len = strlen(oldpass);
487 for (i = 0; i < len; i++) {
488 if (iscntrl((int)oldpass[i])) {
489 DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n"));
494 len = strlen(newpass);
495 for (i = 0; i < len; i++) {
496 if (iscntrl((int)newpass[i])) {
497 DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n"));
503 if (lp_pam_password_change()) {
510 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass);
512 ret = smb_pam_passchange(name, oldpass, newpass);
522 /* A non-PAM password change just doen't make sense without a valid local user */
525 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name));
529 pstrcpy(passwordprogram, lp_passwd_program());
530 pstrcpy(chatsequence, lp_passwd_chat());
532 if (!*chatsequence) {
533 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n"));
537 if (!*passwordprogram) {
538 DEBUG(2, ("chgpasswd: Null password program - no password changing\n"));
543 /* The password program *must* contain the user name to work. Fail if not. */
544 if (strstr(passwordprogram, "%u") == NULL) {
545 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \
546 the string %%u, and the given string %s does not.\n", passwordprogram ));
551 pstring_sub(passwordprogram, "%u", name);
552 /* note that we do NOT substitute the %o and %n in the password program
553 as this would open up a security hole where the user could use
554 a new password containing shell escape characters */
556 pstring_sub(chatsequence, "%u", name);
557 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring));
558 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring));
559 return (chat_with_program
560 (passwordprogram, pass, chatsequence, as_root));
563 #else /* ALLOW_CHANGE_PASSWORD */
565 BOOL chgpasswd(const char *name, const struct passwd *pass,
566 const char *oldpass, const char *newpass, BOOL as_root)
568 DEBUG(0, ("chgpasswd: Password changing not compiled in (user=%s)\n", name));
571 #endif /* ALLOW_CHANGE_PASSWORD */
573 /***********************************************************
574 Code to check the lanman hashed password.
575 ************************************************************/
577 BOOL check_lanman_password(char *user, uchar * pass1,
578 uchar * pass2, SAM_ACCOUNT **hnd)
580 uchar unenc_new_pw[16];
581 uchar unenc_old_pw[16];
582 SAM_ACCOUNT *sampass = NULL;
584 const uint8 *lanman_pw;
588 ret = pdb_getsampwnam(sampass, user);
592 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n"));
593 pdb_free_sam(&sampass);
597 acct_ctrl = pdb_get_acct_ctrl (sampass);
598 lanman_pw = pdb_get_lanman_passwd (sampass);
600 if (acct_ctrl & ACB_DISABLED) {
601 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
602 pdb_free_sam(&sampass);
606 if (lanman_pw == NULL) {
607 if (acct_ctrl & ACB_PWNOTREQ) {
608 /* this saves the pointer for the caller */
612 DEBUG(0, ("check_lanman_password: no lanman password !\n"));
613 pdb_free_sam(&sampass);
618 /* Get the new lanman hash. */
619 D_P16(lanman_pw, pass2, unenc_new_pw);
621 /* Use this to get the old lanman hash. */
622 D_P16(unenc_new_pw, pass1, unenc_old_pw);
624 /* Check that the two old passwords match. */
625 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
626 DEBUG(0,("check_lanman_password: old password doesn't match.\n"));
627 pdb_free_sam(&sampass);
631 /* this saves the pointer for the caller */
636 /***********************************************************
637 Code to change the lanman hashed password.
638 It nulls out the NT hashed password as it will
640 NOTE this function is designed to be called as root. Check the old password
641 is correct before calling. JRA.
642 ************************************************************/
644 BOOL change_lanman_password(SAM_ACCOUNT *sampass, uchar *pass2)
646 static uchar null_pw[16];
647 uchar unenc_new_pw[16];
652 if (sampass == NULL) {
653 DEBUG(0,("change_lanman_password: no smb password entry.\n"));
657 acct_ctrl = pdb_get_acct_ctrl(sampass);
658 pwd = pdb_get_lanman_passwd(sampass);
660 if (acct_ctrl & ACB_DISABLED) {
661 DEBUG(0,("change_lanman_password: account %s disabled.\n",
662 pdb_get_username(sampass)));
667 if (acct_ctrl & ACB_PWNOTREQ) {
669 memset(no_pw, '\0', 14);
670 E_P16(no_pw, null_pw);
672 /* Get the new lanman hash. */
673 D_P16(null_pw, pass2, unenc_new_pw);
675 DEBUG(0,("change_lanman_password: no lanman password !\n"));
679 /* Get the new lanman hash. */
680 D_P16(pwd, pass2, unenc_new_pw);
683 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) {
687 if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) {
688 return False; /* We lose the NT hash. Sorry. */
691 if (!pdb_set_pass_changed_now (sampass)) {
692 pdb_free_sam(&sampass);
693 /* Not quite sure what this one qualifies as, but this will do */
697 /* Now flush the sam_passwd struct to persistent storage */
698 ret = pdb_update_sam_account (sampass);
703 /***********************************************************
704 Code to check and change the OEM hashed password.
705 ************************************************************/
707 NTSTATUS pass_oem_change(char *user,
708 uchar * lmdata, uchar * lmhash,
709 uchar * ntdata, uchar * nthash)
712 SAM_ACCOUNT *sampass = NULL;
713 NTSTATUS nt_status = check_oem_password(user, lmdata, lmhash, ntdata, nthash,
714 &sampass, new_passwd, sizeof(new_passwd));
716 if (!NT_STATUS_IS_OK(nt_status))
719 /* We've already checked the old password here.... */
721 nt_status = change_oem_password(sampass, NULL, new_passwd, True);
724 memset(new_passwd, 0, sizeof(new_passwd));
726 pdb_free_sam(&sampass);
731 /***********************************************************
732 Code to check the OEM hashed password.
734 this function ignores the 516 byte nt OEM hashed password
735 but does use the lm OEM password to check the nt hashed-hash.
737 ************************************************************/
739 static NTSTATUS check_oem_password(const char *user,
740 uchar * lmdata, const uchar * lmhash,
741 const uchar * ntdata, const uchar * nthash,
742 SAM_ACCOUNT **hnd, char *new_passwd,
745 static uchar null_pw[16];
746 static uchar null_ntpw[16];
747 SAM_ACCOUNT *sampass = NULL;
748 const uint8 *lanman_pw, *nt_pw;
752 uchar unenc_old_ntpw[16];
754 uchar unenc_old_pw[16];
758 BOOL nt_pass_set = (ntdata != NULL && nthash != NULL);
762 pdb_init_sam(&sampass);
765 ret = pdb_getsampwnam(sampass, user);
769 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n"));
770 pdb_free_sam(&sampass);
771 return NT_STATUS_WRONG_PASSWORD;
773 TODO: check what Win2k returns for this:
774 return NT_STATUS_NO_SUCH_USER;
778 acct_ctrl = pdb_get_acct_ctrl(sampass);
780 if (acct_ctrl & ACB_DISABLED) {
781 DEBUG(0,("check_lanman_password: account %s disabled.\n", user));
782 pdb_free_sam(&sampass);
783 return NT_STATUS_ACCOUNT_DISABLED;
786 /* construct a null password (in case one is needed */
789 nt_lm_owf_gen(no_pw, null_ntpw, null_pw);
791 /* save pointers to passwords so we don't have to keep looking them up */
792 lanman_pw = pdb_get_lanman_passwd(sampass);
793 nt_pw = pdb_get_nt_passwd(sampass);
795 /* check for null passwords */
796 if (lanman_pw == NULL) {
797 if (!(acct_ctrl & ACB_PWNOTREQ)) {
798 DEBUG(0,("check_oem_password: no lanman password !\n"));
799 pdb_free_sam(&sampass);
800 return NT_STATUS_WRONG_PASSWORD;
804 if (pdb_get_nt_passwd(sampass) == NULL && nt_pass_set) {
805 if (!(acct_ctrl & ACB_PWNOTREQ)) {
806 DEBUG(0,("check_oem_password: no ntlm password !\n"));
807 pdb_free_sam(&sampass);
808 return NT_STATUS_WRONG_PASSWORD;
813 * Call the hash function to get the new password.
815 SamOEMhash( lmdata, lanman_pw, 516);
818 * The length of the new password is in the last 4 bytes of
822 new_pw_len = IVAL(lmdata, 512);
824 if (new_pw_len < 0 || new_pw_len > new_passwd_size - 1) {
825 DEBUG(0,("check_oem_password: incorrect password length (%d).\n", new_pw_len));
826 pdb_free_sam(&sampass);
827 return NT_STATUS_WRONG_PASSWORD;
832 * nt passwords are in unicode
834 pull_ucs2(NULL, new_passwd,
835 (const smb_ucs2_t *)&lmdata[512 - new_pw_len],
836 new_passwd_size, new_pw_len, 0);
838 memcpy(new_passwd, &lmdata[512 - new_pw_len], new_pw_len);
839 new_passwd[new_pw_len] = 0;
843 * To ensure we got the correct new password, hash it and
844 * use it as a key to test the passed old password.
847 nt_lm_owf_gen(new_passwd, new_ntp16, new_p16);
851 * Now use new_p16 as the key to see if the old
854 D_P16(new_p16, lmhash, unenc_old_pw);
856 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
857 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
858 pdb_free_sam(&sampass);
859 return NT_STATUS_WRONG_PASSWORD;
862 #ifdef DEBUG_PASSWORD
864 ("check_oem_password: password %s ok\n", new_passwd));
871 * Now use new_p16 as the key to see if the old
874 D_P16(new_ntp16, lmhash, unenc_old_pw);
875 D_P16(new_ntp16, nthash, unenc_old_ntpw);
877 if (memcmp(lanman_pw, unenc_old_pw, 16)) {
878 DEBUG(0,("check_oem_password: old lm password doesn't match.\n"));
879 pdb_free_sam(&sampass);
880 return NT_STATUS_WRONG_PASSWORD;
883 if (memcmp(nt_pw, unenc_old_ntpw, 16)) {
884 DEBUG(0,("check_oem_password: old nt password doesn't match.\n"));
885 pdb_free_sam(&sampass);
886 return NT_STATUS_WRONG_PASSWORD;
888 #ifdef DEBUG_PASSWORD
889 DEBUG(100, ("check_oem_password: password %s ok\n", new_passwd));
896 /***********************************************************
897 Code to change the oem password. Changes both the lanman
898 and NT hashes. Old_passwd is almost always NULL.
899 NOTE this function is designed to be called as root. Check the old password
900 is correct before calling. JRA.
901 ************************************************************/
903 NTSTATUS change_oem_password(SAM_ACCOUNT *hnd, char *old_passwd, char *new_passwd, BOOL as_root)
910 if (time(NULL) < pdb_get_pass_can_change_time(hnd)) {
911 DEBUG(1, ("user %s cannot change password now, must wait until %s\n",
912 pdb_get_username(hnd), http_timestring(pdb_get_pass_can_change_time(hnd))));
913 return NT_STATUS_PASSWORD_RESTRICTION;
916 if (account_policy_get(AP_MIN_PASSWORD_LEN, &min_len) && (strlen(new_passwd) < min_len)) {
917 DEBUG(1, ("user %s cannot change password - password too short\n",
918 pdb_get_username(hnd)));
919 DEBUGADD(1, (" account policy min password len = %d\n", min_len));
920 return NT_STATUS_PASSWORD_RESTRICTION;
921 /* return NT_STATUS_PWD_TOO_SHORT; */
924 /* Take the passed information and test it for minimum criteria */
925 /* Minimum password length */
926 if (strlen(new_passwd) < lp_min_passwd_length()) {
927 /* too short, must be at least MINPASSWDLENGTH */
928 DEBUG(1, ("Password Change: user %s, New password is shorter than minimum password length = %d\n",
929 pdb_get_username(hnd), lp_min_passwd_length()));
930 return NT_STATUS_PASSWORD_RESTRICTION;
931 /* return NT_STATUS_PWD_TOO_SHORT; */
934 pass = Get_Pwnam(pdb_get_username(hnd));
936 DEBUG(1, ("check_oem_password: Username does not exist in system !?!\n"));
939 #ifdef HAVE_WORKING_CRACKLIB
941 /* if we can, become the user to overcome internal cracklib sillyness */
943 return NT_STATUS_UNSUCCESSFUL;
945 set_sec_ctx(pass->pw_uid, pass->pw_gid, 0, NULL, NULL);
949 if (lp_use_cracklib()) {
950 const char *crack_check_reason;
951 DEBUG(4, ("change_oem_password: Checking password for user [%s]"
952 " against cracklib. \n", pdb_get_username(hnd)));
953 DEBUGADD(4, ("If this is your last message, then something is "
954 "wrong with cracklib, it might be missing it's "
955 "dictionaries at %s\n",
959 crack_check_reason = FascistCheck(new_passwd, (char *)CRACKLIB_DICTPATH);
960 if (crack_check_reason) {
961 DEBUG(1, ("Password Change: user [%s], "
962 "New password failed cracklib test - %s\n",
963 pdb_get_username(hnd), crack_check_reason));
965 /* get back to where we should be */
968 return NT_STATUS_PASSWORD_RESTRICTION;
977 * If unix password sync was requested, attempt to change
978 * the /etc/passwd database first. Return failure if this cannot
981 * This occurs before the oem change, because we don't want to
982 * update it if chgpasswd failed.
984 * Conditional on lp_unix_password_sync() because we don't want
985 * to touch the unix db unless we have admin permission.
988 if(lp_unix_password_sync() &&
989 !chgpasswd(pdb_get_username(hnd), pass, old_passwd, new_passwd, as_root)) {
990 return NT_STATUS_ACCESS_DENIED;
993 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) {
994 return NT_STATUS_ACCESS_DENIED;
997 /* Now write it into the file. */
998 ret = pdb_update_sam_account (hnd);
1001 return NT_STATUS_ACCESS_DENIED;
1004 return NT_STATUS_OK;